最近写自己公司sdk和后台对接的时候,后台给我提供了私钥和公钥,要求参数进行排序拼接后的字符串,进行SHA1WithRSA算法加签,找了一些网站,发现资料首先很少,然后也没有找到根据后台提供的私钥进行算法加签的,最后和后台协商了一下,我这边本地生成java的pem私有公有文件,他那边用我给他的,然后我本地用p12文件进行SHA1WithRSA算法加签,最后完美解决。
先贴一下本地的代码:
.h文件中
#import <Foundation/Foundation.h>
@interface RSAEncryptor : NSObject
+(NSString *)signTheDataSHA1WithRSA:(NSString *)plainText;
@end
.m文件中
#import "RSAEncryptor.h"
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
#import <Security/Security.h>
#import "Base64Util.h"
#define kChosenDigestLength CC_SHA1_DIGEST_LENGTH
@implementation RSAEncryptor
+(NSString *)signTheDataSHA1WithRSA:(NSString *)plainText
{
uint8_t* signedBytes = NULL;
size_t signedBytesSize = 0;
OSStatus sanityCheck = noErr;
NSData* signedHash = nil;
NSString * path = [[NSBundle mainBundle]pathForResource:@"private_key" ofType:@"p12"];
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);
}
NSString *signatureResult=[NSString stringWithFormat:@"%@",[signedHash base64Encoding]];
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;
}
@end
接下来说一下iOS和java的公钥私钥文件的生成。
在iOS中使用RSA加密解密,需要用到.der和.p12后缀格式的文件,其中.der格式的文件存放的是公钥(Public key)用于加密,.p12格式的文件存放的是私钥(Private key)用于解密.
生成环境是在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
将java的那两个直接丢给后台,让他们用这个,他们可以用notepad直接打开获取到~
搞定~