如何从 iOS 中的 PEM 编码密钥检索 ASN.1 编码信息

How retrieves ASN.1 encoded information from PEM encoded key in iOS

目前正在使用 Apple CommonCrypto 进行一些加密。我们有使用密码学来保持零知识原则的 Web 应用程序,现在我们想将这种方法转移到 iOS 应用程序。 我阅读了有关 ASN.1 的信息,当尝试使用那里的工具进行解析时,我收到错误 - 不是有效字符,但为了能够解密,我需要删除一些额外的符号。所以要解密密码,我需要通过几个步骤,其中之一 - 获取盐,这是在私钥中加密的。私钥如下所示:

"-----BEGIN ENCRYPTED PRIVATE KEY-----\r\nMIIFMjBcBgkqhkiG9w0BBQ0wTzAyBgkqhkiG9w0BBQwwJQQQsViPrFXr42CML5Ze\r\nYwQqCgIDAPoAMAwGCCqGSIb3DQIJBQAwGQYJYIZIAWUDBAEuBAwuBIjgFPCE/ESd\r\nqckEggTQjnq/Jv+J+OZUyTn+7plQJxrXHo375RYGNuUFlwkpzDmQAduU1ngrBh2D\r\nLwlBaiZQd+jU+7s5TVcIqJ3dNVdruN2du1v1TN/49NmQeWMc9IW9gH84vbAE5spu\r\naCx0RONt7UdJ1TENM4sRMvIUKky2jmTa/HaTnvBHb4/5TWIPBktj0B5QCqgQPVVB\r\nCmG/cK0JeZ0wPNTkEiP/Exst1smY/x3vqxO+/G8cjVZMi/uzjZgf/jbpJ0qbdQSR\r\nJ6xwVLID8Dc3O43KL3qmnkbu81iAWi4PuKiq3gvONOH/Ud2ENsNRVrLRUT/jYSyY\r\nnIuDccrW+YoTJ1qJLOIPXB/m1dUqS0aUo2VZCHwIPCqeuGEBrGX+U7MLXnXWMYY7\r\n0AIpS8Xq15Z+3OrnJFuQoQ+JZWOk+Ngqfq2rCasgZKZaCnqcUw09TDBhWWxyJUQE\r\nbcTpUX4hi1eJ5vFRNpLS0q7hI2wfAjkn8jnhKo2aH40/a9USjDJWjrW5RfKHkL/N\r\nrO5YKVin2iadoFkxXyv10WyZiYGinBUnr1GNl3fiC9JC6VCb4f4euyH9xvPMn9MU\r\nUw7EGufxcGo5thbyctHY0koBqvnaoQNCdf1IWhU8CCQLiMGKO4ND+cCZv5FGVoOn\r\ny3J6lBIon/g2MoLO8t6cqTK2N8xJbGmiYFayb1FTpvc6sZ7soiqmJ/EQmIxH8/jk\r\nzYGZVaMg3LbT4YkgtVkak0NrgHurk6Cp+Zf1KLM+rUTRRWf354Me6zMXhHiEbALw\r\nw9ubBrZDC5ftW7E0lwCp8y1vs9aUx+zyj7pTorNQYX8eC/A/ZdUj4EasfvqXj0Ke\r\nVLHdLlSPVsPyLY7loDwIQ1PQEU6rTELP/e4agPMda9zTRuJYelbp/oAA0YtHDD8f\r\nKs3OmLofzoWLG29wXi6KzjY09jIXh9sJ2qBHC1dyoJmHbDcIuN0n/sVI23BikdIZ\r\n3yJYfGP+MLq5c/YfiGGXOo1DxChSg+oUtWO0i30GWL4ze/alv3bjaZo6e+ahNatW\r\nqXbqDGAMQtcsaoeZfEJwtsMaQ1GVGOc5N5u7jaaelQ3/nClOwSDmAZ77/FXBaWNy\r\nSnpLfUfI9Hej6GTXDR5CEP0Wlac+n4uXdy801r4bayDKx8wlUNy93wfoHmYDrIlo\r\nyV7dKBZioAJtUA5NDVJj8KZPYI1Na6nIL8hxs44fSOqESZGHI9ir1RgrKk7k1G6F\r\nve6zlj7CENDl3UO4fNbRWI5lObCX4OWlKgYXlPN3SyrT0IzUXuw1QPHlqdl/j2VD\r\n+x6Ve2NFBSN9j8Gi90ZD159Oc+rdjXykGwT8p5ame60lB2qou72dgLUZn6U7GnG0\r\nWip27S4C2o90bwKnNKTX2o1rQRob101k7pkJEu3yJCKCnjIlR7Zwma3ZFXvhB1Ep\r\nikKhtP3zUiyQzzK1j8W98dKmSgTBYxpkJGfyGx8iqPZR5lGuD+Zrz+PzljSYD02l\r\nkiiV+uljWHGNFxo3DrTiJ4O2hSK0VEss5mRebiNWJv11egxL8nKsd0anWvdkajjd\r\nock5U77TGLV7nGks7OU6wGhuTqlB+2O6KYrl7HBoKS7QG75k1r96OFwZcXtlfErP\r\ntObwa4cNvekoknk4jhXyjbySJUB6E8TJal67gkyPCE/xACYniPY=\r\n-----END ENCRYPTED PRIVATE KEY-----" 

我需要从 PEM 编码密钥中检索 ASN.1 编码信息。 Web 开发人员使用执行所有这些解密的库,并作为他们收到的解密值:

