【问题标题】:Diffie-Hellman algorithm between C# and JavaC# 和 Java 之间的 Diffie-Hellman 算法
【发布时间】:2021-02-26 21:16:30
【问题描述】:

我有 c# 和 Java 的控制台应用程序。它们都为椭圆曲线 Diffie-Hellman 算法生成公钥和私钥。公钥在 base64 中加密,然后在控制台中打印。然后我将 c# 中的公钥粘贴到 java 程序中,反之亦然。 不幸的是,最终派生的密钥必须相同。似乎算法的配置相同,没有例外。
C#:

static void Main(string[] args)
        {
            ECDiffieHellmanCng eCDiffie = new ECDiffieHellmanCng(256);
            eCDiffie.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
            eCDiffie.HashAlgorithm = CngAlgorithm.Sha256;



            byte[] myPublicKey = eCDiffie.ExportSubjectPublicKeyInfo();   //export in x509 format
            String myPublicKeyBase64 = Convert.ToBase64String(myPublicKey);
            Console.WriteLine(myPublicKeyBase64);



            string otherKey = Console.ReadLine();  // here paste public key in console from Java
            byte[] otherKeyFromBase64 = Convert.FromBase64String(otherKey);
            ECDiffieHellmanCng eCDiffie2 = new ECDiffieHellmanCng(256);
            eCDiffie2.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
            eCDiffie2.HashAlgorithm = CngAlgorithm.Sha256;
            int some = 0;
            eCDiffie2.ImportSubjectPublicKeyInfo(otherKeyFromBase64, out some);


            byte[] otherKeyDecoded = eCDiffie2.PublicKey.ToByteArray();
            CngKey k = CngKey.Import(otherKeyDecoded, CngKeyBlobFormat.EccPublicBlob);
            byte[] derivedKey = eCDiffie.DeriveKeyMaterial(k);
            String derivedKeyBase64 = Convert.ToBase64String(derivedKey);



            Console.WriteLine("Derived key: ");
            Console.WriteLine(derivedKeyBase64);
        }

Java:

public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
        // Generate ephemeral ECDH keypair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
        kpg.initialize(256);
        KeyPair kp = kpg.generateKeyPair();
        byte[] ourPk = kp.getPublic().getEncoded();  //public key in x509 format

        // Display our public key
        byte[] ourPublicKeyBase64 = Base64.getEncoder().encode(ourPk);
        System.out.println(String.format("Public Key: %s", new String(ourPublicKeyBase64)));

        // Read other's public key:
        Scanner in = new Scanner(System.in);
        String oth = in.nextLine();   // here paste in console public key C#
        byte[] otherPk = Base64.getDecoder().decode(oth);


        KeyFactory kf = KeyFactory.getInstance("EC");
        X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
        PublicKey otherPublicKey = kf.generatePublic(pkSpec);

        // Perform key agreement
        KeyAgreement ka = KeyAgreement.getInstance("ECDH");
        ka.init(kp.getPrivate());
        ka.doPhase(otherPublicKey, true);
        // Read shared secret
        byte[] sharedSecret = ka.generateSecret();



        // Derive a key from the shared secret and both public keys
        MessageDigest hash = MessageDigest.getInstance("SHA-256");
        hash.update(sharedSecret);
        // Simple deterministic ordering
        List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
        Collections.sort(keys);
        hash.update(keys.get(0));
        hash.update(keys.get(1));

        byte[] derivedKey = hash.digest();
        byte[] derivedKeyBase64 = Base64.getEncoder().encode(derivedKey);
        System.out.println(String.format("Derived key: %s", new String(derivedKeyBase64)));
    }

【问题讨论】:

    标签: java c# diffie-hellman


    【解决方案1】:

    您的Java 代码做了一些额外的工作来获取派生密钥。只需删除以下行,您将获得与 С# 代码中相同的密钥:

    // Simple deterministic ordering
    List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
    Collections.sort(keys);
    hash.update(keys.get(0));
    hash.update(keys.get(1));
    

    这是完整的Java 代码:

    public static void main(String[] args) throws Exception {
        // Generate ephemeral ECDH keypair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
        kpg.initialize(256);
        KeyPair kp = kpg.generateKeyPair();
        byte[] ourPk = kp.getPublic().getEncoded();  //public key in x509 format
    
        // Display our public key
        byte[] ourPublicKeyBase64 = Base64.getEncoder().encode(ourPk);
        System.out.println(String.format("Public Key: %s", new String(ourPublicKeyBase64)));
    
        // Read other's public key:
        Scanner in = new Scanner(System.in);
        String oth = in.nextLine();   // here paste in console public key C#
        byte[] otherPk = Base64.getDecoder().decode(oth);
    
        KeyFactory kf = KeyFactory.getInstance("EC");
        X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
        PublicKey otherPublicKey = kf.generatePublic(pkSpec);
    
        // Perform key agreement
        KeyAgreement ka = KeyAgreement.getInstance("ECDH");
        ka.init(kp.getPrivate());
        ka.doPhase(otherPublicKey, true);
        
        // Read shared secret
        byte[] sharedSecret = ka.generateSecret();
    
        // Derive a key from the shared secret
        MessageDigest hash = MessageDigest.getInstance("SHA-256");
        hash.update(sharedSecret);        
    
        byte[] derivedKey = hash.digest();
        byte[] derivedKeyBase64 = Base64.getEncoder().encode(derivedKey);
        System.out.println(String.format("Derived key: %s", new String(derivedKeyBase64)));
    }
    

    【讨论】:

    • 有趣的问题。不幸的是,我不知道答案。但是我可以假设两个代码都是正确的,但是Java 计算derived key(从两个公钥)的方法可以避免一些微妙的漏洞。跨度>
    • 我在几个开源项目中遇到过类似的 Java 代码。以下是RFC 的摘录:Designers using these curves should be aware that for each public key, there are several publicly computable public keys that are equivalent to it, i.e., they produce the same shared secrets. Thus using a public key as an identifier and knowledge of a shared secret as roof of ownership (without including the public keys in the key derivation) might lead to subtle vulnerabilities.
    猜你喜欢
    • 2021-08-07
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 1970-01-01
    • 2011-10-18
    相关资源
    最近更新 更多