本篇文章只是讨论,RSA签名的算法MD5以及sha1和Java后台对应的MD5WithRSA和SHA1WithRSA。
我们的需求:
防止恶意串改请求数据,因此采用移动端RSA私钥签名,后端RSA公钥验签的方式。
和大多数的朋友一样,直接百度。
得到了一下两点的信息(其它的都滤过了,因为没有用到,但是自己会补上的^__^):
1. 签名和加密是不一样的。
2. 签名的算法有md5以及SHA1之分,分别对应于后台的md5WithRSA 、 SHA1WithRSA.
然后市面上感觉全是SHA1的,偏偏我们后台的就是使用的md5WithRSA,给我愁的啊 !^__^~,但是也很感谢后台,让我又多学了点RSA的知识,不多说我直接 贴代码了。
用MD5的方式签名:
- (NSString*)signMD5String:(NSString*)string{
if(!_rsa_pri) {
NSLog(@"please import private key first");
returnnil;
}
const char *message = [string cStringUsingEncoding:NSUTF8StringEncoding];
//int messageLength = (int)strlen(message);
unsigned char *sig = (unsigned char *)malloc(256);
unsignedintsig_len;
unsigned char digest[MD5_DIGEST_LENGTH];
MD5_CTXctx;
MD5_Init(&ctx);
MD5_Update(&ctx, message,strlen(message));
MD5_Final(digest, &ctx);
intrsa_sign_valid =RSA_sign(NID_md5
, digest,MD5_DIGEST_LENGTH
, sig, &sig_len
,_rsa_pri);
if(rsa_sign_valid ==1) {
NSData* data = [NSDatadataWithBytes:siglength:sig_len];
NSString* base64String = [database64EncodedStringWithOptions:0];
free(sig);
returnbase64String;
}
free(sig);
return nil;
}
SHA1的签名:
- (NSString*)signString:(NSString*)string{
if(!_rsa_pri) {
NSLog(@"please import private key first");
returnnil;
}
const char *message = [string cStringUsingEncoding:NSUTF8StringEncoding];
intmessageLength = (int)strlen(message);
unsigned char *sig = (unsigned char *)malloc(256);
unsignedintsig_len;
unsignedcharsha1[20];
SHA1((unsignedchar*)message, messageLength, sha1);
intrsa_sign_valid =RSA_sign(NID_sha1
, sha1,20
, sig, &sig_len
,_rsa_pri);
if(rsa_sign_valid ==1) {
NSData* data = [NSDatadataWithBytes:siglength:sig_len];
NSString* base64String = [database64EncodedStringWithOptions:0];
free(sig);
returnbase64String;
}
free(sig);
return nil;
}
获取RSA对象:
-(RSA* )getRSAWithPrivatekey:(NSString*)pk{
RSA*rsa =NULL;
if(!pk) {
returnrsa;
}
BOOLstatus =NO;
BIO*bio =NULL;
bio =BIO_new(BIO_s_file());
NSString* temPath = NSTemporaryDirectory();
NSString* rsaFilePath = [temPathstringByAppendingPathComponent:@"RSAKEY"];
NSString* formatRSAKeyString = [self formatRSAKeyWithKeyString:pk];
BOOLwriteSuccess = [formatRSAKeyStringwriteToFile:rsaFilePathatomically:YESencoding:NSUTF8StringEncodingerror:nil];
if(!writeSuccess) {
returnrsa;
}
const char* cPath = [rsaFilePath cStringUsingEncoding:NSUTF8StringEncoding];
BIO_read_filename(bio, cPath);
rsa =PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, "");
if(rsa !=NULL&&1==RSA_check_key(rsa)) {
status =YES;
}else{
status =NO;
}
BIO_free_all(bio); if (status) { return rsa; } return NULL;
}
-(NSString*)formatRSAKeyWithKeyString:(NSString*)keyString {
NSIntegerlineNum = -1;
NSMutableString *result = [NSMutableString string];
[resultappendString:@"-----BEGIN PRIVATE KEY-----\n"]; lineNum =79;
}
intcount =0;
for(inti =0; i < [keyString length]; ++i) {
unicharc = [keyStringcharacterAtIndex:i];
if(c =='\n'|| c =='\r') {
continue;
}
[resultappendFormat:@"%c", c];
if(++count == lineNum) {
[resultappendString:@"\n"];
count =0;
}
}
if(type ==KeyTypePrivate) {
[resultappendString:@"\n-----END PRIVATE KEY-----"];
}elseif(type ==KeyTypePublic){
[resultappendString:@"\n-----END PUBLIC KEY-----"];
}
returnresult;
}
***重要:想要用上面方法要导入下面的文件

这个就是openssl库,如果你们的工程里有支付的sdk可以直接使用的,如果没有那么要自己下载的,百度相信会有一堆的。
*最后还有一些额外的:
1.我这里就是直接使用的是后台给的私钥字符串pkcs8格式的,没有转换为pkcs1的,不知道是这个库给自动转了还是根本就不需要。
2.如果你是自己手动导入的openssl的库,当你使用的时候回报错的 <openssl/rsa.h> 没有找到,这个你要到build settings --->Header Search Paths 添加路径:$(PROJECT_DIR)/项目名字/所在的文件夹/openssl/include
eg: $(PROJECT_DIR)/Doctor/Third/RSA/openssl/include

3.此时上面的配置好了,有可能还会报错,报错的是因为你的bticode选择项为YES,将其改为NO就完事了。
就说这么多了,由于不会上传文件,所以都是复制的代码,只要将上面的配置和库都弄好,上面的代码可以直接使用。希望可以帮到你,^__^。
网友评论