美文网首页iOS开发技能
iOS 非对称加密-RSA

iOS 非对称加密-RSA

作者: _涼城 | 来源:发表于2022-03-19 10:48 被阅读0次

通过 Security.framework 实现 RSA 加解密

Security API

iOS 上 Security.framework为我们提供了安全方面相关的 API。

Security.framework
  • 支持的 RSA KeySzie 大小 大小有:512,768,1024,2048位

  • 支持的 RSA 填充方式有三种:NOPadding,PKCS1,OAEP 三种方式 ,填充方式影响最大分组加密数据块的大小

      kSecPaddingNone      = 0,
      kSecPaddingPKCS1     = 1,
      kSecPaddingOAEP      = 2, 
    
  • 加密
    iOS 2.0 - iOS 15.0

    OSStatus SecKeyEncrypt(
                         SecKeyRef           key,
                         SecPadding          padding,
                         const uint8_t  *plainText,
                         size_t              plainTextLen,
                         uint8_t             *cipherText,
                         size_t              *cipherTextLen)
    
  • 解密
    iOS 2.0 - iOS 15.0

    OSStatus SecKeyDecrypt(
                         SecKeyRef           key,                /* Private key */
                         SecPadding          padding,   /* kSecPaddingNone,
                                                               kSecPaddingPKCS1,
                                                               kSecPaddingOAEP */
                         const uint8_t       *cipherText,
                         size_t              cipherTextLen,  /* length of cipherText */
                         uint8_t             *plainText, 
                         size_t              *plainTextLen) 
    

openssl 生成 RSA 密钥

由于在项目开发中,一般使用服务器提供的密钥对,在本地调试时可使用 openssl 生成

#!/usr/bin/env bash
echo "Generating RSA key pair ..."
echo "1024 RSA key: private_key.pem"
openssl genrsa -out private_key.pem 1024

echo "create certification require file: rsaCertReq.csr"
openssl req -new -key private_key.pem -out rsaCertReq.csr

echo "create certification using x509: rsaCert.crt"
openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt

echo "create public_key.der For IOS"
openssl x509 -outform der -in rsaCert.crt -out public_key.der

echo "create private_key.p12 For IOS. Please remember your password. The password will be used in iOS."
openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt

echo "create rsa_public_key.pem For Java"
openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
echo "create pkcs8_private_key.pem For Java"
openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt

echo "finished."    

加载公钥

在加密过程之前,我们需要先获取公钥进行存储,这里是通过 .der 文件 加载到 类型为 SecKeyRef 的公钥数据,并进行存储。

- (SecKeyRef)loadPublicKey:(NSString *)publicKeyPath {
    
    NSAssert(publicKeyPath.length != 0, @"公钥路径为空");
   
    
    // 从一个 DER 表示的证书创建一个证书对象
    NSData *certificateData = [NSData dataWithContentsOfFile:publicKeyPath];
    SecCertificateRef certificateRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificateData);
    NSAssert(certificateRef != NULL, @"公钥文件错误");
    
    // 返回一个默认 X509 策略的公钥对象,使用之后需要调用 CFRelease 释放
    SecPolicyRef policyRef = SecPolicyCreateBasicX509();
    // 包含信任管理信息的结构体
    SecTrustRef trustRef;
    
    // 基于证书和策略创建一个信任管理对象
    OSStatus status = SecTrustCreateWithCertificates(certificateRef, policyRef, &trustRef);
    NSAssert(status == errSecSuccess, @"创建信任管理对象失败");
    
    // 信任结果
    SecTrustResultType trustResult;
    // 评估指定证书和策略的信任管理是否有效
    status = SecTrustEvaluate(trustRef, &trustResult);
    NSAssert(status == errSecSuccess, @"信任评估失败");
    
    // 评估之后返回公钥子证书
    SecKeyRef publicKeyRef = SecTrustCopyPublicKey(trustRef);
    NSAssert(publicKeyRef != NULL, @"公钥创建失败");
    
    if (certificateRef) CFRelease(certificateRef);
    if (policyRef) CFRelease(policyRef);
    if (trustRef) CFRelease(trustRef);
    return publicKeyRef;
}

加载私钥

将.p12 私钥数据获取,并对其存储。

