乱码难点也化解了,ios中生成RSA密钥字符串

明天在利用easywechat对接公司打款到银行卡时,碰到了四个谬误

要跟银行做接口,要求使用delphi来post数据,但对方提供的是https初始的网址,要求拔取证书,对方已提供证书了,不过依旧调用不成功,使用的是idhttp和TIdSSLIOHandlerSocketOpenSSL来post的,indy 版本是10.5.5, OpenSSL的dll版本是openssl-1.0.0-i386-win32。现在报的错是:“could not load certificate error:0906D06C:PEM routines:PEM_read_bio:no start line”。

嘟哝嘟哝:近日收取一个任务:在客户端动态生成RSA密钥对,然后向服务器发送这么些密钥对中的公钥字符串,由服务器举办公钥加密,重临加密后的音信,再由客户端应用私钥举办解密。我在网上查看了汪洋的素材,可是大多是行使公钥私钥文件,或者直接收取RSA公私钥字符串举办加密解密,没有变动并转换成字符串,那里大家就介绍一下自家是怎么着促成这些效能的,以备后用。

集成开发宝 报错:rsa_private read error : private key is NULL

 error:0906D064:PEM
routines:PEM_read_bio:bad base64 decode 和 error:0906D06C:PEM routines:PEM_read_bio:no start
line 。

对方提供了某些个注脚,后缀名有:.cer,.pem,.pfx ,不领悟到底要用哪一个,而且对方没有delphi版本的Demo,唯有 java和C#的。网上查了二日资料,索然无获,不掌握怎么样下手,才能通讯成功。
坛里那位朋友有那上头的付出经历,请不吝指点一二,多谢了!

     
 我明日要介绍的RSA加密属于非对称加密。对于安全性来说肯定非对称加密更优化对称加密。在使用中,甲方索要同时生成公开密钥(公钥)和个体密钥(私钥),把里面的公钥发送给乙方,乙方利用传过来的私钥,对殡葬文书进行加密回传给甲方,甲方接收到加密后的文件后用此前变化的私钥举行解密,从而得到加密前的文书。但加密和解密开销时间长、速度慢,它不吻合于对文本加密而只适用于对少量数码举行加密。

两中化解方法:

那是因为想要正确的行使密钥,必要满足以下多少个规范。

设置以下两个属性

先是介绍利用终端转移公钥私钥

杀鸡取卵办法:

  1. 公物密钥的始发须要添加”—–BEGIN RSA PUBLIC
    KEY—–\n”,结尾须求加上”\n—–BEGIN RSA PUBLIC
    KEY—–\n”。不然会报 error:0906D06C:PEM
    routines:PEM_read_bio:no start line 。
  2. 公钥字符串每隔64隔字符必要加一个换行,负责会报 error:0906D06C:PEM routines:PEM_read_bio:no
    start line 。
  3. 以上2步应该能够知足有些语言的要求,但php不行,还亟需讲以上PKCS#1
    格式密钥转换成PKCS#8 格式密钥。

注明文件:
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.CertFile
密钥文件:
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.KeyFile 

1、生成私钥

1)在RSAntecSigner.m文件中 搜索代码

上边看下具体操作。根据文档使用如下命令:

并在OnGetPassword事件当中重临密钥的护卫密码即可。

openssl genrsa -out rsa_private_key.pem1024

[result appendString:@”—–BEGIN PRIVATE KEY—–\n”];

./vendor/bin/easywechat payment:rsa_public_key \
    --mch_id=14339221228 \
    --api_key=36YTbDmLgyQ52noqdxgwGiYy \
    --cert_path=/Users/overtrue/www/demo/apiclient_cert.pem \
    --key_path=/Users/overtrue/www/demo/apiclient_key.pem

PEM格式证书的开局行和停止行:

2、将原始私钥转换为pkcs8格式

将其改成

将会在现阶段目录生成一个 ./public-14339221228.pem 文件。

引用

openssl pkcs8 -topk8 -inform PEM -inrsa_private_key.pem -outform PEM
-nocrypt

[result appendString:@”—–BEGIN RSA PRIVATE KEY—–\n”];

一经从来接纳那些public
key文件,会报一个不法的key错误,然后可以窥见easywechat有如此一段源码。

