0

システムの /dev/urandom インターフェイスから 32 文字のキーを抽出する必要がある Java プログラムを作成しています。このために、次の手順を使用しています。

public String generateKey() {
            try {
                    Runtime run = Runtime.getRuntime();
                    Process pr = run.exec("tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1;echo;");
                    pr.waitFor();
                    BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
                    StringBuffer sb = new StringBuffer();
                    String line = "";
                    while ((line = buf.readLine())!= null ) {
                            sb.append(line);
                    }
                    return sb.toString();
            } catch (Exception e) {
                    e.printStackTrace();
                    return "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
            }
    }

(それができない場合は、一連の null 文字が返されます)

何らかの理由で、何も返されません (または、例外がスローされ、スタック トレースが出力されません)。私はこれをコンソールに出力し (何も表示しない)、RC4 エンジンに渡すとゼロ除算エラーがスローされるため、これを知っています。コマンドが機能しないのはなぜですか?どうすれば機能させることができますか?

お手伝いありがとう。

編集:これを投稿してから2分も経たないうちに、「レモン」という単語を返すように設定し、同じことを行ったため、null文字が返されていないと推測しました。例外はスローされません。

編集2:コメントの提案に従って、同じ結果でファイルから直接読み取ろうとしましたが、これは間違っていると思います...

File file = new File("/dev/urandom");
            FileReader freader = null;
            StringBuffer sb = new StringBuffer();
            int x = 0;
            try {
                    freader = new FileReader(file);
                    BufferedReader reader = new BufferedReader(freader);
                    for (int i=0;(i<32||(x=reader.read())==-1);i++) {
                            sb.append((char) x);
                    }
            return sb.toString();
            } catch(Exception e) {
                    e.printStackTrace();
                    return "a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
            }

編集 3:これは助けてくれる人に役立つかもしれません: 上記のコードを使用して出力を od にパイプすると、0 を読み取っているだけであることがわかりました。(繰り返しますが、例外をスローしていません。それ以外の場合は、すべてゼロにはなりません:)

# ./run.sh | od
0000000 000000 000000 000000 000000 000000 000000 000000 000000
*
4

4 に答える 4

4

Process pr = run.exec("tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1;echo;");

パイプ ( |) とリダイレクト ( <) は、OS ではなくシェルによって処理されます。コマンド全体を文字列パラメータとして に渡すことで、これを自明に解決できますsh。次の例を参照して、用途に合わせて調整してください。

import java.io.*;
class P1 {
    public static void main(String[] args) throws Exception {
        Runtime run = Runtime.getRuntime();
        Process pr = run.exec("sh -c \"ls </dev/null | grep java\"");
        pr.waitFor();
        BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line;
        while ((line = buf.readLine())!= null ) {
            System.out.println(line);
        }
    }
}

編集

/dev/urandom上記はリダイレクトを使用するシェルコマンドを実行するのに役立つかもしれませんが、現在のインスタンスでは、@ Josh Cartwright がこのコメントで説明しているように、外部プロセスをまったく使用せず、直接読み取るのが正しいアプローチです。

于 2013-01-09T00:38:28.563 に答える
2

これは厳密には必要ではありませんが、複数のコマンド ライン引数を指定してプログラムを実行するには、最初のパラメーターとしてコマンドで構成される文字列の配列を作成する必要があり、各スペースは配列のエントリである必要があります (例: ls)。 -l

String[] command = {"ls" , "-l"};
Runtime.getRuntime().exec(command);

これにより、コマンド ラインが正しく呼び出されます。javadoc は次のとおりです。Exec javadoc

于 2013-01-09T00:24:06.800 に答える
1

すでにユーザーが示しているMiserable Variableように、実際のUnixシェル内でコマンドを実行してみてください。シェルがインタラクティブシェルとして呼び出されることを確認します(sh -i -c 'cmd1 | cmd2')。

そうしないと、UNIXの配管メカニズムは、trからの読み取りを継続するためにブロックされているように見えます/dev/urandomが、何らかの理由でそのへの書き込みを拒否しますstdout

Terminal.app次のコマンドは問題なく実行されますが、で実行されます。

sh -c 'LC_ALL=C tr -cd [:alnum:] < /dev/urandom | fold -w30 | head -n1; echo;'

別のアプローチは、読み取るバイト数を明示的に制限すること/dev/urandomです(以下のコードを参照)。

/*

# cat GenerateKey.java
javac GenerateKey.java
java GenerateKey

# For more information see the "Java exec and Unix pipes" comment in:
# "Java exec - execute system processes with Java ProcessBuilder and Process (part 3)",
# http://alvinalexander.com/java/java-exec-processbuilder-process-3

*/

import java.io.*;
import java.util.*;

public class GenerateKey {
    public static void main(String[] args) throws Exception {
        Runtime run = Runtime.getRuntime();

        // does not work on Mac OS X 10.6.8
        //String[] cmd = { "/bin/sh", "-c", "LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1; echo;" };  

        // works
        String[] cmd = { "/bin/sh", "-i", "-c", "LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1; echo;" };  
        //String[] cmd = { "/bin/sh", "-c", "head -c 3000 < /dev/urandom | LC_ALL=C tr -cd '[:alnum:]' | head -c 30" }; 
        //String[] cmd = { "/bin/sh", "-c", "dd if=/dev/urandom bs=3000 count=1 2>/dev/null | LC_ALL=C tr -cd '[:alnum:]' | fold -w30 | head -n1" }; 
        Process pr = run.exec(cmd);

        pr.waitFor();
        BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line;
        while ((line = buf.readLine())!= null ) {
            System.out.println(line);
        }
    }
}
于 2013-01-11T16:25:41.160 に答える
1

実行時に複数のコマンドを実行するために Linux パイプを使用することはできませんRuntime.exec()。コマンドを個別に実行するか、trコマンドの結果を手動で処理する必要があります。これに加えて、コマンド バイナリへのフル パスを使用する必要がありtrます/usr/bin/tr

于 2013-01-09T00:26:22.357 に答える