iOS验证数字签名

iOS验证数字签名,ios,cryptography,digital-signature,Ios,Cryptography,Digital Signature,在我的应用程序中,我有一个公钥(用字符串表示)、普通消息和数字签名(用base64编码的字符串表示、用SHA256散列、用RSA加密)。 现在,我需要验证数字签名。我试图做到以下几点: 从NSString创建SecKeyRef(取自) 从原始邮件创建SHA256摘要 使用SecKeyRawVerify功能验证签名 (我试图避免使用OpenSSL函数) 此外,我的数字签名是使用Java的SHA256withRSA方法创建的。我读到SHA256WithRSA将算法标识符附加到实际的散列中。现在,我不

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

  • NSString
    创建
    SecKeyRef
    (取自)
  • 从原始邮件创建SHA256摘要
  • 使用
    SecKeyRawVerify
    功能验证签名
  • (我试图避免使用OpenSSL函数)

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

    无论如何,在这两种情况下,我都得到了错误-50,根据苹果的文档,这意味着一个 传递给函数的一个或多个参数无效

    这是我的密码:

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

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

    事实证明,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方法生成的字节


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

    在调用SecKeyRawVerify之前,您需要将算法标识符预加载到使用CC_SHA256Hmm获得的“哈希”数组中。我看不出它在文档中的说明。对于这个论点,它说:“验证[签名]的数据,通常是实际数据的摘要”,因此我传递了实际数据的摘要(SHA256哈希)。你能详细说明一下吗?具体是什么格式?只是传递数据对你有用吗?我必须为实际的散列数据预先添加一个算法标识符。id-sha256:30 0b 06 09 60 86 48 01 65 03 04 02 01谢谢,@user3100783!了解Java签名类的这种行为真的很有帮助!