【问题标题】:X.509 RSA Encryption/Decryption iOSX.509 RSA 加密/解密 iOS
【发布时间】:2014-06-30 05:21:01
【问题描述】:

我需要使用 X.509 RSA 公钥/私钥对来实现加密/解密。

到目前为止,我有一些我认为可以用于加密的东西,但我无法解密检查。我尝试的一切都在读取私钥时出现问题。

生成密钥对(返回 .der.pem

openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem -days 3650

加密(不确定这是否有效,但看起来确实有效)

+ (NSData *) RSAEncryptData:(NSData *)content {
    SecKeyRef publicKey;
    SecCertificateRef certificate;
    SecPolicyRef policy;
    SecTrustRef trust;
    size_t maxPlainLen;

    NSString *publicKeyPath = [[NSBundle mainBundle] pathForResource:@"public_key" ofType:@"der"];
    NSData *base64KeyData = [NSData dataWithContentsOfFile:publicKeyPath];

    certificate = SecCertificateCreateWithData(kCFAllocatorDefault, ( __bridge CFDataRef) base64KeyData);
    if (certificate == nil) {
        NSLog(@"Can not read certificate from data");
        return nil;
    }

    policy = SecPolicyCreateBasicX509();
    OSStatus returnCode = SecTrustCreateWithCertificates(certificate, policy, &trust);
    if (returnCode != 0) {
        NSLog(@"SecTrustCreateWithCertificates fail. Error Code: %d", (int)returnCode);
        return nil;
    }

    SecTrustResultType trustResultType;
    returnCode = SecTrustEvaluate(trust, &trustResultType);
    if (returnCode != 0) {
        return nil;
    }

    publicKey = SecTrustCopyPublicKey(trust);
    if (publicKey == nil) {
        NSLog(@"SecTrustCopyPublicKey fail");
        return nil;
    }

    maxPlainLen = SecKeyGetBlockSize(publicKey) - 12;


    size_t plainLen = [content length];
    if (plainLen > maxPlainLen) {
        NSLog(@"content(%ld) is too long, must < %ld", plainLen, maxPlainLen);
        return nil;
    }

    void *plain = malloc(plainLen);
    [content getBytes:plain
               length:plainLen];

    size_t cipherLen = 128; // currently RSA key length is set to 128 bytes
    void *cipher = malloc(cipherLen);

    OSStatus encryptReturnCode = SecKeyEncrypt(publicKey, kSecPaddingPKCS1, plain,
                                        plainLen, cipher, &cipherLen);

    NSData *result = nil;
    if (encryptReturnCode != 0) {
        NSLog(@"SecKeyEncrypt fail. Error Code: %d", (int)returnCode);
    }
    else {
        result = [NSData dataWithBytes:cipher
                                length:cipherLen];
    }

    free(plain);
    free(cipher);

    return result;
}

解密

我尝试过使用 OpenSSL 的 PEM_read_X509PEM_read_RSAPrivateKey,但都无法读取证书。我什至没有过去。如果我可以在不依赖 OpenSSL 库的情况下做到这一点,那就更好了。

+(void)readTest{
    FILE *fp;
    X509 *x;
    NSString *path =[[NSBundle mainBundle] pathForResource:@"private_key" ofType:@"pem"];
    fp=fopen([path UTF8String],"r");

    x=NULL;
    PEM_read_X509(fp,&x,NULL,NULL); // I have also tried PEM_read_RSAPrivateKey

    if (x == NULL) {
        NSLog(@"Cant Read File"); // This ALWAYS fires
    }

    fclose(fp);
    X509_free(x);
}

如果有人可以帮助我使用 X.509 RSA 对进行加密/解密,我将不胜感激。谢谢。

【问题讨论】:

  • btw,证书过期一段时间后需要继续维护,推送这个应用的时候怎么维护?
  • 真正的应用程序只是使用他们的公钥加密发送给提供商的消息,该公钥是通过网络检索的。在实际使用中,解密是在服务器端完成的。
  • 我猜证书是无效的,因为它们是自签名的,看起来你需要想办法让它受信任
  • 是的,当然,根据你的实现,公钥仍然需要证书,你需要想出一些方法来更新你的证书,而且你应该想一个方法来获得证书,签名它与一些公司将它们转换为可信赖的公司,然后按时发送
  • 必须有一种方法可以在不购买 CA 信任的密钥对的情况下做到这一点?在这个用例中,密钥对验证和信任不是我的责任。

标签: ios objective-c encryption rsa x509


【解决方案1】:

你被困在哪里

您的私钥似乎已加密(openssl 在命令行上要求您输入密码),但是当您尝试打开它时并没有解密它。另外,private_key.pem 是 RSA 密钥,不是证书,所以你应该使用 PEM_read_RSAPrivateKey。

以下解码代码应该可以工作:

int pass_cb(char *buf, int size, int rwflag, void* password) {
    snprintf(buf, size, "%s", (char*) password);
    return strlen(buf);
}

+(void)readTest{
    FILE *fp;
    RSA *x;
    NSString *path =[[NSBundle mainBundle] pathForResource:@"private_key" ofType:@"pem"];
    fp=fopen([path UTF8String],"r");

    x = PEM_read_RSAPrivateKey(fp,&x,pass_cb,"key password");

    if (x == NULL) {
        NSLog(@"Cant Read File"); // This ALWAYS fires
    }

    fclose(fp);
    X509_free(x);
}

或者,您可以生成非加密密钥。在创建密钥和证书时将 -nodes 传递给 openssl。

请注意,您可能需要确保 OpenSSL 已正确初始化:

SSL_library_init();
OpenSSL_add_all_algorithms();

此外,OpenSSL 会生成可以帮助您完成开发的错误消息。您加载错误字符串:

SSL_load_error_strings();

你可以打电话:

ERR_print_errors_fp(stderr);

iOS上的RSA加解密

OpenSSL 不是唯一的解决方案,因为 iOS 上的安全框架包含您需要的一切。我猜你转向 OpenSSL 是因为你不知道如何将你的私钥文件转换为 SecKeyDecrypt 的有效参数。

诀窍是生成一个 PKCS#12 文件并调用SecPKCS12Import

您可以使用 OpenSSL 生成此文件:

openssl x509 -inform der -outform pem -in public_key.der -out public_key.pem
openssl pkcs12 -export -in public_key.pem -inkey private_key.pem -out private_key.p12

这将要求您输入导出密码。此密码应传递给 SecPKCS12Import("key password" 下面)。

NSString *privateKeyPath = [[NSBundle mainBundle] pathForResource:@"private_key" ofType:@"p12"];
NSData *pkcs12key = [NSData dataWithContentsOfFile:privateKeyPath];
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys: @"key password", kSecImportExportPassphrase, nil];
CFArrayRef              importedItems = NULL;
OSStatus returnCode = SecPKCS12Import(
                      (__bridge CFDataRef) pkcs12key,
                      (__bridge CFDictionaryRef) options,
                      &importedItems
                      );

importedItems 是一个数组,包含所有导入的 PKCS12 项,基本上就是“身份”(私钥 + 证书)。

NSDictionary* item = (NSDictionary*) CFArrayGetValueAtIndex(importedItems, 0);
SecIdentityRef  identity = (__bridge SecIdentityRef) [item objectForKey:(__bridge NSString *) kSecImportItemIdentity];
SecKeyRef privateKeyRef;
SecIdentityCopyPrivateKey(identity, &privateKeyRef);

然后你可以使用 privateKeyRef 来执行SecKeyDecrypt 的解密。要匹配您的加密例程:

size_t cipherLen = [content length];
void *cipher = malloc(cipherLen);
[content getBytes:cipher length:cipherLen];
size_t plainLen = SecKeyGetBlockSize(privateKeyRef) - 12;
void *plain = malloc(plainLen);

OSStatus decryptReturnCode = SecKeyDecrypt(privateKeyRef, kSecPaddingPKCS1, cipher, cipherLen, plain, &plainLen);

【讨论】:

  • 这很漂亮。我知道我的问题出在哪里 - 非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 2015-03-16
  • 1970-01-01
  • 2014-11-24
  • 1970-01-01
  • 1970-01-01
  • 2015-02-27
相关资源
最近更新 更多