我试图在iOS上使用带有kSecPaddingPKCS1的RSA(SecKeyEncrypt)加密AES密钥,然后使用RSA算法的标准java提供程序(javax.crypto)解密密钥。我成功接收了由java app生成的公钥,将其存储在iOS钥匙串中并使用它来加密aes密钥,但是当在java应用程序上接收时 - 我得到了众所周知的异常javax.crypto.BadPaddingException :数据必须从零开始。当我禁用填充(有时工作)时,相同的代码工作。那么在iOS上使用的填充与Java patform之间的区别在哪里?有人可以给我答案吗 - 我在这个问题上挣扎太久了。失去耐心。
源代码。 1)生成symetric键,2)使用我的java应用程序中的rsa公钥包装它。 (从公共密钥创建的模数和指数由java app发送给客户端)3)准备NSData:init加密密钥,附加aes加密数据,发送到java app。然后java应用程序获取前128个字节(加密的aes密钥)并尝试解密它,这里抛出异常。
[tools generateSymmetricKey];
NSData* encryptedSymetricKey = [tools wrapSymmetricKey:[tools getSymmetricKeyBytes] keyRef:[tools getPeerPublicKeyRef]];
int option = kCCOptionPKCS7Padding;
NSData* aesEncr = [tools doCipher:data key:[tools getSymmetricKeyBytes] context:kCCEncrypt padding:(CCOptions *)&option];
NSMutableData * result = [[NSMutableData alloc] initWithData:encryptedSymetricKey];
[result appendData:aesEncr];
以及从CryptoExercise借用的方法,这对我来说非常有用:
- (NSData *)wrapSymmetricKey:(NSData *)symmetricKey keyRef:(SecKeyRef)publicKey {
OSStatus sanityCheck = noErr;
size_t cipherBufferSize = 0;
size_t keyBufferSize = 0;
LOGGING_FACILITY( symmetricKey != nil, @"Symmetric key parameter is nil." );
LOGGING_FACILITY( publicKey != nil, @"Key parameter is nil." );
NSData * cipher = nil;
uint8_t * cipherBuffer = NULL;
// Calculate the buffer sizes.
cipherBufferSize = SecKeyGetBlockSize(publicKey);
keyBufferSize = [symmetricKey length];
if (kTypeOfWrapPadding == kSecPaddingNone) {
LOGGING_FACILITY( keyBufferSize <= cipherBufferSize, @"Nonce integer is too large and falls outside multiplicative group." );
} else {
LOGGING_FACILITY( keyBufferSize <= (cipherBufferSize - 11), @"Nonce integer is too large and falls outside multiplicative group." );
}
// Allocate some buffer space. I don't trust calloc.
cipherBuffer = malloc( cipherBufferSize * sizeof(uint8_t) );
memset((void *)cipherBuffer, 0x0, cipherBufferSize);
// Encrypt using the public key.
sanityCheck = SecKeyEncrypt( publicKey,
kSecPaddingPKCS1,
(const uint8_t *)[symmetricKey bytes],
keyBufferSize,
cipherBuffer,
&cipherBufferSize
);
LOGGING_FACILITY1( sanityCheck == noErr, @"Error encrypting, OSStatus == %d.", sanityCheck );
// Build up cipher text blob.
cipher = [NSData dataWithBytes:(const void *)cipherBuffer length:(NSUInteger)cipherBufferSize];
if (cipherBuffer) free(cipherBuffer);
return cipher;
}
还有一件事。在java方面,我使用RSA / ECB / PKCS1Padding密码实例。
我如何传输公钥: 由java生成的公钥解耦为模数和指数,然后将这两个值转换为原始字节数组并发送,然后在ios客户端再现它们,转换为ios密钥环兼容格式并插入密钥环。公钥是正确传输的,我比较了双方的模数和公共指数,它们是匹配的。公钥已经成功导入到ios上的密钥环中(这是通过BasicEncodingRules BER类别完成的)。我认为PKCS1padding填充支持肯定有问题 - 它必须在两个平台上都有所不同(可能与填充有关的计算需要ios上的一些额外的东西)。