iOS验证数字签名

时间:2014-01-09 14:10:28

标签: ios cryptography digital-signature

在我的应用程序中,我有一个公钥(表示为字符串),普通消息和数字签名,表示为base64编码的字符串,用SHA256散列并用RSA加密)。 现在,我需要验证数字签名。我试图做如下:

  1. SecKeyRef(取自here
  2. 创建NSString
  3. 从原始消息创建SHA256摘要
  4. 使用SecKeyRawVerify函数
  5. 验证签名

    (我试图避免使用OpenSSL功能)

    此外,我的数字签名是使用Java的SHA256withRSA方法创建的。我正在阅读here SHA256WithRSA将算法标识符附加到实际哈希值。现在,我不确定是否需要将其附加到哈希。

    无论如何,在这两种情况下我都会得到错误-50,根据Apple的文档,这意味着 One 传递给函数的更多参数无效。

    这是我的代码:

    -(BOOL) verifySignature:(NSString*) rawData andKey:(NSString*) key andSignature:(NSString*)signature {
    
        NSData* originalData = [rawData dataUsingEncoding:NSUTF8StringEncoding];
        NSData *signatureData = [NSData dataFromBase64String:signature];
    
        SecKeyRef publicKey = [self generatePublicKey:key];
    
        uint8_t sha2HashDigest[CC_SHA256_DIGEST_LENGTH];
        CC_SHA256([originalData bytes], [originalData length], sha2HashDigest);
    
        //DO I NEED THIS?
        NSString *algIdentifier = @"1.3.14.3.2.26";
        NSData *algData = [algIdentifier dataUsingEncoding:NSUTF8StringEncoding];
        NSData* d_hash = [NSData dataWithBytes:sha2HashDigest length:CC_SHA256_DIGEST_LENGTH];
    
        NSMutableData *concatenatedData = [NSMutableData data];
        [concatenatedData appendData:algData];
        [concatenatedData appendData:d_hash];
    
        OSStatus verficationResult =  SecKeyRawVerify (publicKey,
                         kSecPaddingPKCS1SHA256,
                         (const uint8_t *)[d_hash bytes],
                         (size_t)[d_hash length],
                         (const uint8_t *)[signatureData bytes],
                         (size_t)[signatureData length]
                         );
    
    
        CFRelease(publicKey);
    
        if (verficationResult == errSecSuccess){
            NSLog(@"Verified");
            return YES;
        }
        return NO;
    
    }
    
    - (SecKeyRef)generatePublicKey:(NSString *)key
    {
    
        // This will be base64 encoded, decode it.
        NSData *d_key = [NSData dataFromBase64String:key];
        d_key = [self stripPublicKeyHeader:d_key];
        if (d_key == nil) return(nil);
    
        NSData *d_tag = [NSData dataWithBytes:[@"pubKey" UTF8String] length:[@"pubKey" length]];
    
        NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
        [publicKey setObject:(id) kSecClassKey forKey:(id)kSecClass];
        [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
        [publicKey setObject:d_tag forKey:(id)kSecAttrApplicationTag];
        SecItemDelete((CFDictionaryRef)publicKey);
    
        CFTypeRef persistKey = nil;
    
        // Add persistent version of the key to system keychain
        [publicKey setObject:d_key forKey:(id)kSecValueData];
        [publicKey setObject:(id) kSecAttrKeyClassPublic forKey:(id)
         kSecAttrKeyClass];
        [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)
         kSecReturnPersistentRef];
    
        OSStatus secStatus = SecItemAdd((CFDictionaryRef)publicKey, &persistKey);
        if (persistKey != nil) CFRelease(persistKey);
    
        if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) {
            [publicKey release];
            return(nil);
        }
    
        // Now fetch the SecKeyRef version of the key
        SecKeyRef keyRef = nil;
    
        [publicKey removeObjectForKey:(id)kSecValueData];
        [publicKey removeObjectForKey:(id)kSecReturnPersistentRef];
        [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef
         ];
    
        [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
        secStatus = SecItemCopyMatching((CFDictionaryRef)publicKey,
                                        (CFTypeRef *)&keyRef);
    
        [publicKey release];
        return keyRef;
    
    }
    

1 个答案:

答案 0 :(得分:3)

也许这个答案有点晚,但我遇到了同样的问题。

事实证明,Java为您处理散列,但iOS没有。

因此,如果您有一个名为plainText的明文,您可以在Java中生成一个签名:

public static byte[] sign(PrivateKey key, byte[] plainText) {
    try {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(key);
        signature.update(plainText);
        return signature.sign();
    } catch (Exception e) {
        return null;
    }
}

但是要在iOS中验证它,您需要手动获取明文的哈希值,如下所示:

+ (BOOL)verifySignature:(uint8_t*)signature signatureLen:(size_t)sLen
            withPlainText:(uint8_t*)plainText plainTextLen:(size_t)pLen
            andKey:(SecKeyRef)key {
    uint8_t hash[32];
    CC_SHA256(plainText, pLen, hash);
    OSStatus returnCode = SecKeyRawVerify(key,
                                          kSecPaddingPKCS1SHA256,
                                          hash,
                                          32,
                                          signature,
                                          sLen);
    return returnCode == 0;
}

在上面的方法中,signature是Java方法生成的字节。

当然,您可能不想硬编码参数,例如使用的哈希函数(以及哈希的长度)。