【ECDH java后端和javaScript前后端互通实现】

ECDH java后端和javaScript前后端互通实现

问题背景

web前端和后端之间的通信不一定可靠,如果不方便使用预共享密钥的方式完成身份的确认,那么可以使用ECDH密钥协商算法在前端和后端进行密钥间的协商。

ECDH算法

Elliptic-curve Diffie-Hellman(ECDH)是一种通过两方达成密钥协商的密钥生成算法,每一方都有一个椭圆双曲线的公私钥对,双方在不安全的通信通道间传递信息达成密钥生成协议。生成的密钥会被直接作为一个密钥或者是生成其他密钥的种子。最终生成的密钥将被对称密码学算法例如AESGCM作为密钥使用。
接下来的例子阐述了共享密钥是如何产生的:
Alice想和Bob建立一个共享密钥,但是唯一能够传递消息的通道被第三方监听。在初始时刻,Alice和Bob共享了些域的参数(p a,b,G,n,h),Alice在整数范围[t,n-1]中随机选择一个私钥d,并通过计算(Q=d·G)具体计算方式,得到了公钥Q,公私钥对为( d A d_A dA, Q A Q_A QA)。Bob用同样的计算方式得到了( d B d_B dB, Q B Q_B QB)。双方将自己的公钥发送给对方,分别计算:
( x k x_k xk, y k y_k yk)= d A d_A dA· Q B Q_B QB
( x k x_k xk, y k y_k yk)= d B d_B dB· Q A Q_A QA
( x k x_k xk, y k y_k yk)即为所得的私钥。
Alice仅仅公开了她的公钥信息,任何参与方想要计算出Alice的公钥需要解决椭圆曲线离散对数问题(这很难被计算出来)。因此我们认为Alice和Bob通过这样的方法协商密钥是安全的。除了Alice和Bob,没有谁能计算出他们协商的密钥。
在众多ECDH算法的计算标准中,Curve25519是使用最为广泛的密钥生成算法。

Java 实现

