XSalsa20: make hsalsa20 a public API function #728

Open
karel-m wants to merge 5 commits from pr/xsalsa20-hsalsa20 into develop
karel-m commented 2026-04-16 10:44:18 -05:00 (Migrated from github.com)

While checking the interoperability of libtomcrypt with NaCl/libsodium seal box, crypto box and secret box, I ended up with this patch.

HSalsa20 was a missing piece needed to implement NaCl's crypto_box (= authenticated public-key encryption using X25519 + HSalsa20 + XSalsa20-Poly1305).

Technically HSalsa20 was already implemented inside xsalsa20_setup(..) - this PR simply exposes it as xsalsa20_hsalsa20(..) as part of the public API.

NaCl sealed box (crypto_box_seal) needed unkeyed BLAKE2b. However, blake2bmac_init() rejected (NULL, 0) even though blake2b_init() supports it. This PR allows NULL key when keylen is 0 (in line with the BLAKE2 specification).

Checklist

  • documentation is added or updated
  • tests are added or updated
While checking the interoperability of libtomcrypt with NaCl/libsodium seal box, crypto box and secret box, I ended up with this patch. HSalsa20 was a missing piece needed to implement NaCl's crypto_box (= authenticated public-key encryption using X25519 + HSalsa20 + XSalsa20-Poly1305). Technically HSalsa20 was already implemented inside `xsalsa20_setup(..)` - this PR simply exposes it as `xsalsa20_hsalsa20(..)` as part of the public API. NaCl sealed box (crypto_box_seal) needed unkeyed BLAKE2b. However, `blake2bmac_init()` rejected (NULL, 0) even though `blake2b_init()` supports it. This PR allows NULL key when keylen is 0 (in line with the BLAKE2 specification). ### Checklist * [x] documentation is added or updated * [x] tests are added or updated
karel-m commented 2026-04-16 10:58:43 -05:00 (Migrated from github.com)

If anybody is interested in how interoperability between libtomcrypt and libsodium works, here it is:

/* Interoperability test between libtomcrypt and libsodium for:
   1. secretbox  (XSalsa20-Poly1305)
   2. cryptobox  (X25519 + HSalsa20 + XSalsa20-Poly1305)
   3. sealbox    (ephemeral X25519 + BLAKE2b nonce + cryptobox)
*/

#include <stdio.h>
#include <string.h>
#include <tomcrypt.h>
#include <sodium.h>

#define CHECK(e) do { if ((e) != 0) { fprintf(stderr, "FAIL line %d\n", __LINE__); return 1; } } while(0)

static int ltc_secretbox_create(unsigned char *out, const unsigned char *msg, unsigned long msglen, const unsigned char nonce[24], const unsigned char key[32])
{
   salsa20_state st;
   poly1305_state poly;
   unsigned char polykey[32];
   unsigned long taglen = 16;
   int err;

   if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, 20)) != CRYPT_OK) return err;
   if ((err = salsa20_keystream(&st, polykey, 32))         != CRYPT_OK) { salsa20_done(&st); return err; }
   if ((err = salsa20_crypt(&st, msg, msglen, out + 16))   != CRYPT_OK) { salsa20_done(&st); return err; }
   salsa20_done(&st);
   if ((err = poly1305_init(&poly, polykey, 32))           != CRYPT_OK) return err;
   if ((err = poly1305_process(&poly, out + 16, msglen))   != CRYPT_OK) return err;
   if ((err = poly1305_done(&poly, out, &taglen))          != CRYPT_OK) return err;
   return CRYPT_OK;
}

static int ltc_secretbox_open(unsigned char *msg, const unsigned char *box, unsigned long boxlen, const unsigned char nonce[24], const unsigned char key[32])
{
   salsa20_state st;
   poly1305_state poly;
   unsigned char polykey[32], tag[16];
   unsigned long taglen = 16, msglen;
   int err;

   if (boxlen < 16) return CRYPT_ERROR;
   msglen = boxlen - 16;
   if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, 20)) != CRYPT_OK) return err;
   if ((err = salsa20_keystream(&st, polykey, 32))         != CRYPT_OK) { salsa20_done(&st); return err; }
   if ((err = poly1305_init(&poly, polykey, 32))           != CRYPT_OK) { salsa20_done(&st); return err; }
   if ((err = poly1305_process(&poly, box + 16, msglen))   != CRYPT_OK) { salsa20_done(&st); return err; }
   if ((err = poly1305_done(&poly, tag, &taglen))          != CRYPT_OK) { salsa20_done(&st); return err; }
   if (memcmp(tag, box, 16) != 0) { salsa20_done(&st); return CRYPT_ERROR; }
   if ((err = salsa20_crypt(&st, box + 16, msglen, msg)) != CRYPT_OK) { salsa20_done(&st); return err; }
   salsa20_done(&st);
   return CRYPT_OK;
}