—–BEGIN CERTIFICATE—–
……
乱码难点也化解了,ios中生成RSA密钥字符串。—–END CERTIFICATE—–

3、根据私钥生成公钥

2)在RS金士顿KingstonSigner.m文件中 搜索代码

function rsa_public_encrypt($content, $publicKey)
{
    $encrypted = '';
    openssl_public_encrypt($content, $encrypted, openssl_pkey_get_public($publicKey), OPENSSL_PKCS1_OAEP_PADDING);

    return base64_encode($encrypted);
}

PEM格式私钥的开局行和甘休行:

openssl rsa -in rsa_private_key.pem -pubout-out ras_public_key.pem

[result appendString:@”\n—–END PRIVATE KEY—–“];

报非法key是因为 openssl_pkey_get_public($publicKey) 重返的是false,那时,你可以加一行代码。

引用

RSAPEM文件格式

将其改成

function rsa_public_encrypt($content, $publicKey)
{
    $encrypted = '';
    openssl_public_encrypt($content, $encrypted, openssl_pkey_get_public($publicKey), OPENSSL_PKCS1_OAEP_PADDING);
    var_dump(openssl_error_string());
    return base64_encode($encrypted);
}

—–BEGIN RSA PRIVATE KEY—–
……
—–END RSA PRIVATE KEY—–

  1. PEM私钥格式文件

[result appendString:@”\n—–END RSA PRIVATE KEY—–“];

这是会晤到以下错误。

 

—–BEGIN RSA PRIVATE KEY—–

杀鸡取卵办法:

error:0906D06C:PEM routines:PEM_read_bio:no start line

pfx格式的申明也可以经过OpenSSL.exe这么些实用工具转换成有效的PEM格式。

—–END RSA PRIVATE KEY—–

A、将私钥转成PKCS8互换一下原私钥即可

那是因为easywechat直接生成的 public-14339221228.pem
 文件中,key的格式是那样的。

引用

  1. PEM公钥格式文件

1、生成私钥pem,  执行命令  openssl genrsa -out rsa_private_key.pem
1024

-----BEGIN RSA PUBLIC KEY-----MIIBCgKCAQEAuVvw3DeWx4wdDl2/I0aAMma2bH3hhU89rqMhJWvQ41uRbatxZxMZ13iEMXg8UfTBR+UGl+NCzpkkTjjcVm/2TcIdWgZCLr3Rzo4XD5hRLs8ExI+uzKnmar......CmtgTKWkqkhCnLwr7bRRzBUi3po7UDLWPePrH1ICd83/wIDAQAB-----END RSA PUBLIC KEY-----

openssl.exe pkcs12 -in 证书.pfx -out 证书和密钥.pem

—–BEGIN PUBLIC KEY—–

2、生成公钥,执行命令  openssl rsa -in rsa_private_key.pem -pubout -out
rsa_public_key.pem

那种格式是不当的,无法直接放到函数 openssl_pkey_get_public 中使用。须要对他举行格式化成如下格局。


—–END PUBLIC KEY—–

3、 将RSA私钥转换成PKCS8格式,命令执行  openssl pkcs8 -topk8 -inform PEM
-in rsa_private_key.pem -outform PEM -nocrypt

-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuVvw3DeWx4wdDl2/I0aA
Mma2bH3hhU89rqMhJWvQ41uRbatxZxMZ13iEMXg8UfTBR+UGl+NCzpkkTjjcVm/2
......
......
EXFyDtEykuiMuhn3A7WWNkc3voHML9C4kDWdJrX3wjQrwZbW3p3F1O/9pGHLNzn9
p3la2C9/Ve3jLdG8lEzvkCmtgTKWkqkhCnLwr7bRRzBUi3po7UDLWPePrH1ICd83
/wIDAQAB
-----END RSA PUBLIC KEY-----

乱码难题也解决了
最主要代码就在那三行
    RsltStrm:=TStringStream.Create(”,TEncoding.UTF8);
    IdHTTPClient.Post(‘www.abcc.com/abc’,tmpStrList,RsltStrm);
    tmpStrList.Text:=RsltStrm.DataString;
谢谢各位朋友!!!

  1. PEM RSAPublicKey公钥格式文件

( PHP服务端语言读取私钥不需求PKCS8转换)

先是行是 —–BEGIN RSA PUBLIC KEY—– ,最后一行是 —–END RSA
PUBLIC KEY—– ,然后中间的key每64个字符一行,可以用php的

 

—–BEGIN RSA PUBLIC KEY—–

wordwrap($key, 64, "\n", true)

—–END RSA PUBLIC KEY—–

函数处理。但那种是PKCS#1 格式密钥。php是函数 openssl_pkey_get_public 也无能为力使用。要求将其更换成PKCS#8
格式密钥。可以用如下命令

回归正题:我们发轫完成生成密钥字符串。在此间大家应用的是openssl框架来扭转密钥对。

openssl rsa -RSAPublicKey_in -in public-14339221228.pem -out public.pem

头文件中引入

那种就是在当前目录得到一个 public.pem 文件。里面存放的是PKCS#8
格式密钥。那种密钥格式是php可以拔取的。密钥如下:

#import <openssl/rsa.h>

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuVvw3DeWx4wdDl2/I0aA
Mma2bH3hhU89rqMhJWvQ41uRbatxZxMZ13iEMXg8UfTBR+UGl+NCzpkkTjjcVm/2
......
......
EXFyDtEykuiMuhn3A7WWNkc3voHML9C4kDWdJrX3wjQrwZbW3p3F1O/9pGHLNzn9
p3la2C9/Ve3jLdG8lEzvkCmtgTKWkqkhCnLwr7bRRzBUi3po7UDLWPePrH1ICd83
/wIDAQAB
-----END PUBLIC KEY-----

#import <openssl/pem.h>

 

1,生成密钥对

/*产生RSA密钥*/

RSA*rsa =NULL;

rsa =RSA_new();

//发生一个模为num位的密钥对,e为公开的加密指数,一般为65537(0x10001)

rsa =RSA_generate_key(1024,0×10001,NULL,NULL);

     
 这里需求验证一下,加密长度是1024位。加密长度是指理论上最大允许”被加密的音信“长度的限制,也就是开诚相见的长短限制。随着这几个参数的附加(比方说2048),允许的领会长度也会大增,但与此同时也会导致总计复杂度的极速拉长。一般推荐的长度就是1024位(128字节)。

     
 那种算法分外可看重,密钥越长,它就越难破解。根据已经揭示的文献,方今被破解的最长RSA密钥是768个二进制位。也就是说,长度超越768位的密钥,还无法破解(至少没人公开揭穿)。由此能够认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。

     
 由于自身并没有在框架中找到办法转换出密钥字符串,所以那里用了个比较愚笨的法子,将公钥私钥保存为txt文件,然后将那一个txt文件读出,读出后就是索要的字符串了。

上面加粗函数即便早已过时,可是当前还足以用,下方加粗部分是顶替格局

BIGNUM*bne =BN_new();

unsignedinte =RSA_3;

intresult =BN_set_word(bne, e);

result =RSA_generate_key_ex(rsa,1024, bne,NULL);

rsa就是得到的密钥对

//路径

NSString*documentsPath =
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)objectAtIndex:0];

/*领到公钥字符串*/

//最后存储的地点,所以必要成立一个路径去存储字符串

NSString*pubPath =
[documentsPathstringByAppendingPathComponent:@”PubFile.txt”];

FILE* pubWrite =NULL;

pubWrite =fopen([pubPathUTF8String],”wb”);

if(pubWrite ==NULL)

NSLog(@”Read Filed.”);

else

{

PEM_write_RSA_PUBKEY(pubWrite,rsa);

fclose(pubWrite);

}

       拿出字符串之后对字符串举行拍卖,这样就赢得了俺们需求的字符串了。

NSString*str=[NSStringstringWithContentsOfFile:pubPathencoding:NSUTF8StringEncodingerror:nil];

str = [strstringByReplacingOccurrencesOfString:@”—–BEGIN

PUBLIC KEY—–“withString:@””];

str = [strstringByReplacingOccurrencesOfString:@”—–END

PUBLIC KEY—–“withString:@””];

str = [strstringByReplacingOccurrencesOfString:@”\n”withString:@””];

/*www.5929.com,领到私钥字符串*/

NSString*priPath =

[documentsPathstringByAppendingPathComponent:@”PriFile.txt”];

