java - EC 客户端和服务器共享 key 不匹配(可能是由于生成服务器 shs 时客户端公钥格式不正确)

标签 java cryptography elliptic-curve diffie-hellman shared-secret

我正在尝试使用 EC 命名曲线生成共享 key ,并发现客户端与服务器共享 key 不匹配。

Security.addProvider(new org.bouncycaSTLe.jce.provider.BouncyCaSTLeProvider());

//客户端

    KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");  
    ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(ecCurveName);  
    kpg.initialize(ecGenParameterSpec, new SecureRandom());  
    ECPublicKey ephemeralPublicKey = (ECPublicKey) kpg.generateKeyPair().getPublic();  
    ECPrivateKey clientEphemeralPrivateKey =(ECPrivateKey) kpg.generateKeyPair().getPrivate();  

    BigInteger  pointx = ephemeralPublicKey.getW().getAffineX();  
    BigInteger  pointy = ephemeralPublicKey.getW().getAffineY();  
    String eCClientEphemeralPublicKeyString = ("04"+pointx.toString(16)+pointy.toString(16)).toUpperCase();  

    byte[] remoteECCPkBytes = DatatypeConverter.parseBase64Binary(remoteECCPkBase64);  

    KeyFactory keyFactory= KeyFactory.getInstance("EC","BC");  
    X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(remoteECCPkBytes);  
    PublicKey serverECCPublicKey = keyFactory.generatePublic(pkSpec);  

    KeyAgreement ka = KeyAgreement.getInstance("ECDH","BC");  
    ka.init(clientEphemeralPrivateKey);  
    ka.doPhase(serverECCPublicKey, true);  
    SecretKey agreedKey = ka.generateSecret("AES[256]");  
    byte[] sharedSecret  = agreedKey.getEncoded();  

//服务器

    String clientEphemeralPKBase64  = java.util.Base64.getEncoder().encodeToString(new BigInteger(eCClientEphemeralPublicKeyString, 16).toByteArray());  
    byte[] clientECPublicKeybytes = DatatypeConverter.parseBase64Binary(clientEphemeralPKBase64);  



    ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec(ecCurveName);  
    ECCurve curve = ecParameterSpec.getCurve();  
    ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(curve.decodePoint(clientECPublicKeybytes), ecParameterSpec);  
    KeyFactory kf = KeyFactory.getInstance("EC","BC");  
    ECPublicKey ecClientPublicKey = (ECPublicKey)kf.generatePublic(pubKeySpec);  

    PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec( Base64.decodeBase64(serverprivateKeyBase64));  
    PrivateKey ecServerPrivateKey = kf.generatePrivate(privateKeySpec);  


    KeyAgreement ka = KeyAgreement.getInstance("ECDH","BC");  
    ka.init(ecServerPrivateKey);  
    ka.doPhase(ecClientPublicKey, true);  
    SecretKey agreedKey = ka.generateSecret("AES[256]");  
    byte[] sharedSecret  = agreedKey.getEncoded();  

最佳答案

这当然是致命的:

ECPublicKey ephemeralPublicKey = (ECPublicKey) kpg.generateKeyPair().getPublic();  
ECPrivateKey clientEphemeralPrivateKey =(ECPrivateKey) kpg.generateKeyPair().getPrivate();  

如果您两次调用 generateKeyPair,您的公钥和私钥将属于同一对 key 。

您需要创建两对 key ,一对用于服务器,一对用于客户端,然后传递公钥。创建公钥并立即丢弃私钥不可能有用,除非以迂回方式检索域参数。

相反,你应该这样做:

KeyPair clientEphemeralKeyPair = kpg.generateKeyPair();
ECPublicKey clientEphemeralPublicKey = (ECPublicKey) clientEphemeralKeyPair.getPublic();  
ECPrivateKey clientEphemeralPrivateKey = (ECPrivateKey) clientEphemeralKeyPair.getPrivate();  

关于java - EC 客户端和服务器共享 key 不匹配(可能是由于生成服务器 shs 时客户端公钥格式不正确),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49039446/

相关文章:

java - 雅可比坐标下的椭圆曲线点加法

java - 除了 Java 之外,还有哪些语言具有非特权代码与特权代码的安全模型?

密码的 Node.js 散列

windows - 如何使用加密 api 获取颁发者证书公钥

encryption - 实用的解释方式 "Information Theory"

math - 带奇点的 Sage Math 椭圆曲线

c - openssl api 函数引用问题

java web start 与签名文件有关的问题

java - 在 JUnit 测试类中使用随机值

java - 封闭实例无效时的封闭类型行为