Mercurial > projects > dcrypt
diff dcrypt/crypto/ciphers/RC4.d @ 0:0e08791a1418
Initial import.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Sun, 10 Aug 2008 14:20:17 -0400 |
parents | |
children | 483e4467b5f6 |
line wrap: on
line diff
--- /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]~")"); + } + } + } +}