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

来源:互联网 发布:h3c ap端口修改为wan 编辑:程序博客网 时间:2024/05/16 15:17


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 alloc] 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




0 0