static int ltc_cryptobox_create(unsigned char *out, const unsigned char *msg, unsigned long msglen, const unsigned char nonce[24], const unsigned char recipient_pk[32], const unsigned char sender_sk[32])
{
   curve25519_key sk, pk;
   unsigned char shared[32], symkey[32];
   static const unsigned char zero16[16] = {0};
   unsigned long shared_len = 32;
   int err;

   if ((err = x25519_import_raw(sender_sk, 32, PK_PRIVATE, &sk))     != CRYPT_OK) return err;
   if ((err = x25519_import_raw(recipient_pk, 32, PK_PUBLIC, &pk))    != CRYPT_OK) return err;
   if ((err = x25519_shared_secret(&sk, &pk, shared, &shared_len))   != CRYPT_OK) return err;
   if ((err = xsalsa20_hsalsa20(symkey, 32, shared, 32, zero16, 16, 20)) != CRYPT_OK) return err;
   return ltc_secretbox_create(out, msg, msglen, nonce, symkey);
}

static int ltc_cryptobox_open(unsigned char *msg, const unsigned char *box, unsigned long boxlen, const unsigned char nonce[24], const unsigned char sender_pk[32], const unsigned char recipient_sk[32])
{
   curve25519_key sk, pk;
   unsigned char shared[32], symkey[32];
   static const unsigned char zero16[16] = {0};
   unsigned long shared_len = 32;
   int err;

   if ((err = x25519_import_raw(recipient_sk, 32, PK_PRIVATE, &sk))  != CRYPT_OK) return err;
   if ((err = x25519_import_raw(sender_pk, 32, PK_PUBLIC, &pk))      != CRYPT_OK) return err;
   if ((err = x25519_shared_secret(&sk, &pk, shared, &shared_len))   != CRYPT_OK) return err;
   if ((err = xsalsa20_hsalsa20(symkey, 32, shared, 32, zero16, 16, 20)) != CRYPT_OK) return err;
   return ltc_secretbox_open(msg, box, boxlen, nonce, symkey);
}

static void ltc_seal_nonce(unsigned char nonce[24], const unsigned char eph_pk[32], const unsigned char recipient_pk[32])
{
   blake2bmac_state bst;
   unsigned long noncelen = 24;

   blake2bmac_init(&bst, 24, NULL, 0);
   blake2bmac_process(&bst, eph_pk, 32);
   blake2bmac_process(&bst, recipient_pk, 32);
   blake2bmac_done(&bst, nonce, &noncelen);
}

static int ltc_sealbox_create(unsigned char *out, const unsigned char *msg, unsigned long msglen, const unsigned char recipient_pk[32])
{
   curve25519_key eph;
   prng_state prng;
   unsigned char nonce[24];
   int prng_idx, err;

   prng_idx = find_prng("sprng");
   if (prng_idx == -1) return CRYPT_ERROR;
   if ((err = x25519_make_key(&prng, prng_idx, &eph)) != CRYPT_OK) return err;
   memcpy(out, eph.pub, 32);
   ltc_seal_nonce(nonce, eph.pub, recipient_pk);
   return ltc_cryptobox_create(out + 32, msg, msglen, nonce, recipient_pk, eph.priv);
}

static int ltc_sealbox_open(unsigned char *msg, const unsigned char *box, unsigned long boxlen, const unsigned char recipient_pk[32], const unsigned char recipient_sk[32])
{
   unsigned char nonce[24];

   if (boxlen < 48) return CRYPT_ERROR;
   ltc_seal_nonce(nonce, box, recipient_pk);
   return ltc_cryptobox_open(msg, box + 32, boxlen - 32, nonce, box, recipient_sk);
}