const res = {
    salt: this.hexStringToArrayBuffer(opt.salt),
    iv: this.hexStringToArrayBuffer(opt.iv),
    cipher: opt.cipher,
    length: opt.length,
    hash: opt.hash,
    iter: opt.iter,
    encryptedData: this.hexStringToArrayBuffer(opt.encryptedData),
  };

我需要使用相同的方法来解密这些私钥。我搜索了很多,但还没有找到 swift 的任何合适的解决方案。我将非常感谢任何建议。

非常感谢您的帮助!

您需要解密-----BEGIN ENCRYPTED PRIVATE KEY-----

在 openssl 中会是

openssl rsa -in enc.key -out dec.key

如果您使用的是 rsa,您将提供加密密钥的密码:

你的情况:

  1. Base64解码私钥
  2. 使用密码解密私钥
  3. base64 结果(或将其用作 ASN.1 解码的来源

在搜索解决方案后,我将 JS 框架转换为 swift 并解密了 pem 密钥:

    func getParsedKey(privateKey: String) -> ResultDecoded? {
    var privateKey = privateKey
    privateKey = privateKey.replacingOccurrences(of: "-----BEGIN ENCRYPTED PRIVATE KEY-----", with: "")
    privateKey = privateKey.replacingOccurrences(of: "-----END ENCRYPTED PRIVATE KEY-----", with: "")
    privateKey = privateKey.replacingOccurrences(of: "\r\n", with: "")
    guard let data = Data(base64EncodedURLSafe: privateKey) else {
        // handle errors in decoding base64 string here
        return nil
    }
    let hex = data.hexa
    var opt = Opt()
    opt.data = hex
    if hex.contains(PBES2_OID) && hex.contains(PBKDF2_OID) {
        opt.valid = true
    }
    if let range = hex.range(of: PBKDF2_OID) {
        opt.saltBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 28
    }
    
    if let range = opt.data.range(of: AES256GCM_OID) {
        opt.cipher = "AES-GCM"
        opt.length = 256;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 24;
      } else if let range = opt.data.range(of: AES192GCM_OID) {
        opt.cipher = "AES-GCM"
        opt.length = 192;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 24;
      } else if let range = opt.data.range(of: AES128GCM_OID) {
        opt.cipher = "AES-GCM";
        opt.length = 128;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 24;
      } else if let range = opt.data.range(of: AES256CBC_OID) {
        opt.cipher = "AES-CBC";
        opt.length = 256;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 24;
      } else if let range = opt.data.range(of: AES192CBC_OID) {
        opt.cipher = "AES-CBC";
        opt.length = 192;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 24;
      } else if let range = opt.data.range(of: AES128CBC_OID) {
        opt.cipher = "AES-CBC";
        opt.length = 128;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 24;
      } else if let range = opt.data.range(of: AES256CFB_OID) {
        opt.cipher = "AES-CFB";
        opt.length = 256;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 24;
      } else if let range = opt.data.range(of: AES192CFB_OID) {
        opt.cipher = "AES-CFB";
        opt.length = 192;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 24;
      } else if let range = opt.data.range(of: AES128CFB_OID) {
        opt.cipher = "AES-CFB";
        opt.length = 128;
        opt.ivBegin = hex.distance(from: hex.startIndex, to: range.lowerBound) + 22;
      }

    if opt.data.contains(SHA512_OID) {
      opt.hash = "SHA-512"
    } else if opt.data.contains(SHA384_OID) {
      opt.hash = "SHA-384"
    } else if opt.data.contains(SHA256_OID) {
      opt.hash = "SHA-256"
    } else if opt.data.contains(SHA1_OID) {
      opt.hash = "SHA-1"
    }
    
    opt.saltLength = opt.data.subString(from: opt.saltBegin, to: 2).integerValue()
    opt.ivLength = opt.data.subString(from: opt.ivBegin, to: 2).integerValue()
    opt.salt = opt.data.subString(from: opt.saltBegin + 2, to: opt.saltLength * 2)
    opt.iv = opt.data.subString(from: opt.ivBegin + 2, to: opt.ivLength * 2);
    
    opt.iterBegin = opt.saltBegin + 4 + opt.saltLength * 2;
    opt.iterLength = opt.data.subString(from:opt.iterBegin, to: 2).integerValue()
    opt.iter = opt.data.subString(from: opt.iterBegin + 2, to: opt.iterLength * 2).integerValue()
    
    opt.sequencePadding = opt.data.subString(from: 2, to: 2) == "81" ? 8 : 10;
    opt.parametersPadding = opt.data.subString(from: 2, to: 2) == "81" ? 12 : 16;
    opt.sequenceLength = opt.data.subString(from: opt.sequencePadding, to: 2).integerValue()
    opt.encryptedDataBegin = opt.parametersPadding + opt.sequenceLength * 2;
    opt.encryptedDataPadding =
    opt.data.subString(from: opt.encryptedDataBegin - 2, to: 2) == "81" ? 2 : 4;
    let sublength = opt.data.subString(from: opt.encryptedDataBegin, to: 6)
    opt.encryptedDataLength = sublength.integerValue()
    opt.encryptedData = opt.data.subString(from: opt.encryptedDataBegin + opt.encryptedDataPadding,
                                           to: opt.encryptedDataLength * 2)
    
    
    return ResultDecoded(salt: Data(opt.salt.utf8),
                         iv: opt.iv.hexaBytes,
                         cipher: opt.cipher,
                         length: opt.length,
                         hash: opt.hash,
                         iter: opt.iter,
                         encryptedData: opt.encryptedData.hexaBytes)
}