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 {
|
|
17 private const uint ROUNDS = 32,
|
|
18 KEY_SIZE = 16,
|
|
19 BLOCK_SIZE = 8,
|
|
20 DELTA = 0x9e3779b9,
|
|
21 DECRYPT_SUM = 0xc6ef3720;
|
|
22 private uint sk0, sk1, sk2, sk3, sum;
|
|
23 private bool initialized,
|
|
24 encrypt;
|
|
25
|
|
26 void reset(){}
|
|
27
|
|
28 char[] name() {
|
|
29 return "TEA";
|
|
30 }
|
|
31
|
|
32 uint blockSize() {
|
|
33 return BLOCK_SIZE;
|
|
34 }
|
|
35
|
|
36 void init(bool encrypt, CipherParameters params) {
|
|
37 SymmetricKey keyParams = cast(SymmetricKey)params;
|
|
38 if (!keyParams)
|
|
39 throw new InvalidParameterError(
|
|
40 name()~": Invalid parameter passed to init");
|
|
41 this.encrypt = encrypt;
|
|
42
|
|
43 if (keyParams.key.length != KEY_SIZE)
|
|
44 throw new InvalidKeyError(
|
|
45 name()~": Invalid key length (requires 16 bytes)");
|
|
46
|
|
47 sk0 = Util.ubytesToUintBig(keyParams.key, 0);
|
|
48 sk1 = Util.ubytesToUintBig(keyParams.key, 4);
|
|
49 sk2 = Util.ubytesToUintBig(keyParams.key, 8);
|
|
50 sk3 = Util.ubytesToUintBig(keyParams.key, 12);
|
|
51
|
|
52 initialized = true;
|
|
53 }
|
|
54
|
|
55 uint processBlock(void[] input_, uint inOff, void[] output_, uint outOff) {
|
|
56 if (!initialized)
|
|
57 throw new NotInitializedError(name()~": Cipher not initialized");
|
|
58
|
|
59 ubyte[] input = cast(ubyte[]) input_;
|
|
60 ubyte[] output = cast(ubyte[]) output_;
|
|
61
|
|
62 if ((inOff + BLOCK_SIZE) > input.length)
|
|
63 throw new ShortBufferError(name()~": Input buffer too short");
|
|
64
|
|
65 if ((outOff + BLOCK_SIZE) > output.length)
|
|
66 throw new ShortBufferError(name()~": Output buffer too short");
|
|
67
|
|
68 uint v0 = Util.ubytesToUintBig(input, inOff),
|
|
69 v1 = Util.ubytesToUintBig(input, inOff+4);
|
|
70
|
|
71 sum = encrypt ? 0 : DECRYPT_SUM;
|
|
72 for (int i = 0; i < ROUNDS; i++) {
|
|
73 if (encrypt) {
|
|
74 sum += DELTA;
|
|
75 v0 += ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1);
|
|
76 v1 += ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3);
|
|
77 } else {
|
|
78 v1 -= ((v0 << 4) + sk2) ^ (v0 + sum) ^ ((v0 >> 5) + sk3);
|
|
79 v0 -= ((v1 << 4) + sk0) ^ (v1 + sum) ^ ((v1 >> 5) + sk1);
|
|
80 sum -= DELTA;
|
|
81 }
|
|
82 }
|
|
83
|
|
84 Util.uintToUbytesBig(v0, output, outOff);
|
|
85 Util.uintToUbytesBig(v1, output, outOff+4);
|
|
86
|
|
87 return BLOCK_SIZE;
|
|
88 }
|
|
89
|
|
90 /** Some TEA test vectors. */
|
|
91 unittest {
|
|
92 static const char[][] test_keys = [
|
|
93 "00000000000000000000000000000000",
|
|
94 "00000000000000000000000000000000",
|
|
95 "0123456712345678234567893456789a",
|
|
96 "0123456712345678234567893456789a"
|
|
97 ];
|
|
98
|
|
99 static const char[][] test_plaintexts = [
|
|
100 "0000000000000000",
|
|
101 "0102030405060708",
|
|
102 "0000000000000000",
|
|
103 "0102030405060708"
|
|
104 ];
|
|
105
|
|
106 static const char[][] test_ciphertexts = [
|
|
107 "41ea3a0a94baa940",
|
|
108 "6a2f9cf3fccf3c55",
|
|
109 "34e943b0900f5dcb",
|
|
110 "773dc179878a81c0"
|
|
111 ];
|
|
112
|
|
113
|
|
114 TEA t = new TEA();
|
|
115 foreach (uint i, char[] test_key; test_keys) {
|
|
116 ubyte[] buffer = new ubyte[t.blockSize];
|
|
117 char[] result;
|
|
118 SymmetricKey key = new SymmetricKey(Util.hexToUbytes(test_key));
|
|
119
|
|
120 // Encryption
|
|
121 t.init(true, key);
|
|
122 t.processBlock(Util.hexToUbytes(test_plaintexts[i]), 0, buffer, 0);
|
|
123 result = Util.ubytesToHex(buffer);
|
|
124 assert(result == test_ciphertexts[i],
|
|
125 t.name()~": ("~result~") != ("~test_ciphertexts[i]~")");
|
|
126
|
|
127 // Decryption
|
|
128 t.init(false, key);
|
|
129 t.processBlock(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer, 0);
|
|
130 result = Util.ubytesToHex(buffer);
|
|
131 assert(result == test_plaintexts[i],
|
|
132 t.name()~": ("~result~") != ("~test_ciphertexts[i]~")");
|
|
133 }
|
|
134 }
|
|
135 }
|