static int test_secretbox(void)
{
   const unsigned char key[32] = {
      0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7,
      0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89
   };
   const unsigned char nonce[24] = {
      0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6,
      0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
   };
   const char *msg = "Hello from the interop test!";
   unsigned long msglen = strlen(msg);
   unsigned char sbox[256], lbox[256], dec[256];

   printf("  sodium create -> ltc open ... ");
   CHECK(crypto_secretbox_easy(sbox, (const unsigned char *)msg, msglen, nonce, key));
   CHECK(ltc_secretbox_open(dec, sbox, msglen + 16, nonce, key));
   CHECK(memcmp(dec, msg, msglen));
   printf("OK\n");
   printf("  ltc create -> sodium open ... ");
   CHECK(ltc_secretbox_create(lbox, (const unsigned char *)msg, msglen, nonce, key));
   CHECK(crypto_secretbox_open_easy(dec, lbox, msglen + 16, nonce, key));
   CHECK(memcmp(dec, msg, msglen));
   printf("OK\n");
   printf("  identical ciphertext ... ");
   CHECK(memcmp(sbox, lbox, msglen + 16));
   printf("OK\n");
   return 0;
}

static int test_cryptobox(void)
{
   unsigned char alice_pk[32], alice_sk[32];
   unsigned char bob_pk[32], bob_sk[32];
   const unsigned char nonce[24] = {
      0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,
      0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18
   };
   const char *msg = "Testing crypto_box interop between libtomcrypt and libsodium.";
   unsigned long msglen = strlen(msg);
   unsigned char sbox[256], lbox[256], dec[256];

   crypto_box_keypair(alice_pk, alice_sk);
   crypto_box_keypair(bob_pk, bob_sk);
   printf("  sodium create -> ltc open ... ");
   CHECK(crypto_box_easy(sbox, (const unsigned char *)msg, msglen, nonce, bob_pk, alice_sk));
   CHECK(ltc_cryptobox_open(dec, sbox, msglen + 16, nonce, alice_pk, bob_sk));
   CHECK(memcmp(dec, msg, msglen));
   printf("OK\n");
   printf("  ltc create -> sodium open ... ");
   CHECK(ltc_cryptobox_create(lbox, (const unsigned char *)msg, msglen, nonce, bob_pk, alice_sk));
   CHECK(crypto_box_open_easy(dec, lbox, msglen + 16, nonce, alice_pk, bob_sk));
   CHECK(memcmp(dec, msg, msglen));
   printf("OK\n");
   printf("  identical ciphertext ... ");
   CHECK(memcmp(sbox, lbox, msglen + 16));
   printf("OK\n");
   return 0;
}

static int test_sealbox(void)
{
   unsigned char pk[32], sk[32];
   const char *msg = "Sealed box: anonymous public-key authenticated encryption!";
   unsigned long msglen = strlen(msg);
   unsigned long sealedlen = msglen + 48;   /* 32 eph_pk + 16 tag */
   unsigned char sealed[256], dec[256];

   crypto_box_keypair(pk, sk);
   printf("  sodium create -> ltc open ... ");
   CHECK(crypto_box_seal(sealed, (const unsigned char *)msg, msglen, pk));
   CHECK(ltc_sealbox_open(dec, sealed, sealedlen, pk, sk));
   CHECK(memcmp(dec, msg, msglen));
   printf("OK\n");
   printf("  ltc create -> sodium open ... ");
   CHECK(ltc_sealbox_create(sealed, (const unsigned char *)msg, msglen, pk));
   CHECK(crypto_box_seal_open(dec, sealed, sealedlen, pk, sk));
   CHECK(memcmp(dec, msg, msglen));
   printf("OK\n");
   return 0;
}

