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

问题描述

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

我的 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 的加载函数,但都不起作用。

我收到了 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 生成的字节使用不同的标头。 Kotlin 的标头长度为 14 个字节,而 Python 的标头长度为 12 个字节。这是编码公钥的这两个“版本”之间的唯一区别,虽然 Python 能够加载 12 字节的标头,但无法加载 Kotlin 的 14 字节标头。

使用从使用密码学的 .public_key().public_bytes(serialization.DER,serialization.SubjectPublicKeyInfo) 编码的字节中提取的标头并用它替换 Kotlin 生成的标头,可以在 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:])