FILE*priWtire =NULL;

priWtire =fopen([priPathUTF8String],”wb”);

EVP_PKEY*pkey =NULL;

if(priWtire ==NULL) {

NSLog(@”Read

Filed.”);

}else{

//函数使用PKCS#8正式保存EVP_PKEY里面的私钥到文件或者BIO中,并利用PKCS#5

//v2.0的科班加密私钥。enc参数定义了使用的加密算法。跟任何PEM的IO函数不均等的是,本函数的加密是根据PKCS#8层次上的,而不是依据PEM音讯字段的,所以那三个函数也是单独落成的函数,而不是宏定义函数。如果enc参数为NULL,那么就不会实施加密操作,只是选用PKCS#8私钥
音讯结构。成功实践回来大于0的数,否则再次来到0。

pkey =EVP_PKEY_new();

EVP_PKEY_assign_RSA(pkey, rsa);

PEM_write_PKCS8PrivateKey(priWtire, pkey,NULL,NULL,0,0,NULL);

fclose(priWtire);

}

NSString*priStr=[NSStringstringWithContentsOfFile:priPathencoding:NSUTF8StringEncodingerror:nil];

priStr = [priStrstringByReplacingOccurrencesOfString:@”—–BEGIN

PRIVATE KEY—–“withString:@””];

priStr = [priStrstringByReplacingOccurrencesOfString:@”—–END

PRIVATE KEY—–“withString:@””];

priStr =
[priStrstringByReplacingOccurrencesOfString:@”\n”withString:@””];

获得私钥字符串。

以下是难题记录:

1.利用PEM_write_RSA_PUBKEY函数保存密钥后,不可以得到密钥,原因是本身在设置文件的时候,参考网上的资料,写成了文件名称,获取的时候也是选用框架中的函数获取到的RSA,仍旧尚未转换成字符串。所以自己将安装文件的地方,写入了文本路径,然后我再用自己的点子读取这些txt文件,那样就得到了自我想要的字符串了。

2.保留密钥的时候,开头的时候取得的公钥私钥都是无法科学加密解密的,原因是本人在保存密钥文件的时候,选错了文本的格式,这里有几个函数很不难令人歪曲:

