node.jstypescriptgoluaecdh

ECDH Exchange in Go, NodeJS, and Lua


Go and NodeJS produced the same result, but not Lua. I want Lua to produce the same one.

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))
}
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'))
local openssl_pkey = require "resty.openssl.pkey"
local openssl_bn = require "resty.openssl.bn"
local ngx = require "ngx"

local function ecdh()
  local a_decoded_key = ngx.decode_base64(a_private_key)
  local b_decoded_key = ngx.decode_base64(b_private_key)
  local a_bn = openssl_bn.new(a_decoded_key, 2)
  local b_bn = openssl_bn.new(b_decoded_key, 2)

  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"
    }
  })
  local b_public_key = openssl_pkey.new(b_key:to_PEM('public'))

  return ngx.encode_base64(a_key:derive(b_public_key))
end

Please help me create the Lua version that produces the same result as Go and NodeJS.

In case you need environment variables, take this .env.

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

Here is my testing environment.

References that might help.

Thank you in advance.


Solution

  • Oh, I just knew the problem. In Lua, we can not create keys from this source.

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

    So, these syntaxes are wrong.

    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"
      }
    })
    

    These AI-suggested syntaxes are also wrong.

    local a_key = openssl_pkey.new({
      type = "X25519",
      curve = "prime256v1",
      private_key = a_decoded_key,
    })
    

    We need to convert the source to the PEM keys first. So, the correct source would be like this.

    A_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_CONTENT_HERE\n-----END PRIVATE KEY-----"
    B_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_CONTENT_HERE\n-----END PRIVATE KEY-----"
    

    Then, the correct Lua syntax would be like this.

    local a_key = openssl_pkey.new(a_private_key)
    local b_key = openssl_pkey.new(b_private_key)