iOS 10之前版本Objective-C实现RSA OAEP SHA256加密技术问询
Hey there! I see you've already got RSA encryption working with kSecKeyAlgorithmRSAEncryptionOAEPSHA256 on newer iOS versions, and now need to adapt it for iOS 10 and earlier. The core issue here is that kSecKeyAlgorithmRSAEncryptionOAEPSHA256 was introduced in iOS 10—so we need alternative approaches for older systems. Let's break down two reliable solutions:
方案1:降级使用PKCS#1 v1.5填充(服务器需配合调整)
If your server team can adjust their decryption logic to support both OAEP and PKCS#1 v1.5, this is the simplest approach since it uses Apple's native Security framework without third-party dependencies.
代码实现
Add version checking to switch between algorithms based on the iOS version:
SecKeyRef keyRef = [self addPublicKey:pubKey]; if (!keyRef) { return nil; } NSData *encryptedData = nil; CFErrorRef error = NULL; if (@available(iOS 10.0, *)) { // 高版本使用OAEP-SHA256 SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256; if (SecKeyIsAlgorithmSupported(keyRef, kSecKeyOperationTypeEncrypt, algorithm)) { encryptedData = (__bridge_transfer NSData *)SecKeyCreateEncryptedData(keyRef, algorithm, (__bridge CFDataRef)plainData, &error); } } else { // iOS 10及以下使用PKCS#1 v1.5 SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionPKCS1; if (SecKeyIsAlgorithmSupported(keyRef, kSecKeyOperationTypeEncrypt, algorithm)) { encryptedData = (__bridge_transfer NSData *)SecKeyCreateEncryptedData(keyRef, algorithm, (__bridge CFDataRef)plainData, &error); } } if (error) { NSLog(@"Encryption error: %@", error); CFRelease(error); } CFRelease(keyRef); return encryptedData;
注意事项
- Make sure your server updates its decryption code to handle both padding schemes. For example, in Java, this would mean checking the iOS version from the request (or trying both paddings if possible) to use
OAEPWithSHA-256AndMGF1PaddingorPKCS1Paddingaccordingly.
方案2:使用OpenSSL实现OAEP-SHA256(无需修改服务器)
If your server can't change its decryption logic and must use OAEP-SHA256, you'll need to use a third-party library like OpenSSL to implement the encryption on iOS 10 and below.
步骤1:集成OpenSSL
You can add OpenSSL to your project via CocoaPods by adding this to your Podfile:
pod 'OpenSSL-Universal'
Run pod install to set it up.
步骤2:OAEP-SHA256加密代码实现
Here's a helper method to encrypt data using OpenSSL's OAEP-SHA256 implementation:
#import <openssl/rsa.h> #import <openssl/pem.h> #import <openssl/err.h> - (NSData *)rsaOAEPEncryptWithOpenSSL:(NSData *)plainData publicKey:(NSString *)pubKey { // 将PEM格式公钥转换为OpenSSL的EVP_PKEY BIO *bio = BIO_new_mem_buf((void *)[pubKey UTF8String], (int)[pubKey length]); EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); BIO_free(bio); if (!pkey) { NSLog(@"Failed to load public key"); ERR_print_errors_fp(stderr); return nil; } EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); if (!ctx || EVP_PKEY_encrypt_init(ctx) <= 0) { NSLog(@"Failed to init encryption context"); EVP_PKEY_free(pkey); return nil; } // 设置OAEP-SHA256参数 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256()) <= 0) { NSLog(@"Failed to set OAEP parameters"); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return nil; } // 计算加密后的数据长度 size_t outLen = 0; if (EVP_PKEY_encrypt(ctx, NULL, &outLen, plainData.bytes, plainData.length) <= 0) { NSLog(@"Failed to calculate output length"); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return nil; } // 分配内存并执行加密 unsigned char *outBuf = malloc(outLen); if (EVP_PKEY_encrypt(ctx, outBuf, &outLen, plainData.bytes, plainData.length) <= 0) { NSLog(@"Encryption failed"); ERR_print_errors_fp(stderr); free(outBuf); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return nil; } NSData *encryptedData = [NSData dataWithBytes:outBuf length:outLen]; free(outBuf); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return encryptedData; }
步骤3:版本判断整合
Combine this with version checking to use native framework on iOS 10+ and OpenSSL on older versions:
SecKeyRef keyRef = [self addPublicKey:pubKey]; if (!keyRef) { return nil; } NSData *encryptedData = nil; CFErrorRef error = NULL; if (@available(iOS 10.0, *)) { SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA256; if (SecKeyIsAlgorithmSupported(keyRef, kSecKeyOperationTypeEncrypt, algorithm)) { encryptedData = (__bridge_transfer NSData *)SecKeyCreateEncryptedData(keyRef, algorithm, (__bridge CFDataRef)plainData, &error); } CFRelease(keyRef); } else { // iOS 10及以下使用OpenSSL实现OAEP-SHA256 encryptedData = [self rsaOAEPEncryptWithOpenSSL:plainData publicKey:pubKey]; } if (error) { NSLog(@"Encryption error: %@", error); CFRelease(error); } return encryptedData;
注意事项
- Ensure your public key is in PEM format (starts with
-----BEGIN PUBLIC KEY-----and ends with-----END PUBLIC KEY-----). If you're using a DER format key, you'll need to convert it to PEM first. - Always clean up OpenSSL resources (like
EVP_PKEY,EVP_PKEY_CTX,BIO) to avoid memory leaks.
最后建议
- Test both implementations thoroughly on iOS 9/10 devices to ensure compatibility.
- If possible, prefer the native Security framework approach (方案1) since it avoids third-party dependencies and is more maintainable.
内容的提问来源于stack exchange,提问作者daniel1511

