Mercurial > projects > dcrypt
annotate dcrypt/crypto/modes/CBC.d @ 23:4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Sat, 14 Feb 2009 19:58:20 -0500 |
parents | 8c7f8fecdd75 |
children | 176c933827a8 |
rev | line source |
---|---|
0 | 1 /** |
2 * This file is part of the dcrypt project. | |
3 * | |
4 * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. | |
5 * License: MIT | |
6 * Authors: Thomas Dixon | |
7 */ | |
8 | |
9 module dcrypt.crypto.modes.CBC; | |
10 | |
11 import dcrypt.crypto.BlockCipher; | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
12 public import dcrypt.crypto.params.ParametersWithIV; |
0 | 13 |
14 version (UnitTest) { | |
15 import dcrypt.crypto.ciphers.XTEA; | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
16 import dcrypt.misc.ByteConverter; |
0 | 17 } |
18 | |
19 /** This class implements the cipher block chaining (CBC) block mode. */ | |
20 class CBC : BlockCipher { | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
21 private BlockCipher wrappedCipher; |
0 | 22 private ubyte[] iv, |
23 previousCiphertext, | |
24 cbcOutput; | |
25 private bool encrypt, | |
26 initialized; | |
27 | |
28 /** | |
29 * Params: | |
30 * cipher = Block cipher to wrap. | |
31 */ | |
32 this (BlockCipher cipher) { | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
33 wrappedCipher = cipher; |
0 | 34 } |
35 | |
36 /** Returns: The underlying cipher we are wrapping. */ | |
37 BlockCipher cipher() { | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
38 return wrappedCipher; |
0 | 39 } |
40 | |
41 char[] name() { | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
42 return wrappedCipher.name~"/CBC"; |
0 | 43 } |
44 | |
45 /** | |
46 * Throws: dcrypt.crypto.errors.InvalidParameterError if params aren't | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
47 * an instance of dcrypt.crypto.params.ParametersWithIV. |
0 | 48 */ |
49 void init(bool encrypt, CipherParameters params) { | |
50 ParametersWithIV ivParams = cast(ParametersWithIV)params; | |
51 | |
52 if (!ivParams) | |
53 throw new InvalidParameterError( | |
54 name()~": Block mode requires IV (use ParametersWithIV)"); | |
55 if (ivParams.iv.length != blockSize) | |
56 throw new InvalidParameterError( | |
57 name()~": IV must be same length as cipher block size"); | |
58 | |
59 this.encrypt = encrypt; | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
60 wrappedCipher.init(encrypt, ivParams.parameters); |
0 | 61 |
62 iv = ivParams.iv[0..blockSize]; | |
63 previousCiphertext = new ubyte[blockSize]; | |
64 previousCiphertext[] = iv; // C_0 = IV | |
65 cbcOutput = new ubyte[blockSize]; // Output buffer for E_k/D_k(...) | |
66 | |
67 initialized = true; | |
68 } | |
69 | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
70 uint update(void[] input_, void[] output_) { |
0 | 71 if (!initialized) |
72 throw new NotInitializedError( | |
73 name()~": Block mode not initialized"); | |
74 | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
75 ubyte[] input = cast(ubyte[]) input_, |
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
76 output = cast(ubyte[]) output_; |
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
77 |
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.
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
78 if (input.length < blockSize) |
0 | 79 throw new ShortBufferError(name()~": Input buffer too short"); |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
80 |
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
81 if (output.length < blockSize) |
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
82 throw new ShortBufferError(name()~": Output buffer too short"); |
0 | 83 |
84 if (encrypt) { | |
85 // P_i XOR C_i-1 | |
86 for (int i = 0; i < blockSize; i++) | |
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.
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
87 previousCiphertext[i] ^= input[i]; |
0 | 88 |
89 // E_k(P_i XOR C_i-1) | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
90 wrappedCipher.update(previousCiphertext, cbcOutput); |
0 | 91 |
92 // Store C_i for next block | |
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.
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
93 previousCiphertext[] = cbcOutput; |
0 | 94 |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
95 // C_i = E_k(P_i XOR C_i-1) |
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
96 output[0..blockSize] = cbcOutput; |
0 | 97 } else { |
98 // Temporarily store C_i | |
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.
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
99 ubyte[] t = input[0..blockSize]; |
0 | 100 |
101 // D_k(C_i) | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
102 wrappedCipher.update(t, cbcOutput); |
0 | 103 |
104 // P_i = D_k(C_i) XOR C_i-1 | |
105 for (int i = 0; i < blockSize; i++) | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
106 output[i] = (cbcOutput[i] ^ previousCiphertext[i]); |
0 | 107 |
108 // Store C_i for next block | |
109 previousCiphertext[] = t; | |
110 } | |
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.
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
111 |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
112 return blockSize; |
0 | 113 } |
114 | |
115 uint blockSize() { | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
116 return wrappedCipher.blockSize; |
0 | 117 } |
118 | |
119 void reset() { | |
120 previousCiphertext[] = iv; | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
121 wrappedCipher.reset(); |
0 | 122 } |
123 | |
124 /** Test vectors for CBC mode. Assumes XTEA passes test vectors. */ | |
125 version (UnitTest) { | |
126 unittest { | |
127 static const char[][] test_keys = [ | |
128 "00000000000000000000000000000000", | |
129 "00000000000000000000000000000000", | |
130 "0123456789abcdef0123456789abcdef" | |
131 ]; | |
132 | |
133 static const char[][] test_plaintexts = [ | |
134 "00000000000000000000000000000000"~ | |
135 "00000000000000000000000000000000", | |
136 | |
137 "41414141414141414141414141414141"~ | |
138 "41414141414141414141414141414141", | |
139 | |
140 "01010101010101010101010101010101"~ | |
141 "01010101010101010101010101010101" | |
142 ]; | |
143 | |
144 static const char[][] test_ciphertexts = [ | |
145 "dee9d4d8f7131ed9b0e40a036a85d2c4"~ | |
146 "4602d6e67f0c603738197998166ef281", | |
147 | |
148 "ed23375a821a8c2d0e1f03d719874eaa"~ | |
149 "4b71be74f261e22f4cd2285883a61a23", | |
150 | |
151 "c09d3c606614d84b8d184fa29c5cb5f6"~ | |
152 "f26fa5a0b6b63ba0f7ebf2f8735f85e3" | |
153 ]; | |
12
8c7f8fecdd75
Added ManagedBlockCipher, changed Crypto to just import everything, made Hash.update() return itself (for chaining) and ditched BlockCipherWrapper.
Thomas Dixon <reikon@reikon.us>
parents:
8
diff
changeset
|
154 |
0 | 155 XTEA x = new XTEA(); |
156 CBC c = new CBC(x); | |
157 ubyte[] iv = new ubyte[x.blockSize], // Initialized to 0 | |
158 buffer = new ubyte[32]; | |
159 char[] result; | |
160 for (int i = 0; i < test_keys.length; i++) { | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
161 SymmetricKey key = new SymmetricKey(ByteConverter.hexDecode(test_keys[i])); |
0 | 162 ParametersWithIV params = new ParametersWithIV(key, iv); |
163 | |
164 // Encryption | |
165 c.init(true, params); | |
166 for (int j = 0; j < 32; j+=x.blockSize) | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
167 c.update(ByteConverter.hexDecode(test_plaintexts[i])[j..j+x.blockSize], buffer[j..j+x.blockSize]); |
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
168 result = ByteConverter.hexEncode(buffer); |
0 | 169 assert(result == test_ciphertexts[i], |
170 c.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); | |
171 | |
172 // Decryption | |
173 c.init(false, params); | |
174 for (int j = 0; j < 32; j+=x.blockSize) | |
23
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
175 c.update(ByteConverter.hexDecode(test_ciphertexts[i])[j..j+x.blockSize], buffer[j..j+x.blockSize]); |
4589f8c5eb3c
Replaced dcrypt.crypto.Util with dcrypt.misc.Bitwise and dcrypt.misc.ByteConverter. Altered all dependent files to reflect changes.
Thomas Dixon <reikon@reikon.us>
parents:
12
diff
changeset
|
176 result = ByteConverter.hexEncode(buffer); |
0 | 177 assert(result == test_plaintexts[i], |
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.
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
178 c.name()~": ("~result~") != ("~test_plaintexts[i]~")"); |
0 | 179 } |
180 } | |
181 } | |
182 } |