1 /** 2 * XTEA 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.block.xtea; 12 13 import botan.constants; 14 static if (BOTAN_HAS_XTEA): 15 16 import std.range : iota; 17 import botan.block.block_cipher; 18 import botan.utils.loadstor; 19 import botan.utils.mem_ops; 20 21 /** 22 * XTEA 23 */ 24 class XTEA : BlockCipherFixedParams!(8, 16), BlockCipher, SymmetricAlgorithm 25 { 26 public: 27 /* 28 * XTEA Encryption 29 */ 30 override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks) 31 { 32 while (blocks >= 4) 33 { 34 xtea_encrypt_4(*cast(ubyte[32]*) input, *cast(ubyte[32]*) output, *cast(uint[64]*) m_EK.ptr); 35 input += 4 * BLOCK_SIZE; 36 output += 4 * BLOCK_SIZE; 37 blocks -= 4; 38 } 39 40 foreach (size_t i; 0 .. blocks) 41 { 42 uint L = loadBigEndian!uint(input, 0); 43 uint R = loadBigEndian!uint(input, 1); 44 45 foreach (size_t j; 0 .. 32) 46 { 47 L += (((R << 4) ^ (R >> 5)) + R) ^ m_EK[2*j]; 48 R += (((L << 4) ^ (L >> 5)) + L) ^ m_EK[2*j+1]; 49 } 50 51 storeBigEndian(output, L, R); 52 53 input += BLOCK_SIZE; 54 output += BLOCK_SIZE; 55 } 56 } 57 58 /* 59 * XTEA Decryption 60 */ 61 override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks) 62 { 63 while (blocks >= 4) 64 { 65 xtea_decrypt_4(*cast(ubyte[32]*) input, *cast(ubyte[32]*) output, *cast(uint[64]*) m_EK.ptr); 66 input += 4 * BLOCK_SIZE; 67 output += 4 * BLOCK_SIZE; 68 blocks -= 4; 69 } 70 71 foreach (size_t i; 0 .. blocks) 72 { 73 uint L = loadBigEndian!uint(input, 0); 74 uint R = loadBigEndian!uint(input, 1); 75 76 foreach (size_t j; 0 .. 32) 77 { 78 R -= (((L << 4) ^ (L >> 5)) + L) ^ m_EK[63 - 2*j]; 79 L -= (((R << 4) ^ (R >> 5)) + R) ^ m_EK[62 - 2*j]; 80 } 81 82 storeBigEndian(output, L, R); 83 84 input += BLOCK_SIZE; 85 output += BLOCK_SIZE; 86 } 87 } 88 89 override void clear() 90 { 91 zap(m_EK); 92 } 93 94 override @property string name() const { return "XTEA"; } 95 override @property size_t parallelism() const { return 1; } 96 override BlockCipher clone() const { return new XTEA; } 97 override size_t blockSize() const { return super.blockSize(); } 98 override KeyLengthSpecification keySpec() const { return super.keySpec(); } 99 protected: 100 /** 101 * Returns: const reference to the key schedule 102 */ 103 ref const(SecureVector!uint) getEK() const { return m_EK; } 104 105 protected: 106 /* 107 * XTEA Key Schedule 108 */ 109 override void keySchedule(const(ubyte)* key, size_t) 110 { 111 m_EK.resize(64); 112 113 SecureVector!uint UK = SecureVector!uint(4); 114 foreach (size_t i; 0 .. 4) 115 UK[i] = loadBigEndian!uint(key, i); 116 117 uint D = 0; 118 foreach (size_t i; iota(0, 64, 2)) 119 { 120 m_EK[i ] = D + UK[D % 4]; 121 D += 0x9E3779B9; 122 m_EK[i+1] = D + UK[(D >> 11) % 4]; 123 } 124 } 125 126 SecureVector!uint m_EK; 127 } 128 129 package: 130 131 void xtea_encrypt_4(in ubyte[32] input, ref ubyte[32] output, in uint[64] EK) 132 { 133 uint L0, R0, L1, R1, L2, R2, L3, R3; 134 loadBigEndian(input.ptr, L0, R0, L1, R1, L2, R2, L3, R3); 135 136 foreach (size_t i; 0 .. 32) 137 { 138 L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*i]; 139 L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*i]; 140 L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*i]; 141 L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*i]; 142 143 R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*i+1]; 144 R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*i+1]; 145 R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*i+1]; 146 R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*i+1]; 147 } 148 149 storeBigEndian(output.ptr, L0, R0, L1, R1, L2, R2, L3, R3); 150 } 151 152 void xtea_decrypt_4(in ubyte[32] input, ref ubyte[32] output, in uint[64] EK) 153 { 154 uint L0, R0, L1, R1, L2, R2, L3, R3; 155 loadBigEndian(input.ptr, L0, R0, L1, R1, L2, R2, L3, R3); 156 157 foreach (size_t i; 0 .. 32) 158 { 159 R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*i]; 160 R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*i]; 161 R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*i]; 162 R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*i]; 163 164 L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*i]; 165 L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*i]; 166 L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*i]; 167 L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*i]; 168 } 169 170 storeBigEndian(output.ptr, L0, R0, L1, R1, L2, R2, L3, R3); 171 }