您的位置:首页 > 移动开发 > Objective-C

object-c 使用openssl进行 rsa 双向加解密

2017-05-11 13:07 477 查看
IOS系统本身自带的RSA加密类有个特性,那就是加解密是单向的,就是只能 公钥加密->私钥解密,反之则会报错。

所以很多朋友就会出现这样的情况,在IOS客户端用公钥加密的数据传到服务器端用私钥解密没有问题。但反过来在服务器端用私钥加密的数据传到IOS客户端用公钥解密,就报-9809或-50的错误。你的服务器端可能是JAVA或者其他语言写的。

很多朋友网上找不到解决案例。我开始也遇到这样的问题,最后果断用了下openssl,使用openssl库才解决了这个问题。使用openssl既可以使用公钥加密,也可以使用私钥进行加密,而且与服务器端的加解密的结果相同。下面我们就一起来捣鼓一下吧。

在IOS上要使用openssl需要先编译openssl的库才能使用,我这里已经编译好了直接下载就可以使用,http://download.csdn.net/detail/kokjuis/9723109 点击打开链接

至于OpenSSL怎么生成公私钥,这个不写了,网上一大把。

下载完以后解压,然后导入到你的xcode工程中,不一定跟我的路径一样,自己根据情况改成自己的路径



然后在build settings的Header Search Paths里面引用 include路径,并且把Always Search User Paths设置为Yes,如图:



然后在 Library Search Paths 引用lib目录。一般导入以后XCODE会自动引用的,如果没有引用,自己手动引用一下。



到这里就基本能正常使用openssl库的加解密功能了,下面是我写的一个工具类,可以参考一下,是用OC语言写的,想用Swift写的话也很简单,可以自己转换一下,这里不折腾了:

//
// IOS使用OpenSSL 生成的公私玥字符串进行RSA加解密
// RsaUtil.h
//
// Created by kokjuis on 16/8/19.
//
//

#import <Foundation/Foundation.h>
#import <openssl/rsa.h>
#import <openssl/pem.h>

@interface RsaUtil : NSObject

/*
注意,RSA加解密的特征是:公钥加密->私钥解密、私钥加密->公钥解密。
*/

+(NSString *) encryptString:(NSString *)content withPublicKey:(NSString *)publicKey;//公钥加密
+(NSString *) decryptString:(NSString *)encryptContent withPublicKey:(NSString *)publicKey;//公钥解密

+(NSString *) encryptString:(NSString *)content withPrivateKey:(NSString *)privateKey;//私钥加密
+(NSString *) decryptString:(NSString *)encryptContent withPrivateKey:(NSString *)privateKey;//私钥解密

@end

//
// RsaUtil.m
// BestTravel
//
// Created by kokjuis on 16/8/19.
//
//

#import "RsaUtil.h"
#import <Security/Security.h>
//#import "GTMBase64.h"

@implementation RsaUtil

#pragma mark -通过公私钥字符串生成公私钥
//通过公钥生成key
+(RSA *)createRsaKeyWithPublicKey:(NSString *) publicKey{

//为了避免写法的不同意,如果公钥已经带有下面标记字符,先去除,后面再统一加上固定格式
NSRange spos = [publicKey rangeOfString:@"-----BEGIN PUBLIC KEY-----"];
NSRange epos = [publicKey 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);
publicKey = [publicKey substringWithRange:range];
}

//除去换行符,空格等
publicKey = [publicKey stringByReplacingOccurrencesOfString:@"\r" withString:@""];
publicKey = [publicKey stringByReplacingOccurrencesOfString:@"\n" withString:@""];
publicKey = [publicKey stringByReplacingOccurrencesOfString:@"\t" withString:@""];
publicKey = [publicKey stringByReplacingOccurrencesOfString:@" " withString:@""];

// ras公钥
NSMutableString * rsa_public_key = [[NSMutableString alloc]initWithString:publicKey];

//从内存中读取,公钥字符串开头要加上“-----BEGIN PUBLIC KEY-----\n”,结尾加上“\n-----END PUBLIC KEY-----\n”。否则会出现error:0906D06C:PEM routines:PEM_read_bio:no start line
[rsa_public_key insertString:@"-----BEGIN PUBLIC KEY-----\n" atIndex:0];
[rsa_public_key appendString:@"\n-----END PUBLIC KEY-----\n"];

BIO *bio = NULL;
const char * chPublicKey =[rsa_public_key UTF8String];
if ((bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) //从字符串读取RSA公钥
{
return nil;
}

RSA *rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL); //从bio结构中得到rsa结构

return rsa;

}

//通过私钥生成key
+(RSA *)createRsaKeyWithPrivateKey:(NSString *) privateKey{

//为了避免写法的不同意,如果私钥已经带有下面标记字符,先去除,后面再统一加上固定格式
NSRange spos = [privateKey rangeOfString:@"-----BEGIN RSA PRIVATE KEY-----"];
NSRange epos = [privateKey rangeOfString:@"-----END RSA 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);
privateKey = [privateKey substringWithRange:range];
}

//除去换行符,空格等
privateKey = [privateKey stringByReplacingOccurrencesOfString:@"\r" withString:@""];
privateKey = [privateKey stringByReplacingOccurrencesOfString:@"\n" withString:@""];
privateKey = [privateKey stringByReplacingOccurrencesOfString:@"\t" withString:@""];
privateKey = [privateKey stringByReplacingOccurrencesOfString:@" " withString:@""];

// ras私钥
NSMutableString * rsa_private_key = [[NSMutableString alloc]initWithString:privateKey];

//从内存中读取,公钥字符串开头要加上“-----BEGIN RSA PRIVATE KEY-----\n”,结尾加上“\n-----END RSA PRIVATE KEY-----\n”。否则会出现error:0906D06C:PEM routines:PEM_read_bio:no start line
[rsa_private_key insertString:@"-----BEGIN RSA PRIVATE KEY-----\n" atIndex:0];
[rsa_private_key appendString:@"\n-----END RSA PRIVATE KEY-----\n"];

BIO *bio = NULL;
const char * chPrivateKey =[rsa_private_key UTF8String];
if ((bio = BIO_new_mem_buf(chPrivateKey, -1)) == NULL) //从字符串读取RSA公钥
{
return nil;
}

RSA *rsa=PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);

return rsa;

}

#pragma mark -公钥加解密
//分段加密
+ (NSData *) encryptData:(NSData *)data withPublicRSA:(RSA *)publicRSA{

//获取公钥
if (!publicRSA) {
return nil;
}

int publicRSALength = RSA_size(publicRSA); //公钥长度
double totalLength = [data length]; //数据总长度
int blockSize = publicRSALength - 12; //数据分段大小
int blockCount = ceil(totalLength / blockSize); //分段个数
size_t publicEncryptSize = publicRSALength;
NSMutableData *encryptDate = [NSMutableData data];
for (int i = 0; i < blockCount; i++) {
NSUInteger loc = i * blockSize;
int dataSegmentRealSize = MIN(blockSize, totalLength - loc);
NSData *dataSegment = [data subdataWithRange:NSMakeRange(loc, dataSegmentRealSize)];
char *publicEncrypt = malloc(publicRSALength);
memset(publicEncrypt, 0, publicRSALength);
const unsigned char *str = [dataSegment bytes];
if(RSA_public_encrypt(blockSize,str,(unsigned char*)publicEncrypt,publicRSA,RSA_PKCS1_PADDING)>=0){
NSData *encryptData = [[NSData alloc] initWithBytes:publicEncrypt length:publicEncryptSize];
[encryptDate appendData:encryptData];
}
free(publicEncrypt);
}
RSA_free(publicRSA);

return encryptDate;
}

//分段解密
+ (NSData *) decryptData:(NSData *)data withPublicRSA:(RSA *)publicRSA{

if (!publicRSA) {
return nil;
}

int publicRSALength = RSA_size(publicRSA);
double totalLength = [data length];
int blockSize = publicRSALength;
int blockCount = ceil(totalLength / blockSize);
NSMutableData *decrypeData = [NSMutableData data];
for (int i = 0; i < blockCount; i++) {
NSUInteger loc = i * blockSize;
long dataSegmentRealSize = MIN(blockSize, totalLength - loc);
NSData *dataSegment = [data subdataWithRange:NSMakeRange(loc, dataSegmentRealSize)];
const unsigned char *str = [dataSegment bytes];
unsigned char *privateDecrypt = malloc(publicRSALength);
memset(privateDecrypt, 0, publicRSALength);
if(RSA_public_decrypt(publicRSALength,str,privateDecrypt,publicRSA,RSA_PKCS1_PADDING)>=0){
NSInteger length =strlen((char *)privateDecrypt);
NSData *data = [[NSData alloc] initWithBytes:privateDecrypt length:length];
[decrypeData appendData:data];
}
free(privateDecrypt);
}

RSA_free(publicRSA);

return decrypeData;
}

#pragma 加密
+ (NSString *) encryptString:(NSString *)content withPublicKey:(NSString *)publicKey{
//加密

RSA *publicRSA=[self createRsaKeyWithPublicKey:publicKey];

NSData *data=[self encryptData:[content dataUsingEncoding:NSUTF8StringEncoding] withPublicRSA:publicRSA];

//NSData *encodeData=[GTMBase64 encodeData:data];
NSData * encodeData = [data base64EncodedDataWithOptions:0];

NSString * encrypotoResult= [[NSString alloc] initWithData:encodeData encoding:NSUTF8StringEncoding];

return encrypotoResult;
}

