当前位置: 首页 > 知识库问答 >
问题:

X.509 RSA加密/解密iOS

钮安歌
2023-03-14
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;
}
+(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);
}

共有1个答案

司寇烨伟
2023-03-14

您的私钥似乎是加密的(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。

SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ERR_print_errors_fp(stderr);

诀窍是生成一个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
                      );
NSDictionary* item = (NSDictionary*) CFArrayGetValueAtIndex(importedItems, 0);
SecIdentityRef  identity = (__bridge SecIdentityRef) [item objectForKey:(__bridge NSString *) kSecImportItemIdentity];
SecKeyRef privateKeyRef;
SecIdentityCopyPrivateKey(identity, &privateKeyRef);
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);
 类似资料:
  • 我尝试过的解决方案: 1.以下代码 https://gist.github.com/huzemin/e8d7a904cec55d4d7635c9322f143c42

  • 问题内容: 我有以下Go代码 输出是 使用以下CryptoJS加密 并且可以用解密 输出是-这是正确的输出 为什么Go会有不同的输出? 问题答案: 请检查您的错误。总是 https://play.golang.org/p/dRLIT51u4I 更具体地说,字节75处的值为,超出了base64可用字符的范围。在ascii中,它是ENQ(查询)字符。至于为什么它最终出现在您的最终base64字符串中,

  • 问题内容: 我迅速编写了一个应用程序,我需要AES加密和解密功能,我从另一个.Net解决方案中接收了加密数据,但是我找不到解决办法。 这是我的.net加密: 我需要迅速解密功能。 问题答案: 我找到了解决方案,它是一个很好的库。 跨平台256位AES加密/解密。 此项目包含在所有平台(C#,iOS,Android)上均可使用的256位AES加密的实现。关键目标之一是通过简单的实现使AES在所有平台

  • 问题内容: 我找到了在PHP中对字符串进行编码/解码的示例。起初它看起来非常好,但是不会起作用:-( 有人知道问题出在哪里吗? 结果是: 加密: 解密: 问题答案: 并且 在您的代码中未定义。查看有效的解决方案( 但不安全! ): 停! 这个例子是 不安全的! 不要使用它! **但是此代码中还有其他问题,使其变得不安全,尤其是使用ECB(这不是_加密_模式,只能在其上定义加密模式的构造块)。

  • 我在这个网站上用AES-256加密一个虚拟字符串: https://www.devglan.com/online-tools/aes-encryption-decryption 具有以下参数: null 当我尝试用OpenSSL从命令行解密它时: 我得到这个错误:

  • 我加密的是对称的AES密钥,它加密我的实际数据,所以密钥长度是16字节。当简单的base64编码密钥时,一切都正常,所以我知道这个RSA加密有问题。 下面是我的iOS调用的一个示例: 下面是我的Java调用的一个示例: null 当我进行更多测试时,我看到了这个页面(http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/pkcs/pkcs1/rsa