RSA SHA256在iOS上签名并在Java上验证

时间:2017-03-09 07:23:11

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

  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服务器无法使用公钥验证它。
  7. 我在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")));
    

1 个答案:

答案 0 :(得分:2)

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

带有SecKeyRawSign的iOS kSecPaddingPKCS1SHA256使用SHA256摘要,但在Java Signature.sign中需要原始数据,它会生成摘要+ pkcs1。使用

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