int main(void)
{
   if (sodium_init() < 0) {
      fprintf(stderr, "sodium_init() failed\n");
      return 1;
   }
   if (register_prng(&sprng_desc) == -1) {
      fprintf(stderr, "register_prng(sprng) failed\n");
      return 1;
   }
   printf("Test 1: secretbox (XSalsa20-Poly1305)\n");
   if (test_secretbox() != 0) return 1;
   printf("Test 2: cryptobox (X25519 + HSalsa20 + secretbox)\n");
   if (test_cryptobox() != 0) return 1;
   printf("Test 3: sealbox (ephemeral X25519 + BLAKE2b + cryptobox)\n");
   if (test_sealbox() != 0) return 1;
   printf("All tests passed.\n");
   return 0;
}
If anybody is interested in how interoperability between libtomcrypt and libsodium works, here it is: ```c /* Interoperability test between libtomcrypt and libsodium for: 1. secretbox (XSalsa20-Poly1305) 2. cryptobox (X25519 + HSalsa20 + XSalsa20-Poly1305) 3. sealbox (ephemeral X25519 + BLAKE2b nonce + cryptobox) */ #include <stdio.h> #include <string.h> #include <tomcrypt.h> #include <sodium.h> #define CHECK(e) do { if ((e) != 0) { fprintf(stderr, "FAIL line %d\n", __LINE__); return 1; } } while(0) static int ltc_secretbox_create(unsigned char *out, const unsigned char *msg, unsigned long msglen, const unsigned char nonce[24], const unsigned char key[32]) { salsa20_state st; poly1305_state poly; unsigned char polykey[32]; unsigned long taglen = 16; int err; if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, 20)) != CRYPT_OK) return err; if ((err = salsa20_keystream(&st, polykey, 32)) != CRYPT_OK) { salsa20_done(&st); return err; } if ((err = salsa20_crypt(&st, msg, msglen, out + 16)) != CRYPT_OK) { salsa20_done(&st); return err; } salsa20_done(&st); if ((err = poly1305_init(&poly, polykey, 32)) != CRYPT_OK) return err; if ((err = poly1305_process(&poly, out + 16, msglen)) != CRYPT_OK) return err; if ((err = poly1305_done(&poly, out, &taglen)) != CRYPT_OK) return err; return CRYPT_OK; } static int ltc_secretbox_open(unsigned char *msg, const unsigned char *box, unsigned long boxlen, const unsigned char nonce[24], const unsigned char key[32]) { salsa20_state st; poly1305_state poly; unsigned char polykey[32], tag[16]; unsigned long taglen = 16, msglen; int err; if (boxlen < 16) return CRYPT_ERROR; msglen = boxlen - 16; if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, 20)) != CRYPT_OK) return err; if ((err = salsa20_keystream(&st, polykey, 32)) != CRYPT_OK) { salsa20_done(&st); return err; } if ((err = poly1305_init(&poly, polykey, 32)) != CRYPT_OK) { salsa20_done(&st); return err; } if ((err = poly1305_process(&poly, box + 16, msglen)) != CRYPT_OK) { salsa20_done(&st); return err; } if ((err = poly1305_done(&poly, tag, &taglen)) != CRYPT_OK) { salsa20_done(&st); return err; } if (memcmp(tag, box, 16) != 0) { salsa20_done(&st); return CRYPT_ERROR; } if ((err = salsa20_crypt(&st, box + 16, msglen, msg)) != CRYPT_OK) { salsa20_done(&st); return err; } salsa20_done(&st); return CRYPT_OK; } static int ltc_cryptobox_create(unsigned char *out, const unsigned char *msg, unsigned long msglen, const unsigned char nonce[24], const unsigned char recipient_pk[32], const unsigned char sender_sk[32]) { curve25519_key sk, pk; unsigned char shared[32], symkey[32]; static const unsigned char zero16[16] = {0}; unsigned long shared_len = 32; int err; if ((err = x25519_import_raw(sender_sk, 32, PK_PRIVATE, &sk)) != CRYPT_OK) return err; if ((err = x25519_import_raw(recipient_pk, 32, PK_PUBLIC, &pk)) != CRYPT_OK) return err; if ((err = x25519_shared_secret(&sk, &pk, shared, &shared_len)) != CRYPT_OK) return err; if ((err = xsalsa20_hsalsa20(symkey, 32, shared, 32, zero16, 16, 20)) != CRYPT_OK) return err; return ltc_secretbox_create(out, msg, msglen, nonce, symkey); } static int ltc_cryptobox_open(unsigned char *msg, const unsigned char *box, unsigned long boxlen, const unsigned char nonce[24], const unsigned char sender_pk[32], const unsigned char recipient_sk[32]) { curve25519_key sk, pk; unsigned char shared[32], symkey[32]; static const unsigned char zero16[16] = {0}; unsigned long shared_len = 32; int err; if ((err = x25519_import_raw(recipient_sk, 32, PK_PRIVATE, &sk)) != CRYPT_OK) return err; if ((err = x25519_import_raw(sender_pk, 32, PK_PUBLIC, &pk)) != CRYPT_OK) return err; if ((err = x25519_shared_secret(&sk, &pk, shared, &shared_len)) != CRYPT_OK) return err; if ((err = xsalsa20_hsalsa20(symkey, 32, shared, 32, zero16, 16, 20)) != CRYPT_OK) return err; return ltc_secretbox_open(msg, box, boxlen, nonce, symkey); } static void ltc_seal_nonce(unsigned char nonce[24], const unsigned char eph_pk[32], const unsigned char recipient_pk[32]) { blake2bmac_state bst; unsigned long noncelen = 24; blake2bmac_init(&bst, 24, NULL, 0); blake2bmac_process(&bst, eph_pk, 32); blake2bmac_process(&bst, recipient_pk, 32); blake2bmac_done(&bst, nonce, &noncelen); } static int ltc_sealbox_create(unsigned char *out, const unsigned char *msg, unsigned long msglen, const unsigned char recipient_pk[32]) { curve25519_key eph; prng_state prng; unsigned char nonce[24]; int prng_idx, err; prng_idx = find_prng("sprng"); if (prng_idx == -1) return CRYPT_ERROR; if ((err = x25519_make_key(&prng, prng_idx, &eph)) != CRYPT_OK) return err; memcpy(out, eph.pub, 32); ltc_seal_nonce(nonce, eph.pub, recipient_pk); return ltc_cryptobox_create(out + 32, msg, msglen, nonce, recipient_pk, eph.priv); } static int ltc_sealbox_open(unsigned char *msg, const unsigned char *box, unsigned long boxlen, const unsigned char recipient_pk[32], const unsigned char recipient_sk[32]) { unsigned char nonce[24]; if (boxlen < 48) return CRYPT_ERROR; ltc_seal_nonce(nonce, box, recipient_pk); return ltc_cryptobox_open(msg, box + 32, boxlen - 32, nonce, box, recipient_sk); } static int test_secretbox(void) { const unsigned char key[32] = { 0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7, 0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89 }; const unsigned char nonce[24] = { 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6, 0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37 }; const char *msg = "Hello from the interop test!"; unsigned long msglen = strlen(msg); unsigned char sbox[256], lbox[256], dec[256]; printf(" sodium create -> ltc open ... "); CHECK(crypto_secretbox_easy(sbox, (const unsigned char *)msg, msglen, nonce, key)); CHECK(ltc_secretbox_open(dec, sbox, msglen + 16, nonce, key)); CHECK(memcmp(dec, msg, msglen)); printf("OK\n"); printf(" ltc create -> sodium open ... "); CHECK(ltc_secretbox_create(lbox, (const unsigned char *)msg, msglen, nonce, key)); CHECK(crypto_secretbox_open_easy(dec, lbox, msglen + 16, nonce, key)); CHECK(memcmp(dec, msg, msglen)); printf("OK\n"); printf(" identical ciphertext ... "); CHECK(memcmp(sbox, lbox, msglen + 16)); printf("OK\n"); return 0; } static int test_cryptobox(void) { unsigned char alice_pk[32], alice_sk[32]; unsigned char bob_pk[32], bob_sk[32]; const unsigned char nonce[24] = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c, 0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18 }; const char *msg = "Testing crypto_box interop between libtomcrypt and libsodium."; unsigned long msglen = strlen(msg); unsigned char sbox[256], lbox[256], dec[256]; crypto_box_keypair(alice_pk, alice_sk); crypto_box_keypair(bob_pk, bob_sk); printf(" sodium create -> ltc open ... "); CHECK(crypto_box_easy(sbox, (const unsigned char *)msg, msglen, nonce, bob_pk, alice_sk)); CHECK(ltc_cryptobox_open(dec, sbox, msglen + 16, nonce, alice_pk, bob_sk)); CHECK(memcmp(dec, msg, msglen)); printf("OK\n"); printf(" ltc create -> sodium open ... "); CHECK(ltc_cryptobox_create(lbox, (const unsigned char *)msg, msglen, nonce, bob_pk, alice_sk)); CHECK(crypto_box_open_easy(dec, lbox, msglen + 16, nonce, alice_pk, bob_sk)); CHECK(memcmp(dec, msg, msglen)); printf("OK\n"); printf(" identical ciphertext ... "); CHECK(memcmp(sbox, lbox, msglen + 16)); printf("OK\n"); return 0; } static int test_sealbox(void) { unsigned char pk[32], sk[32]; const char *msg = "Sealed box: anonymous public-key authenticated encryption!"; unsigned long msglen = strlen(msg); unsigned long sealedlen = msglen + 48; /* 32 eph_pk + 16 tag */ unsigned char sealed[256], dec[256]; crypto_box_keypair(pk, sk); printf(" sodium create -> ltc open ... "); CHECK(crypto_box_seal(sealed, (const unsigned char *)msg, msglen, pk)); CHECK(ltc_sealbox_open(dec, sealed, sealedlen, pk, sk)); CHECK(memcmp(dec, msg, msglen)); printf("OK\n"); printf(" ltc create -> sodium open ... "); CHECK(ltc_sealbox_create(sealed, (const unsigned char *)msg, msglen, pk)); CHECK(crypto_box_seal_open(dec, sealed, sealedlen, pk, sk)); CHECK(memcmp(dec, msg, msglen)); printf("OK\n"); return 0; } int main(void) { if (sodium_init() < 0) { fprintf(stderr, "sodium_init() failed\n"); return 1; } if (register_prng(&sprng_desc) == -1) { fprintf(stderr, "register_prng(sprng) failed\n"); return 1; } printf("Test 1: secretbox (XSalsa20-Poly1305)\n"); if (test_secretbox() != 0) return 1; printf("Test 2: cryptobox (X25519 + HSalsa20 + secretbox)\n"); if (test_cryptobox() != 0) return 1; printf("Test 3: sealbox (ephemeral X25519 + BLAKE2b + cryptobox)\n"); if (test_sealbox() != 0) return 1; printf("All tests passed.\n"); return 0; } ```
sjaeckel commented 2026-04-24 02:38:32 -05:00 (Migrated from github.com)

