iOS RSA/ECB/OAEPWithSHA-256AndMGF1Padding加密整理

参考的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;
}

modexp是生成rsa公钥/私钥的模和指数(幂),使用此方法需要后端提供这两个参数,而不是常规的字符串。关于这两个参数有几点需要注意:

  • 1、modexp必须为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之后

四、关于此加密方式的误区:PKCS1PKCS8

因使用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的代码没有问题,没必要这样改。

你可能感兴趣的:(iOS RSA/ECB/OAEPWithSHA-256AndMGF1Padding加密整理)