# HG changeset patch # User Thomas Dixon # Date 1219277287 14400 # Node ID cd376996cdb3fd1f03cfd1feb812190f7dec1ec0 # Parent 29b910949588ff15fec5421b993fe716992012b1 Renamed SymmetricCipher back to Cipher (we don't support any other kind atm, I'll deal with it when we do.). Added BlockCipherWrapper for the encryption of arbitrary streams with or without padding. Removed hashByName, and replaced it with createHash. Re-did the high-level API, and filled out Crypto. Added cipher creation via createCipher. Added dsk to the CONTRIBUTORS file for helping with the design of the high-level API. diff -r 29b910949588 -r cd376996cdb3 CONTRIBUTORS --- a/CONTRIBUTORS Mon Aug 18 01:19:18 2008 -0400 +++ b/CONTRIBUTORS Wed Aug 20 20:08:07 2008 -0400 @@ -1,1 +1,2 @@ Thomas Dixon +Daniel Korsgaard <#d @ irc.freenode.net> diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/BlockCipher.d --- a/dcrypt/crypto/BlockCipher.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/BlockCipher.d Wed Aug 20 20:08:07 2008 -0400 @@ -8,11 +8,11 @@ module dcrypt.crypto.BlockCipher; -public import dcrypt.crypto.SymmetricCipher; +public import dcrypt.crypto.Cipher; public import dcrypt.crypto.params.SymmetricKey; /** Interface for a standard block cipher. */ -abstract class BlockCipher : SymmetricCipher { +abstract class BlockCipher : Cipher { /** Returns: The block size in bytes that this cipher will operate on. */ uint blockSize(); diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/BlockCipherPadding.d --- a/dcrypt/crypto/BlockCipherPadding.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/BlockCipherPadding.d Wed Aug 20 20:08:07 2008 -0400 @@ -16,15 +16,14 @@ char[] name(); /** - * Pad the (last) block of plaintext to block length. + * Generate padding to a specific length. * * Params: - * input_ = Plaintext block to be padded. - * inOffset = Offset at which to begin padding input_. + * len = Length of padding to generate * - * Returns: The number of padding bytes added. + * Returns: The padding bytes to be added. */ - uint padBlock(void[] input_, uint inOff); + ubyte[] pad(uint len); /** * Return the number of pad bytes in the block. @@ -37,5 +36,5 @@ * Throws: dcrypt.crypto.errors.InvalidPaddingError if * pad length cannot be discerned. */ - uint padLength(void[] input_); + uint unpad(void[] input_); } diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/BlockCipherWrapper.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/BlockCipherWrapper.d Wed Aug 20 20:08:07 2008 -0400 @@ -0,0 +1,85 @@ +/** + * 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.BlockCipherWrapper; + +import dcrypt.crypto.BlockCipher; +import dcrypt.crypto.BlockCipherPadding; + +/** + * Wraps a block cipher, enabling the encryption of a stream + * whose length is a multiple of blockSize. Padding, if specified, + * is to be applied otherwise and the result subsequently processed. + */ +class BlockCipherWrapper : BlockCipher { + BlockCipher cipher; + BlockCipherPadding padding; + bool encrypt; + + this(BlockCipher c, BlockCipherPadding p=null) { + cipher = c; + padding = p; // null signifies no padding is to be applied + } + + void init(bool encrypt, CipherParameters params) { + this.encrypt = encrypt; + cipher.init(encrypt, params); + } + + char[] name() { + if (padding !is null) + return cipher.name~"/"~padding.name; + return cipher.name; + } + + uint blockSize() { + return cipher.blockSize; + } + + ubyte[] process(void[] input_) { + ubyte[] input = cast(ubyte[]) input_; + + uint padLen = blockSize - (input.length % blockSize); + if (padding !is null && !encrypt && padLen != blockSize) + throw new ShortBufferError( + name()~": Encrypted padded block should be multiple of block size."); + + ubyte[] output = new ubyte[input.length]; + + uint len = input.length, + i = 0; + while (len >= blockSize) { + output[i..i+blockSize] = cipher.process(input[i..i+blockSize]); + len -= blockSize; + i += blockSize; + } + + if (padding !is null) { + if (encrypt) { + output.length = output.length + padLen; + ubyte[] t = new ubyte[blockSize]; + if (len > 0) { + t[0..len] = input[i..i+len]; + t[len..blockSize] = padding.pad(padLen); + } else + t[] = padding.pad(padLen); + output[i..i+blockSize] = cipher.process(t); + } else { + output.length = output.length - padding.unpad(output); + } + } else + if (len > 0) + output[i..i+len] = cipher.process(input[i..i+len]); + + return output; + } + + void reset() { + cipher.reset(); + } +} \ No newline at end of file diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/Cipher.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/Cipher.d Wed Aug 20 20:08:07 2008 -0400 @@ -0,0 +1,48 @@ +/** + * 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 symmetric cipher class */ +abstract class 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.) + */ + void init(bool encrypt, CipherParameters params); + + /** + * Process a block of plaintext data from the input array + * and return the encrypted data. + * + * Params: + * input_ = Array containing input data. + * + * Returns: The encrypted data. + */ + ubyte[] process(void[] input_); + + /** Returns: The name of the algorithm of this cipher. */ + char[] name(); + + /** Reset cipher to its state immediately subsequent the last init. */ + void reset(); +} diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/Crypto.d --- a/dcrypt/crypto/Crypto.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/Crypto.d Wed Aug 20 20:08:07 2008 -0400 @@ -8,10 +8,6 @@ module dcrypt.crypto.Crypto; -import dcrypt.crypto.SymmetricCipher; - -import dcrypt.misc.Util; - // Hash functions public import dcrypt.crypto.Hash; import dcrypt.crypto.hashes.MD5; @@ -21,23 +17,147 @@ import dcrypt.crypto.hashes.SHA384; import dcrypt.crypto.hashes.SHA512; +// Params +public import dcrypt.crypto.params.SymmetricKey; +public import dcrypt.crypto.params.ParametersWithIV; + + +// Ciphers +public import dcrypt.crypto.Cipher; +public import dcrypt.crypto.BlockCipher; +public import dcrypt.crypto.StreamCipher; +public import dcrypt.crypto.BlockCipherWrapper; +import dcrypt.crypto.ciphers.Blowfish; +import dcrypt.crypto.ciphers.RC6; +import dcrypt.crypto.ciphers.TEA; +import dcrypt.crypto.ciphers.XTEA; +import dcrypt.crypto.ciphers.RC4; +import dcrypt.crypto.ciphers.AES; + +// Block modes +import dcrypt.crypto.modes.CBC; +import dcrypt.crypto.modes.CTR; + +// Block padding +public import dcrypt.crypto.BlockCipherPadding; +import dcrypt.crypto.padding.NullByte; +import dcrypt.crypto.padding.X923; +import dcrypt.crypto.padding.PKCS7; +import dcrypt.crypto.padding.RFC1321; + +enum Hashes { + MD5=0, + SHA1, + SHA224, + SHA256, + SHA384, + SHA512 +} + +enum Ciphers { + // Block ciphers + Blowfish=0, + AES, + RC6, + TEA, + XTEA, + + // Stream ciphers + RC4 +} + +enum Modes { + ECB=-1, + CTR, + CBC +} + +enum Padding { + None=-1, + NullByte, // lol + X923, + PKCS7, + RFC1321 +} + 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(); + static Hash createHash(uint hash) { + switch (hash) { + case Hashes.MD5: + return new MD5; + case Hashes.SHA1: + return new SHA1; + case Hashes.SHA224: + return new SHA224; + case Hashes.SHA256: + return new SHA256; + case Hashes.SHA384: + return new SHA384; + case Hashes.SHA512: + return new SHA512; default: - throw new InvalidParameterError("Unknown hash function: "~name); + throw new InvalidParameterError("Unknown hash function passed to createHash()"); } } + + static Cipher createCipher(uint cipher, uint mode=Modes.ECB, uint padding=Padding.None) { + BlockCipher c = null, + m = null; + BlockCipherPadding p = null; + switch (cipher) { + case Ciphers.Blowfish: + c = new Blowfish; + break; + case Ciphers.AES: + c = new AES; + break; + case Ciphers.RC6: + c = new RC6; + break; + case Ciphers.TEA: + c = new TEA; + break; + case Ciphers.XTEA: + c = new XTEA; + break; + case Ciphers.RC4: + return new RC4; // Note the return + default: + throw new InvalidParameterError("Unknown cipher passed to createCipher()"); + } + + switch (mode) { + case Modes.ECB: + break; + case Modes.CTR: + m = new CTR(c); + break; + case Modes.CBC: + m = new CBC(c); + break; + default: + throw new InvalidParameterError("Unknown mode passed to createCipher()"); + } + + switch (padding) { + case Padding.None: + break; + case Padding.NullByte: + p = new NullByte; + break; + case Padding.X923: + p = new X923; + break; + case Padding.PKCS7: + p = new PKCS7; + break; + case Padding.RFC1321: + p = new RFC1321; + break; + default: + throw new InvalidParameterError("Unknown padding passed to createCipher()"); + } + + return new BlockCipherWrapper(((m is null) ? c : m), p); + } } diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/StreamCipher.d --- a/dcrypt/crypto/StreamCipher.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/StreamCipher.d Wed Aug 20 20:08:07 2008 -0400 @@ -8,12 +8,12 @@ module dcrypt.crypto.StreamCipher; -public import dcrypt.crypto.SymmetricCipher; +public import dcrypt.crypto.Cipher; public import dcrypt.crypto.params.CipherParameters; public import dcrypt.crypto.params.SymmetricKey; /** Interface for a standard stream cipher. */ -abstract class StreamCipher : SymmetricCipher { +abstract class StreamCipher : Cipher { /** * Process one byte of input. * diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/StreamCipherWrapper.d --- a/dcrypt/crypto/StreamCipherWrapper.d Mon Aug 18 01:19:18 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/** - * 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.StreamCipherWrapper; - -import dcrypt.crypto.SymmetricCipher; -import dcrypt.crypto.StreamCipher; -public import dcrypt.crypto.params.CipherParameters; - -/** High-level API for stream ciphers. */ -class StreamCipherWrapper : SymmetricCipher { - private StreamCipher cipher; - - this(StreamCipher sc) { - cipher = sc; - } - - void init(bool encrypt, CipherParameters params) { - cipher.init(encrypt, params); - } - - uint update(void[] input_, uint inOff, - uint len, void[] output_, uint outOff) { - cipher.processBytes(input_, inOff, len, output_, outOff); - return len; - } - - uint finish(void[] output_, uint outOff) { - return 0; - } - - void reset() { - cipher.reset(); - } - - char[] name() { - return cipher.name; - } -} diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/SymmetricCipher.d --- a/dcrypt/crypto/SymmetricCipher.d Mon Aug 18 01:19:18 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/** - * 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; - -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 symmetric cipher class */ -abstract class SymmetricCipher { - 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.) - */ - void init(bool encrypt, CipherParameters params); - - /** - * Process a block of plaintext data from the input array - * and return the encrypted data. - * - * Params: - * input_ = Array containing input data. - * - * Returns: The encrypted data. - */ - ubyte[] process(void[] input_); - - /** Returns: The name of the algorithm of this cipher. */ - char[] name(); - - /** Reset cipher to its state immediately subsequent the last init. */ - void reset(); -} diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/hashes/MD5.d --- a/dcrypt/crypto/hashes/MD5.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/hashes/MD5.d Wed Aug 20 20:08:07 2008 -0400 @@ -16,6 +16,7 @@ * Conforms: RFC 1321 * References: http://www.faqs.org/rfcs/rfc1321.html * Bugs: MD5 is not cryptographically secure. + * Throws: InsecureAlgorithmError upon instantiation. */ class MD5 : Hash { private uint h0, h1, h2, h3; diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/modes/CTR.d --- a/dcrypt/crypto/modes/CTR.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/modes/CTR.d Wed Aug 20 20:08:07 2008 -0400 @@ -68,19 +68,20 @@ name()~": Block mode not initialized"); ubyte[] input = cast(ubyte[]) input_; + uint len = (counter.length > input.length) ? input.length : counter.length; // Encrypt the counter counterOutput[] = m_cipher.process(counter); // XOR output with plaintext to create ciphertext - for (int i = 0; i < counter.length; i++) + for (int i = 0; i < len; i++) counterOutput[i] ^= input[i]; // Increment the counter for (int i = counter.length-1; i >= 0; i--) if (++counter[i]) break; - return counterOutput; + return counterOutput[0..len]; } uint blockSize() { diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/padding/NullByte.d --- a/dcrypt/crypto/padding/NullByte.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/padding/NullByte.d Wed Aug 20 20:08:07 2008 -0400 @@ -19,20 +19,15 @@ 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_; + ubyte[] pad(uint len) { + ubyte[] output = new ubyte[len]; + + output[0..output.length] = 0; - uint len = (input.length - inOff); - - input[inOff..input.length] = 0; - - return len; + return output; } - uint padLength(void[] input_) { + uint unpad(void[] input_) { ubyte[] input = cast(ubyte[]) input_; uint len = input.length; diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/padding/PKCS7.d --- a/dcrypt/crypto/padding/PKCS7.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/padding/PKCS7.d Wed Aug 20 20:08:07 2008 -0400 @@ -19,20 +19,15 @@ 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[] pad(uint len) { + ubyte[] output = new ubyte[len]; + + output[0..output.length] = cast(byte)len; - ubyte len = (input.length - inOff); - - input[inOff..input.length] = len; - - return len; + return output; } - uint padLength(void[] input_) { + uint unpad(void[] input_) { ubyte[] input = cast(ubyte[]) input_; ubyte len = input[input.length-1]; diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/padding/RFC1321.d --- a/dcrypt/crypto/padding/RFC1321.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/padding/RFC1321.d Wed Aug 20 20:08:07 2008 -0400 @@ -18,22 +18,17 @@ 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); + ubyte[] pad(uint len) { + ubyte[] output = new ubyte[len]; - input[inOff++] = 0x80; - input[inOff..input.length] = 0; + output[0] = 0x80; + output[1..output.length] = 0; - return len; + return output; } - uint padLength(void[] input_) { + uint unpad(void[] input_) { ubyte[] input = cast(ubyte[]) input_; uint len = input.length; diff -r 29b910949588 -r cd376996cdb3 dcrypt/crypto/padding/X923.d --- a/dcrypt/crypto/padding/X923.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/crypto/padding/X923.d Wed Aug 20 20:08:07 2008 -0400 @@ -22,18 +22,16 @@ /* 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); + ubyte[] pad(uint len) { + ubyte[] output = new ubyte[len]; - input[inOff..input.length-1] = 0; - input[input.length-1] = len; + output[0..len-1] = 0; + output[output.length-1] = cast(ubyte)len; - return len; + return output; } - uint padLength(void[] input_) { + uint unpad(void[] input_) { ubyte[] input = cast(ubyte[]) input_; ubyte len = input[input.length-1]; diff -r 29b910949588 -r cd376996cdb3 dcrypt/misc/Util.d --- a/dcrypt/misc/Util.d Mon Aug 18 01:19:18 2008 -0400 +++ b/dcrypt/misc/Util.d Wed Aug 20 20:08:07 2008 -0400 @@ -6,7 +6,7 @@ * Authors: Thomas Dixon */ -// TODO: WRITE DOCS, IMPLEMENT TO/FROM HEX FUNCTIONS, SIMPLIFY UNITTESTS +// TODO: WRITE DOCS module dcrypt.misc.Util; /** Utility functions */ diff -r 29b910949588 -r cd376996cdb3 dsss.conf --- a/dsss.conf Mon Aug 18 01:19:18 2008 -0400 +++ b/dsss.conf Wed Aug 20 20:08:07 2008 -0400 @@ -1,2 +1,4 @@ name = dcrypt [dcrypt] +target = dcrypt +