diff --git a/Makefile.am b/Makefile.am index 0cab73b8..09433ffe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,8 @@ UTIL_FILES = \ coord/store.hpp \ crypto/tea.cpp \ crypto/tea.hpp \ + crypto/xtea.cpp \ + crypto/xtea.hpp \ crypto/arc4.cpp \ crypto/arc4.hpp \ debug.cpp \ @@ -267,6 +269,7 @@ TEST_BIN = \ test/colour \ test/crypto/arc4 \ test/crypto/tea \ + test/crypto/xtea \ test/extent \ test/fixed \ test/float \ diff --git a/crypto/xtea.cpp b/crypto/xtea.cpp new file mode 100644 index 00000000..1337a627 --- /dev/null +++ b/crypto/xtea.cpp @@ -0,0 +1,89 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2015 Danny Robson + */ + +#include "xtea.hpp" + +using util::crypto::XTEA; + + +/////////////////////////////////////////////////////////////////////////////// +static const uint32_t MAGIC = 0x9E3779B9; + +// each iteration performs two feistel rounds, for a total of 64 +static const unsigned ITERATIONS = 32; + + +/////////////////////////////////////////////////////////////////////////////// +XTEA::XTEA (key_t _key): + m_key (_key) +{ } + + +//----------------------------------------------------------------------------- +void +XTEA::encrypt (uint32_t *restrict dst, const uint32_t *restrict src, size_t count) +{ + if (count % 2) + throw std::invalid_argument ("XTEA requires even data count"); + + auto last = src + count; + + while (src < last) { + uint32_t sum = 0; + uint32_t v0 = src[0]; + uint32_t v1 = src[1]; + + for (unsigned i = 0; i < ITERATIONS; ++i) { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + m_key[sum & 3]); + sum += MAGIC; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + m_key[(sum >> 11) & 3]); + } + + dst[0] = v0; + dst[1] = v1; + + src += 2; + dst += 2; + } +} + + +//----------------------------------------------------------------------------- +void +XTEA::decrypt (uint32_t *restrict dst, const uint32_t *restrict src, size_t count) +{ + if (count % 2) + throw std::invalid_argument ("XTEA requires even data count"); + + auto last = src + count; + + while (src < last) { + uint32_t sum = ITERATIONS * MAGIC; + uint32_t v0 = src[0]; + uint32_t v1 = src[1]; + + for (unsigned i = 0; i < ITERATIONS; ++i) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + m_key[(sum >> 11) & 3]); + sum -= MAGIC; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + m_key[sum & 3]); + } + + dst[0] = v0; + dst[1] = v1; + + src += 2; + } +} diff --git a/crypto/xtea.hpp b/crypto/xtea.hpp new file mode 100644 index 00000000..6670a871 --- /dev/null +++ b/crypto/xtea.hpp @@ -0,0 +1,40 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2015 Danny Robson + */ + +#ifndef __UTIL_TEA_HPP +#define __UTIL_TEA_HPP + +#include +#include +#include + +namespace util { namespace crypto { + // http://en.wikipedia.org/wiki/XTEA + class XTEA { + public: + using key_t = std::array; + + XTEA (key_t); + + void encrypt (uint32_t *restrict dst, const uint32_t *restrict src, size_t count); + void decrypt (uint32_t *restrict dst, const uint32_t *restrict src, size_t count); + + private: + key_t m_key; + }; +} } + +#endif diff --git a/test/crypto/xtea.cpp b/test/crypto/xtea.cpp new file mode 100644 index 00000000..eb0a9bdb --- /dev/null +++ b/test/crypto/xtea.cpp @@ -0,0 +1,65 @@ +#include "tap.hpp" +#include "crypto/xtea.hpp" +#include "types.hpp" + +int +main () +{ + // test vectors from 'TeaCrypt', by Logan J. Drews. + struct { + std::array key; + std::array dec; + std::array enc; + } TESTS[] = { + { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0xDEE9D4D8, 0xF7131ED9}, + }, + + { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x01020304, 0x05060708}, + {0x065C1B89, 0x75C6A816}, + }, + + { + {0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF}, + {0x01020304, 0x05060708}, + {0xDCDD7ACD, 0xC1584B79}, + + }, + + { + {0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF}, + {0x01234567, 0x89ABCDEF}, + {0xB8BF2821, 0x622B5B30}, + }, + }; + + util::TAP::logger tap; + + for (size_t i = 0; i < elems (TESTS); ++i) { + const auto &t = TESTS[i]; + util::crypto::XTEA gen (t.key); + + std::array enc, dec; + + gen.encrypt (enc.data (), t.dec.data (), t.dec.size ()); + gen.decrypt (dec.data (), t.enc.data (), t.enc.size ()); + + { + std::ostringstream os; + os << "TEA_enc " << i; + tap.expect (enc == t.enc, os.str ()); + } + + { + std::ostringstream os; + os << "TEA_dec " << i; + tap.expect (dec == t.dec, os.str ()); + } + } + + return tap.status (); +}