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 }