根据个人项目经验:在项目中,使用RSA加密,用到的是RSA和Base64和SHA1。Base64进行编码。RSA进行加密解密。SHA1加签验签。
创建RSAEncryptor类,继承于NSObject。代码如下:
//
// RSAEncryptor.h
// CashLoan
//
// Created by wzk on 2017/12/28.
// Copyright © 2017年 com.shanlinfinance. All rights reserved.
//
#import
#define PublicKey @"PublicKey"
#define PrivateKey @"PrivateKey"
/*
//使用body转成的字符串进行使用公钥加密
NSString* RSAString = [RSAEncryptor encryptString:bodyString publicKey:PublicKey];
//使用body转成的字符串 进行使用私钥SHA1加密
NSString* signString = [RSAEncryptor signTheDataSHA1WithRSA:bodyString privateKey:PrivateKey];
*/
@interfaceRSAEncryptor :NSObject
/**
* 加密方法
*
* @paramstr 需要加密的字符串
* @parampath '.der'格式的公钥文件路径
*/
+ (NSString*)encryptString:(NSString*)str publicKeyWithContentsOfFile:(NSString*)path;
/**
* 解密方法
*
* @paramstr 需要解密的字符串
* @parampath '.p12'格式的私钥文件路径
* @parampassword 私钥文件密码
*/
+ (NSString*)decryptString:(NSString*)str privateKeyWithContentsOfFile:(NSString*)path password:(NSString*)password;
/**
* 加密方法
*
* @paramstr 需要加密的字符串
* @parampubKey 公钥字符串
*/
+ (NSString*)encryptString:(NSString*)str publicKey:(NSString*)pubKey;
/**
* 解密方法
*
* @paramstr 需要解密的字符串
* @paramprivKey 私钥字符串
*/
+ (NSString*)decryptString:(NSString*)str privateKey:(NSString*)privKey;
//签名
+ (NSString*)signTheDataSHA1WithRSA:(NSString*)plainText privateKey:(NSString*)privateKey;
//验签
+ (BOOL)rsaSHA1VertifyingData:(NSString*)plainData withSignature:(NSString*)signature;
@end
//
// RSAEncryptor.m
// CashLoan
//
// Created by wzk on 2017/12/28.
// Copyright © 2017年 com.shanlinfinance. All rights reserved.
//
#import "RSAEncryptor.h"
#import
#import
#import
#import "NSData+Base64.h"
#import "NSString+Base64.h"
#define kChosenDigestLength CC_SHA1_DIGEST_LENGTH // SHA-1消息摘要的数据位数160位
@implementation RSAEncryptor
staticNSString*base64_encode_data(NSData*data){
data = [database64EncodedDataWithOptions:0];
NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
returnret;
}
staticNSData*base64_decode(NSString*str){
NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
returndata;
}
#pragma mark - 使用'.der'公钥文件加密
//加密
+ (NSString*)encryptString:(NSString*)str publicKeyWithContentsOfFile:(NSString*)path{
if(!str || !path) returnnil;
return [self encryptString:str publicKeyRef:[self getPublicKeyRefWithContentsOfFile:path]];
}
//获取公钥
+ (SecKeyRef)getPublicKeyRefWithContentsOfFile:(NSString*)filePath{
NSData*certData = [NSDatadataWithContentsOfFile:filePath];
if(!certData) {
returnnil;
}
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
SecKeyRefkey =NULL;
SecTrustReftrust =NULL;
SecPolicyRefpolicy =NULL;
if(cert !=NULL) {
policy =SecPolicyCreateBasicX509();
if(policy) {
if(SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust) ==noErr) {
SecTrustResultTyperesult;
if(SecTrustEvaluate(trust, &result) ==noErr) {
key =SecTrustCopyPublicKey(trust);
}
}
}
}
if(policy)CFRelease(policy);
if(trust)CFRelease(trust);
if(cert)CFRelease(cert);
returnkey;
}
+ (NSString*)encryptString:(NSString*)str publicKeyRef:(SecKeyRef)publicKeyRef{
if(![str dataUsingEncoding:NSUTF8StringEncoding]){
returnnil;
}
if(!publicKeyRef){
returnnil;
}
NSData*data = [selfencryptData:[strdataUsingEncoding:NSUTF8StringEncoding]withKeyRef:publicKeyRef];
NSString*ret =base64_encode_data(data);
returnret;
}
#pragma mark - 使用'.12'私钥文件解密
//解密
+ (NSString*)decryptString:(NSString*)str privateKeyWithContentsOfFile:(NSString*)path password:(NSString*)password{
if(!str || !path)returnnil;
if(!password) password =@"";
return [self decryptString:str privateKeyRef:[self getPrivateKeyRefWithContentsOfFile:path password:password]];
}
//获取私钥
+ (SecKeyRef)getPrivateKeyRefWithContentsOfFile:(NSString*)filePath password:(NSString*)password{
NSData*p12Data = [NSDatadataWithContentsOfFile:filePath];
if(!p12Data) {
returnnil;
}
SecKeyRefprivateKeyRef =NULL;
NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
[optionssetObject: passwordforKey:(__bridgeid)kSecImportExportPassphrase];
CFArrayRefitems =CFArrayCreate(NULL,0,0,NULL);
OSStatussecurityError =SecPKCS12Import((__bridgeCFDataRef) p12Data, (__bridgeCFDictionaryRef)options, &items);
if(securityError ==noErr&&CFArrayGetCount(items) >0) {
CFDictionaryRefidentityDict =CFArrayGetValueAtIndex(items,0);
SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
securityError =SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);
if(securityError !=noErr) {
privateKeyRef =NULL;
}
}
CFRelease(items);
returnprivateKeyRef;
}
+ (NSString*)decryptString:(NSString*)str privateKeyRef:(SecKeyRef)privKeyRef{
NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
if(!privKeyRef) {
returnnil;
}
data = [selfdecryptData:datawithKeyRef:privKeyRef];
NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
returnret;
}
#pragma mark - 使用公钥字符串加密
/* START: Encryption with RSA public keyn */
//使用公钥字符串加密
+ (NSString*)encryptString:(NSString*)str publicKey:(NSString*)pubKey{
NSData *data = [self encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey];
NSString*ret =base64_encode_data(data);
returnret;
}
+ (NSData*)encryptData:(NSData*)data publicKey:(NSString*)pubKey{
if(!data || !pubKey){
returnnil;
}
SecKeyRefkeyRef = [selfaddPublicKey:pubKey];
if(!keyRef){
returnnil;
}
return[selfencryptData:datawithKeyRef:keyRef];
}
+ (SecKeyRef)addPublicKey:(NSString*)key{
NSRange spos = [key rangeOfString:@"-----BEGIN PUBLIC KEY-----"];
NSRange epos = [key rangeOfString:@"-----END PUBLIC KEY-----"];
if(spos.location != NSNotFound && epos.location != NSNotFound){
NSUIntegers = spos.location+ spos.length;
NSUIntegere = epos.location;
NSRangerange =NSMakeRange(s, e-s);
key = [keysubstringWithRange:range];
}
key = [keystringByReplacingOccurrencesOfString:@"\r" withString:@""];
key = [keystringByReplacingOccurrencesOfString:@"\n" withString:@""];
key = [keystringByReplacingOccurrencesOfString:@"\t" withString:@""];
key = [keystringByReplacingOccurrencesOfString:@" " withString:@""];
// This will be base64 encoded, decode it.
NSData*data =base64_decode(key);
data = [self stripPublicKeyHeader:data];
if(!data){
returnnil;
}
//a tag to read/write keychain storage
NSString *tag = @"RSAUtil_PubKey";
NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
// Delete any old lingering key with the same tag
NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
[publicKeysetObject:(__bridgeid)kSecClassKeyforKey:(__bridgeid)kSecClass];
[publicKeysetObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[publicKeysetObject:d_tagforKey:(__bridgeid)kSecAttrApplicationTag];
SecItemDelete((__bridgeCFDictionaryRef)publicKey);
// Add persistent version of the key to system keychain
[publicKeysetObject:dataforKey:(__bridgeid)kSecValueData];
[publicKeysetObject:(__bridgeid)kSecAttrKeyClassPublicforKey:(__bridgeid)
kSecAttrKeyClass];
[publicKeysetObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
kSecReturnPersistentRef];
CFTypeRefpersistKey =nil;
OSStatusstatus =SecItemAdd((__bridgeCFDictionaryRef)publicKey, &persistKey);
if(persistKey !=nil){
CFRelease(persistKey);
}
if((status !=noErr) && (status !=errSecDuplicateItem)) {
returnnil;
}
[publicKeyremoveObjectForKey:(__bridgeid)kSecValueData];
[publicKeyremoveObjectForKey:(__bridge id)kSecReturnPersistentRef];
[publicKeysetObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[publicKeysetObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
// Now fetch the SecKeyRef version of the key
SecKeyRefkeyRef =nil;
status =SecItemCopyMatching((__bridgeCFDictionaryRef)publicKey, (CFTypeRef*)&keyRef);
if(status !=noErr){
returnnil;
}
returnkeyRef;
}
+ (NSData*)stripPublicKeyHeader:(NSData*)d_key{
// Skip ASN.1 public key header
if(d_key ==nil)return(nil);
unsignedlonglen = [d_keylength];
if(!len)return(nil);
unsignedchar*c_key = (unsignedchar*)[d_keybytes];
unsignedint idx =0;
if(c_key[idx++] !=0x30)return(nil);
if(c_key[idx] >0x80) idx += c_key[idx] -0x80+1;
elseidx++;
// PKCS #1 rsaEncryption szOID_RSA_RSA
static unsigned char seqiod[] =
{0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x01,0x05,0x00};
if(memcmp(&c_key[idx], seqiod,15))return(nil);
idx +=15;
if(c_key[idx++] !=0x03)return(nil);
if(c_key[idx] >0x80) idx += c_key[idx] -0x80+1;
elseidx++;
if(c_key[idx++] !='\0')return(nil);
// Now make a new NSData from this buffer
return([NSDatadataWithBytes:&c_key[idx]length:len - idx]);
}
+ (NSData*)encryptData:(NSData*)data withKeyRef:(SecKeyRef) keyRef{
constuint8_t*srcbuf = (constuint8_t*)[databytes];
size_tsrclen = (size_t)data.length;
size_tblock_size =SecKeyGetBlockSize(keyRef) *sizeof(uint8_t);
void*outbuf =malloc(block_size);
size_tsrc_block_size = block_size -11;
NSMutableData *ret = [[NSMutableData alloc] init];
for(intidx=0; idx
size_tdata_len = srclen - idx;
if(data_len > src_block_size){
data_len = src_block_size;
}
size_toutlen = block_size;
OSStatusstatus =noErr;
status =SecKeyEncrypt(keyRef,
kSecPaddingPKCS1,
srcbuf + idx,
data_len,
outbuf,
&outlen
);
if(status !=0) {
ret =nil;
break;
}else{
[retappendBytes:outbuflength:outlen];
}
}
free(outbuf);
CFRelease(keyRef);
returnret;
}
/* END: Encryption with RSA public key */
#pragma mark - 使用私钥字符串解密
/* START: Decryption with RSA private key */
//使用私钥字符串解密
+ (NSString*)decryptString:(NSString*)str privateKey:(NSString*)privKey{
if(!str)returnnil;
if(![strisKindOfClass:[NSStringclass]]) {
returnnil;
}
NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
data = [selfdecryptData:dataprivateKey:privKey];
NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
returnret;
}
+ (NSData*)decryptData:(NSData*)data privateKey:(NSString*)privKey{
if(!data || !privKey){
returnnil;
}
SecKeyRefkeyRef = [selfaddPrivateKey:privKey];
if(!keyRef){
returnnil;
}
return[selfdecryptData:datawithKeyRef:keyRef];
}
+ (SecKeyRef)addPrivateKey:(NSString*)key{
NSRange spos = [key rangeOfString:@"-----BEGIN RSA PRIVATE KEY-----"];
NSRange epos = [key rangeOfString:@"-----END RSA PRIVATE KEY-----"];
if(spos.location != NSNotFound && epos.location != NSNotFound){
NSUIntegers = spos.location+ spos.length;
NSUIntegere = epos.location;
NSRangerange =NSMakeRange(s, e-s);
key = [keysubstringWithRange:range];
}
key = [keystringByReplacingOccurrencesOfString:@"\r" withString:@""];
key = [keystringByReplacingOccurrencesOfString:@"\n" withString:@""];
key = [keystringByReplacingOccurrencesOfString:@"\t" withString:@""];
key = [keystringByReplacingOccurrencesOfString:@" " withString:@""];
// This will be base64 encoded, decode it.
NSData*data =base64_decode(key);
data = [self stripPrivateKeyHeader:data];
if(!data){
returnnil;
}
//a tag to read/write keychain storage
NSString *tag = @"RSAUtil_PrivKey";
NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
// Delete any old lingering key with the same tag
NSMutableDictionary *privateKey = [[NSMutableDictionary alloc] init];
[privateKeysetObject:(__bridgeid)kSecClassKeyforKey:(__bridgeid)kSecClass];
[privateKeysetObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[privateKeysetObject:d_tagforKey:(__bridgeid)kSecAttrApplicationTag];
SecItemDelete((__bridgeCFDictionaryRef)privateKey);
// Add persistent version of the key to system keychain
[privateKeysetObject:dataforKey:(__bridgeid)kSecValueData];
[privateKeysetObject:(__bridgeid)kSecAttrKeyClassPrivateforKey:(__bridgeid)
kSecAttrKeyClass];
[privateKeysetObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
kSecReturnPersistentRef];
CFTypeRefpersistKey =nil;
OSStatusstatus =SecItemAdd((__bridgeCFDictionaryRef)privateKey, &persistKey);
if(persistKey !=nil){
CFRelease(persistKey);
}
if((status !=noErr) && (status !=errSecDuplicateItem)) {
returnnil;
}
[privateKeyremoveObjectForKey:(__bridgeid)kSecValueData];
[privateKeyremoveObjectForKey:(__bridge id)kSecReturnPersistentRef];
[privateKeysetObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[privateKeysetObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
// Now fetch the SecKeyRef version of the key
SecKeyRefkeyRef =nil;
status =SecItemCopyMatching((__bridgeCFDictionaryRef)privateKey, (CFTypeRef*)&keyRef);
if(status !=noErr){
returnnil;
}
returnkeyRef;
}
+ (NSData*)stripPrivateKeyHeader:(NSData*)d_key{
// Skip ASN.1 private key header
if(d_key ==nil)return(nil);
unsignedlonglen = [d_keylength];
if(!len)return(nil);
unsignedchar*c_key = (unsignedchar*)[d_keybytes];
unsigned int idx =22; //magic byte at offset 22
if(0x04!= c_key[idx++])returnnil;
//calculate length of the key
unsignedintc_len = c_key[idx++];
intdet = c_len &0x80;
if(!det) {
c_len = c_len &0x7f;
}else{
intbyteCount = c_len &0x7f;
if(byteCount + idx > len) {
//rsa length field longer than buffer
returnnil;
}
unsignedintaccum =0;
unsignedchar*ptr = &c_key[idx];
idx += byteCount;
while(byteCount) {
accum = (accum <<8) + *ptr;
ptr++;
byteCount--;
}
c_len = accum;
}
// Now make a new NSData from this buffer
return [d_key subdataWithRange:NSMakeRange(idx, c_len)];
}
+ (NSData*)decryptData:(NSData*)data withKeyRef:(SecKeyRef) keyRef{
constuint8_t*srcbuf = (constuint8_t*)[databytes];
size_tsrclen = (size_t)data.length;
size_tblock_size =SecKeyGetBlockSize(keyRef) *sizeof(uint8_t);
UInt8*outbuf =malloc(block_size);
size_tsrc_block_size = block_size;
NSMutableData *ret = [[NSMutableData alloc] init];
for(intidx=0; idx
size_tdata_len = srclen - idx;
if(data_len > src_block_size){
data_len = src_block_size;
}
size_toutlen = block_size;
OSStatusstatus =noErr;
status =SecKeyDecrypt(keyRef,
kSecPaddingNone,
srcbuf + idx,
data_len,
outbuf,
&outlen
);
if(status !=0) {
ret =nil;
break;
}else{
//the actual decrypted data is in the middle, locate it!
intidxFirstZero = -1;
intidxNextZero = (int)outlen;
for(inti =0; i < outlen; i++ ) {
if( outbuf[i] ==0) {
if( idxFirstZero <0) {
idxFirstZero = i;
}else{
idxNextZero = i;
break;
}
}
}
[retappendBytes:&outbuf[idxFirstZero+1]length:idxNextZero-idxFirstZero-1];
}
}
free(outbuf);
CFRelease(keyRef);
returnret;
}
/* END: Decryption with RSA private key */
/*
*加签
*/
//生成哈希数据
+ (NSData*)getHashBytes:(NSData*)plainText {
CC_SHA1_CTX ctx;
uint8_t* hashBytes =NULL;
NSData* hash =nil;
// Malloc a buffer to hold hash.
hashBytes =malloc(kChosenDigestLength*sizeof(uint8_t) );
memset((void *)hashBytes, 0x0, kChosenDigestLength);
// Initialize the context.
CC_SHA1_Init(&ctx);
// Perform the hash.
CC_SHA1_Update(&ctx, (void*)[plainTextbytes], [plainTextlength]);
// Finalize the output.
CC_SHA1_Final(hashBytes, &ctx);
// Build up the SHA1 blob.
hash = [NSDatadataWithBytes:(constvoid*)hashByteslength:(NSUInteger)kChosenDigestLength];
if(hashBytes)free(hashBytes);
returnhash;
}
//签名
+ (NSString*)signTheDataSHA1WithRSA:(NSString*)plainText privateKey:(NSString*)privateKey
{
uint8_t* signedBytes =NULL;
size_tsignedBytesSize =0;
OSStatussanityCheck =noErr;
NSData* signedHash =nil;
SecKeyRefprivateKeyRef = [selfaddPrivateKey:privateKey];
if(!privateKeyRef){
returnnil;
}
signedBytesSize =SecKeyGetBlockSize(privateKeyRef);
NSData *plainTextBytes = [plainText dataUsingEncoding:NSUTF8StringEncoding];
signedBytes =malloc( signedBytesSize *sizeof(uint8_t) );// Malloc a buffer to hold signature.
memset((void*)signedBytes,0x0, signedBytesSize);
sanityCheck =SecKeyRawSign(privateKeyRef,
kSecPaddingPKCS1SHA1,
(constuint8_t*)[[selfgetHashBytes:plainTextBytes]bytes],
kChosenDigestLength,
(uint8_t*)signedBytes,
&signedBytesSize);
if(sanityCheck ==noErr)
{
signedHash = [NSDatadataWithBytes:(constvoid*)signedByteslength:(NSUInteger)signedBytesSize];
}
else
{
returnnil;
}
if(signedBytes)
{
free(signedBytes);
}
NSString*signatureResult=[NSStringstringWithFormat:@"%@",[signedHashbase64EncodedString]];
returnsignatureResult;
}
/**
验证签名
@paramplainData plainData解密后的data
@paramsignature 服务的签名
@return是否验签成功
将plainData转化成data,将signature签名base64解码,进行验证签名
*/
+ (BOOL)rsaSHA1VertifyingData:(NSString*)plainData withSignature:(NSString*)signature{
NSData *plainTextBytes = [plainData dataUsingEncoding:NSUTF8StringEncoding];
NSData*signatureBytes = [signaturebase64DecodedData];
SecKeyRefpublicKey = [selfaddPublicKey:PublicKey];
if((!publicKey)||(!signatureBytes)||(!plainTextBytes)){
returnNO;
}
size_tsignedHashBytesSize =SecKeyGetBlockSize(publicKey);
constvoid* signedHashBytes = [signatureBytesbytes];
size_thashBytesSize =CC_SHA1_DIGEST_LENGTH;
uint8_t* hashBytes =malloc(hashBytesSize);
if(!CC_SHA1([plainTextBytesbytes], (CC_LONG)[plainTextByteslength], hashBytes)) {
returnNO;
}
OSStatusstatus =SecKeyRawVerify(publicKey,
kSecPaddingPKCS1SHA1,
hashBytes,
hashBytesSize,
signedHashBytes,
signedHashBytesSize);
returnstatus ==errSecSuccess;
}
@end