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 }