验证RSA签名iOS [英] Verifying RSA Signature iOS

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

问题描述

在我的静态库我有一个许可证文件。我想确保是由自己生成的(并没有被改变)。所以想法是使用从我已经阅读的RSA签名。

In my static Library I have a licence file. Which I want to make sure has been generated by myself (and has not been altered). So the idea was to use an RSA Signature from what I've read.

我看过互联网,这是我想出的:

I've looked on the internet and this is what I came up with:

私钥和自签名证书与我在此处找到的信息。

First: Generating the private keys and self signed certificates with the information I found here.

// 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

之后,我创建一个许可证文件(日期和应用程序标识符作为内容),并为该文件生成签名基于此处找到的信息:

After that, I create a licence file (with a date and app identifier as contents) and generate a signature for that file like so based on the information found here:

// 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

我认为一切都很好。我没有得到任何错误,并得到的钥匙和证书和其他文件,如预期。

Which I think all works fine. I don't get any errors and get the keys and certificates and other files as expected.

接下来我复制 certificate.cer signature.sig license.txt

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

Now I want to check if the signature has been signed by me and is valid for the license.txt. I found it fairly hard to find any good examples but this is what I have currently:

Seucyrity.Framework 我发现使用 SecKeyRef 引用RSA密钥/证书和 SecKeyRawVerify 来验证签名。

The Seucyrity.Framework I found out uses a SecKeyRef to reference an RSA key / certificate and SecKeyRawVerify to verify a signature.

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

I have the following method to load the public key from a file.

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

这是基于 SO post。

Which is based on this SO post.

对于签名验证,我找到以下函数

For the signature validation I found the following 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;
}

这取自这里

在我的项目中,我调用的代码如下:

In my project I call the code like so:

// 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文档中,我发现可能是由于已过期的证书。虽然这似乎不是这里的情况。但也许我生成证书的方式有问题吗?

Currently it always says: "Something went wrong!" though I am not sure what. I found out that trust result in the method that fetches the public key equals kSecTrustResultRecoverableTrustFailure which I think is the problem. In the Apple documentation I found that could be the result of a certificate that has been expired. Though that does not seem to be the case here. But maybe there is something wrong with the way I generate my certificate?

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

My question boils down to, what am I doing wrong, and how could I fix that? I find the documentation on this quite sparse and hard to read.

我有上传具有生成的证书和此处引用的代码的iOS项目。

I have uploaded an iOS project with generated certificates and the code referenced here. Maybe that could come in handy.

推荐答案

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

The problem is lying on the way you create the signature file; following the same step I was able to produce the binary equivalent signature.sig file.

code> hash 文件我们可以看到openssl添加一些前缀(和十六进制编码的哈希):

By looking inside the hash file we can see openssl add some prefix (and hex encode the hash):

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

c $ c> signature.sig 是基于 license.txt

So signature.sig is based on that and not on license.txt

通过使用您的示例并使用以下内容创建签名文件:

By using your sample and creating the signing file with:

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

签名步骤正确,并且示例输出:好了!

The hashing & signing step gets correct, and the sample outputs: Alright All good!

我的档案的最后状态,只是为了

The final state of my file, just in case

- (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相同的步骤(添加前缀,十六进制哈希和换行符 \\ n ),然后使用 kSecPaddingPKCS1 将此数据传递到 SecKeyRawVerify ,而不是 kSecPaddingPKCS1SHA256

To make your current signature.sig file work as-is, you have to produce the same step as openssl (add prefix, hex-hash, and a newline \n), then pass this data to SecKeyRawVerify with kSecPaddingPKCS1 and not 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;
}

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

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