busybox/networking/tls_aesgcm.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2018 Denys Vlasenko
   3 *
   4 * Licensed under GPLv2, see file LICENSE in this source tree.
   5 */
   6
   7#include "tls.h"
   8
   9typedef uint8_t byte;
  10typedef uint32_t word32;
  11#define XMEMSET memset
  12#define XMEMCPY memcpy
  13
  14/* from wolfssl-3.15.3/wolfcrypt/src/aes.c */
  15
  16#ifdef UNUSED
  17static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz)
  18{
  19    /* Multiply the sz by 8 */
  20//bbox: these sizes are never even close to 2^32/8
  21//    word32 szHi = (sz >> (8*sizeof(sz) - 3));
  22    sz <<= 3;
  23
  24    /* copy over the words of the sz into the destination buffer */
  25//    buf[0] = (szHi >> 24) & 0xff;
  26//    buf[1] = (szHi >> 16) & 0xff;
  27//    buf[2] = (szHi >>  8) & 0xff;
  28//    buf[3] = szHi & 0xff;
  29    *(uint32_t*)(buf + 0) = 0;
  30//    buf[4] = (sz >> 24) & 0xff;
  31//    buf[5] = (sz >> 16) & 0xff;
  32//    buf[6] = (sz >>  8) & 0xff;
  33//    buf[7] = sz & 0xff;
  34    *(uint32_t*)(buf + 4) = SWAP_BE32(sz);
  35}
  36#endif
  37
  38static void RIGHTSHIFTX(byte* x)
  39{
  40#define l ((unsigned long*)x)
  41#if 0
  42
  43    // Generic byte-at-a-time algorithm
  44    int i;
  45    byte carryIn = (x[15] & 0x01) ? 0xE1 : 0;
  46    for (i = 0; i < AES_BLOCK_SIZE; i++) {
  47        byte carryOut = (x[i] << 7); // zero, or 0x80
  48        x[i] = (x[i] >> 1) ^ carryIn;
  49        carryIn = carryOut;
  50    }
  51
  52#elif BB_BIG_ENDIAN
  53
  54    // Big-endian can shift-right in larger than byte chunks
  55    // (we use the fact that 'x' is long-aligned)
  56    unsigned long carryIn = (x[15] & 0x01)
  57        ? ((unsigned long)0xE1 << (LONG_BIT-8))
  58        : 0;
  59# if ULONG_MAX <= 0xffffffff
  60    int i;
  61    for (i = 0; i < AES_BLOCK_SIZE/sizeof(long); i++) {
  62        unsigned long carryOut = l[i] << (LONG_BIT-1); // zero, or 0x800..00
  63        l[i] = (l[i] >> 1) ^ carryIn;
  64        carryIn = carryOut;
  65    }
  66# else
  67    // 64-bit code: need to process only 2 words
  68    unsigned long carryOut = l[0] << (LONG_BIT-1); // zero, or 0x800..00
  69    l[0] = (l[0] >> 1) ^ carryIn;
  70    l[1] = (l[1] >> 1) ^ carryOut;
  71# endif
  72
  73#else /* LITTLE_ENDIAN */
  74
  75    // In order to use word-sized ops, little-endian needs to byteswap.
  76    // On x86, code size increase is ~10 bytes compared to byte-by-byte.
  77    unsigned long carryIn = (x[15] & 0x01)
  78        ? ((unsigned long)0xE1 << (LONG_BIT-8))
  79        : 0;
  80# if ULONG_MAX <= 0xffffffff
  81    int i;
  82    for (i = 0; i < AES_BLOCK_SIZE/sizeof(long); i++) {
  83        unsigned long ti = SWAP_BE32(l[i]);
  84        unsigned long carryOut = ti << (LONG_BIT-1); // zero, or 0x800..00
  85        ti = (ti >> 1) ^ carryIn;
  86        l[i] = SWAP_BE32(ti);
  87        carryIn = carryOut;
  88    }
  89# else
  90    // 64-bit code: need to process only 2 words
  91    unsigned long tt = SWAP_BE64(l[0]);
  92    unsigned long carryOut = tt << (LONG_BIT-1); // zero, or 0x800..00
  93    tt = (tt >> 1) ^ carryIn; l[0] = SWAP_BE64(tt);
  94    tt = SWAP_BE64(l[1]);
  95    tt = (tt >> 1) ^ carryOut; l[1] = SWAP_BE64(tt);
  96# endif
  97
  98#endif /* LITTLE_ENDIAN */
  99#undef l
 100}
 101
 102// Caller guarantees X is aligned
 103static void GMULT(byte* X, byte* Y)
 104{
 105    byte Z[AES_BLOCK_SIZE] ALIGNED_long;
 106    //byte V[AES_BLOCK_SIZE] ALIGNED_long;
 107    int i;
 108
 109    XMEMSET(Z, 0, AES_BLOCK_SIZE);
 110    //XMEMCPY(V, X, AES_BLOCK_SIZE);
 111    for (i = 0; i < AES_BLOCK_SIZE; i++) {
 112        uint32_t y = 0x800000 | Y[i];
 113        for (;;) { // for every bit in Y[i], from msb to lsb
 114            if (y & 0x80) {
 115                xorbuf_aligned_AES_BLOCK_SIZE(Z, X); // was V, not X
 116            }
 117            RIGHTSHIFTX(X); // was V, not X
 118            y = y << 1;
 119            if ((int32_t)y < 0) // if bit 0x80000000 set = if 8 iterations done
 120                break;
 121        }
 122    }
 123    XMEMCPY(X, Z, AES_BLOCK_SIZE);
 124}
 125
 126//bbox:
 127// for TLS AES-GCM, a (which is AAD) is always 13 bytes long, and bbox code provides
 128// extra 3 zeroed bytes, making it a[16], or a[AES_BLOCK_SIZE].
 129// Resulting auth tag in s[] is also always AES_BLOCK_SIZE bytes.
 130//
 131// This allows some simplifications.
 132#define aSz 13
 133#define sSz AES_BLOCK_SIZE
 134void FAST_FUNC aesgcm_GHASH(byte* h,
 135    const byte* a, //unsigned aSz,
 136    const byte* c, unsigned cSz,
 137    byte* s //, unsigned sSz
 138)
 139{
 140    byte x[AES_BLOCK_SIZE] ALIGNED_long;
 141//    byte scratch[AES_BLOCK_SIZE] ALIGNED_long;
 142    unsigned blocks, partial;
 143    //was: byte* h = aes->H;
 144
 145    //XMEMSET(x, 0, AES_BLOCK_SIZE);
 146
 147    /* Hash in A, the Additional Authentication Data */
 148//    if (aSz != 0 && a != NULL) {
 149//        blocks = aSz / AES_BLOCK_SIZE;
 150//        partial = aSz % AES_BLOCK_SIZE;
 151//        while (blocks--) {
 152            //xorbuf(x, a, AES_BLOCK_SIZE);
 153            XMEMCPY(x, a, AES_BLOCK_SIZE);// memcpy(x,a) = memset(x,0)+xorbuf(x,a)
 154            GMULT(x, h);
 155//            a += AES_BLOCK_SIZE;
 156//        }
 157//        if (partial != 0) {
 158//            XMEMSET(scratch, 0, AES_BLOCK_SIZE);
 159//            XMEMCPY(scratch, a, partial);
 160//            xorbuf(x, scratch, AES_BLOCK_SIZE);
 161//            GMULT(x, h);
 162//        }
 163//    }
 164
 165    /* Hash in C, the Ciphertext */
 166    if (cSz != 0 /*&& c != NULL*/) {
 167        blocks = cSz / AES_BLOCK_SIZE;
 168        partial = cSz % AES_BLOCK_SIZE;
 169        while (blocks--) {
 170            if (BB_UNALIGNED_MEMACCESS_OK) // c is not guaranteed to be aligned
 171                xorbuf_aligned_AES_BLOCK_SIZE(x, c);
 172            else
 173                xorbuf(x, c, AES_BLOCK_SIZE);
 174            GMULT(x, h);
 175            c += AES_BLOCK_SIZE;
 176        }
 177        if (partial != 0) {
 178            //XMEMSET(scratch, 0, AES_BLOCK_SIZE);
 179            //XMEMCPY(scratch, c, partial);
 180            //xorbuf(x, scratch, AES_BLOCK_SIZE);
 181            xorbuf(x, c, partial);//same result as above
 182            GMULT(x, h);
 183        }
 184    }
 185
 186    /* Hash in the lengths of A and C in bits */
 187    //FlattenSzInBits(&scratch[0], aSz);
 188    //FlattenSzInBits(&scratch[8], cSz);
 189    //xorbuf_aligned_AES_BLOCK_SIZE(x, scratch);
 190    // simpler:
 191#define P32(v) ((uint32_t*)v)
 192  //P32(x)[0] ^= 0;
 193    P32(x)[1] ^= SWAP_BE32(aSz * 8);
 194  //P32(x)[2] ^= 0;
 195    P32(x)[3] ^= SWAP_BE32(cSz * 8);
 196#undef P32
 197
 198    GMULT(x, h);
 199
 200    /* Copy the result into s. */
 201    XMEMCPY(s, x, sSz);
 202}
 203