背景概述
最近公司新启动一个项目,老大定了一套前后台加密交互方案:
前台发送请求:RSA公钥加密 - 压缩 - Base64编码;
后台返回响应:RSA私钥加密 - 压缩 - RSA私钥加签 - Base64编码;
前台处理响应:RSA公钥验签 - Base64解码 - 解压 - RSA公钥解密。
因为iOS这边验签时需要der格式的公钥,所以RSA秘钥由iOS端生成。
OpenSSL生成秘钥
- 创建一个临时文件夹,cd到该文件夹下,执行openssl
cd /Users/dqs/Desktop/rsa_key
openssl
- 生成模长为1024bit的私钥文件rsa_private_key.pem(该文件作为后续文件的基石,具体iOS端和Java端的私钥文件需另行生成)
genrsa -out rsa_private_key.pem 1024
- 由私钥文件生成公钥文件(该公钥文件即为最终的公钥文件)
rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
- 生成iOS本地RSA公钥验签时需要的der格式公钥
step1. 由私钥文件生成请求文件rsa_certReq.csr文件(信息、密码等正常填写,可选)
req -new -key rsa_private_key.pem -out rsa_certReq.csr
step2. 由请求文件生成证书rsa_cert.crt,并设置有效时间为10年
x509 -req -days 3650 -in rsa_certReq.csr -signkey rsa_private_key.pem -out rsa_cert.crt
step3. 由证书文件生成der格式的公钥
x509 -outform der -in rsa_cert.crt -out rsa_public_key.der
- 生成供iOS使用的私钥文件iOS_rsa_private_key.p12(此处需要设置密码,后续解密时会用到)
pkcs12 -export -out iOS_rsa_private_key.p12 -inkey rsa_private_key.pem -in rsa_cert.crt
- 生成供Java使用的私钥Java_pkcs8_private_key.pem
pkcs8 -topk8 -in rsa_private_key.pem -out Java_pkcs8_private_key.pem -nocrypt
- 全部执行成功后,会生成如下文件:
iOS本地RSA公钥验签
导入#import <CommonCrypto/CommonCrypto.h>
/**
* 根据der格式的公钥获取验签时需要的SecKeyRef
*/
+ (SecKeyRef)fetchPublicSecKeyRef:(NSString *)pubDerPath; {
static SecKeyRef keyRef = nil;
NSData *certificateData = [NSData dataWithContentsOfFile:pubDerPath];
SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certificateData);
SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
SecTrustRef myTrust;
OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
SecTrustResultType trustResult;
if (status == noErr) {
status = SecTrustEvaluate(myTrust, &trustResult);
}
keyRef = SecTrustCopyPublicKey(myTrust);
CFRelease(myCertificate);
CFRelease(myPolicy);
CFRelease(myTrust);
return keyRef;
}
/**
* 根据加密数据和签名验证
* @param plainData 加密数据
* @param signature 签名
**/
+ (BOOL)rsaSHA256VerifyData:(NSData *)plainData withSignature:(NSData *)signature {
SecKeyRef key = [self fetchPublicSecKeyRef:[[NSBundle mainBundle] pathForResource:@"rsa_public_key" ofType:@"der"]];
size_t signedHashBytesSize = SecKeyGetBlockSize(key);
const void* signedHashBytes = [signature bytes];
size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;
uint8_t* hashBytes = malloc(hashBytesSize);
if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) {
return NO;
}
OSStatus status = SecKeyRawVerify(key,
kSecPaddingPKCS1SHA256,
hashBytes,
hashBytesSize,
signedHashBytes,
signedHashBytesSize);
return status == errSecSuccess;
}