天杀 的pfx证书 提取公钥秘钥 加密签名

项目一开始就入了一个坑

需求是这样的

      后台甩给我一个.pfx格式的证书, 有些人就会问了 这个是啥, 我不是大神 就给那些不懂得人 通俗的说一下. 这个东西是一个证书文件, 其中包含 公钥 和  私钥  (一会解释这俩东西是啥), 这个在表面试看不出来的,  你可能会在网上找到很多提取这个东西里公钥私钥的方法 , demo .但是  我想你会在获取公钥的时候遇到问题.,

  记住其中提取公钥的方法  一定要是.cer格式的公钥文件    .cer格式的公钥文件   .cer格式的公钥文件  说三遍


这个东西怎么弄呢?   在mac里 的终端可以解决这个问题 (百度 mac openssl 提取 公钥) 就是几行命令行 赋值粘贴就行了,具体的我还是希望你自己去努力调研! 之后在你工程里应该 有两个东西 一个是后台给你的操蛋pfx格式的证书  一个是你用终端提取的.cer的公钥文件

然后就是代码了


#import <Foundation/Foundation.h>

#import <Security/Security.h> //这是一个系统自带的库 别管他好是不好使 弄上去

#import <CommonCrypto/CommonDigest.h> //这是一个系统自带的库 别管他好是不好使 弄上去


@interface PrAndPu : NSObject {

    

    SecKeyRef _privateKey;

    SecKeyRef _publicKey;

    

}


//这个是一会要用的最后你要使用的 公钥 属性

@property (nonatomic, assign) SecKeyRef pubKey;


// 可以从PKCS#12文件中提取身份、信任、证书、公钥、私钥,这里,我们只需要保留私钥

- (OSStatus)extractEveryThingFromPKCS12File:(NSString *)pkcsPath passphrase:(NSString *)pkcsPassword;

// 从证书文件中提取公钥

- (OSStatus)extractPublicKeyFromCertificateFile:(NSString *)certPath;

// RSA公钥加密,支持长数据加密

- (NSData *)encryptWithPublicKey:(NSData *)plainData;

// RSA私钥解密,支持长数据解密

- (NSData *)decryptWithPrivateKey:(NSData *)cipherData;


@end








.m

//获取私钥

- (OSStatus)extractEveryThingFromPKCS12File:(NSString *)pkcsPath passphrase:(NSString *)pkcsPassword {

    SecIdentityRef identity;

    SecTrustRef trust;

    OSStatus status = -1;

    if (_privateKey == nil) {

        NSData *p12Data = [NSData dataWithContentsOfFile:pkcsPath];

        if (p12Data) {

            CFStringRef password = (__bridge CFStringRef)pkcsPassword;

            const void *keys[] = {

                kSecImportExportPassphrase

            };

            const void *values[] = {

                password

            };

            CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, NULL, NULL);

            CFArrayRef items = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL);

            status = SecPKCS12Import((CFDataRef)p12Data, options, &items);

            if (status == errSecSuccess) {

                CFDictionaryRef identity_trust_dic = CFArrayGetValueAtIndex(items, 0);

                identity = (SecIdentityRef)CFDictionaryGetValue(identity_trust_dic, kSecImportItemIdentity);

                trust = (SecTrustRef)CFDictionaryGetValue(identity_trust_dic, kSecImportItemTrust);

                // certs数组中包含了所有的证书

                CFArrayRef certs = (CFArrayRef)CFDictionaryGetValue(identity_trust_dic, kSecImportItemCertChain);

                if ([(__bridge NSArray *)certs count] && trust && identity) {

                    //如果没有下面一句,自签名证书的评估信任结果永远是kSecTrustResultRecoverableTrustFailure

                    status = SecTrustSetAnchorCertificates(trust, certs);

                    if (status == errSecSuccess) {

                        SecTrustResultType trustResultType;

                        //通常, 返回的trust result type应为kSecTrustResultUnspecified,如果是,就可以说明签名证书是可信的

                        status = SecTrustEvaluate(trust, &trustResultType);

                        if ((trustResultType == kSecTrustResultUnspecified || trustResultType == kSecTrustResultProceed) && status == errSecSuccess) {

                            //证书可信,可以提取私钥与公钥,然后可以使用公私钥进行加解密操作

                            status = SecIdentityCopyPrivateKey(identity, &_privateKey);

                            if (status == errSecSuccess && _privateKey) {

                                //成功提取私钥

                                NSLog(@"Get private key successfully~ %@", _privateKey);

                            }

                            

                             //这里,不提取公钥,提取公钥的任务放在extractPublicKeyFromCertificateFile方法中

//                             _publicKey = SecTrustCopyPublicKey(trust);

//                             if (_publicKey) {

//                                 

//                                 self.pubKey = (__bridge id)(_publicKey);

//                                 

//                             }

                            

                        }

                    }

                }

            }

            if (options) {

                CFRelease(options);

            }

        }

    }

    return status;

}


