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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
| #include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h>
#define U32C(x) ((uint32_t)(x)) #define ROTL32(v, n) (U32C((v) << (n)) | U32C((v) >> (32 - (n))))
static uint32_t load32_le(const uint8_t *p) { return U32C(p[0]) | (U32C(p[1]) << 8) | (U32C(p[2]) << 16) | (U32C(p[3]) << 24); } static void store32_le(uint8_t *p, uint32_t x) { p[0] = (uint8_t)(x); p[1] = (uint8_t)(x >> 8); p[2] = (uint8_t)(x >> 16); p[3] = (uint8_t)(x >> 24); }
#define QR(a,b,c,d) \ do { \ b ^= ROTL32(a + d, 7); \ c ^= ROTL32(b + a, 9); \ d ^= ROTL32(c + b,13); \ a ^= ROTL32(d + c,18); \ } while(0)
static void salsa20_block(uint32_t out[16], const uint32_t in[16]) { uint32_t x[16]; memcpy(x, in, sizeof(x));
for (int i = 0; i < 10; i++) { QR(x[0], x[4], x[8], x[12]); QR(x[5], x[9], x[13], x[1]); QR(x[10], x[14], x[2], x[6]); QR(x[15], x[3], x[7], x[11]); QR(x[0], x[1], x[2], x[3]); QR(x[5], x[6], x[7], x[4]); QR(x[10], x[11], x[8], x[9]); QR(x[15], x[12], x[13], x[14]); } for (int i = 0; i < 16; i++) out[i] = x[i] + in[i]; }
void salsa20_xor(uint8_t *out, const uint8_t *in, size_t len, const uint8_t key[32], const uint8_t nonce[8], uint64_t counter) { static const uint32_t c0 = 0x61707865; static const uint32_t c1 = 0x3320646e; static const uint32_t c2 = 0x79622d32; static const uint32_t c3 = 0x6b206574;
uint32_t state[16]; uint8_t ks[64]; size_t off = 0;
state[0] = c0; state[1] = load32_le(key + 0); state[2] = load32_le(key + 4); state[3] = load32_le(key + 8); state[4] = load32_le(key + 12); state[5] = c1; state[6] = load32_le(nonce + 0); state[7] = load32_le(nonce + 4); state[8] = (uint32_t)(counter & 0xFFFFFFFFu); state[9] = (uint32_t)(counter >> 32); state[10] = c2; state[11] = load32_le(key + 16); state[12] = load32_le(key + 20); state[13] = load32_le(key + 24); state[14] = load32_le(key + 28); state[15] = c3;
while (len) { uint32_t block[16]; salsa20_block(block, state);
for (int i = 0; i < 16; i++) store32_le(ks + 4*i, block[i]);
size_t n = len < 64 ? len : 64; for (size_t i = 0; i < n; i++) out[off + i] = in[off + i] ^ ks[i];
off += n; len -= n;
state[8]++; if (state[8] == 0) state[9]++; } }
static void hexprint(const uint8_t *p, size_t n) { for (size_t i = 0; i < n; i++) { printf("%02X%s", p[i], (i + 1 == n) ? "" : ((i % 16 == 15) ? "\n" : " ")); } if (n && n % 16) puts(""); }
int main(void) { uint8_t key[32] = "12345678901234567890123456789012"; uint8_t nonce[8] = {0}; const char *msg = "Hello, Salsa20! This is a test message."; size_t len = strlen(msg);
uint8_t *pt = (uint8_t *)msg; uint8_t *ct = (uint8_t *)malloc(len); uint8_t *dec = (uint8_t *)malloc(len);
if (!ct || !dec) return 1;
salsa20_xor(ct, pt, len, key, nonce, 0);
salsa20_xor(dec, ct, len, key, nonce, 0);
printf("Plaintext: %.*s\n", (int)len, pt); printf("Ciphertext (hex):\n"); hexprint(ct, len); printf("Decrypted: %.*s\n", (int)len, dec);
free(ct); free(dec); return 0; }
|