Mercurial > projects > dcrypt
changeset 0:0e08791a1418
Initial import.
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CONTRIBUTORS Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,1 @@ +Thomas Dixon <reikon@reikon.us>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,23 @@ +Copyright (c) 2008 dcrypt contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/BlockCipher.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,38 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.BlockCipher; + +public import dcrypt.crypto.Cipher; +public import dcrypt.crypto.params.SymmetricKey; + +/** Interface for a standard block cipher. */ +abstract class BlockCipher : Cipher { + + /** Returns: The block size in bytes that this cipher will operate on. */ + uint blockSize(); + + /** + * Process a block of data from the input array + * and place it into the output array. + * + * Params: + * input_ = Array containing input data. + * inOff = Offset at where the data in input_ starts. + * output_ = Array which will hold the output data. + * outOff = Offset at which to begin placing data in output_. + * + * Returns: The number of bytes processed (typically blockSize). + * + * Throws: dcrypt.crypto.errors.NotInitializedError if cipher + * was not initialized. + */ + uint processBlock(void[] input_, + uint inOff, void[] output_, uint outOff); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/BlockCipherPadding.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,41 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + + module dcrypt.crypto.BlockCipherPadding; + + public import dcrypt.crypto.errors.InvalidPaddingError; + + /** Base padding class for implementing block padding schemes. */ + abstract class BlockCipherPadding { + /** Returns: The name of the padding scheme implemented. */ + char[] name(); + + /** + * Pad the (last) block of plaintext to block length. + * + * Params: + * input_ = Plaintext block to be padded. + * inOffset = Offset at which to begin padding input_. + * + * Returns: The number of padding bytes added. + */ + uint padBlock(void[] input_, uint inOff); + + /** + * 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. + */ + uint padLength(void[] input_); + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/Cipher.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,38 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.Cipher; + +public import dcrypt.crypto.errors.InvalidKeyError; +public import dcrypt.crypto.errors.ShortBufferError; +public import dcrypt.crypto.errors.NotInitializedError; +public import dcrypt.crypto.errors.InvalidParameterError; + +public import dcrypt.crypto.params.CipherParameters; + +/** Base cipher class */ +interface Cipher { + static const bool ENCRYPT = true, + DECRYPT = false; + + /** + * Initialize a cipher. + * + * Params: + * encrypt = True if we are encrypting. + * params = Parameters to be passed to the cipher. (Key, rounds, etc.) + */ + abstract void init(bool encrypt, CipherParameters params); + + /** Returns: The name of the algorithm of this cipher. */ + abstract char[] name(); + + /** Reset cipher to its state immediately subsequent the last init. */ + abstract void reset(); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/Crypto.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,43 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.Crypto; + +import dcrypt.crypto.Cipher; + +import dcrypt.misc.Util; + +// Hash functions +public import dcrypt.crypto.Hash; +import dcrypt.crypto.hashes.MD5; +import dcrypt.crypto.hashes.SHA1; +import dcrypt.crypto.hashes.SHA224; +import dcrypt.crypto.hashes.SHA256; +import dcrypt.crypto.hashes.SHA384; +import dcrypt.crypto.hashes.SHA512; + +struct Crypto { + static Hash hashByName(char[] name) { + switch (Util.stringToAlphanumeric(Util.stringToUpper(name))) { + case "MD5": + return new MD5(); + case "SHA1": + return new SHA1(); + case "SHA224": + return new SHA224(); + case "SHA256": + return new SHA256(); + case "SHA384": + return new SHA384(); + case "SHA512": + return new SHA512(); + default: + throw new InvalidParameterError("Unknown hash function: "~name); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/Hash.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,110 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.Hash; + +public import dcrypt.misc.Util; + +/** Base class for all cryptographic hash functions */ +class Hash { + private const enum { + MODE_MD=0, // MDx, RipeMD, etc + MODE_SHA, + MODE_TIGER + } + private ubyte[] buffer; + uint bytes, + index; + + this (void[] input_=null) { + buffer = new ubyte[blockSize]; + ubyte[] input = cast(ubyte[]) input_; + if (input) + update(input); + } + + /** Returns: The block size of the hash function in bytes. */ + abstract uint blockSize(); + + /** Returns: The output size of the hash function in bytes. */ + abstract uint digestSize(); + + /** Returns: The name of the algorithm we're implementing. */ + abstract char[] name(); + + /** + * Introduce data into the hash function. + * + * Params: + * input_ = Data to be processed. + */ + void update(void[] input_) { + ubyte[] input = cast(ubyte[]) input_; + foreach (ubyte i; input) + update(i); + } + + void update(ubyte input) { + bytes++; + buffer[index++] = input; + if (index == blockSize) { + transform(buffer); + index = 0; + } + } + + /** Hash function's internal transformation. */ + protected abstract void transform(ubyte[] input); + + /** + * Pad message in the respective manner. + * + * Params: + * mode = Mode constant dictating in which manner + * to pad the message. + */ + protected void padMessage(uint mode) { + ulong length = bytes << 3; + + update(((mode == MODE_TIGER) ? 0x01 : 0x80)); + uint count = (blockSize-(blockSize >> 3)); + if (index > count) + while (index != 0) + update(0); + while (index < (count + ((blockSize == 128) ? 8 : 0))) + update(0); + if (mode == MODE_SHA) + for (int i = 56; i >= 0; i-=8) // big endian + update(length >> i); + else + for (int i = 0; i < 64; i+=8) // little endian + update(length >> i); + } + + /** + * Process all data, pad and finalize. This method will + * reset the digest to its original state ofr subsequent use. + * + * Returns: Binary representation of the hash in bytes. + */ + abstract ubyte[] digest(); + + /** + * Same as digest() but returns hash value in hex. + * + * Returns: Representation of the final hash value in hex. + */ + char[] hexDigest() { + return Util.ubytesToHex(digest()); + } + + /** Reset hash to initial state. */ + void reset() { + bytes = index = 0; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/StreamCipher.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,43 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.StreamCipher; + +public import dcrypt.crypto.Cipher; +public import dcrypt.crypto.params.CipherParameters; +public import dcrypt.crypto.params.SymmetricKey; + +/** Interface for a standard stream cipher. */ +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); + + /** + * Process data from the input array + * and place it into the output array. + * + * Params: + * input_ = Array containing input data. + * inOff = Offset at where the data in input_ starts. + * len = Length of input_ to process. + * output_ = Array which will hold the output data. + * outOff = Offset at which to begin placing data in output_. + * + * Throws: dcrypt.crypto.errors.NotInitializedError if cipher + * was not initialized. + */ + abstract void processBytes(void[] input_, uint inOff, + uint len, void[] output_, uint outOff); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/SymmetricCipher.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,32 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.SymmetricCipher; + +import dcrypt.crypto.Cipher; +import dcrypt.crypto.params.CipherParameters; + +/** Unified cipher class for high-level API. */ +interface SymmetricCipher : Cipher { + /** + * Pass bytes through the cipher object. + * + * Params: + * input_ = Array containing input data. + * inOff = Offset at where the data in input_ starts. + * len = Length of input_ to process. + * output_ = Array which will hold the output data. + * outOff = Offset at which to begin placing data in output_. + * + * Returns: The amount of bytes processed. + */ + uint update(void[] input_, uint inOff, uint len, void[] output_, uint outOff); + + /** Finalize and output the rest of the buffer. */ + uint finish(void[] output_, uint outOff); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/ciphers/RC4.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,203 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.ciphers.RC4; + +import dcrypt.crypto.StreamCipher; + +version (UnitTest) { + import dcrypt.misc.Util; +} + +/** Implementation of RC4 designed by Ron Rivest of RSA Security. */ +class RC4 : StreamCipher { + private ubyte[] state, + workingKey; + private ubyte x, y; + private bool initialized; + + void init(bool encrypt, CipherParameters params) { + SymmetricKey keyParams = cast(SymmetricKey)params; + if (!keyParams) + throw new InvalidParameterError( + name()~": Invalid parameter passed to init"); + if (keyParams.key.length < 0 || keyParams.key.length > 256) + throw new InvalidKeyError( + name()~": Invalid key length (requires 1-256 bytes)"); + workingKey = keyParams.key; + state = new ubyte[256]; + setup(workingKey); + initialized = true; + } + + char[] name() { + return "RC4"; + } + + ubyte returnByte(ubyte input) { + y += state[++x]; + ubyte t = state[x]; + state[x] = state[y]; + state[y] = t; + return (input^state[cast(ubyte)(state[x]+state[y])]); + } + + void processBytes(void[] input_, uint inOff, uint len, void[] output_, uint outOff) { + if (!initialized) + throw new NotInitializedError(name()~": Cipher not initialized"); + + ubyte[] input = cast(ubyte[]) input_; + ubyte[] output = cast(ubyte[]) output_; + + if ((inOff + len) > input.length) + throw new ShortBufferError(name()~": Input buffer too short"); + + if ((outOff + len) > output.length) + throw new ShortBufferError(name()~": Output buffer too short"); + + for (int i = 0; i < len; i++) { + y += state[++x]; + ubyte t = state[x]; + state[x] = state[y]; + state[y] = t; + output[outOff++] = input[inOff++] ^ state[cast(ubyte)(state[x]+state[y])]; + } + } + + void reset() { + setup(workingKey); + } + + // Do RC4's key setup in a separate method to ease resetting + private void setup(ubyte[] key) { + for (int i = 0; i < 256; i++) + state[i] = cast(ubyte)i; + + x = 0; + for (int i = 0; i < 256; i++) { + x += key[i % key.length] + state[i]; + ubyte t = state[i]; + state[i] = state[x]; + state[x] = t; + } + x = y = 0; + } + + /** Some RC4 test vectors. */ + version (UnitTest) { + unittest { + static const char[][] test_keys = [ + "0123456789abcdef", + "0123456789abcdef", + "0000000000000000", + "ef012345", + "0123456789abcdef" + ]; + + static const char[][] test_plaintexts = [ + "0123456789abcdef", + "0000000000000000", + "0000000000000000", + "00000000000000000000", + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101"~ + "01010101010101010101010101010101" + ]; + + static const char[][] test_ciphertexts = [ + "75b7878099e0c596", + "7494c2e7104b0879", + "de188941a3375d3a", + "d6a141a7ec3c38dfbd61", + "7595c3e6114a09780c4ad452338e1ffd"~ + "9a1be9498f813d76533449b6778dcad8"~ + "c78a8d2ba9ac66085d0e53d59c26c2d1"~ + "c490c1ebbe0ce66d1b6b1b13b6b919b8"~ + "47c25a91447a95e75e4ef16779cde8bf"~ + "0a95850e32af9689444fd377108f98fd"~ + "cbd4e726567500990bcc7e0ca3c4aaa3"~ + "04a387d20f3b8fbbcd42a1bd311d7a43"~ + "03dda5ab078896ae80c18b0af66dff31"~ + "9616eb784e495ad2ce90d7f772a81747"~ + "b65f62093b1e0db9e5ba532fafec4750"~ + "8323e671327df9444432cb7367cec82f"~ + "5d44c0d00b67d650a075cd4b70dedd77"~ + "eb9b10231b6b5b741347396d62897421"~ + "d43df9b42e446e358e9c11a9b2184ecb"~ + "ef0cd8e7a877ef968f1390ec9b3d35a5"~ + "585cb009290e2fcde7b5ec66d9084be4"~ + "4055a619d9dd7fc3166f9487f7cb2729"~ + "12426445998514c15d53a18c864ce3a2"~ + "b7555793988126520eacf2e3066e230c"~ + "91bee4dd5304f5fd0405b35bd99c7313"~ + "5d3d9bc335ee049ef69b3867bf2d7bd1"~ + "eaa595d8bfc0066ff8d31509eb0c6caa"~ + "006c807a623ef84c3d33c195d23ee320"~ + "c40de0558157c822d4b8c569d849aed5"~ + "9d4e0fd7f379586b4b7ff684ed6a189f"~ + "7486d49b9c4bad9ba24b96abf924372c"~ + "8a8fffb10d55354900a77a3db5f205e1"~ + "b99fcd8660863a159ad4abe40fa48934"~ + "163ddde542a6585540fd683cbfd8c00f"~ + "12129a284deacc4cdefe58be7137541c"~ + "047126c8d49e2755ab181ab7e940b0c0" + ]; + + RC4 r = new RC4(); + foreach (uint i, char[] test_key; test_keys) { + ubyte[] buffer = new ubyte[test_plaintexts[i].length>>1]; + char[] result; + + r.init(true, new SymmetricKey(Util.hexToUbytes(test_key))); + + // Encryption + r.processBytes(Util.hexToUbytes(test_plaintexts[i]), 0, buffer.length, buffer, 0); + result = Util.ubytesToHex(buffer); + assert(result == test_ciphertexts[i], + r.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + + r.reset(); + + // Decryption + r.processBytes(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer.length, buffer, 0); + result = Util.ubytesToHex(buffer); + assert(result == test_plaintexts[i], + r.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/ciphers/RC6.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,208 @@ +/** + * This file is part of the dcrypt project. + * + * It should be noted that this algorithm is very similar to RC5. + * Currently there are no plans to implement RC5, but should that change + * in the future, it may be wise to rewrite both RC5 and RC6 to use some + * kind of template or base class. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.ciphers.RC6; + +import dcrypt.misc.Util; +import dcrypt.crypto.BlockCipher; + +/** + * Implementation of the RC6-32/20/b cipher designed by + * Ron Rivest et al. of RSA Security. + * + * Note: This algorithm is patented and trademarked. + */ +class RC6 : BlockCipher { + private const uint ROUNDS = 20, + BLOCK_SIZE = 16, + // Magic constants for a 32 bit word size + P = 0xb7e15163, + Q = 0x9e3779b9; + private uint[] S; + private ubyte[] workingKey; + private bool initialized, + encrypt; + + char[] name() { + return "RC6"; + } + + uint blockSize() { + return BLOCK_SIZE; + } + + void init(bool encrypt, CipherParameters params) { + SymmetricKey keyParams = cast(SymmetricKey)params; + if (!keyParams) + throw new InvalidParameterError( + name()~": Invalid parameter passed to init"); + this.encrypt = encrypt; + + uint len = keyParams.key.length; + if (len != 16 && len != 24 && len != 32) + throw new InvalidKeyError( + name()~": Invalid key length (requires 16/24/32 bytes)"); + + S = new uint[2*ROUNDS+4]; + + workingKey = keyParams.key; + setup(workingKey); + + initialized = true; + } + + uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) { + if (!initialized) + throw new NotInitializedError(name()~": Cipher not initialized"); + + ubyte[] input = cast(ubyte[]) input_; + ubyte[] output = cast(ubyte[]) output_; + + if ((inOff + BLOCK_SIZE) > input.length) + throw new ShortBufferError(name()~": Input buffer too short"); + + if ((outOff + BLOCK_SIZE) > output.length) + throw new ShortBufferError(name()~": Output buffer too short"); + + uint A = Util.ubytesToUintLittle(input, inOff), + B = Util.ubytesToUintLittle(input, inOff+4), + C = Util.ubytesToUintLittle(input, inOff+8), + D = Util.ubytesToUintLittle(input, inOff+12), + t, + u; + + if (encrypt) { + B += S[0]; + D += S[1]; + for (int i = 1; i <= ROUNDS; i++) { + t = Util.rotateLeft(B*((B<<1)+1), 5); + u = Util.rotateLeft(D*((D<<1)+1), 5); + A = Util.rotateLeft(A^t, u) + S[i<<1]; + C = Util.rotateLeft(C^u, t) + S[(i<<1)+1]; + t = A; + A = B; + B = C; + C = D; + D = t; + } + A += S[2*ROUNDS+2]; + C += S[2*ROUNDS+3]; + } else { + C -= S[2*ROUNDS+3]; + A -= S[2*ROUNDS+2]; + for (int i = ROUNDS; i >= 1; i--) { + t = D; + D = C; + C = B; + B = A; + A = t; + u = Util.rotateLeft(D*((D<<1)+1), 5); + t = Util.rotateLeft(B*((B<<1)+1), 5); + C = Util.rotateRight(C-S[(i<<1)+1], t) ^ u; + A = Util.rotateRight(A-S[i<<1], u) ^ t; + } + D -= S[1]; + B -= S[0]; + } + + Util.uintToUbytesLittle(A, output, outOff); + Util.uintToUbytesLittle(B, output, outOff+4); + Util.uintToUbytesLittle(C, output, outOff+8); + Util.uintToUbytesLittle(D, output, outOff+12); + + return BLOCK_SIZE; + } + + void reset() { + setup(workingKey); + } + + void setup(ubyte[] key) { + uint c = key.length/4; + uint[] L = new uint[c]; + for (int i = 0, j = 0; i < c; i++, j+=4) + L[i] = Util.ubytesToUintLittle(key, j); + S[0] = P; + for (int i = 1; i <= 2*ROUNDS+3; i++) + S[i] = S[i-1] + Q; + uint A, B, i, j, v = 3*(2*ROUNDS+4); // Relying on ints initializing to 0 + for (int s = 1; s <= v; s++) { + A = S[i] = Util.rotateLeft(S[i]+A+B, 3); + B = L[j] = Util.rotateLeft(L[j]+A+B, A+B); + i = (i + 1) % (2*ROUNDS+4); + j = (j + 1) % c; + } + } + + /** Some RC6 test vectors from the spec. */ + version (UnitTest) { + unittest { + static const char[][] test_keys = [ + "00000000000000000000000000000000", + + "0123456789abcdef0112233445566778", + + "00000000000000000000000000000000"~ + "0000000000000000", + + "0123456789abcdef0112233445566778"~ + "899aabbccddeeff0", + + "00000000000000000000000000000000"~ + "00000000000000000000000000000000", + + "0123456789abcdef0112233445566778"~ + "899aabbccddeeff01032547698badcfe" + ]; + + static const char[][] test_plaintexts = [ + "00000000000000000000000000000000", + "02132435465768798a9bacbdcedfe0f1", + "00000000000000000000000000000000", + "02132435465768798a9bacbdcedfe0f1", + "00000000000000000000000000000000", + "02132435465768798a9bacbdcedfe0f1" + ]; + + static const char[][] test_ciphertexts = [ + "8fc3a53656b1f778c129df4e9848a41e", + "524e192f4715c6231f51f6367ea43f18", + "6cd61bcb190b30384e8a3f168690ae82", + "688329d019e505041e52e92af95291d4", + "8f5fbd0510d15fa893fa3fda6e857ec2", + "c8241816f0d7e48920ad16a1674e5d48" + ]; + + RC6 t = new RC6(); + foreach (uint i, char[] test_key; test_keys) { + ubyte[] buffer = new ubyte[t.blockSize]; + char[] result; + SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key)); + + // Encryption + t.init(true, key); + t.processBlock(Util.hexToUbytes(test_plaintexts[i]), 0, buffer, 0); + result = Util.ubytesToHex(buffer); + assert(result == test_ciphertexts[i], + t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + + // Decryption + t.init(false, key); + t.processBlock(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer, 0); + result = Util.ubytesToHex(buffer); + assert(result == test_plaintexts[i], + t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/ciphers/TEA.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,135 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.ciphers.TEA; + +import dcrypt.misc.Util; +import dcrypt.crypto.BlockCipher; + +/** Implementation of the TEA cipher designed by + David Wheeler and Roger Needham. */ +class TEA : BlockCipher { + private const uint ROUNDS = 32, + KEY_SIZE = 16, + BLOCK_SIZE = 8, + DELTA = 0x9e3779b9, + DECRYPT_SUM = 0xc6ef3720; + private uint sk0, sk1, sk2, sk3, sum; + private bool initialized, + encrypt; + + void reset(){} + + char[] name() { + return "TEA"; + } + + uint blockSize() { + return BLOCK_SIZE; + } + + void init(bool encrypt, CipherParameters params) { + SymmetricKey keyParams = cast(SymmetricKey)params; + if (!keyParams) + throw new InvalidParameterError( + name()~": Invalid parameter passed to init"); + this.encrypt = encrypt; + + if (keyParams.key.length != KEY_SIZE) + throw new InvalidKeyError( + name()~": Invalid key length (requires 16 bytes)"); + + sk0 = Util.ubytesToUintBig(keyParams.key, 0); + sk1 = Util.ubytesToUintBig(keyParams.key, 4); + sk2 = Util.ubytesToUintBig(keyParams.key, 8); + sk3 = Util.ubytesToUintBig(keyParams.key, 12); + + initialized = true; + } + + uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) { + if (!initialized) + throw new NotInitializedError(name()~": Cipher not initialized"); + + ubyte[] input = cast(ubyte[]) input_; + ubyte[] output = cast(ubyte[]) output_; + + if ((inOff + BLOCK_SIZE) > input.length) + throw new ShortBufferError(name()~": Input buffer too short"); + + if ((outOff + BLOCK_SIZE) > output.length) + throw new ShortBufferError(name()~": Output buffer too short"); + + uint v0 = Util.ubytesToUintBig(input, inOff), + v1 = Util.ubytesToUintBig(input, inOff+4); + + sum = encrypt ? 0 : DECRYPT_SUM; + for (int i = 0; i < ROUNDS; i++) { + if (encrypt) { + sum += DELTA; + v0 += ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1); + v1 += ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3); + } else { + v1 -= ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3); + v0 -= ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1); + sum -= DELTA; + } + } + + Util.uintToUbytesBig(v0, output, outOff); + Util.uintToUbytesBig(v1, output, outOff+4); + + return BLOCK_SIZE; + } + + /** Some TEA test vectors. */ + unittest { + static const char[][] test_keys = [ + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "0123456712345678234567893456789a", + "0123456712345678234567893456789a" + ]; + + static const char[][] test_plaintexts = [ + "0000000000000000", + "0102030405060708", + "0000000000000000", + "0102030405060708" + ]; + + static const char[][] test_ciphertexts = [ + "41ea3a0a94baa940", + "6a2f9cf3fccf3c55", + "34e943b0900f5dcb", + "773dc179878a81c0" + ]; + + + TEA t = new TEA(); + foreach (uint i, char[] test_key; test_keys) { + ubyte[] buffer = new ubyte[t.blockSize]; + char[] result; + SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key)); + + // Encryption + t.init(true, key); + t.processBlock(Util.hexToUbytes(test_plaintexts[i]), 0, buffer, 0); + result = Util.ubytesToHex(buffer); + assert(result == test_ciphertexts[i], + t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + + // Decryption + t.init(false, key); + t.processBlock(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer, 0); + result = Util.ubytesToHex(buffer); + assert(result == test_plaintexts[i], + t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/ciphers/XTEA.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,163 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.ciphers.XTEA; + +import dcrypt.misc.Util; +import dcrypt.crypto.BlockCipher; + +/** Implementation of the XTEA cipher designed by + David Wheeler and Roger Needham. */ +class XTEA : BlockCipher { + private const uint ROUNDS = 32, + KEY_SIZE = 16, + BLOCK_SIZE = 8, + DELTA = 0x9e3779b9; + private uint[] subkeys, + sum0, + sum1; + private bool initialized, + encrypt; + + void reset(){} + + char[] name() { + return "XTEA"; + } + + uint blockSize() { + return BLOCK_SIZE; + } + + void init(bool encrypt, CipherParameters params) { + SymmetricKey keyParams = cast(SymmetricKey)params; + if (!keyParams) + throw new InvalidParameterError( + name()~": Invalid parameter passed to init"); + this.encrypt = encrypt; + + if (keyParams.key.length != KEY_SIZE) + throw new InvalidKeyError( + name()~": Invalid key length (requires 16 bytes)"); + + subkeys = new uint[4]; + sum0 = new uint[32]; + sum1 = new uint[32]; + + int i, j; + for (i = j = 0; i < 4; i++, j+=4) + subkeys[i] = Util.ubytesToUintBig(keyParams.key, j); + + // Precompute the values of sum + k[] to speed up encryption + for (i = j = 0; i < ROUNDS; i++) { + sum0[i] = (j + subkeys[j & 3]); + j += DELTA; + sum1[i] = (j + subkeys[j >> 11 & 3]); + } + initialized = true; + } + + uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) { + if (!initialized) + throw new NotInitializedError(name()~": Cipher not initialized"); + + ubyte[] input = cast(ubyte[]) input_; + ubyte[] output = cast(ubyte[]) output_; + + if ((inOff + BLOCK_SIZE) > input.length) + throw new ShortBufferError(name()~": Input buffer too short"); + + if ((outOff + BLOCK_SIZE) > output.length) + throw new ShortBufferError(name()~": Output buffer too short"); + + uint v0 = Util.ubytesToUintBig(input, inOff), + v1 = Util.ubytesToUintBig(input, inOff+4); + + if (encrypt) { + for (int i = 0; i < ROUNDS; i++) { + v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ sum0[i]; + v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ sum1[i]; + } + } else { + for (int i = ROUNDS-1; i >= 0; i--) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ sum1[i]; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ sum0[i]; + } + } + + Util.uintToUbytesBig(v0, output, outOff); + Util.uintToUbytesBig(v1, output, outOff+4); + + return BLOCK_SIZE; + } + + /** Some XTEA test vectors. */ + version (UnitTest) { + unittest { + static const char[][] test_keys = [ + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "0123456712345678234567893456789a", + "0123456712345678234567893456789a", + "00000000000000000000000000000001", + "01010101010101010101010101010101", + "0123456789abcdef0123456789abcdef", + "0123456789abcdef0123456789abcdef", + "00000000000000000000000000000000", + "00000000000000000000000000000000" + ]; + + static const char[][] test_plaintexts = [ + "0000000000000000", + "0102030405060708", + "0000000000000000", + "0102030405060708", + "0000000000000001", + "0101010101010101", + "0123456789abcdef", + "0000000000000000", + "0123456789abcdef", + "4141414141414141" + ]; + + static const char[][] test_ciphertexts = [ + "dee9d4d8f7131ed9", + "065c1b8975c6a816", + "1ff9a0261ac64264", + "8c67155b2ef91ead", + "9f25fa5b0f86b758", + "c2eca7cec9b7f992", + "27e795e076b2b537", + "5c8eddc60a95b3e1", + "7e66c71c88897221", + "ed23375a821a8c2d" + ]; + + XTEA t = new XTEA(); + foreach (uint i, char[] test_key; test_keys) { + ubyte[] buffer = new ubyte[t.blockSize]; + char[] result; + SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key)); + + // Encryption + t.init(true, key); + t.processBlock(Util.hexToUbytes(test_plaintexts[i]), 0, buffer, 0); + result = Util.ubytesToHex(buffer); + assert(result == test_ciphertexts[i], + t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + + // Decryption + t.init(false, key); + t.processBlock(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer, 0); + result = Util.ubytesToHex(buffer); + assert(result == test_plaintexts[i], + t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/errors/InvalidKeyError.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,15 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.errors.InvalidKeyError; + +import dcrypt.crypto.errors.InvalidParameterError; + +class InvalidKeyError : InvalidParameterError { + this(char[] msg) { super(msg); } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/errors/InvalidPaddingError.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,13 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.errors.InvalidPaddingError; + +class InvalidPaddingError : Exception { + this(char[] msg) { super(msg); } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/errors/InvalidParameterError.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,13 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.errors.InvalidParameterError; + +class InvalidParameterError : Exception { + this(char[] msg) { super(msg); } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/errors/NotInitializedError.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,13 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.errors.NotInitializedError; + +class NotInitializedError : Exception { + this(char[] msg) { super(msg); } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/errors/ShortBufferError.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,13 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.errors.ShortBufferError; + +class ShortBufferError : Exception { + this(char[] msg) { super(msg); } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/hashes/MD5.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,245 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.hashes.MD5; + +public import dcrypt.crypto.Hash; + +/** Implementation of Ron Rivest's MD5. */ +class MD5 : Hash { + private uint h0, h1, h2, h3; + + // Shift amounts + private enum { + S11 = 7, + S12 = 12, + S13 = 17, + S14 = 22, + + S21 = 5, + S22 = 9, + S23 = 14, + S24 = 20, + + S31 = 4, + S32 = 11, + S33 = 16, + S34 = 23, + + S41 = 6, + S42 = 10, + S43 = 15, + S44 = 21 + }; + + this (void[] input_=null) { + reset(); + super(input_); + } + + uint blockSize() { + return 64; + } + + uint digestSize() { + return 16; + } + + char[] name() { + return "MD5"; + } + + void transform(ubyte[] input) { + uint[] w = new uint[16]; + + for (int i = 0, j = 0; i < 16; i++,j+=4) + w[i] = Util.ubytesToUintLittle(input, j); + + uint a = h0, + b = h1, + c = h2, + d = h3; + + // Round 1 -- FIGHT! + ff(a, b, c, d, w[ 0], S11, 3614090360); /* 1 */ + ff(d, a, b, c, w[ 1], S12, 3905402710); /* 2 */ + ff(c, d, a, b, w[ 2], S13, 606105819); /* 3 */ + ff(b, c, d, a, w[ 3], S14, 3250441966); /* 4 */ + ff(a, b, c, d, w[ 4], S11, 4118548399); /* 5 */ + ff(d, a, b, c, w[ 5], S12, 1200080426); /* 6 */ + ff(c, d, a, b, w[ 6], S13, 2821735955); /* 7 */ + ff(b, c, d, a, w[ 7], S14, 4249261313); /* 8 */ + ff(a, b, c, d, w[ 8], S11, 1770035416); /* 9 */ + ff(d, a, b, c, w[ 9], S12, 2336552879); /* 10 */ + ff(c, d, a, b, w[10], S13, 4294925233); /* 11 */ + ff(b, c, d, a, w[11], S14, 2304563134); /* 12 */ + ff(a, b, c, d, w[12], S11, 1804603682); /* 13 */ + ff(d, a, b, c, w[13], S12, 4254626195); /* 14 */ + ff(c, d, a, b, w[14], S13, 2792965006); /* 15 */ + ff(b, c, d, a, w[15], S14, 1236535329); /* 16 */ + + // Round 2 + gg(a, b, c, d, w[ 1], S21, 4129170786); /* 17 */ + gg(d, a, b, c, w[ 6], S22, 3225465664); /* 18 */ + gg(c, d, a, b, w[11], S23, 643717713); /* 19 */ + gg(b, c, d, a, w[ 0], S24, 3921069994); /* 20 */ + gg(a, b, c, d, w[ 5], S21, 3593408605); /* 21 */ + gg(d, a, b, c, w[10], S22, 38016083); /* 22 */ + gg(c, d, a, b, w[15], S23, 3634488961); /* 23 */ + gg(b, c, d, a, w[ 4], S24, 3889429448); /* 24 */ + gg(a, b, c, d, w[ 9], S21, 568446438); /* 25 */ + gg(d, a, b, c, w[14], S22, 3275163606); /* 26 */ + gg(c, d, a, b, w[ 3], S23, 4107603335); /* 27 */ + gg(b, c, d, a, w[ 8], S24, 1163531501); /* 28 */ + gg(a, b, c, d, w[13], S21, 2850285829); /* 29 */ + gg(d, a, b, c, w[ 2], S22, 4243563512); /* 30 */ + gg(c, d, a, b, w[ 7], S23, 1735328473); /* 31 */ + gg(b, c, d, a, w[12], S24, 2368359562); /* 32 */ + + // Round 3 + hh(a, b, c, d, w[ 5], S31, 4294588738); /* 33 */ + hh(d, a, b, c, w[ 8], S32, 2272392833); /* 34 */ + hh(c, d, a, b, w[11], S33, 1839030562); /* 35 */ + hh(b, c, d, a, w[14], S34, 4259657740); /* 36 */ + hh(a, b, c, d, w[ 1], S31, 2763975236); /* 37 */ + hh(d, a, b, c, w[ 4], S32, 1272893353); /* 38 */ + hh(c, d, a, b, w[ 7], S33, 4139469664); /* 39 */ + hh(b, c, d, a, w[10], S34, 3200236656); /* 40 */ + hh(a, b, c, d, w[13], S31, 681279174); /* 41 */ + hh(d, a, b, c, w[ 0], S32, 3936430074); /* 42 */ + hh(c, d, a, b, w[ 3], S33, 3572445317); /* 43 */ + hh(b, c, d, a, w[ 6], S34, 76029189); /* 44 */ + hh(a, b, c, d, w[ 9], S31, 3654602809); /* 45 */ + hh(d, a, b, c, w[12], S32, 3873151461); /* 46 */ + hh(c, d, a, b, w[15], S33, 530742520); /* 47 */ + hh(b, c, d, a, w[ 2], S34, 3299628645); /* 48 */ + + // Round 4 + ii(a, b, c, d, w[ 0], S41, 4096336452); /* 49 */ + ii(d, a, b, c, w[ 7], S42, 1126891415); /* 50 */ + ii(c, d, a, b, w[14], S43, 2878612391); /* 51 */ + ii(b, c, d, a, w[ 5], S44, 4237533241); /* 52 */ + ii(a, b, c, d, w[12], S41, 1700485571); /* 53 */ + ii(d, a, b, c, w[ 3], S42, 2399980690); /* 54 */ + ii(c, d, a, b, w[10], S43, 4293915773); /* 55 */ + ii(b, c, d, a, w[ 1], S44, 2240044497); /* 56 */ + ii(a, b, c, d, w[ 8], S41, 1873313359); /* 57 */ + ii(d, a, b, c, w[15], S42, 4264355552); /* 58 */ + ii(c, d, a, b, w[ 6], S43, 2734768916); /* 59 */ + ii(b, c, d, a, w[13], S44, 1309151649); /* 60 */ + ii(a, b, c, d, w[ 4], S41, 4149444226); /* 61 */ + ii(d, a, b, c, w[11], S42, 3174756917); /* 62 */ + ii(c, d, a, b, w[ 2], S43, 718787259); /* 63 */ + ii(b, c, d, a, w[ 9], S44, 3951481745); /* 64 */ + + // FINISH HIM! + h0 += a; + h1 += b; + h2 += c; + h3 += d; + // FATALITY! MD5 Wins. \o/ ('cept not because it's insecure, but whatev) + } + + private uint f(uint x, uint y, uint z) { + return (x&y)|(~x&z); + } + + private uint h(uint x, uint y, uint z) { + return x^y^z; + } + + private uint g(uint x, uint y, uint z) { + return (x&z)|(y&~z); + } + + private uint i(uint x, uint y, uint z) { + return y^(x|~z); + } + + private void ff(ref uint a, uint b, uint c, + uint d, uint x, uint s, uint ac) { + a += f(b, c, d) + x + ac; + a = Util.rotateLeft(a, s); + a += b; + } + + private void gg(ref uint a, uint b, uint c, + uint d, uint x, uint s, uint ac) { + a += g(b, c, d) + x + ac; + a = Util.rotateLeft(a, s); + a += b; + } + + private void hh(ref uint a, uint b, uint c, + uint d, uint x, uint s, uint ac) { + a += h(b, c, d) + x + ac; + a = Util.rotateLeft(a, s); + a += b; + } + + private void ii(ref uint a, uint b, uint c, + uint d, uint x, uint s, uint ac) { + a += i(b, c, d) + x + ac; + a = Util.rotateLeft(a, s); + a += b; + } + + ubyte[] digest() { + padMessage(MODE_MD); + ubyte[] result = new ubyte[digestSize]; + + Util.uintToUbytesLittle(h0, result, 0); + Util.uintToUbytesLittle(h1, result, 4); + Util.uintToUbytesLittle(h2, result, 8); + Util.uintToUbytesLittle(h3, result, 12); + + reset(); + return result; + } + + void reset() { + super.reset(); + h0 = 0x67452301u, + h1 = 0xefcdab89u, + h2 = 0x98badcfeu, + h3 = 0x10325476u; + } + + version (UnitTest) { + // Found in Tango <3 + unittest { + static const char[][] test_inputs = [ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + ]; + + static const char[][] test_results = [ + "d41d8cd98f00b204e9800998ecf8427e", + "0cc175b9c0f1b6a831c399e269772661", + "900150983cd24fb0d6963f7d28e17f72", + "f96b697d7cb7938d525a2f31aaf161d0", + "c3fcd3d76192e4007dfb496cca67e13b", + "d174ab98d277d9f5a5611c2c9f419d9f", + "57edf4a22be3c955ac49da2e2107b67a" + ]; + + MD5 h = new MD5(); + foreach (uint i, char[] input; test_inputs) { + h.update(input); + char[] digest = h.hexDigest(); + assert(digest == test_results[i], + h.name()~": ("~digest~") != ("~test_results[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/hashes/SHA1.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,196 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.hashes.SHA1; + +public import dcrypt.crypto.Hash; + +/** Implementation of SHA-1. */ +class SHA1 : Hash { + private uint h0, h1, h2, h3, h4; + + this (void[] input_=null) { + reset(); + super(input_); + } + + uint blockSize() { + return 64; + } + + uint digestSize() { + return 20; + } + + char[] name() { + return "SHA1"; + } + + void transform(ubyte[] input) { + uint[] w = new uint[80]; + + for (int i = 0, j = 0; i < 16; i++,j+=4) + w[i] = Util.ubytesToUintBig(input, j); + + for (int i = 16; i < 80; i++) + w[i] = Util.rotateLeft(w[i-3]^w[i-8]^w[i-14]^w[i-16], 1); + + uint a = h0, + b = h1, + c = h2, + d = h3, + e = h4; + + int i = 0; + for (; i < 20;) { + e += Util.rotateLeft(a, 5) + f0(b, c, d) + w[i++]; + b = Util.rotateLeft(b, 30); + + d += Util.rotateLeft(e, 5) + f0(a, b, c) + w[i++]; + a = Util.rotateLeft(a, 30); + + c += Util.rotateLeft(d, 5) + f0(e, a, b) + w[i++]; + e = Util.rotateLeft(e, 30); + + b += Util.rotateLeft(c, 5) + f0(d, e, a) + w[i++]; + d = Util.rotateLeft(d, 30); + + a += Util.rotateLeft(b, 5) + f0(c, d, e) + w[i++]; + c = Util.rotateLeft(c, 30); + } + + for (; i < 40;) { + e += Util.rotateLeft(a, 5) + f1(b, c, d) + w[i++]; + b = Util.rotateLeft(b, 30); + + d += Util.rotateLeft(e, 5) + f1(a, b, c) + w[i++]; + a = Util.rotateLeft(a, 30); + + c += Util.rotateLeft(d, 5) + f1(e, a, b) + w[i++]; + e = Util.rotateLeft(e, 30); + + b += Util.rotateLeft(c, 5) + f1(d, e, a) + w[i++]; + d = Util.rotateLeft(d, 30); + + a += Util.rotateLeft(b, 5) + f1(c, d, e) + w[i++]; + c = Util.rotateLeft(c, 30); + } + + for (; i < 60;) { + e += Util.rotateLeft(a, 5) + f2(b, c, d) + w[i++]; + b = Util.rotateLeft(b, 30); + + d += Util.rotateLeft(e, 5) + f2(a, b, c) + w[i++]; + a = Util.rotateLeft(a, 30); + + c += Util.rotateLeft(d, 5) + f2(e, a, b) + w[i++]; + e = Util.rotateLeft(e, 30); + + b += Util.rotateLeft(c, 5) + f2(d, e, a) + w[i++]; + d = Util.rotateLeft(d, 30); + + a += Util.rotateLeft(b, 5) + f2(c, d, e) + w[i++]; + c = Util.rotateLeft(c, 30); + } + + for (; i < 80;) { + e += Util.rotateLeft(a, 5) + f3(b, c, d) + w[i++]; + b = Util.rotateLeft(b, 30); + + d += Util.rotateLeft(e, 5) + f3(a, b, c) + w[i++]; + a = Util.rotateLeft(a, 30); + + c += Util.rotateLeft(d, 5) + f3(e, a, b) + w[i++]; + e = Util.rotateLeft(e, 30); + + b += Util.rotateLeft(c, 5) + f3(d, e, a) + w[i++]; + d = Util.rotateLeft(d, 30); + + a += Util.rotateLeft(b, 5) + f3(c, d, e) + w[i++]; + c = Util.rotateLeft(c, 30); + } + + h0 += a; + h1 += b; + h2 += c; + h3 += d; + h4 += e; + } + + private uint f0(uint x, uint y, uint z) { + return (z^(x&(y^z))) + 0x5a827999; + } + + private uint f1(uint x, uint y, uint z) { + return (x^y^z) + 0x6ed9eba1; + } + + private uint f2(uint x, uint y, uint z) { + return ((x&y)|(z&(x|y))) + 0x8f1bbcdc; + } + + private uint f3(uint x, uint y, uint z) { + return (x^y^z) + 0xca62c1d6; + } + + ubyte[] digest() { + padMessage(MODE_SHA); + ubyte[] result = new ubyte[digestSize]; + + Util.uintToUbytesBig(h0, result, 0); + Util.uintToUbytesBig(h1, result, 4); + Util.uintToUbytesBig(h2, result, 8); + Util.uintToUbytesBig(h3, result, 12); + Util.uintToUbytesBig(h4, result, 16); + + reset(); + return result; + } + + void reset() { + super.reset(); + h0 = 0x67452301u; + h1 = 0xefcdab89u; + h2 = 0x98badcfeu; + h3 = 0x10325476u; + h4 = 0xc3d2e1f0u; + } + + version (UnitTest) { + unittest { + static const char[][] test_inputs = [ + "", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "a", + "0123456701234567012345670123456701234567012345670123456701234567" + ]; + + static const int[] test_repeat = [ + 1, 1, 1, 1000000, 10 + ]; + + static const char[][] test_results = [ + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "a9993e364706816aba3e25717850c26c9cd0d89d", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1", + "34aa973cd4c4daa4f61eeb2bdbad27316534016f", + "dea356a2cddd90c7a7ecedc5ebb563934f460452" + ]; + + SHA1 h = new SHA1(); + foreach (uint i, char[] input; test_inputs) { + for (int j = 0; j < test_repeat[i]; j++) + h.update(input); + char[] digest = h.hexDigest(); + assert(digest == test_results[i], + h.name()~": ("~digest~") != ("~test_results[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/hashes/SHA224.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,87 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.hashes.SHA224; + +import dcrypt.crypto.hashes.SHA256; + +/** Implementation of SHA-224. */ +class SHA224 : SHA256 { + this (void[] input_=null) { + reset(); + super(input_); + } + + uint digestSize() { + return 28; + } + + char[] name() { + return "SHA224"; + } + + ubyte[] digest() { + padMessage(MODE_SHA); + + ubyte[] result = new ubyte[digestSize]; + + Util.uintToUbytesBig(h0, result, 0); + Util.uintToUbytesBig(h1, result, 4); + Util.uintToUbytesBig(h2, result, 8); + Util.uintToUbytesBig(h3, result, 12); + Util.uintToUbytesBig(h4, result, 16); + Util.uintToUbytesBig(h5, result, 20); + Util.uintToUbytesBig(h6, result, 24); + + reset(); + return result; + } + + void reset() { + super.reset(); + h0 = 0xc1059ed8u; + h1 = 0x367cd507u; + h2 = 0x3070dd17u; + h3 = 0xf70e5939u; + h4 = 0xffc00b31u; + h5 = 0x68581511u; + h6 = 0x64f98fa7u; + h7 = 0xbefa4fa4u; + } + + version (UnitTest) { + unittest { + static const char[][] test_inputs = [ + "", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "a" + ]; + + static const int[] test_repeat = [ + 1, 1, 1, 1000000 + ]; + + static const char[][] test_results = [ + "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", + "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", + "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67" + ]; + + SHA224 h = new SHA224(); + foreach (uint i, char[] input; test_inputs) { + for (int j = 0; j < test_repeat[i]; j++) + h.update(input); + char[] digest = h.hexDigest(); + assert(digest == test_results[i], + h.name()~": ("~digest~") != ("~test_results[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/hashes/SHA256.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,176 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.hashes.SHA256; + +public import dcrypt.crypto.Hash; + +/** Implementation of SHA-256. */ +class SHA256 : Hash { + private const uint[] K = [ + 0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u, + 0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u, + 0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u, + 0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u, + 0xe49b69c1u, 0xefbe4786u, 0x0fc19dc6u, 0x240ca1ccu, + 0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau, + 0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u, + 0xc6e00bf3u, 0xd5a79147u, 0x06ca6351u, 0x14292967u, + 0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u, + 0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u, + 0xa2bfe8a1u, 0xa81a664bu, 0xc24b8b70u, 0xc76c51a3u, + 0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u, + 0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u, + 0x391c0cb3u, 0x4ed8aa4au, 0x5b9cca4fu, 0x682e6ff3u, + 0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u, + 0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u + ]; + protected uint h0, h1, h2, h3, h4, h5, h6, h7; + + this (void[] input_=null) { + reset(); + super(input_); + } + + uint blockSize() { + return 64; + } + + uint digestSize() { + return 32; + } + + char[] name() { + return "SHA256"; + } + + void transform(ubyte[] input) { + uint[] w = new uint[64]; + + for (int i = 0, j = 0; i < 16; i++,j+=4) + w[i] = Util.ubytesToUintBig(input, j); + + for (int i = 16; i < 64; i++) + w[i] = theta1(w[i-2]) + w[i-7] + theta0(w[i-15]) + w[i-16]; + + uint a = h0, + b = h1, + c = h2, + d = h3, + e = h4, + f = h5, + g = h6, + h = h7; + + for (int i = 0; i < 64; i++) { + uint t1 = h + sum1(e) + ch(e,f,g) + K[i] + w[i], + t2 = sum0(a) + maj(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + h0 += a; + h1 += b; + h2 += c; + h3 += d; + h4 += e; + h5 += f; + h6 += g; + h7 += h; + } + + private uint ch(uint x, uint y, uint z) { + return (x&y)^(~x&z); + } + + private uint maj(uint x, uint y, uint z) { + return (x&y)^(x&z)^(y&z); + } + + private uint sum0(uint x) { + return Util.rotateRight(x,2)^Util.rotateRight(x,13)^Util.rotateRight(x,22); + } + + private uint sum1(uint x) { + return Util.rotateRight(x,6)^Util.rotateRight(x,11)^Util.rotateRight(x,25); + } + + private uint theta0(uint x) { + return Util.rotateRight(x,7)^Util.rotateRight(x,18)^(x >> 3); + } + + private uint theta1(uint x) { + return Util.rotateRight(x,17)^Util.rotateRight(x,19)^(x >> 10); + } + + ubyte[] digest() { + padMessage(MODE_SHA); + ubyte[] result = new ubyte[digestSize]; + + Util.uintToUbytesBig(h0, result, 0); + Util.uintToUbytesBig(h1, result, 4); + Util.uintToUbytesBig(h2, result, 8); + Util.uintToUbytesBig(h3, result, 12); + Util.uintToUbytesBig(h4, result, 16); + Util.uintToUbytesBig(h5, result, 20); + Util.uintToUbytesBig(h6, result, 24); + Util.uintToUbytesBig(h7, result, 28); + + reset(); + return result; + } + + void reset() { + super.reset(); + h0 = 0x6a09e667u; + h1 = 0xbb67ae85u; + h2 = 0x3c6ef372u; + h3 = 0xa54ff53au; + h4 = 0x510e527fu; + h5 = 0x9b05688cu; + h6 = 0x1f83d9abu; + h7 = 0x5be0cd19u; + } + + version (UnitTest) { + unittest { + static const char[][] test_inputs = [ + "", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "a" + ]; + + static const int[] test_repeat = [ + 1, 1, 1, 1000000 + ]; + + static const char[][] test_results = [ + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" + ]; + + SHA256 h = new SHA256(); + foreach (uint i, char[] input; test_inputs) { + for (int j = 0; j < test_repeat[i]; j++) + h.update(input); + char[] digest = h.hexDigest(); + assert(digest == test_results[i], + h.name()~": ("~digest~") != ("~test_results[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/hashes/SHA384.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,93 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.hashes.SHA384; + +import dcrypt.crypto.hashes.SHA512; + +/** Implementation of SHA-384. */ +class SHA384 : SHA512 { + this (void[] input_=null) { + reset(); + super(input_); + } + + uint digestSize() { + return 48; + } + + char[] name() { + return "SHA384"; + } + + ubyte[] digest() { + padMessage(MODE_SHA); + ubyte[] result = new ubyte[digestSize]; + + Util.ulongToUbytesBig(h0, result, 0); + Util.ulongToUbytesBig(h1, result, 8); + Util.ulongToUbytesBig(h2, result, 16); + Util.ulongToUbytesBig(h3, result, 24); + Util.ulongToUbytesBig(h4, result, 32); + Util.ulongToUbytesBig(h5, result, 40); + + reset(); + return result; + } + + void reset() { + super.reset(); + h0 = 0xcbbb9d5dc1059ed8u, + h1 = 0x629a292a367cd507u, + h2 = 0x9159015a3070dd17u, + h3 = 0x152fecd8f70e5939u, + h4 = 0x67332667ffc00b31u, + h5 = 0x8eb44a8768581511u, + h6 = 0xdb0c2e0d64f98fa7u, + h7 = 0x47b5481dbefa4fa4u; + } + + version (UnitTest) { + unittest { + static const char[][] test_inputs = [ + "", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"~ + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "a" + ]; + + static const int[] test_repeat = [ + 1, 1, 1, 1000000 + ]; + + static const char[][] test_results = [ + "38b060a751ac96384cd9327eb1b1e36a21fdb71114be0743"~ + "4c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", + + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded163"~ + "1a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", + + "09330c33f71147e83d192fc782cd1b4753111b173b3b05d2"~ + "2fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", + + "9d0e1809716474cb086e834e310a4a1ced149e9c00f24852"~ + "7972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985" + ]; + + SHA384 h = new SHA384(); + foreach (uint i, char[] input; test_inputs) { + for (int j = 0; j < test_repeat[i]; j++) + h.update(input); + char[] digest = h.hexDigest(); + assert(digest == test_results[i], + h.name()~": ("~digest~") != ("~test_results[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/hashes/SHA512.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,192 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.hashes.SHA512; + +public import dcrypt.crypto.Hash; + +/** Implementation of SHA-512. */ +class SHA512 : Hash { + private const ulong[] K = [ + 0x428a2f98d728ae22u, 0x7137449123ef65cdu, 0xb5c0fbcfec4d3b2fu, 0xe9b5dba58189dbbcu, + 0x3956c25bf348b538u, 0x59f111f1b605d019u, 0x923f82a4af194f9bu, 0xab1c5ed5da6d8118u, + 0xd807aa98a3030242u, 0x12835b0145706fbeu, 0x243185be4ee4b28cu, 0x550c7dc3d5ffb4e2u, + 0x72be5d74f27b896fu, 0x80deb1fe3b1696b1u, 0x9bdc06a725c71235u, 0xc19bf174cf692694u, + 0xe49b69c19ef14ad2u, 0xefbe4786384f25e3u, 0x0fc19dc68b8cd5b5u, 0x240ca1cc77ac9c65u, + 0x2de92c6f592b0275u, 0x4a7484aa6ea6e483u, 0x5cb0a9dcbd41fbd4u, 0x76f988da831153b5u, + 0x983e5152ee66dfabu, 0xa831c66d2db43210u, 0xb00327c898fb213fu, 0xbf597fc7beef0ee4u, + 0xc6e00bf33da88fc2u, 0xd5a79147930aa725u, 0x06ca6351e003826fu, 0x142929670a0e6e70u, + 0x27b70a8546d22ffcu, 0x2e1b21385c26c926u, 0x4d2c6dfc5ac42aedu, 0x53380d139d95b3dfu, + 0x650a73548baf63deu, 0x766a0abb3c77b2a8u, 0x81c2c92e47edaee6u, 0x92722c851482353bu, + 0xa2bfe8a14cf10364u, 0xa81a664bbc423001u, 0xc24b8b70d0f89791u, 0xc76c51a30654be30u, + 0xd192e819d6ef5218u, 0xd69906245565a910u, 0xf40e35855771202au, 0x106aa07032bbd1b8u, + 0x19a4c116b8d2d0c8u, 0x1e376c085141ab53u, 0x2748774cdf8eeb99u, 0x34b0bcb5e19b48a8u, + 0x391c0cb3c5c95a63u, 0x4ed8aa4ae3418acbu, 0x5b9cca4f7763e373u, 0x682e6ff3d6b2b8a3u, + 0x748f82ee5defb2fcu, 0x78a5636f43172f60u, 0x84c87814a1f0ab72u, 0x8cc702081a6439ecu, + 0x90befffa23631e28u, 0xa4506cebde82bde9u, 0xbef9a3f7b2c67915u, 0xc67178f2e372532bu, + 0xca273eceea26619cu, 0xd186b8c721c0c207u, 0xeada7dd6cde0eb1eu, 0xf57d4f7fee6ed178u, + 0x06f067aa72176fbau, 0x0a637dc5a2c898a6u, 0x113f9804bef90daeu, 0x1b710b35131c471bu, + 0x28db77f523047d84u, 0x32caab7b40c72493u, 0x3c9ebe0a15c9bebcu, 0x431d67c49c100d4cu, + 0x4cc5d4becb3e42b6u, 0x597f299cfc657e2au, 0x5fcb6fab3ad6faecu, 0x6c44198c4a475817u + ]; + protected ulong h0, h1, h2, h3, h4, h5, h6, h7; + + this (void[] input_=null) { + reset(); + super(input_); + } + + uint blockSize() { + return 128; + } + + uint digestSize() { + return 64; + } + + char[] name() { + return "SHA512"; + } + + void transform(ubyte[] input) { + ulong[] w = new ulong[80]; + + for (int i = 0, j = 0; i < 16; i++,j+=8) + w[i] = Util.ubytesToUlongBig(input, j); + + for (int i = 16; i < 80; i++) + w[i] = theta1(w[i-2]) + w[i-7] + theta0(w[i-15]) + w[i-16]; + + ulong a = h0, + b = h1, + c = h2, + d = h3, + e = h4, + f = h5, + g = h6, + h = h7; + + for (int i = 0; i < 80; i++) { + ulong t1 = h + sum1(e) + ch(e,f,g) + K[i] + w[i], + t2 = sum0(a) + maj(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + h0 += a; + h1 += b; + h2 += c; + h3 += d; + h4 += e; + h5 += f; + h6 += g; + h7 += h; + } + + private ulong ch(ulong x, ulong y, ulong z) { + return (x&y)^(~x&z); + } + + private ulong maj(ulong x, ulong y, ulong z) { + return (x&y)^(x&z)^(y&z); + } + + private ulong sum0(ulong x) { + return (Util.rotateRight64(x,28)^ + Util.rotateRight64(x,34)^ + Util.rotateRight64(x,39)); + } + + private ulong sum1(ulong x) { + return (Util.rotateRight64(x,14)^ + Util.rotateRight64(x,18)^ + Util.rotateRight64(x,41)); + } + + private ulong theta0(ulong x) { + return Util.rotateRight64(x,1)^Util.rotateRight64(x,8)^(x >> 7); + } + + private ulong theta1(ulong x) { + return Util.rotateRight64(x,19)^Util.rotateRight64(x,61)^(x >> 6); + } + + ubyte[] digest() { + padMessage(MODE_SHA); + ubyte[] result = new ubyte[digestSize]; + + Util.ulongToUbytesBig(h0, result, 0); + Util.ulongToUbytesBig(h1, result, 8); + Util.ulongToUbytesBig(h2, result, 16); + Util.ulongToUbytesBig(h3, result, 24); + Util.ulongToUbytesBig(h4, result, 32); + Util.ulongToUbytesBig(h5, result, 40); + Util.ulongToUbytesBig(h6, result, 48); + Util.ulongToUbytesBig(h7, result, 56); + + reset(); + return result; + } + + void reset() { + super.reset(); + h0 = 0x6a09e667f3bcc908u; + h1 = 0xbb67ae8584caa73bu; + h2 = 0x3c6ef372fe94f82bu; + h3 = 0xa54ff53a5f1d36f1u; + h4 = 0x510e527fade682d1u; + h5 = 0x9b05688c2b3e6c1fu; + h6 = 0x1f83d9abfb41bd6bu; + h7 = 0x5be0cd19137e2179u; + } + + version (UnitTest) { + unittest { + static const char[][] test_inputs = [ + "", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"~ + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "a" + ]; + + static const int[] test_repeat = [ + 1, 1, 1, 1000000 + ]; + + static const char[][] test_results = [ + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce"~ + "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"~ + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + + "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"~ + "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", + + "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"~ + "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" + ]; + + SHA512 h = new SHA512(); + foreach (uint i, char[] input; test_inputs) { + for (int j = 0; j < test_repeat[i]; j++) + h.update(input); + char[] digest = h.hexDigest(); + assert(digest == test_results[i], + h.name()~": ("~digest~") != ("~test_results[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/modes/CBC.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,181 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.modes.CBC; + +import dcrypt.crypto.BlockCipher; +import dcrypt.crypto.params.ParametersWithIV; + +version (UnitTest) { + import dcrypt.crypto.ciphers.XTEA; + import dcrypt.misc.Util; +} + +/** This class implements the cipher block chaining (CBC) block mode. */ +class CBC : BlockCipher { + private BlockCipher m_cipher; + private ubyte[] iv, + previousCiphertext, + cbcOutput; + private bool encrypt, + initialized; + + /** + * Params: + * cipher = Block cipher to wrap. + */ + this (BlockCipher cipher) { + m_cipher = cipher; + } + + /** Returns: The underlying cipher we are wrapping. */ + BlockCipher cipher() { + return m_cipher; + } + + char[] name() { + return m_cipher.name~"/CBC"; + } + + /** + * Throws: dcrypt.crypto.errors.InvalidParameterError if params aren't + * an instance of dcrypt.crypto.params.ParametersWithIV. + */ + void init(bool encrypt, CipherParameters params) { + ParametersWithIV ivParams = cast(ParametersWithIV)params; + + if (!ivParams) + throw new InvalidParameterError( + name()~": Block mode requires IV (use ParametersWithIV)"); + if (ivParams.iv.length != blockSize) + throw new InvalidParameterError( + name()~": IV must be same length as cipher block size"); + + this.encrypt = encrypt; + m_cipher.init(encrypt, ivParams.parameters); + + iv = ivParams.iv[0..blockSize]; + previousCiphertext = new ubyte[blockSize]; + previousCiphertext[] = iv; // C_0 = IV + cbcOutput = new ubyte[blockSize]; // Output buffer for E_k/D_k(...) + + initialized = true; + } + + uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) { + if (!initialized) + throw new NotInitializedError( + name()~": Block mode not initialized"); + + ubyte[] input = cast(ubyte[]) input_, + output = cast(ubyte[]) output_; + + if ((inOff + blockSize) > input.length) + throw new ShortBufferError(name()~": Input buffer too short"); + + if ((outOff + blockSize) > output.length) + throw new ShortBufferError(name()~": Output buffer too short"); + + if (encrypt) { + // P_i XOR C_i-1 + for (int i = 0; i < blockSize; i++) + previousCiphertext[i] ^= input[inOff++]; + + // E_k(P_i XOR C_i-1) + m_cipher.processBlock(previousCiphertext, 0, cbcOutput, 0); + + // Store C_i for next block + previousCiphertext[] = cbcOutput; + + // C_i = E_k(P_i XOR C_i-1) + output[outOff..(outOff+blockSize)] = cbcOutput; + } else { + // Temporarily store C_i + ubyte[] t = input[inOff..(inOff+blockSize)]; + + // D_k(C_i) + m_cipher.processBlock(t, 0, cbcOutput, 0); + + // P_i = D_k(C_i) XOR C_i-1 + for (int i = 0; i < blockSize; i++) + output[outOff++] = (cbcOutput[i] ^ previousCiphertext[i]); + + // Store C_i for next block + previousCiphertext[] = t; + } + return blockSize; + } + + uint blockSize() { + return m_cipher.blockSize; + } + + void reset() { + previousCiphertext[] = iv; + m_cipher.reset(); + } + + /** Test vectors for CBC mode. Assumes XTEA passes test vectors. */ + version (UnitTest) { + unittest { + static const char[][] test_keys = [ + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "0123456789abcdef0123456789abcdef" + ]; + + static const char[][] test_plaintexts = [ + "00000000000000000000000000000000"~ + "00000000000000000000000000000000", + + "41414141414141414141414141414141"~ + "41414141414141414141414141414141", + + "01010101010101010101010101010101"~ + "01010101010101010101010101010101" + ]; + + static const char[][] test_ciphertexts = [ + "dee9d4d8f7131ed9b0e40a036a85d2c4"~ + "4602d6e67f0c603738197998166ef281", + + "ed23375a821a8c2d0e1f03d719874eaa"~ + "4b71be74f261e22f4cd2285883a61a23", + + "c09d3c606614d84b8d184fa29c5cb5f6"~ + "f26fa5a0b6b63ba0f7ebf2f8735f85e3" + ]; + + XTEA x = new XTEA(); + CBC c = new CBC(x); + ubyte[] iv = new ubyte[x.blockSize], // Initialized to 0 + buffer = new ubyte[32]; + char[] result; + for (int i = 0; i < test_keys.length; i++) { + SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_keys[i])); + ParametersWithIV params = new ParametersWithIV(key, iv); + + // Encryption + c.init(true, params); + for (int j = 0; j < 32; j+=x.blockSize) + c.processBlock(Util.hexToUbytes(test_plaintexts[i]), j, buffer, j); + result = Util.ubytesToHex(buffer); + assert(result == test_ciphertexts[i], + c.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + + // Decryption + c.init(false, params); + for (int j = 0; j < 32; j+=x.blockSize) + c.processBlock(Util.hexToUbytes(test_ciphertexts[i]), j, buffer, j); + result = Util.ubytesToHex(buffer); + assert(result == test_plaintexts[i], + c.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/modes/CTR.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,95 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.modes.CTR; + +import dcrypt.crypto.BlockCipher; +import dcrypt.crypto.params.ParametersWithIV; + + +/** This class implements the counter (CTR/SIC/ICM) block mode, + treating the counter as a big endian integer. */ +class CTR : BlockCipher { + private BlockCipher m_cipher; + private ubyte[] iv, + counter, + counterOutput; + private bool initialized = false; + + /** + * Params: + * cipher = Block cipher to wrap. + */ + this (BlockCipher cipher) { + m_cipher = cipher; + } + + /** Returns: The underlying cipher we are wrapping. */ + BlockCipher cipher() { + return m_cipher; + } + + char[] name() { + return m_cipher.name~"/CTR"; + } + + /** + * Throws: dcrypt.crypto.errors.InvalidParameterError if params aren't + * an instance of dcrypt.crypto.params.ParametersWithIV. + */ + void init(bool encrypt, CipherParameters params) { + ParametersWithIV ivParams = cast(ParametersWithIV)params; + + if (!ivParams) + throw new InvalidParameterError( + name()~": Block mode requires IV (use ParametersWithIV)"); + if (ivParams.iv.length != blockSize) + throw new InvalidParameterError( + name()~": IV must be same length as cipher block size"); + + m_cipher.init(true, ivParams.parameters); + + iv = ivParams.iv[0..blockSize]; + counter = new ubyte[blockSize]; + counter[] = iv; + counterOutput = new ubyte[blockSize]; + + initialized = true; + } + + uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) { + if (!initialized) + throw new NotInitializedError( + name()~": Block mode not initialized"); + + ubyte[] input = cast(ubyte[]) input_; + ubyte[] output = cast(ubyte[]) output_; + + // Encrypt the counter + m_cipher.processBlock(counter, 0, counterOutput, 0); + + // XOR output with plaintext to create ciphertext + for (int i = 0; i < counter.length; i++) + output[outOff++] = (counterOutput[i] ^ input[inOff++]); + + // Increment the counter + for (int i = counter.length-1; i >= 0; i--) + if (++counter[i]) break; + + return counter.length; + } + + uint blockSize() { + return m_cipher.blockSize; + } + + void reset() { + counter[] = iv; + m_cipher.reset(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/padding/NullByte.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,44 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.padding.NullByte; + +import dcrypt.crypto.BlockCipherPadding; + +/** + * This class implements Null/Zero byte padding. + * Ex. [... 0x00, 0x00 ... 0x00] + */ +class NullByte : BlockCipherPadding { + char[] name() { + return "NullByte"; + } + + /* Assumes input_ is a multiple of the underlying + * block cipher's block size. + */ + uint padBlock(void[] input_, uint inOff) { + ubyte[] input = cast(ubyte[]) input_; + + uint len = (input.length - inOff); + + input[inOff..input.length] = 0; + + return len; + } + + uint padLength(void[] input_) { + ubyte[] input = cast(ubyte[]) input_; + + uint len = input.length; + while (len-- > 0) + if (input[len-1] != 0) break; + + return (input.length - len); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/padding/PKCS7.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,50 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.padding.PKCS7; + +import dcrypt.crypto.BlockCipherPadding; + +/** + * This class implements the padding scheme described in PKCS7 + * from RSA Security. Ex. [... 0x03, 0x03, 0x03] + */ +class PKCS7 : BlockCipherPadding { + char[] name() { + return "PKCS7"; + } + + /* Assumes input_ is a multiple of the underlying + * block cipher's block size. + */ + uint padBlock(void[] input_, uint inOff) { + ubyte[] input = cast(ubyte[]) input_; + + ubyte len = (input.length - inOff); + + input[inOff..input.length] = len; + + return len; + } + + uint padLength(void[] input_) { + ubyte[] input = cast(ubyte[]) input_; + + ubyte len = input[input.length-1]; + + if (len > input.length || len == 0) + throw new InvalidPaddingError(name()~": Incorrect padding."); + + uint limit = input.length; + for (int i = 0; i < len; i++) + if (input[--limit] != len) + throw new InvalidPaddingError( + name()~": Pad value does not match pad length."); + return len; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/padding/RFC1321.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,50 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.padding.RFC1321; + +import dcrypt.crypto.BlockCipherPadding; + +/** + * This class implements the padding described in RFC1321 (MD5 spec). + * Ex. [... 0x80, 0x00 ... 0x00] + */ +class RFC1321 : BlockCipherPadding { + char[] name() { + return "RFC1321"; + } + + /* Assumes input_ is a multiple of the underlying + * block cipher's block size. + */ + uint padBlock(void[] input_, uint inOff) { + ubyte[] input = cast(ubyte[]) input_; + + uint len = (input.length - inOff); + + input[inOff++] = 0x80; + input[inOff..input.length] = 0; + + return len; + } + + uint padLength(void[] input_) { + ubyte[] input = cast(ubyte[]) input_; + + uint len = input.length; + + while (len-- > 0) + if (input[len] != 0) break; + + if (input[len] != 0x80) + throw new InvalidPaddingError( + name()~": Incorrect padding."); + + return (input.length - len); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/padding/X923.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,46 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.padding.X923; + +import dcrypt.crypto.BlockCipherPadding; + +/** + * This class implements the Null/Zero byte padding described in ANSI X.923. + * Ex. [... 0x00, 0x00, 0x03] + */ +class X923 : BlockCipherPadding { + char[] name() { + return "X923"; + } + + /* Assumes input_ is a multiple of the underlying + * block cipher's block size. + */ + uint padBlock(void[] input_, uint inOff) { + ubyte[] input = cast(ubyte[]) input_; + + ubyte len = (input.length - inOff); + + input[inOff..input.length-1] = 0; + input[input.length-1] = len; + + return len; + } + + uint padLength(void[] input_) { + ubyte[] input = cast(ubyte[]) input_; + + ubyte len = input[input.length-1]; + + if (len > input.length || len == 0) + throw new InvalidPaddingError(name()~": Incorrect padding."); + + return len; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/params/CipherParameters.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,12 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.params.CipherParameters; + +/** Base class for all cipher parameters. */ +class CipherParameters {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/params/ParametersWithIV.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,63 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.params.ParametersWithIV; + +public import dcrypt.crypto.params.CipherParameters; + +/** Wrap cipher parameters and IV. */ +class ParametersWithIV : CipherParameters { + private ubyte[] m_iv; + private CipherParameters m_params; + + /** + * Params: + * params = Parameters to wrap. + * iv = IV to be held. + */ + this(CipherParameters params=null, ubyte[] iv_=null) { + if (params) + m_params = params; + ubyte[] iv = cast(ubyte[]) iv_; + if (iv) + m_iv = iv; + } + + /** Returns: The IV. */ + ubyte[] iv() { + return m_iv; + } + + /** + * Set the IV held by this object. + * + * Params: + * newIV = The new IV for this parameter object. + * Returns: The new IV. + */ + ubyte[] iv(void[] newIV_) { + ubyte[] newIV = cast(ubyte[]) newIV_; + return m_iv = newIV; + } + + /** Returns: The parameters for this object. */ + CipherParameters parameters() { + return m_params; + } + + /** + * Set the parameters held by this object. + * + * Params: + * newParams = The new parameters to be held. + * Returns: The new parameters. + */ + CipherParameters parameters(CipherParameters newParams) { + return m_params = newParams; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/params/SymmetricKey.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,43 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.params.SymmetricKey; + +import dcrypt.crypto.params.CipherParameters; + +/** Object representing and wrapping a symmetric key in bytes. */ +class SymmetricKey : CipherParameters { + private ubyte[] m_key; + + /** + * Params: + * key = Key to be held. + */ + this(void[] key_=null) { + ubyte[] key = cast(ubyte[]) key_; + if (key) + m_key = key; + } + + /** Returns: Key in ubytes held by this object. */ + ubyte[] key() { + return m_key; + } + + /** + * Set the key held by this object. + * + * Params: + * newKey = New key to be held. + * Returns: The new key. + */ + ubyte[] key(void[] newKey_) { + ubyte[] newKey = cast(ubyte[])newKey_; + return m_key = newKey; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/misc/Util.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,159 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +// TODO: WRITE DOCS, IMPLEMENT TO/FROM HEX FUNCTIONS, SIMPLIFY UNITTESTS +module dcrypt.misc.Util; + +/** Utility functions */ +struct Util { + static const char[] hexits = "0123456789abcdef"; + + final static uint ubytesToUintBig(ubyte[] x, uint offset) { + return cast(uint) (((x[offset++] & 0xff) << 24) | + ((x[offset++] & 0xff) << 16) | + ((x[offset++] & 0xff) << 8) | + (x[offset] & 0xff)); + } + + final static uint ubytesToUintLittle(ubyte[] x, uint offset) { + return cast(uint) ((x[offset++] & 0xff) | + ((x[offset++] & 0xff) << 8) | + ((x[offset++] & 0xff) << 16) | + ((x[offset] & 0xff) << 24)); + } + + final static ulong ubytesToUlongLittle(ubyte[] x, uint offset) { + return cast(ulong) ((x[offset++] & 0xff) | + ((x[offset++] & 0xff) << 8) | + ((x[offset++] & 0xff) << 16) | + ((x[offset++] & 0xff) << 24) | + (cast(ulong)(x[offset++] & 0xff) << 32) | + (cast(ulong)(x[offset++] & 0xff) << 40) | + (cast(ulong)(x[offset++] & 0xff) << 48) | + (cast(ulong)(x[offset] & 0xff) << 56)); + } + + final static ulong ubytesToUlongBig(ubyte[] x, uint offset) { + return cast(ulong) ((cast(ulong)(x[offset++] & 0xff) << 56) | + (cast(ulong)(x[offset++] & 0xff) << 48) | + (cast(ulong)(x[offset++] & 0xff) << 40) | + (cast(ulong)(x[offset++] & 0xff) << 32) | + ((x[offset++] & 0xff) << 24) | + ((x[offset++] & 0xff) << 16) | + ((x[offset++] & 0xff) << 8) | + (x[offset] & 0xff)); + } + + final static ushort ubytesToUshortLittle(ubyte[] x, uint offset) { + return cast(ushort) ((x[offset++] & 0xff) | + ((x[offset] & 0xff) << 8)); + } + + final static ushort ubytesToUshortBig(ubyte[] x, uint offset) { + return cast(ushort) (((x[offset++] & 0xff) << 8) | + (x[offset] & 0xff)); + } + + final static void uintToUbytesBig(uint x, ubyte[] output, uint outOff) { + output[outOff++] = cast(ubyte)(x >> 24); + output[outOff++] = cast(ubyte)(x >> 16); + output[outOff++] = cast(ubyte)(x >> 8); + output[outOff] = cast(ubyte)(x); + } + + final static void uintToUbytesLittle(uint x, ubyte[] output, uint outOff) { + output[outOff++] = cast(ubyte)(x); + output[outOff++] = cast(ubyte)(x >> 8); + output[outOff++] = cast(ubyte)(x >> 16); + output[outOff] = cast(ubyte)(x >> 24); + } + + final static void ulongToUbytesBig(ulong x, ubyte[] output, uint outOff) { + output[outOff++] = cast(ubyte)(x >> 56); + output[outOff++] = cast(ubyte)(x >> 48); + output[outOff++] = cast(ubyte)(x >> 40); + output[outOff++] = cast(ubyte)(x >> 32); + output[outOff++] = cast(ubyte)(x >> 24); + output[outOff++] = cast(ubyte)(x >> 16); + output[outOff++] = cast(ubyte)(x >> 8); + output[outOff] = cast(ubyte)(x); + } + + final static void ulongToUbytesLittle(ulong x, ubyte[] output, uint outOff) { + output[outOff++] = cast(ubyte)(x); + output[outOff++] = cast(ubyte)(x >> 8); + output[outOff++] = cast(ubyte)(x >> 16); + output[outOff++] = cast(ubyte)(x >> 24); + output[outOff++] = cast(ubyte)(x >> 32); + output[outOff++] = cast(ubyte)(x >> 40); + output[outOff++] = cast(ubyte)(x >> 48); + output[outOff] = cast(ubyte)(x >> 56); + } + + final static uint rotateLeft(uint x, uint y) { + return (x << y) | (x >> (32-y)); + } + + final static ulong rotateLeft64(ulong x, uint y) { + return (x << y) | (x >> (64-y)); + } + + final static uint rotateRight(uint x, uint y) { + return (x >> y) | (x << (32-y)); + } + + final static ulong rotateRight64(ulong x, uint y) { + return (x >> y) | (x << (64-y)); + } + + final static char[] ubytesToHex(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; + } + + final static ubyte[] hexToUbytes(char[] input) { + ubyte[] output = new ubyte[input.length>>1]; + static ubyte[char] hexitIndex; + for (int i = 0; i < hexits.length; i++) + hexitIndex[hexits[i]] = i; + for (int i = 0, j = 0; i < output.length; i++) { + output[i] = hexitIndex[input[j++]] << 4; + output[i] |= hexitIndex[input[j++]]; + } + return output; + } + + final static char[] stringToLower(char[] input) { + char[] output = new char[input.length]; + foreach (uint i, char c; input) + output[i] = ((c >= 'A' && c <= 'Z') ? c+32 : c); + return output; + } + + final static char[] stringToUpper(char[] input) { + char[] output = new char[input.length]; + foreach (uint i, char c; input) + output[i] = ((c >= 'a' && c <= 'z') ? c-32 : c); + return output; + } + + final static char[] stringToAlphanumeric(char[] input) { + char[] output = ""; + foreach (char c; input) + if ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')) + output ~= c; + return output; + } +}