diff --git a/doc/crypt.tex b/doc/crypt.tex index 1c3a10288..150cc45b8 100644 --- a/doc/crypt.tex +++ b/doc/crypt.tex @@ -1250,13 +1250,17 @@ \chapter{Stream Ciphers} however LibTomCrypt's implementation works with bytes). The API for all stream ciphers operates in mode: \textit{setup} -- \textit{crypt} -- \textit{crypt} -- ... -- \textit{done}. +The proper order of progression through these modes is enforced with a \textit{status} flag in the cipher's state. +(An empty state has a \textit{status} of 0, a state after \textit{setup} has a \textit{status} of 1 or 3, +and a state after \textit{setiv} has a \textit{status} of 2.) + Please note that both encryption and decryption are implemented via \textit{crypt}. Another useful feature of the stream ciphers API is generation of a random stream of bytes which works like: \textit{setup} -- \textit{keystream} -- \textit{keystream} -- ... -- \textit{done}. The random stream generation is implemented like encryption of a stream of \textit{0x00} bytes. -Note: You shouldn't use the keystream interface as a PRNG, as it doesn't allow to re-seed the internal state. +Note: You shouldn't use the keystream interface as a PRNG, as it doesn't allow re-seeding the internal state. \mysection{ChaCha} @@ -1336,7 +1340,7 @@ \chapter{Stream Ciphers} \end{verbatim} To initialize \textit{XSalsa20} for the recommended 20 rounds with a 256-bit -key (32 bytes) and a 192-bit nonce (24 bytes), use: +key (32 bytes) and a 192-bit nonce (24 bytes), use: \begin{verbatim} salsa20_state st; @@ -1361,6 +1365,21 @@ \chapter{Stream Ciphers} err = salsa20_done(&st); \end{verbatim} +Many encryptions/decryptions are performed on small data. To make this process easier, +Salsa20 has a helper function \textit{salsa20\_onecall()} that with one function call, +will instantiate a state, call \textit{salsa20\_setup()}, \textit{salsa20\_ivctr64()}, +\textit{salsa20\_crypt()}, and \textit{salsa20\_done()}, returning the crypted data. +\begin{verbatim} +int salsa20_onecall(key, keylen, iv ivlen, datain, datalen, rounds, dataout); +\end{verbatim} + +XSalsa20 likewise has a helper function \textit{xsalsa20\_onecall()} that with one +function call, will instantiate a state, call \textit{xsalsa20\_setup()}, +\textit{salsa20\_crypt()}, and \textit{salsa20\_done()}, returning the crypted data. +\begin{verbatim} +int xsalsa20_onecall(key, keylen, nonce, noncelen, datain, datalen, rounds, dataout); +\end{verbatim} + For both \textit{Salsa20} and \textit{XSalsa20} rounds must be an even number and if set to 0 the default number of rounds, 20, will be used. \vspace{1mm} @@ -1387,10 +1406,9 @@ \chapter{Stream Ciphers} another stream cipher, and the block cipher Serpent. (Sosemanuk means "snow snake" in the Cree Indian language.) -Sosemanuk will accept a key between 1 and 256 bits, but Sosemanuk's security level of 128 -bits is achieved only if the key is between 128 and 256 bits. Keys longer than 128 bits -are not guaranteed to provided higher security. The initialization vector is 128 bits. -(All length arguments are expressed in bytes.) +Sosemanuk will accept a key between 16 and 32 bytes (128 and 256 bits). The initialization +vector is 16 bytes (128 bits). Keys longer than 128 bits are not guaranteed to increase +Sosemanuk's security level of 128 bits. All length arguments are expressed in bytes. See \url{http://www.ecrypt.eu.org/stream/p3ciphers/sosemanuk/sosemanuk_p3.pdf} for more information. @@ -1427,6 +1445,14 @@ \chapter{Stream Ciphers} you do not need to re-run \textit{sosemanuk\_setup()} again, unless of course, you called \textit{sosemanuk\_done()}. +Many encryptions/decryptions are performed on small data. To make this process easier, +Sosemanuk has a helper function \textit{sosemanuk\_onecall()} that with one function call, +will instantiate a state, call \textit{sosemanuk\_setup()}, \textit{sosemanuk\_setiv()}, +\textit{sosemanuk\_crypt()}, and \textit{sosemanuk\_done()}, returning the crypted data. +\begin{verbatim} +int sosemanuk_onecall(key, keylen, iv ivlen, datain, datalen, dataout); +\end{verbatim} + \mysection{Rabbit} \textit{Rabbit}, along with Salsa20, Sosemanuk, and HC-128, was named one of the winners @@ -7058,6 +7084,43 @@ \subsection{Radix to binary conversion} print(names_list.value) \end{verbatim} +For stream ciphers, currently only Salsa20/XSalsa20 and Sosemanuk, +LTC now supports an alternate and arguably a preferred way to get +state sizes. +\begin{verbatim} +size = salsa20_state_size(); +size = sosemanuk_state_size(); +\end{verbatim} + +These new functions greatly simplify the supporting code needed +in the calling programs. Using Python as an example, this new +function instantiates \textit{sosemanuk\_state} with one line. +\begin{verbatim} +import ctypes +... +LTC = ctypes.CDLL('libtomcrypt.dylib') +... +state = ctypes.c_buffer(LTC.sosemanuk_state_size()) +\end{verbatim} +replaces +\begin{verbatim} +import ctypes +... +LTC = ctypes.CDLL('libtomcrypt.dylib') +... +def _get_size(name): + size = ctypes.c_int(0) + rc = LTC.crypt_get_size(bytes(name), byref(size)) + if rc != 0: + raise Exception('LTC.crypt_get_size(%s) rc = %d' % (name, rc)) + return size.value +... +state = ctypes.c_buffer(_get_size(b'sosemanuk_state')) +\end{verbatim} + +Over time this new alternate method will applied to all cipher and +hash function state sizes. + \chapter{Programming Guidelines} diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj index da4fccab7..fd6fe96ed 100644 --- a/libtomcrypt_VS2008.vcproj +++ b/libtomcrypt_VS2008.vcproj @@ -1486,6 +1486,10 @@ RelativePath="src\misc\crypt\crypt_hash_is_valid.c" > + + diff --git a/makefile.mingw b/makefile.mingw index 894b0422a..c7bfabb8e 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -101,12 +101,12 @@ src/misc/crypt/crypt_find_cipher_id.o src/misc/crypt/crypt_find_hash.o \ src/misc/crypt/crypt_find_hash_any.o src/misc/crypt/crypt_find_hash_id.o \ src/misc/crypt/crypt_find_hash_oid.o src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o \ src/misc/crypt/crypt_hash_descriptor.o src/misc/crypt/crypt_hash_is_valid.o \ -src/misc/crypt/crypt_inits.o src/misc/crypt/crypt_ltc_mp_descriptor.o \ -src/misc/crypt/crypt_prng_descriptor.o src/misc/crypt/crypt_prng_is_valid.o \ -src/misc/crypt/crypt_prng_rng_descriptor.o src/misc/crypt/crypt_register_all_ciphers.o \ -src/misc/crypt/crypt_register_all_hashes.o src/misc/crypt/crypt_register_all_prngs.o \ -src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \ -src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \ +src/misc/crypt/crypt_helper_functions.o src/misc/crypt/crypt_inits.o \ +src/misc/crypt/crypt_ltc_mp_descriptor.o src/misc/crypt/crypt_prng_descriptor.o \ +src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_prng_rng_descriptor.o \ +src/misc/crypt/crypt_register_all_ciphers.o src/misc/crypt/crypt_register_all_hashes.o \ +src/misc/crypt/crypt_register_all_prngs.o src/misc/crypt/crypt_register_cipher.o \ +src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \ src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/hkdf.o \ src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \ diff --git a/makefile.msvc b/makefile.msvc index 9e039034d..c09731c40 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -94,12 +94,12 @@ src/misc/crypt/crypt_find_cipher_id.obj src/misc/crypt/crypt_find_hash.obj \ src/misc/crypt/crypt_find_hash_any.obj src/misc/crypt/crypt_find_hash_id.obj \ src/misc/crypt/crypt_find_hash_oid.obj src/misc/crypt/crypt_find_prng.obj src/misc/crypt/crypt_fsa.obj \ src/misc/crypt/crypt_hash_descriptor.obj src/misc/crypt/crypt_hash_is_valid.obj \ -src/misc/crypt/crypt_inits.obj src/misc/crypt/crypt_ltc_mp_descriptor.obj \ -src/misc/crypt/crypt_prng_descriptor.obj src/misc/crypt/crypt_prng_is_valid.obj \ -src/misc/crypt/crypt_prng_rng_descriptor.obj src/misc/crypt/crypt_register_all_ciphers.obj \ -src/misc/crypt/crypt_register_all_hashes.obj src/misc/crypt/crypt_register_all_prngs.obj \ -src/misc/crypt/crypt_register_cipher.obj src/misc/crypt/crypt_register_hash.obj \ -src/misc/crypt/crypt_register_prng.obj src/misc/crypt/crypt_sizes.obj \ +src/misc/crypt/crypt_helper_functions.obj src/misc/crypt/crypt_inits.obj \ +src/misc/crypt/crypt_ltc_mp_descriptor.obj src/misc/crypt/crypt_prng_descriptor.obj \ +src/misc/crypt/crypt_prng_is_valid.obj src/misc/crypt/crypt_prng_rng_descriptor.obj \ +src/misc/crypt/crypt_register_all_ciphers.obj src/misc/crypt/crypt_register_all_hashes.obj \ +src/misc/crypt/crypt_register_all_prngs.obj src/misc/crypt/crypt_register_cipher.obj \ +src/misc/crypt/crypt_register_hash.obj src/misc/crypt/crypt_register_prng.obj src/misc/crypt/crypt_sizes.obj \ src/misc/crypt/crypt_unregister_cipher.obj src/misc/crypt/crypt_unregister_hash.obj \ src/misc/crypt/crypt_unregister_prng.obj src/misc/error_to_string.obj src/misc/hkdf/hkdf.obj \ src/misc/hkdf/hkdf_test.obj src/misc/mem_neq.obj src/misc/padding/padding_depad.obj \ diff --git a/makefile.unix b/makefile.unix index 4fa6ac732..f31b37cf5 100644 --- a/makefile.unix +++ b/makefile.unix @@ -111,12 +111,12 @@ src/misc/crypt/crypt_find_cipher_id.o src/misc/crypt/crypt_find_hash.o \ src/misc/crypt/crypt_find_hash_any.o src/misc/crypt/crypt_find_hash_id.o \ src/misc/crypt/crypt_find_hash_oid.o src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o \ src/misc/crypt/crypt_hash_descriptor.o src/misc/crypt/crypt_hash_is_valid.o \ -src/misc/crypt/crypt_inits.o src/misc/crypt/crypt_ltc_mp_descriptor.o \ -src/misc/crypt/crypt_prng_descriptor.o src/misc/crypt/crypt_prng_is_valid.o \ -src/misc/crypt/crypt_prng_rng_descriptor.o src/misc/crypt/crypt_register_all_ciphers.o \ -src/misc/crypt/crypt_register_all_hashes.o src/misc/crypt/crypt_register_all_prngs.o \ -src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \ -src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \ +src/misc/crypt/crypt_helper_functions.o src/misc/crypt/crypt_inits.o \ +src/misc/crypt/crypt_ltc_mp_descriptor.o src/misc/crypt/crypt_prng_descriptor.o \ +src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_prng_rng_descriptor.o \ +src/misc/crypt/crypt_register_all_ciphers.o src/misc/crypt/crypt_register_all_hashes.o \ +src/misc/crypt/crypt_register_all_prngs.o src/misc/crypt/crypt_register_cipher.o \ +src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \ src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/hkdf.o \ src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \ diff --git a/makefile_include.mk b/makefile_include.mk index b03f76d10..ec3d37f34 100644 --- a/makefile_include.mk +++ b/makefile_include.mk @@ -271,12 +271,12 @@ src/misc/crypt/crypt_find_cipher_id.o src/misc/crypt/crypt_find_hash.o \ src/misc/crypt/crypt_find_hash_any.o src/misc/crypt/crypt_find_hash_id.o \ src/misc/crypt/crypt_find_hash_oid.o src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o \ src/misc/crypt/crypt_hash_descriptor.o src/misc/crypt/crypt_hash_is_valid.o \ -src/misc/crypt/crypt_inits.o src/misc/crypt/crypt_ltc_mp_descriptor.o \ -src/misc/crypt/crypt_prng_descriptor.o src/misc/crypt/crypt_prng_is_valid.o \ -src/misc/crypt/crypt_prng_rng_descriptor.o src/misc/crypt/crypt_register_all_ciphers.o \ -src/misc/crypt/crypt_register_all_hashes.o src/misc/crypt/crypt_register_all_prngs.o \ -src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \ -src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \ +src/misc/crypt/crypt_helper_functions.o src/misc/crypt/crypt_inits.o \ +src/misc/crypt/crypt_ltc_mp_descriptor.o src/misc/crypt/crypt_prng_descriptor.o \ +src/misc/crypt/crypt_prng_is_valid.o src/misc/crypt/crypt_prng_rng_descriptor.o \ +src/misc/crypt/crypt_register_all_ciphers.o src/misc/crypt/crypt_register_all_hashes.o \ +src/misc/crypt/crypt_register_all_prngs.o src/misc/crypt/crypt_register_cipher.o \ +src/misc/crypt/crypt_register_hash.o src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_sizes.o \ src/misc/crypt/crypt_unregister_cipher.o src/misc/crypt/crypt_unregister_hash.o \ src/misc/crypt/crypt_unregister_prng.o src/misc/error_to_string.o src/misc/hkdf/hkdf.o \ src/misc/hkdf/hkdf_test.o src/misc/mem_neq.o src/misc/padding/padding_depad.o \ diff --git a/src/encauth/chachapoly/chacha20poly1305_setiv.c b/src/encauth/chachapoly/chacha20poly1305_setiv.c index 4e770a013..80a9a1b49 100644 --- a/src/encauth/chachapoly/chacha20poly1305_setiv.c +++ b/src/encauth/chachapoly/chacha20poly1305_setiv.c @@ -41,6 +41,7 @@ int chacha20poly1305_setiv(chacha20poly1305_state *st, const unsigned char *iv, /* copy chacha20 key to temporary state */ for(i = 0; i < 12; i++) tmp_st.input[i] = st->chacha.input[i]; tmp_st.rounds = 20; + tmp_st.status = st->chacha.status; /* set IV */ if (ivlen == 12) { /* IV 32bit */ diff --git a/src/headers/tomcrypt_cipher.h b/src/headers/tomcrypt_cipher.h index 4b983593d..34e9ad821 100644 --- a/src/headers/tomcrypt_cipher.h +++ b/src/headers/tomcrypt_cipher.h @@ -995,13 +995,22 @@ LTC_MUTEX_PROTO(ltc_cipher_mutex) #ifdef LTC_CHACHA typedef struct { - ulong32 input[16]; + ulong32 input[16]; unsigned char kstream[64]; unsigned long ksleft; + unsigned long rounds; unsigned long ivlen; - int rounds; + unsigned long status; /* 0=uninitialized, 1=finished setup(), 2=finished ivctrXX() */ } chacha_state; +int chacha_state_size(void); + +int chacha_memory(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned long rounds, + unsigned char *dataout); + int chacha_setup(chacha_state *st, const unsigned char *key, unsigned long keylen, int rounds); int chacha_ivctr32(chacha_state *st, const unsigned char *iv, unsigned long ivlen, ulong32 counter); int chacha_ivctr64(chacha_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 counter); @@ -1015,14 +1024,22 @@ int chacha_test(void); #ifdef LTC_SALSA20 typedef struct { - ulong32 input[16]; + ulong32 input[16]; unsigned char kstream[64]; unsigned long ksleft; - unsigned long ivlen; - int rounds; + unsigned long rounds; + unsigned long status; /* 0=uninitialized, 1,3=finished setup(), 2=finished setiv() */ } salsa20_state; -int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, int rounds); +int salsa20_state_size(void); + +int salsa20_memory(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned long rounds, + unsigned char *dataout); + +int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, unsigned long rounds); int salsa20_ivctr64(salsa20_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 counter); int salsa20_crypt(salsa20_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out); int salsa20_keystream(salsa20_state *st, unsigned char *out, unsigned long outlen); @@ -1033,9 +1050,17 @@ int salsa20_test(void); #ifdef LTC_XSALSA20 +int xsalsa20_state_size(void); + +int xsalsa20_memory(const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *datain, unsigned long datalen, + unsigned long rounds, + unsigned char *dataout); + int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, unsigned long noncelen, - int rounds); + unsigned long rounds); int xsalsa20_test(void); #endif /* LTC_XSALSA20 */ @@ -1043,23 +1068,32 @@ int xsalsa20_test(void); #ifdef LTC_SOSEMANUK typedef struct { - ulong32 kc[100]; /* key_context */ - ulong32 s00, s01, s02, s03, s04, s05, s06, s07, s08, s09; - ulong32 r1, r2; - /* - * Buffering: the stream cipher produces output data by - * blocks of 640 bits. buf[] contains such a block, and - * "ptr" is the index of the next output byte. - */ - unsigned char buf[80]; - unsigned ptr; + ulong32 kc[100]; /* key_context */ + ulong32 s00, s01, s02, s03, s04, s05, s06, s07, s08, s09; + ulong32 r1, r2; + /* + * Buffering: the stream cipher produces output data by + * blocks of 640 bits. buf[] contains such a block, and + * "ptr" is the index of the next output byte. + */ + unsigned char buf[80]; + unsigned ptr; + unsigned long ivlen; + unsigned long status; /* 0=uninitialized, 1=finished setup(), 2=finished setiv() */ } sosemanuk_state; -int sosemanuk_setup(sosemanuk_state *ss, const unsigned char *key, unsigned long keylen); -int sosemanuk_setiv(sosemanuk_state *ss, const unsigned char *iv, unsigned long ivlen); -int sosemanuk_crypt(sosemanuk_state *ss, const unsigned char *in, unsigned long datalen, unsigned char *out); -int sosemanuk_keystream(sosemanuk_state *ss, unsigned char *out, unsigned long outlen); -int sosemanuk_done(sosemanuk_state *ss); +int sosemanuk_state_size(void); + +int sosemanuk_memory(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned char *dataout); + +int sosemanuk_setup(sosemanuk_state *st, const unsigned char *key, unsigned long keylen); +int sosemanuk_setiv(sosemanuk_state *st, const unsigned char *iv, unsigned long ivlen); +int sosemanuk_crypt(sosemanuk_state *st, const unsigned char *in, unsigned long datalen, unsigned char *out); +int sosemanuk_keystream(sosemanuk_state *st, unsigned char *out, unsigned long outlen); +int sosemanuk_done(sosemanuk_state *st); int sosemanuk_test(void); #endif /* LTC_SOSEMANUK */ @@ -1075,10 +1109,18 @@ typedef struct { typedef struct { rabbit_ctx master_ctx; rabbit_ctx work_ctx; - unsigned char block[16]; /* last keystream block containing unused bytes */ - ulong32 unused; /* count fm right */ + unsigned char block[16]; /* last keystream block containing unused bytes */ + ulong32 unused; /* count fm right */ + ulong32 status; /* 0=uninitialized, 1=finished setup(), 2=finished setiv() */ } rabbit_state; +int rabbit_state_size(void); + +int rabbit_memory(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned char *dataout); + int rabbit_setup(rabbit_state* st, const unsigned char *key, unsigned long keylen); int rabbit_setiv(rabbit_state* st, const unsigned char *iv, unsigned long ivlen); int rabbit_crypt(rabbit_state* st, const unsigned char *in, unsigned long inlen, unsigned char *out); @@ -1093,8 +1135,15 @@ int rabbit_test(void); typedef struct { unsigned int x, y; unsigned char buf[256]; + unsigned long status; /* 0=uninitialized, 1=finished setup() */ } rc4_state; +int rc4_state_size(void); + +int rc4_memory(const unsigned char *key, unsigned long keylen, + const unsigned char *datain, unsigned long datalen, + unsigned char *dataout); + int rc4_stream_setup(rc4_state *st, const unsigned char *key, unsigned long keylen); int rc4_stream_crypt(rc4_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out); int rc4_stream_keystream(rc4_state *st, unsigned char *out, unsigned long outlen); @@ -1110,9 +1159,17 @@ typedef struct { initR[17], /* saved register contents */ konst, /* key dependent constant */ sbuf; /* partial word encryption buffer */ - int nbuf; /* number of part-word stream bits buffered */ + ulong32 nbuf; /* number of part-word stream bits buffered */ + ulong32 status; /* 0=uninitialized, 1=finished setup(), 2=finished setiv() */ } sober128_state; +int sober128_state_size(void); + +int sober128_memory(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned char *dataout); + int sober128_stream_setup(sober128_state *st, const unsigned char *key, unsigned long keylen); int sober128_stream_setiv(sober128_state *st, const unsigned char *iv, unsigned long ivlen); int sober128_stream_crypt(sober128_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out); diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index 277271868..cc2e9cb33 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -641,6 +641,9 @@ #endif +/* helper functions for stream ciphers (disable to prevent building them) */ +#define LTC_HELPER_FUNCTIONS + /* Debuggers */ /* define this if you use Valgrind, note: it CHANGES the way SOBER-128 and RC4 work (see the code) */ diff --git a/src/misc/crypt/crypt_helper_functions.c b/src/misc/crypt/crypt_helper_functions.c new file mode 100644 index 000000000..f4c7714bb --- /dev/null +++ b/src/misc/crypt/crypt_helper_functions.c @@ -0,0 +1,185 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ +#include "tomcrypt_private.h" + +#ifdef LTC_HELPER_FUNCTIONS + +/** + @file crypt_helper_functions.c + + A home for the "one call" and other helper functions. + Larry Bugbee - June 2018 +*/ + +/* ======================================================================== */ + +#ifdef LTC_CHACHA + +int chacha_memory(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned long rounds, + unsigned char *dataout) +{ + chacha_state state; + int err; + + if ((err = chacha_setup(&state, key, keylen, rounds)) != CRYPT_OK) goto WIPE_KEY; + if (ivlen == 12) { + if ((err = chacha_ivctr32(&state, iv, ivlen, 0)) != CRYPT_OK) goto WIPE_KEY; + } else { + if ((err = chacha_ivctr64(&state, iv, ivlen, 0)) != CRYPT_OK) goto WIPE_KEY; + } + err = chacha_crypt(&state, datain, datalen, dataout); +WIPE_KEY: + chacha_done(&state); + return err; +} + +#endif /* LTC_CHACHA */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#ifdef LTC_SALSA20 + +int salsa20_onecall(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned long rounds, + unsigned char *dataout) +{ + salsa20_state state; + int err; + + if ((err = salsa20_setup(&state, key, keylen, rounds)) != CRYPT_OK) goto WIPE_KEY; + if ((err = salsa20_ivctr64(&state, iv, ivlen, 0)) != CRYPT_OK) goto WIPE_KEY; + err = salsa20_crypt(&state, datain, datalen, dataout); +WIPE_KEY: + salsa20_done(&state); + return err; +} + +#endif /* LTC_SALSA20 */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#ifdef LTC_XSALSA20 + +int xsalsa20_onecall(const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *datain, unsigned long datalen, + unsigned long rounds, + unsigned char *dataout) +{ + salsa20_state state; + int err; + + if ((err = xsalsa20_setup(&state, key, keylen, nonce, noncelen, rounds)) != CRYPT_OK) goto WIPE_KEY; + err = salsa20_crypt(&state, datain, datalen, dataout); +WIPE_KEY: + salsa20_done(&state); + return err; +} + +#endif /* LTC_XSALSA20 */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +#ifdef LTC_SOSEMANUK + +int sosemanuk_onecall(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned char *dataout) +{ + sosemanuk_state state; + int err; + + if ((err = sosemanuk_setup(&state, key, keylen)) != CRYPT_OK) goto WIPE_KEY; + if ((err = sosemanuk_setiv(&state, iv, ivlen)) != CRYPT_OK) goto WIPE_KEY; + err = sosemanuk_crypt(&state, datain, datalen, dataout); +WIPE_KEY: + sosemanuk_done(&state); + return err; +} + +#endif /* LTC_SOSEMANUK */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#ifdef LTC_RABBIT + +int rabbit_onecall(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned char *dataout) +{ + rabbit_state state; + int err; + + if ((err = rabbit_setup(&state, key, keylen)) != CRYPT_OK) goto WIPE_KEY; + if ((err = rabbit_setiv(&state, iv, ivlen)) != CRYPT_OK) goto WIPE_KEY; + err = rabbit_crypt(&state, datain, datalen, dataout); +WIPE_KEY: + rabbit_done(&state); + return err; +} + +#endif /* LTC_RABBIT */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#ifdef LTC_RC4_STREAM + +int rc4_stream_onecall(const unsigned char *key, unsigned long keylen, + const unsigned char *datain, unsigned long datalen, + unsigned char *dataout) +{ + rc4_state state; + int err; + + if ((err = rc4_stream_setup(&state, key, keylen)) != CRYPT_OK) goto WIPE_KEY; + err = rc4_stream_crypt(&state, datain, datalen, dataout); +WIPE_KEY: + rc4_stream_done(&state); + return err; +} + +#endif /* LTC_RC4_STREAM */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#ifdef LTC_SOBER128_STREAM + +int sober128_stream_onecall(const unsigned char *key, unsigned long keylen, + const unsigned char *iv, unsigned long ivlen, + const unsigned char *datain, unsigned long datalen, + unsigned char *dataout) +{ + sober128_state state; + int err; + + if ((err = sober128_stream_setup(&state, key, keylen)) != CRYPT_OK) goto WIPE_KEY; + if ((err = sober128_stream_setiv(&state, iv, ivlen)) != CRYPT_OK) goto WIPE_KEY; + err = sober128_stream_crypt(&state, datain, datalen, dataout); +WIPE_KEY: + sober128_stream_done(&state); + return err; +} + +#endif /* LTC_SOBER128_STREAM */ + +/* ======================================================================== */ + +#endif /* LTC_HELPER_FUNCTIONS */ + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/src/misc/crypt/crypt_sizes.c b/src/misc/crypt/crypt_sizes.c index 5681cc001..7c9121dd4 100644 --- a/src/misc/crypt/crypt_sizes.c +++ b/src/misc/crypt/crypt_sizes.c @@ -290,6 +290,31 @@ static const crypt_size _crypt_sizes[] = { }; +/* ======================================================================== */ + +#ifdef LTC_CHACHA +int chacha_state_size(void) { return sizeof(chacha_state); } +#endif +#ifdef LTC_SALSA20 +int salsa20_state_size(void) { return sizeof(salsa20_state); } +#endif +#ifdef LTC_XSALSA20 +int xsalsa20_state_size(void) { return sizeof(salsa20_state); } +#endif +#ifdef LTC_SOSEMANUK +int sosemanuk_state_size(void) { return sizeof(sosemanuk_state); } +#endif +#ifdef LTC_RABBIT +int rabbit_state_size(void) { return sizeof(rabbit_state); } +#endif +#ifdef LTC_RC4_STREAM +int rc4_state_size(void) { return sizeof(rc4_state); } +#endif +#ifdef LTC_SOBER128_STREAM +int sober128_state_size(void) { return sizeof(sober128_state); } +#endif + +/* ======================================================================== */ /* crypt_get_size() * sizeout will be the size (bytes) of the named struct or union * return -1 if named item not found @@ -306,6 +331,7 @@ int crypt_get_size(const char* namein, unsigned int *sizeout) { return -1; } +/* ======================================================================== */ /* crypt_list_all_sizes() * if names_list is NULL, names_list_size will be the minimum * size needed to receive the complete names_list diff --git a/src/stream/chacha/chacha_crypt.c b/src/stream/chacha/chacha_crypt.c index d72c84e7e..d67d55868 100644 --- a/src/stream/chacha/chacha_crypt.c +++ b/src/stream/chacha/chacha_crypt.c @@ -58,10 +58,10 @@ int chacha_crypt(chacha_state *st, const unsigned char *in, unsigned long inlen, if (inlen == 0) return CRYPT_OK; /* nothing to do */ - LTC_ARGCHK(st != NULL); - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(out != NULL); - LTC_ARGCHK(st->ivlen != 0); + LTC_ARGCHK(st != NULL); + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(st->status == 2); if (st->ksleft > 0) { j = MIN(st->ksleft, inlen); diff --git a/src/stream/chacha/chacha_ivctr32.c b/src/stream/chacha/chacha_ivctr32.c index 72856a090..fe22e2b43 100644 --- a/src/stream/chacha/chacha_ivctr32.c +++ b/src/stream/chacha/chacha_ivctr32.c @@ -28,15 +28,16 @@ int chacha_ivctr32(chacha_state *st, const unsigned char *iv, unsigned long ivle { LTC_ARGCHK(st != NULL); LTC_ARGCHK(iv != NULL); - /* 96bit IV + 32bit counter */ - LTC_ARGCHK(ivlen == 12); + LTC_ARGCHK(ivlen == 12); /* 96bit IV + 32bit counter */ + LTC_ARGCHK(st->status == 1 || st->status == 2); st->input[12] = counter; LOAD32L(st->input[13], iv + 0); LOAD32L(st->input[14], iv + 4); LOAD32L(st->input[15], iv + 8); st->ksleft = 0; - st->ivlen = ivlen; + st->status = 2; + st->ivlen = ivlen; return CRYPT_OK; } diff --git a/src/stream/chacha/chacha_ivctr64.c b/src/stream/chacha/chacha_ivctr64.c index f7cf721fa..1a27dc13d 100644 --- a/src/stream/chacha/chacha_ivctr64.c +++ b/src/stream/chacha/chacha_ivctr64.c @@ -28,15 +28,16 @@ int chacha_ivctr64(chacha_state *st, const unsigned char *iv, unsigned long ivle { LTC_ARGCHK(st != NULL); LTC_ARGCHK(iv != NULL); - /* 64bit IV + 64bit counter */ - LTC_ARGCHK(ivlen == 8); + LTC_ARGCHK(ivlen == 8); /* 64bit IV + 64bit counter */ + LTC_ARGCHK(st->status == 1 || st->status == 2); st->input[12] = (ulong32)(counter & 0xFFFFFFFF); st->input[13] = (ulong32)(counter >> 32); LOAD32L(st->input[14], iv + 0); LOAD32L(st->input[15], iv + 4); st->ksleft = 0; - st->ivlen = ivlen; + st->ivlen = ivlen; + st->status = 2; return CRYPT_OK; } diff --git a/src/stream/chacha/chacha_setup.c b/src/stream/chacha/chacha_setup.c index e997fc951..e6526389a 100644 --- a/src/stream/chacha/chacha_setup.c +++ b/src/stream/chacha/chacha_setup.c @@ -19,6 +19,7 @@ static const char * const sigma = "expand 32-byte k"; static const char * const tau = "expand 16-byte k"; +/* ======================================================================== */ /** Initialize an ChaCha context (only the key) @param st [out] The destination of the ChaCha state @@ -56,7 +57,7 @@ int chacha_setup(chacha_state *st, const unsigned char *key, unsigned long keyle LOAD32L(st->input[2], constants + 8); LOAD32L(st->input[3], constants + 12); st->rounds = rounds; /* e.g. 20 for chacha20 */ - st->ivlen = 0; /* will be set later by chacha_ivctr(32|64) */ + st->status = 1; return CRYPT_OK; } diff --git a/src/stream/rabbit/rabbit.c b/src/stream/rabbit/rabbit.c index 4607bc9ed..9f6dfd646 100644 --- a/src/stream/rabbit/rabbit.c +++ b/src/stream/rabbit/rabbit.c @@ -19,46 +19,50 @@ * The eSTREAM submission was rather picky about the calling sequence of * ECRYPT_process_blocks() and ECRYPT_process_bytes(). That version allowed * calling ECRYPT_process_blocks() multiple times for a multiple of whole - * 16-byte blocks, but once ECRYPT_process_bytes() was called. no more calls + * 16-byte blocks, but once ECRYPT_process_bytes() was called, no more calls * were supported correctly. This implementation handles the keystream * differently and rabbit_crypt() may be called as many times as desired, * crypting any number of bytes each time. * * http://www.ecrypt.eu.org/stream/e2-rabbit.html + * https://www.ietf.org/rfc/rfc4503.txt * * NB: One of the test vectors distributed by the eSTREAM site in the file * "rabbit_p3source.zip" is in error. Referring to "test-vectors.txt" * in that ZIP file, the 3rd line in "out1" should be * "96 D6 73 16 88 D1 68 DA 51 D4 0C 70 C3 A1 16 F4". * + *--------------------------------------------------------------------------- * Here is the original legal notice accompanying the Rabbit submission * to the EU eSTREAM competition. - *--------------------------------------------------------------------------- - * Copyright (C) Cryptico A/S. All rights reserved. * - * YOU SHOULD CAREFULLY READ THIS LEGAL NOTICE BEFORE USING THIS SOFTWARE. + * Copyright (C) Cryptico A/S. All rights reserved. + * + * YOU SHOULD CAREFULLY READ THIS LEGAL NOTICE BEFORE USING THIS SOFTWARE. + * + * This software is developed by Cryptico A/S and/or its suppliers. + * All title and intellectual property rights in and to the software, + * including but not limited to patent rights and copyrights, are owned + * by Cryptico A/S and/or its suppliers. * - * This software is developed by Cryptico A/S and/or its suppliers. - * All title and intellectual property rights in and to the software, - * including but not limited to patent rights and copyrights, are owned - * by Cryptico A/S and/or its suppliers. + * The software may be used solely for non-commercial purposes + * without the prior written consent of Cryptico A/S. For further + * information on licensing terms and conditions please contact + * Cryptico A/S at info@cryptico.com * - * The software may be used solely for non-commercial purposes - * without the prior written consent of Cryptico A/S. For further - * information on licensing terms and conditions please contact - * Cryptico A/S at info@cryptico.com + * Cryptico, CryptiCore, the Cryptico logo and "Re-thinking encryption" + * are either trademarks or registered trademarks of Cryptico A/S. * - * Cryptico, CryptiCore, the Cryptico logo and "Re-thinking encryption" - * are either trademarks or registered trademarks of Cryptico A/S. + * Cryptico A/S shall not in any way be liable for any use of this + * software. The software is provided "as is" without any express or + * implied warranty. * - * Cryptico A/S shall not in any way be liable for any use of this - * software. The software is provided "as is" without any express or - * implied warranty. *--------------------------------------------------------------------------- * On October 6, 2008, Rabbit was "released into the public domain and * may be used freely for any purpose." + * * http://www.ecrypt.eu.org/stream/rabbitpf.html - * https://web.archive.org/web/20090630021733/http://www.ecrypt.eu.org/stream/phorum/read.php?1,1244 + * ******************************************************************************/ @@ -145,8 +149,7 @@ static LTC_INLINE void _rabbit_gen_1_block(rabbit_state* st, unsigned char *out) STORE32L((ptr[6] ^ (ptr[3]>>16) ^ (ulong32)(ptr[1]<<16)), out+12); } -/* -------------------------------------------------------------------------- */ - +/* ======================================================================== */ /* Key setup */ int rabbit_setup(rabbit_state* st, const unsigned char *key, unsigned long keylen) { @@ -214,6 +217,7 @@ int rabbit_setup(rabbit_state* st, const unsigned char *key, unsigned long keyle /* ...and prepare block for crypt() */ XMEMSET(&(st->block), 0, sizeof(st->block)); st->unused = 0; + st->status = 1; return CRYPT_OK; } @@ -229,6 +233,7 @@ int rabbit_setiv(rabbit_state* st, const unsigned char *iv, unsigned long ivlen) LTC_ARGCHK(st != NULL); LTC_ARGCHK(iv != NULL || ivlen == 0); LTC_ARGCHK(ivlen <= 8); + LTC_ARGCHK(st->status != 0); /* pad iv in tmpiv */ if (iv && ivlen > 0) XMEMCPY(tmpiv, iv, ivlen); @@ -261,6 +266,7 @@ int rabbit_setiv(rabbit_state* st, const unsigned char *iv, unsigned long ivlen) /* reset keystream buffer and unused count */ XMEMSET(&(st->block), 0, sizeof(st->block)); st->unused = 0; + st->status = 2; return CRYPT_OK; } @@ -275,9 +281,10 @@ int rabbit_crypt(rabbit_state* st, const unsigned char *in, unsigned long inlen, if (inlen == 0) return CRYPT_OK; /* nothing to do */ - LTC_ARGCHK(st != NULL); - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(out != NULL); + LTC_ARGCHK(st != NULL); + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(st->status == 2); if (st->unused > 0) { j = MIN(st->unused, inlen); diff --git a/src/stream/rc4/rc4_stream.c b/src/stream/rc4/rc4_stream.c index f1c225d01..059f5505e 100644 --- a/src/stream/rc4/rc4_stream.c +++ b/src/stream/rc4/rc4_stream.c @@ -42,6 +42,7 @@ int rc4_stream_setup(rc4_state *st, const unsigned char *key, unsigned long keyl } st->x = 0; st->y = 0; + st->status = 1; return CRYPT_OK; } @@ -61,6 +62,7 @@ int rc4_stream_crypt(rc4_state *st, const unsigned char *in, unsigned long inlen LTC_ARGCHK(st != NULL); LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); + LTC_ARGCHK(st->status == 1); x = st->x; y = st->y; diff --git a/src/stream/salsa20/salsa20_crypt.c b/src/stream/salsa20/salsa20_crypt.c index bf1b00167..07764ffc6 100644 --- a/src/stream/salsa20/salsa20_crypt.c +++ b/src/stream/salsa20/salsa20_crypt.c @@ -59,10 +59,10 @@ int salsa20_crypt(salsa20_state *st, const unsigned char *in, unsigned long inle if (inlen == 0) return CRYPT_OK; /* nothing to do */ - LTC_ARGCHK(st != NULL); - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(out != NULL); - LTC_ARGCHK(st->ivlen == 8 || st->ivlen == 24); + LTC_ARGCHK(st != NULL); + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(st->status == 2 || st->status == 3); if (st->ksleft > 0) { j = MIN(st->ksleft, inlen); diff --git a/src/stream/salsa20/salsa20_ivctr64.c b/src/stream/salsa20/salsa20_ivctr64.c index 9c7ac74f7..241999f5a 100644 --- a/src/stream/salsa20/salsa20_ivctr64.c +++ b/src/stream/salsa20/salsa20_ivctr64.c @@ -29,15 +29,15 @@ int salsa20_ivctr64(salsa20_state *st, const unsigned char *iv, unsigned long iv { LTC_ARGCHK(st != NULL); LTC_ARGCHK(iv != NULL); - /* Salsa20: 64-bit IV (nonce) + 64-bit counter */ LTC_ARGCHK(ivlen == 8); + LTC_ARGCHK(st->status == 1 || st->status == 2); LOAD32L(st->input[6], iv + 0); LOAD32L(st->input[7], iv + 4); st->input[8] = (ulong32)(counter & 0xFFFFFFFF); st->input[9] = (ulong32)(counter >> 32); st->ksleft = 0; - st->ivlen = ivlen; + st->status = 2; return CRYPT_OK; } diff --git a/src/stream/salsa20/salsa20_setup.c b/src/stream/salsa20/salsa20_setup.c index 872bd121d..fa4e5a2fa 100644 --- a/src/stream/salsa20/salsa20_setup.c +++ b/src/stream/salsa20/salsa20_setup.c @@ -20,6 +20,7 @@ static const char * const sigma = "expand 32-byte k"; static const char * const tau = "expand 16-byte k"; +/* ======================================================================== */ /** Initialize an Salsa20 context (only the key) @param st [out] The destination of the Salsa20 state @@ -28,7 +29,7 @@ static const char * const tau = "expand 16-byte k"; @param rounds Number of rounds (e.g. 20 for Salsa20) @return CRYPT_OK if successful */ -int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, int rounds) +int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, unsigned long rounds) { const char *constants; @@ -37,7 +38,7 @@ int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long key LTC_ARGCHK(keylen == 32 || keylen == 16); if (rounds == 0) rounds = 20; - LTC_ARGCHK(rounds % 2 == 0); /* number of rounds must be evenly divisible by 2 */ + LTC_ARGCHK(rounds % 2 == 0); /* rounds must be evenly divisible by 2 */ LOAD32L(st->input[1], key + 0); LOAD32L(st->input[2], key + 4); @@ -58,7 +59,7 @@ int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long key LOAD32L(st->input[10], constants + 8); LOAD32L(st->input[15], constants + 12); st->rounds = rounds; /* default is 20 for salsa20 */ - st->ivlen = 0; /* will be set later by salsa20_ivctr(32|64) */ + st->status = 1; return CRYPT_OK; } diff --git a/src/stream/salsa20/xsalsa20_setup.c b/src/stream/salsa20/xsalsa20_setup.c index 94133a7f3..41bf0a9d1 100644 --- a/src/stream/salsa20/xsalsa20_setup.c +++ b/src/stream/salsa20/xsalsa20_setup.c @@ -18,6 +18,8 @@ #ifdef LTC_XSALSA20 +/* ======================================================================== */ + static const char * const constants = "expand 32-byte k"; #define QUARTERROUND(a,b,c,d) \ @@ -59,7 +61,7 @@ static void _xsalsa20_doubleround(ulong32 *x, int rounds) */ int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, unsigned long noncelen, - int rounds) + unsigned long rounds) { const int sti[] = {0, 5, 10, 15, 6, 7, 8, 9}; /* indices used to build subkey fm x */ ulong32 x[64]; /* input to & output fm doubleround */ @@ -72,7 +74,7 @@ int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long ke LTC_ARGCHK(nonce != NULL); LTC_ARGCHK(noncelen == 24); if (rounds == 0) rounds = 20; - LTC_ARGCHK(rounds % 2 == 0); /* number of rounds must be evenly divisible by 2 */ + LTC_ARGCHK(rounds % 2 == 0); /* rounds must be evenly divisible by 2 */ /* load the state to "hash" the key */ LOAD32L(x[ 0], constants + 0); @@ -119,7 +121,7 @@ int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long ke st->input[ 9] = 0; st->rounds = rounds; st->ksleft = 0; - st->ivlen = 24; /* set switch to say nonce/IV has been loaded */ + st->status = 3; #ifdef LTC_CLEAN_STACK zeromem(x, sizeof(x)); diff --git a/src/stream/sober128/sober128_stream.c b/src/stream/sober128/sober128_stream.c index 44e0c3278..b5b8188a9 100644 --- a/src/stream/sober128/sober128_stream.c +++ b/src/stream/sober128/sober128_stream.c @@ -152,6 +152,7 @@ static void s128_diffuse(sober128_state *c) DROUND(16); } +/* ======================================================================== */ /** Initialize an Sober128 context (only the key) @param c [out] The destination of the Sober128 state @@ -195,6 +196,7 @@ int sober128_stream_setup(sober128_state *c, const unsigned char *key, unsigned s128_genkonst(c); s128_savestate(c); c->nbuf = 0; + c->status = 1; return CRYPT_OK; } @@ -213,6 +215,7 @@ int sober128_stream_setiv(sober128_state *c, const unsigned char *iv, unsigned l LTC_ARGCHK(c != NULL); LTC_ARGCHK(iv != NULL); LTC_ARGCHK(ivlen > 0); + LTC_ARGCHK(c->status != 0); /* ok we are adding an IV then... */ s128_reloadstate(c); @@ -235,6 +238,7 @@ int sober128_stream_setiv(sober128_state *c, const unsigned char *iv, unsigned l /* now diffuse */ s128_diffuse(c); c->nbuf = 0; + c->status = 2; return CRYPT_OK; } @@ -258,6 +262,7 @@ int sober128_stream_crypt(sober128_state *c, const unsigned char *in, unsigned l if (inlen == 0) return CRYPT_OK; /* nothing to do */ LTC_ARGCHK(out != NULL); LTC_ARGCHK(c != NULL); + LTC_ARGCHK(c->status == 2); /* handle any previously buffered bytes */ while (c->nbuf != 0 && inlen != 0) { diff --git a/src/stream/sosemanuk/sosemanuk.c b/src/stream/sosemanuk/sosemanuk.c index b0838f847..4caa7ecf7 100644 --- a/src/stream/sosemanuk/sosemanuk.c +++ b/src/stream/sosemanuk/sosemanuk.c @@ -10,6 +10,12 @@ /* * This LTC implementation was adapted from: * http://www.ecrypt.eu.org/stream/e2-sosemanuk.html + * + * Sosemanuk specifications require: + * 1- a key of at least 128 bits (16 bytes), not exceeding 256 bits (32 bytes). + * 2- keys < 32 bytes are terminated with 0x01 followed by NULLs as needed. + * 3- an iv of 128 bits (16 bytes). + * See http://www.ecrypt.eu.org/stream/p3ciphers/sosemanuk/sosemanuk_p3.pdf */ /* @@ -195,13 +201,13 @@ /* * Initialize Sosemanuk's state by providing a key. The key is an array of - * 1 to 32 bytes. + * 16 to 32 bytes. * @param ss The Sosemanuk state * @param key Key * @param keylen Length of key in bytes * @return CRYPT_OK on success */ -int sosemanuk_setup(sosemanuk_state *ss, const unsigned char *key, unsigned long keylen) +int sosemanuk_setup(sosemanuk_state *st, const unsigned char *key, unsigned long keylen) { /* * This key schedule is actually a truncated Serpent key schedule. @@ -216,10 +222,10 @@ int sosemanuk_setup(sosemanuk_state *ss, const unsigned char *key, unsigned long r2 = w ## o2; \ r3 = w ## o3; \ S(r0, r1, r2, r3, r4); \ - ss->kc[i ++] = r ## d0; \ - ss->kc[i ++] = r ## d1; \ - ss->kc[i ++] = r ## d2; \ - ss->kc[i ++] = r ## d3; \ + st->kc[i ++] = r ## d0; \ + st->kc[i ++] = r ## d1; \ + st->kc[i ++] = r ## d2; \ + st->kc[i ++] = r ## d3; \ } while (0) #define SKS0 SKS(S0, 4, 5, 6, 7, 1, 4, 2, 0) @@ -255,9 +261,9 @@ int sosemanuk_setup(sosemanuk_state *ss, const unsigned char *key, unsigned long ulong32 w0, w1, w2, w3, w4, w5, w6, w7; int i = 0; - LTC_ARGCHK(ss != NULL); + LTC_ARGCHK(st != NULL); LTC_ARGCHK(key != NULL); - LTC_ARGCHK(keylen > 0 && keylen <= 32); + LTC_ARGCHK(keylen >= 16 && keylen <= 32); /* * The key is copied into the wbuf[] buffer and padded to 256 bits @@ -318,32 +324,31 @@ int sosemanuk_setup(sosemanuk_state *ss, const unsigned char *key, unsigned long #undef WUP0 #undef WUP1 + st->status = 1; /* 0=uninitialized, 1=finished setup(), 2=finished setiv() */ return CRYPT_OK; } /* - * Initialization continues by setting the IV. The IV length is up to 16 bytes. - * If "ivlen" is 0 (no IV), then the "iv" parameter can be NULL. If multiple - * encryptions/decryptions are to be performed with the same key and + * Initialization continues by setting the IV. The IV length is 16 bytes. If + * multiple encryptions/decryptions are to be performed with the same key and * sosemanuk_done() has not been called, only sosemanuk_setiv() need be called * to set the state. - * @param ss The Sosemanuk state + * @param st The Sosemanuk state * @param iv Initialization vector - * @param ivlen Length of iv in bytes * @return CRYPT_OK on success */ -int sosemanuk_setiv(sosemanuk_state *ss, const unsigned char *iv, unsigned long ivlen) +int sosemanuk_setiv(sosemanuk_state *st, const unsigned char *iv, unsigned long ivlen) { /* * The Serpent key addition step. */ #define KA(zc, x0, x1, x2, x3) do { \ - x0 ^= ss->kc[(zc)]; \ - x1 ^= ss->kc[(zc) + 1]; \ - x2 ^= ss->kc[(zc) + 2]; \ - x3 ^= ss->kc[(zc) + 3]; \ + x0 ^= st->kc[(zc)]; \ + x1 ^= st->kc[(zc) + 1]; \ + x2 ^= st->kc[(zc) + 2]; \ + x3 ^= st->kc[(zc) + 3]; \ } while (0) /* @@ -373,11 +378,12 @@ int sosemanuk_setiv(sosemanuk_state *ss, const unsigned char *iv, unsigned long ulong32 r0, r1, r2, r3, r4; unsigned char ivtmp[16] = {0}; - LTC_ARGCHK(ss != NULL); - LTC_ARGCHK(ivlen <= 16); - LTC_ARGCHK(iv != NULL || ivlen == 0); + LTC_ARGCHK(st != NULL); + LTC_ARGCHK(iv != NULL); + LTC_ARGCHK(ivlen == 16); + LTC_ARGCHK(st->status != 0); - if (ivlen > 0) XMEMCPY(ivtmp, iv, ivlen); + XMEMCPY(ivtmp, iv, ivlen); /* * Decode IV into four 32-bit words (little-endian). @@ -403,10 +409,10 @@ int sosemanuk_setiv(sosemanuk_state *ss, const unsigned char *iv, unsigned long FSS(36, S1, 1, 3, 2, 4, 0, 2, 1, 4, 3); FSS(40, S2, 2, 1, 4, 3, 0, 4, 3, 1, 0); FSS(44, S3, 4, 3, 1, 0, 2, 3, 1, 0, 2); - ss->s09 = r3; - ss->s08 = r1; - ss->s07 = r0; - ss->s06 = r2; + st->s09 = r3; + st->s08 = r1; + st->s07 = r0; + st->s06 = r2; FSS(48, S4, 3, 1, 0, 2, 4, 1, 4, 3, 2); FSS(52, S5, 1, 4, 3, 2, 0, 4, 2, 1, 3); @@ -414,10 +420,10 @@ int sosemanuk_setiv(sosemanuk_state *ss, const unsigned char *iv, unsigned long FSS(60, S7, 4, 2, 0, 1, 3, 3, 1, 2, 4); FSS(64, S0, 3, 1, 2, 4, 0, 1, 0, 2, 3); FSS(68, S1, 1, 0, 2, 3, 4, 2, 1, 3, 0); - ss->r1 = r2; - ss->s04 = r1; - ss->r2 = r3; - ss->s05 = r0; + st->r1 = r2; + st->s04 = r1; + st->r2 = r3; + st->s05 = r0; FSS(72, S2, 2, 1, 3, 0, 4, 3, 0, 1, 4); FSS(76, S3, 3, 0, 1, 4, 2, 0, 1, 4, 2); @@ -425,17 +431,18 @@ int sosemanuk_setiv(sosemanuk_state *ss, const unsigned char *iv, unsigned long FSS(84, S5, 1, 3, 0, 2, 4, 3, 2, 1, 0); FSS(88, S6, 3, 2, 1, 0, 4, 3, 2, 4, 1); FSF(92, S7, 3, 2, 4, 1, 0, 0, 1, 2, 3); - ss->s03 = r0; - ss->s02 = r1; - ss->s01 = r2; - ss->s00 = r3; + st->s03 = r0; + st->s02 = r1; + st->s01 = r2; + st->s00 = r3; - ss->ptr = sizeof(ss->buf); + st->ptr = sizeof(st->buf); #undef KA #undef FSS #undef FSF + st->status = 2; /* 0=uninitialized, 1=finished setup(), 2=finished setiv() */ return CRYPT_OK; } @@ -584,7 +591,7 @@ static const ulong32 mul_ia[] = { * Compute the next block of bits of output stream. This is equivalent * to one full rotation of the shift register. */ -static LTC_INLINE void _sosemanuk_internal(sosemanuk_state *ss) +static LTC_INLINE void _sosemanuk_internal(sosemanuk_state *st) { /* * MUL_A(x) computes alpha * x (in F_{2^32}). @@ -655,24 +662,24 @@ static LTC_INLINE void _sosemanuk_internal(sosemanuk_state *ss) */ #define SRD(S, x0, x1, x2, x3, ooff) do { \ S(u0, u1, u2, u3, u4); \ - STORE32L(u ## x0 ^ v0, ss->buf + ooff); \ - STORE32L(u ## x1 ^ v1, ss->buf + ooff + 4); \ - STORE32L(u ## x2 ^ v2, ss->buf + ooff + 8); \ - STORE32L(u ## x3 ^ v3, ss->buf + ooff + 12); \ + STORE32L(u ## x0 ^ v0, st->buf + ooff); \ + STORE32L(u ## x1 ^ v1, st->buf + ooff + 4); \ + STORE32L(u ## x2 ^ v2, st->buf + ooff + 8); \ + STORE32L(u ## x3 ^ v3, st->buf + ooff + 12); \ } while (0) - ulong32 s00 = ss->s00; - ulong32 s01 = ss->s01; - ulong32 s02 = ss->s02; - ulong32 s03 = ss->s03; - ulong32 s04 = ss->s04; - ulong32 s05 = ss->s05; - ulong32 s06 = ss->s06; - ulong32 s07 = ss->s07; - ulong32 s08 = ss->s08; - ulong32 s09 = ss->s09; - ulong32 r1 = ss->r1; - ulong32 r2 = ss->r2; + ulong32 s00 = st->s00; + ulong32 s01 = st->s01; + ulong32 s02 = st->s02; + ulong32 s03 = st->s03; + ulong32 s04 = st->s04; + ulong32 s05 = st->s05; + ulong32 s06 = st->s06; + ulong32 s07 = st->s07; + ulong32 s08 = st->s08; + ulong32 s09 = st->s09; + ulong32 r1 = st->r1; + ulong32 r2 = st->r2; ulong32 u0, u1, u2, u3, u4; ulong32 v0, v1, v2, v3; @@ -702,18 +709,18 @@ static LTC_INLINE void _sosemanuk_internal(sosemanuk_state *ss) STEP(09, 00, 01, 02, 03, 04, 05, 06, 07, 08, v3, u3); SRD(S2, 2, 3, 1, 4, 64); - ss->s00 = s00; - ss->s01 = s01; - ss->s02 = s02; - ss->s03 = s03; - ss->s04 = s04; - ss->s05 = s05; - ss->s06 = s06; - ss->s07 = s07; - ss->s08 = s08; - ss->s09 = s09; - ss->r1 = r1; - ss->r2 = r2; + st->s00 = s00; + st->s01 = s01; + st->s02 = s02; + st->s03 = s03; + st->s04 = s04; + st->s05 = s05; + st->s06 = s06; + st->s07 = s07; + st->s08 = s08; + st->s09 = s09; + st->r1 = r1; + st->r2 = r2; } /* @@ -735,40 +742,41 @@ static LTC_INLINE void _xorbuf(const unsigned char *in1, const unsigned char *in * buffer, combined by XOR with the stream, and the result is written * in the "out" buffer. "in" and "out" must be either equal, or * reference distinct buffers (no partial overlap is allowed). - * @param ss The Sosemanuk state + * @param st The Sosemanuk state * @param in Data in * @param inlen Length of data in bytes * @param out Data out * @return CRYPT_OK on success */ -int sosemanuk_crypt(sosemanuk_state *ss, +int sosemanuk_crypt(sosemanuk_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out) { - LTC_ARGCHK(ss != NULL); + LTC_ARGCHK(st != NULL); LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); + LTC_ARGCHK(st->status == 2); - if (ss->ptr < (sizeof(ss->buf))) { - unsigned long rlen = (sizeof(ss->buf)) - ss->ptr; + if (st->ptr < (sizeof(st->buf))) { + unsigned long rlen = (sizeof(st->buf)) - st->ptr; if (rlen > inlen) rlen = inlen; - _xorbuf(ss->buf + ss->ptr, in, out, rlen); + _xorbuf(st->buf + st->ptr, in, out, rlen); in += rlen; out += rlen; inlen -= rlen; - ss->ptr += rlen; + st->ptr += rlen; } while (inlen > 0) { - _sosemanuk_internal(ss); - if (inlen >= sizeof(ss->buf)) { - _xorbuf(ss->buf, in, out, sizeof(ss->buf)); - in += sizeof(ss->buf); - out += sizeof(ss->buf); - inlen -= sizeof(ss->buf); + _sosemanuk_internal(st); + if (inlen >= sizeof(st->buf)) { + _xorbuf(st->buf, in, out, sizeof(st->buf)); + in += sizeof(st->buf); + out += sizeof(st->buf); + inlen -= sizeof(st->buf); } else { - _xorbuf(ss->buf, in, out, inlen); - ss->ptr = inlen; + _xorbuf(st->buf, in, out, inlen); + st->ptr = inlen; inlen = 0; } } @@ -780,29 +788,29 @@ int sosemanuk_crypt(sosemanuk_state *ss, /* * Cipher operation, as a PRNG: the provided output buffer is filled with * pseudo-random bytes as output from the stream cipher. - * @param ss The Sosemanuk state + * @param st The Sosemanuk state * @param out Data out * @param outlen Length of output in bytes * @return CRYPT_OK on success */ -int sosemanuk_keystream(sosemanuk_state *ss, unsigned char *out, unsigned long outlen) +int sosemanuk_keystream(sosemanuk_state *st, unsigned char *out, unsigned long outlen) { if (outlen == 0) return CRYPT_OK; /* nothing to do */ LTC_ARGCHK(out != NULL); XMEMSET(out, 0, outlen); - return sosemanuk_crypt(ss, out, outlen, out); + return sosemanuk_crypt(st, out, outlen, out); } /* * Terminate and clear Sosemanuk key context - * @param ss The Sosemanuk state + * @param st The Sosemanuk state * @return CRYPT_OK on success */ -int sosemanuk_done(sosemanuk_state *ss) +int sosemanuk_done(sosemanuk_state *st) { - LTC_ARGCHK(ss != NULL); - XMEMSET(ss, 0, sizeof(sosemanuk_state)); + LTC_ARGCHK(st != NULL); + XMEMSET(st, 0, sizeof(sosemanuk_state)); return CRYPT_OK; } diff --git a/src/stream/sosemanuk/sosemanuk_test.c b/src/stream/sosemanuk/sosemanuk_test.c index e5514df10..8eb68b400 100644 --- a/src/stream/sosemanuk/sosemanuk_test.c +++ b/src/stream/sosemanuk/sosemanuk_test.c @@ -38,7 +38,7 @@ int sosemanuk_test(void) if ((err = sosemanuk_crypt(&ss, (unsigned char*)pt + 40, len - 40, out + 40)) != CRYPT_OK) return err; if (compare_testvector(out, len, ct, sizeof(ct), "SOSEMANUK-TV1", 1)) return CRYPT_FAIL_TESTVECTOR; - /* crypt in one go - using sosemanuk_ivctr64() */ + /* crypt in one go - using sosemanuk_setiv() */ if ((err = sosemanuk_setup(&ss, k, sizeof(k))) != CRYPT_OK) return err; if ((err = sosemanuk_setiv(&ss, n, sizeof(n))) != CRYPT_OK) return err; if ((err = sosemanuk_crypt(&ss, (unsigned char*)pt, len, out)) != CRYPT_OK) return err;