对于仍在寻找答案的人来说,也许我可以提供帮助。
SecKeyCreateWithData
从 iOS 10 开始你可以使用SecKeyCreateWithData https://developer.apple.com/documentation/security/1643701-seckeycreatewithdata?language=swift创建一个SecKey
来自该密钥的外部表示。
该表示形式的格式应与返回的格式相同SecKeyCopyExternalRepresentation https://developer.apple.com/documentation/security/1643698-seckeycopyexternalrepresentation。正如在docs https://developer.apple.com/documentation/security/1643698-seckeycopyexternalrepresentation,RSA 密钥的格式为 PCKS#1。
所以为了创建一个SecKey
根据给定的模数和指数,我们需要获取该密钥的 PKCS#1 表示形式。
引用自PKCS#1 https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.1:
RSA 公钥应使用 ASN.1 类型表示
RSA公钥:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
RSAPublicKey 类型的字段具有以下含义:
- 模数是 RSA 模数 n。
- publicExponent 是 RSA 公共指数 e。
该 ASN.1 类型需要使用来表示DER https://msdn.microsoft.com/en-us/library/windows/desktop/bb648640(v=vs.85).aspx以获得数据SecKeyCreateWithData
期望。
以正确的格式获取数据
下面我将尝试讨论如何在 Swift 中获取所需的数据格式。请注意,您也可以从命令行使用 OpenSSL 来执行此操作,如果您只需要执行一次,这可能会更容易。
中给出了需要做什么的很好的概述本文 https://digitalleaves.com/blog/2015/10/sharing-public-keys-between-ios-and-the-rest-of-the-world/作者:伊格纳西奥·涅托·卡瓦哈尔。
基本上,您需要将模数和指数编码为整数 https://msdn.microsoft.com/en-us/library/windows/desktop/bb540806(v=vs.85).aspx然后将它们组合成一个德序列 https://msdn.microsoft.com/en-us/library/windows/desktop/bb648645(v=vs.85).aspx.
您可以找到一些有关如何执行此操作的代码here https://github.com/airsidemobile/JOSESwift/blob/master/JOSESwift/Sources/CryptoImplementation/DataRSAPublicKey.swift and here https://github.com/airsidemobile/JOSESwift/blob/master/JOSESwift/Sources/ASN1DEREncoding.swift. (免责声明:我是该库的贡献者之一。)
我将尝试在下面总结一下。
假设我们有一个 RSA 模数和公共指数作为字节数组。从模数和指数的不同表示形式获取字节数组应该不会太难。
let exponent: [UInt8] = [
1, 0, 1
]
var modulus: [UInt8] = [
136, 0, 243, 196, 194, 126, 151, 243, 72, 84, 246, 234, 207, 215, 168, 5, 233, 212, 8, 37, 34, 52, 215, 217, 223, 183, 58, 129, 66, 112, 88, 71, 201, 71, 33, 156, 132, 7, 189, 234, 110, 6, 46, 189, 233, 206, 61, 128, 220, 138, 56, 49, 34, 159, 245, 208, 214, 49, 169, 58, 170, 68, 127, 93, 137, 99, 74, 54, 65, 109, 112, 33, 65, 169, 246, 176, 128, 121, 171, 35, 214, 236, 210, 123, 94, 146, 86, 30, 134, 135, 116, 124, 4, 55, 208, 163, 219, 220, 203, 249, 107, 69, 147, 169, 66, 214, 179, 195, 152, 211, 209, 78, 100, 114, 209, 203, 120, 16, 254, 24, 39, 143, 79, 49, 202, 10, 37, 2, 155, 162, 14, 253, 194, 205, 74, 116, 60, 205, 25, 53, 85, 144, 72, 11, 7, 133, 78, 149, 111, 0, 215, 174, 36, 104, 175, 62, 196, 197, 49, 78, 172, 146, 82, 216, 160, 45, 48, 212, 50, 168, 208, 255, 205, 82, 22, 11, 13, 156, 197, 42, 159, 26, 124, 237, 178, 131, 239, 186, 37, 96, 24, 154, 243, 202, 252, 87, 102, 23, 19, 29, 73, 130, 95, 45, 219, 104, 13, 54, 30, 165, 144, 223, 1, 14, 169, 100, 111, 246, 54, 185, 47, 156, 238, 249, 88, 33, 244, 135, 233, 102, 36, 86, 196, 143, 178, 176, 62, 24, 178, 209, 163, 244, 116, 236, 81, 177, 190, 205, 140, 230, 6, 113, 158, 105, 111, 123
]
然后我们需要确保模数的前缀为0x00
to 表明它是一个非负数 https://msdn.microsoft.com/en-us/library/windows/desktop/bb540806(v=vs.85).aspx.
modulus.insert(0x00, at: 0)
现在我们将模数和指数编码为INTEGERs https://msdn.microsoft.com/en-us/library/windows/desktop/bb540806(v=vs.85).aspx.
var modulusEncoded: [UInt8] = []
modulusEncoded.append(0x02)
modulusEncoded.append(contentsOf: lengthField(of: modulus))
modulusEncoded.append(contentsOf: modulus)
var exponentEncoded: [UInt8] = []
exponentEncoded.append(0x02)
exponentEncoded.append(contentsOf: lengthField(of: exponent))
exponentEncoded.append(contentsOf: exponent)
并将这些结合起来INTEGERs https://msdn.microsoft.com/en-us/library/windows/desktop/bb540806(v=vs.85).aspx to a SEQUENCE https://msdn.microsoft.com/en-us/library/windows/desktop/bb648645(v=vs.85).aspx.
var sequenceEncoded: [UInt8] = []
sequenceEncoded.append(0x30)
sequenceEncoded.append(contentsOf: lengthField(of: (modulusEncoded + exponentEncoded)))
sequenceEncoded.append(contentsOf: (modulusEncoded + exponentEncoded))
以下是计算上面使用的 DER 类型的长度字段的辅助函数:
func lengthField(of valueField: [UInt8]) -> [UInt8] {
var count = valueField.count
if count < 128 {
return [ UInt8(count) ]
}
// The number of bytes needed to encode count.
let lengthBytesCount = Int((log2(Double(count)) / 8) + 1)
// The first byte in the length field encoding the number of remaining bytes.
let firstLengthFieldByte = UInt8(128 + lengthBytesCount)
var lengthField: [UInt8] = []
for _ in 0..<lengthBytesCount {
// Take the last 8 bits of count.
let lengthByte = UInt8(count & 0xff)
// Add them to the length field.
lengthField.insert(lengthByte, at: 0)
// Delete the last 8 bits of count.
count = count >> 8
}
// Include the first byte.
lengthField.insert(firstLengthFieldByte, at: 0)
return lengthField
}
现在我们终于得到了我们想要的数据。
let keyData = Data(bytes: sequenceEncoded)
您可以使用此数据创建SecKey
.
// RSA key size is the number of bits of the modulus.
let keySize = (modulus.count * 8)
let attributes: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits as String: keySize
]
let publicKey = SecKeyCreateWithData(keyData as CFData, attributes as CFDictionary, nil)
我希望这有帮助!如果您需要更多信息,请告诉我。
更多资源
- Heimdall https://github.com/henrinormak/Heimdall/blob/master/Heimdall/Heimdall.swift
- 何塞·斯威夫特 https://github.com/airsidemobile/JOSESwift