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 }