encrypt.c 5.44 KB
Newer Older
lwc-tester committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
#include "api.h"
#include <stdint.h>
#define OCS(a, b) a += (b) + (a + (b) < a ? 1 : 0)  // 1s complement sum
#define Swap(a, b) (a ^= b, b ^= a, a ^= b)
//---------------------------------------------------------------------- Bleep64
inline int Bleep64(B_iv, B_key, B_pt, B_ct, B_ad, adlen, inlen, outlen, encrypt)
  unsigned char *B_iv;        // pointer to initialization vector
  unsigned char *B_key;       // pointer to key
  unsigned char *B_pt, *B_ct; // plaintext and ciphertext pointers respectively
  unsigned char *B_ad;        // pointer to associated data
  int32_t       adlen, inlen; // number of bytes in associated date, and input
  int32_t       *outlen;      // number of bytes in output
  char          encrypt;      // 0 means decrypt, else encrypt
  // local variables
{ register uint32_t t, u;    // short-term temporaries
  register uint32_t x, y;    // auto-key and LFSR filter state
  register uint64_t L0, L1;  // LFSR x^127 + x^63 + 1, left-justified
  register int32_t n;        // byte to process
  uint32_t *iv, *key, *pt, *ct, *ad;    // word casts of byte pointers
  unsigned char *bpt, *bct, *bad; // byte sized pointers for remainders
  unsigned char valid[CRYPTO_ABYTES + 8] = {0}; // buffer for extra validation data

  inline void crypt(char odd, char assoc) // do one word & update crypto state
  { t = (((uint64_t)x * y) >> 32) - (x * y);  // filter LFSR, diffuse autokey
    if (assoc)        u = *ad++ ^ t;  
    else if (encrypt) u = *pt++ ^ t, *ct++ = u + (L0 >> 32*odd);
    else              u = *ct++ - (L0 >> 32*odd), *pt++ = u ^ t;
    if (odd) OCS(y, u), OCS(x, L1 >> 32);      // feedback from 1st half of loop
    else     OCS(x, u), OCS(y, L1 & 0xFFFF);   // feedback from 2nd half of loop
    if (odd || y >> 31) L1 |= (L0 ^ L1) >> 63, L0 = (L0 ^ L1) << 1, Swap(L0,L1); }

  // casting kludges
  iv  = (uint32_t*)B_iv;  // word pointer to initialization vector
  key = (uint32_t*)B_key; // word pointer to key
  pt  = (uint32_t*)B_pt;  // plaintext word pointer
  ct  = (uint32_t*)B_ct;  // ciphertext word pointer
  ad  = (uint32_t*)B_ad;  // word pointer to associated data
  // IV processing
  t  = key[0] * (iv[0] + key[4]);
  u  = key[1] * (iv[1] + t);
  L0 = key[2] * (iv[2] + u);
  L1 = key[3] * (iv[0] + (L0 & 0xFFFF));
  x  = key[0] * (iv[1] + (L1 & 0xFFFF));
  y  = key[1] * (iv[2] + x);
  L0 = ((uint64_t) t << 32) | (L0 & 0xFFFF);   OCS(x, 1);   // x != 0
  L1 = ((uint64_t) u << 32) | x;               OCS(y, x);   // L1 != 0, y != 0
  // process associated data
  n = adlen;
  while ( (n -= 8) >= 0 ) { crypt(1, 1); crypt(0, 1); } // do 8 bytes per loop
  if (n > -5) crypt(1, 1);  // if 4 to 7 bytes left, do another full word
  for (n &= 3, bad = (unsigned char *) ad; n--; OCS(x, *bad), bad++);   // do last 1 to 3 bytes
  // do en/de-cryption; decryption needs to end sooner due to validation data
  n = inlen - (encrypt? 0 : CRYPTO_ABYTES);
  while ( (n -= 8) >= 0 ) { crypt(1, 0); crypt(0, 0); } // do 8 bytes per loop
  if (encrypt) {
    // Copy last n bytes to buffer and encrypt from there instead
    bpt = (unsigned char *) pt;
    for (n = 0; n < (inlen % 8); n++) valid[n] = bpt[n];
    pt = (uint32_t *) valid; // use the buffer for pt instead
    n = (inlen % 8) + CRYPTO_ABYTES; 
    while ( (n -= 8) >= 0 ) { crypt(1, 0); crypt(0, 0); } // do 8 bytes per loop
  } else {
    // Switch to decrypting into our buffer, B_pt is about to run out of space
    pt = (uint32_t *) valid;
    n = (inlen % 8) + CRYPTO_ABYTES;
    while ( (n -= 8) >= 0 ) { crypt(1, 0); crypt(0, 0); } // do 8 bytes per loop
  }
  if (n > -5) crypt(1, 0);  // if 4 to 7 bytes left, do another full word
  t = (((uint64_t)x * y) >> 32) - (x * y);  // filter LFSR and diffuse autokey
  bpt = (unsigned char *) pt; bct = (unsigned char *) ct; // need char sized pointers
  for (n &= 3; n--;)   // do last 1 to 3 bytes little-endian
    if (encrypt) *bct++ = (char) (*bpt++ ^ (t >> 8*(3-n))) + (L0 >> 8*(3-n));
    else         *bpt++ = (char) (*bct++ - (L0 >> 8*(3-n))) ^ (t >> 8*(3-n));
  if (encrypt) *outlen = inlen + CRYPTO_ABYTES;
  else {
    *outlen = inlen - CRYPTO_ABYTES;
    // Copy first few bytes from the temp buffer to the end of the real one
    bpt = B_pt + (((inlen-CRYPTO_ABYTES)/8) * 8);
    for (n = 0; n < (inlen % 8); n++) bpt[n] = valid[n];
    // And the rest should be zeros
    for (n = 0; n < CRYPTO_ABYTES; n++) if (valid[n+(inlen%8)]) return -1;
  }
  return 0;}
//---------------------------------------------------------------------- encrypt
int crypto_aead_encrypt(unsigned char *c,        unsigned long long *clen,
                        const unsigned char *m,  unsigned long long mlen,
                        const unsigned char *ad, unsigned long long adlen,
                        const unsigned char *nsec,
                        const unsigned char *npub,
                        const unsigned char *k)
{ return Bleep64(npub, k, m, c, ad, adlen, mlen, clen, 1); }
//---------------------------------------------------------------------- decrypt
int crypto_aead_decrypt(unsigned char *m,        unsigned long long *mlen,
                        unsigned char *nsec,
                        const unsigned char *c,  unsigned long long clen,
                        const unsigned char *ad, unsigned long long adlen,
                        const unsigned char *npub,
                        const unsigned char *k)
{ return Bleep64(npub, k, m, c, ad, adlen, clen, mlen, 0); }