/* * Noekeon * (C) 1999-2008 Jack Lloyd * * Distributed under the terms of the Botan license */ #include #include #include namespace Botan { namespace { /* * Noekeon's Theta Operation */ inline void theta(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3, const u32bit EK[4]) { u32bit T = A0 ^ A2; T ^= rotate_left(T, 8) ^ rotate_right(T, 8); A1 ^= T; A3 ^= T; A0 ^= EK[0]; A1 ^= EK[1]; A2 ^= EK[2]; A3 ^= EK[3]; T = A1 ^ A3; T ^= rotate_left(T, 8) ^ rotate_right(T, 8); A0 ^= T; A2 ^= T; } /* * Theta With Null Key */ inline void theta(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3) { u32bit T = A0 ^ A2; T ^= rotate_left(T, 8) ^ rotate_right(T, 8); A1 ^= T; A3 ^= T; T = A1 ^ A3; T ^= rotate_left(T, 8) ^ rotate_right(T, 8); A0 ^= T; A2 ^= T; } /* * Noekeon's Gamma S-Box Layer */ inline void gamma(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3) { A1 ^= ~A3 & ~A2; A0 ^= A2 & A1; u32bit T = A3; A3 = A0; A0 = T; A2 ^= A0 ^ A1 ^ A3; A1 ^= ~A3 & ~A2; A0 ^= A2 & A1; } } /* * Noekeon Round Constants */ const byte Noekeon::RC[] = { 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4 }; /* * Noekeon Encryption */ void Noekeon::encrypt_n(const byte in[], byte out[], u32bit blocks) const { for(u32bit i = 0; i != blocks; ++i) { u32bit A0 = load_be(in, 0); u32bit A1 = load_be(in, 1); u32bit A2 = load_be(in, 2); u32bit A3 = load_be(in, 3); for(u32bit j = 0; j != 16; ++j) { A0 ^= RC[j]; theta(A0, A1, A2, A3, EK); A1 = rotate_left(A1, 1); A2 = rotate_left(A2, 5); A3 = rotate_left(A3, 2); gamma(A0, A1, A2, A3); A1 = rotate_right(A1, 1); A2 = rotate_right(A2, 5); A3 = rotate_right(A3, 2); } A0 ^= RC[16]; theta(A0, A1, A2, A3, EK); store_be(out, A0, A1, A2, A3); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * Noekeon Encryption */ void Noekeon::decrypt_n(const byte in[], byte out[], u32bit blocks) const { for(u32bit i = 0; i != blocks; ++i) { u32bit A0 = load_be(in, 0); u32bit A1 = load_be(in, 1); u32bit A2 = load_be(in, 2); u32bit A3 = load_be(in, 3); for(u32bit j = 16; j != 0; --j) { theta(A0, A1, A2, A3, DK); A0 ^= RC[j]; A1 = rotate_left(A1, 1); A2 = rotate_left(A2, 5); A3 = rotate_left(A3, 2); gamma(A0, A1, A2, A3); A1 = rotate_right(A1, 1); A2 = rotate_right(A2, 5); A3 = rotate_right(A3, 2); } theta(A0, A1, A2, A3, DK); A0 ^= RC[0]; store_be(out, A0, A1, A2, A3); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * Noekeon Key Schedule */ void Noekeon::key_schedule(const byte key[], u32bit) { u32bit A0 = load_be(key, 0); u32bit A1 = load_be(key, 1); u32bit A2 = load_be(key, 2); u32bit A3 = load_be(key, 3); for(u32bit j = 0; j != 16; ++j) { A0 ^= RC[j]; theta(A0, A1, A2, A3); A1 = rotate_left(A1, 1); A2 = rotate_left(A2, 5); A3 = rotate_left(A3, 2); gamma(A0, A1, A2, A3); A1 = rotate_right(A1, 1); A2 = rotate_right(A2, 5); A3 = rotate_right(A3, 2); } A0 ^= RC[16]; DK[0] = A0; DK[1] = A1; DK[2] = A2; DK[3] = A3; theta(A0, A1, A2, A3); EK[0] = A0; EK[1] = A1; EK[2] = A2; EK[3] = A3; } /* * Clear memory of sensitive data */ void Noekeon::clear() throw() { EK.clear(); DK.clear(); } }