1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /* The implementation is based on:
5  * "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
6  * and salsa20-ref.c version 20051118
7  * Public domain from D. J. Bernstein
8  */
9 
10 #include "tomcrypt_private.h"
11 
12 #ifdef LTC_SALSA20
13 
14 #define QUARTERROUND(a,b,c,d) \
15     x[b] ^= (ROL((x[a] + x[d]),  7)); \
16     x[c] ^= (ROL((x[b] + x[a]),  9)); \
17     x[d] ^= (ROL((x[c] + x[b]), 13)); \
18     x[a] ^= (ROL((x[d] + x[c]), 18));
19 
s_salsa20_block(unsigned char * output,const ulong32 * input,int rounds)20 static void s_salsa20_block(unsigned char *output, const ulong32 *input, int rounds)
21 {
22    ulong32 x[16];
23    int i;
24    XMEMCPY(x, input, sizeof(x));
25    for (i = rounds; i > 0; i -= 2) {
26       QUARTERROUND( 0, 4, 8,12)
27       QUARTERROUND( 5, 9,13, 1)
28       QUARTERROUND(10,14, 2, 6)
29       QUARTERROUND(15, 3, 7,11)
30       QUARTERROUND( 0, 1, 2, 3)
31       QUARTERROUND( 5, 6, 7, 4)
32       QUARTERROUND(10,11, 8, 9)
33       QUARTERROUND(15,12,13,14)
34    }
35    for (i = 0; i < 16; ++i) {
36      x[i] += input[i];
37      STORE32L(x[i], output + 4 * i);
38    }
39 }
40 
41 /**
42    Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Salsa20
43    @param st      The Salsa20 state
44    @param in      The plaintext (or ciphertext)
45    @param inlen   The length of the input (octets)
46    @param out     [out] The ciphertext (or plaintext), length inlen
47    @return CRYPT_OK if successful
48 */
salsa20_crypt(salsa20_state * st,const unsigned char * in,unsigned long inlen,unsigned char * out)49 int salsa20_crypt(salsa20_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
50 {
51    unsigned char buf[64];
52    unsigned long i, j;
53 
54    if (inlen == 0) return CRYPT_OK; /* nothing to do */
55 
56    LTC_ARGCHK(st        != NULL);
57    LTC_ARGCHK(in        != NULL);
58    LTC_ARGCHK(out       != NULL);
59    LTC_ARGCHK(st->ivlen == 8 || st->ivlen == 24);
60 
61    if (st->ksleft > 0) {
62       j = MIN(st->ksleft, inlen);
63       for (i = 0; i < j; ++i, st->ksleft--) out[i] = in[i] ^ st->kstream[64 - st->ksleft];
64       inlen -= j;
65       if (inlen == 0) return CRYPT_OK;
66       out += j;
67       in  += j;
68    }
69    for (;;) {
70      s_salsa20_block(buf, st->input, st->rounds);
71      /* Salsa20: 64-bit IV, increment 64-bit counter */
72      if (0 == ++st->input[8] && 0 == ++st->input[9]) return CRYPT_OVERFLOW;
73      if (inlen <= 64) {
74        for (i = 0; i < inlen; ++i) out[i] = in[i] ^ buf[i];
75        st->ksleft = 64 - inlen;
76        for (i = inlen; i < 64; ++i) st->kstream[i] = buf[i];
77        return CRYPT_OK;
78      }
79      for (i = 0; i < 64; ++i) out[i] = in[i] ^ buf[i];
80      inlen -= 64;
81      out += 64;
82      in  += 64;
83    }
84 }
85 
86 #endif
87