Created
April 22, 2016 19:20
Revisions
-
extremecoders-re created this gist
Apr 22, 2016 .There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,156 @@ typedef unsigned int uint32_t; typedef unsigned short uint16_t; typedef unsigned char uint8_t; static uint16_t rotl(uint16_t value, uint16_t shift) { return (value << shift) | (value >> (32 - shift)); } static void s20_quarterround(uint16_t *y0, uint16_t *y1, uint16_t *y2, uint16_t *y3) { *y1 = *y1 ^ rotl(*y0 + *y3, 7); *y2 = *y2 ^ rotl(*y1 + *y0, 9); *y3 = *y3 ^ rotl(*y2 + *y1, 13); *y0 = *y0 ^ rotl(*y3 + *y2, 18); } static void s20_rowround(uint16_t y[16]) { s20_quarterround(&y[0], &y[1], &y[2], &y[3]); s20_quarterround(&y[5], &y[6], &y[7], &y[4]); s20_quarterround(&y[10], &y[11], &y[8], &y[9]); s20_quarterround(&y[15], &y[12], &y[13], &y[14]); } static void s20_columnround(uint16_t x[16]) { s20_quarterround(&x[0], &x[4], &x[8], &x[12]); s20_quarterround(&x[5], &x[9], &x[13], &x[1]); s20_quarterround(&x[10], &x[14], &x[2], &x[6]); s20_quarterround(&x[15], &x[3], &x[7], &x[11]); } static void s20_doubleround(uint16_t x[16]) { s20_columnround(x); s20_rowround(x); } static uint16_t s20_littleendian(uint8_t *b) { return (b[0] + (b[1] << 8)); } static void s20_rev_littleendian(uint8_t *b, uint16_t w) { b[0] = w; b[1] = w >> 8; b[2] = w >> 16; // always zero b[3] = w >> 24; // always zero } static void s20_hash(uint8_t seq[64]) { int i; uint16_t x[16]; uint16_t z[16]; // Create two copies of the state in little-endian format // First copy is hashed together // Second copy is added to first, word-by-word for (i = 0; i < 16; ++i) x[i] = z[i] = s20_littleendian(seq + (4 * i)); for (i = 0; i < 10; ++i) s20_doubleround(z); for (i = 0; i < 16; ++i) { z[i] += x[i]; s20_rev_littleendian(seq + (4 * i), z[i]); } } static void s20_expand32(uint8_t *k, uint8_t n[16], uint8_t keystream[64]) { int i, j; // The constants specified by the Salsa20 specification, 'sigma' // "expand 32-byte k" uint8_t o[4][4] = { { 'e', 'x', 'p', 'a' }, { 'n', 'd', ' ', '3' }, { '2', '-', 'b', 'y' }, { 't', 'e', ' ', 'k' } }; // Copy all of 'sigma' into the correct spots in our keystream block for (i = 0; i < 64; i += 20) for (j = 0; j < 4; ++j) keystream[i + j] = o[i / 20][j]; // Copy the key and the nonce into the keystream block for (i = 0; i < 16; ++i) { keystream[4+i] = k[i]; keystream[44+i] = k[i+16]; keystream[24+i] = n[i]; } s20_hash(keystream); } int s20_crypt(uint8_t *key, uint8_t nonce[8], uint16_t si, uint8_t *buf, uint16_t buflen) { uint8_t keystream[64]; // 'n' is the 8-byte nonce (unique message number) concatenated // with the per-block 'counter' value (4 bytes in our case, 8 bytes // in the standard). We leave the high 4 bytes set to zero because // we permit only a 32-bit integer for stream index and length. uint8_t n[16] = { 0 }; uint16_t i; // If any of the parameters we received are invalid if (key == NULL || nonce == NULL || buf == NULL) return -1; // Set up the low 8 bytes of n with the unique message number for (i = 0; i < 8; ++i) n[i] = nonce[i]; // If we're not on a block boundary, compute the first keystream // block. This will make the primary loop (below) cleaner if (si % 64 != 0) { // Set the second-to-highest 4 bytes of n to the block number s20_rev_littleendian(n+8, si / 64); // Expand the key with n and hash to produce a keystream block s20_expand32(key, n, keystream); } // Walk over the plaintext byte-by-byte, xoring the keystream with // the plaintext and producing new keystream blocks as needed for (i = 0; i < buflen; ++i) { // If we've used up our entire keystream block (or have just begun // and happen to be on a block boundary), produce keystream block if ((si + i) % 64 == 0) { s20_rev_littleendian(n+8, ((si + i) / 64)); s20_expand32(key, n, keystream); } // xor one byte of plaintext with one byte of keystream buf[i] ^= keystream[(si + i) % 64]; } return 0; }