1 /**
2  * Copyright: Copyright (C) Thomas Dixon 2008. All rights reserved.
3  * License:   BSD style: $(LICENSE)
4  * Authors:   Thomas Dixon
5  */
6 
7 module tango.util.cipher.Cipher;
8 
9 private import tango.core.Exception : IllegalArgumentException;
10 
11 /** Base symmetric cipher class */
12 abstract class Cipher
13 {
14     enum bool ENCRYPT = true,
15               DECRYPT = false;
16 
17     protected bool _initialized,
18                    _encrypt;
19 
20     /**
21      * Process a block of plaintext data from the input array
22      * and place it in the output array.
23      *
24      * Params:
25      *     input_  = Array containing input data.
26      *     output_  = Array to hold the output data.
27      *
28      * Returns: The amount of encrypted data processed.
29      */
30     abstract uint update(const(void[]) input_, void[] output_);
31 
32     /** Returns: The name of the algorithm of this cipher. */
33     @property abstract const(char)[] name();
34 
35     /** Reset cipher to its state immediately subsequent the last init. */
36     abstract void reset();
37 
38     /**
39      * throw an InvalidArgument exception
40      *
41      * Params:
42      *     msg = message to associate with the exception
43      */
44     static void invalid (const(char[]) msg)
45     {
46         throw new IllegalArgumentException (msg.idup);
47     }
48 
49     /** Returns: Whether or not the cipher has been initialized. */
50     final const bool initialized()
51     {
52         return _initialized;
53     }
54 
55     static protected void reverse(T)(T[] arr)
56     {
57         foreach (i ; 0 .. arr.length / 2)
58         {
59             auto tmp = arr[i];
60             arr[i] = arr[arr.length - i - 1];
61             arr[arr.length - i - 1] = tmp;
62         }
63     }
64 }
65 
66 
67 
68 /** Interface for a standard block cipher. */
69 abstract class BlockCipher : Cipher
70 {
71     /** Returns: The block size in bytes that this cipher will operate on. */
72     @property abstract const uint blockSize();
73 }
74 
75 
76 /** Interface for a standard stream cipher. */
77 abstract class StreamCipher : Cipher
78 {
79     /**
80      * Process one byte of input.
81      *
82      * Params:
83      *     input = Byte to XOR with keystream.
84      *
85      * Returns: One byte of input XORed with the keystream.
86      */
87     abstract ubyte returnByte(ubyte input);
88 }
89 
90 
91  /** Base padding class for implementing block padding schemes. */
92  abstract class BlockCipherPadding
93  {
94     /** Returns: The name of the padding scheme implemented. */
95     @property abstract const(char)[] name();
96 
97     /**
98     * Generate padding to a specific length.
99     *
100     * Params:
101     *     len = Length of padding to generate
102     *
103     * Returns: The padding bytes to be added.
104     */
105     abstract ubyte[] pad(uint len);
106 
107     /**
108     * Return the number of pad bytes in the block.
109     *
110     * Params:
111     *     input_ = Padded block of which to count the pad bytes.
112     *
113     * Returns: The number of pad bytes in the block.
114     *
115     * Throws: dcrypt.crypto.errors.InvalidPaddingError if
116     *         pad length cannot be discerned.
117     */
118     abstract uint unpad(const(void[]) input_);
119  }
120 
121 struct Bitwise
122 {
123     static uint rotateLeft(uint x, uint y)
124     {
125         return (x << y) | (x >> (32u-y));
126     }
127 
128     static uint rotateRight(uint x, uint y)
129     {
130         return (x >> y) | (x << (32u-y));
131     }
132 
133     static ulong rotateLeft(ulong x, uint y)
134     {
135         return (x << y) | (x >> (64u-y));
136     }
137 
138     static ulong rotateRight(ulong x, uint y)
139     {
140         return (x >> y) | (x << (64u-y));
141     }
142 }
143 
144 
145 /** Converts between integral types and unsigned byte arrays */
146 struct ByteConverter
147 {
148     private __gshared immutable immutable(char)[] hexits = "0123456789abcdef";
149     private __gshared immutable immutable(char)[] base32digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
150 
151     /** Conversions between little endian integrals and bytes */
152     struct LittleEndian
153     {
154         /**
155          * Converts the supplied array to integral type T
156          *
157          * Params:
158          *     x_ = The supplied array of bytes (ubytes, bytes, chars, whatever)
159          *
160          * Returns:
161          *     A integral of type T created with the supplied bytes placed
162          *     in the specified byte order.
163          */
164         static T to(T)(const(void[]) x_)
165         {
166             const(ubyte[]) x = cast(const(ubyte[]))x_;
167 
168             T result = ((cast(T)x[0])       |
169                        ((cast(T)x[1]) << 8));
170 
171             static if (T.sizeof >= int.sizeof)
172             {
173                 result |= ((cast(T)x[2]) << 16) |
174                           ((cast(T)x[3]) << 24);
175             }
176 
177             static if (T.sizeof >= long.sizeof)
178             {
179                 result |= ((cast(T)x[4]) << 32) |
180                           ((cast(T)x[5]) << 40) |
181                           ((cast(T)x[6]) << 48) |
182                           ((cast(T)x[7]) << 56);
183             }
184 
185             return result;
186         }
187 
188         /**
189          * Converts the supplied integral to an array of unsigned bytes.
190          *
191          * Params:
192          *     input = Integral to convert to bytes
193          *
194          * Returns:
195          *     Integral input of type T split into its respective bytes
196          *     with the bytes placed in the specified byte order.
197          */
198         static void from(T)(T input, ubyte[] output)
199         {
200             output[0] = cast(ubyte)(input);
201             output[1] = cast(ubyte)(input >> 8);
202 
203             static if (T.sizeof >= int.sizeof)
204             {
205                 output[2] = cast(ubyte)(input >> 16);
206                 output[3] = cast(ubyte)(input >> 24);
207             }
208 
209             static if (T.sizeof >= long.sizeof)
210             {
211                 output[4] = cast(ubyte)(input >> 32);
212                 output[5] = cast(ubyte)(input >> 40);
213                 output[6] = cast(ubyte)(input >> 48);
214                 output[7] = cast(ubyte)(input >> 56);
215             }
216         }
217     }
218 
219     /** Conversions between big endian integrals and bytes */
220     struct BigEndian
221     {
222 
223         static T to(T)(const(void[]) x_)
224         {
225             const(ubyte[]) x = cast(const(ubyte[]))x_;
226 
227             static if (is(T == ushort) || is(T == short))
228             {
229                 return cast(T) (((x[0] & 0xff) << 8) |
230                                  (x[1] & 0xff));
231             }
232             else static if (is(T == uint) || is(T == int))
233             {
234                 return cast(T) (((x[0] & 0xff) << 24) |
235                                 ((x[1] & 0xff) << 16) |
236                                 ((x[2] & 0xff) << 8)  |
237                                  (x[3] & 0xff));
238             }
239             else static if (is(T == ulong) || is(T == long))
240             {
241                 return cast(T) ((cast(T)(x[0] & 0xff) << 56) |
242                                 (cast(T)(x[1] & 0xff) << 48) |
243                                 (cast(T)(x[2] & 0xff) << 40) |
244                                 (cast(T)(x[3] & 0xff) << 32) |
245                                 ((x[4] & 0xff) << 24) |
246                                 ((x[5] & 0xff) << 16) |
247                                 ((x[6] & 0xff) << 8)  |
248                                  (x[7] & 0xff));
249             }
250         }
251 
252         static void from(T)(T input, ubyte[] output)
253         {
254             static if (T.sizeof == long.sizeof)
255             {
256                 output[0] = cast(ubyte)(input >> 56);
257                 output[1] = cast(ubyte)(input >> 48);
258                 output[2] = cast(ubyte)(input >> 40);
259                 output[3] = cast(ubyte)(input >> 32);
260                 output[4] = cast(ubyte)(input >> 24);
261                 output[5] = cast(ubyte)(input >> 16);
262                 output[6] = cast(ubyte)(input >> 8);
263                 output[7] = cast(ubyte)(input);
264             }
265             else static if (T.sizeof == int.sizeof)
266             {
267                 output[0] = cast(ubyte)(input >> 24);
268                 output[1] = cast(ubyte)(input >> 16);
269                 output[2] = cast(ubyte)(input >> 8);
270                 output[3] = cast(ubyte)(input);
271             }
272             else static if (T.sizeof == short.sizeof)
273             {
274                 output[0] = cast(ubyte)(input >> 8);
275                 output[1] = cast(ubyte)(input);
276             }
277         }
278     }
279 
280     static char[] hexEncode(const(void[]) input_)
281     {
282         const(ubyte[]) input = cast(const(ubyte[]))input_;
283         char[] output = new char[input.length<<1];
284 
285         int i = 0;
286         foreach (ubyte j; input)
287         {
288             output[i++] = hexits[j>>4];
289             output[i++] = hexits[j&0xf];
290         }
291 
292         return output;
293     }
294 
295     static char[] base32Encode(const(void[]) input_, bool doPad=true)
296     {
297         if (!input_)
298             return "".dup;
299         const(ubyte[]) input = cast(const(ubyte[]))input_;
300         char[] output;
301         auto inputbits = input.length*8;
302         auto inputquantas = inputbits / 40;
303         if (inputbits % 40)
304             output = new char[(inputquantas+1) * 8];
305         else
306             output = new char[inputquantas * 8];
307 
308         int i = 0;
309         ushort remainder;
310         ubyte remainlen;
311         foreach (ubyte j; input)
312         {
313             remainder = cast(ushort)(remainder<<8) | j;
314             remainlen += 8;
315             while (remainlen > 5) {
316                 output[i++] = base32digits[(remainder>>(remainlen-5))&0b11111];
317                 remainlen -= 5;
318             }
319         }
320         if (remainlen)
321             output[i++] = base32digits[(remainder<<(5-remainlen))&0b11111];
322         while (doPad && (i < output.length)) {
323             output[i++] = '=';
324         }
325 
326         return output[0..i];
327     }
328 
329     static ubyte[] hexDecode(const(char[]) input)
330     {
331         char[] inputAsLower = stringToLower(input);
332         ubyte[] output = new ubyte[input.length>>1];
333 
334         static __gshared ubyte[char] hexitIndex;
335         for (int i = 0; i < hexits.length; i++)
336             hexitIndex[hexits[i]] = cast(ubyte) i;
337 
338         for (int i = 0, j = 0; i < output.length; i++)
339         {
340             output[i] = cast(ubyte) (hexitIndex[inputAsLower[j++]] << 4);
341             output[i] |= hexitIndex[inputAsLower[j++]];
342         }
343 
344         return output;
345     }
346 
347     static ubyte[] base32Decode(const(char[]) input)
348     {
349         static __gshared ubyte[char] b32Index;
350         for (int i = 0; i < base32digits.length; i++)
351             b32Index[base32digits[i]] = cast(ubyte) i;
352 
353         auto outlen = (input.length*5)/8;
354         ubyte[] output = new ubyte[outlen];
355 
356         ushort remainder;
357         ubyte remainlen;
358         size_t oIndex;
359         foreach (c; stringToUpper(input))
360         {
361             if (c == '=')
362                 continue;
363             remainder = cast(ushort)(remainder<<5) | b32Index[c];
364             remainlen += 5;
365             while (remainlen >= 8) {
366                 output[oIndex++] = cast(ubyte) (remainder >> (remainlen-8));
367                 remainlen -= 8;
368             }
369         }
370 
371         return output[0..oIndex];
372     }
373 
374     private static char[] stringToLower(const(char[]) input)
375     {
376         char[] output = new char[input.length];
377 
378         foreach (i, char c; input)
379             output[i] = cast(char) ((c >= 'A' && c <= 'Z') ? c+32 : c);
380 
381         return cast(char[])output;
382     }
383 
384     private static char[] stringToUpper(const(char[]) input)
385     {
386         char[] output = new char[input.length];
387 
388         foreach (i, char c; input)
389             output[i] = cast(char) ((c >= 'a' && c <= 'z') ? c-32 : c);
390 
391         return cast(char[])output;
392     }
393 }