Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdint.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <memory.h>
- #include <string.h>
- #include <inttypes.h>
- #define ROUNDS 16
- //128-bit integers are necessary for full-compliance, but there is not a single
- //use-case I know of that needs to support encrypting more than 2^64-1 bytes
- #ifdef __GNUC__
- typedef unsigned __int128 u128;
- #else
- typedef uint64_t u128;
- #endif
- typedef uint8_t byte;
- typedef struct
- {
- byte elements[16];
- } vector;
- enum direction
- {
- ENCRYPT,
- DECRYPT
- };
- typedef struct state
- {
- vector key_schedule[ROUNDS+3][2];
- vector nonce;
- vector mac;
- u128 counter;
- u128 length;
- vector (*crypt)(vector x, uint8_t block_len, struct state *s);
- enum direction direction;
- char buffer[16];
- uint8_t buffer_len;
- } state;
- /* For internal use only */
- static const vector null_vector = {.elements={0}};
- //The main linear transformation, T, is a 16x16 Matrix modulo 256
- //Every square nxn submatrix composed of the columns 0..n-1 and rows 0..n-1 are invertible
- //This is a permutation of a circulant matrix composed of the first 16 prime numbers in order
- //from least to greatest. The permutation is simply swapping the first and last rows
- //which is necessary so that a two is not at position 0,0 since two does not have a
- //multiplicative inverse mod 256
- static const byte T[16][16] = {
- { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 2},
- {53, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47},
- {47, 53, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43},
- {43, 47, 53, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41},
- {41, 43, 47, 53, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37},
- {37, 41, 43, 47, 53, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31},
- {31, 37, 41, 43, 47, 53, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29},
- {29, 31, 37, 41, 43, 47, 53, 2, 3, 5, 7, 11, 13, 17, 19, 23},
- {23, 29, 31, 37, 41, 43, 47, 53, 2, 3, 5, 7, 11, 13, 17, 19},
- {19, 23, 29, 31, 37, 41, 43, 47, 53, 2, 3, 5, 7, 11, 13, 17},
- {17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 2, 3, 5, 7, 11, 13},
- {13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 2, 3, 5, 7, 11},
- {11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 2, 3, 5, 7},
- { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 2, 3, 5},
- { 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 2, 3},
- { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53}
- };
- //The inverse of T
- static const byte T_inv[16][16] = {
- {131, 125, 39, 97, 65, 243, 115, 149, 53, 163, 245, 179, 27, 181, 253, 196},
- {253, 196, 125, 39, 97, 65, 243, 115, 149, 53, 163, 245, 179, 27, 181, 131},
- {181, 131, 196, 125, 39, 97, 65, 243, 115, 149, 53, 163, 245, 179, 27, 253},
- { 27, 253, 131, 196, 125, 39, 97, 65, 243, 115, 149, 53, 163, 245, 179, 181},
- {179, 181, 253, 131, 196, 125, 39, 97, 65, 243, 115, 149, 53, 163, 245, 27},
- {245, 27, 181, 253, 131, 196, 125, 39, 97, 65, 243, 115, 149, 53, 163, 179},
- {163, 179, 27, 181, 253, 131, 196, 125, 39, 97, 65, 243, 115, 149, 53, 245},
- { 53, 245, 179, 27, 181, 253, 131, 196, 125, 39, 97, 65, 243, 115, 149, 163},
- {149, 163, 245, 179, 27, 181, 253, 131, 196, 125, 39, 97, 65, 243, 115, 53},
- {115, 53, 163, 245, 179, 27, 181, 253, 131, 196, 125, 39, 97, 65, 243, 149},
- {243, 149, 53, 163, 245, 179, 27, 181, 253, 131, 196, 125, 39, 97, 65, 115},
- { 65, 115, 149, 53, 163, 245, 179, 27, 181, 253, 131, 196, 125, 39, 97, 243},
- { 97, 243, 115, 149, 53, 163, 245, 179, 27, 181, 253, 131, 196, 125, 39, 65},
- { 39, 65, 243, 115, 149, 53, 163, 245, 179, 27, 181, 253, 131, 196, 125, 97},
- {125, 97, 65, 243, 115, 149, 53, 163, 245, 179, 27, 181, 253, 131, 196, 39},
- {196, 39, 97, 65, 243, 115, 149, 53, 163, 245, 179, 27, 181, 253, 131, 125}
- };
- //S{N}_inv is the inverse of the nxn matrix composed of rows 0..n-1 and columns 0..n-1
- static const byte S15_inv[15][15] = {
- { 51, 113, 147, 77, 69, 247, 207, 113, 121, 127, 249, 151, 247, 241, 193},
- {193, 235, 222, 104, 84, 180, 136, 168, 56, 42, 86, 16, 104, 24, 56},
- {241, 220, 227, 188, 180, 110, 44, 62, 80, 32, 2, 8, 192, 54, 24},
- {247, 174, 138, 235, 66, 108, 84, 148, 136, 6, 154, 18, 118, 192, 104},
- {151, 148, 230, 76, 207, 8, 228, 190, 124, 16, 62, 8, 18, 8, 16},
- {249, 178, 38, 78, 166, 103, 98, 172, 52, 134, 214, 62, 154, 2, 86},
- {127, 164, 226, 156, 2, 8, 119, 144, 252, 180, 134, 16, 6, 32, 42},
- {121, 188, 116, 188, 200, 144, 248, 217, 64, 252, 52, 124, 136, 80, 56},
- {113, 212, 124, 90, 96, 122, 112, 86, 217, 144, 172, 190, 148, 62, 168},
- {207, 70, 74, 188, 88, 64, 200, 112, 248, 119, 98, 228, 84, 44, 136},
- {247, 236, 230, 52, 216, 22, 64, 122, 144, 8, 103, 8, 108, 110, 180},
- { 69, 74, 198, 70, 6, 216, 88, 96, 200, 2, 166, 207, 66, 180, 84},
- { 77, 192, 126, 64, 70, 52, 188, 90, 188, 156, 78, 76, 235, 188, 104},
- {147, 174, 94, 126, 198, 230, 74, 124, 116, 226, 38, 230, 138, 227, 222},
- {113, 220, 174, 192, 74, 236, 70, 212, 188, 164, 178, 148, 174, 220, 235}
- };
- static const byte S14_inv[14][14] = {
- {224, 221, 137, 13, 103, 51, 253, 245, 69, 147, 227, 219, 237, 93},
- {153, 139, 174, 104, 196, 212, 152, 136, 216, 138, 134, 240, 56, 184},
- { 41, 252, 243, 188, 228, 14, 124, 158, 112, 0, 242, 104, 208, 86},
- { 63, 142, 122, 235, 18, 204, 4, 52, 104, 38, 170, 178, 102, 160},
- {103, 84, 70, 76, 239, 200, 196, 254, 60, 80, 222, 72, 114, 200},
- {151, 250, 202, 206, 18, 143, 214, 4, 188, 62, 114, 22, 62, 74},
- { 97, 92, 62, 28, 150, 224, 3, 56, 116, 252, 234, 56, 98, 216},
- { 81, 92, 68, 188, 56, 176, 8, 185, 224, 92, 100, 92, 88, 240},
- {249, 180, 236, 90, 176, 218, 160, 246, 185, 176, 60, 94, 4, 30},
- {183, 166, 250, 188, 104, 32, 56, 144, 88, 23, 178, 4, 4, 140},
- {155, 220, 222, 52, 192, 70, 152, 74, 0, 24, 239, 216, 100, 94},
- { 9, 186, 126, 70, 46, 136, 112, 176, 184, 146, 110, 31, 250, 36},
- {149, 160, 110, 64, 22, 148, 108, 250, 156, 188, 94, 236, 219, 156},
- { 25, 86, 178, 254, 66, 238, 46, 244, 92, 58, 18, 222, 222, 139}
- };
- static const byte S13_inv[13][13] = {
- { 1, 99, 75, 123, 57, 17, 27, 137, 129, 29, 5, 41, 59},
- {177, 27, 222, 184, 116, 164, 104, 104, 120, 122, 182, 64, 136},
- { 55, 208, 15, 64, 224, 178, 160, 182, 184, 12, 78, 44, 148},
- { 95, 78, 186, 171, 82, 140, 196, 180, 232, 102, 234, 114, 38},
- {207, 196, 22, 252, 63, 248, 244, 30, 156, 96, 174, 248, 34},
- {169, 230, 238, 10, 86, 171, 114, 108, 244, 114, 86, 18, 58},
- { 25, 172, 174, 44, 134, 112, 147, 152, 148, 44, 90, 72, 114},
- { 1, 124, 164, 92, 152, 80, 168, 121, 32, 60, 196, 252, 248},
- {111, 248, 216, 142, 252, 174, 244, 46, 97, 204, 104, 210, 120},
- { 51, 142, 242, 4, 32, 168, 192, 64, 104, 239, 42, 204, 204},
- { 81, 160, 74, 232, 140, 154, 108, 130, 168, 180, 155, 204, 88},
- {253, 114, 102, 30, 86, 32, 8, 192, 232, 26, 214, 119, 82},
- { 97, 104, 6, 232, 110, 124, 84, 234, 108, 180, 118, 20, 3}
- };
- static const byte S12_inv[12][12] = {
- { 56, 187, 213, 83, 27, 53, 167, 143, 53, 73, 159, 245},
- {217, 91, 206, 248, 164, 4, 136, 248, 88, 154, 38, 96},
- {219, 112, 231, 224, 88, 34, 112, 158, 232, 92, 230, 252},
- { 61, 126, 110, 219, 54, 20, 156, 32, 144, 126, 190, 202},
- {217, 212, 210, 12, 11, 208, 60, 194, 212, 104, 202, 192},
- {171, 182, 122, 218, 178, 163, 26, 192, 204, 218, 194, 58},
- {179, 60, 202, 188, 50, 8, 27, 220, 140, 116, 214, 80},
- { 89, 60, 180, 28, 104, 240, 136, 233, 64, 28, 84, 220},
- { 71, 184, 232, 78, 204, 78, 212, 158, 129, 172, 248, 178},
- {111, 238, 90, 100, 232, 184, 112, 24, 184, 31, 210, 124},
- {137, 96, 154, 168, 156, 186, 204, 178, 72, 20, 107, 44},
- {247, 2, 194, 174, 66, 56, 16, 196, 96, 226, 146, 255}
- };
- static const byte S11_inv[11][11] = {
- {155, 165, 127, 217, 69, 205, 247, 35, 21, 147, 89},
- {121, 27, 142, 56, 100, 4, 136, 120, 88, 90, 230},
- {255, 104, 223, 40, 80, 66, 48, 142, 104, 212, 158},
- { 35, 18, 130, 39, 74, 68, 60, 200, 80, 210, 242},
- { 25, 84, 82, 140, 139, 208, 60, 194, 212, 232, 74},
- {161, 42, 110, 70, 166, 83, 186, 40, 140, 14, 214},
- {227, 220, 106, 28, 210, 136, 27, 28, 140, 20, 118},
- {157, 244, 108, 164, 32, 16, 72, 89, 192, 84, 204},
- { 5, 28, 204, 74, 176, 62, 244, 230, 65, 208, 124},
- { 19, 230, 82, 172, 224, 216, 48, 8, 56, 151, 138},
- {253, 184, 242, 144, 244, 90, 140, 98, 200, 236, 131}
- };
- static const byte S10_inv[10][10] = {
- {116, 253, 201, 41, 169, 95, 19, 29, 61, 143},
- { 95, 171, 106, 24, 252, 16, 240, 116, 200, 2},
- {157, 56, 107, 136, 200, 190, 184, 186, 152, 156},
- { 21, 194, 150, 199, 18, 232, 116, 60, 160, 202},
- { 99, 68, 86, 172, 179, 36, 20, 166, 228, 128},
- {119, 58, 170, 38, 254, 63, 98, 132, 124, 246},
- { 89, 236, 230, 252, 170, 180, 67, 184, 124, 124},
- {105, 20, 36, 100, 80, 40, 24, 81, 160, 164},
- {129, 188, 100, 10, 160, 182, 4, 190, 161, 96},
- {157, 214, 214, 204, 8, 172, 8, 108, 72, 47}
- };
- static const byte S9_inv[9][9] = {
- {183, 103, 51, 221, 161, 51, 11, 49, 245},
- {121, 151, 86, 48, 12, 232, 0, 204, 88},
- {137, 32, 83, 216, 168, 142, 152, 138, 120},
- { 87, 222, 178, 63, 98, 32, 196, 244, 112},
- {227, 68, 86, 172, 179, 36, 20, 166, 228},
- {245, 158, 14, 174, 174, 7, 18, 204, 172},
- {165, 20, 14, 204, 138, 4, 35, 8, 92},
- {189, 172, 188, 20, 112, 88, 56, 129, 192},
- { 97, 252, 164, 138, 160, 54, 4, 62, 161}
- };
- static const byte S8_inv[8][8] = {
- { 2, 187, 191, 11, 129, 69, 183, 155},
- { 33, 247, 246, 192, 12, 88, 160, 124},
- { 17, 0, 115, 40, 168, 62, 184, 122},
- {231, 158, 242, 223, 98, 128, 4, 212},
- {255, 212, 70, 196, 51, 12, 132, 110},
- { 73, 78, 222, 246, 46, 191, 98, 36},
- { 73, 132, 30, 52, 10, 156, 179, 192},
- {253, 172, 188, 148, 112, 216, 56, 1}
- };
- static const byte S7_inv[7][7] = {
- {211, 151, 235, 111, 177, 125, 207},
- {149, 167, 230, 16, 204, 184, 128},
- {127, 8, 219, 160, 72, 78, 8},
- { 99, 46, 66, 79, 162, 160, 164},
- { 73, 236, 126, 44, 19, 60, 116},
- {181, 30, 110, 38, 110, 95, 130},
- {137, 132, 30, 52, 10, 156, 179}
- };
- static const byte S6_inv[6][6] = {
- { 54, 67, 53, 171, 31, 49},
- { 21, 167, 230, 16, 204, 184},
- {231, 168, 139, 192, 216, 174},
- { 55, 254, 90, 223, 170, 80},
- {173, 252, 118, 252, 187, 172},
- {143, 70, 154, 46, 210, 119}
- };
- static const byte S5_inv[5][5] = {
- {221, 249, 95, 137, 65},
- {157, 119, 22, 160, 60},
- { 9, 156, 215, 228, 180},
- {103, 222, 122, 63, 74},
- { 33, 196, 46, 164, 19}
- };
- static const byte S4_inv[4][4] = {
- {162, 77, 5, 61},
- {201, 39, 254, 208},
- {141, 172, 143, 116},
- {217, 38, 118, 71}
- };
- static const byte S3_inv[3][3] = {
- {127, 203, 19},
- {153, 7, 222},
- {129, 164, 199}
- };
- static const byte S2_inv[2][2] = {
- {170, 87},
- {103, 255}
- };
- static const byte S1_inv = 171;
- //Lookup table for multiplicative inverse modulo 257
- static const byte mult_inv_mod257[256] = {
- 0, 128, 85, 192, 102, 42, 146, 224, 199, 179, 186, 149, 177, 201, 119, 240,
- 120, 99, 229, 89, 48, 221, 189, 74, 71, 88, 237, 100, 194, 59, 198, 248,
- 147, 188, 234, 49, 131, 114, 144, 44, 162, 152, 5, 110, 39, 94, 174, 165,
- 20, 35, 125, 172, 96, 118, 242, 178, 247, 225, 60, 29, 58, 227, 101, 252,
- 86, 73, 233, 222, 148, 245, 180, 24, 168, 65, 23, 185, 246, 200, 243, 150,
- 164, 209, 95, 204, 126, 2, 64, 183, 25, 19, 208, 175, 151, 215, 45, 82,
- 52, 138, 134, 17, 27, 62, 4, 214, 163, 176, 244, 187, 223, 249, 43, 217,
- 115, 123, 37, 112, 133, 158, 53, 14, 16, 157, 139, 113, 219, 50, 84, 254,
- 1, 171, 205, 36, 142, 116, 98, 239, 241, 202, 97, 122, 143, 218, 132, 140,
- 38, 212, 6, 32, 68, 11, 79, 92, 41, 251, 193, 228, 238, 121, 117, 203,
- 173, 210, 40, 104, 80, 47, 236, 230, 72, 191, 253, 129, 51, 160, 46, 91,
- 105, 12, 55, 9, 70, 232, 190, 87, 231, 75, 10, 107, 33, 22, 182, 169,
- 3, 154, 28, 197, 226, 195, 30, 8, 77, 13, 137, 159, 83, 130, 220, 235,
- 90, 81, 161, 216, 145, 250, 103, 93, 211, 111, 141, 124, 206, 21, 67, 108,
- 7, 57, 196, 61, 155, 18, 167, 184, 181, 66, 34, 207, 166, 26, 156, 135,
- 15, 136, 54, 78, 106, 69, 76, 56, 31, 109, 213, 153, 63, 170, 127, 255
- };
- //To perform multiplication modulo 2^257, we convert to 16-bit integers and add 1,
- //guaranteeing that we don't perform multiplication by zero. When we are done, we subtract 1
- //so that the result is in the range 0..255
- static byte multiply_mod257(uint16_t x, uint16_t y)
- {
- return ((x + 1) * (y + 1)) % 257 - 1;
- }
- static byte rotl(byte x, byte r)
- {
- return (x << r) | (x >> (8-r));
- }
- static byte rotr(byte x, byte r)
- {
- return (x >> r) | (x << (8-r));
- }
- static vector u128_to_vector(u128 x)
- {
- int i;
- vector t;
- for (i=15; i>=0; i--)
- {
- t.elements[i] = x & 0xFF;
- x >>= 8;
- }
- return t;
- }
- static vector vector_xor(vector x, vector y)
- {
- int i;
- for (i=0; i<16; i++)
- {
- x.elements[i] ^= y.elements[i];
- }
- return x;
- }
- static vector vector_multiply(vector x, vector y)
- {
- int i;
- for (i=0; i<16; i++)
- {
- x.elements[i] = multiply_mod257(x.elements[i], y.elements[i]);
- }
- return x;
- }
- static vector vector_multiply_inv(vector x, vector y)
- {
- int i;
- for (i=0; i<16; i++)
- {
- x.elements[i] = multiply_mod257(x.elements[i], mult_inv_mod257[y.elements[i]]);
- }
- return x;
- }
- //Matrix-multiplication mod 256
- static vector matrix_multiply(vector x)
- {
- int i,j;
- vector t;
- for (i=0; i<16; i++)
- {
- t.elements[i] = x.elements[0]*T[i][0];
- for (j=1; j<16; j++)
- {
- t.elements[i] += x.elements[j]*T[i][j];
- }
- }
- return t;
- }
- static vector matrix_multiply_inv(vector x, byte block_len)
- {
- int i, j;
- vector t;
- //If we are decrypting a partial-length block, first remove the contribution
- //from the key before multiplying by the inverse of the submatrix
- for (i=0; i<block_len; i++)
- {
- t.elements[i] = x.elements[i];
- for (j=block_len; j<16; j++)
- {
- t.elements[i] -= x.elements[j]*T[i][j];
- }
- }
- //For partial length blocks, perform matrix multiplication using the inverse of the
- //relevant submatrix (S{N}_inv). For full-length blocks, perform matrix multiplication
- //by T_inv
- switch (block_len)
- {
- case 1:
- x.elements[0] = t.elements[0]*S1_inv;
- break;
- case 2:
- for (i=0; i<2; i++)
- {
- x.elements[i] = t.elements[0]*S2_inv[i][0];
- for (j=1; j<2; j++)
- {
- x.elements[i] += t.elements[j]*S2_inv[i][j];
- }
- }
- break;
- case 3:
- for (i=0; i<3; i++)
- {
- x.elements[i] = t.elements[0]*S3_inv[i][0];
- for (j=1; j<3; j++)
- {
- x.elements[i] += t.elements[j]*S3_inv[i][j];
- }
- }
- break;
- case 4:
- for (i=0; i<4; i++)
- {
- x.elements[i] = t.elements[0]*S4_inv[i][0];
- for (j=1; j<4; j++)
- {
- x.elements[i] += t.elements[j]*S4_inv[i][j];
- }
- }
- break;
- case 5:
- for (i=0; i<5; i++)
- {
- x.elements[i] = t.elements[0]*S5_inv[i][0];
- for (j=1; j<5; j++)
- {
- x.elements[i] += t.elements[j]*S5_inv[i][j];
- }
- }
- break;
- case 6:
- for (i=0; i<6; i++)
- {
- x.elements[i] = t.elements[0]*S6_inv[i][0];
- for (j=1; j<6; j++)
- {
- x.elements[i] += t.elements[j]*S6_inv[i][j];
- }
- }
- break;
- case 7:
- for (i=0; i<7; i++)
- {
- x.elements[i] = t.elements[0]*S7_inv[i][0];
- for (j=1; j<7; j++)
- {
- x.elements[i] += t.elements[j]*S7_inv[i][j];
- }
- }
- break;
- case 8:
- for (i=0; i<8; i++)
- {
- x.elements[i] = t.elements[0]*S8_inv[i][0];
- for (j=1; j<8; j++)
- {
- x.elements[i] += t.elements[j]*S8_inv[i][j];
- }
- }
- break;
- case 9:
- for (i=0; i<9; i++)
- {
- x.elements[i] = t.elements[0]*S9_inv[i][0];
- for (j=1; j<9; j++)
- {
- x.elements[i] += t.elements[j]*S9_inv[i][j];
- }
- }
- break;
- case 10:
- for (i=0; i<10; i++)
- {
- x.elements[i] = t.elements[0]*S10_inv[i][0];
- for (j=1; j<10; j++)
- {
- x.elements[i] += t.elements[j]*S10_inv[i][j];
- }
- }
- break;
- case 11:
- for (i=0; i<11; i++)
- {
- x.elements[i] = t.elements[0]*S11_inv[i][0];
- for (j=1; j<11; j++)
- {
- x.elements[i] += t.elements[j]*S11_inv[i][j];
- }
- }
- break;
- case 12:
- for (i=0; i<12; i++)
- {
- x.elements[i] = t.elements[0]*S12_inv[i][0];
- for (j=1; j<12; j++)
- {
- x.elements[i] += t.elements[j]*S12_inv[i][j];
- }
- }
- break;
- case 13:
- for (i=0; i<13; i++)
- {
- x.elements[i] = t.elements[0]*S13_inv[i][0];
- for (j=1; j<13; j++)
- {
- x.elements[i] += t.elements[j]*S13_inv[i][j];
- }
- }
- break;
- case 14:
- for (i=0; i<14; i++)
- {
- x.elements[i] = t.elements[0]*S14_inv[i][0];
- for (j=1; j<14; j++)
- {
- x.elements[i] += t.elements[j]*S14_inv[i][j];
- }
- }
- break;
- case 15:
- for (i=0; i<15; i++)
- {
- x.elements[i] = t.elements[0]*S15_inv[i][0];
- for (j=1; j<15; j++)
- {
- x.elements[i] += t.elements[j]*S15_inv[i][j];
- }
- }
- break;
- case 16:
- for (i=0; i<16; i++)
- {
- x.elements[i] = t.elements[0]*T_inv[i][0];
- for (j=1; j<16; j++)
- {
- x.elements[i] += t.elements[j]*T_inv[i][j];
- }
- }
- break;
- }
- return x;
- }
- void print_vector(vector x, uint8_t vector_length, int round)
- {
- int i;
- fprintf(stderr, "%d: ", round);
- for (i=0; i<vector_length; i++)
- {
- fprintf(stderr,"%02"PRIx8, x.elements[i]);
- }
- fprintf(stderr, "\n");
- }
- static vector encrypt(vector x, uint8_t block_len, state *s)
- {
- vector tweak[2];
- int i, j;
- //Compute tweak values from the nonce and counter
- //This is an invertible operation to guarantee no two combinations of nonce/counter
- //will result in identical tweak values
- tweak[0] = u128_to_vector(s->counter);
- tweak[1] = s->nonce;
- for (i=0; i<2; i++)
- {
- tweak[0] = vector_xor(tweak[0], s->key_schedule[i][0]);
- tweak[1] = vector_xor(tweak[1], s->key_schedule[i][1]);
- tweak[0] = vector_multiply(tweak[0], tweak[1]);
- tweak[0] = matrix_multiply(tweak[0]);
- tweak[1] = vector_multiply(tweak[1], tweak[0]);
- tweak[1] = matrix_multiply(tweak[1]);
- }
- //Make sure trailing bytes of x are all zero
- for (j=block_len; j<16; j++)
- {
- x.elements[j] = 0;
- }
- //Perform the actual encryption rounds
- for (i=2; i<ROUNDS+2; i++)
- {
- //Key mixing operations, first XOR by one subkey, then multiply by a second
- //subkey xor'd to a tweek value, modulo 257
- x = vector_multiply(
- vector_xor(x, s->key_schedule[i][0]),
- vector_xor(tweak[i%2], s->key_schedule[i][1]));
- //Rotate the bytes by between 1 and 7 bits
- //This helps to provide diffusion at a bit level, as multiplication modulo 257 doesn't
- //guarantee that we will achieve that since the coefficients are dependent entirely
- //on the key and tweek; although it is likely that it would be sufficient alone,
- //this provides extra assurance
- for (j=0; j<16; j++)
- {
- x.elements[j] = rotl(x.elements[j],(5*(i-2)+3*j)%7+1);
- }
- x = matrix_multiply(x);
- //After each matrix multiplication, we need to 0 out the extra bytes otherwise
- //we will not be able to decrypt it
- for (j=block_len; j<16; j++)
- {
- x.elements[j] = 0;
- }
- //After half the rounds, xor the partially encrypted block to the MAC
- if (i-2 == ROUNDS/2)
- {
- s->mac = vector_xor(s->mac, x);
- }
- }
- //Perform output whitening before returning
- x = vector_multiply(
- vector_xor(x, s->key_schedule[ROUNDS+2][0]),
- vector_xor(tweak[0], s->key_schedule[ROUNDS+2][1]));
- return x;
- }
- static vector decrypt(vector x, uint8_t block_len, state *s)
- {
- vector tweak[2];
- vector temp;
- int i, j;
- //Compute tweak values from the nonce and counter
- //This is an invertible operation to guarantee no two combinations of nonce/counter
- //will result in identical tweak values
- tweak[0] = u128_to_vector(s->counter);
- tweak[1] = s->nonce;
- for (i=0; i<2; i++)
- {
- tweak[0] = vector_xor(tweak[0], s->key_schedule[i][0]);
- tweak[1] = vector_xor(tweak[1], s->key_schedule[i][1]);
- tweak[0] = vector_multiply(tweak[0], tweak[1]);
- tweak[0] = matrix_multiply(tweak[0]);
- tweak[1] = vector_multiply(tweak[1], tweak[0]);
- tweak[1] = matrix_multiply(tweak[1]);
- }
- //Remove output whitening
- x = vector_xor(
- vector_multiply_inv(x, vector_xor(tweak[0], s->key_schedule[ROUNDS+2][1])),
- s->key_schedule[ROUNDS+2][0]);
- for (i=ROUNDS+1; i>=2; i--)
- {
- //After half the rounds, xor the partially decrypted block to the MAC
- if (i-2 == ROUNDS/2)
- {
- s->mac = vector_xor(s->mac, x);
- }
- //We need to perform the key mixing opertation from the encryption on a null vector
- //and then set the trailing bytes of the key to that before we can invert the
- //matrix multiplication
- temp = null_vector;
- temp = vector_multiply(
- vector_xor(temp, s->key_schedule[i][0]),
- vector_xor(tweak[i%2], s->key_schedule[i][1]));
- for (j=block_len; j<16; j++)
- {
- x.elements[j] = rotl(temp.elements[j],(5*(i-2)+3*j)%7+1);
- }
- x = matrix_multiply_inv(x, block_len);
- //Rotate the bytes right by between 1 and 7 bits
- for (j=0; j<16; j++)
- {
- x.elements[j] = rotr(x.elements[j], (5*(i-2)+3*j)%7+1);
- }
- //Perform the inverse of the key mixing operation
- x = vector_xor(
- vector_multiply_inv(x, vector_xor(tweak[i%2], s->key_schedule[i][1])),
- s->key_schedule[i][0]);
- }
- return x;
- }
- /* API Functions */
- void reinit(state *s, vector nonce, enum direction direction)
- {
- s->nonce = nonce;
- s->mac = null_vector;
- s->counter = 0;
- s->length = 0;
- s->buffer_len = 0;
- s->direction = direction;
- if (direction == ENCRYPT)
- {
- s->crypt = &encrypt;
- }
- else
- {
- s->crypt = &decrypt;
- }
- }
- state *init(vector *key, size_t key_length, vector nonce, enum direction direction)
- {
- unsigned int i, j, k, l;
- vector x = {0};
- state *s = calloc(1, sizeof(state));
- const vector pi = {.elements={
- 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
- 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44
- }};
- for(i=0; i<key_length; i++)
- {
- x = vector_multiply(vector_xor(x, key[i]), pi);
- for (j=0; j<16; j++)
- {
- x.elements[j] = rotl(x.elements[j],(5*(i-2)+3*j)%7+1);
- }
- x = matrix_multiply(x);
- }
- for (i=0; i<ROUNDS+3; i++)
- {
- for (j=0; j<2; j++)
- {
- x = vector_xor(x, u128_to_vector(2*i+j));
- for(k=0; k<key_length; k++)
- {
- x = vector_multiply(vector_xor(x, key[k]), pi);
- for (l=0; l<16; l++)
- {
- x.elements[l] = rotl(x.elements[l],(3*i+5*j)%7+1);
- }
- x = matrix_multiply(x);
- }
- s->key_schedule[i][j] = x;
- }
- }
- reinit(s, nonce, direction);
- return s;
- }
- void dest(state **s)
- {
- //You should really zero memory here, but memset will be optimized, GCC does not
- //support memset_s, and I'm lazy
- free(*s);
- *s = NULL;
- }
- size_t append(char *in, size_t in_len, char *out, size_t out_len, state *s,
- size_t *bytes_written)
- {
- size_t in_pos = 0;
- size_t out_pos = 0;
- size_t copy_length;
- vector block;
- if (s->buffer_len > 0 && s->buffer_len < 16)
- {
- if (in_len+s->buffer_len >= 16)
- {
- copy_length = 16-s->buffer_len;
- }
- else
- {
- copy_length = in_len;
- }
- memcpy(s->buffer+s->buffer_len, in, copy_length);
- in_pos += copy_length;
- s->buffer_len += copy_length;
- }
- if (s->buffer_len == 16)
- {
- memcpy(block.elements, s->buffer, 16);
- block = s->crypt(block, 16, s);
- s->counter++;
- memcpy(out+out_pos, block.elements, 16);
- out_pos += 16;
- s->buffer_len = 0;
- }
- while (in_len-in_pos >= 16 && out_len-in_pos >= 16)
- {
- memcpy(block.elements, in+in_pos, 16);
- in_pos += 16;
- block = s->crypt(block, 16, s);
- s->counter++;
- memcpy(out+out_pos, block.elements, 16);
- out_pos += 16;
- }
- copy_length = in_len-in_pos;
- if (copy_length > 16)
- {
- copy_length = 16;
- }
- if (copy_length > 0)
- {
- memcpy(s->buffer, in+in_pos, copy_length);
- s->buffer_len = copy_length;
- in_pos += copy_length;
- }
- s->length += out_pos;
- *bytes_written = out_pos;
- return in_pos;
- }
- //Result is freed on call to dest(state), you
- //should not free result or access after calling dest
- char * finalize(size_t *out_length, state *s)
- {
- //Encrypt remaining data if available
- if (s->buffer_len > 0)
- {
- vector block;
- memcpy(block.elements, s->buffer, s->buffer_len);
- block = s->crypt(block, s->buffer_len, s);
- memcpy(s->buffer, block.elements, s->buffer_len);
- }
- *out_length = s->buffer_len;
- s->length += s->buffer_len;
- //Finalize MAC computation by encrypting using the length instead of the counter for the
- //tweak value
- s->counter = s->length;
- s->mac = encrypt(s->mac, 16, s);
- //return a reference to the buffer
- return s->buffer;
- }
- char * get_mac(size_t *out_length, state *s)
- {
- if (s->length != s->counter) //Not finalized
- {
- *out_length = 0;
- return NULL;
- }
- else
- {
- *out_length = 16;
- return (char *)s->mac.elements;
- }
- }
- int check_mac(char *mac, size_t mac_length, state *s)
- {
- int i;
- if (mac_length > 16)
- {
- return 0; //False
- }
- else
- {
- uint8_t check = 0;
- for (i=0; i<mac_length; i++)
- {
- //if any bit differed, check will be non-zero
- check |= s->mac.elements[i] ^ (uint8_t)mac[i];
- }
- return !check;
- }
- }
- //Encrypt or Decrypt all bytes except for the last [trailing_bytes_len] bytes
- size_t process_io(FILE *input, FILE *output,
- char *in_buffer, size_t in_buffer_len, size_t trailing_bytes_len,
- char *out_buffer, size_t out_buffer_len,
- state *s)
- {
- size_t buffer_len, bytes_read, bytes_written;
- size_t buffer_pos = 0;
- char *tail;
- if (trailing_bytes_len > 0)
- {
- buffer_pos = fread(in_buffer, 1, trailing_bytes_len, stdin);
- if (buffer_pos != trailing_bytes_len)
- {
- fprintf(stderr, "Not enough trailing bytes\n");
- exit(1);
- }
- }
- while (trailing_bytes_len < (buffer_len = buffer_pos + fread(in_buffer+buffer_pos, 1,
- in_buffer_len-buffer_pos, stdin)))
- {
- bytes_read = append(in_buffer, buffer_len-trailing_bytes_len, out_buffer,
- out_buffer_len, s, &bytes_written);
- if (bytes_written != fwrite(out_buffer, 1, bytes_written, stdout))
- {
- fprintf(stderr, "Error writing to output\n");
- exit(1);
- }
- memmove(in_buffer, in_buffer+bytes_read, buffer_len-bytes_read);
- buffer_pos = buffer_len-bytes_read;
- }
- tail = finalize(&bytes_written, s);
- if (bytes_written != fwrite(tail, 1, bytes_written, stdout))
- {
- fprintf(stderr, "Error writing to output\n");
- exit(1);
- }
- return buffer_pos;
- }
- int main(int argc, char **argv)
- {
- if (argc == 2)
- {
- char direction = argv[1][0];
- vector key = {0};
- vector nonce;
- state *s;
- char *mac;
- size_t bytes_read, bytes_written;
- char out_buffer[8192];
- if (direction == 'e')
- {
- char in_buffer[8192];
- FILE *random = fopen("/dev/random", "rb");
- if (random == NULL)
- {
- fprintf(stderr, "Error reading from /dev/random\n");
- exit(1);
- }
- bytes_read = fread(nonce.elements, 1, sizeof(nonce.elements), random);
- fclose(random);
- random = NULL;
- if (bytes_read != 16)
- {
- fprintf(stderr, "Error reading from /dev/random\n");
- exit(1);
- }
- if (16 != fwrite(nonce.elements, 1, 16, stdout))
- {
- fprintf(stderr, "Error writing to output\n");
- exit(1);
- }
- s = init(&key, 1, nonce, ENCRYPT);
- process_io(stdin, stdout,
- in_buffer, sizeof(in_buffer), 0, out_buffer, sizeof(out_buffer), s);
- mac = get_mac(&bytes_written, s);
- if (bytes_written != fwrite(mac, 1, bytes_written, stdout))
- {
- fprintf(stderr, "Error writing to output\n");
- exit(1);
- }
- dest(&s);
- }
- else
- {
- char in_buffer[8192+16];
- bytes_read = fread(nonce.elements, 1, sizeof(nonce.elements), stdin);
- if (bytes_read != 16)
- {
- fprintf(stderr, "File did not start with nonce\n");
- exit(1);
- }
- s = init(&key, 1, nonce, DECRYPT);
- bytes_read = process_io(stdin, stdout,
- in_buffer, sizeof(in_buffer), 16, out_buffer, sizeof(out_buffer), s);
- if (!check_mac(in_buffer, bytes_read, s))
- {
- fprintf(stderr, "MAC check failed\n");
- }
- dest(&s);
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement