Mercurial > projects > dcrypt
annotate dcrypt/crypto/ciphers/TEA.d @ 1:483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Tue, 12 Aug 2008 05:48:06 -0400 |
parents | 0e08791a1418 |
children | 71aae178f89a |
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.ciphers.TEA; | |
10 | |
11 import dcrypt.misc.Util; | |
12 import dcrypt.crypto.BlockCipher; | |
13 | |
14 /** Implementation of the TEA cipher designed by | |
15 David Wheeler and Roger Needham. */ | |
16 class TEA : BlockCipher { | |
1
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
17 private { |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
18 const uint ROUNDS = 32, |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
19 KEY_SIZE = 16, |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
20 BLOCK_SIZE = 8, |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
21 DELTA = 0x9e3779b9, |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
22 DECRYPT_SUM = 0xc6ef3720; |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
23 uint sk0, sk1, sk2, sk3, sum; |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
24 bool initialized, |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
25 encrypt; |
483e4467b5f6
Added Blowfish with test vectors. Minor cleanup of other cipher classes (should probably clean more). Continued work on high-level cipher API (didn't get very far).
Thomas Dixon <reikon@reikon.us>
parents:
0
diff
changeset
|
26 } |
0 | 27 |
28 void reset(){} | |
29 | |
30 char[] name() { | |
31 return "TEA"; | |
32 } | |
33 | |
34 uint blockSize() { | |
35 return BLOCK_SIZE; | |
36 } | |
37 | |
38 void init(bool encrypt, CipherParameters params) { | |
39 SymmetricKey keyParams = cast(SymmetricKey)params; | |
40 if (!keyParams) | |
41 throw new InvalidParameterError( | |
42 name()~": Invalid parameter passed to init"); | |
43 this.encrypt = encrypt; | |
44 | |
45 if (keyParams.key.length != KEY_SIZE) | |
46 throw new InvalidKeyError( | |
47 name()~": Invalid key length (requires 16 bytes)"); | |
48 | |
49 sk0 = Util.ubytesToUintBig(keyParams.key, 0); | |
50 sk1 = Util.ubytesToUintBig(keyParams.key, 4); | |
51 sk2 = Util.ubytesToUintBig(keyParams.key, 8); | |
52 sk3 = Util.ubytesToUintBig(keyParams.key, 12); | |
53 | |
54 initialized = true; | |
55 } | |
56 | |
57 uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) { | |
58 if (!initialized) | |
59 throw new NotInitializedError(name()~": Cipher not initialized"); | |
60 | |
61 ubyte[] input = cast(ubyte[]) input_; | |
62 ubyte[] output = cast(ubyte[]) output_; | |
63 | |
64 if ((inOff + BLOCK_SIZE) > input.length) | |
65 throw new ShortBufferError(name()~": Input buffer too short"); | |
66 | |
67 if ((outOff + BLOCK_SIZE) > output.length) | |
68 throw new ShortBufferError(name()~": Output buffer too short"); | |
69 | |
70 uint v0 = Util.ubytesToUintBig(input, inOff), | |
71 v1 = Util.ubytesToUintBig(input, inOff+4); | |
72 | |
73 sum = encrypt ? 0 : DECRYPT_SUM; | |
74 for (int i = 0; i < ROUNDS; i++) { | |
75 if (encrypt) { | |
76 sum += DELTA; | |
77 v0 += ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1); | |
78 v1 += ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3); | |
79 } else { | |
80 v1 -= ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3); | |
81 v0 -= ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1); | |
82 sum -= DELTA; | |
83 } | |
84 } | |
85 | |
86 Util.uintToUbytesBig(v0, output, outOff); | |
87 Util.uintToUbytesBig(v1, output, outOff+4); | |
88 | |
89 return BLOCK_SIZE; | |
90 } | |
91 | |
92 /** Some TEA test vectors. */ | |
93 unittest { | |
94 static const char[][] test_keys = [ | |
95 "00000000000000000000000000000000", | |
96 "00000000000000000000000000000000", | |
97 "0123456712345678234567893456789a", | |
98 "0123456712345678234567893456789a" | |
99 ]; | |
100 | |
101 static const char[][] test_plaintexts = [ | |
102 "0000000000000000", | |
103 "0102030405060708", | |
104 "0000000000000000", | |
105 "0102030405060708" | |
106 ]; | |
107 | |
108 static const char[][] test_ciphertexts = [ | |
109 "41ea3a0a94baa940", | |
110 "6a2f9cf3fccf3c55", | |
111 "34e943b0900f5dcb", | |
112 "773dc179878a81c0" | |
113 ]; | |
114 | |
115 | |
116 TEA t = new TEA(); | |
117 foreach (uint i, char[] test_key; test_keys) { | |
118 ubyte[] buffer = new ubyte[t.blockSize]; | |
119 char[] result; | |
120 SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key)); | |
121 | |
122 // Encryption | |
123 t.init(true, key); | |
124 t.processBlock(Util.hexToUbytes(test_plaintexts[i]), 0, buffer, 0); | |
125 result = Util.ubytesToHex(buffer); | |
126 assert(result == test_ciphertexts[i], | |
127 t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); | |
128 | |
129 // Decryption | |
130 t.init(false, key); | |
131 t.processBlock(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer, 0); | |
132 result = Util.ubytesToHex(buffer); | |
133 assert(result == test_plaintexts[i], | |
134 t.name()~": ("~result~") != ("~test_ciphertexts[i]~")"); | |
135 } | |
136 } | |
137 } |