我已成功以AES格式在BlackBerry中加密数据。为了验证我的结果,我尝试使用以下方法在BlackBerry中实现解密:
private static byte[] decrypt( byte[] keyData, byte[] ciphertext )throws CryptoException, IOException
{
// First, create the AESKey again.
AESKey key = new AESKey( keyData );
// Now, create the decryptor engine.
AESDecryptorEngine engine = new AESDecryptorEngine( key );
// Since we cannot guarantee that the data will be of an equal block length
// we want to use a padding engine (PKCS5 in this case).
PKCS5UnformatterEngine uengine = new PKCS5UnformatterEngine( engine );
// Create the BlockDecryptor to hide the decryption details away.
ByteArrayInputStream input = new ByteArrayInputStream( ciphertext );
BlockDecryptor decryptor = new BlockDecryptor( uengine, input );
// Now, read in the data. Remember that the last 20 bytes represent
// the SHA1 hash of the decrypted data.
byte[] temp = new byte[ 100 ];
DataBuffer buffer = new DataBuffer();
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
byte[] plaintextAndHash = buffer.getArray();
int plaintextLength = plaintextAndHash.length - SHA1Digest.DIGEST_LENGTH;
byte[] plaintext = new byte[ plaintextLength ];
byte[] hash = new byte[ SHA1Digest.DIGEST_LENGTH ];
System.arraycopy( plaintextAndHash, 0, plaintext, 0, plaintextLength );
System.arraycopy( plaintextAndHash, plaintextLength, hash, 0,
SHA1Digest.DIGEST_LENGTH );
// Now, hash the plaintext and compare against the hash
// that we found in the decrypted data.
SHA1Digest digest = new SHA1Digest();
digest.update( plaintext );
byte[] hash2 = digest.getDigest();
if( !Arrays.equals( hash, hash2 )) {
throw new RuntimeException();
}
return plaintext;
}
我在下一行抛出“BadPaddingException”异常
int bytesRead = decryptor.read( temp );
任何人都可以帮忙。
答案 0 :(得分:2)
我认为问题可能出在这个块中:
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
当read
返回-1时,您也将其写入缓冲区。退出条件也是错误的。将其与CryptoDemo示例项目中的块进行比较:
for( ;; ) {
int bytesRead = decryptor.read( temp );
if( bytesRead <= 0 )
{
// We have run out of information to read, bail out of loop
break;
}
db.write(temp, 0, bytesRead);
}
还有几点你应该小心,即使它们没有导致错误:
AESDecryptorEngine engine = new AESDecryptorEngine( key );
如果您阅读the docs for this constructor,则会说:
“给定AES密钥,创建AESEncryptorEngine类的实例 默认块长度为16个字节。“
但是在上一行中,当您创建密钥时,您正在执行此操作:
AESKey key = new AESKey( keyData );
哪个according to the docs,它“从现有数据中创建可能的最长密钥。”,但只有“使用数组的前128位” 。因此,keyData
的长度无关紧要,您将始终使用128位密钥长度,这是3种可用大小中最短的(128,192,256)。
相反,您可以明确选择算法 block 键长度。例如,要使用AES-256:
AESKey key = new AESKey(keyData, 0, 256); //key length in BITS
AESDecryptorEngine engine = new AESDecryptorEngine(key, 32); //key lenth IN BYTES
最后,即使你使这个工作,你应该知道直接从密码(可能是任意大小)导出密钥是不安全的。您可以使用PKCS5KDF2PseudoRandomSource从密钥材料(密码)派生更强的密钥,而不是仅使用PKCS5进行填充。
答案 1 :(得分:1)
您的加密数据应正确填充到块大小(16个字节)。 尝试在没有填充的情况下解密数据,并查看尾部字节是否对应于PKCS#5填充(例如,如果需要5个字节的填充,则应附加0x05 0x05 0x05 0x05 0x05字节)。
答案 2 :(得分:0)
问题是具有正确块大小的任何数据都将被解密。问题在于它可能会解密为随机垃圾。随机查看垃圾通常不兼容PKCS#7填充方案,因此例外。
我说问题是因为如果密钥数据无效,如果使用了错误的填充或块模式,或者只是在输入过程中输入数据出现乱码,则可能抛出此异常。调试此方法的最佳方法是100%确保算法匹配,并且二进制输入参数(包括API的默认值)在两侧都精确匹配。