iOSvalidation数字签名
在我的应用程序中,我有一个公钥(表示为字符串),普通消息和数字签名,表示为base64编码的字符串,用SHA256散列并用RSA加密)。 现在,我需要validation数字签名。 我试图做如下:
- 从
NSString
创建SecKeyRef
(取自此处 ) - 从原始邮件创建SHA256摘要
- 使用
SecKeyRawVerify
函数validation签名
(我试图避免使用OpenSSLfunction)
另外,我的数字签名是使用Java的SHA256withRSA方法创建的。 我在这里读到SHA256WithRSA将算法标识符附加到实际哈希。 现在,我不确定是否需要将其附加到哈希。
无论如何,在这两种情况下我得到错误-50,根据Apple的文档意味着传递给函数的一个或多个参数无效。
这是我的代码:
-(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; }
也许这个答案有点晚,但我遇到了同样的问题。
事实certificate,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中validation它,你需要手动获取明文的哈希值,如下所示:
+ (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方法生成的字节。
当然,您可能不想硬编码参数,例如使用的哈希函数(以及哈希的长度)。