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;
}
很多朋友会纠结在怎样生成证书。我后续会更新