如何从公钥派生共享密钥?secp256k1算法实现解析
应用密钥派生逻辑分析与解释
已知密钥信息
- 服务器返回的Base64公钥:
BEdGgIH9PLFU2BcF41Uqvn38inO3bBHbUwKcAIJRBAnf+hfiZo4hWogn8eqVHBCzjdtxmzieFEuRpqi8NRlWH6o= - 转换后的Hex格式公钥:
0447468081fd3cb154d81705e3552abe7dfc8a73b76c11db53029c0082510409dffa17e2668e215a8827f1ea951c10b38ddb719b389e144b91a6a8bc3519561faa - 派生得到的共享密钥:
7e2f725debc83adafe237b95ed5cf1c9a8b16e25b83848049ecbd4a85b38f000
核心JavaScript代码实现
let a = '0447468081fd3cb154d81705e3552abe7dfc8a73b76c11db53029c0082510409dffa17e2668e215a8827f1ea951c10b38ddb719b389e144b91a6a8bc3519561faa'; n = d.keyFromPublic(a, "hex"); s = e.derive(n.getPublic()); r = s.toString(16); //after run this code r is 7e2f725debc83adafe237b95ed5cf1c9a8b16e25b83848049ecbd4a85b38f000 now r is a hex and use for AES.
代码执行逻辑拆解
- 加载公钥:第一行将转换后的Hex格式公钥赋值给变量
a,开头的04标识这是secp256k1椭圆曲线的未压缩格式公钥,后续字符串是公钥x、y坐标的十六进制拼接值。 - 初始化公钥对象:
d.keyFromPublic(a, "hex")调用密码学库(如elliptic)的方法,把十六进制公钥解析为secp256k1对应的公钥对象n。 - 执行密钥派生:
e.derive(n.getPublic())是核心步骤——e是应用本地生成的secp256k1私钥对象,调用私钥的derive方法传入服务器公钥,通过ECDH(椭圆曲线迪菲-赫尔曼)密钥交换算法计算出共享密钥s。 - 格式转换为Hex:
s.toString(16)将二进制共享密钥转换为十六进制字符串r,这个字符串直接作为AES加密的密钥使用。
从公钥到共享密钥的派生过程
整个流程基于ECDH协议结合secp256k1椭圆曲线实现:
- 公钥格式转换:服务器返回的Base64公钥先解码为二进制,再转换为Hex格式(即代码中的
a),这个Hex串是secp256k1的未压缩公钥,包含椭圆曲线上的x、y坐标。 - 本地私钥生成:应用在本地会生成临时的secp256k1私钥(代码中
e就是该私钥对象,生成逻辑未显式写出,但这是ECDH的必要前提)。 - ECDH密钥计算:用本地私钥对服务器公钥对应的椭圆曲线点执行标量乘法运算,得到一个新的椭圆曲线点,取该点的x坐标作为共享密钥的原始值。
- 格式转换:将原始共享密钥转换为十六进制字符串,得到最终用于AES加密的密钥。
内容的提问来源于stack exchange,提问作者Majid Rezaei
相关产品推荐
相关产品推荐

