通常、JCE 暗号は非常に基本的なものです。整合性とキーのテストを含む完全な機能の保護が必要な場合は、それらを組み合わせる必要があります。いつものように、自分でデバイスを作成しない方がよいでしょう。したがって、PKCS7/12 や PGP などのより高レベルの形式を選択することをお勧めします。
使用するパディングによっては、間違ったキーで解読しようとすると、一部の暗号で PaddingException が発生します。整合性チェックを強化するには、HMAC バイトで構成されるパディングを使用します。
JCE にはかなり完全なメソッドが含まれています。それは AESWrap アルゴリズムです。パディングされたデータが必要ですが、整合性が確保されます。RFC 3537 で説明されているように、長さバイトと組み合わせるのが最適です。これは、少量のシークレット (対称キーなど) のみを対象としていることに注意してください。RFC3537 パディングは 255 バイトに制限されています。
これをパスワード派生キーで使用するには、次を使用できます。
char[] pass = ... // your password
byte[] codeBytes = ... // up to 255 bytes you want to protect
// generate wrapping key from password
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16]; rand.nextBytes(salt);
SecretKey kek = f.generateSecret(new PBEKeySpec(pass, salt, 1000, 128));
kek = new SecretKeySpec(password.getEncoded(), "AES"); // convert into AES
// RFC3537 padding (lengthbyte)
byte[] wrappedCodeBytes = new byte[codeBytes + 1 % 8];
System.arraycopy(codeBytes,0,wrappedCodeBytes,1,wrappedCodeBytes.length);
paddedCodeBytes[0]=(byte)codeBytes.length;
byte[] pad = new byte[paddedCodeBytes.length - codeBytes.length -1]; rand.nextBytes(pad);
System.arraycopy(pad,0,paddedCodeBytes,codeBytes.length+1,pad.length);
// AESWrap is WRAP_MODE:needs a SecretKey
SecretKey paddedCodeKey = new SecretKeySpec(paddedCodeBytes, "RAW");
// now wrap the password with AESWrap kek is 128 bit
Cipher c = Cipher.getInstance("AESWrap"); // default IV
c.init(Cipher.WRAP_MODE, kek);
byte[] result = c.warp(paddedCodeKey);
アンラップは演習として読者に残します :) いずれにせよ、PBKDF2 からはより多くのエントロピーが期待できないため、コード例では 128 ビットのキーサイズを使用します。
これにより、間違ったパスワードが高い確率で検出されることに注意してください。批評家の中には、これを AESWrap の弱点と見なす人もいます。