/src/dropbear/libtomcrypt/src/stream/chacha/chacha_crypt.c
Line | Count | Source |
1 | | /* LibTomCrypt, modular cryptographic library -- Tom St Denis |
2 | | * |
3 | | * LibTomCrypt is a library that provides various cryptographic |
4 | | * algorithms in a highly modular and flexible manner. |
5 | | * |
6 | | * The library is free for all purposes without any express |
7 | | * guarantee it works. |
8 | | */ |
9 | | |
10 | | /* The implementation is based on: |
11 | | * chacha-ref.c version 20080118 |
12 | | * Public domain from D. J. Bernstein |
13 | | */ |
14 | | |
15 | | #include "tomcrypt.h" |
16 | | |
17 | | #ifdef LTC_CHACHA |
18 | | |
19 | | #define QUARTERROUND(a,b,c,d) \ |
20 | 500M | x[a] += x[b]; x[d] = ROL(x[d] ^ x[a], 16); \ |
21 | 500M | x[c] += x[d]; x[b] = ROL(x[b] ^ x[c], 12); \ |
22 | 500M | x[a] += x[b]; x[d] = ROL(x[d] ^ x[a], 8); \ |
23 | 500M | x[c] += x[d]; x[b] = ROL(x[b] ^ x[c], 7); |
24 | | |
25 | | static void _chacha_block(unsigned char *output, const ulong32 *input, int rounds) |
26 | 6.25M | { |
27 | 6.25M | ulong32 x[16]; |
28 | 6.25M | int i; |
29 | 6.25M | XMEMCPY(x, input, sizeof(x)); |
30 | 68.8M | for (i = rounds; i > 0; i -= 2) { |
31 | 62.5M | QUARTERROUND(0, 4, 8,12) |
32 | 62.5M | QUARTERROUND(1, 5, 9,13) |
33 | 62.5M | QUARTERROUND(2, 6,10,14) |
34 | 62.5M | QUARTERROUND(3, 7,11,15) |
35 | 62.5M | QUARTERROUND(0, 5,10,15) |
36 | 62.5M | QUARTERROUND(1, 6,11,12) |
37 | 62.5M | QUARTERROUND(2, 7, 8,13) |
38 | 62.5M | QUARTERROUND(3, 4, 9,14) |
39 | 62.5M | } |
40 | 106M | for (i = 0; i < 16; ++i) { |
41 | 100M | x[i] += input[i]; |
42 | 100M | STORE32L(x[i], output + 4 * i); |
43 | 100M | } |
44 | 6.25M | } |
45 | | |
46 | | /** |
47 | | Encrypt (or decrypt) bytes of ciphertext (or plaintext) with ChaCha |
48 | | @param st The ChaCha state |
49 | | @param in The plaintext (or ciphertext) |
50 | | @param inlen The length of the input (octets) |
51 | | @param out [out] The ciphertext (or plaintext), length inlen |
52 | | @return CRYPT_OK if successful |
53 | | */ |
54 | | int chacha_crypt(chacha_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out) |
55 | 208k | { |
56 | 208k | unsigned char buf[64]; |
57 | 208k | unsigned long i, j; |
58 | | |
59 | 208k | if (inlen == 0) return CRYPT_OK; /* nothing to do */ |
60 | | |
61 | 208k | LTC_ARGCHK(st != NULL); |
62 | 208k | LTC_ARGCHK(in != NULL); |
63 | 208k | LTC_ARGCHK(out != NULL); |
64 | 208k | LTC_ARGCHK(st->ivlen != 0); |
65 | | |
66 | 208k | if (st->ksleft > 0) { |
67 | 0 | j = MIN(st->ksleft, inlen); |
68 | 0 | for (i = 0; i < j; ++i, st->ksleft--) out[i] = in[i] ^ st->kstream[64 - st->ksleft]; |
69 | 0 | inlen -= j; |
70 | 0 | if (inlen == 0) return CRYPT_OK; |
71 | 0 | out += j; |
72 | 0 | in += j; |
73 | 0 | } |
74 | 6.25M | for (;;) { |
75 | 6.25M | _chacha_block(buf, st->input, st->rounds); |
76 | 6.25M | if (st->ivlen == 8) { |
77 | | /* IV-64bit, increment 64bit counter */ |
78 | 6.25M | if (0 == ++st->input[12] && 0 == ++st->input[13]) return CRYPT_OVERFLOW; |
79 | 6.25M | } |
80 | 0 | else { |
81 | | /* IV-96bit, increment 32bit counter */ |
82 | 0 | if (0 == ++st->input[12]) return CRYPT_OVERFLOW; |
83 | 0 | } |
84 | 6.25M | if (inlen <= 64) { |
85 | 4.96M | for (i = 0; i < inlen; ++i) out[i] = in[i] ^ buf[i]; |
86 | 208k | st->ksleft = 64 - inlen; |
87 | 8.76M | for (i = inlen; i < 64; ++i) st->kstream[i] = buf[i]; |
88 | 208k | return CRYPT_OK; |
89 | 208k | } |
90 | 393M | for (i = 0; i < 64; ++i) out[i] = in[i] ^ buf[i]; |
91 | 6.04M | inlen -= 64; |
92 | 6.04M | out += 64; |
93 | 6.04M | in += 64; |
94 | 6.04M | } |
95 | 208k | } |
96 | | |
97 | | #endif |
98 | | |
99 | | /* ref: $Format:%D$ */ |
100 | | /* git commit: $Format:%H$ */ |
101 | | /* commit time: $Format:%ai$ */ |