曲线 25519 对称密钥 Python

Curve 25519 Symmetric Key with Python

我正在使用 Apple 的 CryptoKit 为 iOS 应用程序创建密钥,加密数据,然后通过 JSON 将其发送到后端并将其存储在 PGSQL 数据库中。

虽然所有这些都运行良好,但我需要能够从后端解密数据,因此需要能够创建用于加密数据的相同对称密钥。

当我通过 Swift 创建密钥时,它是按如下方式完成的:

let privateKey = Curve25519.KeyAgreement.PrivateKey()
let publicKey = privateKey.publicKey
let sharedSecret = try! privateKey.sharedSecretFromKeyAgreement(with: publicKey)
let symmetricKey = sharedSecret.hkdfDerivedSymmetricKey(using: SHA512.self,
    salt: "\(vhvioerhvoreovjreoivgifjtughrygryrufejewdf))".data(using: .utf8)!,
    sharedInfo: Data(),
    outputByteCount: 32)

注意:盐只是我为这个示例代码输入了一堆随机字符,但你明白了。

我需要使用 Python 完成同样的事情。这些键也是通过 JSON 发送到后端的 base64 编码字符串,因此我需要对它们进行 b64 解码(我已经开始工作了)。

我尝试使用 pynacl,但我不知道如何使用 sha512 和我在 Swift 中用于创建对称密钥的相同盐来创建对称密钥。如果有更好的选择,我也绝不依赖 pynacl。

同样,上述代码只是用于在 Swift 中创建私钥、public 和对称密钥的过程示例。我实际上是在使用一个帐户的 public 密钥和另一个帐户的私钥来创建对称密钥并加密数据。我将反向解密(即来自私钥帐户的 public 密钥,以及来自 public 密钥帐户的私钥)。

到目前为止,在 python 中使用它我有以下内容(但同样,如果有更好的解决方案,我不会依赖 pynacl):

from nacl.public import Box, PrivateKey, PublicKey, SealedBox
from nacl.hash import sha512
import nacl.encoding
from base64 import b64decode, b64encode
import binascii

privKeyRead = b64decode('uBruInrnbtrberverv6XZZqQDDeS4SwORSHriW04=')
private_key = PrivateKey(privKeyRead)

pubKeyRead = b64decode('UIZSc3QBfewojfoewjgowjgCqA/P8PjXDlQwU7rTHFBw=')
public_key = PublicKey(pubKeyRead)

salt = b64decode('HIHIUGUBLJOIHIBIOHO9nM0NSSkNDejUwcXJMNUdlUT0=')

cryptoBox = Box(private_key, public_key)
sharedSecret = Box.shared_key(cryptoBox)

# Print Keys and Salt
print("Private Key:", privKeyRead)
print("Public Key:", pubKeyRead)
print("Salt:", salt)
print("Crypto Box:", cryptoBox)
print("Shared Secret:", sharedSecret)

return printed

注意:本例中的 privKeyRead、pubKeyRead 和 salt 值有垃圾字符,因为我显然不能 post 真实值。我还注意到 Crypto Box 和 Shared Secret 是相同的,所以我很确定我只需要一个而不是两个。

最后,我不想让任何人在这上面挂断电话,我正在使用 Zope5,这就是为什么您会看到我的 python 示例的原因。这是 zope 中的 python 脚本,完全有效。我还可以创建外部方法,因此如果您有函数等可以更好地工作,请随时 post 确切地了解在等式中不包含 zope 的情况下您将如何做。如有必要,我会重新配置 zope。

Swift代码生成私钥,确定相关public密钥,使用X25519导出共享密钥,使用HKDF导出对称密钥:

import Foundation
import Crypto

let privateKey = Curve25519.KeyAgreement.PrivateKey()
let publicKey = privateKey.publicKey
let sharedSecret = try! privateKey.sharedSecretFromKeyAgreement(with: publicKey)
let symmetricKey = sharedSecret.hkdfDerivedSymmetricKey(using: SHA512.self,
    salt: "a test salt".data(using: .utf8)!,
    sharedInfo: Data(),
    outputByteCount: 32)
print("Private key  : ", privateKey.rawRepresentation.base64EncodedString())
print("Public key   : ", publicKey.rawRepresentation.base64EncodedString())
print("Shared secret: ", sharedSecret.withUnsafeBytes {return Data(Array([=10=])).base64EncodedString()})
print("Symmetric key: ", symmetricKey.withUnsafeBytes {return Data(Array([=10=])).base64EncodedString()})

可能的输出是:

Private key  :  8AtqpW6UJBhAEzTnvHMQ8ki28TrDvAEbKuV3FDiROWw=
Public key   :  kICzRWQYcawmlVJpSJ2TINuUDmI0xGm2BnH10qHVxxs=
Shared secret:  ijACBaZfaCQuvwwILb5uncYroZ4MLBzOfNZLD5khjz4=
Symmetric key:  Il570rzDZ9brWBtxUtWv/Hv29rN6pBls7/AtOK+2oPU=

要在 Python 中实现,需要一个支持 X25519 和 HKDF 的库,例如Cryptography(与 PyNaCl 相比,Cryptography 似乎是更好的选择,因为后者不支持 HKDF):

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
import base64

# X25519
private_key = X25519PrivateKey.generate()
public_key = private_key.public_key()
shared_secret = private_key.exchange(public_key)

# HKDF
symmetric_key = HKDF(
    algorithm=hashes.SHA512(),
    length=32,
    salt='a test salt'.encode('utf-8'),
    info=b'',
).derive(shared_secret)

print(base64.b64encode(shared_secret))
print(base64.b64encode(symmetric_key))

测试:
测试用Swift代码的keys,可以这样导入:

from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
...
private_key = X25519PrivateKey.from_private_bytes(base64.b64decode("8AtqpW6UJBhAEzTnvHMQ8ki28TrDvAEbKuV3FDiROWw="))
public_key = X25519PublicKey.from_public_bytes(base64.b64decode("kICzRWQYcawmlVJpSJ2TINuUDmI0xGm2BnH10qHVxxs="))

有了这个,Python 代码提供了 Swift 代码的共享秘密和密钥。