From bd1490a6cd63f7d166ee1c11bd3b00e7d67f1e49 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 19 Jun 2014 18:44:07 -0700 Subject: [PATCH] Add AEAD_CHACHA20_POLY1305 With a twist: in order to be consistent with the crypto_stream interface, the tag has to come before the ciphertext. --- .gitignore | 1 + src/libsodium/Makefile.am | 1 + .../secretbox_chacha20poly1305.c | 149 ++++++++++++++++++ src/libsodium/include/Makefile.am | 1 + src/libsodium/include/sodium.h | 1 + .../crypto_secretbox_chacha20poly1305.h | 72 +++++++++ test/default/Makefile.am | 6 + test/default/secretbox_chacha20poly1305.c | 63 ++++++++ 8 files changed, 294 insertions(+) create mode 100644 src/libsodium/crypto_secretbox/chacha20poly1305/secretbox_chacha20poly1305.c create mode 100644 src/libsodium/include/sodium/crypto_secretbox_chacha20poly1305.h create mode 100644 test/default/secretbox_chacha20poly1305.c diff --git a/.gitignore b/.gitignore index d0144d62..95a8fd01 100644 --- a/.gitignore +++ b/.gitignore @@ -89,6 +89,7 @@ test/default/scalarmult2 test/default/scalarmult5 test/default/scalarmult6 test/default/secretbox +test/default/secretbox_chacha20poly1305 test/default/secretbox2 test/default/secretbox7 test/default/secretbox8 diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index af829675..933e889c 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -71,6 +71,7 @@ libsodium_la_SOURCES = \ crypto_scalarmult/curve25519/scalarmult_curve25519_api.c \ crypto_secretbox/crypto_secretbox.c \ crypto_secretbox/crypto_secretbox_easy.c \ + crypto_secretbox/chacha20poly1305/secretbox_chacha20poly1305.c \ crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305_api.c \ crypto_secretbox/xsalsa20poly1305/ref/api.h \ crypto_secretbox/xsalsa20poly1305/ref/box_xsalsa20poly1305.c \ diff --git a/src/libsodium/crypto_secretbox/chacha20poly1305/secretbox_chacha20poly1305.c b/src/libsodium/crypto_secretbox/chacha20poly1305/secretbox_chacha20poly1305.c new file mode 100644 index 00000000..edd68800 --- /dev/null +++ b/src/libsodium/crypto_secretbox/chacha20poly1305/secretbox_chacha20poly1305.c @@ -0,0 +1,149 @@ + +#include + +#include "crypto_onetimeauth_poly1305.h" +#include "crypto_secretbox_chacha20poly1305.h" +#include "crypto_stream_chacha20.h" +#include "crypto_verify_16.h" +#include "utils.h" + +static inline void +_u64_le_from_ull(unsigned char out[8U], unsigned long long x) +{ + out[0] = (unsigned char) (x & 0xff); x >>= 8; + out[1] = (unsigned char) (x & 0xff); x >>= 8; + out[2] = (unsigned char) (x & 0xff); x >>= 8; + out[3] = (unsigned char) (x & 0xff); x >>= 8; + out[4] = (unsigned char) (x & 0xff); x >>= 8; + out[5] = (unsigned char) (x & 0xff); x >>= 8; + out[6] = (unsigned char) (x & 0xff); x >>= 8; + out[7] = (unsigned char) (x & 0xff); +} + +int +crypto_secretbox_chacha20poly1305_ad(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *n, + const unsigned char *k) +{ + crypto_onetimeauth_poly1305_state state; + unsigned char block0[64U]; + unsigned char slen[8U]; + + crypto_stream_chacha20_xor_ic + (c + crypto_secretbox_chacha20poly1305_ZEROBYTES, m, mlen, n, 1U, k); + + crypto_stream_chacha20(block0, sizeof block0, n, k); + crypto_onetimeauth_poly1305_init(&state, block0); + sodium_memzero(block0, sizeof block0); + + crypto_onetimeauth_poly1305_update(&state, ad, adlen); + _u64_le_from_ull(slen, adlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_update + (&state, c + crypto_secretbox_chacha20poly1305_ZEROBYTES, mlen); + _u64_le_from_ull(slen, mlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&state, c); + + return 0; +} + +int +crypto_secretbox_chacha20poly1305(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k) +{ + return crypto_secretbox_chacha20poly1305_ad(c, m, mlen, NULL, 0ULL, n, k); +} + +int +crypto_secretbox_chacha20poly1305_ad_open(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *n, + const unsigned char *k) +{ + crypto_onetimeauth_poly1305_state state; + unsigned char block0[64U]; + unsigned char slen[8U]; + unsigned char mac[crypto_secretbox_chacha20poly1305_MACBYTES]; + int ret; + + if (clen < crypto_secretbox_chacha20poly1305_ZEROBYTES) { + return -1; + } + + crypto_stream_chacha20(block0, sizeof block0, n, k); + crypto_onetimeauth_poly1305_init(&state, block0); + sodium_memzero(block0, sizeof block0); + + crypto_onetimeauth_poly1305_update(&state, ad, adlen); + _u64_le_from_ull(slen, adlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_update + (&state, c + crypto_secretbox_chacha20poly1305_ZEROBYTES, + clen - crypto_secretbox_chacha20poly1305_ZEROBYTES); + _u64_le_from_ull(slen, clen - crypto_secretbox_chacha20poly1305_ZEROBYTES); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&state, mac); + + ret = crypto_verify_16(mac, c); + sodium_memzero(mac, sizeof mac); + if (ret != 0) { + memset(m, 0, clen - crypto_secretbox_chacha20poly1305_ZEROBYTES); + return -1; + } + crypto_stream_chacha20_xor_ic + (m, c + crypto_secretbox_chacha20poly1305_ZEROBYTES, + clen - crypto_secretbox_chacha20poly1305_ZEROBYTES, n, 1U, k); + + return 0; +} + +int +crypto_secretbox_chacha20poly1305_open(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) +{ + return crypto_secretbox_chacha20poly1305_ad_open(m, c, clen, + NULL, 0ULL, n, k); +} + +size_t +crypto_secretbox_chacha20poly1305_keybytes(void) { + return crypto_secretbox_chacha20poly1305_KEYBYTES; +} + +size_t +crypto_secretbox_chacha20poly1305_noncebytes(void) { + return crypto_secretbox_chacha20poly1305_NONCEBYTES; +} + +size_t +crypto_secretbox_chacha20poly1305_zerobytes(void) { + return crypto_secretbox_chacha20poly1305_ZEROBYTES; +} + +size_t +crypto_secretbox_chacha20poly1305_boxzerobytes(void) { + return crypto_secretbox_chacha20poly1305_BOXZEROBYTES; +} + +size_t +crypto_secretbox_chacha20poly1305_macbytes(void) { + return crypto_secretbox_chacha20poly1305_MACBYTES; +} diff --git a/src/libsodium/include/Makefile.am b/src/libsodium/include/Makefile.am index 0dcde575..298b7df7 100644 --- a/src/libsodium/include/Makefile.am +++ b/src/libsodium/include/Makefile.am @@ -23,6 +23,7 @@ SODIUM_EXPORT = \ sodium/crypto_scalarmult.h \ sodium/crypto_scalarmult_curve25519.h \ sodium/crypto_secretbox.h \ + sodium/crypto_secretbox_chacha20poly1305.h \ sodium/crypto_secretbox_xsalsa20poly1305.h \ sodium/crypto_shorthash.h \ sodium/crypto_shorthash_siphash24.h \ diff --git a/src/libsodium/include/sodium.h b/src/libsodium/include/sodium.h index 96e8091d..49092c65 100644 --- a/src/libsodium/include/sodium.h +++ b/src/libsodium/include/sodium.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libsodium/include/sodium/crypto_secretbox_chacha20poly1305.h b/src/libsodium/include/sodium/crypto_secretbox_chacha20poly1305.h new file mode 100644 index 00000000..349a7198 --- /dev/null +++ b/src/libsodium/include/sodium/crypto_secretbox_chacha20poly1305.h @@ -0,0 +1,72 @@ +#ifndef crypto_secretbox_chacha20poly1305_H +#define crypto_secretbox_chacha20poly1305_H + +#include +#include "export.h" + +#ifdef __cplusplus +# if __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_secretbox_chacha20poly1305_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_secretbox_chacha20poly1305_keybytes(void); + +#define crypto_secretbox_chacha20poly1305_NONCEBYTES 8U +SODIUM_EXPORT +size_t crypto_secretbox_chacha20poly1305_noncebytes(void); + +#define crypto_secretbox_chacha20poly1305_ZEROBYTES 16U +SODIUM_EXPORT +size_t crypto_secretbox_chacha20poly1305_zerobytes(void); + +#define crypto_secretbox_chacha20poly1305_BOXZEROBYTES 0U +SODIUM_EXPORT +size_t crypto_secretbox_chacha20poly1305_boxzerobytes(void); + +#define crypto_secretbox_chacha20poly1305_MACBYTES \ + (crypto_secretbox_chacha20poly1305_ZEROBYTES - \ + crypto_secretbox_chacha20poly1305_BOXZEROBYTES) +SODIUM_EXPORT +size_t crypto_secretbox_chacha20poly1305_macbytes(void); + +SODIUM_EXPORT +int crypto_secretbox_chacha20poly1305(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_secretbox_chacha20poly1305_open(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k); + + +SODIUM_EXPORT +int crypto_secretbox_chacha20poly1305_ad(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_secretbox_chacha20poly1305_ad_open(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *n, + const unsigned char *k); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/default/Makefile.am b/test/default/Makefile.am index ff6db8f9..8ba6e4a7 100644 --- a/test/default/Makefile.am +++ b/test/default/Makefile.am @@ -38,6 +38,7 @@ EXTRA_DIST = \ scalarmult5.exp \ scalarmult6.exp \ secretbox.exp \ + secretbox_chacha20poly1305.exp \ secretbox2.exp \ secretbox7.exp \ secretbox8.exp \ @@ -93,6 +94,7 @@ DISTCLEANFILES = \ scalarmult5.res \ scalarmult6.res \ secretbox.res \ + secretbox_chacha20poly1305.res \ secretbox2.res \ secretbox7.res \ secretbox8.res \ @@ -156,6 +158,7 @@ TESTS_TARGETS = \ scalarmult5 \ scalarmult6 \ secretbox \ + secretbox_chacha20poly1305 \ secretbox2 \ secretbox7 \ secretbox8 \ @@ -289,6 +292,9 @@ scalarmult6_LDADD = $(TESTS_LDADD) secretbox_SOURCE = cmptest.h secretbox.c secretbox_LDADD = $(TESTS_LDADD) +secretbox_chacha20poly1305_SOURCE = cmptest.h secretbox_chacha20poly1305.c +secretbox_chacha20poly1305_LDADD = $(TESTS_LDADD) + secretbox2_SOURCE = cmptest.h secretbox2.c secretbox2_LDADD = $(TESTS_LDADD) diff --git a/test/default/secretbox_chacha20poly1305.c b/test/default/secretbox_chacha20poly1305.c new file mode 100644 index 00000000..145a2295 --- /dev/null +++ b/test/default/secretbox_chacha20poly1305.c @@ -0,0 +1,63 @@ +#include +#include + +#define TEST_NAME "secretbox_chacha20poly1305" +#include "cmptest.h" + +static unsigned char firstkey[crypto_secretbox_chacha20poly1305_KEYBYTES] = { + 0x42, 0x90, 0xbc, 0xb1, 0x54, 0x17, 0x35, 0x31, + 0xf3, 0x14, 0xaf, 0x57, 0xf3, 0xbe, 0x3b, 0x50, + 0x06, 0xda, 0x37, 0x1e, 0xce, 0x27, 0x2a, 0xfa, + 0x1b, 0x5d, 0xbd, 0xd1, 0x10, 0x0a, 0x10, 0x07 +}; + +static unsigned char m[10U] = { + 0x86, 0xd0, 0x99, 0x74, 0x84, 0x0b, 0xde, 0xd2, 0xa5, 0xca +}; + +static unsigned char nonce[crypto_secretbox_chacha20poly1305_NONCEBYTES] = { + 0xcd, 0x7c, 0xf6, 0x7b, 0xe3, 0x9c, 0x79, 0x4a +}; + +static unsigned char ad[10U] = { + 0x87, 0xe2, 0x29, 0xd4, 0x50, 0x08, 0x45, 0xa0, 0x79, 0xc0 +}; + +static unsigned char c[10U + crypto_secretbox_chacha20poly1305_ZEROBYTES]; + +int main(void) +{ + unsigned char m2[10U]; + size_t i; + + crypto_secretbox_chacha20poly1305_ad(c, m, sizeof m, ad, sizeof ad, + nonce, firstkey); + for (i = 0U; i < sizeof c; ++i) { + printf(",0x%02x", (unsigned int) c[i]); + if (i % 8 == 7) { + printf("\n"); + } + } + printf("\n"); + + if (crypto_secretbox_chacha20poly1305_ad_open(m2, c, sizeof c, + ad, sizeof ad, + nonce, firstkey) != 0) { + printf("crypto_secretbox_chacha20poly1305_ad_open() failed\n"); + } + if (memcmp(m, m2, sizeof m) != 0) { + printf("m != m2\n"); + } + + for (i = 0U; i < sizeof c; i++) { + c[i] ^= (i + 1U); + if (crypto_secretbox_chacha20poly1305_ad_open(m2, c, sizeof c, + ad, sizeof ad, + nonce, firstkey) == 0 || + memcmp(m, m2, sizeof m) == 0) { + printf("message can be forged\n"); + } + c[i] ^= (i + 1U); + } + return 0; +}