1 /// Implementation of RC4 digester.
2 module tern.digest.rc4;
3 
4 import tern.serialization;
5 import tern.digest;
6 import tern.digest.circe;
7 
8 /**
9  * Implementation of RC4 digester.
10  *
11  * RC4 (Rivest Cipher 4) is a stream cipher algorithm widely used in various cryptographic 
12  * applications. It operates by generating a pseudorandom stream of bits (keystream) based on 
13  * a secret key, which is then XORed with the plaintext to produce the ciphertext.
14  *
15  * Example:
16  * ```d
17  * import tern.digest.rc4;
18  * 
19  * ubyte[] data = [1, 2, 3, 4, 5];
20  * string key = "my_secret_key";
21  * RC4.encrypt(data, key);
22  * ```
23  */
24 public static @digester class RC4
25 {
26 public:
27 static:
28 pure:
29     /**
30      * Encrypts the given byte array `data`.
31      *
32      * Params:
33      *  data = Reference to the input byte array to be encrypted.
34      *  key = The encryption key.
35      */
36     void encrypt(ref ubyte[] data, string key) 
37     {        
38         assert(key.length == 32, "Key must be 256 bits!");
39         
40         key = cast(string)Circe.hash(cast(ubyte[])key);
41         ubyte[256] S;
42         ubyte[256] T;
43 
44         for (ubyte i = 0; i < 256; ++i) 
45         {
46             S[i] = i;
47             T[i] = cast(ubyte)key[i % key.length];
48         }
49 
50         ubyte j = 0;
51         for (ubyte i = 0; i < 256; ++i) 
52         {
53             j = (j + S[i] + T[i]) % 256;
54             S[i] = S[i] ^ S[j];
55             S[j] = S[i] ^ S[j];
56             S[i] = S[i] ^ S[j];
57         }
58 
59         ubyte i = 0;
60         j = 0;
61         foreach (ref b; data) 
62         {
63             i = (i + 1) % 256;
64             j = (j + S[i]) % 256;
65             S[i] = S[i] ^ S[j];
66             S[j] = S[i] ^ S[j];
67             S[i] = S[i] ^ S[j];
68             b ^= S[(S[i] + S[j]) % 256];
69         }
70     }
71 
72     /**
73      * Decrypts the given byte array `data`.
74      *
75      * Params:
76      *  data = Reference to the input byte array to be decrypted.
77      *  key = The decryption key.
78      */
79     void decrypt(ref ubyte[] data, string key) => encrypt(data, key);
80 }