1
$\begingroup$

I'm aware that the difference between the NaCL sign keys vs the box keys is that the secret key that comes from the NaCL box keypair is the 32 bit secret key + 32 bit public key.

So I decided to use the tweetnacl.js library to create a signing key and use the box functions to encrypt and decrypt data. I used the nacl.sign.keyPair() to generate a sign key then I stripped off the last 32 bits (public key) off the secretKey Uint8Array then used the following 2 functions to encrypt and decrypt the data.

The encryption works fine, but the decryption always fails most probably because of an incorrect key. I'm not sure if there's some other nuance of NaCL that I'm not considering here.

const nacl = require("tweetnacl")
const util = require("tweetnacl-util")

// Encrypt function
function encrypt(receiverPublicKey, msgParams) {
  const ephemeralKeyPair = nacl.box.keyPair()
  const pubKeyUInt8Array = util.decodeBase64(receiverPublicKey)
  const msgParamsUInt8Array = util.decodeUTF8(msgParams)
  const nonce = nacl.randomBytes(nacl.box.nonceLength)
  const encryptedMessage = nacl.box(
    msgParamsUInt8Array,
    nonce,
    pubKeyUInt8Array,
    ephemeralKeyPair.secretKey
  )
  return {
    ciphertext: util.encodeBase64(encryptedMessage),
    ephemPubKey: util.encodeBase64(ephemeralKeyPair.publicKey),
    nonce: util.encodeBase64(nonce),
    version: "x25519-xsalsa20-poly1305"
  }

}

// Decrypt function
function decrypt(receiverSecretKey, encryptedData) {
  const receiverSecretKeyUint8Array = util.decodeBase64(
    receiverSecretKey
  )
  const nonce = util.decodeBase64(encryptedData.nonce)
  const ciphertext = util.decodeBase64(encryptedData.ciphertext)
  const ephemPubKey = util.decodeBase64(encryptedData.ephemPubKey)
  const decryptedMessage = nacl.box.open(
    ciphertext,
    nonce,
    ephemPubKey,
    receiverSecretKeyUint8Array
  )
  return util.encodeUTF8(decryptedMessage)
}

Note - I have passed in the public and private keys encoded in base64 into the encrypt and decrypt function respectively.

$\endgroup$

1 Answer 1

3
$\begingroup$

NaCl/TweetNaCl use the Montgomery Curve25519 curve for key exchange (for "box"), but the Twisted Edwards Ed25519 curve for signing. The public keys cannot directly be used interchangeably.

If you understand the implications of what you're doing, you can convert between Curve25519 points and Ed25519 points (see Can curve25519 keys be used with ed25519 keys?).

Due to the different life cycles of authentication keys vs encryption keys, you should normally use different keys for these different purposes. See Using same keypair for Diffie-Hellman and signing

If it's essential that you avoid having two different secret keys, the easiest way to resolve this is to have a master key, and use HKDF to derive a separate authentication secret key and encryption secret key from that master key.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.