当前位置: 首页 > 面试题库 >

RSA:在iOS中加密,在Java中解密

宁锐
2023-03-14
问题内容

我有一个从Java服务器发送的公钥。在我解码并去除ASN.1标头之前,base64编码的字符串匹配。我使用将公钥存储在钥匙串中SecItemAdd

因此,我尝试使用公共密钥对数据进行加密,并使用Java中的私有密钥对其进行解密。我SecKeyEncrypt在iOS端和CipherJava端使用。

我正在加密的是对称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(抛出org.bouncycastle.crypto.DataLengthException: input too large for RSA cipher.
  • iOS:OAEP,Java:RSA / ECB / OAEPWithSHA-1AndMGF1Padding
  • iOS:OAEP,Java:RSA / ECB / OAEPWithSHA-256AndMGF1Padding

我还尝试过使用内部Java提供程序以及BouncyCastle提供程序。javax.crypto.BadPaddingException每次都会抛出该get,但是每种组合所传达的信息都是不同的。有的表演Data must start with zero,有的表演Message is larger than modulus

iOS: PKCS1, Java: RSA不抛出异常,但所得到的解密的byte[]阵列应该是长度16,但它的长度为256,这意味着填充未正确剥离出来。

有人可以帮忙吗?

*编辑 ***

在进行更多测试时,我偶然发现了此页面(http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/pkcs/pkcs1/RSACipher.html),该页面实际上告诉我RSA == RSA/None/PKCS1Padding。解密在没有异常的意义上起作用,但是我仍然得到一个解密的密钥,该密钥的byte
[]是长度256而不是长度16。

另一个兴趣点。看来,如果Java服务器具有从iOS设备生成的公钥,并且使用进行Cipher.getInstance("RSA")了加密,则电话能够使用RSA
/ PKCS1正确解码消息。

*编辑2 ***

我看过这些教程,并再次在iOS端浏览了我的代码:

  • http://blog.flirble.org/2011/01/05/rsa-public-key-openssl-ios/
  • http://blog.wingsofhermes.org/?p=42
  • http://blog.wingsofhermes.org/?p=75

据我所知,我的代码可以正确执行所有操作。一个显着的区别是我保存密钥的方式,因此我尝试用另一种方法保存它:

    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字节长。


问题答案:

我有同样的问题。是否有工作kSecPaddingNone,但
与工作kSecPaddingPKCS1有任何PKCS1Java代码组合。

但是,最好不填充使用它。

因此,在iOS上,替换kSecPaddingNone为Java代码kSecPaddingOAEPRSA/NONE/OAEPWithSHA1AndMGF1Padding在其中使用。这确实对我有用。



 类似资料:
  • 我用java加密一个单词,但用php解密时遇到了问题。 以下是我如何在android中创建密钥: 下面是我如何在android中使用生成的公钥加密单词: 然后我在android中将加密字符串转换为Bas64: 在php中,我解码base64字符串: 获取私钥: 最后,我尝试用php解密这个字符串: 我得到的错误是: 警告:openssl_private_decrypt():密钥参数不是有效的私钥.

  • 问题内容: 我需要用openssl生成的和密钥替换从Unix到Java代码的加密和解密步骤 我生成密钥 我在Unix中使用键(我需要在Java中执行) 这是我的尝试 但它不起作用,PKCS8EncodedKeySpec / X509EncodedKeySpec不正确…但是我不知道该放什么 问题答案: 我认为您在读取PEM文件时遇到问题。JPA不直接支持PEM格式。您有两种选择,要么将它们转换为DE

  • 我正在研究一个客户机-服务器安全协议,其中我需要使用Java中的RSA来加密HMAC摘要的SecretKey,因为密钥必须发送到服务器。加密分为两个阶段;首先,我需要用一个公共非对称密钥加密对称密钥,然后,该加密消息用一个私有非对称密钥加密。 为此,我将SecretKey生成为: 如何将SecretKey转换为字节数组,以便使用RSA和公钥对其进行加密? 由于公钥加密产生128字节的字节数组,如果

  • 我收到一个错误解密在C#中加密的消息(使用相应的公钥/私钥) 我的客户端是用C编写的,服务器是用Go编写的。我通过go的crypto/rsa包生成了一个私钥和公钥(使用rsa.GenerateKey(随机读取器,bits int))。然后,我将生成的公钥文件存储在客户端可以访问的地方,将私钥存储在服务器可以访问的地方。我使用以下代码(使用bouncy castle)在客户端上加密: go服务器从标