//获取公钥 注意!!!!!!****** 只支持 cer 格式的文件 *****

- (OSStatus)extractPublicKeyFromCertificateFile:(NSString *)certPath {

    

    OSStatus status = - 1;

    

    

    if (_publicKey == nil) {

        

       

        

        SecTrustRef trust;

        SecTrustResultType trustResult;

        NSData *derData = [NSData dataWithContentsOfFile:certPath];

        if (derData) {

            SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)derData);

            SecPolicyRef policy = SecPolicyCreateBasicX509();

            status = SecTrustCreateWithCertificates(cert, policy, &trust);

            if (status == errSecSuccess && trust) {

                NSArray *certs = [NSArray arrayWithObject:(__bridge id)cert];

                status = SecTrustSetAnchorCertificates(trust, (CFArrayRef)certs);

                if (status == errSecSuccess) {

                    status = SecTrustEvaluate(trust, &trustResult);

                    //自签名证书可信

                    if (status == errSecSuccess && (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)) {

                        _publicKey = SecTrustCopyPublicKey(trust);

                    

                        if (_publicKey) {

                            NSLog(@"Get public key successfully~ ");

                            self.pubKey = _publicKey; //这个地方可以把提取出来的公钥 传个之前.h里的属性

                        }

                        if (cert) {

                            CFRelease(cert);

                        }

                        if (policy) {

                            CFRelease(policy);

                        }

                        if (trust) {

                            CFRelease(trust);

                        }

                    }

                }

            }

        }

    }

    return status;

}



//公钥加密,因为每次的加密长度有限,所以用到了分段加密,苹果官方文档中提到了分段加密思想。

- (NSData *)encryptWithPublicKey:(NSData *)plainData {

    //分配内存块,用于存放加密后的数据段

    size_t cipherBufferSize = SecKeyGetBlockSize(_pubKey);

    uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));

    /*

     为什么这里要减12而不是减11?

    苹果官方文档给出的说明是,加密时,如果sec padding使用的是kSecPaddingPKCS1

    那么支持的最长加密长度为SecKeyGetBlockSize()-11

     这里说的最长加密长度,我估计是包含了字符串最后的空字符'\0'

    因为在实际应用中我们是不考虑'\0'的,所以,支持的真正最长加密长度应为SecKeyGetBlockSize()-12

     */

    double totalLength = [plainData length];

    size_t blockSize = cipherBufferSize - 12;//使用cipherBufferSize - 11是错误的!

    size_t blockCount = (size_t)ceil(totalLength / blockSize);

    NSMutableData *encryptedData = [NSMutableData data];

    //分段加密

    for (int i = 0; i < blockCount; i++) {

        NSUInteger loc = i * blockSize;

        //数据段的实际大小。最后一段可能比blockSize小。

        int dataSegmentRealSize = MIN(blockSize, [plainData length] - loc);

        //截取需要加密的数据段

        NSData *dataSegment = [plainData subdataWithRange:NSMakeRange(loc, dataSegmentRealSize)];

        OSStatus status = SecKeyEncrypt(_publicKey,kSecPaddingNone(此处高能预警.估计你找的方法里 这个位置 是 kSecPaddingPKCS1 你最好点进去看看都有哪些东西, 苹果默认的方法是PKCS1但是 我们的后台 他们的默认格式却不是这个 想我的就是PKCS12  所以不同的标准会影响你加密之后传到服务器的东西服务器看不懂 会有乱码 然后告诉你 账号密码错误), (constuint8_t *)[dataSegment bytes], dataSegmentRealSize, cipherBuffer, &cipherBufferSize);

        if (status == errSecSuccess) {

            NSData *encryptedDataSegment = [[NSData alloc] initWithBytes:(const void *)cipherBuffer length:cipherBufferSize];

            //追加加密后的数据段

            [encryptedData appendData:encryptedDataSegment];

            

        } else {

            if (cipherBuffer) {

                free(cipherBuffer);

            }

            return nil;

        }

    }

    if (cipherBuffer) {

        free(cipherBuffer);

    }

    return encryptedData;

}