How about adding the libsodium API under an ltc_ prefix as suggested in your comment? I somehow like the idea.

How about adding the libsodium API under an `ltc_` prefix as suggested in your comment? I somehow like the idea.
karel-m commented 2026-04-28 13:59:00 -05:00 (Migrated from github.com)

do you mean having something like this in our public API?

int ltc_secretbox_create(const unsigned char *msg,   unsigned long msglen,
                         const unsigned char *nonce, unsigned long noncelen,
                         const unsigned char *key,   unsigned long keylen,
                               unsigned char *out,   unsigned long *outlen);

int ltc_secretbox_open(const unsigned char *enc,   unsigned long enclen,
                       const unsigned char *nonce, unsigned long noncelen,
                       const unsigned char *key,   unsigned long keylen,
                             unsigned char *out,   unsigned long *outlen);

int ltc_cryptobox_create(const unsigned char *msg,   unsigned long msglen,
                         const unsigned char *nonce, unsigned long noncelen,
                         const unsigned char *pk,    unsigned long pklen,
                         const unsigned char *sk,    unsigned long sklen,
                               unsigned char *out,   unsigned long *outlen);

int ltc_cryptobox_open(const unsigned char *enc,   unsigned long enclen,
                       const unsigned char *nonce, unsigned long noncelen,
                       const unsigned char *pk,    unsigned long pklen,
                       const unsigned char *sk,    unsigned long sklen,
                             unsigned char *out,   unsigned long *outlen);

