8rsa加密错误 ios_ios rsa加密 rsa/ecb/nopadding - CSDN
  • iOS下的RSA加密方法

    2016-03-04 12:04:54
    iOS下的RSA加密方法 最近几天折腾了一下如何在iOS上使用RSA来加密。iOS上并没有直接的RSA加密API。但是iOS提供了x509的API,而x509是支持RSA加密的。因此,我们可以通过制作自签名的x509证书(由于对安全性要求不...
    
    

    最近几天折腾了一下如何在iOS上使用RSA来加密。iOS上并没有直接的RSA加密API。但是iOS提供了x509的API,而x509是支持RSA加密的。因此,我们可以通过制作自签名的x509证书(由于对安全性要求不高,我们并不需要使用CA认证的证书),再调用x509的相关API来进行加密。接下来记录一下整个流程。

    第一步,制作自签名的证书

    1.最简单快捷的方法,打开Terminal,使用openssl(Mac OS X自带)生成私钥和自签名的x509证书。

    1. openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem -days 3650  

    按照命令行的提示输入内容就行了。

    几个说明:

    public_key.der是输出的自签名的x509证书,即我们要用的。

    private_key.pem是输出的私钥,用来解密的,请妥善保管。

    rsa:1024这里的1024是密钥长度,1024是比较安全的,如果需要更安全的话,可以用2048,但是加解密代价也会增加。

    -days:证书过期时间,一定要加上这个参数,默认的证书过期时间是30天,一般我们不希望证书这么短就过期,所以写上比较合适的天数,例如这里的3650(10年)。

    事实上,这一行命令包含了好几个步骤(我研究下面这些步骤的原因是我手头已经由一个private_key.pem私钥了,想直接用这个来生成x509证书,也就是用到了下面的2-3)

    1)创建私钥

    1. openssl genrsa -out private_key.pem 1024  
    2)创建证书请求(按照提示输入信息)

    1. openssl req -new -out cert.csr -key private_key.pem  
    3)自签署根证书

    1. openssl x509 -req -in cert.csr -out public_key.der -outform der -signkey private_key.pem -days 3650  

    2.验证证书。把public_key.der拖到xcode中,如果文件没有问题的话,那么就可以直接在xcode中打开,看到证书的各种信息。如下图所示:

    第二步,使用public_key.der来进行加密。

    1.导入Security.framework。

    2.把public_key.der放到mainBundle中(一般直接拖到Xcode就行啦)。

    3.从public_key.der读取公钥。

    4.加密。

    下面是参考代码(只能用于加密长度小于等于116字节的内容,适合于对密码进行加密。使用了ARC,不过还是要注意部分资源需要使用CFRealse来释放)

    RSA.h


    1. //  
    2. //  RSA.h  
    3. //  
    4. #import <Foundation/Foundation.h>  
    5.   
    6. @interface RSA : NSObject {  
    7.     SecKeyRef publicKey;  
    8.     SecCertificateRef certificate;  
    9.     SecPolicyRef policy;  
    10.     SecTrustRef trust;  
    11.     size_t maxPlainLen;  
    12. }  
    13.   
    14. - (NSData *) encryptWithData:(NSData *)content;  
    15. - (NSData *) encryptWithString:(NSString *)content;  
    16.   
    17. @end  
    RSA.m

    1. //  
    2. //  RSA.m  
    3. //  
    4. #import "RSA.h"  
    5.   
    6. @implementation RSA  
    7.   
    8. - (id)init {  
    9.     self = [super init];  
    10.       
    11.     NSString *publicKeyPath = [[NSBundle mainBundle] pathForResource:@"public_key"  
    12.                                                      ofType:@"der"];  
    13.     if (publicKeyPath == nil) {  
    14.         NSLog(@"Can not find pub.der");  
    15.         return nil;  
    16.     }  
    17.       
    18.     NSDate *publicKeyFileContent = [NSData dataWithContentsOfFile:publicKeyPath];  
    19.     if (publicKeyFileContent == nil) {  
    20.         NSLog(@"Can not read from pub.der");  
    21.         return nil;  
    22.     }  
    23.       
    24.     certificate = SecCertificateCreateWithData(kCFAllocatorDefault, ( __bridge CFDataRef)publicKeyFileContent);  
    25.     if (certificate == nil) {  
    26.         NSLog(@"Can not read certificate from pub.der");  
    27.         return nil;  
    28.     }  
    29.       
    30.     policy = SecPolicyCreateBasicX509();  
    31.     OSStatus returnCode = SecTrustCreateWithCertificates(certificate, policy, &trust);  
    32.     if (returnCode != 0) {  
    33.         NSLog(@"SecTrustCreateWithCertificates fail. Error Code: %ld", returnCode);  
    34.         return nil;  
    35.     }  
    36.       
    37.     SecTrustResultType trustResultType;  
    38.     returnCode = SecTrustEvaluate(trust, &trustResultType);  
    39.     if (returnCode != 0) {  
    40.         NSLog(@"SecTrustEvaluate fail. Error Code: %ld", returnCode);  
    41.         return nil;  
    42.     }  
    43.       
    44.     publicKey = SecTrustCopyPublicKey(trust);  
    45.     if (publicKey == nil) {  
    46.         NSLog(@"SecTrustCopyPublicKey fail");  
    47.         return nil;  
    48.     }  
    49.       
    50.     maxPlainLen = SecKeyGetBlockSize(publicKey) - 12;  
    51.     return self;  
    52. }  
    53.   
    54. - (NSData *) encryptWithData:(NSData *)content {  
    55.       
    56.     size_t plainLen = [content length];  
    57.     if (plainLen > maxPlainLen) {  
    58.         NSLog(@"content(%ld) is too long, must < %ld", plainLen, maxPlainLen);  
    59.         return nil;  
    60.     }  
    61.       
    62.     voidvoid *plain = malloc(plainLen);  
    63.     [content getBytes:plain   
    64.                length:plainLen];  
    65.       
    66.     size_t cipherLen = 128// 当前RSA的密钥长度是128字节  
    67.     voidvoid *cipher = malloc(cipherLen);  
    68.       
    69.     OSStatus returnCode = SecKeyEncrypt(publicKey, kSecPaddingPKCS1, plain,   
    70.                                         plainLen, cipher, &cipherLen);  
    71.       
    72.     NSData *result = nil;  
    73.     if (returnCode != 0) {  
    74.         NSLog(@"SecKeyEncrypt fail. Error Code: %ld", returnCode);  
    75.     }  
    76.     else {  
    77.         result = [NSData dataWithBytes:cipher   
    78.                                 length:cipherLen];  
    79.     }  
    80.       
    81.     free(plain);  
    82.     free(cipher);  
    83.       
    84.     return result;  
    85. }  
    86.   
    87. - (NSData *) encryptWithString:(NSString *)content {  
    88.     return [self encryptWithData:[content dataUsingEncoding:NSUTF8StringEncoding]];  
    89. }  
    90.   
    91. - (void)dealloc{  
    92.     CFRelease(certificate);  
    93.     CFRelease(trust);  
    94.     CFRelease(policy);  
    95.     CFRelease(publicKey);  
    96. }  
    97.   
    98. @end  
    使用方法:

    1. RSA *rsa = [[RSA alloc] init];  
    2. if (rsa != nil) {  
    3.     NSLog(@"%@",[rsa encryptWithString:@"test"]);  
    4. }  
    5. else {  
    6.     NSLog(@"init rsa error");  
    7. }  

    参考:

    1. (原创)如何生成以及导入X.509证书

    http://hi.baidu.com/five00/blog/item/43bf1fd77df2d8d9a044df39.html

    2. ios下使用rsa算法与php进行加解密通讯

    http://blog.yorkgu.me/2011/10/27/rsa-in-ios-using-publick-key-generated-by-openssl/

    3. Certificate, Key, and Trust Services Reference

    http://developer.apple.com/library/mac/#documentation/security/Reference/certifkeytrustservices/Reference/reference.html

    4. X509

    http://baike.baidu.com/view/2841580.htm

    5. RSA

    http://zh.wikipedia.org/zh/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95


    转自:

    http://blog.iamzsx.me/show.html?id=155002

    展开全文
  • iOS中使用RSA加密

    2016-11-23 10:40:47
    iOS中使用RSA加密解密,需要用到.der和.p12后缀格式的文件,其中.der格式的文件存放的是公钥(Public key)用于加密,.p12格式的文件存放的是私钥(Private key)用于解密. 首先需要先生成这些文件,然后再将文件...

    在iOS中使用RSA加密解密,需要用到.der和.p12后缀格式的文件,其中.der格式的文件存放的是公钥(Public key)用于加密,.p12格式的文件存放的是私钥(Private key)用于解密. 首先需要先生成这些文件,然后再将文件导入工程使用,不多说,开始做!
    一、使用openssl生成所需秘钥文件

      生成环境是在mac系统下,使用openssl进行生成,首先打开终端,按下面这些步骤依次来做:
    1. 生成模长为1024bit的私钥文件private_key.pem

    openssl genrsa -out private_key.pem 1024

    1. 生成证书请求文件rsaCertReq.csr

    openssl req -new -key private_key.pem -out rsaCerReq.csr

    注意:这一步会提示输入国家、省份、mail等信息,可以根据实际情况填写,或者全部不用填写,直接全部敲回车.
    3. 生成证书rsaCert.crt,并设置有效时间为1年

    openssl x509 -req -days 3650 -in rsaCerReq.csr -signkey private_key.pem -out rsaCert.crt

    1. 生成供iOS使用的公钥文件public_key.der

    openssl x509 -outform der -in rsaCert.crt -out public_key.der

    1. 生成供iOS使用的私钥文件private_key.p12

    openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt

    注意:这一步会提示给私钥文件设置密码,直接输入想要设置密码即可,然后敲回车,然后再验证刚才设置的密码,再次输入密码,然后敲回车,完毕!
    在解密时,private_key.p12文件需要和这里设置的密码配合使用,因此需要牢记此密码.
    6. 生成供Java使用的公钥rsa_public_key.pem

    openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout

    1. 生成供Java使用的私钥pkcs8_private_key.pem

    openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt

    全部执行成功后,会生成如下文件,其中public_key.der和private_key.p12就是iOS需要用到的文件,如下图:
    这里写图片描述
    生成的文件
    二、将文件导入工程使用
    1.新建工程, 并导入Security.framework框架, 如下图:
    这里写图片描述
    新建工程并添加框架
    2.导入秘钥文件

    导入.der和.p12格式的秘钥文件, 如下图:
    这里写图片描述
    导入秘钥文件
    3.新建用于加密、解密的类RSAEncryptor, 并实现相关方法

    新建RSAEncryptor类, 如下图:
    这里写图片描述
    新建用于加密解密的类

    下面开始上代码, 可以直接复制过去用:
    RSAEncryptor.h代码如下:

    #import <Foundation/Foundation.h>
    
    @interface RSAEncryptor : NSObject
    
    /**
     *  加密方法
     *
     *  @param str   需要加密的字符串
     *  @param path  '.der'格式的公钥文件路径
     */
    + (NSString *)encryptString:(NSString *)str publicKeyWithContentsOfFile:(NSString *)path;
    
    /**
     *  解密方法
     *
     *  @param str       需要解密的字符串
     *  @param path      '.p12'格式的私钥文件路径
     *  @param password  私钥文件密码
     */
    + (NSString *)decryptString:(NSString *)str privateKeyWithContentsOfFile:(NSString *)path password:(NSString *)password;
    
    /**
     *  加密方法
     *
     *  @param str    需要加密的字符串
     *  @param pubKey 公钥字符串
     */
    + (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey;
    
    /**
     *  解密方法
     *
     *  @param str     需要解密的字符串
     *  @param privKey 私钥字符串
     */
    + (NSString *)decryptString:(NSString *)str privateKey:(NSString *)privKey;
    
    @end
    
    RSAEncryptor.m代码如下:
    
    #import "RSAEncryptor.h"
    #import <Security/Security.h>
    
    @implementation RSAEncryptor
    
    static NSString *base64_encode_data(NSData *data){
        data = [data base64EncodedDataWithOptions:0];
        NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        return ret;
    }
    
    static NSData *base64_decode(NSString *str){
        NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
        return data;
    }
    
    #pragma mark - 使用'.der'公钥文件加密
    
    //加密
    + (NSString *)encryptString:(NSString *)str publicKeyWithContentsOfFile:(NSString *)path{
        if (!str || !path)  return nil;
        return [self encryptString:str publicKeyRef:[self getPublicKeyRefWithContentsOfFile:path]];
    }
    
    //获取公钥
    + (SecKeyRef)getPublicKeyRefWithContentsOfFile:(NSString *)filePath{
        NSData *certData = [NSData dataWithContentsOfFile:filePath];
        if (!certData) {
            return nil;
        }
        SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
        SecKeyRef key = NULL;
        SecTrustRef trust = NULL;
        SecPolicyRef policy = NULL;
        if (cert != NULL) {
            policy = SecPolicyCreateBasicX509();
            if (policy) {
                if (SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust) == noErr) {
                    SecTrustResultType result;
                    if (SecTrustEvaluate(trust, &result) == noErr) {
                        key = SecTrustCopyPublicKey(trust);
                    }
                }
            }
        }
        if (policy) CFRelease(policy);
        if (trust) CFRelease(trust);
        if (cert) CFRelease(cert);
        return key;
    }
    
    + (NSString *)encryptString:(NSString *)str publicKeyRef:(SecKeyRef)publicKeyRef{
        if(![str dataUsingEncoding:NSUTF8StringEncoding]){
            return nil;
        }
        if(!publicKeyRef){
            return nil;
        }
        NSData *data = [self encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] withKeyRef:publicKeyRef];
        NSString *ret = base64_encode_data(data);
        return ret;
    }
    
    #pragma mark - 使用'.12'私钥文件解密
    
    //解密
    + (NSString *)decryptString:(NSString *)str privateKeyWithContentsOfFile:(NSString *)path password:(NSString *)password{
        if (!str || !path) return nil;
        if (!password) password = @"";
        return [self decryptString:str privateKeyRef:[self getPrivateKeyRefWithContentsOfFile:path password:password]];
    }
    
    //获取私钥
    + (SecKeyRef)getPrivateKeyRefWithContentsOfFile:(NSString *)filePath password:(NSString*)password{
    
        NSData *p12Data = [NSData dataWithContentsOfFile:filePath];
        if (!p12Data) {
            return nil;
        }
        SecKeyRef privateKeyRef = NULL;
        NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
        [options setObject: password forKey:(__bridge id)kSecImportExportPassphrase];
        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
        OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data, (__bridge CFDictionaryRef)options, &items);
        if (securityError == noErr && CFArrayGetCount(items) > 0) {
            CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
            SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
            securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);
            if (securityError != noErr) {
                privateKeyRef = NULL;
            }
        }
        CFRelease(items);
    
        return privateKeyRef;
    }
    
    + (NSString *)decryptString:(NSString *)str privateKeyRef:(SecKeyRef)privKeyRef{
        NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
        if (!privKeyRef) {
            return nil;
        }
        data = [self decryptData:data withKeyRef:privKeyRef];
        NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        return ret;
    }
    
    #pragma mark - 使用公钥字符串加密
    
    /* START: Encryption with RSA public key */
    
    //使用公钥字符串加密
    + (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey{
        NSData *data = [self encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey];
        NSString *ret = base64_encode_data(data);
        return ret;
    }
    
    + (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{
        if(!data || !pubKey){
            return nil;
        }
        SecKeyRef keyRef = [self addPublicKey:pubKey];
        if(!keyRef){
            return nil;
        }
        return [self encryptData:data withKeyRef: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){
            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 = [self stripPublicKeyHeader:data];
        if(!data){
            return nil;
        }
    
        //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:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
        [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
        SecItemDelete((__bridge CFDictionaryRef)publicKey);
    
        // Add persistent version of the key to system keychain
        [publicKey setObject:data forKey:(__bridge id)kSecValueData];
        [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)
         kSecAttrKeyClass];
        [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
         kSecReturnPersistentRef];
    
        CFTypeRef persistKey = nil;
        OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey);
        if (persistKey != nil){
            CFRelease(persistKey);
        }
        if ((status != noErr) && (status != errSecDuplicateItem)) {
            return nil;
        }
    
        [publicKey removeObjectForKey:(__bridge id)kSecValueData];
        [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
        [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
        [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    
        // Now fetch the SecKeyRef version of the key
        SecKeyRef keyRef = nil;
        status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef);
        if(status != noErr){
            return nil;
        }
        return keyRef;
    }
    
    + (NSData *)stripPublicKeyHeader:(NSData *)d_key{
        // Skip ASN.1 public key header
        if (d_key == nil) return(nil);
    
        unsigned long len = [d_key length];
        if (!len) return(nil);
    
        unsigned char *c_key = (unsigned char *)[d_key bytes];
        unsigned int  idx     = 0;
    
        if (c_key[idx++] != 0x30) return(nil);
    
        if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
        else idx++;
    
        // 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;
        else idx++;
    
        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{
        const uint8_t *srcbuf = (const uint8_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(int idx=0; idx<srclen; idx+=src_block_size){
            //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);
        return ret;
    }
    
    /* END: Encryption with RSA public key */
    
    #pragma mark - 使用私钥字符串解密
    
    /* START: Decryption with RSA private key */
    
    //使用私钥字符串解密
    + (NSString *)decryptString:(NSString *)str privateKey:(NSString *)privKey{
        if (!str) return nil;
        NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
        data = [self decryptData:data privateKey:privKey];
        NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        return ret;
    }
    
    + (NSData *)decryptData:(NSData *)data privateKey:(NSString *)privKey{
        if(!data || !privKey){
            return nil;
        }
        SecKeyRef keyRef = [self addPrivateKey:privKey];
        if(!keyRef){
            return nil;
        }
        return [self decryptData:data withKeyRef: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){
            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 = [self stripPrivateKeyHeader:data];
        if(!data){
            return nil;
        }
    
        //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:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
        [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [privateKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
        SecItemDelete((__bridge CFDictionaryRef)privateKey);
    
        // Add persistent version of the key to system keychain
        [privateKey setObject:data forKey:(__bridge id)kSecValueData];
        [privateKey setObject:(__bridge id) kSecAttrKeyClassPrivate forKey:(__bridge id)
         kSecAttrKeyClass];
        [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
         kSecReturnPersistentRef];
    
        CFTypeRef persistKey = nil;
        OSStatus status = SecItemAdd((__bridge CFDictionaryRef)privateKey, &persistKey);
        if (persistKey != nil){
            CFRelease(persistKey);
        }
        if ((status != noErr) && (status != errSecDuplicateItem)) {
            return nil;
        }
    
        [privateKey removeObjectForKey:(__bridge id)kSecValueData];
        [privateKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
        [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
        [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    
        // Now fetch the SecKeyRef version of the key
        SecKeyRef keyRef = nil;
        status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKey, (CFTypeRef *)&keyRef);
        if(status != noErr){
            return nil;
        }
        return keyRef;
    }
    
    + (NSData *)stripPrivateKeyHeader:(NSData *)d_key{
        // Skip ASN.1 private key header
        if (d_key == nil) return(nil);
    
        unsigned long len = [d_key length];
        if (!len) return(nil);
    
        unsigned char *c_key = (unsigned char *)[d_key bytes];
        unsigned int  idx     = 22; //magic byte at offset 22
    
        if (0x04 != c_key[idx++]) return nil;
    
        //calculate length of the key
        unsigned int c_len = c_key[idx++];
        int det = c_len & 0x80;
        if (!det) {
            c_len = c_len & 0x7f;
        } else {
            int byteCount = c_len & 0x7f;
            if (byteCount + idx > len) {
                //rsa length field longer than buffer
                return nil;
            }
            unsigned int accum = 0;
            unsigned char *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{
        const uint8_t *srcbuf = (const uint8_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(int idx=0; idx<srclen; idx+=src_block_size){
            //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 = SecKeyDecrypt(keyRef,
                                   kSecPaddingNone,
                                   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!
                int idxFirstZero = -1;
                int idxNextZero = (int)outlen;
                for ( int i = 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);
        return ret;
    }
    
    /* END: Decryption with RSA private key */
    
    @end
    1. 测试加密、解密

    首先先测试使用.der和.p12秘钥文件进行加密、解密, 在ViewController.m中进行测试, 代码如下:

    #import "ViewController.h"
    #import "RSAEncryptor.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //原始数据
        NSString *originalString = @"这是一段将要使用'.der'文件加密的字符串!";
    
        //使用.der和.p12中的公钥私钥加密解密
        NSString *public_key_path = [[NSBundle mainBundle] pathForResource:@"public_key.der" ofType:nil];
        NSString *private_key_path = [[NSBundle mainBundle] pathForResource:@"private_key.p12" ofType:nil];
    
        NSString *encryptStr = [RSAEncryptor encryptString:originalString publicKeyWithContentsOfFile:public_key_path];
        NSLog(@"加密前:%@", originalString);
        NSLog(@"加密后:%@", encryptStr);
        NSLog(@"解密后:%@", [RSAEncryptor decryptString:encryptStr privateKeyWithContentsOfFile:private_key_path password:@"123456"]);
    
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end

    运行后, 输出信息如下:
    这里写图片描述
    输出结果

    可以看到已经可以成功加密、解密了.

    下面接着测试使用秘钥字符串进行加密、解密, 那么秘钥字符串从哪里来? 可以来这里:http://web.chacuo.net/netrsakeypair, 这是一个在线生成RSA秘钥的网站, 生成公钥和秘钥后, 复制出来用于测试. 然后在ViewController.m中使用RSAEntryptor.h头文件中对应的加密方法进行加密, ViewController.m中代码如下:

    #import "ViewController.h"
    #import "RSAEncryptor.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //原始数据
        NSString *originalString = @"这是一段将要使用'秘钥字符串'进行加密的字符串!";
    
        //使用字符串格式的公钥私钥加密解密
        NSString *encryptStr = [RSAEncryptor encryptString:originalString publicKey:@"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTbZ6cNH9PgdF60aQKveLz3FTalyzHQwbp601y77SzmGHX3F5NoVUZbdK7UMdoCLK4FBziTewYD9DWvAErXZo9BFuI96bAop8wfl1VkZyyHTcznxNJFGSQd/B70/ExMgMBpEwkAAdyUqIjIdVGh1FQK/4acwS39YXwbS+IlHsPSQIDAQAB"];
    
        NSLog(@"加密前:%@", originalString);
        NSLog(@"加密后:%@", encryptStr);
        NSLog(@"解密后:%@", [RSAEncryptor decryptString:encryptStr privateKey:@"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANNtnpw0f0+B0XrRpAq94vPcVNqXLMdDBunrTXLvtLOYYdfcXk2hVRlt0rtQx2gIsrgUHOJN7BgP0Na8AStdmj0EW4j3psCinzB+XVWRnLIdNzOfE0kUZJB38HvT8TEyAwGkTCQAB3JSoiMh1UaHUVAr/hpzBLf1hfBtL4iUew9JAgMBAAECgYA1tGeQmAkqofga8XtwuxEWDoaDS9k0+EKeUoXGxzqoT/GyiihuIafjILFhoUA1ndf/yCQaG973sbTDhtfpMwqFNQq13+JAownslTjWgr7Hwf7qplYW92R7CU0v7wFfjqm1t/2FKU9JkHfaHfb7qqESMIbO/VMjER9o4tEx58uXDQJBAO0O4lnWDVjr1gN02cqvxPOtTY6DgFbQDeaAZF8obb6XqvCqGW/AVms3Bh8nVlUwdQ2K/xte8tHxjW9FtBQTLd8CQQDkUncO35gAqUF9Bhsdzrs7nO1J3VjLrM0ITrepqjqtVEvdXZc+1/UrkWVaIigWAXjQCVfmQzScdbznhYXPz5fXAkEAgB3KMRkhL4yNpmKRjhw+ih+ASeRCCSj6Sjfbhx4XaakYZmbXxnChg+JB+bZNz06YBFC5nLZM7y/n61o1f5/56wJBALw+ZVzE6ly5L34114uG04W9x0HcFgau7MiJphFjgUdAtd/H9xfgE4odMRPUD3q9Me9LlMYK6MiKpfm4c2+3dzcCQQC8y37NPgpNEkd9smMwPpSEjPW41aMlfcKvP4Da3z7G5bGlmuICrva9YDAiaAyDGGCK8LxC8K6HpKrFgYrXkRtt"]);
    
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end

    运行后, 输出信息如下:
    这里写图片描述
    输出结果

    可以看到,也成功加密、解密了.

    至此, RSA加密演示完毕!

    展开全文
  • 注:本文全部转载自:https://www.jianshu.com/p/43f7fc8d8e14iOSRSA加密解密与后台之间的双向加密详解序言因为项目中需要用到RSA加密,刚开始也是有点乱,这两天也整理的差不多了,希望能帮到大家。这次先上代码...

    注:本文全部转载自:https://www.jianshu.com/p/43f7fc8d8e14

    iOS之RSA加密解密与后台之间的双向加密详解

    序言

    因为项目中需要用到RSA加密,刚开始也是有点乱,这两天也整理的差不多了,希望能帮到大家。
    这次先上代码,我想大部分人肯定是着急解决问题,所以不要废话太多。

    iOS端

    后台是PHP,给我了一段公钥和他用私钥加密后的base64编码,让我先解一下,看看能否解出(请先不要纠结为什么给我公钥解密,公钥私钥都可以解密,具体后面会讲到)。
    公钥:

    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3//sR2tXw0wrC2DySx8vNGlqt  
    3Y7ldU9+LBLI6e1KS5lfc5jlTGF7KBTSkCHBM3ouEHWqp1ZJ85iJe59aF5gIB2kl  
    Bd6h4wrbbHA2XE1sq21ykja/Gqx7/IRia3zQfxGv/qEkyGOx+XALVoOlZqDwh76o  
    2n1vP1D+tD3amHsK7QIDAQAB
    

    base64编码后的加密数据(注意:后台给你的一定是经过base64编码后的):

    eZVIkIEDb83YfdpOQCTg1SMfJtAHjdl92oKCALYeItxwvvyBsIR/L2e7y1+rXYCztBELXff/L9SijAYrUWOcvPVLPlkJbiJhZjRn+v4L9UeLtSUfO/qv30K3JROb2OniOvRImK3ZcBq319VT8e62zjJscGBIlwfFfMxRVT/mAzY=
    

    下面使用RSA这是一个封装的第三方框架,只需要将下面这两个文件导入到项目中,便可以使用(不用再导入其他的一些框架),别的框架不敢保证能使用,但这个是肯定可以使用的。

    1.png

    代码:

     //公钥
        NSString *publicKey = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3//sR2tXw0wrC2DySx8vNGlqt3Y7ldU9+LBLI6e1KS5lfc5jlTGF7KBTSkCHBM3ouEHWqp1ZJ85iJe59aF5gIB2klBd6h4wrbbHA2XE1sq21ykja/Gqx7/IRia3zQfxGv/qEkyGOx+XALVoOlZqDwh76o2n1vP1D+tD3amHsK7QIDAQAB";
        //base64编码后的加密数据
        NSString *base64Str = @"eZVIkIEDb83YfdpOQCTg1SMfJtAHjdl92oKCALYeItxwvvyBsIR/L2e7y1+rXYCztBELXff/L9SijAYrUWOcvPVLPlkJbiJhZjRn+v4L9UeLtSUfO/qv30K3JROb2OniOvRImK3ZcBq319VT8e62zjJscGBIlwfFfMxRVT/mAzY=";
        //结果:注意,这里是用公钥进行解密的,方法一定要用对
        NSString *resultStr = [RSA decryptString:base64Str publicKey:publicKey];
        NSLog(@"结果 = %@",resultStr);
    
    

    打印结果:

    2

    这只是先进行测试的数据,如果给你私钥解密,就用别的方法,在RSA.h中可以很容易找到。
    上面讲述的是单向加密,那么如何进行双向加密呢?

    • 1、  iOS端和后台(这里后台使用的是java,因为我后台语言只会java,效果都是一样的)各生成自己的公钥和私钥。
    • 2、  iOS端生成的公钥和私钥定义为iOSPublicKeyiOSPrivateKeyjava端生成的公钥私钥定义为javaPublicKeyjavaPrivateKey。将iOSPublicKeyjava,让它用iOSPublicKey加密数据传给iOS端,iOS端用iOSPrivateKey解密;java端将javaPublicKeyiOS端,iOS端用javaPublicKey加密数据后上传给javajava端利用javaPrivateKey去解密,这样就实现了数据传输过程中的加密与解密,当然,也不一定非要按照我上面的步骤来,具体情况要和后台商量如何加密。

    具体实现:

    iOS端
    • 生成公钥和私钥

    1)新建文件夹,用来保存生成的私钥和公钥,打开终端 cd 新建,进入到新建文件夹中,openssl,打开openssl

    3
    1. genrsa -out rsa_private_key.pem 1024生成私钥
    4
    1. pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt这步一定要有,需要将私钥转成PKCS8的格式才能使用,此时复制私钥(先复制私钥,然后在4步取出公钥)
    5

    4)rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem 生成公钥

    6

    此时在新建文件夹中会出现两个文件

    7

    我们用文本编辑器打开便可获取iOS端生成的公钥和私钥。

    • Xcode项目实战

    还得利用上面提到的RSA文件

     //公钥
        NSString *publicKey = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDl5RBHD3abOyeYCOLkaWkpJXgJQfMklOWPmdJAnG1eD6CV+UOpUKMy5LtfGHQEM7ao5x3BpMx4MNRUYVwBAmU84PhwNm6xpTJrg5zZCloFmsX+E5ukWE5YFRu8i5+5d8LuQTTTv4XfzbTCTOhON8uj+ypkomETuVNwgRFVFjHd1QIDAQAB";
        //私钥
        NSString *privateKey = @"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOXlEEcPdps7J5gI4uRpaSkleAlB8ySU5Y+Z0kCcbV4PoJX5Q6lQozLku18YdAQztqjnHcGkzHgw1FRhXAECZTzg+HA2brGlMmuDnNkKWgWaxf4Tm6RYTlgVG7yLn7l3wu5BNNO/hd/NtMJM6E43y6P7KmSiYRO5U3CBEVUWMd3VAgMBAAECgYEAkqHVDQ4O35oOegmI9plJauYsNvNqqzWRalN5aJ6dn3YmPiI8Bt2ZClgcLt6A+UEmy3qGX0HG7Q5wD9X9geNOQB3ZiD/pGAGW08wS/wTxnWSnSBwdtZ03pUttfnFctkxULfDq4iG1ywdjqEk3F8QVFajQ0c76kWbt9LGAv2OGIi0CQQD2CmbVFXy4JeNHK3TDoLMjsUCiLa+qPnyyVDLDG9Ozb7wN2ydTrMhI+0udmjKvy/Lm1E2bKyp42iYuubEqvSAXAkEA7zNZsOgUe0q73sxXqrLQ7Fs7TNtIEXghrGmkVTHN0I7uMKzQ7KEbA6hfcBm4hPMoLa6Ag3m9tiMNBWtDWc/Y8wJAK0//dEl5EC3TSccTohCbGJBukV47i1u+teHuobw3U2I7F7FZxfgntflPAWqQu7PKieob01IRAv9cM2OLFbv/dwJBAIniXedeQMA5ekaaIEbjwQ8eH/bTyJ1ZVH/gfbwmc2+vlJo2ZFCjJcFcA3fJO9ZXnGeI2cfwG22sksr24+IXsAUCQG5yvVIleTDYqWuWVG1Rc8fk5UFjoZzJpp0nil0z+0fR5rogr4fxcH7vbWsE0id7gSvtV7KxPzkvJTpOK3yGDN0=";
        //测试要加密的数据
        NSString *sourceStr = @"iOS端RSA";
        //公钥加密
        NSString *encryptStr = [RSA encryptString:sourceStr publicKey:publicKey];
        //私钥解密
        NSString *decrypeStr = [RSA decryptString:encryptStr privateKey:privateKey];
        NSLog(@"加密后的数据 %@ 解密后的数据 %@",encryptStr,decrypeStr);
    

    打印结果:

    8

    经过测试,私钥和公钥是可以使用的。

    Java端

    我是用的是Eclipse,具体实现方法也是从网上找的,因为打开的东西太多,忘了是哪篇博客了,知道的请联系我,会注明作者的。

    • 前期准备

    9

    RSAUtils.java代码:

    package RSA;
    
    import java.io.ByteArrayOutputStream;  
    import java.security.Key;  
    import java.security.KeyFactory;  
    import java.security.KeyPair;  
    import java.security.KeyPairGenerator;  
    import java.security.PrivateKey;  
    import java.security.PublicKey;  
    import java.security.Signature;  
    import java.security.interfaces.RSAPrivateKey;  
    import java.security.interfaces.RSAPublicKey;  
    import java.security.spec.PKCS8EncodedKeySpec;  
    import java.security.spec.X509EncodedKeySpec;  
    import java.util.HashMap;  
    import java.util.Map;
    import javax.crypto.Cipher;  
    /** *//** 
     * <p> 
     * RSA公钥/私钥/签名工具包 
     * </p> 
     * <p> 
     * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman) 
     * </p> 
     * <p> 
     * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/> 
     * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/> 
     * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全 
     * </p> 
     *  
     * @author IceWee 
     * @date 2012-4-26 
     * @version 1.0 
     */  
    public class RSAUtils {
        /** *//** 
         * 加密算法RSA 
         */  
        public static final String KEY_ALGORITHM = "RSA";  
          
        /** *//** 
         * 签名算法 
         */  
        public static final String SIGNATURE_ALGORITHM = "MD5withRSA";  
      
        /** *//** 
         * 获取公钥的key 
         */  
        private static final String PUBLIC_KEY = "RSAPublicKey";  
          
        /** *//** 
         * 获取私钥的key 
         */  
        private static final String PRIVATE_KEY = "RSAPrivateKey";  
          
        /** *//** 
         * RSA最大加密明文大小 
         */  
        private static final int MAX_ENCRYPT_BLOCK = 117;  
          
        /** *//** 
         * RSA最大解密密文大小 
         */  
        private static final int MAX_DECRYPT_BLOCK = 128;  
      
        /** *//** 
         * <p> 
         * 生成密钥对(公钥和私钥) 
         * </p> 
         *  
         * @return 
         * @throws Exception 
         */  
        public static Map<String, Object> genKeyPair() throws Exception {  
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);  
            keyPairGen.initialize(1024);  
            KeyPair keyPair = keyPairGen.generateKeyPair();  
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();  
            Map<String, Object> keyMap = new HashMap<String, Object>(2);  
            keyMap.put(PUBLIC_KEY, publicKey);  
            keyMap.put(PRIVATE_KEY, privateKey);  
            return keyMap;  
        }  
          
        /** *//** 
         * <p> 
         * 用私钥对信息生成数字签名 
         * </p> 
         *  
         * @param data 已加密数据 
         * @param privateKey 私钥(BASE64编码) 
         *  
         * @return 
         * @throws Exception 
         */  
        public static String sign(byte[] data, String privateKey) throws Exception {  
            byte[] keyBytes = Base64Utils.decode(privateKey);  
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);  
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initSign(privateK);  
            signature.update(data);  
            return Base64Utils.encode(signature.sign());  
        }  
      
        /** *//** 
         * <p> 
         * 校验数字签名 
         * </p> 
         *  
         * @param data 已加密数据 
         * @param publicKey 公钥(BASE64编码) 
         * @param sign 数字签名 
         *  
         * @return 
         * @throws Exception 
         *  
         */  
        public static boolean verify(byte[] data, String publicKey, String sign)  
                throws Exception {  
            byte[] keyBytes = Base64Utils.decode(publicKey);  
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            PublicKey publicK = keyFactory.generatePublic(keySpec);  
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initVerify(publicK);  
            signature.update(data);  
            return signature.verify(Base64Utils.decode(sign));  
        }  
      
        /** *//** 
         * <P> 
         * 私钥解密 
         * </p> 
         *  
         * @param encryptedData 已加密数据 
         * @param privateKey 私钥(BASE64编码) 
         * @return 
         * @throws Exception 
         */  
        public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)  
                throws Exception {  
            byte[] keyBytes = Base64Utils.decode(privateKey);  
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);  
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.DECRYPT_MODE, privateK);  
            int inputLen = encryptedData.length;  
            ByteArrayOutputStream out = new ByteArrayOutputStream();  
            int offSet = 0;  
            byte[] cache;  
            int i = 0;  
            // 对数据分段解密  
            while (inputLen - offSet > 0) {  
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {  
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);  
                } else {  
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);  
                }  
                out.write(cache, 0, cache.length);  
                i++;  
                offSet = i * MAX_DECRYPT_BLOCK;  
            }  
            byte[] decryptedData = out.toByteArray();  
            out.close();  
            return decryptedData;  
        }  
      
        /** *//** 
         * <p> 
         * 公钥解密 
         * </p> 
         *  
         * @param encryptedData 已加密数据 
         * @param publicKey 公钥(BASE64编码) 
         * @return 
         * @throws Exception 
         */  
        public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)  
                throws Exception {  
            byte[] keyBytes = Base64Utils.decode(publicKey);  
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            Key publicK = keyFactory.generatePublic(x509KeySpec);  
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.DECRYPT_MODE, publicK);  
            int inputLen = encryptedData.length;  
            ByteArrayOutputStream out = new ByteArrayOutputStream();  
            int offSet = 0;  
            byte[] cache;  
            int i = 0;  
            // 对数据分段解密  
            while (inputLen - offSet > 0) {  
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {  
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);  
                } else {  
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);  
                }  
                out.write(cache, 0, cache.length);  
                i++;  
                offSet = i * MAX_DECRYPT_BLOCK;  
            }  
            byte[] decryptedData = out.toByteArray();  
            out.close();  
            return decryptedData;  
        }  
      
        /** *//** 
         * <p> 
         * 公钥加密 
         * </p> 
         *  
         * @param data 源数据 
         * @param publicKey 公钥(BASE64编码) 
         * @return 
         * @throws Exception 
         */  
        public static byte[] encryptByPublicKey(byte[] data, String publicKey)  
                throws Exception {  
            byte[] keyBytes = Base64Utils.decode(publicKey);  
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            Key publicK = keyFactory.generatePublic(x509KeySpec);  
            // 对数据加密  
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.ENCRYPT_MODE, publicK);  
            int inputLen = data.length;  
            ByteArrayOutputStream out = new ByteArrayOutputStream();  
            int offSet = 0;  
            byte[] cache;  
            int i = 0;  
            // 对数据分段加密  
            while (inputLen - offSet > 0) {  
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {  
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);  
                } else {  
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);  
                }  
                out.write(cache, 0, cache.length);  
                i++;  
                offSet = i * MAX_ENCRYPT_BLOCK;  
            }  
            byte[] encryptedData = out.toByteArray();  
            out.close();  
            return encryptedData;  
        }  
      
        /** *//** 
         * <p> 
         * 私钥加密 
         * </p> 
         *  
         * @param data 源数据 
         * @param privateKey 私钥(BASE64编码) 
         * @return 
         * @throws Exception 
         */  
        public static byte[] encryptByPrivateKey(byte[] data, String privateKey)  
                throws Exception {  
            byte[] keyBytes = Base64Utils.decode(privateKey);  
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);  
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());  
            cipher.init(Cipher.ENCRYPT_MODE, privateK);  
            int inputLen = data.length;  
            ByteArrayOutputStream out = new ByteArrayOutputStream();  
            int offSet = 0;  
            byte[] cache;  
            int i = 0;  
            // 对数据分段加密  
            while (inputLen - offSet > 0) {  
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {  
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);  
                } else {  
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);  
                }  
                out.write(cache, 0, cache.length);  
                i++;  
                offSet = i * MAX_ENCRYPT_BLOCK;  
            }  
            byte[] encryptedData = out.toByteArray();  
            out.close();  
            return encryptedData;  
        }  
      
        /** *//** 
         * <p> 
         * 获取私钥 
         * </p> 
         *  
         * @param keyMap 密钥对 
         * @return 
         * @throws Exception 
         */  
        public static String getPrivateKey(Map<String, Object> keyMap)  
                throws Exception {  
            Key key = (Key) keyMap.get(PRIVATE_KEY);  
            return Base64Utils.encode(key.getEncoded());  
        }  
      
        /** *//** 
         * <p> 
         * 获取公钥 
         * </p> 
         *  
         * @param keyMap 密钥对 xs
         * @return 
         * @throws Exception 
         */  
        public static String getPublicKey(Map<String, Object> keyMap)  
                throws Exception {  
            Key key = (Key) keyMap.get(PUBLIC_KEY);  
            return Base64Utils.encode(key.getEncoded());  
        } 
    }
    

    Base64Utils.java 文件代码:

    package RSA;
    import java.io.ByteArrayInputStream;  
    import java.io.ByteArrayOutputStream;  
    import java.io.File;  
    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
    import java.io.InputStream;  
    import java.io.OutputStream;
    import it.sauronsoftware.base64.Base64;  
    
    public class Base64Utils {
        /** *//** 
         * 文件读取缓冲区大小 
         */  
        private static final int CACHE_SIZE = 1024;  
          
        /** *//** 
         * <p> 
         * BASE64字符串解码为二进制数据 
         * </p> 
         *  
         * @param base64 
         * @return 
         * @throws Exception 
         */  
        public static byte[] decode(String base64) throws Exception {  
            return Base64.decode(base64.getBytes());  
        }  
          
        /** *//** 
         * <p> 
         * 二进制数据编码为BASE64字符串 
         * </p> 
         *  
         * @param bytes 
         * @return 
         * @throws Exception 
         */  
        public static String encode(byte[] bytes) throws Exception {  
            return new String(Base64.encode(bytes));  
        }  
          
        /** *//** 
         * <p> 
         * 将文件编码为BASE64字符串 
         * </p> 
         * <p> 
         * 大文件慎用,可能会导致内存溢出 
         * </p> 
         *  
         * @param filePath 文件绝对路径 
         * @return 
         * @throws Exception 
         */  
        public static String encodeFile(String filePath) throws Exception {  
            byte[] bytes = fileToByte(filePath);  
            return encode(bytes);  
        }  
          
        /** *//** 
         * <p> 
         * BASE64字符串转回文件 
         * </p> 
         *  
         * @param filePath 文件绝对路径 
         * @param base64 编码字符串 
         * @throws Exception 
         */  
        public static void decodeToFile(String filePath, String base64) throws Exception {  
            byte[] bytes = decode(base64);  
            byteArrayToFile(bytes, filePath);  
        }  
          
        /** *//** 
         * <p> 
         * 文件转换为二进制数组 
         * </p> 
         *  
         * @param filePath 文件路径 
         * @return 
         * @throws Exception 
         */  
        public static byte[] fileToByte(String filePath) throws Exception {  
            byte[] data = new byte[0];  
            File file = new File(filePath);  
            if (file.exists()) {  
                FileInputStream in = new FileInputStream(file);  
                ByteArrayOutputStream out = new ByteArrayOutputStream(2048);  
                byte[] cache = new byte[CACHE_SIZE];  
                int nRead = 0;  
                while ((nRead = in.read(cache)) != -1) {  
                    out.write(cache, 0, nRead);  
                    out.flush();  
                }  
                out.close();  
                in.close();  
                data = out.toByteArray();  
             }  
            return data;  
        }  
          
        /** *//** 
         * <p> 
         * 二进制数据写文件 
         * </p> 
         *  
         * @param bytes 二进制数据 
         * @param filePath 文件生成目录 
         */  
        public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {  
            InputStream in = new ByteArrayInputStream(bytes);     
            File destFile = new File(filePath);  
            if (!destFile.getParentFile().exists()) {  
                destFile.getParentFile().mkdirs();  
            }  
            destFile.createNewFile();  
            OutputStream out = new FileOutputStream(destFile);  
            byte[] cache = new byte[CACHE_SIZE];  
            int nRead = 0;  
            while ((nRead = in.read(cache)) != -1) {     
                out.write(cache, 0, nRead);  
                out.flush();  
            }  
            out.close();  
            in.close();  
        }
    
    }
    
    

    Test.java文件中

    package RSA;
    import java.util.Map;  
    
    
    public class Test {
         static String publicKey;  
            static String privateKey;  
          
            static {  
                try {  
                    Map<String, Object> keyMap = RSAUtils.genKeyPair();  
                    publicKey = RSAUtils.getPublicKey(keyMap);  
                    privateKey = RSAUtils.getPrivateKey(keyMap);  
                    System.err.println("公钥: \n\r" + publicKey);  
                    System.err.println("私钥: \n\r" + privateKey);  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
        
        public static void main(String[] args) throws Exception {
            test();
        }
    //加密数据
        static void test() throws Exception {  
            String source = "Java端RSA";  
            System.out.println("\r加密前文字:\r\n" + source);  
            byte[] data = source.getBytes();  
                 
            byte[] encodedData = RSAUtils.encryptByPrivateKey(data,privateKey); 
            System.out.println("加密后文字:\r\n" + new String(encodedData));  
           
            byte[] decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey);  
            
            String target = new String(decodedData);  
            System.out.println("解密后文字: \r\n" + target);  
        }  
      //验证签名
        static void testSign() throws Exception {  
            System.err.println("私钥加密——公钥解密");  
            String source = "这是一行测试RSA数字签名的无意义文字";  
            System.out.println("原文字:\r\n" + source);  
            byte[] data = source.getBytes();  
            byte[] encodedData = RSAUtils.encryptByPrivateKey(data, privateKey);  
            System.out.println("加密后:\r\n" + new String(encodedData));  
            byte[] decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey);  
            String target = new String(decodedData);  
            System.out.println("解密后: \r\n" + target);  
            System.err.println("私钥签名——公钥验证签名");  
            String sign = RSAUtils.sign(encodedData, privateKey);  
            System.err.println("签名:\r" + sign);  
            boolean status = RSAUtils.verify(encodedData, publicKey, sign);  
            System.err.println("验证结果:\r" + status);  
        }  
    }
    

    打印结果:

    10

    在此,我们可以获取java端生成的私钥和公钥
    javaPrivateKey:

    MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAICJzSMJQJWRMP/eAQpHpeFvoZ6TlEpDwzOu7U7COK0QFOfbSqw8+jVckcUXsbIeluay5kQBogrlzcBcEOUabMczFQRsb9Lo9fa1TObDPOb+Vexg2ndk6BjGO85npXTQlRx1PQzJ2JoFWjdwFxUX9bgkeZLgkYyPpQroHK4SIe5HAgMBAAECgYAYl8T67htAQp5IZjZ2vAyd3Fjk2UGnD936Nn7K8dgcLJaDYe6gk64fpY1yUz05YibnDtWFr3ZMdXlvU24cF3k2PoIyu/CK+/HxToAI1kx0yk52QdiBfiG9vPIqZmCCDWYm0kLE1ayEt2JMDbMWqlMfA7LWzlFEPsO63Jc4hH0BOQJBAPul4inORuoDgtBPxPGUcCICJJZ0xw+kFxgZjSnV0qcP3nQDdzqLiPPJ9Z8jJziIUEqXaxI0qOG7OFlMW8os5qUCQQCCwuBk/Gve/z+j386yiaJFQwxH8SAO97FuHDmYPJtdjrX7o6Uboq9GydzrPwNNK1odV4S858pXksZnU7K2lRl7AkEA6cv8i4qyJ8iLSK5T835Nj8sd4wsrxkRVkHZsyGl4BO6hZnex1hq9aoJASVGHpuY+co6rU4bJQK+Icq6WuQduYQJAaVcM5s3jKNaAMkhOf84ZB6sn7Zz2spggPBBI5beNgiVBveLrVAQPJ/vfGTS+OCDAi/rBWF1yyHHZm8v1oNkkmQJBAPJ5eXbeQngp3s4fi4wc+RuaXVpnwv1HHsUc3JlxfIRcuLthNKZJdLbQO8tjCfnEjztweJP6HjaO6VxZ50o/EDw=
    

    javaPublicKey:

    上面的只是生成公钥和私钥并且是在当前环境测试,也就是iOS测试自己的,Java测试自己的,我上面也已经说了,iOS端与后台如何进行双向加密的,下面具体测试。

    双向加密
    • iOS端加密,Java端解密
      iOS端利用javaPublicKey加密数据

    11

    java端利用javaPrivate解密
    12

    打印结果:

    13
    • Java端加密,iOS端解密
      Java端利用 iOSPublicKey加密
    14

    15

    iOS端利用iOSPrivateKey解密

    16

    打印结果:

    17
    最后

    至此,单向加密与双向加密,尤其是与后台之间的加密已经讲完了,因为之前看过一些文章有的很模糊,双向加密的讲解很少,并且一些文章的编辑格式真的是难看,根本就没办法看下去,所以花了一点时间讲讲我对这方面的理解,知识其实很浅,并不高深。
    注意点:
    1、关于iOS端保存的私钥和公钥最好是生成文件保存,并且设置密码,这样为了更安全,这个网上都有,可以找找。
    2、在RSA原理上公钥和私钥是可以互相加密互相解密的。公钥加密,私钥解密一般是用于加密数据的,私钥加密公钥解密是用于验证身份的,也就是验证签名。但在iOS端只能用公钥加密私钥解密(不和后台交互,只是在iOS平台),只能用私钥加密公钥验签,请参考文章。如果是和后台进行加密,无论后台是用公钥加密还是私钥加密,iOS端都是可以解的。这个大家可以试试,在RSA文件中,其实他在RSA.h中已经说明了
    // enc with private key NOT working YET!
    + (NSString *)encryptString:(NSString *)str privateKey:(NSString *)privKey;
    用私钥加密的方法并未实现,具体iOS为何不能用私钥加密公钥解密还在搜索资料中,如果有知道的童鞋请告知,不胜感谢。
    8月4日解答:关于非对称加密是没有说用私钥加密公钥解密的,私钥只能用来解密和生成签名,公钥只能用来加密和验签,特此声明!


    展开全文
  • 别人分享的githup地址:https://github.com/caohuoxia/RSADemo在iOS中使用RSA加密解密,需要用到.der和.p12后缀格式的文件,其中.der格式的文件存放的是公钥(Public key)用于加密,.p12格式的文件存放的是私钥...

    别人分享的githup地址:https://github.com/caohuoxia/RSADemo

    在iOS中使用RSA加密解密,需要用到.der.p12后缀格式的文件,其中.der格式的文件存放的是公钥(Public key)用于加密,.p12格式的文件存放的是私钥(Private key)用于解密. 首先需要先生成这些文件,然后再将文件导入工程使用,不多说,开始做!

    一、使用openssl生成所需秘钥文件

    生成环境是在mac系统下,使用openssl进行生成,首先打开终端,按下面这些步骤依次来做:

    1. 生成模长为1024bit的私钥文件private_key.pem
    openssl genrsa -out private_key.pem 1024
    
    2. 生成证书请求文件rsaCertReq.csr
    openssl req -new -key private_key.pem -out rsaCerReq.csr
    

    注意:这一步会提示输入国家、省份、mail等信息,可以根据实际情况填写,或者全部不用填写,直接全部敲回车.

    3. 生成证书rsaCert.crt,并设置有效时间为1年
    openssl x509 -req -days 3650 -in rsaCerReq.csr -signkey private_key.pem -out rsaCert.crt
    
    4. 生成供iOS使用的公钥文件public_key.der
    openssl x509 -outform der -in rsaCert.crt -out public_key.der
    
    5. 生成供iOS使用的私钥文件private_key.p12
    openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt
    

    注意:这一步会提示给私钥文件设置密码,直接输入想要设置密码即可,然后敲回车,然后再验证刚才设置的密码,再次输入密码,然后敲回车,完毕!
    在解密时,private_key.p12文件需要和这里设置的密码配合使用,因此需要牢记此密码.

    6. 生成供Java使用的公钥rsa_public_key.pem
    openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
    
    7. 生成供Java使用的私钥pkcs8_private_key.pem
    openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt
    

    全部执行成功后,会生成如下文件,其中public_key.derprivate_key.p12就是iOS需要用到的文件,如下图:

    二、将文件导入工程使用

    1.新建工程, 并导入Security.framework框架, 如下图:
    新建工程并添加框架
    2.导入秘钥文件

    导入.der.p12格式的秘钥文件, 如下图:

    导入秘钥文件

    3.新建用于加密、解密的类RSAEncryptor, 并实现相关方法

    新建RSAEncryptor类, 如下图:

    新建用于加密解密的类

    下面开始上代码, 可以直接复制过去用:
    RSAEncryptor.h代码如下:

    #import <Foundation/Foundation.h>
    
    @interface RSAEncryptor : NSObject
    
    /**
     *  加密方法
     *
     *  @param str   需要加密的字符串
     *  @param path  '.der'格式的公钥文件路径
     */
    + (NSString *)encryptString:(NSString *)str publicKeyWithContentsOfFile:(NSString *)path;
    
    /**
     *  解密方法
     *
     *  @param str       需要解密的字符串
     *  @param path      '.p12'格式的私钥文件路径
     *  @param password  私钥文件密码
     */
    + (NSString *)decryptString:(NSString *)str privateKeyWithContentsOfFile:(NSString *)path password:(NSString *)password;
    
    /**
     *  加密方法
     *
     *  @param str    需要加密的字符串
     *  @param pubKey 公钥字符串
     */
    + (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey;
    
    /**
     *  解密方法
     *
     *  @param str     需要解密的字符串
     *  @param privKey 私钥字符串
     */
    + (NSString *)decryptString:(NSString *)str privateKey:(NSString *)privKey;
    
    @end
    

    RSAEncryptor.m代码如下:

    #import "RSAEncryptor.h"
    #import <Security/Security.h>
    
    @implementation RSAEncryptor
    
    static NSString *base64_encode_data(NSData *data){
        data = [data base64EncodedDataWithOptions:0];
        NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        return ret;
    }
    
    static NSData *base64_decode(NSString *str){
        NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
        return data;
    }
    
    #pragma mark - 使用'.der'公钥文件加密
    
    //加密
    + (NSString *)encryptString:(NSString *)str publicKeyWithContentsOfFile:(NSString *)path{
        if (!str || !path)  return nil;
        return [self encryptString:str publicKeyRef:[self getPublicKeyRefWithContentsOfFile:path]];
    }
    
    //获取公钥
    + (SecKeyRef)getPublicKeyRefWithContentsOfFile:(NSString *)filePath{
        NSData *certData = [NSData dataWithContentsOfFile:filePath];
        if (!certData) {
            return nil;
        }
        SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
        SecKeyRef key = NULL;
        SecTrustRef trust = NULL;
        SecPolicyRef policy = NULL;
        if (cert != NULL) {
            policy = SecPolicyCreateBasicX509();
            if (policy) {
                if (SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust) == noErr) {
                    SecTrustResultType result;
                    if (SecTrustEvaluate(trust, &result) == noErr) {
                        key = SecTrustCopyPublicKey(trust);
                    }
                }
            }
        }
        if (policy) CFRelease(policy);
        if (trust) CFRelease(trust);
        if (cert) CFRelease(cert);
        return key;
    }
    
    + (NSString *)encryptString:(NSString *)str publicKeyRef:(SecKeyRef)publicKeyRef{
        if(![str dataUsingEncoding:NSUTF8StringEncoding]){
            return nil;
        }
        if(!publicKeyRef){
            return nil;
        }
        NSData *data = [self encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] withKeyRef:publicKeyRef];
        NSString *ret = base64_encode_data(data);
        return ret;
    }
    
    #pragma mark - 使用'.12'私钥文件解密
    
    //解密
    + (NSString *)decryptString:(NSString *)str privateKeyWithContentsOfFile:(NSString *)path password:(NSString *)password{
        if (!str || !path) return nil;
        if (!password) password = @"";
        return [self decryptString:str privateKeyRef:[self getPrivateKeyRefWithContentsOfFile:path password:password]];
    }
    
    //获取私钥
    + (SecKeyRef)getPrivateKeyRefWithContentsOfFile:(NSString *)filePath password:(NSString*)password{
        
        NSData *p12Data = [NSData dataWithContentsOfFile:filePath];
        if (!p12Data) {
            return nil;
        }
        SecKeyRef privateKeyRef = NULL;
        NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
        [options setObject: password forKey:(__bridge id)kSecImportExportPassphrase];
        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
        OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data, (__bridge CFDictionaryRef)options, &items);
        if (securityError == noErr && CFArrayGetCount(items) > 0) {
            CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
            SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
            securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);
            if (securityError != noErr) {
                privateKeyRef = NULL;
            }
        }
        CFRelease(items);
        
        return privateKeyRef;
    }
    
    + (NSString *)decryptString:(NSString *)str privateKeyRef:(SecKeyRef)privKeyRef{
        NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
        if (!privKeyRef) {
            return nil;
        }
        data = [self decryptData:data withKeyRef:privKeyRef];
        NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        return ret;
    }
    
    #pragma mark - 使用公钥字符串加密
    
    /* START: Encryption with RSA public key */
    
    //使用公钥字符串加密
    + (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey{
        NSData *data = [self encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey];
        NSString *ret = base64_encode_data(data);
        return ret;
    }
    
    + (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{
        if(!data || !pubKey){
            return nil;
        }
        SecKeyRef keyRef = [self addPublicKey:pubKey];
        if(!keyRef){
            return nil;
        }
        return [self encryptData:data withKeyRef: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){
            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 = [self stripPublicKeyHeader:data];
        if(!data){
            return nil;
        }
        
        //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:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
        [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
        SecItemDelete((__bridge CFDictionaryRef)publicKey);
        
        // Add persistent version of the key to system keychain
        [publicKey setObject:data forKey:(__bridge id)kSecValueData];
        [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)
         kSecAttrKeyClass];
        [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
         kSecReturnPersistentRef];
        
        CFTypeRef persistKey = nil;
        OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey);
        if (persistKey != nil){
            CFRelease(persistKey);
        }
        if ((status != noErr) && (status != errSecDuplicateItem)) {
            return nil;
        }
        
        [publicKey removeObjectForKey:(__bridge id)kSecValueData];
        [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
        [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
        [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        
        // Now fetch the SecKeyRef version of the key
        SecKeyRef keyRef = nil;
        status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef);
        if(status != noErr){
            return nil;
        }
        return keyRef;
    }
    
    + (NSData *)stripPublicKeyHeader:(NSData *)d_key{
        // Skip ASN.1 public key header
        if (d_key == nil) return(nil);
        
        unsigned long len = [d_key length];
        if (!len) return(nil);
        
        unsigned char *c_key = (unsigned char *)[d_key bytes];
        unsigned int  idx     = 0;
        
        if (c_key[idx++] != 0x30) return(nil);
        
        if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
        else idx++;
        
        // 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;
        else idx++;
        
        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{
        const uint8_t *srcbuf = (const uint8_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(int idx=0; idx<srclen; idx+=src_block_size){
            //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);
        return ret;
    }
    
    /* END: Encryption with RSA public key */
    
    #pragma mark - 使用私钥字符串解密
    
    /* START: Decryption with RSA private key */
    
    //使用私钥字符串解密
    + (NSString *)decryptString:(NSString *)str privateKey:(NSString *)privKey{
        if (!str) return nil;
        NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
        data = [self decryptData:data privateKey:privKey];
        NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        return ret;
    }
    
    + (NSData *)decryptData:(NSData *)data privateKey:(NSString *)privKey{
        if(!data || !privKey){
            return nil;
        }
        SecKeyRef keyRef = [self addPrivateKey:privKey];
        if(!keyRef){
            return nil;
        }
        return [self decryptData:data withKeyRef: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){
            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 = [self stripPrivateKeyHeader:data];
        if(!data){
            return nil;
        }
        
        //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:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
        [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        [privateKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
        SecItemDelete((__bridge CFDictionaryRef)privateKey);
        
        // Add persistent version of the key to system keychain
        [privateKey setObject:data forKey:(__bridge id)kSecValueData];
        [privateKey setObject:(__bridge id) kSecAttrKeyClassPrivate forKey:(__bridge id)
         kSecAttrKeyClass];
        [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)
         kSecReturnPersistentRef];
        
        CFTypeRef persistKey = nil;
        OSStatus status = SecItemAdd((__bridge CFDictionaryRef)privateKey, &persistKey);
        if (persistKey != nil){
            CFRelease(persistKey);
        }
        if ((status != noErr) && (status != errSecDuplicateItem)) {
            return nil;
        }
        
        [privateKey removeObjectForKey:(__bridge id)kSecValueData];
        [privateKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
        [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
        [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
        
        // Now fetch the SecKeyRef version of the key
        SecKeyRef keyRef = nil;
        status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKey, (CFTypeRef *)&keyRef);
        if(status != noErr){
            return nil;
        }
        return keyRef;
    }
    
    + (NSData *)stripPrivateKeyHeader:(NSData *)d_key{
        // Skip ASN.1 private key header
        if (d_key == nil) return(nil);
        
        unsigned long len = [d_key length];
        if (!len) return(nil);
        
        unsigned char *c_key = (unsigned char *)[d_key bytes];
        unsigned int  idx     = 22; //magic byte at offset 22
        
        if (0x04 != c_key[idx++]) return nil;
        
        //calculate length of the key
        unsigned int c_len = c_key[idx++];
        int det = c_len & 0x80;
        if (!det) {
            c_len = c_len & 0x7f;
        } else {
            int byteCount = c_len & 0x7f;
            if (byteCount + idx > len) {
                //rsa length field longer than buffer
                return nil;
            }
            unsigned int accum = 0;
            unsigned char *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{
        const uint8_t *srcbuf = (const uint8_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(int idx=0; idx<srclen; idx+=src_block_size){
            //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 = SecKeyDecrypt(keyRef,
                                   kSecPaddingNone,
                                   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!
                int idxFirstZero = -1;
                int idxNextZero = (int)outlen;
                for ( int i = 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);
        return ret;
    }
    
    /* END: Decryption with RSA private key */
    
    @end
    
    4. 测试加密、解密

    首先先测试使用.der.p12秘钥文件进行加密、解密, 在ViewController.m中进行测试, 代码如下:

    #import "ViewController.h"
    #import "RSAEncryptor.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //原始数据
        NSString *originalString = @"这是一段将要使用'.der'文件加密的字符串!";
        
        //使用.der和.p12中的公钥私钥加密解密
        NSString *public_key_path = [[NSBundle mainBundle] pathForResource:@"public_key.der" ofType:nil];
        NSString *private_key_path = [[NSBundle mainBundle] pathForResource:@"private_key.p12" ofType:nil];
        
        NSString *encryptStr = [RSAEncryptor encryptString:originalString publicKeyWithContentsOfFile:public_key_path];
        NSLog(@"加密前:%@", originalString);
        NSLog(@"加密后:%@", encryptStr);
        NSLog(@"解密后:%@", [RSAEncryptor decryptString:encryptStr privateKeyWithContentsOfFile:private_key_path password:@"123456"]);
        
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    运行后, 输出信息如下:


    输出结果

    可以看到已经可以成功加密、解密了.

    下面接着测试使用秘钥字符串进行加密、解密, 那么秘钥字符串从哪里来? 可以来这里:http://web.chacuo.net/netrsakeypair, 这是一个在线生成RSA秘钥的网站, 生成公钥和秘钥后, 复制出来用于测试. 然后在ViewController.m中使用RSAEntryptor.h头文件中对应的加密方法进行加密, ViewController.m中代码如下:

    #import "ViewController.h"
    #import "RSAEncryptor.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //原始数据
        NSString *originalString = @"这是一段将要使用'秘钥字符串'进行加密的字符串!";
        
        //使用字符串格式的公钥私钥加密解密
        NSString *encryptStr = [RSAEncryptor encryptString:originalString publicKey:@"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTbZ6cNH9PgdF60aQKveLz3FTalyzHQwbp601y77SzmGHX3F5NoVUZbdK7UMdoCLK4FBziTewYD9DWvAErXZo9BFuI96bAop8wfl1VkZyyHTcznxNJFGSQd/B70/ExMgMBpEwkAAdyUqIjIdVGh1FQK/4acwS39YXwbS+IlHsPSQIDAQAB"];
        
        NSLog(@"加密前:%@", originalString);
        NSLog(@"加密后:%@", encryptStr);
        NSLog(@"解密后:%@", [RSAEncryptor decryptString:encryptStr privateKey:@"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANNtnpw0f0+B0XrRpAq94vPcVNqXLMdDBunrTXLvtLOYYdfcXk2hVRlt0rtQx2gIsrgUHOJN7BgP0Na8AStdmj0EW4j3psCinzB+XVWRnLIdNzOfE0kUZJB38HvT8TEyAwGkTCQAB3JSoiMh1UaHUVAr/hpzBLf1hfBtL4iUew9JAgMBAAECgYA1tGeQmAkqofga8XtwuxEWDoaDS9k0+EKeUoXGxzqoT/GyiihuIafjILFhoUA1ndf/yCQaG973sbTDhtfpMwqFNQq13+JAownslTjWgr7Hwf7qplYW92R7CU0v7wFfjqm1t/2FKU9JkHfaHfb7qqESMIbO/VMjER9o4tEx58uXDQJBAO0O4lnWDVjr1gN02cqvxPOtTY6DgFbQDeaAZF8obb6XqvCqGW/AVms3Bh8nVlUwdQ2K/xte8tHxjW9FtBQTLd8CQQDkUncO35gAqUF9Bhsdzrs7nO1J3VjLrM0ITrepqjqtVEvdXZc+1/UrkWVaIigWAXjQCVfmQzScdbznhYXPz5fXAkEAgB3KMRkhL4yNpmKRjhw+ih+ASeRCCSj6Sjfbhx4XaakYZmbXxnChg+JB+bZNz06YBFC5nLZM7y/n61o1f5/56wJBALw+ZVzE6ly5L34114uG04W9x0HcFgau7MiJphFjgUdAtd/H9xfgE4odMRPUD3q9Me9LlMYK6MiKpfm4c2+3dzcCQQC8y37NPgpNEkd9smMwPpSEjPW41aMlfcKvP4Da3z7G5bGlmuICrva9YDAiaAyDGGCK8LxC8K6HpKrFgYrXkRtt"]);
        
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    运行后, 输出信息如下:

    输出结果

    可以看到,也成功加密、解密了.

    至此, RSA加密演示完毕!



    作者:jianshu_wl
    链接:https://www.jianshu.com/p/74a796ec5038
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    展开全文
  • 然后在IOS端,如果直接拿着这个转化的字符串密钥(通过BASE64解密后)去做RSA加密的话,这边JAVA端解密会失败。所以,请问下,在密钥方面应该怎么处理呢?JAVA端生成的密钥怎样处理给到IOS端才会成功?谢谢!
  • RSA 加密解密,主要涉及到的框架为 Security框架。 所需的 公匙(加密) 私匙(解密),基本由后台提供。一般格式为.der 或者 更简单粗暴的后台,会...这是我在兼容iOS10出现问题后,再度研究rsa加密的过程中看到的 最简单

    RSA 加密解密,主要涉及到的框架为 Security框架。

    所需的 公匙(加密)   私匙(解密),基本由后台提供。一般格式为.der 或者 更简单粗暴的后台,会给你字符串。 关于der格式的,可以参考 http://blog.csdn.net/yi_zz32/article/details/50097325 这篇博客。这是我在兼容iOS10出现问题后,再度研究rsa加密的过程中看到的 最简单粗暴的方法。因为看到这篇文章的时候,我的项目已经完成了rsa加密,所以并没有试用。


    我主要说的是  后台给的 公匙(加密)   私匙(解密)是字符串的情况。


    具体代码。。我就不贴了。。。因为我觉得那并没有什么卵用。我将所需的类和一些辅助使用的类放在一个文件夹里。压缩后,放在网盘。可以自行下载。


    关于iOS10 的RSA 加密。

    我必须提醒一下,请打开钥匙串的权限。不然的话,虽然不会报错,但是 你会发现  SecKeyRef这个类的对象,是个空值。从而导致, seletemAdd 和 maching 这两个方法导致 -34018的错误。然后你的加密就废掉了。钥匙串权限开启,我已经截了图。


    其他相关的类文件,在网盘里,请自行下载。   相关类点击下载




    展开全文
  • iOS接口的RSA加密算法

    2018-07-31 11:42:51
    之前说过,我最近一段时间负责APP的接口部分的工作,所以... 在iOS中使用RSA加密解密,需要用到.der和.p12后缀格式的文件,其中.der格式的文件存放的是公钥(Public key)用于加密,.p12格式的文件存放的是私钥(Pr...
  • iOS RSA加密失败

    2016-12-08 15:32:11
    前段时间做RSA加密的时候,在调试的过程中,经常失败,后台接收到的加密参数为空,但是这种不是经常发生,而是随机的。经过测试,发现,这种情况在单独使用真机、模拟器的时候都不发生,只有在真机连接xcode进行调试...
  • IOS开发rsa加密,解密,公钥,私钥导入,导入方法有字符串导入,文件导入两种形式。
  • IOS 与JAVA RSA加密解密

    2015-10-10 21:05:19
    这两天在做iOSRSA加密功能,搞了两天,找了很多资料,都没有解决,头都晕了,最后参考了一篇文章,终于解决了!记录下来,以免大家多走弯路。 下面附上参考原文: 在网上找了许多篇关于RSA加密解密的...
  • iOS中使用RSA加密解密,需要用到.der和.p12后缀格式的文件,其中.der格式的文件存放的是公钥(Public key)用于加密,.p12格式的文件存放的是私钥(Private key)用于解密. 首先需要先生成这些文件,然后再将文件...
  • 最近项目中需要将密码数据以文件的...RSA本地加密需要使用 公钥加密,私钥解密。当然也可以给服务端解密使用。 1、在桌面新建一个文件夹 RSA_Pem ,然后打开终端,cd 切换到改文件夹中,依次输入以下 2、输入指令:op
  • 文章转载自:http://www.cnblogs.com/makemelike/articles/3802518.html  在网上找了许多篇关于RSA加密解密的文章与博客,是很有帮助,但比较零散与不简洁。 (至于RSA的基本原理,大家可以看 阮一峰的网络日志 的...
  • 最近在公司项目中被要求使用RSA加密,且要求是全程加解密,期间也是踩了很多的坑,在此做个记录也算给要使用的朋友一点帮助.注意,具体的RSA加密算法内容并不在此文的讨论范围之内.本文更多聚焦于使用部分. 我当前的使用...
  • 因为项目中需要用到RSA加密,刚开始也是有点乱,这两天也整理的差不多了,希望能帮到大家。 这次先上代码,我想大部分人肯定是着急解决问题,所以不要废话太多。 iOS端 后台是PHP,给我了一段公钥和他用私钥加密后...
  • RSA加密和解密方法的实现和详解
  • iOS中使用RSA加密解密,需要用到.der和.p12后缀格式的文件,其中.der格式的文件存放的是公钥(Public key)用于加密,.p12格式的文件存放的是私钥(Private key)用于解密. 首先需要先生成这些文件,然后再将文件...
  • iOS RSA 公钥加密

    2017-04-07 17:55:54
    1.添加相关的工具类 RSAEncryptor #import ...@interface RSAEncryptor : NSObject ... * @param str 需要加密的字符串  * @param path '.der'格式的公钥文件路径  */ + (NSString *)encryptString:(NSSt
  • iOS RSA加密 解密

    2019-09-09 13:25:53
    最近在公司项目中被要求使用RSA加密,且要求是全程加解密,期间也是踩了很多的坑,在此做个记录也算给要使用的朋友一点帮助.注意,具体的RSA加密算法内容并不在此文的讨论范围。 1.需要获取公钥:从后端获取模和指数 ...
1 2 3 4 5 ... 20
收藏数 5,262
精华内容 2,104
关键字:

8rsa加密错误 ios