//私钥解密,用到分段解密。

- (NSData *)decryptWithPrivateKey:(NSData *)cipherData {

    //分配内存块,用于存放解密后的数据段

    size_t plainBufferSize = SecKeyGetBlockSize(_privateKey);

    NSLog(@"plainBufferSize = %zd", plainBufferSize);

    uint8_t *plainBuffer = malloc(plainBufferSize * sizeof(uint8_t));

    //计算数据段最大长度及数据段的个数

    double totalLength = [cipherData length];

    size_t blockSize = plainBufferSize;

    size_t blockCount = (size_t)ceil(totalLength / blockSize);

    NSMutableData *decryptedData = [NSMutableData data];

    //分段解密

    for (int i = 0; i < blockCount; i++) {

        NSUInteger loc = i * blockSize;

        //数据段的实际大小。最后一段可能比blockSize小。

        int dataSegmentRealSize = MIN(blockSize, totalLength - loc);

        //截取需要解密的数据段

        NSData *dataSegment = [cipherData subdataWithRange:NSMakeRange(loc, dataSegmentRealSize)];

        OSStatus status = SecKeyDecrypt(_privateKey,kSecPaddingNone(解密也是一样的), (constuint8_t *)[dataSegment bytes], dataSegmentRealSize, plainBuffer, &plainBufferSize);

        if (status == errSecSuccess) {

            NSData *decryptedDataSegment = [[NSData alloc] initWithBytes:(const void *)plainBuffer length:plainBufferSize];

            [decryptedData appendData:decryptedDataSegment];

                   } else {

            if (plainBuffer) {

                free(plainBuffer);

            }

            return nil;

        }

    }

    if (plainBuffer) {

        free(plainBuffer);

    }

    return decryptedData;

}



鄙人不才 以上的方法我也几乎看不懂也是网上的大神写的只不过 有些东西对于一些特定情况 不一定会使用, 毕竟人家只是给你铺好路, 怎么走还是要自己想的.


说说怎么实现吧  引头文件什么的我就不说了
我写的是一个登录的流程 只是一个大概 看看就好

//如果没做过登录的可能 一听什么两次握手 我你妈比啊?@!@#!@# 不要紧 其实很简单 

第一次握手其实就是 第一次访问服务器, 你的app在点击登录的一刹那 会对服务器进行两次访问, 而服务器也会返回给你两回数据 往下慢慢看吧

// *****************第一次请求 GET 请求 ************************

    

    NSString *url = @"http://192.168.188.137/api/Account/HitMessage";

   

    

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    

    [manager GET:url parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {

   //这个地方 我家的服务器 会返回 一个 字典  { hit : 6位的随机数, requste:(一大长串的字符串 一会 进行第二次访问的时候 要用)}


        NSString *hit = [NSString stringWithFormat:@"%@", [responseObject valueForKey:@"hit"]];

        

//        NSLog(@"%@", hit);

        

        NSString *requset = [NSString stringWithFormat:@"%@", [responseObject valueForKey:@"request"]];

        

//第二吃访问的链接

        NSString *url2 = [NSString stringWithFormat:@"http://192.168.188.137/api/Account/Login/%@/1", requset(这个就是第一次访问服务器返回的requset)];

    

        //之前的工具类

        PrAndPu *tool = [[PrAndPu alloc] init];

        

        //获得公钥

        [tool extractPublicKeyFromCertificateFile:@"/Users/cloudfit/cloudfitb_ios/CloudSports/CloudSports/pubKey证书.cer”];(格式别弄错了 公钥文件)

        

        

        

        //获取私钥(这是另一个的请无视...... 直接用那个方法就行)

        SecKeyRef privateKey =[DJZSafeTool getPrivateKey];

      

       //私钥签名(这一步很关键了, 首先你要吧你第一次访问服务器 返回给你的验证码 进行私钥加签(其实也可以说是加密)   这么做的原因是 你在网上约到了一个 py 见面的时候需要对暗号, 你的把你想表达的意思 用你们约定好的好表达出来, 你的py听见了 心里想: 哦 原来那个人就是你呀 .所以首先你就已经成功了一半了, 就是说你最起码通过了服务器的认证证明他之前确实联系过你

       // NSLog(@"%@", hit);

//私钥加签之后的字符串

        NSString *HitMess = [DJZSafeTool signTheDataSHA1WithRSA:hit privateKey:privateKey];

       

//我猜通常可能一般 你们后台会让你们 把 设备id 账号 密码 用你们的方法拼接起来然后 公钥加密 第二次握手的时候 传上去

        //获取 UUID (获取设备 ID

        APPIdentificationManager * identificationManager = [[APPIdentificationManager alloc] init];

        NSString * uuid = [identificationManager readUDID];

        //账号 测试的时候 一定要确定你的账号密码是对的 如果真是你们后台的问题别干打自己脸的事

        NSString *userId  = @"su#001025";

        //密码

        NSString *usePassWord = @"123456";

    

        //拼接

        NSString *tokens = [NSString stringWithFormat:@"%@&%@&%@", userId, usePassWord, uuid];

        

       // NSString转换 NSData(这俩玩意可以互转的)

       NSData * tokenData = [tokens dataUsingEncoding:NSUTF8StringEncoding];

       

       // 公钥加密 (公钥加密的原理就是 你和你的 py对完见面时确认彼此的暗号了 就要商量 去哪家宾馆的 几零几 但是你们不能就这么说 万一让你媳妇或者老公发现了就完了, 所以 你需要把你们要去的 地址门牌号用另一种方式说出来 ,就是公钥加密了)

        NSData *da = [tool encryptWithPublicKey:tokenData];

        

       //这里 你可能会在网上看到什么GTMBase64de 东东 我告诉你 没有用因为那是 上古的方法 7.0以后 系统自带了

 //这个东西就是一会你要上传的数据...之一

       NSString * Token = [da base64EncodedStringWithOptions:0];

        

        

//       NSLog(@"base64   ==  %@", Token);

        

#warning测试用!!!(其实这个并没有什么卵用, 有可能会让你打自己脸,当你气冲冲的 和别人说, 这回登录的问题 不是你的问题,,,,,其实可能就是你的问题, 因为你在你自己家里加密解密都是有自己的一套标准的 所以你会觉得没问题...别干那种傻事, 仔细看看你传到后台的东西 服务器解密之后是什么鬼..当然这还是一个判断你的公钥加密是否有问题的好方法)

//        //私钥 解密

        NSData *tokenPrivate = [DJZSafeTool rsaDecryptWithData:da usingKey:privateKey];

        

        

        NSString *tokenPrivateStr = [[NSString alloc] initWithData:tokenPrivate encoding:NSUTF8StringEncoding];

     

        NSLog(@"++++++++++++++测试:私钥解密后的结果是————%@",tokenPrivateStr);

        

#pragma mark —第二次握手 //第二次上床…不..是握手 就是你已经和你的py对完见面确认是不是彼此的安好了  也说好哪家宾馆的那个房间了 就要去ppppp了;

//其实就是在你第一次获取网络数据成功之后在访问以下服务器, 只不过这回事post因为你要传参数到服务器

        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

        

        //参数

(私钥加签之后的字符串)

       // NSLog(@"hitmess=== %@", [NSString stringWithFormat:@"%@", HitMess]);

(公钥加密的 设备id 账号密码 拼接的字符串)

       // NSLog(@"token === %@", [NSString stringWithFormat:@"%@", Token]);

//几乎都是传一个字典上去

        NSDictionary *parameters = @{@"HitMess" : HitMess,

                                     @"Token" :  Token};

        

        

        [manager POST:url2 parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {

            

           

            

        NSLog(@"%@", responseObject);

            

           

                //进入用户首页 开始 pppppp

            UserHomePageViewController *userHomeVc = [[UserHomePageViewController alloc] init];

            [self.navigationController pushViewController:userHomeVc animated:YES];


            

            

        } failure:^(NSURLSessionDataTask *task, NSError *error) {

            

            

            

        }];

        

        

        

        

        

     

    } failure:^(NSURLSessionDataTask *task, NSError *error) {

        

    }];;


    

算了DJL也放上去吧

    

#import <Foundation/Foundation.h>

//pfx文件名

#define PFX_NAME @"cloudfit_debug"

@interface DJZSafeTool : NSObject

/**

 *  SHA1加密

 *

 *  @param plainText 加密前data

 *

 *  @return 加密后data

 */

+ (NSData *)getHashBytes:(NSData *)plainText;

/**

 *  pfxp12文件中获取公钥

 *

 *  @return 公钥

 */

+ (SecKeyRef)getPublicKey;

/**

 *  pfx文件中获取私钥

 *

 *  @return 私钥

 */

+ (SecKeyRef)getPrivateKey;

/**

 *  使用公钥加密

 *

 *  @param data 加密前data

 *  @param key  公钥

 *

 *  @return 加密后data

 */

+ (NSData*)rsaEncryptWithData:(NSData*)data usingKey:(SecKeyRef)key;

/**

 *  私钥解密

 *

 *  @param data 解密前data

 *  @param key  私钥

 *

 *  @return 解密后data

 */

+ (NSData*)rsaDecryptWithData:(NSData*)data usingKey:(SecKeyRef)key;

/**

 *  私钥对字符串数字签名

 *

 *  @param plainText     密码

 *  @param privateKeyRef 私钥

 *

 *  @return 签名后字符串

 */

+ (NSString *)signTheDataSHA1WithRSA:(NSString *)plainText privateKey:(SecKeyRef)privateKeyRef;




- (NSData *)getHashBytes:(NSData *)plainText;

- (NSString *)signTheDataSHA1WithRSA:(NSString *)plainText;


}







#import "DJZSafeTool.h"

#import <Security/Security.h>

#import "GTMBase64.h"

#import <CommonCrypto/CommonDigest.h>

#import <CommonCrypto/CommonCryptor.h>

static NSString * const publicString = @"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAteoLIiNA2bfQu5pMrRsP9Hfwbr8FouWVwj0pG4akT0OFQkjKPDVC5GGNxE3OjpO4Y8Cr7aJLQxZtvJBEaDh2uOEdSHj5MRwnmWpv2VvJ2s42wsABGEQbx26baHNZmLXsH6Ad/JIx0Ow3cgBxLACWBuasd/V7C3/CysxyXg1KpIZYF1Fepo47HxWWDVYsdXaqIyuorabz2stJgqExOuLC5FchzYOn+nSlADwN43nV4VBWVnVRCr6SKccHCUjm7Wn6YCxatPluX49Be78ScxEF/PtpNuNItYqCryBY462flLCe9tLRnOg8QxjRyix1gPs/t1r+pJkKwXObQvHfiw3u/wIDAQAB";


#define kChosenDigestLength CC_SHA1_DIGEST_LENGTH // SHA-1消息摘要的数据位数160



@implementation DJZSafeTool

#pragma mark - 获取公钥

+ (SecKeyRef)getPublicKey

{

    

   

    

    SecCertificateRef myCertificate = nil;

    

    NSString *path = [[NSBundle mainBundle] pathForResource: @"pubKey证书" ofType:@"cer"];

    //NSLog(@"%@", path);

    NSData *certificateData = [NSData dataWithContentsOfFile:path];

   

    NSString *str = [GTMBase64 encodeBase64Data:certificateData];

    

    

//    NSData *pubData = [GTMBase64 decodeString:publicString];

//    NSString *str = [[NSString alloc] initWithData:certificateData encoding:NSUTF8StringEncoding];

//    NSRange startRange = [str rangeOfString:@"-----BEGIN PUBLIC KEY-----\n"];

//    str = [str stringByReplacingCharactersInRange:startRange withString:@""];

//    NSRange endRange = [str rangeOfString:@"-----END PUBLIC KEY-----\n"];

//    str = [str stringByReplacingCharactersInRange:endRange withString:@""];

//    NSLog(@"%@", str);

//    NSData *data = [GTMBase64 decodeData:certificateData];

    

     myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificateData);

    NSLog(@"%@", myCertificate);

    

    if (myCertificate == nil) {

        NSLog(@"获取公钥失败");

        return nil;

    }

    SecPolicyRef myPolicy = SecPolicyCreateBasicX509();

    SecTrustRef myTrust;

    OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);

    SecTrustResultType trustResult;

    if (status == noErr) {

        status = SecTrustEvaluate(myTrust, &trustResult);

    }

    

   

    

    return SecTrustCopyPublicKey(trustResult);

    

}




#pragma mark - 获取私钥

+ (SecKeyRef)getPrivateKey

{

    NSString *publicKeyPath = [[NSBundle mainBundle] pathForResource:PFX_NAME ofType:@"pfx"];

    NSData *pfxkeyData = [[NSData alloc]initWithContentsOfFile:publicKeyPath];

    

    NSMutableDictionary * options = [[NSMutableDictionary alloc] init];

    [options setObject:@"123456" forKey:(__bridge id)kSecImportExportPassphrase];

    

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);

    

    OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) pfxkeyData,

                                             (__bridge CFDictionaryRef)options, &items);

    

    CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);

    SecIdentityRef identityApp =

    (SecIdentityRef)CFDictionaryGetValue(identityDict,

                                         kSecImportItemIdentity);

    

    assert(securityError == noErr);

    SecKeyRef privateKeyRef;

    SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);

    

   // NSLog(@"私钥%@", privateKeyRef);

    

    return privateKeyRef;

    

}

#pragma mark - 公钥加密

+ (NSData*)rsaEncryptWithData:(NSData*)data usingKey:(SecKeyRef)key {

    

    size_t cipherBufferSize = SecKeyGetBlockSize(key);

    uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));

    memset((void *)cipherBuffer, 0*0, cipherBufferSize);

    

    NSData *plainTextBytes = data;

    size_t blockSize = cipherBufferSize - 11;

    size_t blockCount = (size_t)ceil([plainTextBytes length] / (double)blockSize);

    NSMutableData *encryptedData = [NSMutableData dataWithCapacity:0];

    

    for (int i=0; i<blockCount; i++) {

        

        int bufferSize = MIN(blockSize,[plainTextBytes length] - i * blockSize);

        NSData *buffer = [plainTextBytes subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];

        

        OSStatus status = SecKeyEncrypt(key,

                                        kSecPaddingPKCS1,

                                        (const uint8_t *)[buffer bytes],

                                        [buffer length],

                                        cipherBuffer,

                                        &cipherBufferSize);

        

        if (status == noErr){

            NSData *encryptedBytes = [NSData dataWithBytes:(const void *)cipherBuffer length:cipherBufferSize];

            [encryptedData appendData:encryptedBytes];

            

        }else{

            

            if (cipherBuffer) {

                free(cipherBuffer);

            }

            return nil;

        }

    }

    if (cipherBuffer) free(cipherBuffer);

    return encryptedData;

    

}

#pragma mark - 私钥解密

//私钥解密:

+ (NSData*)rsaDecryptWithData:(NSData*)data usingKey:(SecKeyRef)key {

    NSData *wrappedSymmetricKey = data;

    

    size_t cipherBufferSize = SecKeyGetBlockSize(key);

    size_t keyBufferSize = [wrappedSymmetricKey length];

    

    NSMutableData *bits = [NSMutableData dataWithLength:keyBufferSize];

    OSStatus sanityCheck = SecKeyDecrypt(key,

                                         kSecPaddingNone,

                                         (const uint8_t *) [wrappedSymmetricKey bytes],

                                         cipherBufferSize,

                                         [bits mutableBytes],

                                         &keyBufferSize);

    NSAssert(sanityCheck == noErr, @"Error decrypting, OSStatus == %d.", (int)sanityCheck);

    

    [bits setLength:keyBufferSize];

    

    return bits;

    

}

#pragma mark - 私钥加签

+ (NSString *)signTheDataSHA1WithRSA:(NSString *)plainText privateKey:(SecKeyRef)privateKeyRef

{

    uint8_t* signedBytes = NULL;

    size_t signedBytesSize = 0;

    OSStatus sanityCheck = noErr;

    NSData* signedHash = nil;

    

    signedBytesSize = SecKeyGetBlockSize(privateKeyRef);

    

    NSData *plainTextBytes = [plainText dataUsingEncoding:NSUTF8StringEncoding];

    

    signedBytes = malloc( signedBytesSize * sizeof(uint8_t) ); //分配一个缓冲区来保存签名

    

    memset((void *)signedBytes, 0x0, signedBytesSize);

    

    sanityCheck = SecKeyRawSign(privateKeyRef,

                                kSecPaddingPKCS1SHA1,

                                (const uint8_t *)[[self getHashBytes:plainTextBytes] bytes],

                                kChosenDigestLength,

                                (uint8_t *)signedBytes,

                                &signedBytesSize);

   // NSLog(@"sanityCheck%d", (int)sanityCheck);

    

    if (sanityCheck == errSecSuccess)

    {

        signedHash = [NSData dataWithBytes:(const void *)signedBytes length:(NSUInteger)signedBytesSize];

        

    }else{

        

        NSLog(@"error!! err code:%d", (int)sanityCheck);

        return  nil;

    }

    

    if (signedBytes)

    {

        free(signedBytes);

    }

    

    NSString *signatureResult=[NSString stringWithFormat:@"%@",[GTMBase64 encodeBase64Data:signedHash]];

    return signatureResult;

}


