Mercurial > projects > dcrypt
comparison 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 |
comparison
equal
deleted
inserted
replaced
22:74303a717032 | 23:4589f8c5eb3c |
---|---|
11 import dcrypt.crypto.BlockCipher; | 11 import dcrypt.crypto.BlockCipher; |
12 public import dcrypt.crypto.params.ParametersWithIV; | 12 public import dcrypt.crypto.params.ParametersWithIV; |
13 | 13 |
14 version (UnitTest) { | 14 version (UnitTest) { |
15 import dcrypt.crypto.ciphers.XTEA; | 15 import dcrypt.crypto.ciphers.XTEA; |
16 import dcrypt.misc.Util; | 16 import dcrypt.misc.ByteConverter; |
17 } | 17 } |
18 | 18 |
19 /** This class implements the cipher block chaining (CBC) block mode. */ | 19 /** This class implements the cipher block chaining (CBC) block mode. */ |
20 class CBC : BlockCipher { | 20 class CBC : BlockCipher { |
21 private BlockCipher m_cipher; | 21 private BlockCipher wrappedCipher; |
22 private ubyte[] iv, | 22 private ubyte[] iv, |
23 previousCiphertext, | 23 previousCiphertext, |
24 cbcOutput; | 24 cbcOutput; |
25 private bool encrypt, | 25 private bool encrypt, |
26 initialized; | 26 initialized; |
28 /** | 28 /** |
29 * Params: | 29 * Params: |
30 * cipher = Block cipher to wrap. | 30 * cipher = Block cipher to wrap. |
31 */ | 31 */ |
32 this (BlockCipher cipher) { | 32 this (BlockCipher cipher) { |
33 m_cipher = cipher; | 33 wrappedCipher = cipher; |
34 } | 34 } |
35 | 35 |
36 /** Returns: The underlying cipher we are wrapping. */ | 36 /** Returns: The underlying cipher we are wrapping. */ |
37 BlockCipher cipher() { | 37 BlockCipher cipher() { |
38 return m_cipher; | 38 return wrappedCipher; |
39 } | 39 } |
40 | 40 |
41 char[] name() { | 41 char[] name() { |
42 return m_cipher.name~"/CBC"; | 42 return wrappedCipher.name~"/CBC"; |
43 } | 43 } |
44 | 44 |
45 /** | 45 /** |
46 * Throws: dcrypt.crypto.errors.InvalidParameterError if params aren't | 46 * Throws: dcrypt.crypto.errors.InvalidParameterError if params aren't |
47 * an instance of dcrypt.crypto.params.ParametersWithIV. | 47 * an instance of dcrypt.crypto.params.ParametersWithIV. |
48 */ | 48 */ |
49 void init(bool encrypt, CipherParameters params) { | 49 void init(bool encrypt, CipherParameters params) { |
50 ParametersWithIV ivParams = cast(ParametersWithIV)params; | 50 ParametersWithIV ivParams = cast(ParametersWithIV)params; |
51 | 51 |
52 if (!ivParams) | 52 if (!ivParams) |
55 if (ivParams.iv.length != blockSize) | 55 if (ivParams.iv.length != blockSize) |
56 throw new InvalidParameterError( | 56 throw new InvalidParameterError( |
57 name()~": IV must be same length as cipher block size"); | 57 name()~": IV must be same length as cipher block size"); |
58 | 58 |
59 this.encrypt = encrypt; | 59 this.encrypt = encrypt; |
60 m_cipher.init(encrypt, ivParams.parameters); | 60 wrappedCipher.init(encrypt, ivParams.parameters); |
61 | 61 |
62 iv = ivParams.iv[0..blockSize]; | 62 iv = ivParams.iv[0..blockSize]; |
63 previousCiphertext = new ubyte[blockSize]; | 63 previousCiphertext = new ubyte[blockSize]; |
64 previousCiphertext[] = iv; // C_0 = IV | 64 previousCiphertext[] = iv; // C_0 = IV |
65 cbcOutput = new ubyte[blockSize]; // Output buffer for E_k/D_k(...) | 65 cbcOutput = new ubyte[blockSize]; // Output buffer for E_k/D_k(...) |
85 // P_i XOR C_i-1 | 85 // P_i XOR C_i-1 |
86 for (int i = 0; i < blockSize; i++) | 86 for (int i = 0; i < blockSize; i++) |
87 previousCiphertext[i] ^= input[i]; | 87 previousCiphertext[i] ^= input[i]; |
88 | 88 |
89 // E_k(P_i XOR C_i-1) | 89 // E_k(P_i XOR C_i-1) |
90 m_cipher.update(previousCiphertext, cbcOutput); | 90 wrappedCipher.update(previousCiphertext, cbcOutput); |
91 | 91 |
92 // Store C_i for next block | 92 // Store C_i for next block |
93 previousCiphertext[] = cbcOutput; | 93 previousCiphertext[] = cbcOutput; |
94 | 94 |
95 // C_i = E_k(P_i XOR C_i-1) | 95 // C_i = E_k(P_i XOR C_i-1) |
97 } else { | 97 } else { |
98 // Temporarily store C_i | 98 // Temporarily store C_i |
99 ubyte[] t = input[0..blockSize]; | 99 ubyte[] t = input[0..blockSize]; |
100 | 100 |
101 // D_k(C_i) | 101 // D_k(C_i) |
102 m_cipher.update(t, cbcOutput); | 102 wrappedCipher.update(t, cbcOutput); |
103 | 103 |
104 // P_i = D_k(C_i) XOR C_i-1 | 104 // P_i = D_k(C_i) XOR C_i-1 |
105 for (int i = 0; i < blockSize; i++) | 105 for (int i = 0; i < blockSize; i++) |
106 output[i] = (cbcOutput[i] ^ previousCiphertext[i]); | 106 output[i] = (cbcOutput[i] ^ previousCiphertext[i]); |
107 | 107 |
111 | 111 |
112 return blockSize; | 112 return blockSize; |
113 } | 113 } |
114 | 114 |
115 uint blockSize() { | 115 uint blockSize() { |
116 return m_cipher.blockSize; | 116 return wrappedCipher.blockSize; |
117 } | 117 } |
118 | 118 |
119 void reset() { | 119 void reset() { |
120 previousCiphertext[] = iv; | 120 previousCiphertext[] = iv; |
121 m_cipher.reset(); | 121 wrappedCipher.reset(); |
122 } | 122 } |
123 | 123 |
124 /** Test vectors for CBC mode. Assumes XTEA passes test vectors. */ | 124 /** Test vectors for CBC mode. Assumes XTEA passes test vectors. */ |
125 version (UnitTest) { | 125 version (UnitTest) { |
126 unittest { | 126 unittest { |
156 CBC c = new CBC(x); | 156 CBC c = new CBC(x); |
157 ubyte[] iv = new ubyte[x.blockSize], // Initialized to 0 | 157 ubyte[] iv = new ubyte[x.blockSize], // Initialized to 0 |
158 buffer = new ubyte[32]; | 158 buffer = new ubyte[32]; |
159 char[] result; | 159 char[] result; |
160 for (int i = 0; i < test_keys.length; i++) { | 160 for (int i = 0; i < test_keys.length; i++) { |
161 SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_keys[i])); | 161 SymmetricKey key = new SymmetricKey(ByteConverter.hexDecode(test_keys[i])); |
162 ParametersWithIV params = new ParametersWithIV(key, iv); | 162 ParametersWithIV params = new ParametersWithIV(key, iv); |
163 | 163 |
164 // Encryption | 164 // Encryption |
165 c.init(true, params); | 165 c.init(true, params); |
166 for (int j = 0; j < 32; j+=x.blockSize) | 166 for (int j = 0; j < 32; j+=x.blockSize) |
167 c.update(Util.hexToUbytes(test_plaintexts[i])[j..j+x.blockSize], buffer[j..j+x.blockSize]); | 167 c.update(ByteConverter.hexDecode(test_plaintexts[i])[j..j+x.blockSize], buffer[j..j+x.blockSize]); |
168 result = Util.ubytesToHex(buffer); | 168 result = ByteConverter.hexEncode(buffer); |
169 assert(result == test_ciphertexts[i], | 169 assert(result == test_ciphertexts[i], |
170 c.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); | 170 c.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); |
171 | 171 |
172 // Decryption | 172 // Decryption |
173 c.init(false, params); | 173 c.init(false, params); |
174 for (int j = 0; j < 32; j+=x.blockSize) | 174 for (int j = 0; j < 32; j+=x.blockSize) |
175 c.update(Util.hexToUbytes(test_ciphertexts[i])[j..j+x.blockSize], buffer[j..j+x.blockSize]); | 175 c.update(ByteConverter.hexDecode(test_ciphertexts[i])[j..j+x.blockSize], buffer[j..j+x.blockSize]); |
176 result = Util.ubytesToHex(buffer); | 176 result = ByteConverter.hexEncode(buffer); |
177 assert(result == test_plaintexts[i], | 177 assert(result == test_plaintexts[i], |
178 c.name()~": ("~result~") != ("~test_plaintexts[i]~")"); | 178 c.name()~": ("~result~") != ("~test_plaintexts[i]~")"); |
179 } | 179 } |
180 } | 180 } |
181 } | 181 } |