- (SecKeyRef)loadPrivateKey:(NSString *)privateKeyPath password:(NSString *)password {
    
    NSAssert(privateKeyPath.length != 0, @"私钥路径为空");

    
    NSData *PKCS12Data = [NSData dataWithContentsOfFile:privateKeyPath];
    CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
    CFStringRef passwordRef = (__bridge CFStringRef)password;
    
    // 从 PKCS #12 证书中提取标示和证书
    SecIdentityRef myIdentity;
    SecTrustRef myTrust;
    const void *keys[] =   {kSecImportExportPassphrase};
    const void *values[] = {passwordRef};
    CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    
    // 返回 PKCS #12 格式数据中的标示和证书
    OSStatus status = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
    
    if (status == noErr) {
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
        myIdentity = (SecIdentityRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
        myTrust = (SecTrustRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
    }
    
    if (optionsDictionary) CFRelease(optionsDictionary);
    
    NSAssert(status == noErr, @"提取身份和信任失败");
    
    SecTrustResultType trustResult;
    // 评估指定证书和策略的信任管理是否有效
    status = SecTrustEvaluate(myTrust, &trustResult);
    NSAssert(status == errSecSuccess, @"信任评估失败");
    SecKeyRef privateKeyRef;
    // 提取私钥
    status = SecIdentityCopyPrivateKey(myIdentity, &privateKeyRef);
    NSAssert(status == errSecSuccess, @"私钥创建失败");
    return privateKeyRef;
}

加密数据

- (NSData *)encryptData:(NSData *)plainData {
    OSStatus sanityCheck = noErr;
    size_t cipherBufferSize = 0;
    size_t keyBufferSize = 0;
    
    NSAssert(plainData != nil, @"明文数据为空");
    NSAssert(publicKeyRef != nil, @"公钥为空");
    
    NSData *cipher = nil;
    uint8_t *cipherBuffer = NULL;
    
    // 计算缓冲区大小
    cipherBufferSize = SecKeyGetBlockSize(publicKeyRef);
    keyBufferSize = [plainData length];
    
    if (kTypeOfWrapPadding == kSecPaddingNone) {
        NSAssert(keyBufferSize <= cipherBufferSize, @"加密内容太大");
    } else {
        NSAssert(keyBufferSize <= (cipherBufferSize - 11), @"加密内容太大");
    }
    
    // 分配缓冲区
    cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
    memset((void *)cipherBuffer, 0x0, cipherBufferSize);
    
    // 使用公钥加密
    sanityCheck = SecKeyEncrypt(publicKeyRef,
                                kTypeOfWrapPadding,
                                (const uint8_t *)[plainData bytes],
                                keyBufferSize,
                                cipherBuffer,
                                &cipherBufferSize
                                );
    
    NSAssert(sanityCheck == noErr, @"加密错误,OSStatus == %d", sanityCheck);
    
    // 生成密文数据
    cipher = [NSData dataWithBytes:(const void *)cipherBuffer length:(NSUInteger)cipherBufferSize];
    
    if (cipherBuffer) free(cipherBuffer);
    
    return cipher;
}
    

解密数据

- (NSData *)decryptData:(NSData *)cipherData {
    OSStatus sanityCheck = noErr;
    size_t cipherBufferSize = 0;
    size_t keyBufferSize = 0;
    
    NSData *key = nil;
    uint8_t *keyBuffer = NULL;
    
    SecKeyRef privateKey = NULL;
    
    privateKey = [self getPrivateKeyRef];
    NSAssert(privateKey != NULL, @"私钥不存在");
    
    // 计算缓冲区大小
    cipherBufferSize = SecKeyGetBlockSize(privateKey);
    keyBufferSize = [cipherData length];
    
    NSAssert(keyBufferSize <= cipherBufferSize, @"解密内容太大");
    
    // 分配缓冲区
    keyBuffer = malloc(keyBufferSize * sizeof(uint8_t));
    memset((void *)keyBuffer, 0x0, keyBufferSize);
    
    // 使用私钥解密
    sanityCheck = SecKeyDecrypt(privateKey,
                                kTypeOfWrapPadding,
                                (const uint8_t *)[cipherData bytes],
                                cipherBufferSize,
                                keyBuffer,
                                &keyBufferSize
                                );
    
    NSAssert1(sanityCheck == noErr, @"解密错误,OSStatus == %d", sanityCheck);
    
    // 生成明文数据
    key = [NSData dataWithBytes:(const void *)keyBuffer length:(NSUInteger)keyBufferSize];
    
    if (keyBuffer) free(keyBuffer);
    
    return key;
}

通过 openssl 实现 RSA 加解密

首先在工程中 引入 openssl ,openssl 是一个开源库,我们可以使用 OpenSSL-Universal,这个仓库一直在维护,支持 静态库、framework、Cocoapods等等方式引入工程。

相关文章

  • RSA非对称加密

    RSA非对称加密 RSA非对称加密, 适用于Java和iOS 应用场景:用户登录时对登录密码进行加密 启动终端, ...

  • kotlin版本RSA非对称加密解密与分段加密解密

    基于kotlin语言的RSA非对称加密解密与分段加密解密 RSA非对称加密 RSA非对称加密的具体算法与来源我就不...

  • 非对称加密算法RSA 学习

    非对称加密算法RSA 学习 RSA加密算法是一种非对称加密算法。RSA是1977年由罗纳德·李维斯特(Ron Ri...

  • RSA加密

    RSA加密为非对称加密实现 对称加密:加密解密使用同一个算法 非对称加密:加密和解密使用不同算法 rsa加密原理 ...

  • 3.2 RSA算法简介

    非对称加密技术 -- RSA算法 RSA算法是流行最广泛的非对称加密算法,也是唯一的基于因式分解的非对称加密算法。...

  • 非对称加密

    非对称加密 非对称加密算法有:RSA,DSA,ECC,DH.其中RSA最为常用. 非对称加密一般有一对公钥和私钥,...

  • 6.1 密码学专题 - 非对称加密算法 - RSA 算法

    密码学专题 - 非对称加密算法 - RSA 算法 6.1 RSA 算法 第一个较完善的非对称加密算法 RSA,它既...

  • iOS-对称加密和(rsa)非对称加密

    说起rsa,大家自然就会说,非对称加密嘛。是的,rsa非对称加密算是安全级别非常高的加密方式,至少对于现在而言。这...

  • 密码学基础(三):非对称加密(RSA算法原理)

    什么是RSA加密 加密和解密使用的是两个不同的秘钥,这种算法叫做非对称加密。非对称加密又称为公钥加密,RSA只是公...

  • ios开发之证书和签名机制(一)

    非对称加密和摘要 1、非对称加密的特性和用法 1) 非对称加密算法(RSA):非对称加密算法指加密秘钥和解密秘钥是...

网友评论

    本文标题:iOS 非对称加密-RSA

    本文链接:https://www.haomeiwen.com/subject/rsugdrtx.html