1 /** 2 * Noekeon 3 * 4 * Copyright: 5 * (C) 1999-2008 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.noekeon; 12 13 import botan.constants; 14 static if (BOTAN_HAS_NOEKEON): 15 16 import botan.block.block_cipher; 17 import botan.utils.loadstor; 18 import botan.utils.rotate; 19 import botan.utils.mem_ops; 20 21 /** 22 * Noekeon 23 */ 24 class Noekeon : BlockCipherFixedParams!(16, 16), BlockCipher, SymmetricAlgorithm 25 { 26 public: 27 /* 28 * Noekeon Encryption 29 */ 30 override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks) 31 { 32 foreach (size_t i; 0 .. blocks) 33 { 34 uint A0 = loadBigEndian!uint(input, 0); 35 uint A1 = loadBigEndian!uint(input, 1); 36 uint A2 = loadBigEndian!uint(input, 2); 37 uint A3 = loadBigEndian!uint(input, 3); 38 39 foreach (size_t j; 0 .. 16) 40 { 41 A0 ^= m_RC[j]; 42 theta(A0, A1, A2, A3, m_EK.ptr[0 .. 4]); 43 44 A1 = rotateLeft(A1, 1); 45 A2 = rotateLeft(A2, 5); 46 A3 = rotateLeft(A3, 2); 47 48 gamma(A0, A1, A2, A3); 49 50 A1 = rotateRight(A1, 1); 51 A2 = rotateRight(A2, 5); 52 A3 = rotateRight(A3, 2); 53 } 54 55 A0 ^= m_RC[16]; 56 theta(A0, A1, A2, A3, m_EK.ptr[0 .. 4]); 57 58 storeBigEndian(output, A0, A1, A2, A3); 59 60 input += BLOCK_SIZE; 61 output += BLOCK_SIZE; 62 } 63 } 64 65 /* 66 * Noekeon Encryption 67 */ 68 override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks) 69 { 70 foreach (size_t i; 0 .. blocks) 71 { 72 uint A0 = loadBigEndian!uint(input, 0); 73 uint A1 = loadBigEndian!uint(input, 1); 74 uint A2 = loadBigEndian!uint(input, 2); 75 uint A3 = loadBigEndian!uint(input, 3); 76 77 for (size_t j = 16; j != 0; --j) 78 { 79 theta(A0, A1, A2, A3, m_DK.ptr[0 .. 4]); 80 A0 ^= m_RC[j]; 81 82 A1 = rotateLeft(A1, 1); 83 A2 = rotateLeft(A2, 5); 84 A3 = rotateLeft(A3, 2); 85 86 gamma(A0, A1, A2, A3); 87 88 A1 = rotateRight(A1, 1); 89 A2 = rotateRight(A2, 5); 90 A3 = rotateRight(A3, 2); 91 } 92 93 theta(A0, A1, A2, A3, m_DK.ptr[0 .. 4]); 94 A0 ^= m_RC[0]; 95 96 storeBigEndian(output, A0, A1, A2, A3); 97 98 input += BLOCK_SIZE; 99 output += BLOCK_SIZE; 100 } 101 } 102 103 104 /* 105 * Clear memory of sensitive data 106 */ 107 override void clear() 108 { 109 zap(m_EK); 110 zap(m_DK); 111 } 112 113 114 @property string name() const { return "Noekeon"; } 115 override @property size_t parallelism() const { return 1; } 116 override BlockCipher clone() const { return new Noekeon; } 117 override size_t blockSize() const { return super.blockSize(); } 118 override KeyLengthSpecification keySpec() const { return super.keySpec(); } 119 120 protected: 121 /** 122 * The Noekeon round constants 123 */ 124 __gshared immutable ubyte[17] m_RC = [ 125 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 126 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 127 0xD4 ]; 128 129 /** 130 * Returns: const reference to encryption subkeys 131 */ 132 ref const(SecureVector!uint) getEK() const { return m_EK; } 133 134 /** 135 * Returns: const reference to decryption subkeys 136 */ 137 ref const(SecureVector!uint) getDK() const { return m_DK; } 138 139 protected: 140 /* 141 * Noekeon Key Schedule 142 */ 143 override void keySchedule(const(ubyte)* key, size_t) 144 { 145 uint A0 = loadBigEndian!uint(key, 0); 146 uint A1 = loadBigEndian!uint(key, 1); 147 uint A2 = loadBigEndian!uint(key, 2); 148 uint A3 = loadBigEndian!uint(key, 3); 149 150 foreach (size_t i; 0 .. 16) 151 { 152 A0 ^= m_RC[i]; 153 theta(A0, A1, A2, A3); 154 155 A1 = rotateLeft(A1, 1); 156 A2 = rotateLeft(A2, 5); 157 A3 = rotateLeft(A3, 2); 158 159 gamma(A0, A1, A2, A3); 160 161 A1 = rotateRight(A1, 1); 162 A2 = rotateRight(A2, 5); 163 A3 = rotateRight(A3, 2); 164 } 165 166 A0 ^= m_RC[16]; 167 168 m_DK.resize(4); 169 m_DK[0] = A0; 170 m_DK[1] = A1; 171 m_DK[2] = A2; 172 m_DK[3] = A3; 173 174 theta(A0, A1, A2, A3); 175 176 m_EK.resize(4); 177 m_EK[0] = A0; 178 m_EK[1] = A1; 179 m_EK[2] = A2; 180 m_EK[3] = A3; 181 } 182 183 SecureVector!uint m_EK, m_DK; 184 } 185 186 package: 187 188 /* 189 * Noekeon's Theta Operation 190 */ 191 void theta(ref uint A0, ref uint A1, 192 ref uint A2, ref uint A3, 193 in uint[] EK) pure 194 { 195 uint T = A0 ^ A2; 196 T ^= rotateLeft(T, 8) ^ rotateRight(T, 8); 197 A1 ^= T; 198 A3 ^= T; 199 200 A0 ^= EK[0]; 201 A1 ^= EK[1]; 202 A2 ^= EK[2]; 203 A3 ^= EK[3]; 204 205 T = A1 ^ A3; 206 T ^= rotateLeft(T, 8) ^ rotateRight(T, 8); 207 A0 ^= T; 208 A2 ^= T; 209 } 210 211 /* 212 * Theta With Null Key 213 */ 214 void theta(ref uint A0, ref uint A1, 215 ref uint A2, ref uint A3) pure 216 { 217 uint T = A0 ^ A2; 218 T ^= rotateLeft(T, 8) ^ rotateRight(T, 8); 219 A1 ^= T; 220 A3 ^= T; 221 222 T = A1 ^ A3; 223 T ^= rotateLeft(T, 8) ^ rotateRight(T, 8); 224 A0 ^= T; 225 A2 ^= T; 226 } 227 228 /* 229 * Noekeon's Gamma S-Box Layer 230 */ 231 void gamma(ref uint A0, ref uint A1, ref uint A2, ref uint A3) pure 232 { 233 A1 ^= ~A3 & ~A2; 234 A0 ^= A2 & A1; 235 236 uint T = A3; 237 A3 = A0; 238 A0 = T; 239 240 A2 ^= A0 ^ A1 ^ A3; 241 242 A1 ^= ~A3 & ~A2; 243 A0 ^= A2 & A1; 244 }