1 /**
2 * RC4
3 * 
4 * Copyright:
5 * (C) 1999-2008 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.stream.rc4;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_RC4):
15 
16 import botan.stream.stream_cipher;
17 import botan.utils.types;
18 import botan.utils.xor_buf;
19 import botan.utils.rounding;
20 import botan.utils.mem_ops;
21 import std.conv : to;
22 import std.algorithm : swap;
23 
24 /**
25 * RC4 stream cipher
26 */
27 final class RC4 : StreamCipher, SymmetricAlgorithm
28 {
29 public:
30     /*
31     * Combine cipher stream with message
32     */
33     override void cipher(const(ubyte)* input, ubyte* output, size_t length)
34     {
35         while (length >= m_buffer.length - m_position)
36         {
37             xorBuf(output, input, &m_buffer[m_position], m_buffer.length - m_position);
38             length -= (m_buffer.length - m_position);
39             input += (m_buffer.length - m_position);
40             output += (m_buffer.length - m_position);
41             generate();
42         }
43         xorBuf(output, input, &m_buffer[m_position], length);
44         m_position += length;
45     }
46 
47     /*
48     * Clear memory of sensitive data
49     */
50     void clear()
51     {
52         zap(m_state);
53         zap(m_buffer);
54         m_position = m_X = m_Y = 0;
55     }
56 
57     /*
58     * Return the name of this type
59     */
60     @property string name() const
61     {
62         if (m_SKIP == 0)    return "RC4";
63         if (m_SKIP == 256)  return "MARK-4";
64         else                return "RC4_skip(" ~ to!string(m_SKIP) ~ ")";
65     }
66 
67     override RC4 clone() const { return new RC4(m_SKIP); }
68 
69     KeyLengthSpecification keySpec() const
70     {
71         return KeyLengthSpecification(1, 256);
72     }
73 
74     /**
75     * Params:
76     *  s = skip this many initial bytes in the keystream
77     */
78     this(size_t s = 0) { m_SKIP = s; }
79 
80     override bool validIvLength(size_t iv_len) const
81     { return (iv_len == 0); }
82 
83     override void setIv(const(ubyte)*, size_t iv_len) 
84     { 
85         if (iv_len) 
86             throw new InvalidArgument("The stream cipher " ~ name ~ " does not support resyncronization"); 
87     }
88 
89     ~this() { clear(); }
90 protected:
91     /*
92     * RC4 Key Schedule
93     */
94     override void keySchedule(const(ubyte)* key, size_t length)
95     {
96         m_state.resize(256);
97         m_buffer.resize(roundUp!size_t(DEFAULT_BUFFERSIZE, 4));
98         
99         m_position = m_X = m_Y = 0;
100         
101         foreach (size_t i; 0 .. 256)
102             m_state[i] = cast(ubyte)(i);
103         
104         for (size_t i = 0, state_index = 0; i != 256; ++i)
105         {
106             state_index = (state_index + key[i % length] + m_state[i]) % 256;
107             swap(m_state[i], m_state[state_index]);
108         }
109         
110         for (size_t i = 0; i <= m_SKIP; i += m_buffer.length)
111             generate();
112         
113         m_position += (m_SKIP % m_buffer.length);
114     }
115 
116 
117     /*
118     * Generate cipher stream
119     */
120     void generate()
121     {
122         ubyte SX, SY;
123         for (size_t i = 0; i != m_buffer.length; i += 4)
124         {
125             SX = m_state[m_X+1]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y];
126             m_state[m_X+1] = SY; m_state[m_Y] = SX;
127             m_buffer[i] = m_state[(SX + SY) % 256];
128             
129             SX = m_state[m_X+2]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y];
130             m_state[m_X+2] = SY; m_state[m_Y] = SX;
131             m_buffer[i+1] = m_state[(SX + SY) % 256];
132             
133             SX = m_state[m_X+3]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y];
134             m_state[m_X+3] = SY; m_state[m_Y] = SX;
135             m_buffer[i+2] = m_state[(SX + SY) % 256];
136             
137             m_X = (m_X + 4) % 256;
138             SX = m_state[m_X]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y];
139             m_state[m_X] = SY; m_state[m_Y] = SX;
140             m_buffer[i+3] = m_state[(SX + SY) % 256];
141         }
142         m_position = 0;
143     }
144 
145     const size_t m_SKIP;
146 
147     ubyte m_X, m_Y;
148     SecureVector!ubyte m_state;
149 
150     SecureVector!ubyte m_buffer;
151     size_t m_position;
152 }