Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Ticket #857: Cipher.d

File Cipher.d, 13.0 kB (added by Wazar, 2 years ago)
Line 
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 alias char[] string;
12
13 /** Base symmetric cipher class */
14 abstract class Cipher
15 {
16     interface Parameters {}
17
18     static const bool ENCRYPT = true,
19                       DECRYPT = false;
20                      
21     protected bool _initialized,
22                    _encrypt;
23    
24     /**
25      * Process a block of plaintext data from the input array
26      * and place it in the output array.
27      *
28      * Params:
29      *     input_  = Array containing input data.
30      *     output_  = Array to hold the output data.
31      *
32      * Returns: The amount of encrypted data processed.
33      */
34     abstract uint update(void[] input_, void[] output_);
35    
36     /** Returns: The name of the algorithm of this cipher. */
37     abstract string name();
38    
39     /** Reset cipher to its state immediately subsequent the last init. */
40     abstract void reset();
41    
42     /**
43      * throw an InvalidArgument exception
44      *
45      * Params:
46      *     msg = message to associate with the exception
47      */
48     static void invalid (char[] msg)
49     {
50         throw new IllegalArgumentException (msg);
51     }
52      
53     /** Returns: Whether or not the cipher has been initialized. */
54     final bool initialized()
55     {
56         return _initialized;
57     }
58 }
59
60
61
62 /** Interface for a standard block cipher. */
63 abstract class BlockCipher : Cipher
64 {
65     /** Returns: The block size in bytes that this cipher will operate on. */
66     abstract uint blockSize();
67 }
68
69
70 /** Interface for a standard stream cipher. */
71 abstract class StreamCipher : Cipher
72 {  
73     /**
74      * Process one byte of input.
75      *
76      * Params:
77      *     input = Byte to XOR with keystream.
78      *
79      * Returns: One byte of input XORed with the keystream.
80      */
81     abstract ubyte returnByte(ubyte input);
82 }
83
84  
85  /** Base padding class for implementing block padding schemes. */
86  abstract class BlockCipherPadding
87  {
88     /** Returns: The name of the padding scheme implemented. */
89     abstract string name();
90
91     /**
92     * Generate padding to a specific length.
93     *
94     * Params:
95     *     len = Length of padding to generate
96     *
97     * Returns: The padding bytes to be added.
98     */
99     abstract ubyte[] pad(uint len);
100
101     /**
102     * Return the number of pad bytes in the block.
103     *
104     * Params:
105     *     input_ = Padded block of which to count the pad bytes.
106     *
107     * Returns: The number of pad bytes in the block.
108     *
109     * Throws: dcrypt.crypto.errors.InvalidPaddingError if
110     *         pad length cannot be discerned.
111     */
112     abstract uint unpad(void[] input_);
113  }
114
115
116
117 /** Object representing and wrapping a symmetric key in bytes. */
118 class SymmetricKey : Cipher.Parameters
119 {
120     private ubyte[] _key;
121    
122     /**
123      * Params:
124      *     key = Key to be held.
125      */
126     this(void[] key=null)
127     {
128         _key = cast(ubyte[]) key;
129     }
130    
131     /** Play nice with D2's idea of const. */
132     version (D_Version2)
133     {
134         this (string key)
135         {
136             this(cast(ubyte[])key);
137         }
138     }
139    
140     /** Returns: Key in ubytes held by this object. */
141     ubyte[] key()
142     {
143         return _key;
144     }
145    
146     /**
147      * Set the key held by this object.
148      *
149      * Params:
150      *     newKey = New key to be held.
151      * Returns: The new key.
152      */
153     ubyte[] key(void[] newKey)
154     {
155         return _key = cast(ubyte[]) newKey;
156     }
157 }
158
159
160 /** Wrap cipher parameters and IV. */
161 class ParametersWithIV : Cipher.Parameters
162 {
163     private ubyte[] _iv;
164     private Cipher.Parameters _params;
165    
166     /**
167      * Params:
168      *     params = Parameters to wrap.
169      *     iv     = IV to be held.
170      */
171     this (Cipher.Parameters params=null, void[] iv=null)
172     {
173         _params = params;
174         _iv = cast(ubyte[]) iv;
175     }
176    
177     /** Returns: The IV. */
178     ubyte[] iv()
179     {
180         return _iv;
181     }
182    
183     /**
184      * Set the IV held by this object.
185      *
186      * Params:
187      *     newIV = The new IV for this parameter object.
188      * Returns: The new IV.
189      */
190     ubyte[] iv(void[] newIV)
191     {
192         return _iv = cast(ubyte[]) newIV;
193     }
194    
195     /** Returns: The parameters for this object. */
196     Cipher.Parameters parameters()
197     {
198         return _params;
199     }
200    
201     /**
202      * Set the parameters held by this object.
203      *
204      * Params:
205      *     newParams = The new parameters to be held.
206      * Returns: The new parameters.
207      */
208     Cipher.Parameters parameters(Cipher.Parameters newParams)
209     {
210         return _params = newParams;
211     }
212 }
213
214
215 struct Bitwise
216 {
217     static uint rotateLeft(uint x, uint y)
218     {
219         return (x << y) | (x >> (32u-y));
220     }
221    
222     static uint rotateRight(uint x, uint y)
223     {
224         return (x >> y) | (x << (32u-y));   
225     }
226    
227     static ulong rotateLeft(ulong x, uint y)
228     {
229         return (x << y) | (x >> (64u-y));
230     }
231    
232     static ulong rotateRight(ulong x, uint y)
233     {
234         return (x >> y) | (x << (64u-y));   
235     }
236 }
237
238
239 /** Converts between integral types and unsigned byte arrays */
240 struct ByteConverter
241 {
242     private static string hexits = "0123456789abcdef";
243     private static string base32digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
244    
245     /** Conversions between little endian integrals and bytes */
246     struct LittleEndian
247     {
248         /**
249          * Converts the supplied array to integral type T
250          *
251          * Params:
252          *     x_ = The supplied array of bytes (ubytes, bytes, chars, whatever)
253          *
254          * Returns:
255          *     A integral of type T created with the supplied bytes placed
256          *     in the specified byte order.
257          */
258         static T to(T)(void[] x_)
259         {
260             ubyte[] x = cast(ubyte[])x_;
261            
262             T result = ((cast(T)x[0])       |
263                        ((cast(T)x[1]) << 8));
264                        
265             static if (T.sizeof >= int.sizeof)
266             {
267                 result |= ((cast(T)x[2]) << 16) |
268                           ((cast(T)x[3]) << 24);
269             }
270            
271             static if (T.sizeof >= long.sizeof)
272             {
273                 result |= ((cast(T)x[4]) << 32) |
274                           ((cast(T)x[5]) << 40) |
275                           ((cast(T)x[6]) << 48) |
276                           ((cast(T)x[7]) << 56);
277             }
278            
279             return result;
280         }
281        
282         /**
283          * Converts the supplied integral to an array of unsigned bytes.
284          *
285          * Params:
286          *     input = Integral to convert to bytes
287          *
288          * Returns:
289          *     Integral input of type T split into its respective bytes
290          *     with the bytes placed in the specified byte order.
291          */
292         static ubyte[] from(T)(T input)
293         {
294             ubyte[] output = new ubyte[T.sizeof];
295            
296             output[0] = cast(ubyte)(input);
297             output[1] = cast(ubyte)(input >> 8);
298            
299             static if (T.sizeof >= int.sizeof)
300             {
301                 output[2] = cast(ubyte)(input >> 16);
302                 output[3] = cast(ubyte)(input >> 24);
303             }
304            
305             static if (T.sizeof >= long.sizeof)
306             {
307                 output[4] = cast(ubyte)(input >> 32);
308                 output[5] = cast(ubyte)(input >> 40);
309                 output[6] = cast(ubyte)(input >> 48);
310                 output[7] = cast(ubyte)(input >> 56);
311             }
312            
313             return output;
314         }
315     }
316    
317     /** Conversions between big endian integrals and bytes */
318     struct BigEndian
319     {
320        
321         static T to(T)(void[] x_)
322         {
323             ubyte[] x = cast(ubyte[])x_;
324            
325             static if (is(T == ushort) || is(T == short))
326             {
327                 return cast(T) (((x[0] & 0xff) << 8) |
328                                  (x[1] & 0xff));
329             }
330             else static if (is(T == uint) || is(T == int))
331             {
332                 return cast(T) (((x[0] & 0xff) << 24) |
333                                 ((x[1] & 0xff) << 16) |
334                                 ((x[2] & 0xff) << 8)  |
335                                  (x[3] & 0xff));
336             }
337             else static if (is(T == ulong) || is(T == long))
338             {
339                 return cast(T) ((cast(T)(x[0] & 0xff) << 56) |
340                                 (cast(T)(x[1] & 0xff) << 48) |
341                                 (cast(T)(x[2] & 0xff) << 40) |
342                                 (cast(T)(x[3] & 0xff) << 32) |
343                                 ((x[4] & 0xff) << 24) |
344                                 ((x[5] & 0xff) << 16) |
345                                 ((x[6] & 0xff) << 8)  |
346                                  (x[7] & 0xff));
347             }
348         }
349        
350         static ubyte[] from(T)(T input)
351         {
352             ubyte[] output = new ubyte[T.sizeof];
353            
354             static if (T.sizeof == long.sizeof)
355             {
356                 output[0] = cast(ubyte)(input >> 56);
357                 output[1] = cast(ubyte)(input >> 48);
358                 output[2] = cast(ubyte)(input >> 40);
359                 output[3] = cast(ubyte)(input >> 32);
360                 output[4] = cast(ubyte)(input >> 24);
361                 output[5] = cast(ubyte)(input >> 16);
362                 output[6] = cast(ubyte)(input >> 8);
363                 output[7] = cast(ubyte)(input);
364             }
365             else static if (T.sizeof == int.sizeof)
366             {
367                 output[0] = cast(ubyte)(input >> 24);
368                 output[1] = cast(ubyte)(input >> 16);
369                 output[2] = cast(ubyte)(input >> 8);
370                 output[3] = cast(ubyte)(input);
371             }
372             else static if (T.sizeof == short.sizeof)
373             {
374                 output[0] = cast(ubyte)(input >> 8);
375                 output[1] = cast(ubyte)(input);
376             }
377            
378             return output;
379         }
380     }
381
382     static string hexEncode(void[] input_)
383     {
384         ubyte[] input = cast(ubyte[])input_;
385         char[] output = new char[input.length<<1];
386        
387         int i = 0;
388         foreach (ubyte j; input)
389         {
390             output[i++] = hexits[j>>4];
391             output[i++] = hexits[j&0xf];
392         }
393        
394         return cast(string)output;   
395     }
396    
397     static string base32Encode(void[] input_, bool doPad=true)
398     {
399         if (!input_)
400             return "";
401         ubyte[] input = cast(ubyte[])input_;
402         char[] output;
403         auto inputbits = input.length*8;
404         auto inputquantas = inputbits / 40;
405         if (inputbits % 40)
406             output = new char[(inputquantas+1) * 8];
407         else
408             output = new char[inputquantas * 8];
409
410         int i = 0;
411         ushort remainder;
412         ubyte remainlen;
413         foreach (ubyte j; input)
414         {
415             remainder = (remainder<<8) | j;
416             remainlen += 8;
417             while (remainlen > 5) {
418                 output[i++] = base32digits[(remainder>>(remainlen-5))&0b11111];
419                 remainlen -= 5;
420             }
421         }
422         if (remainlen)
423             output[i++] = base32digits[(remainder<<(5-remainlen))&0b11111];
424         while (doPad && (i < output.length)) {
425             output[i++] = '=';
426         }
427
428         return output[0..i];
429     }
430
431     static ubyte[] hexDecode(string input)
432     {
433         string inputAsLower = stringToLower(input);
434         ubyte[] output = new ubyte[input.length>>1];
435        
436         static ubyte[char] hexitIndex;
437         for (int i = 0; i < hexits.length; i++)
438             hexitIndex[hexits[i]] = cast(ubyte) i;
439            
440         for (int i = 0, j = 0; i < output.length; i++)
441         {
442             output[i] = cast(ubyte) (hexitIndex[inputAsLower[j++]] << 4);
443             output[i] |= hexitIndex[inputAsLower[j++]];
444         }
445        
446         return output;
447     }
448    
449     static ubyte[] base32Decode(string input)
450     {
451         static ubyte[char] b32Index;
452         for (int i = 0; i < base32digits.length; i++)
453             b32Index[base32digits[i]] = cast(ubyte) i;
454
455         auto outlen = (input.length*5)/8;
456         ubyte[] output = new ubyte[outlen];
457
458         ushort remainder;
459         ubyte remainlen;
460         size_t oIndex;
461         foreach (c; stringToUpper(input))
462         {
463             if (c == '=')
464                 continue;
465             remainder = (remainder<<5) | b32Index[c];
466             remainlen += 5;
467             while (remainlen >= 8) {
468                 output[oIndex++] = cast(ubyte) (remainder >> (remainlen-8));
469                 remainlen -= 8;
470             }
471         }
472
473         return output[0..oIndex];
474     }
475
476     private static string stringToLower(string input)
477     {
478         char[] output = new char[input.length];
479        
480         foreach (int i, char c; input)
481             output[i] = cast(char) ((c >= 'A' && c <= 'Z') ? c+32 : c);
482            
483         return cast(string)output;
484     }
485
486     private static string stringToUpper(string input)
487     {
488         char[] output = new char[input.length];
489
490         foreach (int i, char c; input)
491             output[i] = cast(char) ((c >= 'a' && c <= 'z') ? c-32 : c);
492
493         return cast(string)output;
494     }
495 }