Swift使用RSA/ECB/OAEPWithSHA-256AndMGF1Padding加密出现填充错误求助
RSA加密解密填充错误问题排查与修复
问题场景
后端提供RSA公钥,需使用RSA/ECB/OAEPWithSHA-256AndMGF1Padding算法加密数据后发送至服务器,但当前Swift实现加密后,后端解密时报错:解密时填充错误(原英文错误:Padding error in decryption)。
原实现代码:
static func encrypt(string: String, publicKey: String?) -> String? { guard let publicKey = publicKey else { return nil } let keyString = publicKey.replacingOccurrences(of: "-----BEGIN RSA PUBLIC KEY-----\n", with: "").replacingOccurrences(of: "\n-----END RSA PUBLIC KEY-----", with: "") guard let data = Data(base64Encoded: keyString) else { return nil } var attributes: CFDictionary { return [kSecAttrKeyType : kSecAttrKeyTypeRSA, kSecAttrKeyClass : kSecAttrKeyClassPublic, kSecAttrKeySizeInBits : 2048, kSecReturnPersistentRef : true] as CFDictionary } var error: Unmanaged<CFError>? = nil guard let secKey = SecKeyCreateWithData(data as CFData, attributes, &error) else { print(error.debugDescription) return nil } return encrypt(string: string, publicKey: secKey) } static func encrypt(string: String, publicKey: SecKey) -> String? { let bufferData = string.data(using: .utf8)! var error: Unmanaged<CFError>? guard let encryptedData = SecKeyCreateEncryptedData( publicKey, .rsaEncryptionOAEPSHA256, // Specify OAEP with SHA-256 padding bufferData as CFData, &error ) as Data? else { return nil } return encryptedData.base64EncodedString() }
问题原因与修复方案
1. 公钥格式处理不鲁棒
原代码仅替换固定换行的头尾标记,若公钥中的换行符为\r\n或无换行,会导致残留无效字符,影响密钥解析。
修复:统一去掉头尾标记,并修剪所有空白字符(包括换行、空格):
let keyString = publicKey .replacingOccurrences(of: "-----BEGIN RSA PUBLIC KEY-----", with: "") .replacingOccurrences(of: "-----END RSA PUBLIC KEY-----", with: "") .trimmingCharacters(in: .whitespacesAndNewlines)
2. MGF1哈希算法不匹配
RSA/ECB/OAEPWithSHA-256AndMGF1Padding要求MGF1掩码生成函数使用SHA-256,但Swift默认的.rsaEncryptionOAEPSHA256仅指定了加密哈希为SHA-256,MGF1默认用SHA-1,与后端算法不一致导致填充错误。
修复:显式指定MGF1哈希算法为SHA-256:
static func encrypt(string: String, publicKey: SecKey) -> String? { guard let bufferData = string.data(using: .utf8) else { return nil } // 配置OAEP参数:加密哈希和MGF1哈希均为SHA-256 let oaepParams = [ kSecKeyEncryptionOAEPHashAttribute: kSecDigestSHA256, kSecKeyEncryptionOAEPEncodingMGF1Attribute: kSecDigestSHA256 ] as CFDictionary var error: Unmanaged<CFError>? guard let encryptedData = SecKeyCreateEncryptedData( publicKey, .rsaEncryptionOAEPSHA256, bufferData as CFData, oaepParams, &error ) as Data? else { print(error?.takeRetainedValue() ?? "加密失败") return nil } return encryptedData.base64EncodedString() }
3. 冗余密钥属性干扰
原代码中kSecReturnPersistentRef : true属于密钥持久化属性,临时创建加密密钥时无需设置,可能导致密钥初始化异常。
修复:移除该属性,简化密钥属性字典:
var attributes: CFDictionary { return [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPublic, kSecAttrKeySizeInBits: 2048 ] as CFDictionary }
完整修复后代码
static func encrypt(string: String, publicKey: String?) -> String? { guard let publicKey = publicKey else { return nil } // 鲁棒处理公钥格式 let keyString = publicKey .replacingOccurrences(of: "-----BEGIN RSA PUBLIC KEY-----", with: "") .replacingOccurrences(of: "-----END RSA PUBLIC KEY-----", with: "") .trimmingCharacters(in: .whitespacesAndNewlines) guard let data = Data(base64Encoded: keyString) else { return nil } // 简化密钥属性 var attributes: CFDictionary { return [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPublic, kSecAttrKeySizeInBits: 2048 ] as CFDictionary } var error: Unmanaged<CFError>? = nil guard let secKey = SecKeyCreateWithData(data as CFData, attributes, &error) else { print(error?.takeRetainedValue() ?? "公钥解析失败") return nil } return encrypt(string: string, publicKey: secKey) } static func encrypt(string: String, publicKey: SecKey) -> String? { guard let bufferData = string.data(using: .utf8) else { return nil } // 指定MGF1哈希为SHA-256 let oaepParams = [ kSecKeyEncryptionOAEPHashAttribute: kSecDigestSHA256, kSecKeyEncryptionOAEPEncodingMGF1Attribute: kSecDigestSHA256 ] as CFDictionary var error: Unmanaged<CFError>? guard let encryptedData = SecKeyCreateEncryptedData( publicKey, .rsaEncryptionOAEPSHA256, bufferData as CFData, oaepParams, &error ) as Data? else { print(error?.takeRetainedValue() ?? "加密失败") return nil } return encryptedData.base64EncodedString() }
内容的提问来源于stack exchange,提问作者Axtamov O'lmas
相关产品推荐
相关产品推荐

