RSA:在iOS中加密,在Java中解密 [英] RSA: encrypt in iOS, decrypt in Java

查看:289
本文介绍了RSA:在iOS中加密,在Java中解密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a public key that's sent from a Java server. The base64 encoded strings match before I decode and strip out the ASN.1 headers. I store the public key in the keychain with SecItemAdd.

所以我正在尝试使用以下方法加密数据公钥并使用Java中的私钥对其进行解密。我在iOS端使用 SecKeyEncrypt ,在Java端使用 Cipher

So I'm trying to encrypt the data using the public key and decrypt it with the private key in Java. I'm using SecKeyEncrypt on the iOS side and Cipher on the Java side.

我正在加密的是加密我的实际数据的对称AES密钥,因此密钥长度为16个字节。当简单地对base64进行编码时,一切正常,所以我知道这个RSA加密有问题。

What I'm encrypting is the symmetric AES key that encrypts my actual data, so the key length is 16 bytes. When simply base64 encoding the key, everything works, so I know something is wrong with this RSA encryption.

以下是我的iOS调用示例:

Here's an example of my iOS call:

OSStatus sanityCheck = SecKeyEncrypt(publicKey,
        kSecPaddingPKCS1,
        (const uint8_t *) [incomingData bytes],
        keyBufferSize,
        cipherBuffer,
        &cipherBufferSize
);

以下是我的Java调用示例:

Here's an example of my Java call:

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;
}

我尝试了很多组合,没有任何效果。

I've tried so many combinations and nothing has worked.


  • iOS:PKCS1,Java:RSA / ECB / PKCS1Padding

  • iOS:PKCS1,Java:RSA

  • iOS:PKCS1,Java:RSA / None / PKCS1Padding(抛出 org.bouncycastle.crypto.DataLengthException:输入对于RSA密码而言太大。

  • iOS:OAEP,Java:RSA / ECB / OAEPWithSHA-1AndMGF1Padding

  • iOS:OAEP,Java:RSA / ECB / OAEPWithSHA-256AndMGF1Padding

  • iOS: PKCS1, Java: RSA/ECB/PKCS1Padding
  • iOS: PKCS1, Java: RSA
  • iOS: PKCS1, Java: RSA/None/PKCS1Padding (throws 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 ,但每个组合的消息都不同。一些显示数据必须以零开头,而其他显示消息大于模数

I've also tried using the internal Java provider as well as the BouncyCastle provider. The javax.crypto.BadPaddingException gets thrown every time, but the message is different for each combination. Some show Data must start with zero, while others are Message is larger than modulus.

iOS:PKCS1,Java:RSA 不会抛出异常,但产生的解密 byte [] 数组应该是长度为16,但它的长度为256,这意味着填充没有被正确地删除。

The iOS: PKCS1, Java: RSA doesn't throw an exception, but the resulting decrypted byte[] array should be length 16, but it's length 256, which means the padding isn't correctly stripped out.

有人可以帮忙吗?

*** 编辑 ***

当我正在做更多测试时,我发现了这个页面( http://javadoc.iaik。 tugraz.at/iaik_jce/current/iaik/pkcs/pkcs1/RSACipher.html ),它基本上告诉我 RSA == RSA / None / PKCS1Padding 。解密工作的意义是没有异常,但我仍然得到一个解密密钥,其byte []长度为256而不是长度为16。

As I'm doing more testing, I came across this page (http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/pkcs/pkcs1/RSACipher.html), which essentially tells me that RSA == RSA/None/PKCS1Padding. The decryption works in the sense that there are no exceptions, but I'm still getting a decrypted key whose byte[] is length 256 instead of length 16.

另一点出于兴趣。似乎如果Java服务器具有从iOS设备生成并使用 Cipher.getInstance(RSA)加密的公钥,则手机能够正确解码消息使用RSA / PKCS1。

Another point of interest. It seems that if the Java server has the public key generated from the iOS device and encrypted using Cipher.getInstance("RSA"), the phone is able to decode the message correctly with RSA/PKCS1.

*** 编辑2 ***

我已经查看了这些教程并在iOS端再次查看了我的代码:

I have looked at these tutorials and looked through my code again on the iOS side:

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

据我所知,我的代码是做正确的事。一个显着的区别在于我如何保存密钥,所以我尝试以另一种方式保存它:

As far as I can tell, my code is doing everything correctly. One significant difference was in how I was saving the key, so I tried saving it the other way:

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

That save was successful, but the end result was the same: the decrypted AES key was still 256 bytes long instead of 16 bytes.

推荐答案

我遇到了同样的问题。适用于 kSecPaddingNone ,但使用 kSecPaddingPKCS1 使用任何 PKCS1 Java代码中的组合。

I had same problem. Does work with kSecPaddingNone, but doesn't work with kSecPaddingPKCS1 with any PKCS1 combination in Java code.

但是,不使用填充来使用它不是一个好主意。

But, it's not good idea to use it without padding.

因此,在iOS上,用 kSecPaddingOAEP 替换 kSecPaddingNone 并使用 Java代码中的RSA / NONE / OAEPWithSHA1AndMGF1Padding 。这对我有用。

So, on iOS, replace kSecPaddingNone with kSecPaddingOAEP and use RSA/NONE/OAEPWithSHA1AndMGF1Padding in your Java code. This does work for me.

这篇关于RSA:在iOS中加密,在Java中解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