Mercurial > projects > dcrypt
view dcrypt/crypto/ciphers/RC4.d @ 8:23c62e28b3a4
Reworked symmetric cipher classes to have SymmetricCipher as their superclass, and follow the general interface of init(), process(), etc. Made sure everything still passed test vectors. Removed Cipher class. I'll worry about that shit when we support something other than symmetric ciphers.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Mon, 18 Aug 2008 01:14:37 -0400 |
parents | 5cb17e09d685 |
children | 8c7f8fecdd75 |
line wrap: on
line source
/** * 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; ubyte x, y; 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])]); } ubyte[] process(void[] input_) { if (!initialized) throw new NotInitializedError(name()~": Cipher not initialized"); ubyte[] input = cast(ubyte[]) input_, output = new ubyte[input.length]; for (int i = 0; i < input.length; i++) { y += state[++x]; ubyte t = state[x]; state[x] = state[y]; state[y] = t; output[i] = input[i] ^ state[cast(ubyte)(state[x]+state[y])]; } return output; } 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 buffer = r.process(Util.hexToUbytes(test_plaintexts[i])); result = Util.ubytesToHex(buffer); assert(result == test_ciphertexts[i], r.name~": ("~result~") != ("~test_ciphertexts[i]~")"); r.reset(); // Decryption buffer = r.process(Util.hexToUbytes(test_ciphertexts[i])); result = Util.ubytesToHex(buffer); assert(result == test_plaintexts[i], r.name~": ("~result~") != ("~test_plaintexts[i]~")"); } } } }