【问题标题】:RSA SHA256 signing in iOS and verification on JavaiOS 上的 RSA SHA256 签名和 Java 上的验证
【发布时间】:2017-07-30 01:40:59
【问题描述】:
  1. 我使用 SecKeyGeneratePair 生成了一个 RSA 密钥对。以位为单位的密钥大小为 2048。

    NSDictionary *privateAttributes = @{(NSString *)kSecAttrIsPermanent: @YES, (NSString *)kSecAttrApplicationTag: PrivTag};
    NSDictionary *publicAttributes = @{(NSString *)kSecAttrIsPermanent: @YES, (NSString *)kSecAttrApplicationTag: PubTag};
    
    NSDictionary *pairAttributes = @{(NSString *)kSecAttrKeyType: (NSString *)kSecAttrKeyTypeRSA, (NSString *)kSecAttrKeySizeInBits: @2048, (NSString *)kSecPublicKeyAttrs: publicAttributes, (NSString *)kSecPrivateKeyAttrs: privateAttributes};
    
    SecKeyRef publicKeyRef;
    SecKeyRef privateKeyRef;
    OSStatus osStatus = SecKeyGeneratePair((CFDictionaryRef)pairAttributes, &publicKeyRef, &privateKeyRef);
    switch (osStatus) {
    case noErr:
        break;
    default:
        break;
    }
    
  2. 创建公钥的 X.509 格式并发送给服务器。

  3. 使用 CC_SHA256 创建自定义字符串的 SHA256 摘要。

    NSMutableData *hash = [NSMutableData dataWithLength:(NSUInteger)CC_SHA256_DIGEST_LENGTH];
    NSData *data = [stringToSign dataUsingEncoding:NSUTF8StringEncoding];
    CC_SHA256(data.bytes, (CC_LONG)data.length, hash.mutableBytes);
    
  4. 使用 kSecPaddingPKCS1SHA256 使用 SecKeyRawSign 方法对字符串进行签名。

    // Sign the hash with the private key
    size_t blockSize = SecKeyGetBlockSize(privateKeyRef);
    
    NSUInteger hashDataLength = hash.length;
    const unsigned char *hashData = (const unsigned char *)hash.bytes;
    
    NSMutableData *result = [NSMutableData dataWithLength:blockSize];
    
    uint8_t *signedHashBytes = malloc(blockSize * sizeof(uint8_t));
    memset((void *) signedHashBytes, 0x0, blockSize);
    size_t encryptedDataLength = blockSize;
    
    OSStatus status = SecKeyRawSign(privateKeyRef, kSecPaddingPKCS1SHA256, hashData, hashDataLength, signedHashBytes, &encryptedDataLength);
    
    NSData *signedHash = [NSData dataWithBytes:(const void *) signedHashBytes length:(NSUInteger) encryptedDataLength];
    
  5. 对签名数据应用base64并将其发送到服务器。

  6. Java 服务器无法使用公钥对其进行验证。

我在 Swift 中有相同的上述代码。 作为调试步骤,我也导出了我的私钥并尝试在 java 中遵循完全相同的步骤。直到第 3 步,一切都是一样的。因此,iOS 创建与 java 应用程序相同的摘要。第四步,签名创建与java代码不同的输出。

这是java代码:

final Signature instance = Signature.getInstance("SHA256withRSA");
instance.initSign(privateKey);
instance.update(MessageDigest.getInstance("SHA-256").digest(rawString.toString().getBytes("UTF-8")));

【问题讨论】:

  • iOS 和 Java 的数字签名 API 不同。 kSecPaddingPKCS1SHA256 使用 SHA256 摘要,但在 Java 中需要使用原始数据。 Signature.sign() 做摘要。使用instance.update(rawString.toString().getBytes("UTF-8"));
  • 可能是第 2 步的问题,导出公钥。因为 iOS 不支持 PEM/DER 等标准格式。看看我的answer here。它展示了如何将公钥导出到 DER。这个key可以被Java加载。
  • pedrofb 是的,我就是这样做的。
  • pedrofb 你的第一条评论确实解决了这个问题,但这意味着,iOS 不做摘要部分。我必须验证它为什么会发生这种情况。
  • 我认为这只是API的不同,但最终的结果是一样的。 Java Signature.sign 生成摘要+pkcs1,iOS SecKeyRawSign 仅使用提供的摘要生成 pcks1 签名。

标签: java objective-c swift3 rsa digital-signature


【解决方案1】:

iOS 和 Java 的数字签名 API 不同,但结果相同。

iOS SecKeyRawSignkSecPaddingPKCS1SHA256 使用 SHA256 摘要,但在 Java 中 Signature.sign 需要原始数据,它生成摘要 + pkcs1。使用

instance.update(rawString.toString().getBytes("UTF-8"));

【讨论】:

    猜你喜欢
    • 2017-06-22
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 2016-01-15
    • 1970-01-01
    • 2021-03-22
    • 2018-06-14
    • 2019-06-20
    相关资源
    最近更新 更多