10ac341f1SConrad Meyer /*
20ac341f1SConrad Meyer version 20140420
30ac341f1SConrad Meyer D. J. Bernstein
40ac341f1SConrad Meyer Public domain.
50ac341f1SConrad Meyer */
60ac341f1SConrad Meyer 
70ac341f1SConrad Meyer #include <stdint.h>
80ac341f1SConrad Meyer 
90ac341f1SConrad Meyer #include "crypto_core_salsa20.h"
100ac341f1SConrad Meyer #include "crypto_stream_salsa20.h"
110ac341f1SConrad Meyer #include "utils.h"
120ac341f1SConrad Meyer 
130ac341f1SConrad Meyer #include "../stream_salsa20.h"
140ac341f1SConrad Meyer #include "salsa20_ref.h"
150ac341f1SConrad Meyer 
160ac341f1SConrad Meyer #ifndef HAVE_AMD64_ASM
170ac341f1SConrad Meyer 
180ac341f1SConrad Meyer static int
stream_ref(unsigned char * c,unsigned long long clen,const unsigned char * n,const unsigned char * k)190ac341f1SConrad Meyer stream_ref(unsigned char *c, unsigned long long clen, const unsigned char *n,
200ac341f1SConrad Meyer            const unsigned char *k)
210ac341f1SConrad Meyer {
220ac341f1SConrad Meyer     unsigned char in[16];
230ac341f1SConrad Meyer     unsigned char block[64];
240ac341f1SConrad Meyer     unsigned char kcopy[32];
250ac341f1SConrad Meyer     unsigned int  i;
260ac341f1SConrad Meyer     unsigned int  u;
270ac341f1SConrad Meyer 
280ac341f1SConrad Meyer     if (!clen) {
290ac341f1SConrad Meyer         return 0;
300ac341f1SConrad Meyer     }
310ac341f1SConrad Meyer     for (i = 0; i < 32; i++) {
320ac341f1SConrad Meyer         kcopy[i] = k[i];
330ac341f1SConrad Meyer     }
340ac341f1SConrad Meyer     for (i = 0; i < 8; i++) {
350ac341f1SConrad Meyer         in[i] = n[i];
360ac341f1SConrad Meyer     }
370ac341f1SConrad Meyer     for (i = 8; i < 16; i++) {
380ac341f1SConrad Meyer         in[i] = 0;
390ac341f1SConrad Meyer     }
400ac341f1SConrad Meyer     while (clen >= 64) {
410ac341f1SConrad Meyer         crypto_core_salsa20(c, in, kcopy, NULL);
420ac341f1SConrad Meyer         u = 1;
430ac341f1SConrad Meyer         for (i = 8; i < 16; i++) {
440ac341f1SConrad Meyer             u += (unsigned int) in[i];
450ac341f1SConrad Meyer             in[i] = u;
460ac341f1SConrad Meyer             u >>= 8;
470ac341f1SConrad Meyer         }
480ac341f1SConrad Meyer         clen -= 64;
490ac341f1SConrad Meyer         c += 64;
500ac341f1SConrad Meyer     }
510ac341f1SConrad Meyer     if (clen) {
520ac341f1SConrad Meyer         crypto_core_salsa20(block, in, kcopy, NULL);
530ac341f1SConrad Meyer         for (i = 0; i < (unsigned int) clen; i++) {
540ac341f1SConrad Meyer             c[i] = block[i];
550ac341f1SConrad Meyer         }
560ac341f1SConrad Meyer     }
570ac341f1SConrad Meyer     sodium_memzero(block, sizeof block);
580ac341f1SConrad Meyer     sodium_memzero(kcopy, sizeof kcopy);
590ac341f1SConrad Meyer 
600ac341f1SConrad Meyer     return 0;
610ac341f1SConrad Meyer }
620ac341f1SConrad Meyer 
630ac341f1SConrad Meyer static int
stream_ref_xor_ic(unsigned char * c,const unsigned char * m,unsigned long long mlen,const unsigned char * n,uint64_t ic,const unsigned char * k)640ac341f1SConrad Meyer stream_ref_xor_ic(unsigned char *c, const unsigned char *m,
650ac341f1SConrad Meyer                   unsigned long long mlen, const unsigned char *n, uint64_t ic,
660ac341f1SConrad Meyer                   const unsigned char *k)
670ac341f1SConrad Meyer {
680ac341f1SConrad Meyer     unsigned char in[16];
690ac341f1SConrad Meyer     unsigned char block[64];
700ac341f1SConrad Meyer     unsigned char kcopy[32];
710ac341f1SConrad Meyer     unsigned int  i;
720ac341f1SConrad Meyer     unsigned int  u;
730ac341f1SConrad Meyer 
740ac341f1SConrad Meyer     if (!mlen) {
750ac341f1SConrad Meyer         return 0;
760ac341f1SConrad Meyer     }
770ac341f1SConrad Meyer     for (i = 0; i < 32; i++) {
780ac341f1SConrad Meyer         kcopy[i] = k[i];
790ac341f1SConrad Meyer     }
800ac341f1SConrad Meyer     for (i = 0; i < 8; i++) {
810ac341f1SConrad Meyer         in[i] = n[i];
820ac341f1SConrad Meyer     }
830ac341f1SConrad Meyer     for (i = 8; i < 16; i++) {
840ac341f1SConrad Meyer         in[i] = (unsigned char) (ic & 0xff);
850ac341f1SConrad Meyer         ic >>= 8;
860ac341f1SConrad Meyer     }
870ac341f1SConrad Meyer     while (mlen >= 64) {
880ac341f1SConrad Meyer         crypto_core_salsa20(block, in, kcopy, NULL);
890ac341f1SConrad Meyer         for (i = 0; i < 64; i++) {
900ac341f1SConrad Meyer             c[i] = m[i] ^ block[i];
910ac341f1SConrad Meyer         }
920ac341f1SConrad Meyer         u = 1;
930ac341f1SConrad Meyer         for (i = 8; i < 16; i++) {
940ac341f1SConrad Meyer             u += (unsigned int) in[i];
950ac341f1SConrad Meyer             in[i] = u;
960ac341f1SConrad Meyer             u >>= 8;
970ac341f1SConrad Meyer         }
980ac341f1SConrad Meyer         mlen -= 64;
990ac341f1SConrad Meyer         c += 64;
1000ac341f1SConrad Meyer         m += 64;
1010ac341f1SConrad Meyer     }
1020ac341f1SConrad Meyer     if (mlen) {
1030ac341f1SConrad Meyer         crypto_core_salsa20(block, in, kcopy, NULL);
1040ac341f1SConrad Meyer         for (i = 0; i < (unsigned int) mlen; i++) {
1050ac341f1SConrad Meyer             c[i] = m[i] ^ block[i];
1060ac341f1SConrad Meyer         }
1070ac341f1SConrad Meyer     }
1080ac341f1SConrad Meyer     sodium_memzero(block, sizeof block);
1090ac341f1SConrad Meyer     sodium_memzero(kcopy, sizeof kcopy);
1100ac341f1SConrad Meyer 
1110ac341f1SConrad Meyer     return 0;
1120ac341f1SConrad Meyer }
1130ac341f1SConrad Meyer 
1140ac341f1SConrad Meyer struct crypto_stream_salsa20_implementation
1150ac341f1SConrad Meyer     crypto_stream_salsa20_ref_implementation = {
1160ac341f1SConrad Meyer         SODIUM_C99(.stream =) stream_ref,
1170ac341f1SConrad Meyer         SODIUM_C99(.stream_xor_ic =) stream_ref_xor_ic,
1180ac341f1SConrad Meyer     };
1190ac341f1SConrad Meyer 
1200ac341f1SConrad Meyer #endif
121