Swift 从字符串加载 RSA Public 密钥 (MacOS)

Swift Load RSA Public Key from String (MacOS)

我想知道如何从字符串加载 RSA Public 密钥并用它加密另一个字符串。 public 键类似于:

let key = """ -----BEGIN PUBLIC KEY----- blah blah blah -----END PUBLIC KEY-----"""

我宁愿在没有外部库的情况下执行此操作,但如果它使事情变得更容易,我愿意使用它们。 提前致谢。

您拥有的关键数据 PEM encoded. However, Apple supports DER encoding 是为了他们的安全 API。因此,首先我们必须将您的关键数据转换为正确的格式。下面的示例是使用随机 RSA 密钥创建的,将 public 密钥导出为 PEM 格式。 PEM headers 可能因库而异,因此请确保在继续进行 DER 转换之前删除标签。

var pem = "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAs6AofVx+UAXcVjnIU0Z5SAGO/LPlTunA9zi7jNDcIrZTR8ULHTrm\naSAg/ycNR1/wUeac617RrFeQuoPSWjhZPRJrMa3faVMCqTgV2AmaPgKnPWBrY2ir\nGhnCnIAvD3sitCEKultjCstrTA71Jo/BuVaj6BVgaA/Qn3U9mQ+4JiEFiTxy4kOF\nes1/WwTLjRQYVf42oG350bTKw9F0MklTTZdiZKCQtc3op86A7VscFhwusY0CaZfB\nlRDnTgTMoUhZJpKSLZae93NVFSJY1sUANPZg8TzujqhRKt0g5HR/Ud61icvBbcx8\n+a3NzmuwPylvp5m6hz/l14Y7UZ8UT5deywIDAQAB\n-----END RSA PUBLIC KEY-----\n"

// Remove headers and footers from the PEM, leaving us with DER encoded data split by new lines
[
    "-----BEGIN RSA PUBLIC KEY-----", "-----END RSA PUBLIC KEY-----",
    "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----"
].forEach { pem = pem.replacingOccurrences(of: [=10=], with: "") }

// Construct DER data from the remaining PEM data
let der = Data(base64Encoded: pem, options: .ignoreUnknownCharacters)!

现在我们有了 DER 编码数据,是时候构建我们​​的密钥了。首先,创建描述密钥的属性,然后从 DER 数据创建密钥。注意这里 derData 类型而不是 String 类型。一般来说,加密操作发生在 Data 上。然而,安全性 API 使用 CFData,但可以很容易地交换它们(as CFDataas Data)。属性字典也是如此。

// Key generation attributes
let attributes: [String: Any] = [
    String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
    String(kSecAttrKeyClass): kSecAttrKeyClassPublic,
    String(kSecAttrKeySizeInBits): der.count * 8
]

// For simplicity I force unwrap here. The nil parameter can be used to extract an error
let key = SecKeyCreateWithData(der as CFData, attributes as CFDictionary, nil)!

现在我们有了密钥,可以用它来加密了。但是请注意,RSA 无法加密大量数据(从技术上讲不是真的,您可以创建数据块并以这种方式进行,但 RSA 并非为此目的。如果您想这样做,请阅读密钥交换和对称加密。RSA 不适用于该行为)。另请注意,OAEP(如示例中所用)具有随机因素。这意味着每次 运行 此代码时密文输出都会不同。这并不意味着它不起作用,它只是一个 属性 OAEP。我还想指出,在支持 OAEP 的情况下,应避免使用 PKCS1 填充。

// An example message to encrypt
let plainText = "This is my secret".data(using: .utf8)!
    
// Perform the actual encryption
// Again force unwrapping for simplicity
let cipherText = SecKeyCreateEncryptedData(key, .rsaEncryptionOAEPSHA256, plainText as CFData, nil)! as Data

在上面的示例中使用了 .rsaEncryptionOAEPSHA256。这是 RSA 可用的加密算法之一:

  • .rsaEncryptionRaw
  • .rsaEncryptionPKCS1
  • .rsaEncryptionOAEPSHA1
  • .rsaEncryptionOAEPSHA224
  • .rsaEncryptionOAEPSHA256
  • .rsaEncryptionOAEPSHA384
  • .rsaEncryptionOAEPSHA512

我强烈建议使用其中一种 OAEP 变体,但这取决于您。我希望这有帮助。 SecKeyCreateEncryptedData 自 10.12 起可用于 macOS。您可以阅读更多相关信息 here