/* spritz++, C++ header-only implementation * * Copyright (c) 2015 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License ("GPL") version 2 or any later version, * in which case the provisions of the GPL are applicable instead of * the above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the BSD license, indicate your decision * by deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file under * either the BSD or the GPL. */ #include #include #include struct spritz { enum { N = 256 }; uint8_t a, i, j, k, z, w; uint8_t s[N]; // helper to reduce index to uint8_t uint8_t &S (uint8_t i) { return s[i]; } spritz () { a = i = j = k = z = 0; w = 1; uint_fast8_t v = N - 1; do S(v) = v; while (v--); } void update () { i += w; j = k + S(j + S(i)); k = k + i + S(j); swap (S(i), S(j)); } void whip (uint_fast16_t r) { while (r--) update (); w += 2; } static void swap (uint8_t &a, uint8_t &b) { uint8_t c = a; a = b; b = c; } void crush () { for (uint_fast16_t v = 0; v < (N >> 1); ++v) if (S(v) > S(N - 1 - v)) swap (S(v), S(N - 1 - v)); } void shuffle () { whip (2 * N); crush (); whip (2 * N); crush (); whip (2 * N); a = 0; } void shuffle_absorb () { if (a == (N >> 1)) shuffle (); } void absorb_nibble (uint8_t x) { shuffle_absorb (); swap (S(a), S((N >> 1) + x)); ++a; } void absorb_byte (uint8_t b) { absorb_nibble (b & 15); absorb_nibble (b >> 4); } void absorb (const void *I, size_t I_len) { uint8_t *i = (uint8_t *)I; while (I_len--) absorb_byte (*i++); } void absorb_stop () { shuffle_absorb (); ++a; } // commonly used helper function void absorb_stop (const void *I, size_t I_len) { absorb (I, I_len); absorb_stop (); } void shuffle_squeeze () { if (a) shuffle (); } uint8_t output () { return z = S(j + S(i + S(z + k))); } // slightly faster internal helper, drip without squeeze preparation uint8_t drip_nosqueeze () { update (); return output (); } void squeeze (void *P, size_t P_len) { shuffle_squeeze (); uint8_t *p = (uint8_t *)P; while (P_len--) *p++ = drip_nosqueeze (); } uint8_t drip () { shuffle_squeeze (); return drip_nosqueeze (); } }; // what follows is wrappers that make using spritz easier and less error-prone // spritz-xor variant of cipher struct spritz_xor : protected spritz { // key K required, IV optional spritz_xor (const void *K, size_t K_len, const void *IV = 0, size_t IV_len = 0) { absorb (K, K_len); if (IV) { absorb_stop (); absorb (IV, IV_len); } shuffle_squeeze (); } // can be called multiple times/incrementally // can work inplace // works for both encryption and decryption void crypt (const void *I, void *O, size_t len) { const uint8_t *i = (const uint8_t *)I; uint8_t *o = ( uint8_t *)O; while (len--) *o++ = *i++ ^ drip_nosqueeze (); } }; struct spritz_hash : protected spritz { spritz_hash () { } // can be called multiple times/incrementally void add (const void *M, size_t M_len) { absorb (M, M_len); } // must be called at most once at the end void hash (void *H, size_t H_len) { absorb_stop (); assert (H_len <= 0xff); absorb_byte (H_len); squeeze (H, H_len); } }; struct spritz_mac : protected spritz_hash { spritz_mac (const void *K, size_t K_len) { absorb_stop (K, K_len); } // use add to incrementally add data using spritz_hash::add; // must be called at most once at the end void mac (void *H, size_t H_len) { hash (H, H_len); } }; struct spritz_aead : protected spritz_mac { spritz_aead (const void *K, size_t K_len) : spritz_mac (K, K_len) { } // must be called after construction, before data void nonce (const void *N, size_t N_len) { absorb_stop (N, N_len); } // must be called after nonce, before crypt void associated_data (const void *D, size_t D_len) { absorb_stop (D, D_len); } // must be called after data, only once, before mac // works for both encryption and decryption void crypt (const void *I, void *O, size_t len) { const uint8_t *i = (const uint8_t *)I; uint8_t *o = ( uint8_t *)O; uint8_t x[N >> 2]; while (len) { uint8_t l = len > sizeof (x) ? sizeof (x) : len; len -= l; squeeze (x, l); for (uint_fast8_t j = 0; j < l; ++j) absorb_byte (*o++ = *i++ ^ x[j]); } } // call mac() at most once at the end using spritz_mac::mac; }; struct spritz_prng : protected spritz { // seed optional, can be done via put spritz_prng (const void *S = 0, size_t S_len = 0) { absorb (S, S_len); } // add additional entropy void add (const void *S, size_t S_len) { absorb (S, S_len); } // get random bytes void get (void *R, size_t R_len) { squeeze (R, R_len); } };