int ltc_sealedbox_create(const unsigned char *msg, unsigned long msglen,
                         const unsigned char *pk,  unsigned long pklen,
                               unsigned char *out, unsigned long *outlen);

int ltc_sealedbox_open(const unsigned char *enc, unsigned long enclen,
                       const unsigned char *pk,  unsigned long pklen,
                       const unsigned char *sk,  unsigned long sklen,
                             unsigned char *out, unsigned long *outlen);

FYI here is how original libsodium api looks like:

do you mean having something like this in our public API? ```c int ltc_secretbox_create(const unsigned char *msg, unsigned long msglen, const unsigned char *nonce, unsigned long noncelen, const unsigned char *key, unsigned long keylen, unsigned char *out, unsigned long *outlen); int ltc_secretbox_open(const unsigned char *enc, unsigned long enclen, const unsigned char *nonce, unsigned long noncelen, const unsigned char *key, unsigned long keylen, unsigned char *out, unsigned long *outlen); int ltc_cryptobox_create(const unsigned char *msg, unsigned long msglen, const unsigned char *nonce, unsigned long noncelen, const unsigned char *pk, unsigned long pklen, const unsigned char *sk, unsigned long sklen, unsigned char *out, unsigned long *outlen); int ltc_cryptobox_open(const unsigned char *enc, unsigned long enclen, const unsigned char *nonce, unsigned long noncelen, const unsigned char *pk, unsigned long pklen, const unsigned char *sk, unsigned long sklen, unsigned char *out, unsigned long *outlen); int ltc_sealedbox_create(const unsigned char *msg, unsigned long msglen, const unsigned char *pk, unsigned long pklen, unsigned char *out, unsigned long *outlen); int ltc_sealedbox_open(const unsigned char *enc, unsigned long enclen, const unsigned char *pk, unsigned long pklen, const unsigned char *sk, unsigned long sklen, unsigned char *out, unsigned long *outlen); ``` FYI here is how original libsodium api looks like: - secretbox = https://libsodium.gitbook.io/doc/secret-key_cryptography/secretbox - cryptobox = https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption - sealedbox = https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes
sjaeckel commented 2026-04-29 02:59:41 -05:00 (Migrated from github.com)

