iOS验证数字签名 [英] iOS verify digital signature

查看:503
本文介绍了iOS验证数字签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my application, I have a public key (represented as string), plain message and digital signature, represented as base64 encoded string, hashed with SHA256 and encrypted with RSA). Now, I need to verify digital signature. I was trying to do as follows:


  1. 创建 SecKeyRef NSString (摘自 here

  2. 使用原始邮件创建SHA256摘要

  3. 使用验证签名SecKeyRawVerify function

  1. create SecKeyRef from NSString (taken from here)
  2. create SHA256 digest from original message
  3. verify signature using SecKeyRawVerify function

(我想避免使用OpenSSL函数)

(I am trying to avoid using OpenSSL function)

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

Additionally, my digital signature was created using Java's SHA256withRSA method. I was reading here that SHA256WithRSA appends algorithm identifier with the actual hash. Now, I am not sure whether or not I need to append it to the hash.

无论如何,在这两种情况下,我得到错误-50,根据苹果的文档意味着

Anyway, in both cases I get error -50, which according to Apple's documentations means One or more parameters passed to a function were not valid.

这是我的代码:

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

}


推荐答案

回答有点晚,但我有同样的问题。

Maybe this answer is a little late but I had the same problem.

事实证明,Java处理哈希为你,但iOS不。

It turns out that Java handles the hashing for you, but iOS does not.

因此,如果你有一个名为 plainText 的纯文本,你可以在Java上生成一个签名,这样做:

So if you have a plaintext called plainText you might generate a signature on it in Java doing this:

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中验证它,使用如下的明文散列:

But then to verify it in iOS you need to manually take a hash of the plaintext like so:

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

在上述方法中,签名是由Java方法生成的字节。

In the above method, signature is the bytes generated by the Java method.

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

Of course, you may not want to hardcode parameters such as the the hash function used (and length of hash).

这篇关于iOS验证数字签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