3

次の現在のタスクを Java (Windows 上) で実行する最良の方法を探しています。

ユーザーが入力した特定の文字列のおかげで、プログラムの「内部」でランダムな他の文字列/キー(英数字)を作成し、ユーザーには見えません。

同じ文字列を入力する場合、キーは同じでなければなりません。

基本的に、ランダムな文字列を作成する方法はわかりましたが、このプログラムのユーザーが内部的に返されたキーを見つけられないようにしたいと思います (実際には、このキーを使用してデータを暗号化するため、このキーへの単純なユーザー アクセスは必要ありません)。

どうすればそれを作ることができますか?適切なソリューションのコードの実行例を教えていただけますか?

編集:ユーザーが入力した同じ文字列に対して同じキーを要求します。これは、別のクライアントで自分のコンピューターで次に使用するために、この生成されたキーを知る必要があるためです。

4

4 に答える 4

2

セキュリティの観点からアドバイスするために、あなたのユースケースについて本当に十分に知りません。ただし、ユーザー提供の入力から再現可能なキーを生成する問題を直接解決するために、パスワードベースのキー導出を利用できます。この場合、ユーザー提供の入力をパスワードとして扱います(完全な例として編集)。

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import sun.security.provider.SecureRandom;

public class DerivationExample {

  private static SecretKey makeKeyFromUserInput(String userInput, byte[] salt)
      throws NoSuchAlgorithmException, InvalidKeySpecException {

    SecretKeyFactory factory = SecretKeyFactory
        .getInstance("PBKDF2WithHmacSHA1");
    KeySpec keySpec = new PBEKeySpec(userInput.toCharArray(), salt, 1024, 256);
    byte[] derivedKey = factory.generateSecret(keySpec).getEncoded();
    return new SecretKeySpec(derivedKey, "AES");
  }

  public static void main(String[] args) throws Exception {
    String userInput = "foo";

    // PBKDF2 standard recommends at least 64-bit salt
    // Note: you want to randomly generate this elsewhere and keep it constant
    byte[] salt = new byte[8];
    new SecureRandom().engineNextBytes(salt);

    SecretKey derivedKey = makeKeyFromUserInput(userInput, salt);

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, derivedKey, new IvParameterSpec(
        new byte[16]));

    String plaintext = "Hello, World!";
    byte[] cipherText = cipher.doFinal(plaintext.getBytes());

    // Derive key again to demonstrate it is the same
    SecretKey derivedKey2 = makeKeyFromUserInput(userInput, salt);
    cipher.init(Cipher.DECRYPT_MODE, derivedKey2, new IvParameterSpec(
        new byte[16]));

    byte[] plainText = cipher.doFinal(cipherText);
    // Prints "Hello, World!"
    System.out.println(new String(plainText));
  }
}

塩が一定に保たれていれば、結果として得られるキーは再現可能になります。同じキーを生成する必要がある他のデバイス間でソルトを共有します。

注:この例を機能させるには、無制限のポリシーファイル(このページの下部を参照)をインストールする必要があります。

「安全な」ビットとピースで構成されるセキュリティシステムは、全体として見た場合、安全であるとは限らないことに注意してください。私たちはあなたの要件の抜粋を見ただけなので、私たちのアドバイスはほんの少しの塩でとられるべきです(しゃれは意図されていません)。より完全な答えを得るには、保護しようとしているエンドツーエンドのプロセスを理解する必要があります。

ただし、StackOverflowはセキュリティシステムを設計する場所ではないため、他の場所でこのヘルプを探す必要がある場合があります。

于 2012-08-24T09:36:18.483 に答える
2

多分ソルトハッシュ関数?

ユーザー入力を取得し、秘密の入力を追加して、ハッシュします。

(秘密の入力がなければ、ユーザーはこれを自分で作成する方法を理解できます)。

もちろん、この文字列はまったくランダムではありません。この反復可能にする必要があるため、ランダム性は排除されます。ただし、これらの文字列には識別可能なパターンがないため、「ランダム」に見えます。

于 2012-08-24T09:01:21.867 に答える
0

何を達成したいのかよくわかりませんが、ハッシュを使用して文字列を暗号化できると思います。

このリンクが役立つかもしれません: MD5 ハッシュを生成するにはどうすればよいですか?

文字列をハッシュする前に、最初に文字列を「ソルト」する方がよいでしょう。

于 2012-08-24T09:01:25.047 に答える
0

比較的少量の入力しか期待していない場合は、文字の Unicode と Random を使用して乱数を生成し、すべての結果をマップに格納できます。この方法では、値が既に作成されている場合に値の生成を繰り返さず、代わりにキャッシュされた値を使用します。

于 2012-08-24T09:10:21.730 に答える