-(NSString *)signTheDataSHA1WithRSA:(NSString *)plainText

{

    uint8_t* signedBytes = NULL;

    size_t signedBytesSize = 0;

    OSStatus sanityCheck = noErr;

    NSData* signedHash = nil;

    

    NSString * path = [[NSBundle mainBundle]pathForResource:@"cloudfit_debug" ofType:@"pfx"];

    NSData * data = [NSData dataWithContentsOfFile:path];

    NSMutableDictionary * options = [[NSMutableDictionary alloc] init]; // Set the private key query dictionary.

    [options setObject:@"123456" forKey:(id)kSecImportExportPassphrase];

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);

    OSStatus securityError = SecPKCS12Import((CFDataRef) data, (CFDictionaryRef)options, &items);

    if (securityError!=noErr) {

        return nil ;

    }

    CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);

    SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity);

    SecKeyRef privateKeyRef=nil;

    SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);

    signedBytesSize = SecKeyGetBlockSize(privateKeyRef);

    

    NSData *plainTextBytes = [plainText dataUsingEncoding:NSUTF8StringEncoding];

    

    signedBytes = malloc( signedBytesSize * sizeof(uint8_t) ); // Malloc a buffer to hold signature.

    memset((void *)signedBytes, 0x0, signedBytesSize);

    

    sanityCheck = SecKeyRawSign(privateKeyRef,

                                kSecPaddingPKCS1SHA1,

                                (const uint8_t *)[[self getHashBytes:plainTextBytes] bytes],

                                kChosenDigestLength,

                                (uint8_t *)signedBytes,

                                &signedBytesSize);

    

    if (sanityCheck == noErr)

    {

        signedHash = [NSData dataWithBytes:(const void *)signedBytes length:(NSUInteger)signedBytesSize];

    }

    else

    {

        return nil;

    }

    

    if (signedBytes)

    {

        free(signedBytes);

    }

   // NSLog(@"signedHash == %@", signedHash);

    

    NSString *signatureResult=[NSString stringWithFormat:@"%@",[GTMBase64 encodeBase64Data:signedHash]];

   // NSLog(@"签名之后%@", signatureResult);

    return signatureResult;

}


- (NSData *)getHashBytes:(NSData *)plainText {

    CC_SHA1_CTX ctx;

    uint8_t * hashBytes = NULL;

    NSData * hash = nil;

    

    // Malloc a buffer to hold hash.

    hashBytes = malloc( kChosenDigestLength * sizeof(uint8_t) );

    memset((void *)hashBytes, 0x0, kChosenDigestLength);

    // Initialize the context.

    CC_SHA1_Init(&ctx);

    // Perform the hash.

    CC_SHA1_Update(&ctx, (void *)[plainText bytes], [plainText length]);

    // Finalize the output.

    CC_SHA1_Final(hashBytes, &ctx);

    

    // Build up the SHA1 blob.

    hash = [NSData dataWithBytes:(const void *)hashBytes length:(NSUInteger)kChosenDigestLength];

    if (hashBytes) free(hashBytes);

    

    return hash;

}


#pragma mark - SHA1

+ (NSData *)getHashBytes:(NSData *)plainText {

    CC_SHA1_CTX ctx;

    uint8_t * hashBytes = NULL;

    NSData * hash = nil;

    

    // Malloc a buffer to hold hash.

    hashBytes = malloc( kChosenDigestLength * sizeof(uint8_t) );

    memset((void *)hashBytes, 0x0, kChosenDigestLength);

    // Initialize the context.

    CC_SHA1_Init(&ctx);

    // Perform the hash.

    CC_SHA1_Update(&ctx, (void *)[plainText bytes], [plainText length]);

    // Finalize the output.

    CC_SHA1_Final(hashBytes, &ctx);

    

    // Build up the SHA1 blob.

    hash = [NSData dataWithBytes:(const void *)hashBytes length:(NSUInteger)kChosenDigestLength];

    if (hashBytes) free(hashBytes);

    

    return hash;




}



都是一个参考 加油吧骚年



  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值