RSA秘钥 .cem 证书加密代码
1、使用.pem加密
注:iOS上没有直接处理RSA加密的API,网上说的大多数也是处理X.509的证书的方法来实现,不过X.509证书是带签名的,在这里我们利用ios兼容c程序的特点,利用openssl的api实现rsa的加密解密,代码如下:
.h文件
#import <Foundation/Foundation.h> #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h> typedef enum { KeyTypePublic, KeyTypePrivate }KeyType; typedef enum { RSA_PADDING_TYPE_NONE = RSA_NO_PADDING, RSA_PADDING_TYPE_PKCS1 = RSA_PKCS1_PADDING, RSA_PADDING_TYPE_SSLV23 = RSA_SSLV23_PADDING }RSA_PADDING_TYPE; @interface CRSA : NSObject{ RSA *_rsa; } + (id)shareInstance; - (BOOL)importRSAKeyWithType:(KeyType)type; - (int)getBlockSizeWithRSA_PADDING_TYPE:(RSA_PADDING_TYPE)padding_type; - (NSString *) encryptByRsa:(NSString*)content withKeyType:(KeyType)keyType; - (NSString *) decryptByRsa:(NSString*)content withKeyType:(KeyType)keyType; @end
.m文件
#import "CRSA.h" #define BUFFSIZE 1024 #import "Base64.h" #define PADDING RSA_PADDING_TYPE_PKCS1 @implementation CRSA + (id)shareInstance { static CRSA *_crsa = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _crsa = [[self alloc] init]; }); return _crsa; } - (BOOL)importRSAKeyWithType:(KeyType)type { FILEFILE *file; NSString *keyName = type == KeyTypePublic ? @"public_key" : @"private_key"; NSString *keyPath = [[NSBundle mainBundle] pathForResource:keyName ofType:@"pem"]; file = fopen([keyPath UTF8String], "rb"); if (NULL != file) { if (type == KeyTypePublic) { _rsa = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL); assert(_rsa != NULL); } else { _rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL); assert(_rsa != NULL); } fclose(file); return (_rsa != NULL) ? YES : NO; } return NO; } - (NSString *) encryptByRsa:(NSString*)content withKeyType:(KeyType)keyType { if (![self importRSAKeyWithType:keyType]) return nil; int status; int length = [content length]; unsigned char input[length + 1]; bzero(input, length + 1); int i = 0; for (; i < length; i++) { input[i] = [content characterAtIndex:i]; } NSInteger flen = [self getBlockSizeWithRSA_PADDING_TYPE:PADDING]; charchar *encData = (char*)malloc(flen); bzero(encData, flen); switch (keyType) { case KeyTypePublic: status = RSA_public_encrypt(length, (unsigned char*)input, (unsigned char*)encData, _rsa, PADDING); break; default: status = RSA_private_encrypt(length, (unsigned char*)input, (unsigned char*)encData, _rsa, PADDING); break; } if (status) { NSData *returnData = [NSData dataWithBytes:encData length:status]; free(encData); encData = NULL; NSString *ret = [returnData base64EncodedString]; return ret; } free(encData); encData = NULL; return nil; } - (NSString *) decryptByRsa:(NSString*)content withKeyType:(KeyType)keyType { if (![self importRSAKeyWithType:keyType]) return nil; int status; NSData *data = [content base64DecodedData]; int length = [data length]; NSInteger flen = [self getBlockSizeWithRSA_PADDING_TYPE:PADDING]; charchar *decData = (char*)malloc(flen); bzero(decData, flen); switch (keyType) { case KeyTypePublic: status = RSA_public_decrypt(length, (unsigned char*)[data bytes], (unsigned char*)decData, _rsa, PADDING); break; default: status = RSA_private_decrypt(length, (unsigned char*)[data bytes], (unsigned char*)decData, _rsa, PADDING); break; } if (status) { NSMutableString *decryptString = [[NSMutableString alloc] initWithBytes:decData length:strlen(decData) encoding:NSASCIIStringEncoding]; free(decData); decData = NULL; return decryptString; } free(decData); decData = NULL; return nil; } - (int)getBlockSizeWithRSA_PADDING_TYPE:(RSA_PADDING_TYPE)padding_type { int len = RSA_size(_rsa); if (padding_type == RSA_PADDING_TYPE_PKCS1 || padding_type == RSA_PADDING_TYPE_SSLV23) { len -= 11; } return len; } @end
2、使用证书加密
使用证书加密非常简单,可以在github上搜索Cryptor
#import "CryptorTools.h" #import <CommonCrypto/CommonCrypto.h> // 填充模式 #define kTypeOfWrapPadding kSecPaddingPKCS1 @interface CryptorTools() { SecKeyRef _publicKeyRef; // 公钥引用 SecKeyRef _privateKeyRef; // 私钥引用 } @end @implementation CryptorTools
#pragma mark - RSA 加密/解密算法 - (void)loadPublicKeyWithFilePath:(NSString *)filePath; { NSAssert(filePath.length != 0, @"公钥路径为空"); // 删除当前公钥 if (_publicKeyRef) CFRelease(_publicKeyRef); // 从一个 DER 表示的证书创建一个证书对象 NSData *certificateData = [NSData dataWithContentsOfFile:filePath]; 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, @"信任评估失败"); // 评估之后返回公钥子证书 _publicKeyRef = SecTrustCopyPublicKey(trustRef); NSAssert(_publicKeyRef != NULL, @"公钥创建失败"); if (certificateRef) CFRelease(certificateRef); if (policyRef) CFRelease(policyRef); if (trustRef) CFRelease(trustRef); } - (void)loadPrivateKey:(NSString *)filePath password:(NSString *)password { NSAssert(filePath.length != 0, @"私钥路径为空"); // 删除当前私钥 if (_privateKeyRef) CFRelease(_privateKeyRef); NSData *PKCS12Data = [NSData dataWithContentsOfFile:filePath]; 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, @"信任评估失败"); // 提取私钥 status = SecIdentityCopyPrivateKey(myIdentity, &_privateKeyRef); NSAssert(status == errSecSuccess, @"私钥创建失败"); CFRelease(items); } - (NSString *)RSAEncryptString:(NSString *)string { NSData *cipher = [self RSAEncryptData:[string dataUsingEncoding:NSUTF8StringEncoding]]; return [cipher base64EncodedStringWithOptions:0]; } - (NSData *)RSAEncryptData:(NSData *)data { OSStatus sanityCheck = noErr; size_t cipherBufferSize = 0; size_t keyBufferSize = 0; NSAssert(data, @"明文数据为空"); NSAssert(_publicKeyRef, @"公钥为空"); NSData *cipher = nil; uint8_t *cipherBuffer = NULL; // 计算缓冲区大小 cipherBufferSize = SecKeyGetBlockSize(_publicKeyRef); keyBufferSize = data.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 *)data.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; } - (NSString *)RSADecryptString:(NSString *)string { NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0]; NSData *tempData = [data subdataWithRange:NSMakeRange(0, 100)]; NSData *keyData = [self RSADecryptData:tempData]; return [[NSString alloc] initWithData:keyData encoding:NSUTF8StringEncoding]; } - (NSData *)RSADecryptData:(NSData *)data { OSStatus sanityCheck = noErr; size_t cipherBufferSize = 0; size_t keyBufferSize = 0; // NSMutableData // for (int i = 0; i <data.length; i +=128) { // // } NSData *key = nil; uint8_t *keyBuffer = NULL; SecKeyRef privateKey = _privateKeyRef; NSAssert(privateKey != NULL, @"私钥不存在"); // 计算缓冲区大小 cipherBufferSize = SecKeyGetBlockSize(privateKey); keyBufferSize = data.length; NSAssert(keyBufferSize <= cipherBufferSize, @"解密内容太大"); // 分配缓冲区 keyBuffer = malloc(keyBufferSize * sizeof(uint8_t)); memset((void *)keyBuffer, 0x0, keyBufferSize); // 使用私钥解密 sanityCheck = SecKeyDecrypt(privateKey, kTypeOfWrapPadding, (const uint8_t *)data.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; }
很多朋友会纠结在怎样生成证书。我后续会更新