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