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