You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修复Lua版ECDH密钥交换,使其与Go、NodeJS结果一致

修复Lua版ECDH共享密钥不匹配问题

问题概述

Go与NodeJS实现的P256(prime256v1)椭圆曲线密钥交换(ECDH)生成的共享密钥结果一致,但Lua版本输出不匹配,需调整Lua代码使其输出相同结果。

参考实现代码

Go实现

package main

import (
    "crypto/ecdh"
    "encoding/base64"
    "log"
    "os"

    "github.com/joho/godotenv"
)

func main() {
    _ = godotenv.Load()

    aDecodedPrivateKey, _ := base64.StdEncoding.DecodeString(os.Getenv("A_PRIVATE_KEY"))
    bDecodedPrivateKey, _ := base64.StdEncoding.DecodeString(os.Getenv("B_PRIVATE_KEY"))

    aPrivateKey, _ := ecdh.P256().NewPrivateKey(aDecodedPrivateKey)
    bPrivateKey, _ := ecdh.P256().NewPrivateKey(bDecodedPrivateKey)

    sharedSecret, _ := aPrivateKey.ECDH(bPrivateKey.PublicKey())

    log.Println(base64.StdEncoding.EncodeToString(sharedSecret))
}

NodeJS实现

require('dotenv').config()

import { createECDH } from 'crypto'

const aKey = createECDH('prime256v1')
const bKey = createECDH('prime256v1')

aKey.setPrivateKey(Buffer.from(String(process.env.A_PRIVATE_KEY), 'base64'))
bKey.setPrivateKey(Buffer.from(String(process.env.B_PRIVATE_KEY), 'base64'))

console.log(aKey.computeSecret(bKey.getPublicKey()).toString('base64'))

原Lua实现问题分析

原Lua代码存在两处关键问题:

  1. 私钥BN对象创建格式错误:使用openssl_bn.new(a_decoded_key, 2)时,参数2表示解析0/1组成的二进制文本字符串,但实际a_decoded_key是base64解码后的原始字节流,格式不匹配导致私钥加载错误。
  2. 公钥处理冗余:将私钥对象转为PEM格式后再重新解析为公钥对象,虽不直接导致错误,但增加不必要的开销。

修改后的Lua实现代码

local openssl_pkey = require "resty.openssl.pkey"
local openssl_bn = require "resty.openssl.bn"
local ngx = require "ngx"

local function ecdh()
  -- 解码base64格式的私钥(需确保a_private_key、b_private_key已从环境变量加载)
  local a_decoded_key = ngx.decode_base64(a_private_key)
  local b_decoded_key = ngx.decode_base64(b_private_key)
  
  -- 从原始二进制字节创建BN私钥对象,指定"binary"格式
  local a_bn = openssl_bn.new(a_decoded_key, "binary")
  local b_bn = openssl_bn.new(b_decoded_key, "binary")

  -- 初始化EC私钥
  local a_key = openssl_pkey.new({
    type = "EC",
    params = {
      private = a_bn,
      group = "prime256v1"
    }
  })
  local b_key = openssl_pkey.new({
    type = "EC",
    params = {
      private = b_bn,
      group = "prime256v1"
    }
  })
  
  -- 直接从私钥对象获取公钥,避免PEM转换开销
  local b_public_key = b_key:public_key()

  -- 派生共享密钥,返回结果为原始32字节x坐标,与Go/NodeJS一致
  local shared_secret = a_key:derive(b_public_key)
  
  return ngx.encode_base64(shared_secret)
end

环境变量配置

A_PRIVATE_KEY="w2UwuwmF9h5p02fnr3MkxtKoDTl8aTtJXqLbsPwbqPg="
B_PRIVATE_KEY="ZyoPMal0TZzNwDyUUE30iThXCKgPOthPaIN2qnOhkNs="

测试环境

  • Go 1.23.4
  • NodeJS v22.12.0
  • Lua 5.1

内容的提问来源于stack exchange,提问作者user29212913

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 00:50:55