[英]Creating shared secret using public and private keys using swift
我正在嘗試將一個字節序列的ephemeralKey
轉換為一個橢圓曲線公鑰,然后用它來創建一個使用我的私鑰的共享密鑰。
我知道如何在 python(下面的代碼)中執行此操作。 但是我在 Swift 找不到方法。我的 Swift 代碼也在下面復制,但它不正確。 你看到我的 Swift 代碼有問題了嗎?
我的 python 代碼:
from cryptography.hazmat.primitives.asymmetric import ec
privateKey = ec.generate_private_key(ec.SECP256R1())
devicePublicKey = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), ephemeralKey)
sharedKey = privateKey.exchange(ec.ECDH(), devicePublicKey)
我的 Swift 代碼:
let privateKeyParams: [String: Any] = [
kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256
]
var error: Unmanaged<CFError>?
let privateKey = SecKeyCreateRandomKey(privateKeyParams as CFDictionary, &error)
let attributes: [String:Any] =
[
kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
]
let devicePublicKey = SecKeyCreateWithData(ephemeralKey as CFData, attributes as CFDictionary, nil)!
let sharedKey = ecdhSecretCalculation(publicKey: devicePublicKey, privateKey: privateKey)
func ecdhSecretCalculation(publicKey: SecKey, privateKey: SecKey) -> Data? {
var error: Unmanaged<CFError>?
let keyPairAttr:[String : Any] = [
kSecAttrKeySizeInBits as String: 256,
SecKeyKeyExchangeParameter.requestedSize.rawValue as String: 32,
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: false],
kSecPublicKeyAttrs as String:[kSecAttrIsPermanent as String: false]
]
let algorithm:SecKeyAlgorithm = .ecdhKeyExchangeStandardX963SHA256
let shared = SecKeyCopyKeyExchangeResult(privateKey, algorithm, publicKey, keyPairAttr as CFDictionary, &error) as Data?
return shared
}
不同共享密鑰的原因是ecdhKeyExchangeStandardX963SHA256
在發布的 Swift 代碼中應用。 相反,必須應用ecdhKeyExchangeStandard
。
另外,請記住 Swift 代碼中的SecKeyCreateWithData()
期望私鑰是未壓縮的公鑰 ( 0x04|x|y
) 和原始私鑰: 0x04|x|y|private
的串聯,而在Python 代碼只指定了原始私鑰(這只是為了完整性,因為發布的代碼沒有顯示私鑰是如何導入的)。
如果考慮到這一點,則兩個代碼都提供相同的共享秘密。
測試:
Python:
from cryptography.hazmat.primitives.asymmetric import ec
import base64
ephemeralKey = base64.b64decode("BK/Rckcy/PFSkdMCIYg6/CRTk3eSv4VQ2+7sNFQ8TjO1aqK5Wmb+UgjDPQ5cB1QGccATrtmgPDRnPzR5JCMPs/M=")
devicePublicKey = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), ephemeralKey)
privateKeyRaw = base64.b64decode("v5PriRLFXqqILYFZkX2LWEbUQ/y/NCZXD6il5S6KPus=")
privateKey = ec.derive_private_key(int.from_bytes(privateKeyRaw, 'big'), ec.SECP256R1())
sharedKey = privateKey.exchange(ec.ECDH(), devicePublicKey)
print(base64.b64encode(sharedKey)) # 8bOrCLEe1eCciEDbq710xbSXQnKzvSHnVjnXnhpJImE=
Swift:
import Foundation
let keyStringPub = "BK/Rckcy/PFSkdMCIYg6/CRTk3eSv4VQ2+7sNFQ8TjO1aqK5Wmb+UgjDPQ5cB1QGccATrtmgPDRnPzR5JCMPs/M="
let ephemeralKey = Data(base64Encoded: keyStringPub)!
let devicePublicKey = SecKeyCreateWithData(ephemeralKey as CFData, [kSecAttrKeyClass as String: kSecAttrKeyClassPublic, kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeySizeInBits as String: 256] as CFDictionary, nil)!
let keyStringPriv = "BK/Rckcy/PFSkdMCIYg6/CRTk3eSv4VQ2+7sNFQ8TjO1aqK5Wmb+UgjDPQ5cB1QGccATrtmgPDRnPzR5JCMPs/O/k+uJEsVeqogtgVmRfYtYRtRD/L80JlcPqKXlLoo+6w=="
let privateKeyRaw = Data(base64Encoded: keyStringPriv)!
let privateKey = SecKeyCreateWithData(privateKeyRaw as CFData, [kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeySizeInBits as String: 256,] as CFDictionary, nil)!
let sharedKey = ecdhSecretCalculation(publicKey: devicePublicKey, privateKey: privateKey)
let sharedKeyB64 = sharedKey!.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
print(sharedKeyB64) // 8bOrCLEe1eCciEDbq710xbSXQnKzvSHnVjnXnhpJImE=
func ecdhSecretCalculation(publicKey: SecKey, privateKey: SecKey) -> Data? {
var error: Unmanaged<CFError>?
let keyPairAttr:[String : Any] = [
kSecAttrKeySizeInBits as String: 256,
SecKeyKeyExchangeParameter.requestedSize.rawValue as String: 32,
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: false],
kSecPublicKeyAttrs as String:[kSecAttrIsPermanent as String: false]
]
let algorithm:SecKeyAlgorithm = .ecdhKeyExchangeStandard // Fix!
let shared = SecKeyCopyKeyExchangeResult(privateKey, algorithm, publicKey, keyPairAttr as CFDictionary, &error) as Data?
return shared
}
兩種代碼都提供相同的共享秘密。
如果在 Swift 代碼中使用了ecdhKeyExchangeStandardX963SHA256
算法,則共享密鑰會額外使用ANSI-X9.63-KDF進行處理。 Cryptography 庫還提供了這個X963KDF
:
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF
import base64
xkdf = X963KDF(
algorithm=hashes.SHA256(),
length=32,
sharedinfo=None,
)
key = xkdf.derive(sharedKey)
print(base64.b64encode(key)) # ULQCW4bsStNQGg/avnlqaNALpAy2Z42SBZN97Qlnqa0=
對於之后通常使用 KDF 的原因,請參見此處。 請注意,X9.63-KDF 只是一種可能性,還有其他可能性,請參見此處。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.