EC 客户端和服务器共享密钥不匹配(可能是由于生成服务器 shs 时客户端公钥格式不正确)
EC Client and Server shared secret mismatch ( could be due to client pub key not in correct format while generating server shs)
我正在尝试使用 EC 命名曲线生成共享密钥并发现客户端与服务器共享密钥不匹配。
Security.addProvider(新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
两次,您的 public 和私钥将 不会 成为同一密钥对的一部分。
您需要创建两对密钥,一对用于服务器,一对用于客户端,然后传送 public 密钥。创建 public 密钥并立即丢弃私钥 不能 有用,除了以迂回的方式检索域参数。
你应该这样做:
KeyPair clientEphemeralKeyPair = kpg.generateKeyPair();
ECPublicKey clientEphemeralPublicKey = (ECPublicKey) clientEphemeralKeyPair.getPublic();
ECPrivateKey clientEphemeralPrivateKey = (ECPrivateKey) clientEphemeralKeyPair.getPrivate();
我正在尝试使用 EC 命名曲线生成共享密钥并发现客户端与服务器共享密钥不匹配。
Security.addProvider(新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
两次,您的 public 和私钥将 不会 成为同一密钥对的一部分。
您需要创建两对密钥,一对用于服务器,一对用于客户端,然后传送 public 密钥。创建 public 密钥并立即丢弃私钥 不能 有用,除了以迂回的方式检索域参数。
你应该这样做:
KeyPair clientEphemeralKeyPair = kpg.generateKeyPair();
ECPublicKey clientEphemeralPublicKey = (ECPublicKey) clientEphemeralKeyPair.getPublic();
ECPrivateKey clientEphemeralPrivateKey = (ECPrivateKey) clientEphemeralKeyPair.getPrivate();