public class EcdhKeyPair{
private String privatekey;
private String publicKey;
public String getprivatekey(){
    return privatekey;
}
public String getPublicKey(){
    return publickey;
}
public class Ecdhservice{
private static final int ECDH_KEY_LEN= 32;

private static final int SHARED_KEY_LEN= 16;

private byte[] privatekey;

private byte[] publicKey;

private BigInteger pInteger;

private EcdhKeyPair ecdhKeyPair;

private static final SecureRandom RANDOM_GENERATOR;
static {
   try {
        RANDOM_GENERATOR = SecureRandom.getInstancestrong();
   } catch(NoSuchAlgorithmException e){
        log.error("SecureRandom init failed. ECDH encryption would be unavailable.");
EcdhService.");
        throw new InnerException(INTERNAL_ERROR, "Failed to init ECDHService.");
        }
   }
   private void generatetckeyPair() {
       privatekey = new byte[ECDH KEY_LEN];
       publicKey= new byte [ECDH KEY LEN];
       X25519.generatePrivateKey(RANDOM_GENERATOR, privateKey);
       X25519.generatePublickey(privatekey, 0, publicKey, 0);
   }
   private byte[] establisSharedKey(byte[] clientPublicKey){
       if (clientPublicKey.length != 32 ) {
          throw new InnerExecption(INVALID_REQUEST, "Client ECDH public key should be 256 bits/32 bytes");
       }
       BigInteger cInteger = new Biginteger(clientpublickey);
       if (cInteger.equals(BigInteger ZERO) || cInteger.equals(BigInteger.ONE) || cInteger.equals(pInteger)|| cInteger.equals(pInteger.subtract(BigInteges.ONE))){
          throw new InnerException(INVALID_REQUEST, "Client ECDH public key Cannot be specific value.");
         }
         try {
         byte[] agreement = new byte[ECDH_KEY_LEN];
         try {
           X25519.calculateAgreement(getprivatekey(), 0,clientPublickey,0, agreement, 0);
          }catch (RuntimetException e) {
            throw new InnerException(INVALID_REQUEST,
"Cannot calculate the agreement with client key, please check the request parameters.");
          }
          MessageDigest digester = MessageDigest.getInstance("SHA-256");
          return Arrays.copy0fRange(digester.digest(agreement),0, SHARED_KEY_LEN);
    } catch (NoSuchAIgorithmException e) {
         throw new InnerException(INTERNAL_ERROR,
"Failed to calculate shared key. " + e.getLocalizedMessage());
   }
}

前端JavaScript 实现

注意: 此处JavaScript代码没有将生成的sharedKey进行SHA256处理。

import { sharedkey, generateKeypair } from "curve25519-js"
* @description 生成公钥秘钥
* @param {Uint8Array} backPublickeyBase64 后端base64加密的的公钥
* @return 共享秘key:Uint&Arnay privatekey 私钥
*
export function generatekey(backPublicKeyBase64: string){
// 获取后端的公钥进行base64转成Uint8Array
const backPublickey=base64ToUint8Array(backPublicKeyBase64)
//符合密码学要求的安全的随机值 Uint8Array 32字节 8位无符号整型数组
const randomBytes = window.crypto.getRandomValues(new Uint8Array(32))
// 前端使用generatekeyPair得到自己的公钥和私钥,用自己前端的公钥去交换后端的公钥
const keyPair = generateKeyPair(randomBytes)
//将生成的公钥通过base64 加密发给后台
const publicKey =uint8arrayToBase64(keyPair.public)
// 根据后端的公钥用前端的松铜和后端的公钥生成前端的sharekey 
const sharekey = sharedkey(keypair.private, backPublicKey)
return {
  publicKey,
  shareKey
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是 Java 实现 ECDH 算法的示例代码: ```java import java.security.*; import java.security.spec.*; import javax.crypto.*; import javax.crypto.spec.*; public class ECDHDemo { public static void main(String[] args) throws Exception { // 创建椭圆曲线密钥对生成器 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); // 使用 secp256r1 椭圆曲线 kpg.initialize(new ECGenParameterSpec("secp256r1")); // 生成密钥对 KeyPair kp1 = kpg.generateKeyPair(); KeyPair kp2 = kpg.generateKeyPair(); // 获取公钥和私钥 PublicKey pubKey1 = kp1.getPublic(); PrivateKey priKey1 = kp1.getPrivate(); PublicKey pubKey2 = kp2.getPublic(); PrivateKey priKey2 = kp2.getPrivate(); // ECDH 密钥协商 KeyAgreement ka1 = KeyAgreement.getInstance("ECDH"); ka1.init(priKey1); ka1.doPhase(pubKey2, true); byte[] secret1 = ka1.generateSecret(); KeyAgreement ka2 = KeyAgreement.getInstance("ECDH"); ka2.init(priKey2); ka2.doPhase(pubKey1, true); byte[] secret2 = ka2.generateSecret(); // 验证协商的密钥是否相同 if (MessageDigest.isEqual(secret1, secret2)) { System.out.println("ECDH 密钥协商成功!"); } else { System.out.println("ECDH 密钥协商失败!"); } } } ``` 在上面的示例代码中,我们使用 `secp256r1` 椭圆曲线生成密钥对,并使用 ECDH 算法进行密钥协商。具体步骤如下: 1. 通过 `KeyPairGenerator` 生成密钥对。 2. 获取公钥和私钥。 3. 创建 `KeyAgreement` 实例,初始化为自己的私钥。 4. 使用 `doPhase` 方法将对方的公钥作为输入,并执行密钥协商。 5. 使用 `generateSecret` 方法生成协商的密钥。 6. 验证双方协商的密钥是否相同,如果相同则密钥协商成功。 值得注意的是,ECDH 密钥协商只能协商出一个共享密钥,而且这个共享密钥不是公钥或私钥,它只能用于对称加密。因此,在实际应用中,我们通常需要使用协商出的共享密钥来加密通信内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值