XSalsa20: make hsalsa20 a public API function#728
Open
Conversation
…n line with the BLAKE2 spec)
Member
Author
|
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;
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 asxsalsa20_hsalsa20(..)as part of the public API.NaCl sealed box (crypto_box_seal) needed unkeyed BLAKE2b. However,
blake2bmac_init()rejected (NULL, 0) even thoughblake2b_init()supports it. This PR allows NULL key when keylen is 0 (in line with the BLAKE2 specification).Checklist