如何使用密码学在 Python 中使用 Kotlin PublicKey 对象加载编码的 public 密钥

How to load encoded public key using Kotlin PublicKey object in Python using cryptography

我目前在加载从 Python 中的 Kotlin“提取”的 public 键时遇到问题。我正在尝试在 Kotlin 和 Python 之间创建功能性 X25519 EDH,因此我需要加载 Python 中由 Kotlin 代码创建的 public 密钥。反之亦然。

我的 Kotlin 代码如下所示

class EllipticDiffieHellman {
    private val keyPairGenerator = KeyPairGenerator.getInstance("XDH")
    private val parameters = NamedParameterSpec("X25519")
    private val keyAgreement = KeyAgreement.getInstance("XDH")
    private val keyFactory = KeyFactory.getInstance("XDH")

    fun generateKeyPair() : KeyPair {
        keyPairGenerator.initialize(parameters)
        return keyPairGenerator.generateKeyPair()
    }

    fun getKeyShare(keyPair: KeyPair) : ByteArray = keyPair.public.encoded

    fun bytesToPubKey(keyShare: ByteArray) : PublicKey = keyFactory.generatePublic(X509EncodedKeySpec(keyShare))

    fun getSharedKey(keyPair: KeyPair, keyShare: PublicKey) : ByteArray {
        keyAgreement.init(keyPair.private)
        keyAgreement.doPhase(keyShare, true)
        return keyAgreement.generateSecret()
    }
}

...

    val EDH = EllipticDiffieHellman()
    val keypair_python = EDH.generateKeyPair()
    File("keyshare_kotlin").writeBytes(EDH.getKeyShare(keypair_python))

当我尝试使用 bytesToPubKey 加载相同的 ByteArray 时,一切正常。 现在我的 Python 代码(一部分):

import cryptography.hazmat.primitives.serialization as serialization
with open("keyshare_kotlin", "rb") as f:
    keyshare_kotlin = f.read()
loaded_public_key = serialization.load_der_public_key(keyshare_kotlin)

这行不通。我一直在尝试使用其他 cryptography 的加载函数,但 none 有效。

我得到 ValueError: Could not deserialize key data. The data may be in an incorrect format or it may be encrypted with an unsupported algorithm.

感谢您的帮助。

我找到了一个可行的解决方案,尽管如评论中所述 - 它不是最优的。

Kotlin/Java 生成的字节与 Python 生成的字节使用不同的 header。 Kotlin 的 header 是 14 个字节长,而 Python 的 header 是 12 个字节长。这是编码 public 键的这两个“版本”之间的唯一区别,虽然 Python 能够加载 12 字节 header,但无法加载 Kotlin 的 14 字节 header.

使用从使用密码学 .public_key().public_bytes(serialization.DER, serialization.SubjectPublicKeyInfo) 编码的字节中提取的 header 并用它替换 Kotlin 生成的 header 可以在 Python 中加载编码字节。

import cryptography.hazmat.primitives.asymmetric.x25519 as x25519
import cryptography.hazmat.primitives.serialization as serialization

private_key = x25519.X25519PrivateKey.generate()
public_bytes = private_key.public_bytes(
        encoding=serialization.Encoding.DER,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
)

with open("keyshare_kotlin", "rb") as f:
        keyshare_kotlin = f.read()
loaded_keyshare = serialization.load_der_public_key(public_bytes[:12] + keyshare_kotlin[14:])