java pfx提取私钥加签,详解pfx证书提取公私钥的方法
什么是pfx
公钥加密技术12号标准。
公钥加密技术12号标准(Public Key Cryptography Standards #12,PKCS#12)为存储和传输用户或服务器私钥、公钥和证书指定了一个可移植的格式。它是一种二进制格式,这些文件也称为PFX文件。开发人员通常需要将PFX文件转换为某些不同的格式,如PEM或JKS,以便可以为使用SSL通信的独立Java客户端或WebLogic Server使用。
下面是pfx证书提取公私钥的步骤
//
// PrAndPu.h
// PFX
//
// Created by cloudfit on 15/12/12.
// Copyright © 2015年 cloudfit. All rights reserved.
//
#import
#import
#import
@interface PrAndPu : NSObject {
SecKeyRef _privateKey;
SecKeyRef _publicKey;
}
// 可以从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
//
// PrAndPu.m
// PFX
//
// Created by cloudfit on 15/12/12.
// Copyright © 2015年 cloudfit. All rights reserved.
//
#import “PrAndPu.h”
@implementation PrAndPu
//获取私钥
– (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) {
//获取公钥
NSLog(@”Get public key successfully~ %@”, _publicKey);
}
}
}
}
}
if (options) {
CFRelease(options);
}
}
}
return status;
}
//获取公钥
– (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~ %@”, _publicKey);
}
if (cert) {
CFRelease(cert);
}
if (policy) {
CFRelease(policy);
}
if (trust) {
CFRelease(trust);
}
}
}
}
}
}
return status;
}
//公钥加密,因为每次的加密长度有限,所以用到了分段加密,苹果官方文档中提到了分段加密思想。
– (NSData *)encryptWithPublicKey:(NSData *)plainData {
// 分配内存块,用于存放加密后的数据段
size_t cipherBufferSize = SecKeyGetBlockSize(_publicKey);
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, kSecPaddingPKCS1, (const uint8_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, kSecPaddingPKCS1, (const uint8_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;
}
@end
java pfx提取私钥加签,详解pfx证书提取公私钥的方法相关推荐
- 银行接口的私钥和公钥详解
银行接口的私钥和公钥详解 中国银行.建设银行.农业银行.工商银行.招商银行等支付接口的私钥和公钥详解 密钥: 我理解是公钥+私钥的统称. 密钥对: 公钥(证书)和私钥成对存在. 通信双方各持有自己的私 ...
- python正则表达式提取数字比较好_python正则表达式从字符串中提取数字的思路详解...
python从字符串中提取数字 使用正则表达式,用法如下: ## 总结 ## ^ 匹配字符串的开始. ## $ 匹配字符串的结尾. ## \b 匹配一个单词的边界. ## \d 匹配任意数字. ## ...
- java string()函数_转载java String.split()函数的用法详解
转载java String.split()函数的用法详解 如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!在java.lang包中有String.split()方法的原型是: p ...
- 2015年 第06届 蓝桥杯 Java B组 决赛真题详解及小结
蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[2013年(第4届)~2020年(第11届)] 第11届 蓝桥杯-第1.2次模拟(软件类)真题-(2020年3月.4月)-官方讲解视频 说明:大部 ...
- 2017年 第08届 蓝桥杯 Java B组 决赛真题详解及小结
蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[2013年(第4届)~2020年(第11届)] 第11届 蓝桥杯-第1.2次模拟(软件类)真题-(2020年3月.4月)-官方讲解视频 ...
- (7)Java数据结构--集合map,set,list详解
MAP,SET,LIST,等JAVA中集合解析(了解) - clam_clam的专栏 - CSDN博---有颜色, http://blog.csdn.net/clam_clam/article/det ...
- Java(enum)枚举用法详解
转载自 Java(enum)枚举用法详解 本篇文章主要介绍了Java 枚举用法详解,枚举的好处:可以将常量组织起来,统一进行管理.有兴趣的可以一起来了解一下. 概念 enum的全称为 enumerat ...
- 【转】Java魔法堂:String.format详解
Java魔法堂:String.format详解 目录 一.前言 二.重载方法 三.占位符 四.对字符.字符串进行格式化 五.对整数进行格式化 六.对 ...
- java学习 类变量 类方法_这篇文章主要介绍了JAVA类变量及类方法代码实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下类变量(...
这篇文章主要介绍了JAVA类变量及类方法代码实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 类变量(static) 类变量是该类的所有对象共 ...
最新文章
- VSTS LoadTest使用原则
- 区块链系列4-智能合约
- 又一理论横空出现或将颠覆世界
- scikit-learn kmeans++
- day41——多进程的消息队列、消息队列pipe
- statCVS的问题剖析
- Java网络爬虫实操(8)
- 牛客网【每日一题】4月17日题目精讲 华华给月月准备礼物
- Ubuntu16.04下Nvidia+Cuda8.0+Dynet安装教程
- C++自增和自减运算符(--和++)
- win8需要计算机管理员权限才能删除,win8系统使用管理员权限无法删除部分文件怎么办...
- 用友u8服务器修改ipv4,用友U8-OA11.1 用友U8加密狗更换服务器了-用友U8
- 继续逼近FLASH效果
- Android MTU 值修改
- 【奥黛丽赫本】女神一样的优雅
- jme-旋转的双子星
- 给一个IP地址,如何划分为几个子网?
- 把一个用阿拉伯数字表示的正整数转换成汉字大写表示
- 服务器的创意工坊文件,Steam 创意工坊实现指南
- Asset Store上常用的40个Unity插件汇总——进阶开发者必备Unity插件
热门文章
- Potted Flower(线段树+dp)
- JAVA 即时网络通信我的服务器
- 尝试从远程计算机访问Web服务不显示调用按钮
- 如何解决markdown中图片上传的问题
- 从程序员角度--解决ipad白苹果问题的最佳办法---纠正网上的错误言论
- JDBC的批量查询报告内存溢出解决方法
- 基于深度学习的个性化新闻推荐.pdf(附下载链接)
- 全球首发!计算机视觉Polygon Mesh Processing总结7——Remeshing Local Structure
- 用python写行列式_用Python开发线性代数算法(一) | 手写行列式算法的实现
- 吉林大学计算机专业宿舍研究生,吉林大学计算机系的研究生宿舍怎么样?我想考那的..._在职考研_帮考网...