#pragma 解密
+(NSString *) decryptString:(NSString *)encryptContent withPublicKey:(NSString *)publicKey{
//解密

RSA *publicRSA=[self createRsaKeyWithPublicKey:publicKey];

//NSData *encodeData=[GTMBase64 decodeString:encryptContent];
NSData *encodeData = [[NSData alloc] initWithBase64EncodedString:encryptContent options:NSDataBase64DecodingIgnoreUnknownCharacters];

NSData *data=[self decryptData:encodeData withPublicRSA:publicRSA];
NSString * decrypotoResult= [[NSString a
bfc7
lloc] initWithData:data encoding:NSUTF8StringEncoding];

return decrypotoResult;
}

#pragma mark -私钥加解密

//私钥加密
+ (NSData *)encryptDate:(NSData *)data withPrivateRSA:(RSA *)privateRSA{

if (!privateRSA) {
return nil;
}
int privateRSALength = RSA_size(privateRSA); //公钥长度
double totalLength = [data length]; //数据总长度
int blockSize = privateRSALength - 12; //数据分段大小
int blockCount = ceil(totalLength / blockSize); //分段个数
size_t privateEncryptSize = privateRSALength;
NSMutableData *encryptDate = [NSMutableData data];
for (int i = 0; i < blockCount; i++) {
NSUInteger loc = i * blockSize;
int dataSegmentRealSize = MIN(blockSize, totalLength - loc);
NSData *dataSegment = [data subdataWithRange:NSMakeRange(loc, dataSegmentRealSize)];
char *publicEncrypt = malloc(privateRSALength);
memset(publicEncrypt, 0, privateRSALength);
const unsigned char *str = [dataSegment bytes];
if(RSA_private_encrypt(dataSegmentRealSize,str,(unsigned char*)publicEncrypt,privateRSA,RSA_PKCS1_PADDING)>=0){
NSData *encryptData = [[NSData alloc] initWithBytes:publicEncrypt length:privateEncryptSize];
[encryptDate appendData:encryptData];
}
free(publicEncrypt);
}
RSA_free(privateRSA);
return encryptDate;
}

//私钥解密
+ (NSData *)decryptData:(NSData *)data withPrivateRSA:(RSA *)privateRSA {

if (!privateRSA) {
return nil;
}

int privateRSALenght = RSA_size(privateRSA);
double totalLength = [data length];
int blockSize = privateRSALenght;
int blockCount = ceil(totalLength / blockSize);
NSMutableData *decrypeData = [NSMutableData data];
for (int i = 0; i < blockCount; i++) {
NSUInteger loc = i * blockSize;
long dataSegmentRealSize = MIN(blockSize, totalLength - loc);
NSData *dataSegment = [data subdataWithRange:NSMakeRange(loc, dataSegmentRealSize)];
const unsigned char *str = [dataSegment bytes];
unsigned char *privateDecrypt = malloc(privateRSALenght);
memset(privateDecrypt, 0, privateRSALenght);
if(RSA_private_decrypt(privateRSALenght,str,privateDecrypt,privateRSA,RSA_PKCS1_PADDING)>=0){
NSInteger length =strlen((char *)privateDecrypt);
NSData *data = [[NSData alloc] initWithBytes:privateDecrypt length:length];
[decrypeData appendData:data];

}
free(privateDecrypt);
}

RSA_free(privateRSA);
return decrypeData;
}

#pragma 加密
+ (NSString *) encryptString:(NSString *)content withPrivateKey:(NSString *)privateKey{
//加密

RSA *privateRSA=[self createRsaKeyWithPrivateKey:privateKey];

NSData *data=[self encryptDate:[content dataUsingEncoding:NSUTF8StringEncoding] withPrivateRSA:privateRSA];
// NSData *encodeData=[GTMBase64 encodeData:data];
NSData * encodeData = [data base64EncodedDataWithOptions:0];
NSString * encrypotoResult= [[NSString alloc] initWithData:encodeData encoding:NSUTF8StringEncoding];

return encrypotoResult;
}

#pragma 解密
+(NSString *) decryptString:(NSString *)encryptContent withPrivateKey:(NSString *)privateKey{
//解密

RSA *privateRSA=[self createRsaKeyWithPrivateKey:privateKey];

//可以用系统自带的base64,也可以用GTMBase64这个库
//NSData *encodeData=[GTMBase64 decodeString:encryptContent];
NSData *encodeData = [[NSData alloc] initWithBase64EncodedString:encryptContent options:NSDataBase64DecodingIgnoreUnknownCharacters];

NSData *data=[self decryptData:encodeData withPrivateRSA:privateRSA];
NSString * decrypotoResult= [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

return decrypotoResult;
}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: