Binance Chain Key and Signature Conversion

Setup

You can do this in a clean folder without needing to clone any repository, or if you want to save space, open up the node CLI from a project folder that already has @binance-chain/javascript-sdk as a dependency installed.

Convert Mnemonic into PEM Private key

Reference: https://bitcoin.stackexchange.com/a/66622, https://stackoverflow.com/a/48102827/5740053

To convert a seed phrase into a private key (to be imported to the HSM), do the following commands:

$ npm install @binance-chain/javascript-sdk
$ node
> const B = require('@binance-chain/javascript-sdk');
> B.crypto.getPrivateKeyFromMnemonic('insert the mnemonic here');
'a0d2c4d6e87b9594905848bcefb47bc38d2a24b4a6f42541e0b817b597b8e026'

In this example, a0d2c4d6e87b9594905848bcefb47bc38d2a24b4a6f42541e0b817b597b8e026 is the raw private key. We need to convert it to a format that OpenSSL can recognize.

echo 302e0201010420 a0d2c4d6e87b9594905848bcefb47bc38d2a24b4a6f42541e0b817b597b8e026 a00706052b8104000a | xxd -p -r | openssl ec -inform der

302e0201010420 is the prefix for a DER-formatted private key, and a00706052b8104000a is the suffix. Those bytes can be treated as constant. We pipe that into xxd -p -r to convert it to binary, then we pipe the binary DER key into openssl ec -inform der, where ec is for elliptic curve keys, and -inform der specifies the input format.

You should get an output like this:

read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MC4CAQEEIKDSxNboe5WUkFhIvO+0e8ONKiS0pvQlQeC4F7WXuOAmoAcGBSuBBAAK
-----END EC PRIVATE KEY-----

The public key can also be derived by modifying the flags for openssl in the previous command into:

openssl ec -inform der -pubout -text -conv_form compressed

You should get an output like this:

read EC key
Private-Key: (256 bit)
priv:
    a0:d2:c4:d6:e8:7b:95:94:90:58:48:bc:ef:b4:7b:
    c3:8d:2a:24:b4:a6:f4:25:41:e0:b8:17:b5:97:b8:
    e0:26
pub:
    03:7e:9d:e6:9d:02:a0:86:23:f8:68:15:90:31:80:
    b6:28:3f:30:13:b5:16:f4:ba:ba:52:9f:76:62:1c:
    d1:d2:1a
ASN1 OID: secp256k1
writing EC key
-----BEGIN PUBLIC KEY-----
MDYwEAYHKoZIzj0CAQYFK4EEAAoDIgADfp3mnQKghiP4aBWQMYC2KD8wE7UW9Lq6
Up92YhzR0ho=
-----END PUBLIC KEY-----

To generate a Binance address from the public key, run the following:

$ node
> const B = require('@binance-chain/javascript-sdk');
> B.crypto.getAddressFromPublicKey('037e9de69d02a08623f86815903180b6283f3013b516f4baba529f76621cd1d21a')
'tbnb1whgs68y3kwesskej4mqmk858u9kgynkrn6zg2r'
> // Set the prefix for Mainnet - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VVV
> B.crypto.getAddressFromPublicKey('037e9de69d02a08623f86815903180b6283f3013b516f4baba529f76621cd1d21a', 'bnb')
'bnb1whgs68y3kwesskej4mqmk858u9kgynkra0tv2j' //                                                           ^^^

Convert CloudHSM's DER signature to Binance

Binance's Javascript API accepts <r,s> values for the signature when using a SigningDelegate. By default, CloudHSM provides a DER-encoded signature when signing through the key_mgmt_util, so we have to convert it.