aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2014-12-29 02:40:08 +0000
committerlloyd <[email protected]>2014-12-29 02:40:08 +0000
commitdfc93a3c8992b067f66ca148ac91c24489f493fc (patch)
treed2af4bc335fc1ceebbaedc75dc7fa2d4f04ff2b4
parent05b6811827fe7f4e107a9339142f6aec56f0f202 (diff)
Add Poly1305, based on poly1305-donna by Andrew Moon.
-rw-r--r--doc/license.rst1
-rw-r--r--doc/relnotes/1_11_12.rst4
-rw-r--r--doc/website/algos.rst1
-rw-r--r--src/lib/engine/core_engine/lookup_mac.cpp22
-rw-r--r--src/lib/mac/poly1305/info.txt9
-rw-r--r--src/lib/mac/poly1305/poly1305.cpp73
-rw-r--r--src/lib/mac/poly1305/poly1305.h48
-rw-r--r--src/lib/mac/poly1305/poly1305_donna.h152
-rw-r--r--src/lib/pubkey/curve25519/info.txt4
-rw-r--r--src/lib/utils/donna128.h (renamed from src/lib/pubkey/curve25519/donna128.h)0
-rw-r--r--src/lib/utils/info.txt1
-rw-r--r--src/tests/data/mac/poly1305.vec323
12 files changed, 626 insertions, 12 deletions
diff --git a/doc/license.rst b/doc/license.rst
index 0bf7226fc..bd33743f2 100644
--- a/doc/license.rst
+++ b/doc/license.rst
@@ -30,6 +30,7 @@ Botan (http://botan.randombit.net/) is distributed under these terms::
2012-2014 Markus Wanner
2013 Joel Low
2014 cryptosource GmbH
+ 2014 Andrew Moon
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/doc/relnotes/1_11_12.rst b/doc/relnotes/1_11_12.rst
index 516f41e81..88ece0477 100644
--- a/doc/relnotes/1_11_12.rst
+++ b/doc/relnotes/1_11_12.rst
@@ -6,8 +6,10 @@ Version 1.11.12, Not Yet Released
encrypting Curve25519 keys under PKCS #8 and including them in
certificates and CRLs have been defined.
+* Add Poly1305, based on the implementation poly1305-donna by
+ Andrew Moon.
+
* When encrypted as PKCS #8 structures, Curve25519 and McEliece
private keys default to using AES-256/GCM instead of AES-256/CBC
* Define OIDs for OCB mode with AES, Serpent and Twofish.
-
diff --git a/doc/website/algos.rst b/doc/website/algos.rst
index 698342af4..d2afbd2ba 100644
--- a/doc/website/algos.rst
+++ b/doc/website/algos.rst
@@ -62,6 +62,7 @@ Authentication Codes
* HMAC
* CMAC (aka OMAC1)
+ * Poly1305
* Obsolete designs CBC-MAC, ANSI X9.19 DES-MAC, and the
protocol-specific SSLv3 authentication code
diff --git a/src/lib/engine/core_engine/lookup_mac.cpp b/src/lib/engine/core_engine/lookup_mac.cpp
index 32275b559..acb8da019 100644
--- a/src/lib/engine/core_engine/lookup_mac.cpp
+++ b/src/lib/engine/core_engine/lookup_mac.cpp
@@ -21,6 +21,10 @@
#include <botan/hmac.h>
#endif
+#if defined(BOTAN_HAS_POLY1305)
+ #include <botan/poly1305.h>
+#endif
+
#if defined(BOTAN_HAS_SSL3_MAC)
#include <botan/ssl3_mac.h>
#endif
@@ -38,10 +42,9 @@ MessageAuthenticationCode*
Core_Engine::find_mac(const SCAN_Name& request,
Algorithm_Factory& af) const
{
-
-#if defined(BOTAN_HAS_CBC_MAC)
- if(request.algo_name() == "CBC-MAC" && request.arg_count() == 1)
- return new CBC_MAC(af.make_block_cipher(request.arg(0)));
+#if defined(BOTAN_HAS_HMAC)
+ if(request.algo_name() == "HMAC" && request.arg_count() == 1)
+ return new HMAC(af.make_hash_function(request.arg(0)));
#endif
#if defined(BOTAN_HAS_CMAC)
@@ -49,9 +52,14 @@ Core_Engine::find_mac(const SCAN_Name& request,
return new CMAC(af.make_block_cipher(request.arg(0)));
#endif
-#if defined(BOTAN_HAS_HMAC)
- if(request.algo_name() == "HMAC" && request.arg_count() == 1)
- return new HMAC(af.make_hash_function(request.arg(0)));
+#if defined(BOTAN_HAS_POLY1305)
+ if(request.algo_name() == "Poly1305")
+ return new Poly1305;
+#endif
+
+#if defined(BOTAN_HAS_CBC_MAC)
+ if(request.algo_name() == "CBC-MAC" && request.arg_count() == 1)
+ return new CBC_MAC(af.make_block_cipher(request.arg(0)));
#endif
#if defined(BOTAN_HAS_SSL3_MAC)
diff --git a/src/lib/mac/poly1305/info.txt b/src/lib/mac/poly1305/info.txt
new file mode 100644
index 000000000..84491aa41
--- /dev/null
+++ b/src/lib/mac/poly1305/info.txt
@@ -0,0 +1,9 @@
+define POLY1305 20141227
+
+<header:public>
+poly1305.h
+</header:public>
+
+<header:internal>
+poly1305_donna.h
+</header:internal>
diff --git a/src/lib/mac/poly1305/poly1305.cpp b/src/lib/mac/poly1305/poly1305.cpp
new file mode 100644
index 000000000..32ab64d7e
--- /dev/null
+++ b/src/lib/mac/poly1305/poly1305.cpp
@@ -0,0 +1,73 @@
+/*
+* Poly1305
+* (C) 2014 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/poly1305.h>
+#include <botan/internal/poly1305_donna.h>
+
+namespace Botan {
+
+void Poly1305::clear()
+ {
+ zap(m_poly);
+ zap(m_buf);
+ m_buf_pos = 0;
+ }
+
+void Poly1305::key_schedule(const byte key[], size_t key_len)
+ {
+ m_buf_pos = 0;
+ m_buf.resize(16);
+ m_poly.resize(8);
+
+ poly1305_init(m_poly, key);
+ }
+
+void Poly1305::add_data(const byte input[], size_t length)
+ {
+ BOTAN_ASSERT_EQUAL(m_poly.size(), 8, "Initialized");
+
+ if(m_buf_pos)
+ {
+ buffer_insert(m_buf, m_buf_pos, input, length);
+
+ if(m_buf_pos + length >= m_buf.size())
+ {
+ poly1305_blocks(m_poly, &m_buf[0], 1);
+ input += (m_buf.size() - m_buf_pos);
+ length -= (m_buf.size() - m_buf_pos);
+ m_buf_pos = 0;
+ }
+ }
+
+ const size_t full_blocks = length / m_buf.size();
+ const size_t remaining = length % m_buf.size();
+
+ if(full_blocks)
+ poly1305_blocks(m_poly, input, full_blocks);
+
+ buffer_insert(m_buf, m_buf_pos, input + full_blocks * m_buf.size(), remaining);
+ m_buf_pos += remaining;
+ }
+
+void Poly1305::final_result(byte out[])
+ {
+ BOTAN_ASSERT_EQUAL(m_poly.size(), 8, "Initialized");
+
+ if(m_buf_pos != 0)
+ {
+ m_buf[m_buf_pos] = 1;
+ clear_mem(&m_buf[m_buf_pos+1], m_buf.size() - m_buf_pos);
+ poly1305_blocks(m_poly, &m_buf[0], 1, true);
+ }
+
+ poly1305_finish(m_poly, out);
+
+ m_poly.clear();
+ m_buf_pos = 0;
+ }
+
+}
diff --git a/src/lib/mac/poly1305/poly1305.h b/src/lib/mac/poly1305/poly1305.h
new file mode 100644
index 000000000..8334edb03
--- /dev/null
+++ b/src/lib/mac/poly1305/poly1305.h
@@ -0,0 +1,48 @@
+/*
+* Poly1305
+* (C) 2014 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_MAC_POLY1305_H__
+#define BOTAN_MAC_POLY1305_H__
+
+#include <botan/mac.h>
+#include <memory>
+
+namespace Botan {
+
+/**
+* DJB's Poly1305
+* Important note: each key can only be used once
+*/
+class BOTAN_DLL Poly1305 : public MessageAuthenticationCode
+ {
+ public:
+ std::string name() const override { return "Poly1305"; }
+
+ MessageAuthenticationCode* clone() const { return new Poly1305; }
+
+ void clear();
+
+ size_t output_length() const { return 16; }
+
+ Key_Length_Specification key_spec() const
+ {
+ return Key_Length_Specification(32);
+ }
+
+ private:
+ void add_data(const byte[], size_t);
+ void final_result(byte[]);
+ void key_schedule(const byte[], size_t);
+
+ secure_vector<u64bit> m_poly;
+ secure_vector<byte> m_buf;
+ size_t m_buf_pos = 0;
+ };
+
+}
+
+#endif
diff --git a/src/lib/mac/poly1305/poly1305_donna.h b/src/lib/mac/poly1305/poly1305_donna.h
new file mode 100644
index 000000000..f0f3fe387
--- /dev/null
+++ b/src/lib/mac/poly1305/poly1305_donna.h
@@ -0,0 +1,152 @@
+/*
+* Derived from poly1305-donna-64.h by Andrew Moon <[email protected]>
+* in https://github.com/floodyberry/poly1305-donna
+*
+* (C) 2014 Andrew Moon
+* (C) 2014 Jack Lloyd
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_POLY1305_DONNA_H__
+#define BOTAN_POLY1305_DONNA_H__
+
+#include <botan/loadstor.h>
+#include <botan/mul128.h>
+
+#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
+ #include <botan/internal/donna128.h>
+#endif
+
+namespace Botan {
+
+namespace {
+
+#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
+typedef donna128 uint128_t;
+#else
+inline u64bit carry_shift(const uint128_t a, size_t shift)
+ {
+ return static_cast<u64bit>(a >> shift);
+ }
+#endif
+
+void poly1305_init(secure_vector<u64bit>& X, const byte key[32])
+ {
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ const u64bit t0 = load_le<u64bit>(key, 0);
+ const u64bit t1 = load_le<u64bit>(key, 1);
+
+ X[0] = ( t0 ) & 0xffc0fffffff;
+ X[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
+ X[2] = ((t1 >> 24) ) & 0x00ffffffc0f;
+
+ /* h = 0 */
+ X[3] = 0;
+ X[4] = 0;
+ X[5] = 0;
+
+ /* save pad for later */
+ X[6] = load_le<u64bit>(key, 2);
+ X[7] = load_le<u64bit>(key, 3);
+ }
+
+void poly1305_blocks(secure_vector<u64bit>& X, const byte *m, size_t blocks, bool is_final = false)
+ {
+ const u64bit hibit = is_final ? 0 : (static_cast<u64bit>(1) << 40); /* 1 << 128 */
+ //u64bit c;
+
+ const u64bit r0 = X[0];
+ const u64bit r1 = X[1];
+ const u64bit r2 = X[2];
+
+ u64bit h0 = X[3+0];
+ u64bit h1 = X[3+1];
+ u64bit h2 = X[3+2];
+
+ const u64bit s1 = r1 * (5 << 2);
+ const u64bit s2 = r2 * (5 << 2);
+
+ while(blocks--)
+ {
+ /* h += m[i] */
+ const u64bit t0 = load_le<u64bit>(m, 0);
+ const u64bit t1 = load_le<u64bit>(m, 1);
+
+ h0 += (( t0 ) & 0xfffffffffff);
+ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
+ h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit;
+
+ /* h *= r */
+ uint128_t d0 = uint128_t(h0) * r0 + uint128_t(h1) * s2 + uint128_t(h2) * s1;
+ uint128_t d1 = uint128_t(h0) * r1 + uint128_t(h1) * r0 + uint128_t(h2) * s2;
+ uint128_t d2 = uint128_t(h0) * r2 + uint128_t(h1) * r1 + uint128_t(h2) * r0;
+
+ /* (partial) h %= p */
+ u64bit c = carry_shift(d0, 44); h0 = d0 & 0xfffffffffff;
+ d1 += c; c = carry_shift(d1, 44); h1 = d1 & 0xfffffffffff;
+ d2 += c; c = carry_shift(d2, 42); h2 = d2 & 0x3ffffffffff;
+ h0 += c * 5; c = carry_shift(h0, 44); h0 = h0 & 0xfffffffffff;
+ h1 += c;
+
+ m += 16;
+ }
+
+ X[3+0] = h0;
+ X[3+1] = h1;
+ X[3+2] = h2;
+ }
+
+void poly1305_finish(secure_vector<u64bit>& X, byte mac[16])
+ {
+ /* fully carry h */
+ u64bit h0 = X[3+0];
+ u64bit h1 = X[3+1];
+ u64bit h2 = X[3+2];
+
+ u64bit c;
+ c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
+ h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
+ h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += c;
+
+ /* compute h + -p */
+ u64bit g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff;
+ u64bit g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff;
+ u64bit g2 = h2 + c - ((u64bit)1 << 42);
+
+ /* select h if h < p, or h + -p if h >= p */
+ c = (g2 >> ((sizeof(u64bit) * 8) - 1)) - 1;
+ g0 &= c;
+ g1 &= c;
+ g2 &= c;
+ c = ~c;
+ h0 = (h0 & c) | g0;
+ h1 = (h1 & c) | g1;
+ h2 = (h2 & c) | g2;
+
+ /* h = (h + pad) */
+ const u64bit t0 = X[6];
+ const u64bit t1 = X[7];
+
+ h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff;
+
+ /* mac = h % (2^128) */
+ h0 = ((h0 ) | (h1 << 44));
+ h1 = ((h1 >> 20) | (h2 << 24));
+
+ store_le(&mac[0], h0, h1);
+
+ /* zero out the state */
+ zero_mem(&X[0], X.size());
+ }
+
+}
+
+}
+
+#endif
diff --git a/src/lib/pubkey/curve25519/info.txt b/src/lib/pubkey/curve25519/info.txt
index 68c417056..6139dc32f 100644
--- a/src/lib/pubkey/curve25519/info.txt
+++ b/src/lib/pubkey/curve25519/info.txt
@@ -3,7 +3,3 @@ define CURVE_25519 20141227
<header:public>
curve25519.h
</header:public>
-
-<header:internal>
-donna128.h
-</header:internal>
diff --git a/src/lib/pubkey/curve25519/donna128.h b/src/lib/utils/donna128.h
index f2b2d88ea..f2b2d88ea 100644
--- a/src/lib/pubkey/curve25519/donna128.h
+++ b/src/lib/utils/donna128.h
diff --git a/src/lib/utils/info.txt b/src/lib/utils/info.txt
index 9ba51f193..84e1c8740 100644
--- a/src/lib/utils/info.txt
+++ b/src/lib/utils/info.txt
@@ -4,6 +4,7 @@ load_on always
<header:internal>
bit_ops.h
+donna128.h
prefetch.h
rounding.h
semaphore.h
diff --git a/src/tests/data/mac/poly1305.vec b/src/tests/data/mac/poly1305.vec
new file mode 100644
index 000000000..992000292
--- /dev/null
+++ b/src/tests/data/mac/poly1305.vec
@@ -0,0 +1,323 @@
+
+[Poly1305]
+
+# self test included in poly1305-donna
+Key = DDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFC
+In = 797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1
+Out = DDB9DA7DDD5E52792730ED5CDA5F90A4
+
+# onetimeauth test from libsodium
+Key = EEA6A7251C1E72916D11C2CB214D3C252539121D8E234E652D651FA4C8CFF880
+In = 8E993B9F48681273C29650BA32FC76CE48332EA7164D96A4476FB8C531A1186AC0DFC17C98DCE87B4DA7F011EC48C97271D2C20F9B928FE2270D6FB863D51738B48EEEE314A7CC8AB932164548E526AE90224368517ACFEABD6BB3732BC0E9DA99832B61CA01B6DE56244A9E88D5F9B37973F622A43D14A6599B1F654CB45A74E355A5
+Out = F3FFC7703F9400E52A7DFB4B3D3305D9
+
+# draft-agl-tls-chacha20poly1305-04
+
+Key = 746869732069732033322d62797465206b657920666f7220506f6c7931333035
+In = 48656c6c6f20776f726c6421
+Out = a6f745008f81c916a20dcc74eef2b2f0
+
+# draft-irtf-cfrg-chacha20-poly1305-03
+
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Out = 00000000000000000000000000000000
+
+Key = 0000000000000000000000000000000036E5F6B5C5E06070F0EFCA96227A863E
+In = 416E79207375626D697373696F6E20746F20746865204945544620696E74656E6465642062792074686520436F6E7472696275746F7220666F72207075626C69636174696F6E20617320616C6C206F722070617274206F6620616E204945544620496E7465726E65742D4472616674206F722052464320616E6420616E792073746174656D656E74206D6164652077697468696E2074686520636F6E74657874206F6620616E204945544620616374697669747920697320636F6E7369646572656420616E20224945544620436F6E747269627574696F6E222E20537563682073746174656D656E747320696E636C756465206F72616C2073746174656D656E747320696E20494554462073657373696F6E732C2061732077656C6C206173207772697474656E20616E6420656C656374726F6E696320636F6D6D756E69636174696F6E73206D61646520617420616E792074696D65206F7220706C6163652C207768696368206172652061646472657373656420746F
+Out = 36E5F6B5C5E06070F0EFCA96227A863E
+
+Key = 36E5F6B5C5E06070F0EFCA96227A863E00000000000000000000000000000000
+In = 416E79207375626D697373696F6E20746F20746865204945544620696E74656E6465642062792074686520436F6E7472696275746F7220666F72207075626C69636174696F6E20617320616C6C206F722070617274206F6620616E204945544620496E7465726E65742D4472616674206F722052464320616E6420616E792073746174656D656E74206D6164652077697468696E2074686520636F6E74657874206F6620616E204945544620616374697669747920697320636F6E7369646572656420616E20224945544620436F6E747269627574696F6E222E20537563682073746174656D656E747320696E636C756465206F72616C2073746174656D656E747320696E20494554462073657373696F6E732C2061732077656C6C206173207772697474656E20616E6420656C656374726F6E696320636F6D6D756E69636174696F6E73206D61646520617420616E792074696D65206F7220706C6163652C207768696368206172652061646472657373656420746F
+Out = F3477E7CD95417AF89A6B8794C310CF0
+
+Key = 1C9240A5EB55D38AF333888604F6B5F0473917C1402B80099DCA5CBC207075C0
+In = 2754776173206272696C6C69672C20616E642074686520736C6974687920746F7665730A446964206779726520616E642067696D626C6520696E2074686520776162653A0A416C6C206D696D737920776572652074686520626F726F676F7665732C0A416E6420746865206D6F6D65207261746873206F757467726162652E
+Out = 4541669A7EAAEE61E708DC7CBCC5EB62
+
+Key = 0200000000000000000000000000000000000000000000000000000000000000
+In = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+Out = 03000000000000000000000000000000
+
+Key = 02000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+In = 02000000000000000000000000000000
+Out = 03000000000000000000000000000000
+
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+In = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11000000000000000000000000000000
+Out = 05000000000000000000000000000000
+
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+In = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE01010101010101010101010101010101
+Out = 00000000000000000000000000000000
+
+Key = 0200000000000000000000000000000000000000000000000000000000000000
+In = FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+Out = FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+
+Key = 0100000000000000040000000000000000000000000000000000000000000000
+In = E33594D7505E43B900000000000000003394D7505E4379CD01000000000000000000000000000000000000000000000001000000000000000000000000000000
+Out = 14000000000000005500000000000000
+
+Key = 0100000000000000040000000000000000000000000000000000000000000000
+In = E33594D7505E43B900000000000000003394D7505E4379CD010000000000000000000000000000000000000000000000
+Out = 13000000000000000000000000000000
+
+# Randomly generated by libsodium
+
+Key = 9E9D85AAD102FDF3867984CAD7436C36D1A00481C8F19ECE2070271B5D998FD0
+In =
+Out = D1A00481C8F19ECE2070271B5D998FD0
+
+Key = B1DF3FB9EA530109228401A375516AF7337AAA04EBD1F9BB79B0EE97AD6DD946
+In = E9
+Out = 5BC3ACAF241883EFAA11D4554704EF70
+
+Key = 548E3E7495C8DDD028EF42C85BEC26CAF49B402592A25E37D54CD086C742620D
+In = F062
+Out = 4844B6A0345BA7B688D345D4BB90B164
+
+Key = 95C9DDBAF2A0D598517EB8E3869CE1E1DCE86384F8C7B9CE8F2B157DD297469B
+In = D815EC
+Out = C4BC6F4BA5258216624AED8416A23081
+
+Key = FC7B0C21141632AE850B31A9CD0BA1BDCD68689AE88817ECC294AD5F1217395B
+In = 15E0213E
+Out = 67E592B5167E669BE51E6F907AB2795C
+
+Key = A2C48C332C649467416B072DB19F6376EC75BCCDB1CF03C4AD86BA2D1B69D00C
+In = B5ED4BC907
+Out = A96C7AAA30F5F70D4F466CBDCD1F8431
+
+Key = 6B554DA6070086A0D81DA6F3A18B57951DD94959499DFFA5946769E4CFE08420
+In = AA99E9E0635B
+Out = 837AD6CE4A89DBE067817498CC3AA0AA
+
+Key = E86CEC57707D632B7F3CC2257A5D8025C15D723FAB8FACCC8398AA8B5A3FA765
+In = 525030B06AAC7D
+Out = AD406A25FBFF944A474514F5AEA51E38
+
+Key = 8CACA0437F997872FDA55C4E663733EBA37C7C7407D67A0C3DD65B211FDAF5CA
+In = A877A82AE521AA02
+Out = DC35AF493BAB087D16F0C68E027C73B5
+
+Key = 8B9F30F2065CCEB9F763D79F1B6433A058A8F2AF052A4555FDABDC624FF3B0CE
+In = 4F0522E58738DCAD50
+Out = 939C9ADDD0CEB75BD7B82807AFD483D8
+
+Key = E29D977D6439CB90358DBBD2538C8BD48DAA5CD09A0038232CAB61769128ACC5
+In = BEE52800EB0DC6FA3E43
+Out = 4ED9A237B5895EF61FDD100F16C53888
+
+Key = 2995E27B27F510E25F926C0109679605DB8FF757CC83822DEDD9C1F6615FE39D
+In = BAD92754E84F435F3284E6
+Out = 08096723A036D7FB8F15507BB8C0BC43
+
+Key = C81413ADCE932303D367A96AB5485B5CF1C32005AB1B6CCDC921EAEE077ECC1E
+In = 907A005DDDFB330FD9C0CCE9
+Out = 29C1DDD60375E77B69E38B522B32E709
+
+Key = 7C7DF24D60A6A202564BF3124DCB06137A7FF53B1864E43E2E7B73FF2209B9B7
+In = 4DB2DE834EC7CBBD042D9581A5
+Out = 5BE481E149F955C65BEA350A4DAD4C21
+
+Key = 1C20C733E41854683EBBC49A085E47704073359BDF26C24817DBD855DAD2FD76
+In = 47FE8BFF7501E52AC14FCC687384
+Out = 4A650D205CE287CB8C9BE568C4A451A3
+
+Key = 079810FD6F1AD87D7A2E1A9D72C55249A8CFA875B41FA14568EF9741E6A769BF
+In = 5B5EAB1283967770542A7A57702A93
+Out = BF159EA2671A07302FE2D6B5A5F40E75
+
+Key = 828C4B03687DE973E34AC6FA5CF01699EB658EC84F3DCE60BAB5A35AA7D2585E
+In = 3EC00AAE4DFA8952BCBA685521D9872A
+Out = 359138B3E5E097BF48694AF31DBD915F
+
+Key = 73DCAC8AFDE03315932C4B6F032ECB86901D1A401DB20E45334A52967FB6A5A1
+In = DA71371BDA6B96B51D361660F7E2221A0A
+Out = CAF6EF581BEBF03C00D33917EDED3E00
+
+Key = 7FDE7001E3FB22D673FDFC2E6138F7E2C2409537B95C04C8FA6C8097E3880BF2
+In = 2826E1BD0C643140C2A750E1F4E08E9CBB35
+Out = 8734CDA02BE02553D41455C99971711C
+
+Key = CED5B7D685752522B80233F4F47262E5C1E1709C30F8E9415EA20AB1F7DA1D6F
+In = A03B1F880AB72B0F12C22BC837F1DAE38FBA9E
+Out = 9D0DCF5BBF90DE436BCC864FCB43DEBF
+
+Key = F5403228FA8A9879A3C8288319072C62A70F1605CB0C36F7612DD131AAE59C55
+In = 592C0D0BBD2CF2225EAB8912CDE12F9752F0E217
+Out = F88A11292AE0CF5854C626E6B079EB84
+
+Key = B5CD17608F894FB90A014144F9677FDC490CCD20059FD3F99B569ED9B51D3B4F
+In = 2063CDFD23683718F0994B3E2F6789A443DF0E447B
+Out = 6E5E516FA39CD06B3E901ADE57FC8C08
+
+Key = CF04CB06DE7AF28D2A9E022034389509FD2EF5168FA40D6F29D500A287BD647F
+In = DE69747C2ED30A5B69567B528604BC968AFBC546CC90
+Out = 1186387E982661E6F80A5D38D4C63D4C
+
+Key = 8642E25ABA2FEBC3F8D7F1E7737D7CB55CB5991E6933CD7E1AFB4F68A046944C
+In = ABD9F8E04CD681D50A679877B2EDBDA1A0A376EBECE6E0
+Out = E2843F3D16E7666EFB8EC48E6C507657
+
+Key = 32029CBC18697477DDBB910A9494868DEEB0315D25A49F76BB43544B2F83B941
+In = 9E354F70B52AECB086DF664825C039824ABD6A0F9A7C7FCB
+Out = 0194DB1F13222163729A8F0ED84DE466
+
+Key = BA34D5CEED7A4F134CCADEAABF1C42B37AE8B1334B78B789DD29A989B50E029D
+In = BBB666E23FD40458BA38D06A5DCC388BA103BC6D04095A7AA6
+Out = 9356DF51E8E76D5466F509EA513112AA
+
+Key = 158CD22AB957A0F9F977353BD9C83B688D51088DDEAF847BE81468EC345EA443
+In = 3E820F3AE6EA6EF9C59D7B527BDB76C5EFD65E76B3E3B93C9EF5
+Out = A3EBE4E930B3EB5B7A3E475B84A29F45
+
+Key = 59E4BBD352419AE4E5819240A0033A301CC3AC86187426053B69F572E83F2470
+In = 9655D7D3D6C74F9A0C9502C9EC7FC22F4710BDC7A0AA0BAB35C929
+Out = 13B6F916539A5D06DBE3F801DE8D83C1
+
+Key = F868AEE434D463FB1635F209481D60815A03869198B95141F89C1485CA969730
+In = 612E7057B89390E7FA920111D2F61598D3769568E1F2675B3D13C01E
+Out = 835C1C8745B16B5AD0168C646C99EEF0
+
+Key = 325AC69BA9B00B0609E3DD12DB3D75681F43A398EEC2C92C9E99A440440A1E4C
+In = D8AE537E24503E12405BC80DD4ECE2D48C90CA74DCFD90E87C2E756EC4
+Out = 5549B4C997557CAF14DC198869C76CA8
+
+Key = EB63EABF1FC590A086E7C8AD25F2A4BFFD4AB6016EBE9D274B630353A162234B
+In = 0E2934DC1FB134A1C1CF6EDAB1D0E24423E4A39538822EA2D9B94931BD23
+Out = B07A079761EB76679343540A3F75CBDF
+
+Key = DE07129A2B4C79FB8789D4A9564BA185A2F1F4C674ECCFEB19D0940D64CC2DD1
+In = FB01B7D9D4B46307AFF6E4DC19A211969D479D2496433B8A4B5C1B7BE2F6B9
+Out = 4E412BD481F219BB9D88B636AFC0E1D6
+
+Key = 344579DD843D176804888F814E4FCB11D7D41FBB4E157E0E71DAAF5AE49FC1DA
+In = D1632FBFF20101520A1B7BB071BD9089E23435633B180941F4A4F00A127EC3B8
+Out = A24F40C6F63E7FEE5458D86FCD0C340D
+
+Key = D29B469F0E5067BFC7597B3415B5D3EB2F55388707446A614C8233EE1AC7A052
+In = 26B5CCE0A1A1722360E0C99D65EBC49CB253536177F5F95B42BF462B7C82947B29
+Out = 24A91FAC5D4BECB46307EEED954ED011
+
+Key = C5824C96352B4639AF1172BF019C93FB5507EE82815764022C89EE001ACF3A14
+In = 59F890D5F008B064D8CB8A491522A944CFEB1846521B39AAE9E198B1F7B07171BFA9
+Out = E9A211BB3F2B0A11445C5D06378309AB
+
+Key = 884DB7C6C2D254824A7E514D29829FB5580D77B948CEE0377D1218E674849660
+In = 25822916523687B1A68E51C55C97A56DF6893B5E2716B7F2A1483138D4D45CA7DE813F
+Out = 53FA73CF055F7A21521F8D4F33915A88
+
+Key = 229222BE1B32557A5741EF3182FCFDFB63A6550BAA9892EFD3DDBD67608229A7
+In = 8E8B1188CF23A77C89D474F001373B52F9A6FB76F40B28FD83345E7673812B985BD558BE
+Out = C659279CDCBD804F889877137449DF73
+
+Key = C3C747651BA5B9975B87ED7EAFFC023569662970558BDD2992774D4F721449E6
+In = CE8ABB5B6AFA5614C682608B7F6D1374DC282EF0E033542B5BF2C4C3B2AD02CABE5C13EAF7
+Out = E746A81205ED30C8A1872D5E81516B05
+
+Key = 4ECFD1C9A89F2F5CDB6C2A99C2A8AA6A7E5DD7184B87E265D68BCDA15D1040CE
+In = E6484C98EF43276B36182B8E4B9BAA058330E192E2FE0B0AEC0AEBE64A6BDC2AA4A8CD65B10A
+Out = 2564EE67D9C00EF3248F3239378E25AE
+
+Key = D6B7BCC368DA611151F58A58096DA802FE64DFE9D18BD8A8D8FB97157EE96099
+In = CA460B21E0D3BCA60B56667B12D3C42D4F525D6DBDD37F8E14DD7B201AA03CE2E69DD4C5FCD283
+Out = F5F74E3FDAA14CC0426C89C999BA2E30
+
+Key = A63CB4A43CE1EDEF181D1BD339E9DFD9DD7667BC9E5B642DFDF26E7E6DE4BA8D
+In = F40FC0763C321E2F668DAFEC1422A399405629E5D1C9B80C5C1DD5D8DF7643475D13E79BADF451C6
+Out = CF5E17C8890B63A4D3E061A53C51E9FD
+
+Key = 040F48958744F1E8169DB72BB800CF339A4B4CD86BC237180C2E7D279093BA61
+In = 0C7291DAEE8B5EABD8F8373ED30C240474287951D8739BFA9978C252AB2D92C89C3D3730CA9AE15C90
+Out = CD7BE663024A843F0244777FDED633FF
+
+Key = 8F235B87E0B652FB146A4A9E1367FEDC04F009F3807049DDD8AD83D93F2392DD
+In = B58BB0431016BB591040F15C2CDC303214C0E290A802F97077B7F3B0D8B7E4AC83C2662B880837AF550F
+Out = A31889EB51AE63DE762F912D2020BD7D
+
+Key = F149D8929882EBF4457D0579AC795ADEDBF724FC2A4422FC42BD9848A44C6A06
+In = 9549A9797916B7567B011A96D43D7615ECA15BE9DD955ABDC38517033E346C2F52C505021FFE351157C190
+Out = F299FB43775F3EE5101B7D12485E11BE
+
+Key = 3EB6529C93F120190EC3819B5356211F67F224A1CBE1BBE8400EA3F8375506C2
+In = 4E3C135056EF1EDE0B56E67C35B359F8778944A7C060CE3D9A455E31006DAB955194E830FE458E300460967F
+Out = A7E9B419DED98F092AD1034B1A008A9E
+
+Key = CB89B844CD47C422D94F75D7E05EB722C564A924531EEFB8EA39F5CC8154A0FA
+In = 920AB028BDD9F877845E1A8995F5255AF2C6BDB2C5C218E52AC72B58571E81F27AA30EA78C50C85EF504ED056F
+Out = C038DCBDE5CBE58469ADC6491CEEF8CC
+
+Key = DC4667C6574DDC3E949DF0F51DFDED57E1DD4FB9C7F64C93C68EBF223E2180FF
+In = EC3FC04B9B01BC7CEA445E9C5A713C782C083DC75408416BCD071A2D311642DCBA891825E0044DF800E5ED65314A
+Out = 2B9301B71DB683131EEDC55227925F12
+
+Key = 492AB714C763ABB9BAA4FE4311B89277C2926F1BE7105262CB50C80B4B70469C
+In = A9E528BCD43297E7D2F33AC7488DF5EDBEF08AAF8D1994F60098653FF6913138AB3C03262ABFDE8BAAC10033098E7E
+Out = 562BFE9F91BFF7318D44E52BF5E55603
+
+Key = 7C939CA4F592B90C2C65D530983740155A3F1C7C63BA0CD84EEBED1A579D959F
+In = DF99C5E78BDCA6D261F0B8BF5EC7631F572BC2A6C2F734372C35CF9E2F8D812943D23F17BE0636C7FDFCD53C73F79FD2
+Out = 02BA172589E102D0C071129C74F440A9
+
+Key = 7C74F59B91FD56D09A14D318A457517E83656106B6E933E590DA6A2DA1D4B0A1
+In = 75C194EEA5B223358AC7D0920F9451B20318B97A72E63FD711095746BAF5358AAAFD4DEA1F3722688799A5B0685C7E843E
+Out = 351B1117D44D528ADB283F0450C50B25
+
+Key = A78D532E96553A435B44CC54BBB22FB23AA1F4F41C6087C60CC9FFC564C95051
+In = 6D8EE97A667FDF890356C7CC5E69C1EB4EEFF1C11C019D257E2537797A9EB45CC2FCDA4A7536DC0CE929D7C8A0CDB9834677
+Out = AAD5FDF14D229E87816245FB06D9B505
+
+Key = 7D6880EFE74747D0713956B079D74D717358B69772480DC5B9E473D71BE84A94
+In = 410351D27DF685CBD0CFDC166B3F90C0FD4A334BEF5774EF2E59948DC7BD118B4D46B3AEE139EAEB54EA0A267F8D0A2E057933
+Out = 8B4CF9CF2500A25C86FC5AB6B6565AE3
+
+Key = E96CEE991E966AAA662C1C0FB5C15F422A98C5529629826B645BED629192085B
+In = C6551853EC02C8315B6219564C11D319C797FCD9E4528D2700B7A562FC4A0D4DD1DD6D445F13E27EE6373539470A4AB7A9366654
+Out = 4F8D294470CDCBBABA89A246BAEA9014
+
+Key = 9E89E9C49DAF18CD8EED9733AEB53D3804AF2775D61C9A833F65B0E4560C4738
+In = 2AD404004B5589253AA91D392905200B8A28F94AEBE5D45CF674B158004BFC91CC48584E7451FDEE87132B7058EC9E48CDF16F3380
+Out = 3EDA0BB3F660A60E15D90BFAA2E996F2
+
+Key = A3FDA18F925C1588291F26DFB43E1B7D70AF097462F52C276A89095ED7D01685
+In = 933A72A8351DB8367E9F6E63C2A36DCB02801470AB7846308A2DF7925B6D81E50340C22457F6E3A10EBC6D7E205B113B8E5B9C9EB41E
+Out = 20235C71ADA97CB8796D0CF986A7FCB4
+
+Key = EF411C2190426495EF79C6913615E9A6CAC435CC4796C421331DBEF519FEACB9
+In = 54B66666FDCE1754A62C75DBBE40D4380739FA959841DF05F267EDA6C6F9049A9D1E5770E42D237AB8E411FBA613ED55F60A12A26FFEF4
+Out = D551758D4AD5DD0A52DE7CA1424A03D2
+
+Key = 427525D85A907836D5024566719C9373F5684F18CB1F8B4D3F2BF6F0A8B36274
+In = 5D5AE246E9E84F54B4C8015F4FC3AB5C63A3A2F5EA257E7574940F1A3C60C796DF3E0C96B73B3EC3597504F048F7A1437FDB268ED23733F0
+Out = 39351B13A888D194BE63F869B5D0C57B
+
+Key = BB78DD08395D96F18BD71C084FAF26490A492E1345CA8A1190CAA509A13C1A43
+In = E324F0BC28D8C51DAC56087928BB784D613FA00E4E0399D81CF24C6317A28DF48C3A2A35BF2E16E366F9E1DBFD20C01C7B6ABA6C98F72AAF6E
+Out = 1FDC7616DF7809FE775F3694D2166EBC
+
+Key = 325544641FC9E14C344BB0BD42C88540D6B3E8FEB2DAA8AAC4E518952831EEE8
+In = C3708D1969C9D980F1108936055BAC50ED43A3BD7DB246E34FA282F77A0F9D5968D7A1856EDD36CD06D768125ADDD3368E41E025FC689368AE20
+Out = 1935CC6A925E182589CF85BD289E8430
+
+Key = 932FB37709A9DFCD232E5B6FCBCEA06DD384818DDE1BA6A85AE813A054D8437F
+In = 98945E5490056F4C616BA055D5F22F05EC99834F1702057AFBD0B812E95AE669F4E6C0A940318A162EA85FA8DFE0D5F9479C87402A1E9D45649EAD
+Out = 163BA4F137C343172ADAD46BCE7F1CAA
+
+Key = E286704F857F611C6A10FCB650A6974496AAD9A285AC6F65977B11B6E5310B16
+In = 8883CEA30073C555537BEFB1A4CA25B50E71AC313446B6039CA4CF0BFA9074AFB448EFE2B02E124F0C3EB35BFBD878F2C632C8D0AA37D9DA6858554E
+Out = 3C96DB1DB3EBE7260E6527DD93E5B95D
+
+Key = 375B7709A43196D08C8D91406AA82B307C4A7D5CDCBF59118077B69FBDF5A649
+In = 3AD186DC498A3DAB9142AEA55899EC0AB125A0AF010DC71E77C8F9DDA9A65DD7CF4FDC41029465F3998931285D6DCC2C454CF6D5E4F73A224312C343CB
+Out = 3C5D43309DF559415E6E4D2300BFA847
+
+Key = 7B5532DEB4AA9DAF0EDDA3D361FAF33E83B309BF3EF7E88912E00905562049FB
+In = 4FB4B3F34F54C6A1ED4BD8E5AAE61E03E99643DD1EFC996A4579AC88E6702DDA06B66F84054CC3BFCCA6CD3EB67E0569FEB48191398A27C2D605CFD6AA38
+Out = C79753AF74F8E1CC65A48190200E8F94
+
+Key = 3ACC533363DFB5012D00F8F67BF5F16167E9235AB0E7D535D0C2E8E2C0F2FFAA
+In = 66CA0F0DD4D4013C18BB7B51CEE12492706FDCD59DC0927FA9637A3687F1FFE6C15AC64D97FDCD6602AA7CC3B1C7E4D11FC336F4CCF516A4A4710BF41678EC
+Out = 5B00273784949EC5AB564DB7AA54F008
+