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.cer
, signature.sig
和license.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; }