| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 | /** * Copyright: Copyright (C) Thomas Dixon 2008. All rights reserved. * License: BSD style: $(LICENSE) * Authors: Thomas Dixon */ module tango.util.cipher.Cipher; private import tango.core.Exception : IllegalArgumentException; /** Base symmetric cipher class */ abstract class Cipher { enum bool ENCRYPT = true, DECRYPT = false; protected bool _initialized, _encrypt; /** * Process a block of plaintext data from the input array * and place it in the output array. * * Params: * input_ = Array containing input data. * output_ = Array to hold the output data. * * Returns: The amount of encrypted data processed. */ abstract uint update(const(void[]) input_, void[] output_); /** Returns: The name of the algorithm of this cipher. */ @property abstract const(char)[] name(); /** Reset cipher to its state immediately subsequent the last init. */ abstract void reset(); /** * throw an InvalidArgument exception * * Params: * msg = message to associate with the exception */ static void invalid (const(char[]) msg) { throw new IllegalArgumentException (msg.idup); } /** Returns: Whether or not the cipher has been initialized. */ final const bool initialized() { return _initialized; } } /** Interface for a standard block cipher. */ abstract class BlockCipher : Cipher { /** Returns: The block size in bytes that this cipher will operate on. */ @property abstract const uint blockSize(); } /** Interface for a standard stream cipher. */ abstract class StreamCipher : Cipher { /** * Process one byte of input. * * Params: * input = Byte to XOR with keystream. * * Returns: One byte of input XORed with the keystream. */ abstract ubyte returnByte(ubyte input); } /** Base padding class for implementing block padding schemes. */ abstract class BlockCipherPadding { /** Returns: The name of the padding scheme implemented. */ @property abstract const(char)[] name(); /** * Generate padding to a specific length. * * Params: * len = Length of padding to generate * * Returns: The padding bytes to be added. */ abstract ubyte[] pad(uint len); /** * Return the number of pad bytes in the block. * * Params: * input_ = Padded block of which to count the pad bytes. * * Returns: The number of pad bytes in the block. * * Throws: dcrypt.crypto.errors.InvalidPaddingError if * pad length cannot be discerned. */ abstract uint unpad(const(void[]) input_); } struct Bitwise { static uint rotateLeft(uint x, uint y) { return (x << y) | (x >> (32u-y)); } static uint rotateRight(uint x, uint y) { return (x >> y) | (x << (32u-y)); } static ulong rotateLeft(ulong x, uint y) { return (x << y) | (x >> (64u-y)); } static ulong rotateRight(ulong x, uint y) { return (x >> y) | (x << (64u-y)); } } /** Converts between integral types and unsigned byte arrays */ struct ByteConverter { private enum immutable(char)[] hexits = "0123456789abcdef"; private enum immutable(char)[] base32digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; /** Conversions between little endian integrals and bytes */ struct LittleEndian { /** * Converts the supplied array to integral type T * * Params: * x_ = The supplied array of bytes (ubytes, bytes, chars, whatever) * * Returns: * A integral of type T created with the supplied bytes placed * in the specified byte order. */ static T to(T)(const(void[]) x_) { const(ubyte[]) x = cast(const(ubyte[]))x_; T result = ((cast(T)x[0]) | ((cast(T)x[1]) << 8)); static if (T.sizeof >= int.sizeof) { result |= ((cast(T)x[2]) << 16) | ((cast(T)x[3]) << 24); } static if (T.sizeof >= long.sizeof) { result |= ((cast(T)x[4]) << 32) | ((cast(T)x[5]) << 40) | ((cast(T)x[6]) << 48) | ((cast(T)x[7]) << 56); } return result; } /** * Converts the supplied integral to an array of unsigned bytes. * * Params: * input = Integral to convert to bytes * * Returns: * Integral input of type T split into its respective bytes * with the bytes placed in the specified byte order. */ static void from(T)(T input, ubyte[] output) { output[0] = cast(ubyte)(input); output[1] = cast(ubyte)(input >> 8); static if (T.sizeof >= int.sizeof) { output[2] = cast(ubyte)(input >> 16); output[3] = cast(ubyte)(input >> 24); } static if (T.sizeof >= long.sizeof) { output[4] = cast(ubyte)(input >> 32); output[5] = cast(ubyte)(input >> 40); output[6] = cast(ubyte)(input >> 48); output[7] = cast(ubyte)(input >> 56); } } } /** Conversions between big endian integrals and bytes */ struct BigEndian { static T to(T)(const(void[]) x_) { const(ubyte[]) x = cast(const(ubyte[]))x_; static if (is(T == ushort) || is(T == short)) { return cast(T) (((x[0] & 0xff) << 8) | (x[1] & 0xff)); } else static if (is(T == uint) || is(T == int)) { return cast(T) (((x[0] & 0xff) << 24) | ((x[1] & 0xff) << 16) | ((x[2] & 0xff) << 8) | (x[3] & 0xff)); } else static if (is(T == ulong) || is(T == long)) { return cast(T) ((cast(T)(x[0] & 0xff) << 56) | (cast(T)(x[1] & 0xff) << 48) | (cast(T)(x[2] & 0xff) << 40) | (cast(T)(x[3] & 0xff) << 32) | ((x[4] & 0xff) << 24) | ((x[5] & 0xff) << 16) | ((x[6] & 0xff) << 8) | (x[7] & 0xff)); } } static void from(T)(T input, ubyte[] output) { static if (T.sizeof == long.sizeof) { output[0] = cast(ubyte)(input >> 56); output[1] = cast(ubyte)(input >> 48); output[2] = cast(ubyte)(input >> 40); output[3] = cast(ubyte)(input >> 32); output[4] = cast(ubyte)(input >> 24); output[5] = cast(ubyte)(input >> 16); output[6] = cast(ubyte)(input >> 8); output[7] = cast(ubyte)(input); } else static if (T.sizeof == int.sizeof) { output[0] = cast(ubyte)(input >> 24); output[1] = cast(ubyte)(input >> 16); output[2] = cast(ubyte)(input >> 8); output[3] = cast(ubyte)(input); } else static if (T.sizeof == short.sizeof) { output[0] = cast(ubyte)(input >> 8); output[1] = cast(ubyte)(input); } } } static char[] hexEncode(const(void[]) input_) { const(ubyte[]) input = cast(const(ubyte[]))input_; char[] output = new char[input.length<<1]; int i = 0; foreach (ubyte j; input) { output[i++] = hexits[j>>4]; output[i++] = hexits[j&0xf]; } return output; } static char[] base32Encode(const(void[]) input_, bool doPad=true) { if (!input_) return "".dup; const(ubyte[]) input = cast(const(ubyte[]))input_; char[] output; auto inputbits = input.length*8; auto inputquantas = inputbits / 40; if (inputbits % 40) output = new char[(inputquantas+1) * 8]; else output = new char[inputquantas * 8]; int i = 0; ushort remainder; ubyte remainlen; foreach (ubyte j; input) { remainder = cast(ushort)(remainder<<8) | j; remainlen += 8; while (remainlen > 5) { output[i++] = base32digits[(remainder>>(remainlen-5))&0b11111]; remainlen -= 5; } } if (remainlen) output[i++] = base32digits[(remainder<<(5-remainlen))&0b11111]; while (doPad && (i < output.length)) { output[i++] = '='; } return output[0..i]; } static ubyte[] hexDecode(const(char[]) input) { char[] inputAsLower = stringToLower(input); ubyte[] output = new ubyte[input.length>>1]; static __gshared ubyte[char] hexitIndex; for (int i = 0; i < hexits.length; i++) hexitIndex[hexits[i]] = cast(ubyte) i; for (int i = 0, j = 0; i < output.length; i++) { output[i] = cast(ubyte) (hexitIndex[inputAsLower[j++]] << 4); output[i] |= hexitIndex[inputAsLower[j++]]; } return output; } static ubyte[] base32Decode(const(char[]) input) { static __gshared ubyte[char] b32Index; for (int i = 0; i < base32digits.length; i++) b32Index[base32digits[i]] = cast(ubyte) i; auto outlen = (input.length*5)/8; ubyte[] output = new ubyte[outlen]; ushort remainder; ubyte remainlen; size_t oIndex; foreach (c; stringToUpper(input)) { if (c == '=') continue; remainder = cast(ushort)(remainder<<5) | b32Index[c]; remainlen += 5; while (remainlen >= 8) { output[oIndex++] = cast(ubyte) (remainder >> (remainlen-8)); remainlen -= 8; } } return output[0..oIndex]; } private static char[] stringToLower(const(char[]) input) { char[] output = new char[input.length]; foreach (int i, char c; input) output[i] = cast(char) ((c >= 'A' && c <= 'Z') ? c+32 : c); return cast(char[])output; } private static char[] stringToUpper(const(char[]) input) { char[] output = new char[input.length]; foreach (int i, char c; input) output[i] = cast(char) ((c >= 'a' && c <= 'z') ? c-32 : c); return cast(char[])output; } } |