do you mean having something like this in our public API?

I like that API proposal.

Not sure though if we should add it as an official API or as an inofficial one in demos, like the gcm-file one ... if we add it, we should also have it tested. (Which I will add now for the gcm-file one.)

> do you mean having something like this in our public API? I like that API proposal. Not sure though if we should add it as an official API or as an inofficial one in demos, like the gcm-file one ... if we add it, we should also have it tested. (Which I will add now for the gcm-file one.)
karel-m commented 2026-04-29 15:26:36 -05:00 (Migrated from github.com)

for now, maybe demos/libsodium-boxes.c?

for now, maybe `demos/libsodium-boxes.c`?
sjaeckel commented 2026-04-29 16:03:16 -05:00 (Migrated from github.com)

I'd prefer to directly separate the demo from the boxes and put the boxes to a separate folder ...
Maybe demos/sodium/boxes.c and demos/libsodium.c?

I'd prefer to directly separate the demo from the boxes and put the boxes to a separate folder ... Maybe `demos/sodium/boxes.c` and `demos/libsodium.c`?
sjaeckel (Migrated from github.com) requested changes 2026-08-03 04:02:21 -05:00
sjaeckel (Migrated from github.com) left a comment

Basically LGTM

If we put the boxes into the library we should also have them in the docs. (That's also why I suggested to have the boxes in the demos instead of the library, but I'm fine with both.)

We should also run the demo in CI (or something like that ... maybe turn it into a testcase or so...) to ensure that this doesn't break, especially if the boxes API is provided as an official API.

Basically LGTM If we put the boxes into the library we should also have them in the docs. (That's also why I suggested to have the boxes in the demos instead of the library, but I'm fine with both.) We should also run the demo in CI (or something like that ... maybe turn it into a testcase or so...) to ensure that this doesn't break, especially if the boxes API is provided as an official API.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 'pr/xsalsa20-hsalsa20:pr/xsalsa20-hsalsa20'
git switch 'pr/xsalsa20-hsalsa20'

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 'develop'
git merge --no-ff 'pr/xsalsa20-hsalsa20'
git switch 'pr/xsalsa20-hsalsa20'
git rebase 'develop'
git switch 'develop'
git merge --ff-only 'pr/xsalsa20-hsalsa20'
git switch 'pr/xsalsa20-hsalsa20'
git rebase 'develop'
git switch 'develop'
git merge --no-ff 'pr/xsalsa20-hsalsa20'
git switch 'develop'
git merge --squash 'pr/xsalsa20-hsalsa20'
git switch 'develop'
git merge --ff-only 'pr/xsalsa20-hsalsa20'
git switch 'develop'
git merge 'pr/xsalsa20-hsalsa20'
git push origin 'develop'
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-libtom/libtomcrypt!728
No description provided.