【问题标题】:Signing and Verifying on iOS using RSA使用 RSA 在 iOS 上签名和验证
【发布时间】:2014-03-10 13:35:27
【问题描述】:

如何在 iOS 上使用 RSA 密钥对一些数据进行签名和验证(最好使用系统自带的libcommonCrypto)?

【问题讨论】:

  • RSA 密钥在哪里(复数,因为用于验证和签名的公共和私人部分)?它们是在钥匙串中,还是在 PEM 或 DER 格式的外部?
  • 如问题中所述,我更喜欢使用 libcommonCrypto。这意味着在程序员看来,密钥可用作SecKeyRef(在内存引用中,可能源自钥匙串、PEM 或 Apple 安全框架支持的任何其他内容)。密钥的类型对我的问题无关紧要,但目前我将所有密钥(自己的私钥和一些公钥)存储在设备沙盒钥匙串中。
  • 您是否尝试使用 RSA 使用公钥/私钥加密/解密某些数据?
  • 加密和解密数据有据可查,我已经完成了。是的,我知道签名和验证是如何工作的,所以我可以实现自己的解决方案。但我想知道在这样一个有用的框架中没有任何实现。 (比如java.security.Signature。)
  • 如果您的设备上有公钥和私钥,加密的目的是什么?那不是还很脆弱吗?

标签: ios rsa pkcs#7 commoncrypto


【解决方案1】:

其实简单多了,不用手动创建hash

func validateRSASignature(signedData: Data, signature: Data, publicKeyData: Data) -> Bool {

    // Create a SecKey instance from the public key data.
    let publicKey: SecKey! = SecKeyCreateWithData(publicKeyData as NSData, [
        kSecAttrKeyType: kSecAttrKeyTypeRSA,
        kSecAttrKeyClass: kSecAttrKeyClassPublic
    ] as NSDictionary, nil)

    // Verify the RSA signature.
    return SecKeyVerifySignature(publicKey,
                                 .rsaSignatureMessagePKCS1v15SHA512,
                                 signedData as NSData,
                                 signature as NSData,
                                 nil)
}

从 iOS 10 开始这应该是可能的。如果您的关键数据和其他输入发生变化,您可能希望扩展错误处理。

【讨论】:

    【解决方案2】:

    由于在 StackOverflow 和 Apple 文档上几乎没有任何关于签名和验证的知识,我不得不手动浏览 iOS 头文件并找到 SecKeyRawSignSecKeyRawVerify。以下代码行似乎有效。


    签署 NSData(使用 SHA256 和 RSA):

    NSData* PKCSSignBytesSHA256withRSA(NSData* plainData, SecKeyRef privateKey)
    {
        size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey);
        uint8_t* signedHashBytes = malloc(signedHashBytesSize);
        memset(signedHashBytes, 0x0, signedHashBytesSize);
    
        size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;
        uint8_t* hashBytes = malloc(hashBytesSize);
        if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) {
            return nil;
        }
    
        SecKeyRawSign(privateKey,
                      kSecPaddingPKCS1SHA256,
                      hashBytes,
                      hashBytesSize,
                      signedHashBytes,
                      &signedHashBytesSize);
    
        NSData* signedHash = [NSData dataWithBytes:signedHashBytes
                                            length:(NSUInteger)signedHashBytesSize];
    
        if (hashBytes)
            free(hashBytes);
        if (signedHashBytes)
            free(signedHashBytes);
    
        return signedHash;
    }
    

    验证(使用 SHA256 和 RSA):

    BOOL PKCSVerifyBytesSHA256withRSA(NSData* plainData, NSData* signature, SecKeyRef publicKey)
    {
        size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey);
        const void* signedHashBytes = [signature bytes];
    
        size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;
        uint8_t* hashBytes = malloc(hashBytesSize);
        if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) {
            return nil;
        }
    
        OSStatus status = SecKeyRawVerify(publicKey,
                                          kSecPaddingPKCS1SHA256,
                                          hashBytes,
                                          hashBytesSize,
                                          signedHashBytes,
                                          signedHashBytesSize);
    
        return status == errSecSuccess;
    }
    

    替代方案 (OpenSSL):

    有一个非常好的替代方案,它直接利用 OpenSSL 而不是 libCommonCrypto。 MIHCrypto 是一个精心设计的用于 OpenSSL 的 Objective-C 包装库,它使密码学的工作变得非常容易。请参阅下面的示例。

    生成密钥就是这么简单:

    MIHAESKeyFactory *factory = [[MIHAESKeyFactory alloc] init];
    id<MIHSymmetricKey> aesKey = [factory generateKey];
    

    或从文件中加载密钥:

    NSData *privateKeyData = [[NSFileManager defaultManager] contentsAtPath:"mykey.pem"];
    MIHRSAPrivateKey *privateKey = [[MIHRSAPrivateKey alloc] initWithData:privateKeyData];
    

    现在签署一些东西:

    NSError *signingError = nil;
    NSData *message = // load something to sign from somewhere
    NSData *signature = [privateKey signWithSHA256:message error:&signingError]
    

    有关更多示例,请浏览MIHCrypto 页面。

    【讨论】:

    • 如果在 Swift 中有类似的 SecKeyRawSignSecKeyRawVerify 示例,那就太好了。如果有人成功了,请在此处链接/粘贴。当我让它工作时也会这样做。
    • 运气好吗?我真的需要帮助! stackoverflow.com/questions/32759385/…
    • 别忘了导入
    • 效果很好!唯一的问题是当我在 C# 中验证签名时,结果总是错误的。它与 C# 中的 RSACryptoServiceProvider 兼容吗?
    猜你喜欢
    • 2016-01-15
    • 2017-07-30
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    相关资源
    最近更新 更多