validationRSA签名iOS

在我的静态库中,我有一个许可证文件。 我想确定的是我自己生成的(并没有被改变)。 所以这个想法是使用我读过的RSA签名。

我在互联网上看过,这就是我想到的:

首先:使用我在这里find的信息生成私钥和自签名证书。

// Generate private key openssl genrsa -out private_key.pem 2048 -sha256 // Generate certificate request openssl req -new -key private_key.pem -out certificate_request.pem -sha256 // Generate public certificate openssl x509 -req -days 2000 -in certificate_request.pem -signkey private_key.pem -out certificate.pem -sha256 // Convert it to cer format so iOS kan work with it openssl x509 -outform der -in certificate.pem -out certificate.cer -sha256 

之后,我创build一个许可证文件(以date和应用程序标识符作为内容),并根据以下信息生成该文件的签名:

 // Store the sha256 of the licence in a file openssl dgst -sha256 licence.txt > hash // And generate a signature file for that hash with the private key generated earlier openssl rsautl -sign -inkey private_key.pem -keyform PEM -in hash > signature.sig 

我认为所有的工作正常。 我没有得到任何错误,并得到按键和证书和其他文件的预期。

接下来,我将certificate.cersignature.siglicense.txt复制到我的应用程序中。

现在我想检查签名是否已经由我签名,并且对于license.txt有效。 我发现很难find任何好的例子,但这是我目前的:

我find的Seucyrity.Framework使用SecKeyRef来引用RSA密钥/证书和SecKeyRawVerify来validation签名。

我有以下方法从文件加载公钥。

 - (SecKeyRef)publicKeyFromFile:(NSString *) path { NSData *myCertData = [[NSFileManager defaultManager] contentsAtPath:path]; CFDataRef myCertDataRef = (__bridge CFDataRef) myCertData; SecCertificateRef cert = SecCertificateCreateWithData (kCFAllocatorDefault, myCertDataRef); CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **) &cert, 1, NULL); SecPolicyRef policy = SecPolicyCreateBasicX509(); SecTrustRef trust; SecTrustCreateWithCertificates(certs, policy, &trust); SecTrustResultType trustResult; SecTrustEvaluate(trust, &trustResult); SecKeyRef pub_key_leaf = SecTrustCopyPublicKey(trust); if (trustResult == kSecTrustResultRecoverableTrustFailure) { NSLog(@"I think this is the problem"); } return pub_key_leaf; } 

这是基于这个 SOpost。

对于签名validation,我发现了以下function

 BOOL PKCSVerifyBytesSHA256withRSA(NSData* plainData, NSData* signature, SecKeyRef publicKey) { size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey); const void* signedHashBytes = [signature bytes]; size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return nil; } OSStatus status = SecKeyRawVerify(publicKey, kSecPaddingPKCS1SHA256, hashBytes, hashBytesSize, signedHashBytes, signedHashBytesSize); return status == errSecSuccess; } 

这是从这里采取的

在我的项目中,我这样调用代码:

 // Get the licence data NSString *licencePath = [[NSBundle mainBundle] pathForResource:@"licence" ofType:@"txt"]; NSData *data = [[NSFileManager defaultManager] contentsAtPath:licencePath]; // Get the signature data NSString *signaturePath = [[NSBundle mainBundle] pathForResource:@"signature" ofType:@"sig"]; NSData *signature = [[NSFileManager defaultManager] contentsAtPath:signaturePath]; // Get the public key NSString *publicKeyPath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"cer"]; SecKeyRef publicKey = [self publicKeyFromFile:publicKeyPath]; // Check if the signature is valid with this public key for this data BOOL result = PKCSVerifyBytesSHA256withRSA(data, signature, publicKey); if (result) { NSLog(@"Alright All good!"); } else { NSLog(@"Something went wrong!"); } 

目前它总是说:“出错了!” 虽然我不知道是什么。 我发现信任导致提取公钥的方法等于kSecTrustResultRecoverableTrustFailure ,我认为这是问题。 在Apple文档中,我发现可能是由于证书已过期而导致的结果。 虽然这似乎并不是这种情况。 但是我的证书生成方式可能有问题吗?

我的问题归结为,我做错了什么,我怎么能解决这个问题? 我发现这个文档非常稀疏,很难阅读。

我已经上传了一个带有生成证书的iOS项目以及这里引用的代码。 也许这可能派上用场。

问题在于你创build签名文件的方式; 遵循相同的步骤,我能够生成二进制等效的signature.sig文件。

通过查看hash文件,我们可以看到openssl添加了一些前缀(和hex编码哈希):

 $ cat hash SHA256(licence.txt)= 652b23d424dd7106b66f14c49bac5013c74724c055bc2711521a1ddf23441724 

所以signature.sig是基于这个而不是license.txt

通过使用您的示例并创build签名文件:

 openssl dgst -sha256 -sign certificates/private_key.pem licence.txt > signature.sig 

哈希&签名步骤得到正确,并且示例输出: Alright All good!


为了以防万一,我的文件的最终状态

 - (SecKeyRef)publicKeyFromFile:(NSString *) path { NSData * certificateData = [[NSFileManager defaultManager] contentsAtPath:path]; SecCertificateRef certificateFromFile = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData); SecPolicyRef secPolicy = SecPolicyCreateBasicX509(); SecTrustRef trust; SecTrustCreateWithCertificates( certificateFromFile, secPolicy, &trust); SecTrustResultType resultType; SecTrustEvaluate(trust, &resultType); SecKeyRef publicKey = SecTrustCopyPublicKey(trust); return publicKey; } BOOL PKCSVerifyBytesSHA256withRSA(NSData* plainData, NSData* signature, SecKeyRef publicKey) { uint8_t digest[CC_SHA256_DIGEST_LENGTH]; if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], digest)) return NO; OSStatus status = SecKeyRawVerify(publicKey, kSecPaddingPKCS1SHA256, digest, CC_SHA256_DIGEST_LENGTH, [signature bytes], [signature length]); return status == errSecSuccess; } 

PS: malloc是一个泄漏


编辑:

要使当前的signature.sig文件按原样工作,必须产生与openssl(添加前缀,hex哈希和换行符\n )相同的步骤,然后使用kSecPaddingPKCS1将此数据传递给SecKeyRawVerify ,而不是kSecPaddingPKCS1SHA256

 BOOL PKCSVerifyBytesSHA256withRSA(NSData* plainData, NSData* signature, SecKeyRef publicKey) { uint8_t digest[CC_SHA256_DIGEST_LENGTH]; if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], digest)) return NO; NSMutableString *hashFile = [NSMutableString stringWithFormat:@"SHA256(licence.txt)= "]; for (NSUInteger index = 0; index < sizeof(digest); ++index) [hashFile appendFormat:@"%02x", digest[index]]; [hashFile appendString:@"\n"]; NSData *hashFileData = [hashFile dataUsingEncoding:NSNonLossyASCIIStringEncoding]; OSStatus status = SecKeyRawVerify(publicKey, kSecPaddingPKCS1, [hashFileData bytes], [hashFileData length], [signature bytes], [signature length]); return status == errSecSuccess; }