如何从 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,您将提供加密密钥的密码:
你的情况:
- Base64解码私钥
- 使用密码解密私钥
- 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)
}
目前正在使用 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,您将提供加密密钥的密码:
你的情况:
- Base64解码私钥
- 使用密码解密私钥
- 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)
}