1 /// Implementation of Salsa20 digester.
2 module tern.digest.salsa20;
3 
4 import tern.digest;
5 import tern.digest.circe;
6 
7 /**
8  * Implementation of Salsa20 digester.
9  *
10  * Salsa20 is a stream cipher designed to be highly efficient and secure. It operates 
11  * on 512-bit (64-byte) blocks and accepts a 256-bit (32-byte) key and a 64-bit (8-byte) 
12  * nonce.
13  *
14  * Example:
15  * ```d
16  * import tern.digest.salsa20;
17  *
18  * ubyte[] data = [1, 2, 3, 4, 5];
19  * string key = "my_secret_key"; // Must be exactly 256 bits (32 bytes) in length.
20  * ubyte[8] nonce = [0, 0, 0, 0, 0, 0, 0, 0]; // Must be exactly 64 bits (8 bytes) in length.
21  * Salsa20.encrypt(data, key, nonce);
22  * ```
23  */
24 public static @digester class Salsa20
25 {
26 private:
27 static:
28     void quarterRound(ref uint[16] block, uint a, uint b, uint c, uint d)
29     {
30         block[a] += block[b]; block[d] = (block[d] ^ block[a]) << 7 | (block[d] ^ block[a]) >>> (32 - 7);
31         block[c] += block[d]; block[b] = (block[b] ^ block[c]) << 9 | (block[b] ^ block[c]) >>> (32 - 9);
32         block[a] += block[b]; block[d] = (block[d] ^ block[a]) << 13 | (block[d] ^ block[a]) >>> (32 - 13);
33         block[c] += block[d]; block[b] = (block[b] ^ block[c]) << 18 | (block[b] ^ block[c]) >>> (32 - 18);
34     }
35 
36     uint[16] innerRound(ref uint[16] block)
37     {
38         foreach (i; 0 .. 10) 
39         {
40             quarterRound(block, 0, 4, 8, 12);
41             quarterRound(block, 1, 5, 9, 13);
42             quarterRound(block, 2, 6, 10, 14);
43             quarterRound(block, 3, 7, 11, 15);
44             quarterRound(block, 0, 5, 10, 15);
45             quarterRound(block, 1, 6, 11, 12);
46             quarterRound(block, 2, 7, 8, 13);
47             quarterRound(block, 3, 4, 9, 14);
48         }
49         return block;
50     }
51 
52 public:
53     /**
54      * Encrypts the given byte array `data`.
55      *
56      * Params:
57      *  data: Reference to the input byte array to be encrypted.
58      *  key: The encryption key. Must be exactly 256 bits (32 bytes) in length.
59      *  nonce: The nonce value. Must be exactly 64 bits (8 bytes) in length.
60      */
61     void encrypt(ref ubyte[] data, string key, ubyte[8] nonce = (ubyte[8]).init, uint counter = 0)
62     {
63         assert(key.length == 32, "Key must be 256 bits!");
64         key = cast(string)Circe.hash(cast(ubyte[])key);
65 
66         uint[16] state;
67         state[0..4] = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574];
68         state[4..12] = *cast(uint[8]*)key.ptr;
69         state[12..14] = counter;
70         state[14..16] = cast(uint[2])nonce;
71 
72         uint[16] keyStream;
73         ubyte offset = 64;
74 
75         foreach (ref octet; data) 
76         {
77             if (offset >= 64) 
78             {
79                 keyStream = state.dup;
80                 innerRound(keyStream);
81                 // Counter
82                 state[12]++;
83                 offset = 0;
84             }
85 
86             octet ^= (cast(ubyte[64])keyStream)[offset];
87             offset++;
88         }
89     }
90 
91     /**
92      * Decrypts the given byte array `data`.
93      *
94      * Params:
95      *  data: Reference to the input byte array to be encrypted.
96      *  key: The encryption key. Must be exactly 256 bits (32 bytes) in length.
97      *  nonce: The nonce value. Must be exactly 64 bits (8 bytes) in length.
98      */
99     void decrypt(ref ubyte[] data, string key, ubyte[8] nonce = (ubyte[8]).init, uint counter = 0) => encrypt(data, key, nonce, counter);
100 }