私は現在、この投稿に触発されて、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 を使用できますか? 現在のところ、パフォーマンスとのバランスを保つことによって、可能な限り安全にする別の方法は見当たりません。
私が書いたことが十分に明確であり、誰かがそれについてアドバイスをくれることを願っています.
敬具
ゾイドバーグ