首页 > 解决方案 > PHP 服务器和 .NET 客户端之间的 Diffie Hellman 身份验证

问题描述

我的桌面软件是用 C# 编写的,托管我的 API 的服务器是用 PHP 编写的。我正在尝试实现 Diffie-Hellman 密钥共享,以便我们可以生成共享秘密并安全地加密客户端和服务器之间的通信。

我可以在两端生成公钥和私钥,但我不确定在从客户端到服务器的过程中以什么格式发送密钥。在 C# 中创建我的密钥的代码:

    class DiffieHellman
    {
        private Aes aes = null;
        private ECDiffieHellmanCng diffieHellman = null;
        private readonly byte[] publicKey;
        private string pkce;
        private static readonly HttpClient client = new HttpClient();

        public DiffieHellman()
        {
            this.aes = new AesCryptoServiceProvider();
            this.diffieHellman = new ECDiffieHellmanCng()
            {
                KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash,
                HashAlgorithm = CngAlgorithm.Sha256,
            };

            this.publicKey = this.diffieHellman.PublicKey.ToByteArray();
        }


        public async Task sendKey()
        {

            byte[] key = this.publicKey;
            string base64EncodedKey = Convert.ToBase64String(key);
            var values = new Dictionary<string, string>
            {
                { "key", base64EncodedKey }
            };

            var content = new FormUrlEncodedContent(values);

            var response = await client.PostAsync("API_URL", content);

            var responseString = await response.Content.ReadAsStringAsync();


        }

    }

这里的问题是密钥被格式化为字节数组,所以在我的 PHP 服务器上对其进行 base64 解码后,我无法读取密钥并生成共享密钥。我也尝试将字节数组转换为十六进制并以这种方式发送。PHP 使用 elliptic-php 库:

        $ec = new EC('curve25519');
        $senderPublicKey = $_POST["key"];

        // Generate keys
        $testKey1 = $ec->genKeyPair();
        $testKey2 = $ec->genKeyPair();

        //Generate shared key with testKey2 to verify library can generate common secret
        $shared1 = $testKey1->derive($testKey2->getPublic()); 
        echo $shared1->toString(16); //5986d466388b3b0e25cd8270659d81efe6d0696b1a8d983241a6d8da543203fb

        //Generate shared key with the public key sent by the client
        $shared2 = $testKey2->derive($senderPublicKey);  
        echo $shared2->toString(16); //nothing is echoed

我知道它们在 C# 中生成的密钥属于 BCRYPT_ECCPUBLIC_BLOB 结构,但我如何将其转换为 PHP 可读格式?

标签: c#php.netencryptiondiffie-hellman

解决方案


尝试将字节数组作为 JSON 发送到您的 API,对其进行反序列化并将其提供给BigNumber构造函数:

$senderPublicKeyByteArray = json_decode($_POST['key']);   // [10, 42, 9, ...] byte array
$senderPublicKey = new BN($senderPublicKeyByteArray);

推荐阅读