当前位置: 首页 > 知识库问答 >
问题:

iOS验证数字签名

楚宏胜
2023-03-14

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

  1. nsstring创建seckeyref(取自此处)
  2. 根据原始消息创建SHA256摘要
  3. 使用seckeyrawverify函数
  4. 验证签名

(我正在努力避免使用OpenSSL函数)

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

下面是我的代码:

-(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个答案

柴声
2023-03-14

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

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

当然,您可能不希望硬编码参数,如所使用的散列函数(和散列长度)。

 类似资料:
  • 我有字节数组格式的公钥。在我的数据库里。像这样 在此处输入图像描述 总是suc=false。我确信bytetoverify的值与方法符号中的输入值相同。 我不知道我用这种方式生成公钥是问题还是符号有问题。在符号方法中,我使用sh1和pkcs1,但在验证中,我只找到sh1。 每个人都能帮我吗?

  • 我有一个电子签名/数字签名的PDF,该文档在分离签名中使用iText lib进行签名。我在验证签名时遇到问题,收到消息“签名者身份无效,因为它已过期或尚未有效”,并且在签名者信息中“构建从签名者证书到颁发者证书的路径时出错。” 我尝试了很多方法来验证签名,但都没有成功。如果我明确地将签名者证书添加为可信证书,那么我会得到一个绿色检查,并能够验证签名,但我认为这不是正确的方法。 数字签名的pdf可以

  • 我在iText web上遵循了这个示例(http://gitlab.itextsupport.com/itextsharp/tutorial/blob/master/signatures/chapter5/C5_03_CertificateValidation/C5_03_CertificateValidation.cs),但结果与我预期的不一样。具体地说,当试图通过OCSP或CRL验证签名时,结

  • 我的手被https、ssl、PKI之类的东西弄得脏兮兮的。对于自签名证书,有一点我不太理解。假设我想创建一个自签名证书,并在我们想要建立安全连接时将其发送给我的朋友。 所以步骤是: 创建一个私钥。 创建一个公钥。 用我的公钥在证书上签名。 因此,当我的朋友得到我的证书时,他必须验证他得到的证书是我的,他需要解密数字签名。但为了解密和验证他必须拥有我的私钥。所以,我有点困惑。

  • 为什么我的代码返回奇怪的结果? 我的代码给出了以下结果,它看起来不像是正确的计算结果:

  • 情况是我必须检查一个数字签名: 字符串1“A1005056807CE11EE2B4CE0025305725CFRCN=KED,OU=I0020266601,OU=SAPWebAS,O=SAPTrustCommunity,C=DE20130611102236”通过PKCS#7签名并通过HTTP-URL发送给我。 我在BASE64中获得签名的内容(在代码字符串sc中查找)。 现在我必须检查,如果Str