3

私は現在、この投稿に触発されて、Android で AES 256 を使用して対称的な暗号化/復号化を実装しています: Java 256bit AES Encryption。私の実装の目的は、データベース内のデータを暗号化することです。

キーの生成には、char[] パスワードを受け取る次のコンストラクターを使用します。

public Cryptography(char[] password) throws NoSuchAlgorithmException,
        InvalidKeySpecException, NoSuchPaddingException {

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
    KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
    secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
    cipher = Cipher.getInstance(AES/CBC/PKCS5Padding);
}

そのため、Android でアクティビティを開始すると、Cryptography クラスの新しいインスタンスが初期化され、生成されたキーが取得されます。ソルトは、16 バイトの固定ランダム byte[] です。つまり、常に同じキーを取得します。その理由は後ほど。

1 つのアクティビティでオブジェクトを取得した後、次の暗号化および復号化メソッドを常に同じキーで使用できます。

public byte[] encrypt(String cleartext) throws InvalidKeyException,
        IllegalBlockSizeException, BadPaddingException,
        UnsupportedEncodingException, InvalidParameterSpecException {

    cipher.init(Cipher.ENCRYPT_MODE, secretKey);

    byte[] encText = cipher.doFinal(cleartext.getBytes(CHARSET_NAME));
    byte[] iv = cipher.getParameters()
            .getParameterSpec(IvParameterSpec.class).getIV();

    byte[] enc = new byte[IV_SIZE + encText.length];

    for (int i = 0; i < enc.length; i++) {
        if (i < IV_SIZE)
            enc[i] = iv[i];
        else if (i < enc.length)
            enc[i] = encText[i - IV_SIZE];
    }

    return enc;
}

public String decrypt(byte[] encryptedText) throws InvalidKeyException,
        InvalidAlgorithmParameterException, UnsupportedEncodingException,
        IllegalBlockSizeException, BadPaddingException {

    byte[] iv = new byte[IV_SIZE];
    byte[] dec = new byte[encryptedText.length - IV_SIZE];

    for (int i = 0; i < encryptedText.length; i++) {
        if (i < IV_SIZE)
            iv[i] = encryptedText[i];
        else if (i < encryptedText.length)
            dec[i - IV_SIZE] = encryptedText[i];
    }

    cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));

    return new String(cipher.doFinal(dec), CHARSET_NAME);
}

ご覧のとおり、メッセージを暗号化するたびに、暗号文とともに新しい IV を保存します。

結論として、データベース テーブルのすべてのフィールドに 1 つの暗号化キー、1 つのランダム ソルト、および新しい IV を使用します。

最初に、データベース テーブルの 1 つのフィールドを暗号化し、必要なソルトと IV を暗号文と共に、または少なくとも 1 つのテーブル行に保存するたびに、新しいソルトと新しい IV を使用して新しいキーを生成したいと考えました。しかし、上記のようにした理由は、Android デバイスでキーを生成するには時間がかかるためです。エミュレーターでテストしましたが、キーの生成に約 2 秒かかりました。これが、Activity の開始時にキーを 1 つだけ生成した理由です。

最後に私の質問: 私のアプローチでは、キーを 1 つだけ使用するだけで十分に安全ですが、メッセージごとに新鮮なランダム IV を使用できますか? 現在のところ、パフォーマンスとのバランスを保つことによって、可能な限り安全にする別の方法は見当たりません。

私が書いたことが十分に明確であり、誰かがそれについてアドバイスをくれることを願っています.

敬具

ゾイドバーグ

4

1 に答える 1

1

この質問はあなた (xoidberg) には関係ないと思いますが、他の人には関係があるかもしれません。

私が理解していることから、ソルトを使用してパスワードから(安全にランダムな)キーを作成します。すべてのユーザーがランダムな (異なる) ソルトを持っていれば問題ありません。そうしないと、問題が発生する可能性があります。

これはあなたがしたことだと思いますので、(私には)大丈夫だと思います。

いくつかの値(通常はパスワード)のハッシュ関数を保存するときに、通常、ソルトを使用したいということを言いたいだけです。MD5 や SHA などのハッシュ関数にはキーがなく、この目的のためにランダム性を追加する必要があります。これがソルトが必要な理由であり、この場合、通常、各値にランダムなソルトが必要な理由です (パスワードハッシュを同じソルトで保存するだけで、最も一般的なハッシュを検出し、ユーザーのパスワードを知ることができます)。最も一般的なハッシュは 123456 です)。あなたの場合、すべてのユーザーに固有のソルトが必要です。

IV について - 毎回ランダムなものが必要です (だから問題ありません)。

于 2013-12-22T11:05:06.373 に答える