参考的iOS 使用 RSA/ECB/OAEPWithSHA-256AndMGF1Padding
一、使用模和指数加密
上面文章中是通过模和指数加密的,这里就把代码直接贴出来:
- (NSData *)getRSAWithOAEPWithSHA256AndMGF1Padding:(NSString *)input mod:(NSString *)mod exp:(NSString *)exp{
if(mod.length == 0 || exp.length == 0 || input.length == 0 ){
return nil;
}
RSA * rsa_pub = RSA_new();
const char *N = [mod UTF8String] ;
const char *E = [exp UTF8String];
if (!BN_hex2bn(&rsa_pub->n, N)) {
return nil;
}
if (!BN_hex2bn(&rsa_pub->e, E)) {
return nil;
}
if(!rsa_pub){
return nil;
}
NSData *plainData = [input dataUsingEncoding:NSUTF8StringEncoding];
int paddingSize = 0;
int publicRSALength = RSA_size(rsa_pub);
double totalLength = [plainData length];
int blockSize = publicRSALength - paddingSize;
int blockCount = ceil(totalLength / blockSize);
size_t publicEncryptSize = publicRSALength;
NSMutableData *encryptDate = [NSMutableData data];
for (int i = 0; i < blockCount; i++) {
NSUInteger loc = i * blockSize;
int dataSegmentRealSize = MIN(blockSize, totalLength - loc);
NSData *dataSegment = [plainData subdataWithRange:NSMakeRange(loc, dataSegmentRealSize)];
char *publicEncrypt = malloc(publicRSALength);
memset(publicEncrypt, 0, publicRSALength);
const unsigned char *str = [dataSegment bytes];
int r = RSA_public_encrypt_sha256(dataSegmentRealSize,str,(unsigned char*)publicEncrypt,rsa_pub,RSA_PKCS1_OAEP_PADDING);
if (r < 0) {
free(publicEncrypt);
return nil;
}
NSData *encryptData = [[NSData alloc] initWithBytes:publicEncrypt length:publicEncryptSize];
[encryptDate appendData:encryptData];
free(publicEncrypt);
}
return encryptDate;
}
mod
和exp
是生成rsa公钥/私钥的模和指数(幂),使用此方法需要后端提供这两个参数,而不是常规的字符串。关于这两个参数有几点需要注意:
1、
mod
和exp
必须为16进制。例如exp
后端给我的65537
,使用的时候需要转为010001
。2、模必须为
00
开头。例如00********
。
二、使用公钥加密
使用公钥加密,还是使用上面的方法,这里需要将公钥转为RSA
对象。参考iOS使用OpenSSL进行RSA加密、验签的心得。
关键代码:
- (RSA *)getRSAWithKey:(NSString *)key isPublic:(BOOL)isPublic{
NSString *result = [self getPEMFormaterKeyWithKey:key isPublic:isPublic];
return [self getRSAWithPEMKey:result isPublic:isPublic];
}
/// 需要将base64的key转为PEM格式的key
- (NSString *)getPEMFormaterKeyWithKey:(NSString *)key isPublic:(BOOL)isPublic{
NSMutableString *result = [NSMutableString string];
if (isPublic) {
[result appendString:@"-----BEGIN PUBLIC KEY-----\n"];
}else{
[result appendString:@"-----BEGIN RSA PRIVATE KEY-----\n"];
}
int count = 0;
for (int i = 0; i < [key length]; ++i) {
unichar c = [key characterAtIndex:i];
if (c == '\n' || c == '\r') {
continue;
}
[result appendFormat:@"%c", c];
if (++count == 64) {
[result appendString:@"\n"];
count = 0;
}
}
if (isPublic) {
[result appendString:@"\n-----END PUBLIC KEY-----"];
}else{
[result appendString:@"\n-----END RSA PRIVATE KEY-----"];
}
return result;
}
/// 将PEM格式的key转为RSA对象
- (RSA *)getRSAWithPEMKey:(NSString *)pemKey isPublic:(BOOL)isPublic{
const char *buffer = [pemKey UTF8String];
BIO *keyBio = BIO_new_mem_buf(buffer, (int)strlen(buffer));
RSA *rsa;
if (isPublic) {
rsa = PEM_read_bio_RSA_PUBKEY(keyBio, NULL, NULL, NULL);
}else{
rsa = PEM_read_bio_RSAPrivateKey(keyBio, NULL, NULL, NULL);
}
BIO_free_all(keyBio);
return rsa;
}
最后将加密完成的data转为base64,加密完成!
三、swift加密RSA/ECB/OAEPWithSHA-256AndMGF1Padding
参考文章。
适用于iOS13之后
四、关于此加密方式的误区:PKCS1
和PKCS8
因使用openssl加密时,使用的类型为RSA_PKCS1_OAEP_PADDING
。
PKCS1。开头为
-----BEGIN RSA PUBLIC KEY-----
,生成RSA对象使用PEM_read_bio_RSAPublicKey
PKCS8。开头为
-----BEGIN PUBLIC KEY-----
,生成RSA对象使用PEM_read_bio_RSA_PUBKEY
还尝试了PKCS1的公钥和PKCS8公钥互相转换,最后事实证明:1、2的代码没有问题,没必要这样改。