/* Having accumulated a MAC, finish processing and return it */ void s128_finish(s128_ctx *c, UCHAR *buf, int nbytes) { UCHAR *endbuf; WORD t = 0; if ((nbytes & 3) != 0) abort(); /* perturb the state to mark end of input -- sort of like adding more key */ ADDKEY(INITKONST); cycle(c->R); XORNL(nltap(c)); s128_diffuse(c); /* don't bother optimising this loop, because it's a state * of delusion to generate more than N words of MAC. */ endbuf = &buf[nbytes]; while (buf < endbuf) { cycle(c->R); t = nltap(c); WORD2BYTE(t, buf); buf += 4; } }
/** Add entropy to the PRNG state @param in The data to add @param inlen Length of the data to add @param prng PRNG state to update @return CRYPT_OK if successful */ int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) { struct sober128_prng *c; ulong32 i, k; LTC_ARGCHK(in != NULL); LTC_ARGCHK(prng != NULL); c = &(prng->sober128); if (c->flag == 1) { /* this is the first call to the add_entropy so this input is the key */ /* inlen must be multiple of 4 bytes */ if ((inlen & 3) != 0) { return CRYPT_INVALID_KEYSIZE; } for (i = 0; i < inlen; i += 4) { k = BYTE2WORD((unsigned char *)&in[i]); ADDKEY(k); cycle(c->R); XORNL(nltap(c)); } /* also fold in the length of the key */ ADDKEY(inlen); /* now diffuse */ s128_diffuse(c); s128_genkonst(c); s128_savestate(c); c->nbuf = 0; c->flag = 0; c->set = 1; } else { /* ok we are adding an IV then... */ s128_reloadstate(c); /* inlen must be multiple of 4 bytes */ if ((inlen & 3) != 0) { return CRYPT_INVALID_KEYSIZE; } for (i = 0; i < inlen; i += 4) { k = BYTE2WORD((unsigned char *)&in[i]); ADDKEY(k); cycle(c->R); XORNL(nltap(c)); } /* also fold in the length of the key */ ADDKEY(inlen); /* now diffuse */ s128_diffuse(c); c->nbuf = 0; } return CRYPT_OK; }
unsigned long sober128_read(unsigned char *buf, unsigned long nbytes, sober128_prng *c) { ulong32 t, tlen; tlen = nbytes; /* handle any previously buffered bytes */ while (c->nbuf != 0 && nbytes != 0) { *buf++ ^= c->sbuf & 0xFF; c->sbuf >>= 8; c->nbuf -= 8; --nbytes; } #ifndef SMALL_CODE /* do lots at a time, if there's enough to do */ while (nbytes >= N*4) { SROUND(0); SROUND(1); SROUND(2); SROUND(3); SROUND(4); SROUND(5); SROUND(6); SROUND(7); SROUND(8); SROUND(9); SROUND(10); SROUND(11); SROUND(12); SROUND(13); SROUND(14); SROUND(15); SROUND(16); buf += 4*N; nbytes -= 4*N; } #endif /* do small or odd size buffers the slow way */ while (4 <= nbytes) { cycle(c->R); t = nltap(c); XORWORD(t, buf); buf += 4; nbytes -= 4; } /* handle any trailing bytes */ if (nbytes != 0) { cycle(c->R); c->sbuf = nltap(c); c->nbuf = 32; while (c->nbuf != 0 && nbytes != 0) { *buf++ ^= c->sbuf & 0xFF; c->sbuf >>= 8; c->nbuf -= 8; --nbytes; } }
int sober128_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng) { struct sober128_prng *c; ulong32 i, k; c = &(prng->sober128); if (c->flag == 1) { /* this is the first call to the add_entropy so this input is the key */ /* len must be multiple of 4 bytes */ assert ((len & 3) == 0); for (i = 0; i < len; i += 4) { k = BYTE2WORD(&buf[i]); ADDKEY(k); cycle(c->R); XORNL(nltap(c)); } /* also fold in the length of the key */ ADDKEY(len); /* now diffuse */ s128_diffuse(c); s128_genkonst(c); s128_savestate(c); c->nbuf = 0; c->flag = 0; c->set = 1; } else { /* ok we are adding an IV then... */ s128_reloadstate(c); /* len must be multiple of 4 bytes */ assert ((len & 3) == 0); for (i = 0; i < len; i += 4) { k = BYTE2WORD(&buf[i]); ADDKEY(k); cycle(c->R); XORNL(nltap(c)); } /* also fold in the length of the key */ ADDKEY(len); /* now diffuse */ s128_diffuse(c); c->nbuf = 0; } return CRYPT_OK; }
/** Set IV to the Sober128 state @param c The Sober12820 state @param iv The IV data to add @param ivlen The length of the IV (must be 12) @return CRYPT_OK on success */ int sober128_stream_setiv(sober128_state *c, const unsigned char *iv, unsigned long ivlen) { ulong32 i, k; LTC_ARGCHK(c != NULL); LTC_ARGCHK(iv != NULL); LTC_ARGCHK(ivlen > 0); /* ok we are adding an IV then... */ s128_reloadstate(c); /* ivlen must be multiple of 4 bytes */ if ((ivlen & 3) != 0) { return CRYPT_INVALID_KEYSIZE; } for (i = 0; i < ivlen; i += 4) { k = BYTE2WORD((unsigned char *)&iv[i]); ADDKEY(k); cycle(c->R); XORNL(nltap(c)); } /* also fold in the length of the key */ ADDKEY(ivlen); /* now diffuse */ s128_diffuse(c); c->nbuf = 0; return CRYPT_OK; }
/* Initialise "konst" */ static void s128_genkonst(struct sober128_prng *c) { ulong32 newkonst; do { cycle(c->R); newkonst = nltap(c); } while ((newkonst & 0xFF000000) == 0); c->konst = newkonst; }
/* Initialise "konst" */ static void s128_genkonst(s128_ctx *c) { WORD newkonst; do { cycle(c->R); newkonst = nltap(c); } while ((newkonst & 0xFF000000) == 0); c->konst = newkonst; }
void s128_decrypt(s128_ctx *c, UCHAR *buf, int nbytes) { UCHAR *endbuf; WORD t = 0; if ((nbytes & 3) != 0) abort(); endbuf = &buf[nbytes]; /* do small or odd size buffers the slow way, at least at first */ while ((nbytes % (N*4)) != 0) { cycle(c->R); t = nltap(c); t ^= BYTE2WORD(buf); macfunc(c, t); WORD2BYTE(t, buf); nbytes -= 4; buf += 4; } /* now do lots at a time, if there's any left */ while (buf < endbuf) { DROUND(0); DROUND(1); DROUND(2); DROUND(3); DROUND(4); DROUND(5); DROUND(6); DROUND(7); DROUND(8); DROUND(9); DROUND(10); DROUND(11); DROUND(12); DROUND(13); DROUND(14); DROUND(15); DROUND(16); buf += 4*17; } }
/** Initialize an Sober128 context (only the key) @param c [out] The destination of the Sober128 state @param key The secret key @param keylen The length of the secret key (octets) @return CRYPT_OK if successful */ int sober128_stream_setup(sober128_state *c, const unsigned char *key, unsigned long keylen) { ulong32 i, k; LTC_ARGCHK(c != NULL); LTC_ARGCHK(key != NULL); LTC_ARGCHK(keylen > 0); /* keylen must be multiple of 4 bytes */ if ((keylen & 3) != 0) { return CRYPT_INVALID_KEYSIZE; } /* Register initialised to Fibonacci numbers */ c->R[0] = 1; c->R[1] = 1; for (i = 2; i < N; ++i) { c->R[i] = c->R[i-1] + c->R[i-2]; } c->konst = INITKONST; for (i = 0; i < keylen; i += 4) { k = BYTE2WORD((unsigned char *)&key[i]); ADDKEY(k); cycle(c->R); XORNL(nltap(c)); } /* also fold in the length of the key */ ADDKEY(keylen); /* now diffuse */ s128_diffuse(c); s128_genkonst(c); s128_savestate(c); c->nbuf = 0; return CRYPT_OK; }
static void s128_loadkey(s128_ctx *c, UCHAR key[], int keylen) { int i; WORD k; /* start folding in key, reject odd sized keys */ if ((keylen & 3) != 0) abort(); for (i = 0; i < keylen; i += 4) { k = BYTE2WORD(&key[i]); ADDKEY(k); cycle(c->R); XORNL(nltap(c)); } /* also fold in the length of the key */ ADDKEY(keylen); /* now diffuse */ s128_diffuse(c); }
/** Read from the PRNG @param out Destination @param outlen Length of output @param prng The active PRNG to read from @return Number of octets read */ unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng) { struct sober128_prng *c; ulong32 t, tlen; LTC_ARGCHK(out != NULL); LTC_ARGCHK(prng != NULL); #ifdef LTC_VALGRIND zeromem(out, outlen); #endif c = &(prng->sober128); t = 0; tlen = outlen; /* handle any previously buffered bytes */ while (c->nbuf != 0 && outlen != 0) { *out++ ^= c->sbuf & 0xFF; c->sbuf >>= 8; c->nbuf -= 8; --outlen; } #ifndef LTC_SMALL_CODE /* do lots at a time, if there's enough to do */ while (outlen >= N*4) { SROUND(0); SROUND(1); SROUND(2); SROUND(3); SROUND(4); SROUND(5); SROUND(6); SROUND(7); SROUND(8); SROUND(9); SROUND(10); SROUND(11); SROUND(12); SROUND(13); SROUND(14); SROUND(15); SROUND(16); out += 4*N; outlen -= 4*N; } #endif /* do small or odd size buffers the slow way */ while (4 <= outlen) { cycle(c->R); t = nltap(c); XORWORD(t, out); out += 4; outlen -= 4; } /* handle any trailing bytes */ if (outlen != 0) { cycle(c->R); c->sbuf = nltap(c); c->nbuf = 32; while (c->nbuf != 0 && outlen != 0) { *out++ ^= c->sbuf & 0xFF; c->sbuf >>= 8; c->nbuf -= 8; --outlen; } }
/** Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Sober128 @param c The Sober128 state @param in The plaintext (or ciphertext) @param inlen The length of the input (octets) @param out [out] The ciphertext (or plaintext), length inlen @return CRYPT_OK if successful */ int sober128_stream_crypt(sober128_state *c, const unsigned char *in, unsigned long inlen, unsigned char *out) { ulong32 t; if (inlen == 0) return CRYPT_OK; /* nothing to do */ LTC_ARGCHK(out != NULL); LTC_ARGCHK(c != NULL); /* handle any previously buffered bytes */ while (c->nbuf != 0 && inlen != 0) { *out++ = *in++ ^ (unsigned char)(c->sbuf & 0xFF); c->sbuf >>= 8; c->nbuf -= 8; --inlen; } #ifndef LTC_SMALL_CODE /* do lots at a time, if there's enough to do */ while (inlen >= N*4) { SROUND(0); SROUND(1); SROUND(2); SROUND(3); SROUND(4); SROUND(5); SROUND(6); SROUND(7); SROUND(8); SROUND(9); SROUND(10); SROUND(11); SROUND(12); SROUND(13); SROUND(14); SROUND(15); SROUND(16); out += 4*N; in += 4*N; inlen -= 4*N; } #endif /* do small or odd size buffers the slow way */ while (4 <= inlen) { cycle(c->R); t = nltap(c); XORWORD(t, in, out); out += 4; in += 4; inlen -= 4; } /* handle any trailing bytes */ if (inlen != 0) { cycle(c->R); c->sbuf = nltap(c); c->nbuf = 32; while (c->nbuf != 0 && inlen != 0) { *out++ = *in++ ^ (unsigned char)(c->sbuf & 0xFF); c->sbuf >>= 8; c->nbuf -= 8; --inlen; } }