void crypto_encryptAndSeal(const uint8_t* key, uint8_t* nonce, uint8_t* plain, uint16_t length, uint8_t* output_buf, uint8_t* output_mac) { uint8_t polykey[sizeof(zeros64)]; crypto_stream_chacha20_xor(polykey, zeros64, sizeof(zeros64), nonce, key, 0); uint8_t padding = (16 - length % 16) % 16; uint8_t message[length + padding + 16]; crypto_stream_chacha20_xor(message, plain, length, nonce, key, 1); memset(message + length, 0, padding + 16); message[length + padding + 8] = (uint8_t)length; message[length + padding + 9] = (uint8_t)(length >> 8); crypto_onetimeauth_poly1305(output_mac, message, sizeof(message), polykey); memcpy(output_buf, message, length); }
int dfcrypt_decrypt( const dfcrypt_state_t *state, const unsigned char *ctxt, size_t ctxt_len_bytes, const unsigned char *message_number, unsigned char *ptxt_out ) { const unsigned char *salt = ctxt; const unsigned char *nonce = ctxt + DFCRYPT_INTERNAL_SALT_BYTES; const unsigned char *encrypted = nonce + crypto_stream_chacha20_NONCEBYTES; const unsigned char *ciphertext_mac = ctxt + ctxt_len_bytes - DFCRYPT_INTERNAL_MAC_BYTES; unsigned char keys[DFCRYPT_INTERNAL_AKEY_BYTES + DFCRYPT_INTERNAL_EKEY_BYTES]; const unsigned char *akey = keys; const unsigned char *ekey = keys + DFCRYPT_INTERNAL_AKEY_BYTES; unsigned char computed_mac[DFCRYPT_INTERNAL_MAC_BYTES]; /* Derive the authentication and encryption keys. */ assert(sizeof(keys) == 64); crypto_generichash_blake2b_salt_personal( keys, /* output */ sizeof(keys), /* output length */ state->appseed, /* input */ state->appseed_length, /* input length */ state->key, /* key */ DFCRYPT_KEY_BYTES, /* key length */ salt, /* salt */ message_number /* personalization (can be NULL) */ ); /* Re-compute the MAC. */ crypto_generichash_blake2b( computed_mac, /* output */ DFCRYPT_INTERNAL_MAC_BYTES, /* output length */ ctxt, /* input */ ctxt_len_bytes - DFCRYPT_INTERNAL_MAC_BYTES, /* input length */ akey, /* key */ DFCRYPT_INTERNAL_AKEY_BYTES /* key length */ ); /* Check the MAC. */ if (sodium_memcmp(computed_mac, ciphertext_mac, DFCRYPT_INTERNAL_MAC_BYTES) != 0) { return -1; } /* Decrypt the plaintext. */ crypto_stream_chacha20_xor( ptxt_out, /* output */ encrypted, /* input */ ctxt_len_bytes - DFCRYPT_CIPHERTEXT_GROWTH, /* input length */ nonce, /* nonce */ ekey /* key */ ); return 0; }
void dfcrypt_encrypt( const dfcrypt_state_t *state, const unsigned char *ptxt, size_t ptxt_len_bytes, const unsigned char *message_number, unsigned char *ctxt_out ) { unsigned char *salt = ctxt_out; unsigned char *nonce = ctxt_out + DFCRYPT_INTERNAL_SALT_BYTES; unsigned char *encrypted = nonce + crypto_stream_chacha20_NONCEBYTES; unsigned char *mac = encrypted + ptxt_len_bytes; unsigned char keys[DFCRYPT_INTERNAL_AKEY_BYTES + DFCRYPT_INTERNAL_EKEY_BYTES]; const unsigned char *akey = keys; const unsigned char *ekey = keys + DFCRYPT_INTERNAL_AKEY_BYTES; /* Sample a random salt and nonce. */ randombytes_buf(salt, DFCRYPT_INTERNAL_SALT_BYTES); randombytes_buf(nonce, crypto_stream_chacha20_NONCEBYTES); /* Derive the authentication and encryption keys. */ assert(sizeof(keys) == 64); crypto_generichash_blake2b_salt_personal( keys, /* output */ sizeof(keys), /* output length */ state->appseed, /* input */ state->appseed_length, /* input length */ state->key, /* key */ DFCRYPT_KEY_BYTES, /* key length */ salt, /* salt */ message_number /* personalization (can be NULL) */ ); /* Encrypt the ciphertext. */ crypto_stream_chacha20_xor( encrypted, /* output */ ptxt, /* input */ ptxt_len_bytes, /* input length */ nonce, /* nonce */ ekey /* key */ ); /* Append the MAC. */ crypto_generichash_blake2b( mac, /* output */ DFCRYPT_INTERNAL_MAC_BYTES, /* output length */ ctxt_out, /* input */ DFCRYPT_INTERNAL_SALT_BYTES + crypto_stream_chacha20_NONCEBYTES + ptxt_len_bytes, /* input length */ akey, /* key */ DFCRYPT_INTERNAL_AKEY_BYTES /* key length */ ); }
uint8_t crypto_verifyAndDecrypt(const uint8_t* key, uint8_t* nonce, uint8_t* encrypted, uint8_t length, uint8_t* output_buf, uint8_t* mac) { uint8_t polykey[sizeof(zeros64)]; crypto_stream_chacha20_xor(polykey, zeros64, sizeof(zeros64), nonce, key, 0); uint8_t padding = (16 - length % 16) % 16; uint8_t message[length + padding + 16]; memcpy(message, encrypted, length); memset(message + length, 0, padding + 16); message[length + padding + 8] = (uint8_t)length; message[length + padding + 9] = (uint8_t)(length >> 8); if (crypto_onetimeauth_poly1305_verify(mac, message, sizeof(message), polykey) != 0) { // Fail return 0; } else { crypto_stream_chacha20_xor(output_buf, message, length, nonce, key, 1); return 1; } }
static void tv(void) { static struct { const char *key_hex; const char *nonce_hex; } tests[] = { { "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000" }, { "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000" }, { "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000001" }, { "0000000000000000000000000000000000000000000000000000000000000000", "0100000000000000" }, { "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "0001020304050607" } }; unsigned char key[crypto_stream_chacha20_KEYBYTES]; unsigned char nonce[crypto_stream_chacha20_NONCEBYTES]; unsigned char *part; unsigned char out[160]; unsigned char zero[160]; char out_hex[160 * 2 + 1]; size_t i = 0U; size_t plen; memset(zero, 0, sizeof zero); do { sodium_hex2bin((unsigned char *)key, sizeof key, tests[i].key_hex, strlen(tests[i].key_hex), NULL, NULL, NULL); sodium_hex2bin(nonce, sizeof nonce, tests[i].nonce_hex, strlen(tests[i].nonce_hex), NULL, NULL, NULL); crypto_stream_chacha20(out, sizeof out, nonce, key); sodium_bin2hex(out_hex, sizeof out_hex, out, sizeof out); printf("[%s]\n", out_hex); for (plen = 1U; plen < sizeof out; plen++) { part = (unsigned char *) sodium_malloc(plen); crypto_stream_chacha20_xor(part, out, plen, nonce, key); if (memcmp(part, zero, plen) != 0) { printf("Failed with length %lu\n", (unsigned long) plen); } sodium_free(part); } } while (++i < (sizeof tests) / (sizeof tests[0])); randombytes_buf(out, sizeof out); crypto_stream_chacha20(out, sizeof out, nonce, key); sodium_bin2hex(out_hex, sizeof out_hex, out, sizeof out); printf("[%s]\n", out_hex); assert(crypto_stream_chacha20(out, 0U, nonce, key) == 0); assert(crypto_stream_chacha20_xor(out, out, 0U, nonce, key) == 0); assert(crypto_stream_chacha20_xor(out, out, 0U, nonce, key) == 0); assert(crypto_stream_chacha20_xor_ic(out, out, 0U, nonce, 1U, key) == 0); memset(out, 0x42, sizeof out); crypto_stream_chacha20_xor(out, out, sizeof out, nonce, key); sodium_bin2hex(out_hex, sizeof out_hex, out, sizeof out); printf("[%s]\n", out_hex); crypto_stream_chacha20_xor_ic(out, out, sizeof out, nonce, 0U, key); sodium_bin2hex(out_hex, sizeof out_hex, out, sizeof out); printf("[%s]\n", out_hex); crypto_stream_chacha20_xor_ic(out, out, sizeof out, nonce, 1U, key); sodium_bin2hex(out_hex, sizeof out_hex, out, sizeof out); printf("[%s]\n", out_hex); };