如何访问 SecKeyCreateRandomKey() 生成的 public 密钥中的字节?
How to access bytes in public key generated by SecKeyCreateRandomKey()?
我正在尝试使用 AES-GCM 在 iOS 应用程序和 ESP 微控制器之间发送加密消息。但在我这样做之前,我需要在两个设备之间执行密钥交换,以便它们都有一个共享的秘密。因此,我正在研究用于生成 private/public 密钥对的 iOS 方法,并且有多种方法。但是有一个问题,iOS 生成的密钥不能与 iOS 之外的任何东西兼容(据我所知)这意味着我必须跳入并对密钥进行一些修改.我注意到生成的密钥总是 abdc1234
,其中 abcd
永远不会改变,而 1234
每次生成密钥时都会改变。所以我假设 abcd
只是 iOS 使用的东西,而 1234
是实际的关键。至少,这就是 Android 中发生的事情。因此,为了验证我的假设,我试图获取 iOS 中生成的 public 密钥的原始字节,以便我可以切断 abcd
并发送实际密钥 1234
到 ESP。问题是我找不到如何访问密钥包含的字节。到目前为止,这是我尝试过的...
let tag = "".data(using: .utf8)!
let attributes: [String: Any] = [
kSecAttrType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
kSecPrivateKeyAttrs as String: [
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: tag
]
]
let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error)
let publicKey = SecKeyCopyPublicKey(privateKey!)
print("\(publicKey!)")
var address = Unmanaged.passUnretained(publicKey!).toOpaque()
do{
withUnsafeBytes(of: &address) { bytes in
for byte in bytes{
print(byte)
}
}
}
所以第一条打印语句输出如下
<SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPublicKey, version: 4, block size: 256, bits, y: ..., x: ..., addr: 0x...>
到目前为止一切顺利,我想要的关键在我想要的曲线上,关键是正确的长度等等。
但是现在下一个打印输出如下
144
70
215
9
1
0
0
0
就是这样。显然,最后要打印的 8 个东西不是关键,它太短了。是的,我如何提取 public 键的 x 和 y 值。我可以看到它已打印出来,所以必须有一种方法可以访问它,但是是的,我到处都搜索过但没有骰子。我认为我可以 "chop" 关闭生成密钥的 "iOS" 部分的理论甚至可能不正确,但问题是我什至无法在无法将字节发送到 ESP 的情况下对其进行测试。我希望有一种更简单的方法来实现 iOS 应用程序和 ESP 之间的密钥交换,但目前,这是我知道的唯一方法。哦,是的,我通过蓝牙发送密钥字节,我能够通过蓝牙将 iOS 应用程序连接到 ESP,这就是我尝试进行密钥交换的方式。我知道蓝牙在技术上是加密的,但我只想进行密钥交换,然后使用 AES-GCM 进一步加密蓝牙消息。所以,请。如果您知道访问密钥字节的方法,请分享!
更新:
我使用此代码为 ECDH 密钥交换生成密钥对:
let attributes: [String: Any] = [
kSecAttrType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
kSecPrivateKeysAttrs as String: [
kSecAttrIsPermanent as String: true
]
]
var error: Unmanaged<CFError>?
privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error)!
publicKey = SecKeyCopyPublicKey(privateKey!)!
let pubKeyExternRep = SecKeyCopyExternalRepresentation(publicKey!, &error)
print("\(publicKeyExternRep!)")
输出如下:
{length = 65, bytes = 0x048820d8 0482e62f 7abac673 02d8a68e ... 6e0117684
ff455540 }
我试图将 bytes
部分中 0x04
之后的所有内容都放在字符数组中,以便我可以通过蓝牙以一系列数据包的形式发送它。因此,我必须获取 0x04
之后的所有内容,所有 128 个字符,并将其放在一个字节数组中。最后,如果我打印字节数组的内容,它应该只是说 8820d80482e62f ... 6e0117684ff455540
.
我试过以下方法:
//^^^ previous code block that generates the key pair ^^^
let length = CFDataGetLength(pubKeyExternRep!)
let range = CFRange.init(location: 0, length: length)
let uint8Pointer = UnsafeMutablePointer<UInt8>.allocate(capacity:length)
CFDataGetBytes(pubKeyExternRep!, range, uint8Pointer)
print("\(uint8Pointer.pointee)")
这将输出以下内容:
4
这看起来很有希望,因为它匹配密钥的前 4 个 0x04
但随后我通过切换 location: 5
向上移动指针并打印一个随机的两位数匹配任何有用的东西,即 68
或类似的东西。
我也试过这个:
^^^ previous code block that generates the key pair ^^^
let keyData = pubKeyExternRep as Data?
let dataString = keyData?.base64EncodedString()
var byteArray: [UInt8] = []
byteArray = Array(dataString!.utf8)
print("\(byteArray)")
现在这让我非常接近我需要的东西,它是一个字节数组,我可以对其执行操作并连接东西等等,如果我打印它输出:
[66, 79, 76, ..., 119, 81, 61]
问题不仅在于数组的成员不匹配 pubKeyExternRep
中的任何 128 个字节,而且它也比我需要的 128 个字节短。它是 64 个字节。这实际上是我在尝试的两种方法(CFDataGetBytes 方法和 String to Array 方法)中都注意到的,无论我得到什么,它永远不是 128 字节,它总是 64。
当我 print(publicKeyExternRep!)
时,我只需要 0x04
之后的所有 128 个字节
更新 2:
找到解决方案,它不是标记的解决方案,但在技术上确实回答了问题。请问post解决后工作!
只需使用SecKeyCopyExternalRepresentation(_:_:)
。顺便说一句,编码格式不是通常所说的X9.63,它是一个扁平的未压缩public关键点,没有命名曲线的参数。
我正在尝试使用 AES-GCM 在 iOS 应用程序和 ESP 微控制器之间发送加密消息。但在我这样做之前,我需要在两个设备之间执行密钥交换,以便它们都有一个共享的秘密。因此,我正在研究用于生成 private/public 密钥对的 iOS 方法,并且有多种方法。但是有一个问题,iOS 生成的密钥不能与 iOS 之外的任何东西兼容(据我所知)这意味着我必须跳入并对密钥进行一些修改.我注意到生成的密钥总是 abdc1234
,其中 abcd
永远不会改变,而 1234
每次生成密钥时都会改变。所以我假设 abcd
只是 iOS 使用的东西,而 1234
是实际的关键。至少,这就是 Android 中发生的事情。因此,为了验证我的假设,我试图获取 iOS 中生成的 public 密钥的原始字节,以便我可以切断 abcd
并发送实际密钥 1234
到 ESP。问题是我找不到如何访问密钥包含的字节。到目前为止,这是我尝试过的...
let tag = "".data(using: .utf8)!
let attributes: [String: Any] = [
kSecAttrType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
kSecPrivateKeyAttrs as String: [
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: tag
]
]
let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error)
let publicKey = SecKeyCopyPublicKey(privateKey!)
print("\(publicKey!)")
var address = Unmanaged.passUnretained(publicKey!).toOpaque()
do{
withUnsafeBytes(of: &address) { bytes in
for byte in bytes{
print(byte)
}
}
}
所以第一条打印语句输出如下
<SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPublicKey, version: 4, block size: 256, bits, y: ..., x: ..., addr: 0x...>
到目前为止一切顺利,我想要的关键在我想要的曲线上,关键是正确的长度等等。 但是现在下一个打印输出如下
144
70
215
9
1
0
0
0
就是这样。显然,最后要打印的 8 个东西不是关键,它太短了。是的,我如何提取 public 键的 x 和 y 值。我可以看到它已打印出来,所以必须有一种方法可以访问它,但是是的,我到处都搜索过但没有骰子。我认为我可以 "chop" 关闭生成密钥的 "iOS" 部分的理论甚至可能不正确,但问题是我什至无法在无法将字节发送到 ESP 的情况下对其进行测试。我希望有一种更简单的方法来实现 iOS 应用程序和 ESP 之间的密钥交换,但目前,这是我知道的唯一方法。哦,是的,我通过蓝牙发送密钥字节,我能够通过蓝牙将 iOS 应用程序连接到 ESP,这就是我尝试进行密钥交换的方式。我知道蓝牙在技术上是加密的,但我只想进行密钥交换,然后使用 AES-GCM 进一步加密蓝牙消息。所以,请。如果您知道访问密钥字节的方法,请分享!
更新:
我使用此代码为 ECDH 密钥交换生成密钥对:
let attributes: [String: Any] = [
kSecAttrType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
kSecPrivateKeysAttrs as String: [
kSecAttrIsPermanent as String: true
]
]
var error: Unmanaged<CFError>?
privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error)!
publicKey = SecKeyCopyPublicKey(privateKey!)!
let pubKeyExternRep = SecKeyCopyExternalRepresentation(publicKey!, &error)
print("\(publicKeyExternRep!)")
输出如下:
{length = 65, bytes = 0x048820d8 0482e62f 7abac673 02d8a68e ... 6e0117684
ff455540 }
我试图将 bytes
部分中 0x04
之后的所有内容都放在字符数组中,以便我可以通过蓝牙以一系列数据包的形式发送它。因此,我必须获取 0x04
之后的所有内容,所有 128 个字符,并将其放在一个字节数组中。最后,如果我打印字节数组的内容,它应该只是说 8820d80482e62f ... 6e0117684ff455540
.
我试过以下方法:
//^^^ previous code block that generates the key pair ^^^
let length = CFDataGetLength(pubKeyExternRep!)
let range = CFRange.init(location: 0, length: length)
let uint8Pointer = UnsafeMutablePointer<UInt8>.allocate(capacity:length)
CFDataGetBytes(pubKeyExternRep!, range, uint8Pointer)
print("\(uint8Pointer.pointee)")
这将输出以下内容:
4
这看起来很有希望,因为它匹配密钥的前 4 个 0x04
但随后我通过切换 location: 5
向上移动指针并打印一个随机的两位数匹配任何有用的东西,即 68
或类似的东西。
我也试过这个:
^^^ previous code block that generates the key pair ^^^
let keyData = pubKeyExternRep as Data?
let dataString = keyData?.base64EncodedString()
var byteArray: [UInt8] = []
byteArray = Array(dataString!.utf8)
print("\(byteArray)")
现在这让我非常接近我需要的东西,它是一个字节数组,我可以对其执行操作并连接东西等等,如果我打印它输出:
[66, 79, 76, ..., 119, 81, 61]
问题不仅在于数组的成员不匹配 pubKeyExternRep
中的任何 128 个字节,而且它也比我需要的 128 个字节短。它是 64 个字节。这实际上是我在尝试的两种方法(CFDataGetBytes 方法和 String to Array 方法)中都注意到的,无论我得到什么,它永远不是 128 字节,它总是 64。
当我 print(publicKeyExternRep!)
0x04
之后的所有 128 个字节
更新 2: 找到解决方案,它不是标记的解决方案,但在技术上确实回答了问题。请问post解决后工作!
只需使用SecKeyCopyExternalRepresentation(_:_:)
。顺便说一句,编码格式不是通常所说的X9.63,它是一个扁平的未压缩public关键点,没有命名曲线的参数。