私は MEGA (この奇妙な人のクラウド サイト) のライブラリに取り組んでいます。私が正しければ、彼らは次の方法でユーザーのパスワードから AES マスターキーを導き出します。
- パスワードの UTF-8 エンコーディングを開始シーケンスとして使用する
- 長さが 16 の倍数になるように 0 を追加して s を展開します
- 初期ベクトルを修正するために 128 ビットのマスターキー pkey を設定します
- 64,000 ラウンドごとに:
- s AES/ECB の 128 ビット ブロック s[i] ごとに、s[i] をキーとして使用して k を暗号化します。
全体として、28 文字のパスワードの場合、AES に対して 128k の呼び出しを行う必要があります。私の実装はかなり遅いことがわかりました。のように:「地獄、それには時間がかかりすぎます。」
DDMS は、GC が過熱していることを示しています。AES 実装でこれらすべてのラウンドを内部的に、または少なくともより効率的に実行するにはどうすればよいですか? 各呼び出しは、後で破棄される新しいバイト配列を作成します。これをインプレースで行う方法はありますか?
public static byte[] calculatePasswordKey(String password) {
Log.v(TAG, ">calculatePasswordKey");
byte[] pw = password.getBytes();
byte[] pkey = {(byte)0x93, (byte)0xC4, 0x67, (byte)0xE3, 0x7D, (byte)0xB0, (byte)0xC7, (byte)0xA4, (byte)0xD1, (byte)0xBE, 0x3F, (byte)0x81, 0x01, 0x52, (byte)0xCB, 0x56};
//expand by appending 0s
Log.v(TAG, Arrays.toString(pw));
if ((pw.length & 0xf0) != 0) {
int l = (pw.length & 0xf0) + 0x10;
byte[] paddedpw = new byte[l];
System.arraycopy(pw, 0, paddedpw, 0, pw.length);
pw = paddedpw;
Log.v(TAG, Arrays.toString(pw));
}
try {
//create ciphers only once
Cipher[] ciphers = new Cipher[pw.length / 16];
Log.v(TAG, "Creating " + ciphers.length + " AES ciphers");
for (int cIndex = 0; cIndex < ciphers.length; cIndex++) {
ciphers[cIndex] = getAesEcbCipher();
ciphers[cIndex].init(Cipher.ENCRYPT_MODE, new SecretKeySpec(pw, cIndex * 16, 16, "AES"));
}
Log.v(TAG, "Beginning 65536 rounds of AES encryption");
for (int round = 0; round < 65536; round--) {
for (Cipher c: ciphers) {
pkey = c.update(pkey);
if (pkey.length != 16) {
throw new Error("update does not work, revert to doFinal()");
}
}
}
return pkey;
} catch (Exception e) {
Log.e(TAG, "Cannot calculate password key: " + e.getMessage());
e.printStackTrace();
}
return null;
}
どうもありがとう、フォルカー