乱码难点也化解了,ios中生成RSA密钥字符串。PEM_write_RSAPublicKey(<#FILE *fp#>,<#const RSA
*x#>)

由那几个函数得到的文件是PRM
RSAPublicKey公钥格式文件,而我辈须求的文书是PEM公钥格式文件,所以要看好函数指定的文件格式。利用PEM_write_RSA_PUBKEY函数。

PEM_write_RSAPrivateKey(<#FILE *fp#>, <#RSA *x#>,
<#constEVP_CIPHER *enc#>, <#unsigned char *kstr#>,
<#int klen#>,<#pem_password_cb *cb#>, <#void
*u#>)

经过那么些函数我们固然可以得到私钥文件,可是却是PKCS1格式的,但是自己需要的是PKCS8格式的。所以必要改用这几个函数PEM_write_PKCS8PrivateKey。

选用了不错的文件格式,生成的公钥私钥就可以使用了。

这篇博文中有至于文件格式的大致介绍

     
 那篇作品并没有对规律举行分析,只是表达了须臾间用到格局,而且动用方法不是很好,我想框架中应当也有可以兑现的方法,可是方今还尚未找到,如果有哪位朋友找到了,一定要记得私信告诉自己,谢谢。

不知底怎么传文书 贴一份源码吧 (源码中包蕴生成动态key
以及加密解密可能会有结余的方法,因为是在旁人的源码基础上改动的)

急需引入:

libcrypto.a

libssl.a

以及openssl框架(我间接从支付宝的框架里搞来的)

急需导入框架

//

//RYTRSAEncryptor.h

//SMSCodeTest

//Created by timmy on 16/10/19.

//Copyright © 2016年 timmy. All rights reserved.

//

#import <Foundation/Foundation.h>

#import <openssl/rsa.h>

@interface RYTRSAEncryptor : NSObject

+ (void)keyWith:(void(^)(NSString *pubKey, NSString *priKey))block;

/**

*加密格局

*

*@param str须求加密的字符串

*@param pubKey公钥字符串

*/

+ (NSString *)encryptString:(NSString *)str publicKey:(NSString
*)pubKey;

+ (SecKeyRef)addPublicKey:(NSString *)key;

/**

*解密方法

*

*@param str需要解密的字符串

*@param privKey私钥字符串

*/

+ (NSString *)decryptString:(NSString *)str privateKey:(NSString
*)privKey;

+ (SecKeyRef)addPrivateKey:(NSString *)key;

@end

//RYTRSAEncryptor.m

//SMSCodeTest

//Created by timmy on 16/10/19.

//Copyright © 2016年 timmy. All rights reserved.

#import “RYTRSAEncryptor.h”

#import <Security/Security.h>

#import <openssl/rsa.h>

#import <openssl/pem.h>

#import “RYTBase64.h”

@implementation  RYTRSAEncryptor

staticNSString *base64_encode_data(NSData *data){

data = [data base64EncodedDataWithOptions: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 -生成密钥

/* START: creat keys */

+ (void)keyWith:(void(^)(NSString *pubKey, NSString *priKey))block {

/* 产生RSA密钥 */

RSA *rsa =NULL;

rsa = RSA_new();

//发生一个模为num位的密钥对,e为公开的加密指数,一般为65537(0x10001)

rsa = RSA_generate_key(1024,0×10001,NULL,NULL);

// 路径

NSString *documentsPath =
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,YES) objectAtIndex:0];

/* 提取公钥字符串 */

// 最后存储的地点,所以要求成立一个门路去存储字符串

NSString *pubPath = [documentsPath
stringByAppendingPathComponent:@”PubFile.txt”];

FILE* pubWrite =NULL;

pubWrite = fopen([pubPath UTF8String],”wb”);

if(pubWrite ==NULL)

NSLog(@”Read Filed.”);

else

{

PEM_write_RSA_PUBKEY(pubWrite,rsa);

fclose(pubWrite);

}

NSString *str=[NSString stringWithContentsOfFile:pubPath
encoding:NSUTF8StringEncoding error:nil];

str = [str stringByReplacingOccurrencesOfString:@”—–BEGIN PUBLIC
KEY—–“withString:@””];

str = [str stringByReplacingOccurrencesOfString:@”—–END PUBLIC
KEY—–“withString:@””];

str = [str stringByReplacingOccurrencesOfString:@”\n”withString:@””];

/*领到私钥字符串*/

NSString *priPath = [documentsPath
stringByAppendingPathComponent:@”PriFile.txt”];

FILE *priWtire =NULL;

priWtire = fopen([priPath UTF8String],”wb”);

EVP_PKEY *pkey =NULL;

if(priWtire ==NULL) {

NSLog(@”Read Filed.”);

}else{

//函数使用PKCS#8专业保存EVP_PKEY里面的私钥到文件或者BIO中,并选用PKCS#5

//v2.0的正统加密私钥。enc参数定义了动用的加密算法。跟其他PEM的IO函数不等同的是,本函数的加密是根据PKCS#8层次上的,而不是根据PEM信息字段的,所以那五个函数也是单身落成的函数,而不是宏定义函数。假诺enc参数为NULL,那么就不会履行加密操作,只是使用PKCS#8私钥
音信结构。成功施行回来大于0 的数,否则再次来到0。

pkey = EVP_PKEY_new();

EVP_PKEY_assign_RSA(pkey, rsa);

PEM_write_PKCS8PrivateKey(priWtire, pkey,NULL,NULL,0,0,NULL);

fclose(priWtire);

}

NSString *priStr=[NSString stringWithContentsOfFile:priPath
encoding:NSUTF8StringEncoding error:nil];

priStr = [priStr stringByReplacingOccurrencesOfString:@”—–BEGIN
PRIVATE KEY—–“withString:@””];

priStr = [priStr stringByReplacingOccurrencesOfString:@”—–END
PRIVATE KEY—–“withString:@””];

priStr = [priStr
stringByReplacingOccurrencesOfString:@”\n”withString:@””];

block(str,priStr);

}

#pragma mark -使用公钥字符串加密

/* START: Encryption with RSA public key */

//使用公钥字符串加密(PKCS8格式)

+ (NSString *)encryptString:(NSString *)str publicKey:(NSString
*)pubKey{

NSData *data = [selfencryptData:[str
dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey];

NSString *ret = base64_encode_data(data);

returnret;

}

+ (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{

if(!data || !pubKey){

returnnil;

}

SecKeyRef keyRef = [selfaddPublicKey:pubKey];

if(!keyRef){

returnnil;

}

return[selfencryptData:data withKeyRef:keyRef];

}

//创设公钥(PKCS8格式)

+ (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){

NSUInteger s = spos.location + spos.length;

NSUInteger e = epos.location;

NSRange range = NSMakeRange(s, e-s);

key = [key substringWithRange:range];

}

key = [key stringByReplacingOccurrencesOfString:@”\r”withString:@””];

key = [key stringByReplacingOccurrencesOfString:@”\n”withString:@””];

key = [key stringByReplacingOccurrencesOfString:@”\t”withString:@””];

key = [key stringByReplacingOccurrencesOfString:@” “withString:@””];

//key经过base64编码 解码

NSData *data = base64_decode(key);

data = [selfstripPublicKeyHeader: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];

[publicKey setObject:(__bridgeid) kSecClassKey
forKey:(__bridgeid)kSecClass];

[publicKey setObject:(__bridgeid) kSecAttrKeyTypeRSA
forKey:(__bridgeid)kSecAttrKeyType];

[publicKey setObject:d_tag
forKey:(__bridgeid)kSecAttrApplicationTag];

SecItemDelete((__bridgeCFDictionaryRef)publicKey);

// Add persistent version of the key to system keychain

[publicKey setObject:data forKey:(__bridgeid)kSecValueData];

[publicKey setObject:(__bridgeid) kSecAttrKeyClassPublic
forKey:(__bridgeid)

kSecAttrKeyClass];

[publicKey setObject:[NSNumber numberWithBool:YES]
forKey:(__bridgeid)

kSecReturnPersistentRef];

CFTypeRef persistKey =nil;

OSStatus status = SecItemAdd((__bridgeCFDictionaryRef)publicKey,
&persistKey);

if(persistKey !=nil){

CFRelease(persistKey);

}

if((status != noErr) && (status != errSecDuplicateItem)) {

returnnil;

}

[publicKey removeObjectForKey:(__bridgeid)kSecValueData];

[publicKey removeObjectForKey:(__bridgeid)kSecReturnPersistentRef];

[publicKey setObject:[NSNumber numberWithBool:YES]
forKey:(__bridgeid)kSecReturnRef];

[publicKey setObject:(__bridgeid) kSecAttrKeyTypeRSA
forKey:(__bridgeid)kSecAttrKeyType];

// Now fetch the SecKeyRef version of the key

SecKeyRef keyRef =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_key length];

if(!len)return(nil);

unsignedchar*c_key = (unsignedchar*)[d_key bytes];

unsignedintidx=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

staticunsignedcharseqiod[] =

{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([NSData dataWithBytes:&c_key[idx] length:len – idx]);

}

+ (NSData *)encryptData:(NSData *)data withKeyRef:(SecKeyRef) keyRef{

constuint8_t *srcbuf = (constuint8_t *)[data bytes];

size_t srclen = (size_t)data.length;

size_t block_size = SecKeyGetBlockSize(keyRef) *sizeof(uint8_t);

void*outbuf = malloc(block_size);

size_t src_block_size = block_size -11;

NSMutableData *ret = [[NSMutableData alloc] init];

for(intidx=0; idx

//NSLog(@”%d/%d block_size: %d”, idx, (int)srclen, (int)block_size);

size_t data_len = srclen – idx;

if(data_len > src_block_size){

data_len = src_block_size;

}

size_t outlen = block_size;

OSStatus status = noErr;

status = SecKeyEncrypt(keyRef,

kSecPaddingPKCS1,

srcbuf + idx,

data_len,

outbuf,

&outlen

);

if(status !=0) {

NSLog(@”SecKeyEncrypt fail. Error Code: %d”, status);

ret =nil;

break;

}else{

[ret appendBytes:outbuf length: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;

NSData *data = [[NSData alloc] initWithBase64EncodedString:str
options:NSDataBase64DecodingIgnoreUnknownCharacters];

data = [selfdecryptData:data privateKey:privKey];

NSString *ret = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];

returnret;

}

+ (NSData *)decryptData:(NSData *)data privateKey:(NSString
*)privKey{

if(!data || !privKey){

returnnil;

}

SecKeyRef keyRef = [selfaddPrivateKey:privKey];

if(!keyRef){

returnnil;

}

return[selfdecryptData:data withKeyRef:keyRef];

}

//(PKCS8格式)

+ (SecKeyRef)addPrivateKey:(NSString *)key{

NSRange spos = [key rangeOfString:@”—–BEGIN PRIVATE KEY—–“];

NSRange epos = [key rangeOfString:@”—–END PRIVATE KEY—–“];

if(spos.location != NSNotFound && epos.location != NSNotFound){

NSUInteger s = spos.location + spos.length;

NSUInteger e = epos.location;

NSRange range = NSMakeRange(s, e-s);

key = [key substringWithRange:range];

}

key = [key stringByReplacingOccurrencesOfString:@”\r”withString:@””];

key = [key stringByReplacingOccurrencesOfString:@”\n”withString:@””];

key = [key stringByReplacingOccurrencesOfString:@”\t”withString:@””];

key = [key stringByReplacingOccurrencesOfString:@” “withString:@””];

// This will be base64 encoded, decode it.

NSData *data = base64_decode(key);

data = [selfstripPrivateKeyHeader: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];

[privateKey setObject:(__bridgeid) kSecClassKey
forKey:(__bridgeid)kSecClass];

[privateKey setObject:(__bridgeid) kSecAttrKeyTypeRSA
forKey:(__bridgeid)kSecAttrKeyType];

[privateKey setObject:d_tag
forKey:(__bridgeid)kSecAttrApplicationTag];

SecItemDelete((__bridgeCFDictionaryRef)privateKey);

// Add persistent version of the key to system keychain

[privateKey setObject:data forKey:(__bridgeid)kSecValueData];

[privateKey setObject:(__bridgeid) kSecAttrKeyClassPrivate
forKey:(__bridgeid)

kSecAttrKeyClass];

[privateKey setObject:[NSNumber numberWithBool:YES]
forKey:(__bridgeid)

kSecReturnPersistentRef];

CFTypeRef persistKey =nil;

OSStatus status = SecItemAdd((__bridgeCFDictionaryRef)privateKey,
&persistKey);

if(persistKey !=nil){

CFRelease(persistKey);

}

if((status != noErr) && (status != errSecDuplicateItem)) {

returnnil;

}

[privateKey removeObjectForKey:(__bridgeid)kSecValueData];

[privateKey removeObjectForKey:(__bridgeid)kSecReturnPersistentRef];

[privateKey setObject:[NSNumber numberWithBool:YES]
forKey:(__bridgeid)kSecReturnRef];

[privateKey setObject:(__bridgeid) kSecAttrKeyTypeRSA
forKey:(__bridgeid)kSecAttrKeyType];

// Now fetch the SecKeyRef version of the key

SecKeyRef keyRef =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_key length];

if(!len)return(nil);

unsignedchar*c_key = (unsignedchar*)[d_key bytes];

unsignedintidx=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 *)[data bytes];

size_t srclen = (size_t)data.length;

size_t block_size = SecKeyGetBlockSize(keyRef) *sizeof(uint8_t);

UInt8 *outbuf = malloc(block_size);

size_t src_block_size = block_size;

NSMutableData *ret = [[NSMutableData alloc] init];

for(intidx=0; idx

size_t data_len = srclen – idx;

if(data_len > src_block_size){

data_len = src_block_size;

}

size_t outlen = block_size;

OSStatus status = noErr;

status = SecKeyDecrypt(keyRef,

kSecPaddingPKCS1,

srcbuf + idx,

data_len,

outbuf,

&outlen

);

if(status !=0) {

NSLog(@”SecKeyEncrypt fail. Error Code: %d”, status);

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;

}

}

}

[ret appendBytes:&outbuf[idxFirstZero+1]
length:idxNextZero-idxFirstZero-1];

}

}

free(outbuf);

CFRelease(keyRef);

returnret;

}

@end

比最少源码,仍然放项目相比一贯,那么些是种类地址,有趣味的同室可以看看。

Leave a Comment.