我有一个公钥从
Java服务器发送. base64编码的字符串在解码和删除ASN.1标头之前匹配.我使用SecItemAdd将公钥存储在钥匙扣中.
所以我试图使用公钥加密数据,并用Java中的私钥进行解密.我在iOS端使用SecKeyEncrypt,在Java端使用Cipher.
我加密的是加密我的实际数据的对称AES密钥,因此密钥长度为16字节.当简单的base64编码的关键,一切都有效,所以我知道这个RSA加密有问题.
以下是我的iOS电话示例:
OSStatus sanityCheck = SecKeyEncrypt(publicKey,
kSecPaddingPKCS1,
(const uint8_t *) [incomingData bytes],
keyBufferSize,
cipherBuffer,
&cipherBufferSize
);
以下是我的Java调用示例:
public static byte[] decryptMessage (byte[] message, PrivateKey privateKey, String algorithm) {
if (message == null || privateKey == null) {
return null;
}
Cipher cipher = createCipher(Cipher.DECRYPT_MODE, privateKey, algorithm, false);
if (cipher == null) {
return null;
}
try {
return cipher.doFinal(message);
}
catch (IllegalBlockSizeException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
}
catch (BadPaddingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
}
}
private static Cipher createCipher (int mode, Key encryptionKey, String algorithm, boolean useBouncyCastle) {
Cipher cipher;
try {
if (useBouncyCastle) {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher = Cipher.getInstance(algorithm, "BC");
}
else {
cipher = Cipher.getInstance(algorithm);
}
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
}
catch (NoSuchPaddingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
}
catch (NoSuchProviderException e) {
e.printStackTrace();
return null;
}
try {
cipher.init(mode, encryptionKey);
}
catch (InvalidKeyException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
}
return cipher;
}
我尝试了很多组合,没有任何工作.
> iOS:PKCS1,Java:RSA / ECB / PKCS1Padding
> iOS:PKCS1,Java:RSA
> iOS:PKCS1,Java:RSA / None / PKCS1Padding(throws org.bouncycastle.crypto.DataLengthException:输入对于RSA密码太大)
> iOS:OAEP,Java:RSA / ECB / OAEPWithSHA-1AndMGF1Padding
> iOS:OAEP,Java:RSA / ECB / OAEPWithSHA-256AndMGF1Padding
我也尝试使用内部Java提供程序以及BouncyCastle提供程序.每次抛出javax.crypto.BadPaddingException,但每个组合的消息是不同的.一些显示数据必须从零开始,而其他消息大于模数.
iOS:PKCS1,Java:RSA不会引发异常,但生成的解密字节[]数组应为长度16,但长度为256,这意味着填充未正确删除.
有人可以帮忙吗?
***编辑***
当我在做更多的测试时,我遇到了这个页面(http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/pkcs/pkcs1/RSACipher.html),这本质上告诉我,RSA == RSA / None / PKCS1Padding.解密的工作原理是没有例外,但是我仍然得到一个解密的密钥,其字节[]是长度256而不是长度16.
另一个兴趣点.看来,如果Java服务器具有从iOS设备生成并使用Cipher.getInstance(“RSA”)加密的公钥,则手机能够使用RSA / PKCS1正确解码该消息.
***编辑2 ***
我已经看过这些教程,并在iOS端再次查看了我的代码:
据我所知,我的代码正在做一切正常.一个显着的区别是我如何保存密钥,所以我尝试保存它的另一种方式:
OSStatus error = noErr;
CFTypeRef persistPeer = NULL;
NSMutableDictionary * keyAttr = [[NSMutableDictionary alloc] init];
keyAttr[(__bridge id) kSecClass] = (__bridge id) kSecClassKey;
keyAttr[(__bridge id) kSecAttrKeyType] = (__bridge id) kSecAttrKeyTypeRSA;
keyAttr[(__bridge id) kSecAttrApplicationTag] = [secKeyWrapper getKeyTag:serverPublicKeyTag];
keyAttr[(__bridge id) kSecValueData] = strippedServerPublicKey;
keyAttr[(__bridge id) kSecReturnPersistentRef] = @YES;
error = SecItemAdd((__bridge CFDictionaryRef) keyAttr, (CFTypeRef *)&persistPeer);
if (persistPeer == nil || ( error != noErr && error != errSecDuplicateItem)) {
NSLog(@"Problem adding public key to keychain");
return;
}
CFRelease(persistPeer);
该保存成功,但最终结果是一样的:解密的AES密钥仍然是256字节长,而不是16字节.