Swift 4 中的 RSA 加密函数来自 Public 密钥字符串
RSA Encryption function in Swift 4 from Public Key string
我的最终目标是创建一个 JWE 字符串,给定 iOS 的 public 键。
为了让我自己更轻松,我已经非常紧迫地分解了我的步骤,我需要使用来自秘密密钥和 public 密钥字符串的 RSA 加密来创建加密密钥。
我已经尝试了很多在堆栈溢出和互联网其他地方找到的东西。由于各种原因,他们只是没有解决。
我正在接受一些 Objective C 代码的指导:
/* Device Data encryption - create JWE given DS publicKey */ +(NSString *)createJWE:(NSString *)payload withPublicKey:(SecKeyRef)publicKey {
// create secretKey for encryption
NSData *secret = [self generateRandom:(KEY_SIZE*2)];
NSData *hmacKey = [secret subdataWithRange:NSMakeRange(0, KEY_SIZE)]; NSData *aesKey = [secret subdataWithRange:NSMakeRange(KEY_SIZE,
KEY_SIZE)];
NSData *iv = [self generateRandom: IV_SIZE];
// create header
NSString *header = @"{\"enc\":\"A128CBC-HS256\",\"alg\":\"RSA-OAEP\"}";
// encrypt secretKey
NSData *encryptedKey = [self rsaEncrypt:secret key:publicKey];
// encrypt payload
NSData *encrypted = [self aesEncrypt:[payload dataUsingEncoding:NSUTF8StringEncoding] withKey:aesKey withIV:iv];
NSString *basePayload = [encrypted unpaddedBase64URLEncoded];
NSString *baseCEK = [encryptedKey unpaddedBase64URLEncoded];
NSString *baseHeader = [[header dataUsingEncoding:NSUTF8StringEncoding]
unpaddedBase64URLEncoded];
NSString *baseIV = [iv unpaddedBase64URLEncoded];
// create auth hash
NSData *hmac = [self hmac: encrypted withKey: hmacKey withIV: iv withA:
[baseHeader dataUsingEncoding:NSASCIIStringEncoding]];
return [NSString stringWithFormat:@"%@.%@.%@.%@.%@", baseHeader, baseCEK, baseIV, basePayload, [[self hmacToTag: hmac] unpadded
我目前正处于函数的这一点:
NSData *encryptedKey = [self rsaEncrypt:secret key:publicKey];
据此我假设存在一个接受秘密和 public 密钥的 rsaEncrypt 函数。
我有权访问的 public 密钥如下所示:
let publicKey = """
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEChqe80lJLTTkJD3X3Lyd7Fj+
zuOhDZkjuLNPog3YR20e5JcrdqI9IFzNbACY/GQVhbnbvBqYgyql8DfPCGXpn0+X
NSxELIUw9Vh32QuhGNr3/TBpechrVeVpFPLwyaYNEk1CawgHCeQqf5uaqiaoBDOT
qeox88Lc1ld7MsfggQIDAQAB
-----END PUBLIC KEY-----
"""
在 Internet 上找到的示例将 public 密钥作为 SecKey 类型进行处理。这是我执行加密的第一个障碍。
- 如果必须转换字符串,如何将其转换为 SecKey?
- 我的 rsaEncrypt 函数应该做什么?
我希望执行加密后输出的是加密密钥。
更新:另一种变体,发送的一个 public 密钥也如下所示:
{ "kty": "RSA", "kid": "UUIDkeyidentifierforDS", "use": "enc", "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O- XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL- QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe- OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0F Vbb9k3- tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5i aiQkqgc5gHdrNP5zw", "e": "AQAB" }
github 上有 RSAUtils.swift class。将此文件添加到您的项目中。
然后您可以使用以下函数 encrypt/decrypt 带有 base64 编码 public 令牌的任何字符串内容:
/**
Returns RSA encrypted Base64 encoded string with specified public key which is Base64 encoded string.
- parameter withPublickKeyBase64: Base64 encoded string value of public key.
- returns: RSA encrypted Base64 encoded string.
*/
func encryptRsaBase64(_ string: String, withPublickKeyBase64: String) -> String? {
if let data = string.data(using: .utf8) {
if let encrypted = RSAUtils.encryptWithRSAPublicKey(data, pubkeyBase64: withPublickKeyBase64, keychainTag: "") {
return encrypted.base64EncodedString()
}
}
return nil
}
/**
Returns RSA decrypted Base64 encoded string with specified public key which is Base64 encoded string.
- parameter withPublickKeyBase64: Base64 encoded string value of public key.
- returns: RSA decrypted Base64 encoded string.
*/
func decryptRsaBase64Encrypted(_ string: String, withPublicKeyBase64: String) -> String? {
if let encrypted = Data(base64Encoded: string, options: Data.Base64DecodingOptions.init(rawValue: 0)) {
if let data = RSAUtils.decryptWithRSAPublicKey(encrypted, pubkeyBase64: withPublicKeyBase64, keychainTag: "") {
return String(data: data, encoding: .utf8)
}
}
return nil
}
你可以这样做...
static func encrypt(string: String, publicKey: String?) -> String? {
guard let publicKey = publicKey else { return nil }
let keyString = publicKey.replacingOccurrences(of: "-----BEGIN PUBLIC KEY-----\n", with: "").replacingOccurrences(of: "\n-----END PUBLIC KEY-----", with: "")
guard let data = Data(base64Encoded: keyString) else { return nil }
var attributes: CFDictionary {
return [kSecAttrKeyType : kSecAttrKeyTypeRSA,
kSecAttrKeyClass : kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits : 2048,
kSecReturnPersistentRef : kCFBooleanTrue] 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 buffer = [UInt8](string.utf8)
var keySize = SecKeyGetBlockSize(publicKey)
var keyBuffer = [UInt8](repeating: 0, count: keySize)
// Encrypto should less than key length
guard SecKeyEncrypt(publicKey, SecPadding.PKCS1, buffer, buffer.count, &keyBuffer, &keySize) == errSecSuccess else { return nil }
return Data(bytes: keyBuffer, count: keySize).base64EncodedString()
}
这对我有用:
RSA/ECB/PKCS1Padding编码UTF-8
import Foundation
static func encrypt(string: String, publicKey: String?) -> String? {
guard let publicKey = publicKey else {
return nil
}
let keyString = publicKey.replacingOccurrences(of: "-----BEGIN PUBLIC KEY-----\n", with: "").replacingOccurrences(of: "\n-----END PUBLIC KEY-----", with: "")
guard let data = Data(base64Encoded: keyString) else {
return nil
}
var attributes: CFDictionary {
return [kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits: 2048,
kSecReturnPersistentRef: kCFBooleanTrue] as CFDictionary
}
var error: Unmanaged<CFError>? = nil
guard let secKey = SecKeyCreateWithData(data as CFData, attributes, &error) else {
print(error.debugDescription)
return nil
}
return vEncrypt(string: string, publicKey: secKey)
}
static func vEncrypt(string: String, publicKey: SecKey) -> String? {
let buffer = [UInt8](string.utf8)
var keySize = SecKeyGetBlockSize(publicKey)
var keyBuffer = [UInt8](repeating: 0, count: keySize)
//
guard SecKeyEncrypt(publicKey, SecPadding.PKCS1, buffer, buffer.count, &keyBuffer, &keySize) == errSecSuccess else {
return nil
}
return Data(bytes: keyBuffer, count: keySize).base64EncodedString()
}
我的最终目标是创建一个 JWE 字符串,给定 iOS 的 public 键。
为了让我自己更轻松,我已经非常紧迫地分解了我的步骤,我需要使用来自秘密密钥和 public 密钥字符串的 RSA 加密来创建加密密钥。
我已经尝试了很多在堆栈溢出和互联网其他地方找到的东西。由于各种原因,他们只是没有解决。
我正在接受一些 Objective C 代码的指导:
/* Device Data encryption - create JWE given DS publicKey */ +(NSString *)createJWE:(NSString *)payload withPublicKey:(SecKeyRef)publicKey {
// create secretKey for encryption
NSData *secret = [self generateRandom:(KEY_SIZE*2)];
NSData *hmacKey = [secret subdataWithRange:NSMakeRange(0, KEY_SIZE)]; NSData *aesKey = [secret subdataWithRange:NSMakeRange(KEY_SIZE,
KEY_SIZE)];
NSData *iv = [self generateRandom: IV_SIZE];
// create header
NSString *header = @"{\"enc\":\"A128CBC-HS256\",\"alg\":\"RSA-OAEP\"}";
// encrypt secretKey
NSData *encryptedKey = [self rsaEncrypt:secret key:publicKey];
// encrypt payload
NSData *encrypted = [self aesEncrypt:[payload dataUsingEncoding:NSUTF8StringEncoding] withKey:aesKey withIV:iv];
NSString *basePayload = [encrypted unpaddedBase64URLEncoded];
NSString *baseCEK = [encryptedKey unpaddedBase64URLEncoded];
NSString *baseHeader = [[header dataUsingEncoding:NSUTF8StringEncoding]
unpaddedBase64URLEncoded];
NSString *baseIV = [iv unpaddedBase64URLEncoded];
// create auth hash
NSData *hmac = [self hmac: encrypted withKey: hmacKey withIV: iv withA:
[baseHeader dataUsingEncoding:NSASCIIStringEncoding]];
return [NSString stringWithFormat:@"%@.%@.%@.%@.%@", baseHeader, baseCEK, baseIV, basePayload, [[self hmacToTag: hmac] unpadded
我目前正处于函数的这一点:
NSData *encryptedKey = [self rsaEncrypt:secret key:publicKey];
据此我假设存在一个接受秘密和 public 密钥的 rsaEncrypt 函数。
我有权访问的 public 密钥如下所示:
let publicKey = """
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEChqe80lJLTTkJD3X3Lyd7Fj+
zuOhDZkjuLNPog3YR20e5JcrdqI9IFzNbACY/GQVhbnbvBqYgyql8DfPCGXpn0+X
NSxELIUw9Vh32QuhGNr3/TBpechrVeVpFPLwyaYNEk1CawgHCeQqf5uaqiaoBDOT
qeox88Lc1ld7MsfggQIDAQAB
-----END PUBLIC KEY-----
"""
在 Internet 上找到的示例将 public 密钥作为 SecKey 类型进行处理。这是我执行加密的第一个障碍。
- 如果必须转换字符串,如何将其转换为 SecKey?
- 我的 rsaEncrypt 函数应该做什么?
我希望执行加密后输出的是加密密钥。
更新:另一种变体,发送的一个 public 密钥也如下所示:
{ "kty": "RSA", "kid": "UUIDkeyidentifierforDS", "use": "enc", "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O- XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL- QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe- OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0F Vbb9k3- tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5i aiQkqgc5gHdrNP5zw", "e": "AQAB" }
github 上有 RSAUtils.swift class。将此文件添加到您的项目中。
然后您可以使用以下函数 encrypt/decrypt 带有 base64 编码 public 令牌的任何字符串内容:
/**
Returns RSA encrypted Base64 encoded string with specified public key which is Base64 encoded string.
- parameter withPublickKeyBase64: Base64 encoded string value of public key.
- returns: RSA encrypted Base64 encoded string.
*/
func encryptRsaBase64(_ string: String, withPublickKeyBase64: String) -> String? {
if let data = string.data(using: .utf8) {
if let encrypted = RSAUtils.encryptWithRSAPublicKey(data, pubkeyBase64: withPublickKeyBase64, keychainTag: "") {
return encrypted.base64EncodedString()
}
}
return nil
}
/**
Returns RSA decrypted Base64 encoded string with specified public key which is Base64 encoded string.
- parameter withPublickKeyBase64: Base64 encoded string value of public key.
- returns: RSA decrypted Base64 encoded string.
*/
func decryptRsaBase64Encrypted(_ string: String, withPublicKeyBase64: String) -> String? {
if let encrypted = Data(base64Encoded: string, options: Data.Base64DecodingOptions.init(rawValue: 0)) {
if let data = RSAUtils.decryptWithRSAPublicKey(encrypted, pubkeyBase64: withPublicKeyBase64, keychainTag: "") {
return String(data: data, encoding: .utf8)
}
}
return nil
}
你可以这样做...
static func encrypt(string: String, publicKey: String?) -> String? {
guard let publicKey = publicKey else { return nil }
let keyString = publicKey.replacingOccurrences(of: "-----BEGIN PUBLIC KEY-----\n", with: "").replacingOccurrences(of: "\n-----END PUBLIC KEY-----", with: "")
guard let data = Data(base64Encoded: keyString) else { return nil }
var attributes: CFDictionary {
return [kSecAttrKeyType : kSecAttrKeyTypeRSA,
kSecAttrKeyClass : kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits : 2048,
kSecReturnPersistentRef : kCFBooleanTrue] 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 buffer = [UInt8](string.utf8)
var keySize = SecKeyGetBlockSize(publicKey)
var keyBuffer = [UInt8](repeating: 0, count: keySize)
// Encrypto should less than key length
guard SecKeyEncrypt(publicKey, SecPadding.PKCS1, buffer, buffer.count, &keyBuffer, &keySize) == errSecSuccess else { return nil }
return Data(bytes: keyBuffer, count: keySize).base64EncodedString()
}
这对我有用:
RSA/ECB/PKCS1Padding编码UTF-8
import Foundation
static func encrypt(string: String, publicKey: String?) -> String? {
guard let publicKey = publicKey else {
return nil
}
let keyString = publicKey.replacingOccurrences(of: "-----BEGIN PUBLIC KEY-----\n", with: "").replacingOccurrences(of: "\n-----END PUBLIC KEY-----", with: "")
guard let data = Data(base64Encoded: keyString) else {
return nil
}
var attributes: CFDictionary {
return [kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits: 2048,
kSecReturnPersistentRef: kCFBooleanTrue] as CFDictionary
}
var error: Unmanaged<CFError>? = nil
guard let secKey = SecKeyCreateWithData(data as CFData, attributes, &error) else {
print(error.debugDescription)
return nil
}
return vEncrypt(string: string, publicKey: secKey)
}
static func vEncrypt(string: String, publicKey: SecKey) -> String? {
let buffer = [UInt8](string.utf8)
var keySize = SecKeyGetBlockSize(publicKey)
var keyBuffer = [UInt8](repeating: 0, count: keySize)
//
guard SecKeyEncrypt(publicKey, SecPadding.PKCS1, buffer, buffer.count, &keyBuffer, &keySize) == errSecSuccess else {
return nil
}
return Data(bytes: keyBuffer, count: keySize).base64EncodedString()
}