diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..69fa449 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +_build/ diff --git a/mitosis-crypto/mitosis-aes-ctr.c b/mitosis-crypto/mitosis-aes-ctr.c new file mode 100644 index 0000000..08388c2 --- /dev/null +++ b/mitosis-crypto/mitosis-aes-ctr.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include "mitosis-aes-ctr.h" + +bool mitosis_aes_ctr_init(const uint8_t* key, const uint8_t* nonce, mitosis_encrypt_context_t* context) +{ + memset(context, 0, sizeof(*context)); + memcpy(context->ctr.key, key, sizeof(context->ctr.key)); + memcpy(context->ctr.iv_bytes, nonce, sizeof(context->ctr.iv_bytes)); + return mitosis_aes_ecb_init(&context->ecb); +} + +static inline +void xor(const uint8_t* left, const uint8_t* right, size_t len, uint8_t* out) +{ + int idx = 0; + for (; len >= 4; idx += 4, len -= 4) + { + *((uint32_t*) &out[idx]) = *((uint32_t*) &left[idx]) ^ *((uint32_t*) &right[idx]); + } + if (len >= 2) + { + *((uint16_t*) &out[idx]) = *((uint16_t*) &left[idx]) ^ *((uint16_t*) &right[idx]); + idx += 2; + len -= 2; + } + if (len > 0) + { + out[idx] = left[idx] ^ right[idx]; + } +} + +bool mitosis_aes_ctr_encrypt(mitosis_encrypt_context_t* context, uint32_t datalen, const uint8_t* plaintext, uint8_t* ciphertext) +{ + if (datalen > AES_BLOCK_SIZE) + { + return false; + } + + if (!mitosis_aes_ecb_encrypt(&context->ecb)) + { + return false; + } + xor(plaintext, context->ctr.scratch, datalen, ciphertext); + + return true; +} diff --git a/mitosis-crypto/mitosis-aes-ctr.h b/mitosis-crypto/mitosis-aes-ctr.h new file mode 100644 index 0000000..64f3d14 --- /dev/null +++ b/mitosis-crypto/mitosis-aes-ctr.h @@ -0,0 +1,32 @@ +/* +Interface for AES in CTR mode for mitosis +*/ +#include "mitosis-aes-ecb.h" + +typedef struct _mitosis_aes_ctr_context_t { + uint8_t key[AES_BLOCK_SIZE]; + union { + struct { + uint8_t nonce[AES_BLOCK_SIZE - sizeof(uint32_t)]; + uint32_t counter; + } iv; + uint8_t iv_bytes[AES_BLOCK_SIZE]; + }; + uint8_t scratch[AES_BLOCK_SIZE]; +} mitosis_aes_ctr_context_t; + +_Static_assert(sizeof(mitosis_aes_ctr_context_t) == sizeof(mitosis_aes_ecb_context_t)); + +typedef union _mitosis_encrypt_context_t { + mitosis_aes_ecb_context_t ecb; + mitosis_aes_ctr_context_t ctr; +} mitosis_encrypt_context_t; + +/* +Key and nonce are 16 bytes for consistency. +*/ +bool mitosis_aes_ctr_init(const uint8_t* key, const uint8_t* nonce, mitosis_encrypt_context_t* context); + +bool mitosis_aes_ctr_encrypt(mitosis_encrypt_context_t* context, uint32_t datalen, const uint8_t* plaintext, uint8_t* ciphertext); + +#define mitosis_aes_ctr_decrypt(context, datalen, ciphertext, plaintext) mitosis_aes_ctr_encrypt(context, datalen, ciphertext, plaintext) diff --git a/mitosis-crypto/mitosis-aes-ecb.c b/mitosis-crypto/mitosis-aes-ecb.c new file mode 100644 index 0000000..5ead309 --- /dev/null +++ b/mitosis-crypto/mitosis-aes-ecb.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "mitosis-aes-ecb.h" + +#define ENCRYPT_WAIT 0x1000000 + +static uint32_t wait_counts = 0; +static uint32_t encrypt_count = 0; + +bool mitosis_aes_ecb_init(mitosis_aes_ecb_context_t* state) +{ + if (state == NULL) + { + return false; + } + + NRF_ECB->ECBDATAPTR = (uint32_t) state; + return true; +} + +bool mitosis_aes_ecb_encrypt(mitosis_aes_ecb_context_t* state) +{ + if (state == NULL) + { + return false; + } + + if (NRF_ECB->ECBDATAPTR != (uint32_t) state) + { + NRF_ECB->ECBDATAPTR = (uint32_t) state; + } + + uint32_t wait_counter = ENCRYPT_WAIT; + + NRF_ECB->EVENTS_ERRORECB = 0; + NRF_ECB->EVENTS_ENDECB = 0; + NRF_ECB->TASKS_STARTECB = 1; + while (!(NRF_ECB->EVENTS_ENDECB | NRF_ECB->EVENTS_ERRORECB)) + { + wait_counter--; + if(wait_counter == 0) + { + return false; + } + } + ++encrypt_count; + wait_counts += (ENCRYPT_WAIT - wait_counter); + NRF_ECB->EVENTS_ENDECB = 0; + if (NRF_ECB->EVENTS_ERRORECB) + { + NRF_ECB->EVENTS_ERRORECB = 0; + return false; + } + return true; +} diff --git a/mitosis-crypto/mitosis-aes-ecb.h b/mitosis-crypto/mitosis-aes-ecb.h new file mode 100644 index 0000000..aa5cebb --- /dev/null +++ b/mitosis-crypto/mitosis-aes-ecb.h @@ -0,0 +1,21 @@ +/* + This file provides an alternate interface to the underlying AES engine. + The point is to reduce the number of calls to memcpy(). +*/ + +#ifndef _MITOSIS_AES_ECB +#define _MITOSIS_AES_ECB + +#define AES_BLOCK_SIZE 16 + +typedef struct _mitosis_aes_ecb_context_t { + uint8_t key[AES_BLOCK_SIZE]; + uint8_t plaintext[AES_BLOCK_SIZE]; + uint8_t ciphertext[AES_BLOCK_SIZE]; +} mitosis_aes_ecb_context_t; + +bool mitosis_aes_ecb_init(mitosis_aes_ecb_context_t* state); + +bool mitosis_aes_ecb_encrypt(mitosis_aes_ecb_context_t* state); + +#endif diff --git a/mitosis-crypto/mitosis-ckdf.c b/mitosis-crypto/mitosis-ckdf.c new file mode 100644 index 0000000..a44f0fe --- /dev/null +++ b/mitosis-crypto/mitosis-ckdf.c @@ -0,0 +1,85 @@ + +#include +#include +#include +#include +#include "mitosis-ckdf.h" + +bool mitosis_ckdf_extract(const uint8_t* ikm, size_t ikm_len, const uint8_t* salt, size_t salt_len, uint8_t* prk) +{ + mitosis_cmac_context_t state; + + if (!mitosis_cmac_init(&state, salt, salt_len)) + { + return false; + } + return mitosis_cmac_compute(&state, ikm, ikm_len, prk); +} + +bool +mitosis_ckdf_expand(const uint8_t* prk, size_t prk_len, const uint8_t* info, size_t info_len, uint8_t* okm, size_t okm_len) +{ + mitosis_cmac_context_t state; + uint8_t scratch[AES_BLOCK_SIZE]; + uint8_t iterations; + uint16_t offset = 0; + + if (okm_len > 255 * AES_BLOCK_SIZE) + { + return false; + } + + if (okm_len % AES_BLOCK_SIZE) + { + iterations = (uint8_t)(okm_len / AES_BLOCK_SIZE) + 1; + } + else + { + iterations = (uint8_t)(okm_len / AES_BLOCK_SIZE); + } + + // i starts at 1 so it can be used to save the memory needed for a separate + // block counter. + for (uint8_t i = 1; i <= iterations && i > 0; ++i) + { + if (!mitosis_cmac_init(&state, prk, prk_len)) + { + return false; + } + + if (i > 1) + { + if (!mitosis_cmac_hash(&state, scratch, sizeof(scratch))) + { + return false; + } + } + + if (!mitosis_cmac_hash(&state, info, info_len)) + { + return false; + } + + if (!mitosis_cmac_hash(&state, &i, 1)) + { + return false; + } + + if (!mitosis_cmac_complete(&state, scratch)) + { + return false; + } + + if (okm_len > sizeof(scratch)) + { + memcpy(okm + offset, scratch, sizeof(scratch)); + okm_len -= sizeof(scratch); + offset += sizeof(scratch); + } + else + { + memcpy(okm + offset, scratch, okm_len); + } + } + return true; +} diff --git a/mitosis-crypto/mitosis-ckdf.h b/mitosis-crypto/mitosis-ckdf.h new file mode 100644 index 0000000..35260dd --- /dev/null +++ b/mitosis-crypto/mitosis-ckdf.h @@ -0,0 +1,10 @@ +/* +CKDF interface for Mitosis keyboard + +Based on draft-agl-ckdf-01 (https://tools.ietf.org/html/draft-agl-ckdf-01) +*/ + + +bool mitosis_ckdf_extract(const uint8_t* ikm, size_t ikm_len, const uint8_t* salt, size_t salt_len, uint8_t* prk); + +bool mitosis_ckdf_expand(const uint8_t* prk, size_t prk_len, const uint8_t* info, size_t info_len, uint8_t* okm, size_t okm_len); diff --git a/mitosis-crypto/mitosis-cmac.c b/mitosis-crypto/mitosis-cmac.c new file mode 100644 index 0000000..f787e19 --- /dev/null +++ b/mitosis-crypto/mitosis-cmac.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include "mitosis-cmac.h" + +static inline +void shiftleft(const uint8_t* in, uint8_t* out) +{ + uint32_t overflow = 0; + for (int i = 15; i >= 0; --i) + { + out[i] = in[i] << 1; + out[i] |= overflow; + overflow = (in[i] & 0x80) ? 1 : 0; + } +} + +static inline +void xor128(const uint8_t* left, const uint8_t* right, uint8_t* out) +{ + for (int i = 0; i < 4; ++i) + { + ((uint32_t*) out)[i] = ((const uint32_t*) left)[i] ^ ((const uint32_t*) right)[i]; + } +} + +static inline +void xor(const uint8_t* left, const uint8_t* right, size_t len, uint8_t* out) +{ + int idx = 0; + for (; len >= 4; idx += 4, len -= 4) + { + *((uint32_t*) &out[idx]) = *((uint32_t*) &left[idx]) ^ *((uint32_t*) &right[idx]); + } + if (len >= 2) + { + *((uint16_t*) &out[idx]) = *((uint16_t*) &left[idx]) ^ *((uint16_t*) &right[idx]); + idx += 2; + len -= 2; + } + if (len > 0) + { + out[idx] = left[idx] ^ right[idx]; + } +} + +bool mitosis_cmac_init(mitosis_cmac_context_t* context, const uint8_t* key, size_t key_len) +{ + if (key_len < sizeof(context->ecb.key)) + { + // Left-pad key with zeroes. + uint32_t delta = sizeof(context->ecb.key) - key_len; + uint32_t idx = 0; + for (; idx < delta; ++idx) + { + context->ecb.key[idx] = 0; + } + for (uint32_t key_idx = 0; idx < sizeof(context->ecb.key); ++idx, ++key_idx) + { + context->ecb.key[idx] = key[key_idx]; + } + } + else + { + // If key length is greater than AES-128 key length, truncate. + memcpy(context->ecb.key, key, sizeof(context->ecb.key)); + } + memset(context->ecb.plaintext, 0, sizeof(context->ecb.plaintext)); + context->multiblock = false; + context->plaintext_index = 0; + + if (!mitosis_aes_ecb_encrypt(&context->ecb)) + { + return false; + } + + // Left-shift the output to generate K1. + shiftleft(context->ecb.ciphertext, context->key1); + + // If MSB is 1, XOR the last byte of K1. + if (context->ecb.ciphertext[0] & 0x80) + { + context->key1[15] ^= 0x87; + } + + // Left-shift K1 to generate K2. + shiftleft(context->key1, context->key2); + + // If MSB is 1, XOR the last byte of K2. + if (context->key1[0] & 0x80) + { + context->key2[15] ^= 0x87; + } + + return true; +} + +bool mitosis_cmac_hash(mitosis_cmac_context_t* context, const uint8_t* data, size_t data_len) +{ + do + { + int available_space = AES_BLOCK_SIZE - context->plaintext_index; + // copy data into plaintext + if (data_len <= available_space) + { + // Note: If this is unaligned, ARM will crash. + memcpy(context->ecb.plaintext + context->plaintext_index, data, data_len); + context->plaintext_index += data_len; + data_len = 0; + } + else + { + // Note: If this is unaligned, ARM will crash. + memcpy(context->ecb.plaintext + context->plaintext_index, data, available_space); + context->plaintext_index += available_space; + data += available_space; + data_len -= available_space; + } + + // if plaintext is full and there's more data left to copy, process plaintext + if (context->plaintext_index == AES_BLOCK_SIZE && data_len > 0) + { + // carry forward previous result, if present + if (context->multiblock) + { + xor128(context->ecb.ciphertext, context->ecb.plaintext, context->ecb.plaintext); + } + // compute hash + if (!mitosis_aes_ecb_encrypt(&context->ecb)) + { + return false; + } + context->multiblock = true; + context->plaintext_index = 0; + } + } + while (data_len > 0); + + return true; +} + +bool mitosis_cmac_complete(mitosis_cmac_context_t* context, uint8_t* output) +{ + // Prepare the last block of data in the plaintext. + if (context->plaintext_index == AES_BLOCK_SIZE) + { + xor128(context->ecb.plaintext, context->key1, context->ecb.plaintext); + } + else + { + // XOR the remaining data with K2. + xor(context->ecb.plaintext, context->key2, context->plaintext_index, context->ecb.plaintext); + // XOR K2 with the first byte of padding. + context->ecb.plaintext[context->plaintext_index] = 0x80 ^ context->key2[context->plaintext_index]; + // If there's more data, copy K2 into input. + if (context->plaintext_index < 15) + { + // Note: If this is unaligned, ARM will crash. + memcpy( + context->ecb.plaintext + context->plaintext_index + 1, + context->key2 + context->plaintext_index + 1, + sizeof(context->ecb.plaintext) - context->plaintext_index - 1); + } + } + + // If previous blocks were processed, XOR them into the last block. + if (context->multiblock) + { + xor128(context->ecb.plaintext, context->ecb.ciphertext, context->ecb.plaintext); + } + + if (!mitosis_aes_ecb_encrypt(&context->ecb)) + { + return false; + } + + context->multiblock = false; + context->plaintext_index = 0; + memcpy(output, context->ecb.ciphertext, sizeof(context->ecb.ciphertext)); + return true; +} + +bool mitosis_cmac_compute(mitosis_cmac_context_t* context, const uint8_t* data, size_t datalen, uint8_t* output) +{ + if (!mitosis_cmac_hash(context, data, datalen)) + { + return false; + } + if (!mitosis_cmac_complete(context, output)) + { + return false; + } + + return true; +} diff --git a/mitosis-crypto/mitosis-cmac.h b/mitosis-crypto/mitosis-cmac.h new file mode 100644 index 0000000..0eca271 --- /dev/null +++ b/mitosis-crypto/mitosis-cmac.h @@ -0,0 +1,24 @@ +/* + Implementation of CMAC using AES for Mitosis. +*/ + +#include "mitosis-aes-ecb.h" + +#define MITOSIS_CMAC_OUTPUT_SIZE AES_BLOCK_SIZE + +typedef struct _mitosis_cmac_context_t { + uint8_t key1[AES_BLOCK_SIZE]; + uint8_t key2[AES_BLOCK_SIZE]; + mitosis_aes_ecb_context_t ecb; + uint32_t multiblock : 1; + uint32_t plaintext_index : 5; +} mitosis_cmac_context_t; + +bool mitosis_cmac_init(mitosis_cmac_context_t* context, const uint8_t* key, size_t key_len); + +bool mitosis_cmac_hash(mitosis_cmac_context_t* context, const uint8_t* data, size_t data_len); + +bool mitosis_cmac_complete(mitosis_cmac_context_t* context, uint8_t* output); + +// If all data is ready in a contiguous buffer, call this. +bool mitosis_cmac_compute(mitosis_cmac_context_t* context, const uint8_t* data, size_t datalen, uint8_t* output); diff --git a/mitosis-crypto/mitosis-crypto.h b/mitosis-crypto/mitosis-crypto.h new file mode 100644 index 0000000..1c3e705 --- /dev/null +++ b/mitosis-crypto/mitosis-crypto.h @@ -0,0 +1,176 @@ +#ifndef _MITOSIS_CRYPTO_H +#define _MITOSIS_CRYPTO_H + +#include "mitosis-hmac.h" +#include "mitosis-hkdf.h" +#include "mitosis-ckdf.h" +#include "mitosis-aes-ctr.h" +#include "mitosis-cmac.h" + +/* + CHANGE THIS VALUE TO BE UNIQUE TO YOUR MITOSIS KEYBOARD. + IT MUST BE AT LEAST 16 BYTES LONG. + You can get random bytes from, for example, https://www.random.org/bytes/ + or the following shell script: + od -vN 16 -An -tx1 /dev/urandom | sed -E 's/^ /0x/; s/ /, 0x/g;' +*/ +#define MITOSIS_MASTER_SECRET_SEED { 0xd4, 0xec, 0x88, 0x1e, 0x32, 0x0e, 0x97, 0x86, 0xf2, 0xdb, 0x75, 0xfa, 0x73, 0xda, 0x8a, 0x10 } + +/* + THESE SALT VALUES MUST BE EXACTLY 16 BYTES LONG. + These salt values are byte arrays because CKDF uses the SALT as an AES key. +*/ +#define MITOSIS_LEFT_SALT { 0xa9, 0x09, 0xb0, 0x9d, 0x36, 0x4d, 0xc2, 0x40, 0xeb, 0x37, 0xcb, 0x13, 0xf3, 0xb3, 0xe6, 0x41 } + +#define MITOSIS_RIGHT_SALT { 0x99, 0x3f, 0xfc, 0x88, 0xbf, 0x21, 0x44, 0x90, 0xf0, 0x2b, 0x53, 0x2e, 0x02, 0xff, 0x7e, 0xc5 } + +#define MITOSIS_RECEIVER_SALT { 0xff, 0xe5, 0x5d, 0xcc, 0x7b, 0xce, 0x11, 0x1f, 0xb3, 0xb6, 0xe8, 0x7e, 0xa3, 0x81, 0xe0, 0x49 } + +#define MITOSIS_ENCRYPT_KEY_INFO "encryption key" + +#define MITOSIS_CMAC_KEY_INFO "MAC key" + +#define MITOSIS_NONCE_INFO "encryption nonce" + +/* + The number of encryptions a keyboard half can do before the receiver tells it + to update the keys. This doesn't cleanly map to keypresses, since a single + press may generate tens of packets. + + Note: Values less than 30 seem cause problems. + And anything less than 1,000,000,000 is overkill. +*/ +#define MITOSIS_REKEY_INTERVAL 100000 + +typedef struct _mitosis_crypto_context_t { + mitosis_encrypt_context_t encrypt; + mitosis_cmac_context_t cmac; +} mitosis_crypto_context_t; + +typedef struct _mitosis_crypto_data_payload_t { + union { + struct { + uint8_t data[3]; + uint8_t key_id; + uint32_t counter; + }; + uint8_t payload[8]; + }; + uint8_t mac[16]; +} mitosis_crypto_data_payload_t; + +_Static_assert(sizeof(mitosis_crypto_data_payload_t) == 24); + +typedef struct _mitosis_crypto_seed_payload_t { + union { + struct { + uint8_t seed[15]; + uint8_t key_id; + }; + uint8_t payload[16]; + }; + uint8_t mac[16]; +} mitosis_crypto_seed_payload_t; + +_Static_assert(sizeof(mitosis_crypto_seed_payload_t) == 32); + +typedef enum _mitosis_crypto_key_type_t { + right_keyboard_crypto_key, + left_keyboard_crypto_key, + receiver_crypto_key +} mitosis_crypto_key_type_t; + + +inline +bool +mitosis_crypto_rekey(mitosis_crypto_context_t* context, mitosis_crypto_key_type_t type, const uint8_t* seed, size_t seed_len) +{ + bool result = true; + uint8_t prk[MITOSIS_CMAC_OUTPUT_SIZE]; + static const uint8_t left_salt[sizeof((uint8_t[]) MITOSIS_LEFT_SALT)] = MITOSIS_LEFT_SALT; + static const uint8_t right_salt[sizeof((uint8_t[]) MITOSIS_RIGHT_SALT)] = MITOSIS_RIGHT_SALT; + static const uint8_t receiver_salt[sizeof((uint8_t[]) MITOSIS_RECEIVER_SALT)] = MITOSIS_RECEIVER_SALT; + const uint8_t* salt; + size_t salt_len; + + switch(type) + { + case right_keyboard_crypto_key: + salt = right_salt; + salt_len = sizeof(right_salt); + break; + case left_keyboard_crypto_key: + salt = left_salt; + salt_len = sizeof(left_salt); + break; + case receiver_crypto_key: + salt = receiver_salt; + salt_len = sizeof(receiver_salt); + break; + default: + return false; + } + + result = + mitosis_ckdf_extract( + seed, seed_len, + salt, salt_len, + prk); + if (!result) + { + return result; + } + + result = + mitosis_ckdf_expand( + prk, sizeof(prk), + (uint8_t*)MITOSIS_ENCRYPT_KEY_INFO, sizeof(MITOSIS_ENCRYPT_KEY_INFO), + context->encrypt.ctr.key, sizeof(context->encrypt.ctr.key)); + if (!result) + { + return result; + } + + result = + mitosis_ckdf_expand( + prk, sizeof(prk), + (uint8_t*)MITOSIS_NONCE_INFO, + sizeof(MITOSIS_NONCE_INFO), + context->encrypt.ctr.iv_bytes, sizeof(context->encrypt.ctr.iv_bytes)); + if (!result) + { + return result; + } + + // Initialize counter to zero. + context->encrypt.ctr.iv.counter = 0; + + // prk can be overwritten here because mitosis_ckdf_expand is done with it + // by the time that output is being written. + result = + mitosis_ckdf_expand( + prk, sizeof(prk), + (uint8_t*)MITOSIS_CMAC_KEY_INFO, sizeof(MITOSIS_CMAC_KEY_INFO), + prk, AES_BLOCK_SIZE); + if (!result) + { + return result; + } + + if (!mitosis_cmac_init(&(context->cmac), prk, sizeof(prk))) + { + return false; + } + + return mitosis_aes_ecb_init(&(context->encrypt.ecb)); +} + +inline +bool +mitosis_crypto_init(mitosis_crypto_context_t* context, mitosis_crypto_key_type_t type) +{ + static const uint8_t ikm[sizeof((uint8_t[])MITOSIS_MASTER_SECRET_SEED)] = MITOSIS_MASTER_SECRET_SEED; + return mitosis_crypto_rekey(context, type, ikm, sizeof(ikm)); +} + +#endif // _MITOSIS_CRYPTO_H diff --git a/mitosis-crypto/mitosis-hkdf.c b/mitosis-crypto/mitosis-hkdf.c new file mode 100644 index 0000000..7bfe415 --- /dev/null +++ b/mitosis-crypto/mitosis-hkdf.c @@ -0,0 +1,87 @@ + +#include +#include +#include +#include +#include "mitosis-hkdf.h" + +bool mitosis_hkdf_extract(const uint8_t* ikm, size_t ikm_len, const uint8_t* salt, size_t salt_len, uint8_t* prk) +{ + mitosis_hmac_context_t state; + if (!mitosis_hmac_init(&state, salt, salt_len)) + { + return false; + } + if (!mitosis_hmac_hash(&state, ikm, ikm_len)) + { + return false; + } + + return mitosis_hmac_complete(&state, prk); +} + +bool mitosis_hkdf_expand(const uint8_t* prk, size_t prk_len, const uint8_t* info, size_t info_len, uint8_t* okm, size_t okm_len) +{ + mitosis_hmac_context_t state; + uint8_t scratch[MITOSIS_HMAC_OUTPUT_SIZE]; + uint8_t iterations; + uint16_t offset = 0; + + if (okm_len > 255 * MITOSIS_HMAC_OUTPUT_SIZE) + { + return false; + } + + if (okm_len % MITOSIS_HMAC_OUTPUT_SIZE) + { + iterations = (uint8_t)(okm_len / MITOSIS_HMAC_OUTPUT_SIZE) + 1; + } + else + { + iterations = (uint8_t)(okm_len / MITOSIS_HMAC_OUTPUT_SIZE); + } + + if (!mitosis_hmac_init(&state, prk, prk_len)) + { + return false; + } + + // i starts at 1 so it can be used to save the memory needed for a separate + // block counter. + for (uint8_t i = 1; i <= iterations && i > 0; ++i) + { + if (i > 1) { + if(!mitosis_hmac_hash(&state, scratch, sizeof(scratch))) + { + return false; + } + } + + if (!mitosis_hmac_hash(&state, info, info_len)) + { + return false; + } + + if (!mitosis_hmac_hash(&state, &i, 1)) + { + return false; + } + + if (!mitosis_hmac_complete(&state, scratch)) + { + return false; + } + + if (okm_len > sizeof(scratch)) + { + memcpy(okm + offset, scratch, sizeof(scratch)); + okm_len -= sizeof(scratch); + offset += sizeof(scratch); + } + else + { + memcpy(okm + offset, scratch, okm_len); + } + } + return true; +} diff --git a/mitosis-crypto/mitosis-hkdf.h b/mitosis-crypto/mitosis-hkdf.h new file mode 100644 index 0000000..5144f4c --- /dev/null +++ b/mitosis-crypto/mitosis-hkdf.h @@ -0,0 +1,10 @@ +/* +HKDF interface for Mitosis keyboard + +Based on RFC 5869 (https://tools.ietf.org/html/rfc5869) +*/ + + +bool mitosis_hkdf_extract(const uint8_t* ikm, size_t ikm_len, const uint8_t* salt, size_t salt_len, uint8_t* prk); + +bool mitosis_hkdf_expand(const uint8_t* prk, size_t prk_len, const uint8_t* info, size_t info_len, uint8_t* okm, size_t okm_len); diff --git a/mitosis-crypto/mitosis-hmac.c b/mitosis-crypto/mitosis-hmac.c new file mode 100644 index 0000000..b7d94ee --- /dev/null +++ b/mitosis-crypto/mitosis-hmac.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include "mitosis-hmac.h" +#include + +#define INNER_PAD 0x36 +#define OUTER_PAD 0x5c +#define INNER_PAD_32 (uint32_t)0x36363636 +#define OUTER_PAD_32 (uint32_t)0x5c5c5c5c + + + +bool +mitosis_hmac_init(mitosis_hmac_context_t* state, const uint8_t* key, size_t len) +{ + if (state == 0 || key == 0) + { + return false; + } + + if (len > SHA256_BLOCK_SIZE) + { + uint8_t newKey[MITOSIS_HMAC_OUTPUT_SIZE] = { 0 }; + sha256_init(&(state->sha256_context)); + sha256_update(&(state->sha256_context), key, len); + sha256_final(&(state->sha256_context), newKey); + key = newKey; + len = MITOSIS_HMAC_OUTPUT_SIZE; + } + + // create inner and outer key from key material. + uint32_t idx = 0; + for (; len - idx > 4; idx += 4) + { + // This does a "fast" XOR by doing 32-bits at a time. + *(uint32_t*)(state->inner_key + idx) = *(uint32_t*)(key + idx) ^ INNER_PAD_32; + *(uint32_t*)(state->outer_key + idx) = *(uint32_t*)(key + idx) ^ OUTER_PAD_32; + } + for (; len - idx > 0; ++idx) + { + // Fallback to "slow" XOR for the rest of the key material. + state->inner_key[idx] = key[idx] ^ INNER_PAD; + state->outer_key[idx] = key[idx] ^ OUTER_PAD; + } + for (; (idx & 0x3) && idx < sizeof(state->inner_key); ++idx) + { + // "Slow" copy to the next 4-byte boundary. + state->inner_key[idx] = INNER_PAD; + state->outer_key[idx] = OUTER_PAD; + } + for (; idx < sizeof(state->inner_key); idx += 4) + { + // "Fast" copy the rest of the key material. + *(uint32_t*)(state->inner_key + idx) = INNER_PAD_32; + *(uint32_t*)(state->outer_key + idx) = OUTER_PAD_32; + } + + sha256_init(&(state->sha256_context)); + + sha256_update(&(state->sha256_context), state->inner_key, sizeof(state->inner_key)); + + return true; +} + +bool +mitosis_hmac_hash(mitosis_hmac_context_t* state, const uint8_t* data, size_t len) +{ + if (state == 0 || data == 0) + { + return false; + } + if (state->need_reset) + { + sha256_init(&(state->sha256_context)); + sha256_update(&(state->sha256_context), state->inner_key, sizeof(state->inner_key)); + state->need_reset = 0; + } + return sha256_update(&(state->sha256_context), data, len) == NRF_SUCCESS; +} + +bool +mitosis_hmac_complete(mitosis_hmac_context_t* state, uint8_t* hash) { + if (state == 0 || hash == 0) + { + return false; + } + uint8_t first_hash[MITOSIS_HMAC_OUTPUT_SIZE]; + state->need_reset = 1; + sha256_final(&(state->sha256_context), first_hash); + // Re-use the hash object to compute the 2nd hash pass. + sha256_init(&(state->sha256_context)); + sha256_update(&(state->sha256_context), state->outer_key, sizeof(state->outer_key)); + sha256_update(&(state->sha256_context), first_hash, sizeof(first_hash)); + return sha256_final(&(state->sha256_context), hash) == NRF_SUCCESS; +} diff --git a/mitosis-crypto/mitosis-hmac.h b/mitosis-crypto/mitosis-hmac.h new file mode 100644 index 0000000..bfa7048 --- /dev/null +++ b/mitosis-crypto/mitosis-hmac.h @@ -0,0 +1,20 @@ +/* +Interface for HMAC-SHA256 for Mitosis keyboard +*/ +#include "sha256.h" +#define SHA256_BLOCK_SIZE 64 + +#define MITOSIS_HMAC_OUTPUT_SIZE 32 + +typedef struct _mitosis_hmac_context_t { + sha256_context_t sha256_context; + uint8_t inner_key[SHA256_BLOCK_SIZE]; + uint8_t outer_key[SHA256_BLOCK_SIZE]; + uint32_t need_reset : 1; +} mitosis_hmac_context_t; + +bool mitosis_hmac_init(mitosis_hmac_context_t* state, const uint8_t* key, size_t len); + +bool mitosis_hmac_hash(mitosis_hmac_context_t* state, const uint8_t* data, size_t len); + +bool mitosis_hmac_complete(mitosis_hmac_context_t* state, uint8_t* hash); diff --git a/mitosis-crypto/mitosis-keys.c b/mitosis-crypto/mitosis-keys.c new file mode 100644 index 0000000..822f243 --- /dev/null +++ b/mitosis-crypto/mitosis-keys.c @@ -0,0 +1,9 @@ +#include +#include +#include +#include "mitosis-crypto.h" + + +extern bool mitosis_crypto_init(mitosis_crypto_context_t* context, mitosis_crypto_key_type_t type); + +extern bool mitosis_crypto_rekey(mitosis_crypto_context_t* context, mitosis_crypto_key_type_t type, const uint8_t* seed, size_t seed_len); diff --git a/mitosis-crypto/test/Makefile b/mitosis-crypto/test/Makefile new file mode 100644 index 0000000..785faca --- /dev/null +++ b/mitosis-crypto/test/Makefile @@ -0,0 +1,99 @@ +PROJECT_NAME := mitosis-crypto-tests + +OUTPUT_FILENAME := crypto-tests +#MAKEFILE_NAME := $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) +MAKEFILE_NAME := $(MAKEFILE_LIST) +MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) + +TEMPLATE_PATH = ../../../components/toolchain/gcc +ifeq ($(OS),Windows_NT) +include $(TEMPLATE_PATH)/Makefile.windows +else +include $(TEMPLATE_PATH)/Makefile.posix +endif + +MK := mkdir +RM := rm -rf + +#echo suspend +ifeq ("$(VERBOSE)","1") +NO_ECHO := +else +NO_ECHO := @ +endif + +# Toolchain commands +# CC := '$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-gcc' +AS := '$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-as' +AR := '$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-ar' -r +# LD := '$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-ld' +NM := '$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-nm' +OBJDUMP := '$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-objdump' +OBJCOPY := '$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-objcopy' +SIZE := '$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-size' +CC := gcc +LD := ld + +#function for removing duplicates in a list +remduplicates = $(strip $(if $1,$(firstword $1) $(call remduplicates,$(filter-out $(firstword $1),$1)))) + +#source common to all targets +C_SOURCE_FILES += \ +$(abspath ./main.c) \ +$(abspath ./aes.c) \ +$(abspath ../mitosis-hmac.c) \ +$(abspath ../mitosis-cmac.c) \ +$(abspath ../mitosis-hkdf.c) \ +$(abspath ../mitosis-ckdf.c) \ +$(abspath ../mitosis-aes-ctr.c) \ +$(abspath ../mitosis-keys.c) \ +$(abspath ../../../components/libraries/sha256/sha256.c) \ + +#includes common to all targets +INC_PATHS = -I$(abspath ../) +INC_PATHS += -I$(abspath ../../../components/drivers_nrf/hal) +INC_PATHS += -I$(abspath ../../../components/libraries/sha256) +INC_PATHS += -I$(abspath ../../../components/libraries/util) +INC_PATHS += -I$(abspath ../../../components/drivers_nrf/nrf_soc_nosd) +INC_PATHS += -I$(abspath ../../../components/device) + +OBJECT_DIRECTORY = _build +LISTING_DIRECTORY = $(OBJECT_DIRECTORY) +OUTPUT_BINARY_DIRECTORY = bin + +BUILD_DIRECTORIES := $(sort $(OBJECT_DIRECTORY) $(OUTPUT_BINARY_DIRECTORY) $(LISTING_DIRECTORY) ) + +CFLAGS = -DUNIX +CFLAGS += -Wall -Og -g3 +CFLAGS += -Wno-unused-function +CFLAGS += -Wno-unused-variable + +LDFLAGS=-Wall + +C_SOURCE_FILE_NAMES = $(notdir $(C_SOURCE_FILES)) +C_PATHS = $(call remduplicates, $(dir $(C_SOURCE_FILES) ) ) +C_OBJECTS = $(addprefix $(OBJECT_DIRECTORY)/, $(C_SOURCE_FILE_NAMES:.c=.o) ) + +vpath %.c $(C_PATHS) + +OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS) + +default: $(BUILD_DIRECTORIES) $(OBJECTS) + $(NO_ECHO)$(CC) $(LDFLAGS) $(OBJECTS) -lm -o $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out + +## Create build directories +$(BUILD_DIRECTORIES): + echo $(MAKEFILE_NAME) + $(MK) $@ + +# Create objects from C SRC files +$(OBJECT_DIRECTORY)/%.o: %.c + @echo Compiling file: $(notdir $<) + $(NO_ECHO)$(CC) $(CFLAGS) $(INC_PATHS) -c -o $@ $< +# Link +$(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out: $(BUILD_DIRECTORIES) $(OBJECTS) + @echo Linking target: $(OUTPUT_FILENAME).out + $(NO_ECHO)$(CC) $(LDFLAGS) $(OBJECTS) -lm -o $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out + +clean: + $(RM) $(BUILD_DIRECTORIES) diff --git a/mitosis-crypto/test/aes.c b/mitosis-crypto/test/aes.c new file mode 100644 index 0000000..c416a94 --- /dev/null +++ b/mitosis-crypto/test/aes.c @@ -0,0 +1,760 @@ +/********************************************************************* +* Filename: aes.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: This code is the implementation of the AES algorithm. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include +#include +#include +#include +#include "mitosis-aes-ecb.h" + +#include + +/****************************** MACROS ******************************/ +// The least significant byte of the word is rotated to the end. +#define KE_ROTWORD(x) (((x) << 8) | ((x) >> 24)) + +#define TRUE 1 +#define FALSE 0 + +/**************************** DATA TYPES ****************************/ +#define AES_128_ROUNDS 10 +#define AES_192_ROUNDS 12 +#define AES_256_ROUNDS 14 + +/**************************** VARIABLES *****************************/ +// This is the specified AES SBox. To look up a substitution value, put the first +// nibble in the first index (row) and the second nibble in the second index (column). +static const uint8_t aes_sbox[16][16] = { + {0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76}, + {0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0}, + {0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15}, + {0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75}, + {0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84}, + {0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF}, + {0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8}, + {0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2}, + {0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73}, + {0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB}, + {0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79}, + {0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08}, + {0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A}, + {0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E}, + {0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF}, + {0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16} +}; + +static const uint8_t aes_invsbox[16][16] = { + {0x52,0x09,0x6A,0xD5,0x30,0x36,0xA5,0x38,0xBF,0x40,0xA3,0x9E,0x81,0xF3,0xD7,0xFB}, + {0x7C,0xE3,0x39,0x82,0x9B,0x2F,0xFF,0x87,0x34,0x8E,0x43,0x44,0xC4,0xDE,0xE9,0xCB}, + {0x54,0x7B,0x94,0x32,0xA6,0xC2,0x23,0x3D,0xEE,0x4C,0x95,0x0B,0x42,0xFA,0xC3,0x4E}, + {0x08,0x2E,0xA1,0x66,0x28,0xD9,0x24,0xB2,0x76,0x5B,0xA2,0x49,0x6D,0x8B,0xD1,0x25}, + {0x72,0xF8,0xF6,0x64,0x86,0x68,0x98,0x16,0xD4,0xA4,0x5C,0xCC,0x5D,0x65,0xB6,0x92}, + {0x6C,0x70,0x48,0x50,0xFD,0xED,0xB9,0xDA,0x5E,0x15,0x46,0x57,0xA7,0x8D,0x9D,0x84}, + {0x90,0xD8,0xAB,0x00,0x8C,0xBC,0xD3,0x0A,0xF7,0xE4,0x58,0x05,0xB8,0xB3,0x45,0x06}, + {0xD0,0x2C,0x1E,0x8F,0xCA,0x3F,0x0F,0x02,0xC1,0xAF,0xBD,0x03,0x01,0x13,0x8A,0x6B}, + {0x3A,0x91,0x11,0x41,0x4F,0x67,0xDC,0xEA,0x97,0xF2,0xCF,0xCE,0xF0,0xB4,0xE6,0x73}, + {0x96,0xAC,0x74,0x22,0xE7,0xAD,0x35,0x85,0xE2,0xF9,0x37,0xE8,0x1C,0x75,0xDF,0x6E}, + {0x47,0xF1,0x1A,0x71,0x1D,0x29,0xC5,0x89,0x6F,0xB7,0x62,0x0E,0xAA,0x18,0xBE,0x1B}, + {0xFC,0x56,0x3E,0x4B,0xC6,0xD2,0x79,0x20,0x9A,0xDB,0xC0,0xFE,0x78,0xCD,0x5A,0xF4}, + {0x1F,0xDD,0xA8,0x33,0x88,0x07,0xC7,0x31,0xB1,0x12,0x10,0x59,0x27,0x80,0xEC,0x5F}, + {0x60,0x51,0x7F,0xA9,0x19,0xB5,0x4A,0x0D,0x2D,0xE5,0x7A,0x9F,0x93,0xC9,0x9C,0xEF}, + {0xA0,0xE0,0x3B,0x4D,0xAE,0x2A,0xF5,0xB0,0xC8,0xEB,0xBB,0x3C,0x83,0x53,0x99,0x61}, + {0x17,0x2B,0x04,0x7E,0xBA,0x77,0xD6,0x26,0xE1,0x69,0x14,0x63,0x55,0x21,0x0C,0x7D} +}; + +// This table stores pre-calculated values for all possible GF(2^8) calculations.This +// table is only used by the (Inv)MixColumns steps. +// USAGE: The second index (column) is the coefficient of multiplication. Only 7 different +// coefficients are used: 0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e, but multiplication by +// 1 is negligible leaving only 6 coefficients. Each column of the table is devoted to one +// of these coefficients, in the ascending order of value, from values 0x00 to 0xFF. +static const uint8_t gf_mul[256][6] = { + {0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x03,0x09,0x0b,0x0d,0x0e}, + {0x04,0x06,0x12,0x16,0x1a,0x1c},{0x06,0x05,0x1b,0x1d,0x17,0x12}, + {0x08,0x0c,0x24,0x2c,0x34,0x38},{0x0a,0x0f,0x2d,0x27,0x39,0x36}, + {0x0c,0x0a,0x36,0x3a,0x2e,0x24},{0x0e,0x09,0x3f,0x31,0x23,0x2a}, + {0x10,0x18,0x48,0x58,0x68,0x70},{0x12,0x1b,0x41,0x53,0x65,0x7e}, + {0x14,0x1e,0x5a,0x4e,0x72,0x6c},{0x16,0x1d,0x53,0x45,0x7f,0x62}, + {0x18,0x14,0x6c,0x74,0x5c,0x48},{0x1a,0x17,0x65,0x7f,0x51,0x46}, + {0x1c,0x12,0x7e,0x62,0x46,0x54},{0x1e,0x11,0x77,0x69,0x4b,0x5a}, + {0x20,0x30,0x90,0xb0,0xd0,0xe0},{0x22,0x33,0x99,0xbb,0xdd,0xee}, + {0x24,0x36,0x82,0xa6,0xca,0xfc},{0x26,0x35,0x8b,0xad,0xc7,0xf2}, + {0x28,0x3c,0xb4,0x9c,0xe4,0xd8},{0x2a,0x3f,0xbd,0x97,0xe9,0xd6}, + {0x2c,0x3a,0xa6,0x8a,0xfe,0xc4},{0x2e,0x39,0xaf,0x81,0xf3,0xca}, + {0x30,0x28,0xd8,0xe8,0xb8,0x90},{0x32,0x2b,0xd1,0xe3,0xb5,0x9e}, + {0x34,0x2e,0xca,0xfe,0xa2,0x8c},{0x36,0x2d,0xc3,0xf5,0xaf,0x82}, + {0x38,0x24,0xfc,0xc4,0x8c,0xa8},{0x3a,0x27,0xf5,0xcf,0x81,0xa6}, + {0x3c,0x22,0xee,0xd2,0x96,0xb4},{0x3e,0x21,0xe7,0xd9,0x9b,0xba}, + {0x40,0x60,0x3b,0x7b,0xbb,0xdb},{0x42,0x63,0x32,0x70,0xb6,0xd5}, + {0x44,0x66,0x29,0x6d,0xa1,0xc7},{0x46,0x65,0x20,0x66,0xac,0xc9}, + {0x48,0x6c,0x1f,0x57,0x8f,0xe3},{0x4a,0x6f,0x16,0x5c,0x82,0xed}, + {0x4c,0x6a,0x0d,0x41,0x95,0xff},{0x4e,0x69,0x04,0x4a,0x98,0xf1}, + {0x50,0x78,0x73,0x23,0xd3,0xab},{0x52,0x7b,0x7a,0x28,0xde,0xa5}, + {0x54,0x7e,0x61,0x35,0xc9,0xb7},{0x56,0x7d,0x68,0x3e,0xc4,0xb9}, + {0x58,0x74,0x57,0x0f,0xe7,0x93},{0x5a,0x77,0x5e,0x04,0xea,0x9d}, + {0x5c,0x72,0x45,0x19,0xfd,0x8f},{0x5e,0x71,0x4c,0x12,0xf0,0x81}, + {0x60,0x50,0xab,0xcb,0x6b,0x3b},{0x62,0x53,0xa2,0xc0,0x66,0x35}, + {0x64,0x56,0xb9,0xdd,0x71,0x27},{0x66,0x55,0xb0,0xd6,0x7c,0x29}, + {0x68,0x5c,0x8f,0xe7,0x5f,0x03},{0x6a,0x5f,0x86,0xec,0x52,0x0d}, + {0x6c,0x5a,0x9d,0xf1,0x45,0x1f},{0x6e,0x59,0x94,0xfa,0x48,0x11}, + {0x70,0x48,0xe3,0x93,0x03,0x4b},{0x72,0x4b,0xea,0x98,0x0e,0x45}, + {0x74,0x4e,0xf1,0x85,0x19,0x57},{0x76,0x4d,0xf8,0x8e,0x14,0x59}, + {0x78,0x44,0xc7,0xbf,0x37,0x73},{0x7a,0x47,0xce,0xb4,0x3a,0x7d}, + {0x7c,0x42,0xd5,0xa9,0x2d,0x6f},{0x7e,0x41,0xdc,0xa2,0x20,0x61}, + {0x80,0xc0,0x76,0xf6,0x6d,0xad},{0x82,0xc3,0x7f,0xfd,0x60,0xa3}, + {0x84,0xc6,0x64,0xe0,0x77,0xb1},{0x86,0xc5,0x6d,0xeb,0x7a,0xbf}, + {0x88,0xcc,0x52,0xda,0x59,0x95},{0x8a,0xcf,0x5b,0xd1,0x54,0x9b}, + {0x8c,0xca,0x40,0xcc,0x43,0x89},{0x8e,0xc9,0x49,0xc7,0x4e,0x87}, + {0x90,0xd8,0x3e,0xae,0x05,0xdd},{0x92,0xdb,0x37,0xa5,0x08,0xd3}, + {0x94,0xde,0x2c,0xb8,0x1f,0xc1},{0x96,0xdd,0x25,0xb3,0x12,0xcf}, + {0x98,0xd4,0x1a,0x82,0x31,0xe5},{0x9a,0xd7,0x13,0x89,0x3c,0xeb}, + {0x9c,0xd2,0x08,0x94,0x2b,0xf9},{0x9e,0xd1,0x01,0x9f,0x26,0xf7}, + {0xa0,0xf0,0xe6,0x46,0xbd,0x4d},{0xa2,0xf3,0xef,0x4d,0xb0,0x43}, + {0xa4,0xf6,0xf4,0x50,0xa7,0x51},{0xa6,0xf5,0xfd,0x5b,0xaa,0x5f}, + {0xa8,0xfc,0xc2,0x6a,0x89,0x75},{0xaa,0xff,0xcb,0x61,0x84,0x7b}, + {0xac,0xfa,0xd0,0x7c,0x93,0x69},{0xae,0xf9,0xd9,0x77,0x9e,0x67}, + {0xb0,0xe8,0xae,0x1e,0xd5,0x3d},{0xb2,0xeb,0xa7,0x15,0xd8,0x33}, + {0xb4,0xee,0xbc,0x08,0xcf,0x21},{0xb6,0xed,0xb5,0x03,0xc2,0x2f}, + {0xb8,0xe4,0x8a,0x32,0xe1,0x05},{0xba,0xe7,0x83,0x39,0xec,0x0b}, + {0xbc,0xe2,0x98,0x24,0xfb,0x19},{0xbe,0xe1,0x91,0x2f,0xf6,0x17}, + {0xc0,0xa0,0x4d,0x8d,0xd6,0x76},{0xc2,0xa3,0x44,0x86,0xdb,0x78}, + {0xc4,0xa6,0x5f,0x9b,0xcc,0x6a},{0xc6,0xa5,0x56,0x90,0xc1,0x64}, + {0xc8,0xac,0x69,0xa1,0xe2,0x4e},{0xca,0xaf,0x60,0xaa,0xef,0x40}, + {0xcc,0xaa,0x7b,0xb7,0xf8,0x52},{0xce,0xa9,0x72,0xbc,0xf5,0x5c}, + {0xd0,0xb8,0x05,0xd5,0xbe,0x06},{0xd2,0xbb,0x0c,0xde,0xb3,0x08}, + {0xd4,0xbe,0x17,0xc3,0xa4,0x1a},{0xd6,0xbd,0x1e,0xc8,0xa9,0x14}, + {0xd8,0xb4,0x21,0xf9,0x8a,0x3e},{0xda,0xb7,0x28,0xf2,0x87,0x30}, + {0xdc,0xb2,0x33,0xef,0x90,0x22},{0xde,0xb1,0x3a,0xe4,0x9d,0x2c}, + {0xe0,0x90,0xdd,0x3d,0x06,0x96},{0xe2,0x93,0xd4,0x36,0x0b,0x98}, + {0xe4,0x96,0xcf,0x2b,0x1c,0x8a},{0xe6,0x95,0xc6,0x20,0x11,0x84}, + {0xe8,0x9c,0xf9,0x11,0x32,0xae},{0xea,0x9f,0xf0,0x1a,0x3f,0xa0}, + {0xec,0x9a,0xeb,0x07,0x28,0xb2},{0xee,0x99,0xe2,0x0c,0x25,0xbc}, + {0xf0,0x88,0x95,0x65,0x6e,0xe6},{0xf2,0x8b,0x9c,0x6e,0x63,0xe8}, + {0xf4,0x8e,0x87,0x73,0x74,0xfa},{0xf6,0x8d,0x8e,0x78,0x79,0xf4}, + {0xf8,0x84,0xb1,0x49,0x5a,0xde},{0xfa,0x87,0xb8,0x42,0x57,0xd0}, + {0xfc,0x82,0xa3,0x5f,0x40,0xc2},{0xfe,0x81,0xaa,0x54,0x4d,0xcc}, + {0x1b,0x9b,0xec,0xf7,0xda,0x41},{0x19,0x98,0xe5,0xfc,0xd7,0x4f}, + {0x1f,0x9d,0xfe,0xe1,0xc0,0x5d},{0x1d,0x9e,0xf7,0xea,0xcd,0x53}, + {0x13,0x97,0xc8,0xdb,0xee,0x79},{0x11,0x94,0xc1,0xd0,0xe3,0x77}, + {0x17,0x91,0xda,0xcd,0xf4,0x65},{0x15,0x92,0xd3,0xc6,0xf9,0x6b}, + {0x0b,0x83,0xa4,0xaf,0xb2,0x31},{0x09,0x80,0xad,0xa4,0xbf,0x3f}, + {0x0f,0x85,0xb6,0xb9,0xa8,0x2d},{0x0d,0x86,0xbf,0xb2,0xa5,0x23}, + {0x03,0x8f,0x80,0x83,0x86,0x09},{0x01,0x8c,0x89,0x88,0x8b,0x07}, + {0x07,0x89,0x92,0x95,0x9c,0x15},{0x05,0x8a,0x9b,0x9e,0x91,0x1b}, + {0x3b,0xab,0x7c,0x47,0x0a,0xa1},{0x39,0xa8,0x75,0x4c,0x07,0xaf}, + {0x3f,0xad,0x6e,0x51,0x10,0xbd},{0x3d,0xae,0x67,0x5a,0x1d,0xb3}, + {0x33,0xa7,0x58,0x6b,0x3e,0x99},{0x31,0xa4,0x51,0x60,0x33,0x97}, + {0x37,0xa1,0x4a,0x7d,0x24,0x85},{0x35,0xa2,0x43,0x76,0x29,0x8b}, + {0x2b,0xb3,0x34,0x1f,0x62,0xd1},{0x29,0xb0,0x3d,0x14,0x6f,0xdf}, + {0x2f,0xb5,0x26,0x09,0x78,0xcd},{0x2d,0xb6,0x2f,0x02,0x75,0xc3}, + {0x23,0xbf,0x10,0x33,0x56,0xe9},{0x21,0xbc,0x19,0x38,0x5b,0xe7}, + {0x27,0xb9,0x02,0x25,0x4c,0xf5},{0x25,0xba,0x0b,0x2e,0x41,0xfb}, + {0x5b,0xfb,0xd7,0x8c,0x61,0x9a},{0x59,0xf8,0xde,0x87,0x6c,0x94}, + {0x5f,0xfd,0xc5,0x9a,0x7b,0x86},{0x5d,0xfe,0xcc,0x91,0x76,0x88}, + {0x53,0xf7,0xf3,0xa0,0x55,0xa2},{0x51,0xf4,0xfa,0xab,0x58,0xac}, + {0x57,0xf1,0xe1,0xb6,0x4f,0xbe},{0x55,0xf2,0xe8,0xbd,0x42,0xb0}, + {0x4b,0xe3,0x9f,0xd4,0x09,0xea},{0x49,0xe0,0x96,0xdf,0x04,0xe4}, + {0x4f,0xe5,0x8d,0xc2,0x13,0xf6},{0x4d,0xe6,0x84,0xc9,0x1e,0xf8}, + {0x43,0xef,0xbb,0xf8,0x3d,0xd2},{0x41,0xec,0xb2,0xf3,0x30,0xdc}, + {0x47,0xe9,0xa9,0xee,0x27,0xce},{0x45,0xea,0xa0,0xe5,0x2a,0xc0}, + {0x7b,0xcb,0x47,0x3c,0xb1,0x7a},{0x79,0xc8,0x4e,0x37,0xbc,0x74}, + {0x7f,0xcd,0x55,0x2a,0xab,0x66},{0x7d,0xce,0x5c,0x21,0xa6,0x68}, + {0x73,0xc7,0x63,0x10,0x85,0x42},{0x71,0xc4,0x6a,0x1b,0x88,0x4c}, + {0x77,0xc1,0x71,0x06,0x9f,0x5e},{0x75,0xc2,0x78,0x0d,0x92,0x50}, + {0x6b,0xd3,0x0f,0x64,0xd9,0x0a},{0x69,0xd0,0x06,0x6f,0xd4,0x04}, + {0x6f,0xd5,0x1d,0x72,0xc3,0x16},{0x6d,0xd6,0x14,0x79,0xce,0x18}, + {0x63,0xdf,0x2b,0x48,0xed,0x32},{0x61,0xdc,0x22,0x43,0xe0,0x3c}, + {0x67,0xd9,0x39,0x5e,0xf7,0x2e},{0x65,0xda,0x30,0x55,0xfa,0x20}, + {0x9b,0x5b,0x9a,0x01,0xb7,0xec},{0x99,0x58,0x93,0x0a,0xba,0xe2}, + {0x9f,0x5d,0x88,0x17,0xad,0xf0},{0x9d,0x5e,0x81,0x1c,0xa0,0xfe}, + {0x93,0x57,0xbe,0x2d,0x83,0xd4},{0x91,0x54,0xb7,0x26,0x8e,0xda}, + {0x97,0x51,0xac,0x3b,0x99,0xc8},{0x95,0x52,0xa5,0x30,0x94,0xc6}, + {0x8b,0x43,0xd2,0x59,0xdf,0x9c},{0x89,0x40,0xdb,0x52,0xd2,0x92}, + {0x8f,0x45,0xc0,0x4f,0xc5,0x80},{0x8d,0x46,0xc9,0x44,0xc8,0x8e}, + {0x83,0x4f,0xf6,0x75,0xeb,0xa4},{0x81,0x4c,0xff,0x7e,0xe6,0xaa}, + {0x87,0x49,0xe4,0x63,0xf1,0xb8},{0x85,0x4a,0xed,0x68,0xfc,0xb6}, + {0xbb,0x6b,0x0a,0xb1,0x67,0x0c},{0xb9,0x68,0x03,0xba,0x6a,0x02}, + {0xbf,0x6d,0x18,0xa7,0x7d,0x10},{0xbd,0x6e,0x11,0xac,0x70,0x1e}, + {0xb3,0x67,0x2e,0x9d,0x53,0x34},{0xb1,0x64,0x27,0x96,0x5e,0x3a}, + {0xb7,0x61,0x3c,0x8b,0x49,0x28},{0xb5,0x62,0x35,0x80,0x44,0x26}, + {0xab,0x73,0x42,0xe9,0x0f,0x7c},{0xa9,0x70,0x4b,0xe2,0x02,0x72}, + {0xaf,0x75,0x50,0xff,0x15,0x60},{0xad,0x76,0x59,0xf4,0x18,0x6e}, + {0xa3,0x7f,0x66,0xc5,0x3b,0x44},{0xa1,0x7c,0x6f,0xce,0x36,0x4a}, + {0xa7,0x79,0x74,0xd3,0x21,0x58},{0xa5,0x7a,0x7d,0xd8,0x2c,0x56}, + {0xdb,0x3b,0xa1,0x7a,0x0c,0x37},{0xd9,0x38,0xa8,0x71,0x01,0x39}, + {0xdf,0x3d,0xb3,0x6c,0x16,0x2b},{0xdd,0x3e,0xba,0x67,0x1b,0x25}, + {0xd3,0x37,0x85,0x56,0x38,0x0f},{0xd1,0x34,0x8c,0x5d,0x35,0x01}, + {0xd7,0x31,0x97,0x40,0x22,0x13},{0xd5,0x32,0x9e,0x4b,0x2f,0x1d}, + {0xcb,0x23,0xe9,0x22,0x64,0x47},{0xc9,0x20,0xe0,0x29,0x69,0x49}, + {0xcf,0x25,0xfb,0x34,0x7e,0x5b},{0xcd,0x26,0xf2,0x3f,0x73,0x55}, + {0xc3,0x2f,0xcd,0x0e,0x50,0x7f},{0xc1,0x2c,0xc4,0x05,0x5d,0x71}, + {0xc7,0x29,0xdf,0x18,0x4a,0x63},{0xc5,0x2a,0xd6,0x13,0x47,0x6d}, + {0xfb,0x0b,0x31,0xca,0xdc,0xd7},{0xf9,0x08,0x38,0xc1,0xd1,0xd9}, + {0xff,0x0d,0x23,0xdc,0xc6,0xcb},{0xfd,0x0e,0x2a,0xd7,0xcb,0xc5}, + {0xf3,0x07,0x15,0xe6,0xe8,0xef},{0xf1,0x04,0x1c,0xed,0xe5,0xe1}, + {0xf7,0x01,0x07,0xf0,0xf2,0xf3},{0xf5,0x02,0x0e,0xfb,0xff,0xfd}, + {0xeb,0x13,0x79,0x92,0xb4,0xa7},{0xe9,0x10,0x70,0x99,0xb9,0xa9}, + {0xef,0x15,0x6b,0x84,0xae,0xbb},{0xed,0x16,0x62,0x8f,0xa3,0xb5}, + {0xe3,0x1f,0x5d,0xbe,0x80,0x9f},{0xe1,0x1c,0x54,0xb5,0x8d,0x91}, + {0xe7,0x19,0x4f,0xa8,0x9a,0x83},{0xe5,0x1a,0x46,0xa3,0x97,0x8d} +}; + + +/******************* +* AES +*******************/ +///////////////// +// KEY EXPANSION +///////////////// + +// Substitutes a word using the AES S-Box. +uint32_t SubWord(uint32_t word) +{ + unsigned int result; + + result = (int)aes_sbox[(word >> 4) & 0x0000000F][word & 0x0000000F]; + result += (int)aes_sbox[(word >> 12) & 0x0000000F][(word >> 8) & 0x0000000F] << 8; + result += (int)aes_sbox[(word >> 20) & 0x0000000F][(word >> 16) & 0x0000000F] << 16; + result += (int)aes_sbox[(word >> 28) & 0x0000000F][(word >> 24) & 0x0000000F] << 24; + return(result); +} + +// Performs the action of generating the keys that will be used in every round of +// encryption. "key" is the user-supplied input key, "w" is the output key schedule, +// "keysize" is the length in bits of "key", must be 128, 192, or 256. +void aes_key_setup(const uint8_t key[], uint32_t w[], int keysize) +{ + int Nb=4,Nr,Nk,idx; + uint32_t temp,Rcon[]={0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000, + 0x40000000,0x80000000,0x1b000000,0x36000000,0x6c000000,0xd8000000, + 0xab000000,0x4d000000,0x9a000000}; + + switch (keysize) { + case 128: Nr = 10; Nk = 4; break; + case 192: Nr = 12; Nk = 6; break; + case 256: Nr = 14; Nk = 8; break; + default: return; + } + + for (idx=0; idx < Nk; ++idx) { + w[idx] = ((key[4 * idx]) << 24) | ((key[4 * idx + 1]) << 16) | + ((key[4 * idx + 2]) << 8) | ((key[4 * idx + 3])); + } + + for (idx = Nk; idx < Nb * (Nr+1); ++idx) { + temp = w[idx - 1]; + if ((idx % Nk) == 0) + temp = SubWord(KE_ROTWORD(temp)) ^ Rcon[(idx-1)/Nk]; + else if (Nk > 6 && (idx % Nk) == 4) + temp = SubWord(temp); + w[idx] = w[idx-Nk] ^ temp; + } +} + +///////////////// +// ADD ROUND KEY +///////////////// + +// Performs the AddRoundKey step. Each round has its own pre-generated 16-byte key in the +// form of 4 integers (the "w" array). Each integer is XOR'd by one column of the state. +// Also performs the job of InvAddRoundKey(); since the function is a simple XOR process, +// it is its own inverse. +void AddRoundKey(uint8_t state[][4], const uint32_t w[]) +{ + uint8_t subkey[4]; + + // memcpy(subkey,&w[idx],4); // Not accurate for big endian machines + // Subkey 1 + subkey[0] = w[0] >> 24; + subkey[1] = w[0] >> 16; + subkey[2] = w[0] >> 8; + subkey[3] = w[0]; + state[0][0] ^= subkey[0]; + state[1][0] ^= subkey[1]; + state[2][0] ^= subkey[2]; + state[3][0] ^= subkey[3]; + // Subkey 2 + subkey[0] = w[1] >> 24; + subkey[1] = w[1] >> 16; + subkey[2] = w[1] >> 8; + subkey[3] = w[1]; + state[0][1] ^= subkey[0]; + state[1][1] ^= subkey[1]; + state[2][1] ^= subkey[2]; + state[3][1] ^= subkey[3]; + // Subkey 3 + subkey[0] = w[2] >> 24; + subkey[1] = w[2] >> 16; + subkey[2] = w[2] >> 8; + subkey[3] = w[2]; + state[0][2] ^= subkey[0]; + state[1][2] ^= subkey[1]; + state[2][2] ^= subkey[2]; + state[3][2] ^= subkey[3]; + // Subkey 4 + subkey[0] = w[3] >> 24; + subkey[1] = w[3] >> 16; + subkey[2] = w[3] >> 8; + subkey[3] = w[3]; + state[0][3] ^= subkey[0]; + state[1][3] ^= subkey[1]; + state[2][3] ^= subkey[2]; + state[3][3] ^= subkey[3]; +} + +///////////////// +// (Inv)SubBytes +///////////////// + +// Performs the SubBytes step. All bytes in the state are substituted with a +// pre-calculated value from a lookup table. +void SubBytes(uint8_t state[][4]) +{ + state[0][0] = aes_sbox[state[0][0] >> 4][state[0][0] & 0x0F]; + state[0][1] = aes_sbox[state[0][1] >> 4][state[0][1] & 0x0F]; + state[0][2] = aes_sbox[state[0][2] >> 4][state[0][2] & 0x0F]; + state[0][3] = aes_sbox[state[0][3] >> 4][state[0][3] & 0x0F]; + state[1][0] = aes_sbox[state[1][0] >> 4][state[1][0] & 0x0F]; + state[1][1] = aes_sbox[state[1][1] >> 4][state[1][1] & 0x0F]; + state[1][2] = aes_sbox[state[1][2] >> 4][state[1][2] & 0x0F]; + state[1][3] = aes_sbox[state[1][3] >> 4][state[1][3] & 0x0F]; + state[2][0] = aes_sbox[state[2][0] >> 4][state[2][0] & 0x0F]; + state[2][1] = aes_sbox[state[2][1] >> 4][state[2][1] & 0x0F]; + state[2][2] = aes_sbox[state[2][2] >> 4][state[2][2] & 0x0F]; + state[2][3] = aes_sbox[state[2][3] >> 4][state[2][3] & 0x0F]; + state[3][0] = aes_sbox[state[3][0] >> 4][state[3][0] & 0x0F]; + state[3][1] = aes_sbox[state[3][1] >> 4][state[3][1] & 0x0F]; + state[3][2] = aes_sbox[state[3][2] >> 4][state[3][2] & 0x0F]; + state[3][3] = aes_sbox[state[3][3] >> 4][state[3][3] & 0x0F]; +} + +void InvSubBytes(uint8_t state[][4]) +{ + state[0][0] = aes_invsbox[state[0][0] >> 4][state[0][0] & 0x0F]; + state[0][1] = aes_invsbox[state[0][1] >> 4][state[0][1] & 0x0F]; + state[0][2] = aes_invsbox[state[0][2] >> 4][state[0][2] & 0x0F]; + state[0][3] = aes_invsbox[state[0][3] >> 4][state[0][3] & 0x0F]; + state[1][0] = aes_invsbox[state[1][0] >> 4][state[1][0] & 0x0F]; + state[1][1] = aes_invsbox[state[1][1] >> 4][state[1][1] & 0x0F]; + state[1][2] = aes_invsbox[state[1][2] >> 4][state[1][2] & 0x0F]; + state[1][3] = aes_invsbox[state[1][3] >> 4][state[1][3] & 0x0F]; + state[2][0] = aes_invsbox[state[2][0] >> 4][state[2][0] & 0x0F]; + state[2][1] = aes_invsbox[state[2][1] >> 4][state[2][1] & 0x0F]; + state[2][2] = aes_invsbox[state[2][2] >> 4][state[2][2] & 0x0F]; + state[2][3] = aes_invsbox[state[2][3] >> 4][state[2][3] & 0x0F]; + state[3][0] = aes_invsbox[state[3][0] >> 4][state[3][0] & 0x0F]; + state[3][1] = aes_invsbox[state[3][1] >> 4][state[3][1] & 0x0F]; + state[3][2] = aes_invsbox[state[3][2] >> 4][state[3][2] & 0x0F]; + state[3][3] = aes_invsbox[state[3][3] >> 4][state[3][3] & 0x0F]; +} + +///////////////// +// (Inv)ShiftRows +///////////////// + +// Performs the ShiftRows step. All rows are shifted cylindrically to the left. +void ShiftRows(uint8_t state[][4]) +{ + int t; + + // Shift left by 1 + t = state[1][0]; + state[1][0] = state[1][1]; + state[1][1] = state[1][2]; + state[1][2] = state[1][3]; + state[1][3] = t; + // Shift left by 2 + t = state[2][0]; + state[2][0] = state[2][2]; + state[2][2] = t; + t = state[2][1]; + state[2][1] = state[2][3]; + state[2][3] = t; + // Shift left by 3 + t = state[3][0]; + state[3][0] = state[3][3]; + state[3][3] = state[3][2]; + state[3][2] = state[3][1]; + state[3][1] = t; +} + +// All rows are shifted cylindrically to the right. +void InvShiftRows(uint8_t state[][4]) +{ + int t; + + // Shift right by 1 + t = state[1][3]; + state[1][3] = state[1][2]; + state[1][2] = state[1][1]; + state[1][1] = state[1][0]; + state[1][0] = t; + // Shift right by 2 + t = state[2][3]; + state[2][3] = state[2][1]; + state[2][1] = t; + t = state[2][2]; + state[2][2] = state[2][0]; + state[2][0] = t; + // Shift right by 3 + t = state[3][3]; + state[3][3] = state[3][0]; + state[3][0] = state[3][1]; + state[3][1] = state[3][2]; + state[3][2] = t; +} + +///////////////// +// (Inv)MixColumns +///////////////// + +// Performs the MixColums step. The state is multiplied by itself using matrix +// multiplication in a Galios Field 2^8. All multiplication is pre-computed in a table. +// Addition is equivilent to XOR. (Must always make a copy of the column as the original +// values will be destoyed.) +void MixColumns(uint8_t state[][4]) +{ + uint8_t col[4]; + + // Column 1 + col[0] = state[0][0]; + col[1] = state[1][0]; + col[2] = state[2][0]; + col[3] = state[3][0]; + state[0][0] = gf_mul[col[0]][0]; + state[0][0] ^= gf_mul[col[1]][1]; + state[0][0] ^= col[2]; + state[0][0] ^= col[3]; + state[1][0] = col[0]; + state[1][0] ^= gf_mul[col[1]][0]; + state[1][0] ^= gf_mul[col[2]][1]; + state[1][0] ^= col[3]; + state[2][0] = col[0]; + state[2][0] ^= col[1]; + state[2][0] ^= gf_mul[col[2]][0]; + state[2][0] ^= gf_mul[col[3]][1]; + state[3][0] = gf_mul[col[0]][1]; + state[3][0] ^= col[1]; + state[3][0] ^= col[2]; + state[3][0] ^= gf_mul[col[3]][0]; + // Column 2 + col[0] = state[0][1]; + col[1] = state[1][1]; + col[2] = state[2][1]; + col[3] = state[3][1]; + state[0][1] = gf_mul[col[0]][0]; + state[0][1] ^= gf_mul[col[1]][1]; + state[0][1] ^= col[2]; + state[0][1] ^= col[3]; + state[1][1] = col[0]; + state[1][1] ^= gf_mul[col[1]][0]; + state[1][1] ^= gf_mul[col[2]][1]; + state[1][1] ^= col[3]; + state[2][1] = col[0]; + state[2][1] ^= col[1]; + state[2][1] ^= gf_mul[col[2]][0]; + state[2][1] ^= gf_mul[col[3]][1]; + state[3][1] = gf_mul[col[0]][1]; + state[3][1] ^= col[1]; + state[3][1] ^= col[2]; + state[3][1] ^= gf_mul[col[3]][0]; + // Column 3 + col[0] = state[0][2]; + col[1] = state[1][2]; + col[2] = state[2][2]; + col[3] = state[3][2]; + state[0][2] = gf_mul[col[0]][0]; + state[0][2] ^= gf_mul[col[1]][1]; + state[0][2] ^= col[2]; + state[0][2] ^= col[3]; + state[1][2] = col[0]; + state[1][2] ^= gf_mul[col[1]][0]; + state[1][2] ^= gf_mul[col[2]][1]; + state[1][2] ^= col[3]; + state[2][2] = col[0]; + state[2][2] ^= col[1]; + state[2][2] ^= gf_mul[col[2]][0]; + state[2][2] ^= gf_mul[col[3]][1]; + state[3][2] = gf_mul[col[0]][1]; + state[3][2] ^= col[1]; + state[3][2] ^= col[2]; + state[3][2] ^= gf_mul[col[3]][0]; + // Column 4 + col[0] = state[0][3]; + col[1] = state[1][3]; + col[2] = state[2][3]; + col[3] = state[3][3]; + state[0][3] = gf_mul[col[0]][0]; + state[0][3] ^= gf_mul[col[1]][1]; + state[0][3] ^= col[2]; + state[0][3] ^= col[3]; + state[1][3] = col[0]; + state[1][3] ^= gf_mul[col[1]][0]; + state[1][3] ^= gf_mul[col[2]][1]; + state[1][3] ^= col[3]; + state[2][3] = col[0]; + state[2][3] ^= col[1]; + state[2][3] ^= gf_mul[col[2]][0]; + state[2][3] ^= gf_mul[col[3]][1]; + state[3][3] = gf_mul[col[0]][1]; + state[3][3] ^= col[1]; + state[3][3] ^= col[2]; + state[3][3] ^= gf_mul[col[3]][0]; +} + +void InvMixColumns(uint8_t state[][4]) +{ + uint8_t col[4]; + + // Column 1 + col[0] = state[0][0]; + col[1] = state[1][0]; + col[2] = state[2][0]; + col[3] = state[3][0]; + state[0][0] = gf_mul[col[0]][5]; + state[0][0] ^= gf_mul[col[1]][3]; + state[0][0] ^= gf_mul[col[2]][4]; + state[0][0] ^= gf_mul[col[3]][2]; + state[1][0] = gf_mul[col[0]][2]; + state[1][0] ^= gf_mul[col[1]][5]; + state[1][0] ^= gf_mul[col[2]][3]; + state[1][0] ^= gf_mul[col[3]][4]; + state[2][0] = gf_mul[col[0]][4]; + state[2][0] ^= gf_mul[col[1]][2]; + state[2][0] ^= gf_mul[col[2]][5]; + state[2][0] ^= gf_mul[col[3]][3]; + state[3][0] = gf_mul[col[0]][3]; + state[3][0] ^= gf_mul[col[1]][4]; + state[3][0] ^= gf_mul[col[2]][2]; + state[3][0] ^= gf_mul[col[3]][5]; + // Column 2 + col[0] = state[0][1]; + col[1] = state[1][1]; + col[2] = state[2][1]; + col[3] = state[3][1]; + state[0][1] = gf_mul[col[0]][5]; + state[0][1] ^= gf_mul[col[1]][3]; + state[0][1] ^= gf_mul[col[2]][4]; + state[0][1] ^= gf_mul[col[3]][2]; + state[1][1] = gf_mul[col[0]][2]; + state[1][1] ^= gf_mul[col[1]][5]; + state[1][1] ^= gf_mul[col[2]][3]; + state[1][1] ^= gf_mul[col[3]][4]; + state[2][1] = gf_mul[col[0]][4]; + state[2][1] ^= gf_mul[col[1]][2]; + state[2][1] ^= gf_mul[col[2]][5]; + state[2][1] ^= gf_mul[col[3]][3]; + state[3][1] = gf_mul[col[0]][3]; + state[3][1] ^= gf_mul[col[1]][4]; + state[3][1] ^= gf_mul[col[2]][2]; + state[3][1] ^= gf_mul[col[3]][5]; + // Column 3 + col[0] = state[0][2]; + col[1] = state[1][2]; + col[2] = state[2][2]; + col[3] = state[3][2]; + state[0][2] = gf_mul[col[0]][5]; + state[0][2] ^= gf_mul[col[1]][3]; + state[0][2] ^= gf_mul[col[2]][4]; + state[0][2] ^= gf_mul[col[3]][2]; + state[1][2] = gf_mul[col[0]][2]; + state[1][2] ^= gf_mul[col[1]][5]; + state[1][2] ^= gf_mul[col[2]][3]; + state[1][2] ^= gf_mul[col[3]][4]; + state[2][2] = gf_mul[col[0]][4]; + state[2][2] ^= gf_mul[col[1]][2]; + state[2][2] ^= gf_mul[col[2]][5]; + state[2][2] ^= gf_mul[col[3]][3]; + state[3][2] = gf_mul[col[0]][3]; + state[3][2] ^= gf_mul[col[1]][4]; + state[3][2] ^= gf_mul[col[2]][2]; + state[3][2] ^= gf_mul[col[3]][5]; + // Column 4 + col[0] = state[0][3]; + col[1] = state[1][3]; + col[2] = state[2][3]; + col[3] = state[3][3]; + state[0][3] = gf_mul[col[0]][5]; + state[0][3] ^= gf_mul[col[1]][3]; + state[0][3] ^= gf_mul[col[2]][4]; + state[0][3] ^= gf_mul[col[3]][2]; + state[1][3] = gf_mul[col[0]][2]; + state[1][3] ^= gf_mul[col[1]][5]; + state[1][3] ^= gf_mul[col[2]][3]; + state[1][3] ^= gf_mul[col[3]][4]; + state[2][3] = gf_mul[col[0]][4]; + state[2][3] ^= gf_mul[col[1]][2]; + state[2][3] ^= gf_mul[col[2]][5]; + state[2][3] ^= gf_mul[col[3]][3]; + state[3][3] = gf_mul[col[0]][3]; + state[3][3] ^= gf_mul[col[1]][4]; + state[3][3] ^= gf_mul[col[2]][2]; + state[3][3] ^= gf_mul[col[3]][5]; +} + +///////////////// +// (En/De)Crypt +///////////////// + +void aes_encrypt(const uint8_t in[], uint8_t out[], const uint32_t key[], int keysize) +{ + uint8_t state[4][4]; + + // Copy input array (should be 16 bytes long) to a matrix (sequential bytes are ordered + // by row, not col) called "state" for processing. + // *** Implementation note: The official AES documentation references the state by + // column, then row. Accessing an element in C requires row then column. Thus, all state + // references in AES must have the column and row indexes reversed for C implementation. + state[0][0] = in[0]; + state[1][0] = in[1]; + state[2][0] = in[2]; + state[3][0] = in[3]; + state[0][1] = in[4]; + state[1][1] = in[5]; + state[2][1] = in[6]; + state[3][1] = in[7]; + state[0][2] = in[8]; + state[1][2] = in[9]; + state[2][2] = in[10]; + state[3][2] = in[11]; + state[0][3] = in[12]; + state[1][3] = in[13]; + state[2][3] = in[14]; + state[3][3] = in[15]; + + // Perform the necessary number of rounds. The round key is added first. + // The last round does not perform the MixColumns step. + AddRoundKey(state,&key[0]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[4]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[8]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[12]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[16]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[20]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[24]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[28]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[32]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[36]); + if (keysize != 128) { + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[40]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[44]); + if (keysize != 192) { + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[48]); + SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[52]); + SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[56]); + } + else { + SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[48]); + } + } + else { + SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[40]); + } + + // Copy the state to the output array. + out[0] = state[0][0]; + out[1] = state[1][0]; + out[2] = state[2][0]; + out[3] = state[3][0]; + out[4] = state[0][1]; + out[5] = state[1][1]; + out[6] = state[2][1]; + out[7] = state[3][1]; + out[8] = state[0][2]; + out[9] = state[1][2]; + out[10] = state[2][2]; + out[11] = state[3][2]; + out[12] = state[0][3]; + out[13] = state[1][3]; + out[14] = state[2][3]; + out[15] = state[3][3]; +} + +void aes_decrypt(const uint8_t in[], uint8_t out[], const uint32_t key[], int keysize) +{ + uint8_t state[4][4]; + + // Copy the input to the state. + state[0][0] = in[0]; + state[1][0] = in[1]; + state[2][0] = in[2]; + state[3][0] = in[3]; + state[0][1] = in[4]; + state[1][1] = in[5]; + state[2][1] = in[6]; + state[3][1] = in[7]; + state[0][2] = in[8]; + state[1][2] = in[9]; + state[2][2] = in[10]; + state[3][2] = in[11]; + state[0][3] = in[12]; + state[1][3] = in[13]; + state[2][3] = in[14]; + state[3][3] = in[15]; + + // Perform the necessary number of rounds. The round key is added first. + // The last round does not perform the MixColumns step. + if (keysize > 128) { + if (keysize > 192) { + AddRoundKey(state,&key[56]); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[52]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[48]);InvMixColumns(state); + } + else { + AddRoundKey(state,&key[48]); + } + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[44]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[40]);InvMixColumns(state); + } + else { + AddRoundKey(state,&key[40]); + } + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[36]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[32]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[28]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[24]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[20]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[16]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[12]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[8]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[4]);InvMixColumns(state); + InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[0]); + + // Copy the state to the output array. + out[0] = state[0][0]; + out[1] = state[1][0]; + out[2] = state[2][0]; + out[3] = state[3][0]; + out[4] = state[0][1]; + out[5] = state[1][1]; + out[6] = state[2][1]; + out[7] = state[3][1]; + out[8] = state[0][2]; + out[9] = state[1][2]; + out[10] = state[2][2]; + out[11] = state[3][2]; + out[12] = state[0][3]; + out[13] = state[1][3]; + out[14] = state[2][3]; + out[15] = state[3][3]; +} + +/****************** +** MITOSIS AES ECB INTERFACE FUNCTIONS +*******************/ + +bool mitosis_aes_ecb_init(mitosis_aes_ecb_context_t* state) { + return true; +} + +bool mitosis_aes_ecb_encrypt(mitosis_aes_ecb_context_t* state) { + uint32_t key_schedule[60]; + aes_key_setup(state->key, key_schedule, 128); + aes_encrypt(state->plaintext, state->ciphertext, key_schedule, 128); + return true; +} diff --git a/mitosis-crypto/test/main.c b/mitosis-crypto/test/main.c new file mode 100644 index 0000000..7bc70c8 --- /dev/null +++ b/mitosis-crypto/test/main.c @@ -0,0 +1,1145 @@ +#include +#include +#include +#include +#include +#include "mitosis-crypto.h" + +typedef struct _hmac_sha256_vector { + uint8_t key[131]; + size_t key_len; + uint8_t data[153]; + size_t data_len; + uint8_t expected[MITOSIS_HMAC_OUTPUT_SIZE]; +} hmac_sha256_test_vector; + +typedef struct _aes_cmac_test_vector { + uint8_t key[AES_BLOCK_SIZE]; + uint8_t data[65]; + size_t data_len; + uint8_t expected[MITOSIS_CMAC_OUTPUT_SIZE]; + size_t expected_len; +} aes_cmac_test_vector; + +typedef struct _ckdf_aes128_extract_vector { + uint8_t ikm[16]; + uint8_t ikm_len; + uint8_t salt[16]; + uint8_t salt_len; + uint8_t expected_prk[16]; +} ckdf_aes128_extract_test_vector; + +typedef struct _ckdf_aes128_expand_vector { + uint8_t prk[16]; + uint8_t info[11]; + uint8_t info_len; + uint8_t expected_okm[256]; + uint32_t L; +} ckdf_aes128_expand_test_vector; + +typedef struct _hkdf_sha256_vector { + uint8_t ikm[80]; + uint8_t ikm_len; + uint8_t salt[80]; + uint8_t salt_len; + uint8_t info[80]; + uint8_t info_len; + uint8_t expected_prk[32]; + uint8_t expected_okm[82]; + uint8_t L; +} hkdf_sha256_test_vector; + +typedef struct _aes_ctr_vector { + uint8_t key[AES_BLOCK_SIZE]; + uint8_t nonce[AES_BLOCK_SIZE]; + uint8_t expected_encrypted_counter[AES_BLOCK_SIZE]; + uint8_t plaintext[AES_BLOCK_SIZE]; + uint8_t expected_ciphertext[AES_BLOCK_SIZE]; +} aes_ctr_test_vector; + +#define RUN_TEST_LOG(test) \ + bool test ##_result = test(); \ + if(! test ##_result) { \ + printf("%s failed!\n", #test); \ + ++failures; \ + } \ + result &= test ##_result; \ + + +void print_hex(const char* label, const uint8_t* bytes, size_t len) { + for(int idx = 0; idx < len; ++idx) { + if(idx == 0) { + printf("%s:\t%02x ", label, bytes[idx]); + } else if (idx == len - 1) { + printf("%02x\n", bytes[idx]); + } else { + printf("%02x ", bytes[idx]); + } + } +} + +bool compare_expected(const uint8_t* actual, const uint8_t* expected, size_t len, const char* func, const char* label) { + if(memcmp(actual, expected, len) != 0) { + printf("%s: expected %s doesn't match actual\n", func, label); + print_hex("Actual ", actual, len); + print_hex("Expected", expected, len); + int idx = 0; + while(actual[idx] == expected[idx]) ++idx; + printf("Index %d doesn't match (%02x actual vs. %02x expected)\n", idx, actual[idx], expected[idx]); + return false; + } + return true; +} + +bool hmac_sha256_kat() { + hmac_sha256_test_vector test_cases[] = { + { + { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b + }, + 20, + "Hi There", + 8, + { + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, + 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, + 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, + 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 + } + }, + { + "Jefe", + 4, + "what do ya want for nothing?", + 28, + { + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, + 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, + 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 + } + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa + }, + 131, + "Test Using Larger Than Block-Size Key - Hash Key First", + 54, + { + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, + 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, + 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, + 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 + } + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa + }, + 131, + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", + 152, + { + 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, + 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, + 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, + 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 + } + }, + }; + mitosis_hmac_context_t state = { 0 }; + + for(int test_idx = 0; test_idx < sizeof(test_cases)/sizeof(test_cases[0]); ++test_idx) { + hmac_sha256_test_vector* test_case = &test_cases[test_idx]; + + uint8_t* key = test_case->key; + if(!mitosis_hmac_init(&state, key, test_case->key_len)) { + printf("%s: failed HMAC init\n", __func__); + return false; + } + + uint8_t* data = test_case->data; + if(!mitosis_hmac_hash(&state, data, test_case->data_len)) { + printf("%s: failed HMAC hash\n", __func__); + return false; + } + uint8_t result[MITOSIS_HMAC_OUTPUT_SIZE] = { 0 }; + if(!mitosis_hmac_complete(&state, result)) { + printf("%s: failed HMAC complete\n", __func__); + return false; + } + + uint8_t* expected = test_case->expected; + if(!compare_expected(result, expected, sizeof(result), __func__, "HMAC")) { + return false; + } + } + return true; +} + +bool cmac_kat() { + // Keys for sub-key verification. + uint8_t key[] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }; + uint8_t key0[] = { + 0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3, + 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f + }; + uint8_t key1[] = { + 0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66, + 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde + }; + uint8_t key2[] = { + 0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc, + 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b + }; + + aes_cmac_test_vector test_cases[] = { + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + {0}, + 0, + { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }, + 16 + }, + { + { + 0x55, 0x34, 0x21, 0xad, 0x3f, 0x58, 0x4d, 0x9f, + 0x4c, 0xce, 0x5a, 0x6d, 0x3f, 0x18, 0x4e, 0x57 + }, + {0}, + 0, + { + 0x99, 0x5a, 0x02, 0xbd, 0xca, 0x8a, 0x07, 0x00, + 0x2c, 0xe5, 0x8c, 0xd7, 0x50, 0x5f, 0xaa + }, + 15 + }, + { + { + 0x00, 0x34, 0x1f, 0xb8, 0x12, 0x09, 0xc2, 0xab, + 0xdf, 0xe3, 0xa9, 0xd6, 0x07, 0xb9, 0x82, 0x77 + }, + { + 0x4c, 0xf0, 0x5b + }, + 3, + { + 0x3a, 0x1f, 0x08, 0xb3, 0x04, 0x7f, 0x6a, 0x1c, + 0x1f, 0x0e, 0x65, 0x66, 0xaa, 0xdc, 0x0f, 0x29 + }, + 16 + }, + { + { + 0xc9, 0x8f, 0xc3, 0x41, 0x64, 0x57, 0xd9, 0xee, + 0xd0, 0xfa, 0x7a, 0xb1, 0xdc, 0x1b, 0x8a, 0x6a + }, + { + 0x65, 0xd6, 0x2d, 0x89, 0x6e, 0xd6, 0x6f + }, + 7, + { + 0x56, 0x32, 0x00, 0x72, 0xe5, 0x2d, 0x40, 0x40, + 0xe2, 0x7b, 0x8a, 0x5a, 0x0b, 0x6e, 0x33, 0xb0 + }, + 16 + }, + { + { + 0x1b, 0x31, 0x63, 0xe2, 0xd3, 0xa4, 0x71, 0xb9, + 0x82, 0x35, 0x25, 0xab, 0xc7, 0x54, 0x3c, 0x4c + }, + { + 0xca, 0xda, 0x03, 0xe8, 0xc9, 0x67, 0xf9, 0x73, + 0x2a, 0x81 + }, + 10, + { + 0x53, 0x70, 0x2f, 0xa9, 0x8e, 0x6f, 0x9a, 0x19 + }, + 8 + }, + { + { + 0xc7, 0x25, 0xd9, 0xef, 0x0d, 0xc6, 0xcf, 0xca, + 0x84, 0x86, 0x5c, 0xf5, 0xcc, 0x91, 0xd4, 0x03 + }, + { + 0xa8, 0x54, 0xd2, 0xda, 0x46, 0xaf, 0xb7, 0x7a, + 0x78, 0x7f, 0x06, 0x06, 0xa6, 0x9c, 0xf4 + }, + 15, + { + 0x20, 0xe5, 0xc7, 0x78, 0x91, 0xe4, 0x2f, 0x68, + 0x27, 0x65, 0xa3, 0xd2, 0x1f, 0x91, 0x14, 0xd2 + }, + 16 + }, + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, + 16, + { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, + 16 + }, + { + { + 0xe3, 0x9c, 0x6f, 0xf1, 0xad, 0x22, 0x79, 0x3d, + 0xc5, 0x25, 0xd3, 0x4e, 0x7d, 0x7e, 0x7d, 0x6d + }, + { + 0xf2, 0x38, 0x77, 0xb7, 0x74, 0x71, 0xc8, 0x0d, + 0xd5, 0x65, 0xec, 0xe7, 0xb2, 0xca, 0x0b, 0xdd + }, + 16, + { + 0x1a, 0x5c, 0x33, 0xd5, 0x4e, 0x6d, 0xe6, 0xd9, + 0xfa, 0x61, 0xcb, 0x96, 0x36, 0x05, 0x3f + }, + 15 + }, + { + { + 0xa1, 0x7c, 0x96, 0xfa, 0xa6, 0x4c, 0xca, 0xb2, + 0xc4, 0x5d, 0x93, 0xa0, 0x63, 0x89, 0x36, 0x81 + }, + { + 0xf2, 0x68, 0xc7, 0xd4, 0xdf, 0x15, 0x9e, 0xf4, + 0xd2, 0x84, 0xbe, 0x92, 0x42, 0x9b, 0x80, 0x72, + 0x6e, 0xf1, 0x34, 0x73, 0x4e, 0xeb, 0xb9, 0xcc, + 0xc9, 0x25, 0x4c, 0x96, 0x28, 0x13, 0x9e, 0x8b + }, + 32, + { + 0xb7, 0x3d, 0xfe, 0x7c, 0x49, 0x1b, 0x2d, 0x69, + 0x2e, 0x17, 0x04, 0x81, 0x97, 0x1e, 0x4e + }, + 15 + }, + { + { + 0xa0, 0xc3, 0x34, 0xff, 0x35, 0x01, 0xc9, 0x9a, + 0x9d, 0x5f, 0x26, 0x60, 0xf4, 0xa2, 0xcc, 0x5f + }, + { + 0xb4, 0x69, 0x3a, 0x2a, 0xa1, 0x1c, 0xf9, 0xa5, + 0x44, 0x2f, 0x08, 0xdf, 0xa7, 0x18, 0x59, 0x0f, + 0xef, 0xf8, 0xd3, 0x8f, 0xdf, 0x15, 0xf8, 0xee, + 0x9d, 0x8a, 0xc5, 0x41, 0xb9, 0x3d, 0xd9, 0xb9, + 0x6b + }, + 33, + { + 0x6d, 0x4b, 0xf5, 0x0d, 0x3a, 0x13, 0xa2, 0x6d, + 0x9d, 0xc7, 0x56, 0x6d, 0xee, 0x12, 0x23 + }, + 15 + }, + { + { + 0x1f, 0x07, 0x69, 0xa7, 0xae, 0x82, 0xbd, 0x98, + 0x56, 0x61, 0xe0, 0x31, 0xc4, 0xa8, 0x92, 0xc1 + }, + { + 0xa0, 0xa6, 0x45, 0x82, 0xef, 0xf0, 0x02, 0xbb, + 0x34, 0x8d, 0x27, 0x98, 0xf6, 0x78, 0x12, 0x10, + 0x23, 0x77, 0xc3, 0x34, 0x54, 0x4e, 0x3e, 0x06, + 0x53, 0x32, 0x31, 0x8d, 0xdb, 0x80, 0xd7, 0x29, + 0x9e, 0xaf, 0x1c, 0x25, 0x8c + }, + 37, + { + 0x3a, 0xc1, 0xf8, 0x0a, 0xee, 0x7d, 0x9e, 0xc5, + 0x28, 0x43, 0x73, 0xe4, 0x3a, 0x56, 0xd7 + }, + 15 + }, + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 + }, + 40, + { + 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, + 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 + }, + 16 + }, + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }, + 64, + { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + }, + 16 + }, + { + { + 0xc9, 0x8f, 0xc3, 0x41, 0x64, 0x57, 0xd9, 0xee, + 0xd0, 0xfa, 0x7a, 0xb1, 0xdc, 0x1b, 0x8a, 0x6a + }, + { + 0x19, 0x0a, 0xe5, 0x7a, 0xb8, 0xbb, 0x70, 0x46, + 0x4e, 0x4a, 0x10, 0xc1, 0x12, 0xa5, 0x4c, 0x64, + 0x64, 0x38, 0x30, 0x1b, 0x56, 0x62, 0xf3, 0x53, + 0x6c, 0x26, 0xd7, 0x54, 0xa0, 0x24, 0x51, 0xd1, + 0xa9, 0xc7, 0x6a, 0xbd, 0x7d, 0xbf, 0x65, 0x61, + 0x15, 0xb2, 0xa2, 0xac, 0x70, 0x2e, 0xc2, 0xca, + 0xda, 0xe3, 0x0c, 0xf8, 0x6e, 0x0f, 0x0f, 0x96, + 0xda, 0x39, 0x89, 0x7d, 0x62, 0x22, 0x88, 0x94, + 0x28 + }, + 65, + { + 0x1b, 0xea, 0x94, 0xa4, 0x57, 0xb2, 0x88, 0x6e, + 0x90, 0x98, 0xbf, 0x3d, 0xed, 0x93, 0x2a, 0x3a + }, + 16 + } + }; + uint8_t output[AES_BLOCK_SIZE]; + mitosis_cmac_context_t context; + bool result = mitosis_cmac_init(&context, key, sizeof(key)); + if (!result) { + printf("%s: failed to initialize CMAC\n", __func__); + return result; + } + + // Verify sub-key generation + if (!compare_expected(context.ecb.ciphertext, key0, sizeof(key0), __func__, "CMAC Key0")) { + return false; + } + if (!compare_expected(context.key1, key1, sizeof(key1), __func__, "CMAC Key1")) { + return false; + } + if (!compare_expected(context.key2, key2, sizeof(key2), __func__, "CMAC Key2")) { + return false; + } + + for (int test_idx = 0; test_idx < sizeof(test_cases)/sizeof(test_cases[0]); ++test_idx) { + aes_cmac_test_vector* test_case = &test_cases[test_idx]; + + result = mitosis_cmac_init(&context, test_case->key, sizeof(test_case->key)); + if (!result) { + printf("%s: failed to initialize CMAC\n", __func__); + return result; + } + + result = mitosis_cmac_compute(&context, test_case->data, test_case->data_len, output); + if (!result) { + printf("%s: failed to compute CMAC\n", __func__); + return result; + } + + if (!compare_expected(output, test_case->expected, test_case->expected_len, __func__, "CMAC")) { + return false; + } + } + + return result; +} + +bool cmac_reuse_kat() { + aes_cmac_test_vector test_data = { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, + 16, + { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, + 16 + }; + + uint8_t output[AES_BLOCK_SIZE]; + mitosis_cmac_context_t context; + aes_cmac_test_vector *test_case = &test_data; + bool result = false; + + result = mitosis_cmac_init(&context, test_case->key, sizeof(test_case->key)); + if (!result) { + printf("%s: failed to initialize CMAC\n", __func__); + return result; + } + + result = mitosis_cmac_compute(&context, test_case->data, test_case->data_len, output); + if (!result) { + printf("%s: failed to compute CMAC\n", __func__); + return result; + } + + if (!compare_expected(output, test_case->expected, test_case->expected_len, __func__, "first CMAC")) { + return false; + } + + result = mitosis_cmac_compute(&context, test_case->data, test_case->data_len, output); + if (!result) { + printf("%s: failed to compute CMAC\n", __func__); + return result; + } + + if (!compare_expected(output, test_case->expected, test_case->expected_len, __func__, "second CMAC")) { + return false; + } + return result; +} + + +bool ckdf_extract_kat() { + + ckdf_aes128_extract_test_vector test_cases[] = + { + { + {0}, + 0, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + 16, + { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + } + }, + { + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, + 16, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + 16, + { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + } + }, + { + { + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x20, 0x6b, + 0x65, 0x79 + }, + 10, + {0}, + 0, + { + 0x6f, 0x79, 0xb4, 0x01, 0xea, 0x76, 0x1a, 0x01, + 0x00, 0xb7, 0xca, 0x60, 0xc1, 0x78, 0xb6, 0x9d + } + } + }; + + bool result = true; + for(int test_idx = 0; test_idx < sizeof(test_cases)/sizeof(test_cases[0]); ++test_idx) { + ckdf_aes128_extract_test_vector* test_case = &test_cases[test_idx]; + uint8_t prk[AES_BLOCK_SIZE]; + + if(!mitosis_ckdf_extract(test_case->ikm, test_case->ikm_len, test_case->salt, test_case->salt_len, prk)) { + printf("%s: mitosis_ckdf_extract failed!\n", __func__); + return false; + } + if(!compare_expected(prk, test_case->expected_prk, sizeof(prk), __func__, "PRK")) { + return false; + } + } + return result; +} + +bool ckdf_expand_kat() { + + ckdf_aes128_expand_test_vector test_cases[] = + { + { + { + 0x6f, 0x79, 0xb4, 0x01, 0xea, 0x76, 0x1a, 0x01, + 0x00, 0xb7, 0xca, 0x60, 0xc1, 0x78, 0xb6, 0x9d + }, + {0}, + 0, + { + 0x92, 0x2d, 0xa3, 0x1d, 0x7e, 0x19, 0x55, 0xf0, + 0x6a, 0x56, 0x46, 0x4b, 0x5f, 0xeb, 0x70, 0x32, + 0x8f, 0x7e, 0x6f, 0x60, 0xaa, 0xea, 0x57, 0x35, + 0xc2, 0x77, 0x2e, 0x33, 0x17, 0xd0, 0xa2, 0x88 + }, + 32 + }, + { + { + 0x6f, 0x79, 0xb4, 0x01, 0xea, 0x76, 0x1a, 0x01, + 0x00, 0xb7, 0xca, 0x60, 0xc1, 0x78, 0xb6, 0x9d + }, + { + 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67 + }, + 11, + { + 0x61, 0x74, 0xe6, 0x72, 0x12, 0xe1, 0x23, 0x4b, + 0x6e, 0x05, 0xbf, 0xd3, 0x10, 0x43, 0x42, 0x2c, + 0xdf, 0x1e, 0x34, 0xcd, 0x29, 0xee, 0x09, 0xf5, + 0xbd, 0x5e, 0xdb, 0x90, 0xdb, 0x39, 0xdc, 0xd4, + 0xc3, 0x01, 0xe8, 0x73, 0xd9, 0x1a, 0xcb, 0xd5, + 0x33, 0x3c, 0x87, 0x01, 0x6d, 0xda, 0x05, 0xbe, + 0x3a, 0x8f, 0xaa, 0xde, 0x2c, 0x39, 0x92, 0xc8, + 0xf3, 0x22, 0x1f, 0x05, 0x5e, 0xfb, 0x3b, 0x51, + 0x76, 0xdb, 0xbe, 0x76, 0x90, 0xcb, 0x44, 0x00, + 0xf7, 0x37, 0x29, 0x8d, 0x63, 0x8b, 0x80, 0x26, + 0xd5, 0x27, 0xc1, 0xe5, 0x81, 0xf4, 0xe3, 0x7d, + 0xa0, 0x49, 0x9c, 0x31, 0xab, 0xfd, 0x89, 0x08, + 0x20, 0x71, 0x60, 0xde, 0x34, 0x3c, 0x12, 0x6e, + 0xcb, 0x46, 0x0e, 0x38, 0x84, 0x81, 0xfa, 0x9f, + 0x73, 0x39, 0x1f, 0xe6, 0x35, 0xa0, 0xe4, 0xb6, + 0xcd, 0xe3, 0xd3, 0x85, 0x78, 0xbc, 0xb8, 0xb5, + 0x5a, 0x60, 0x95, 0x2b, 0xac, 0x6f, 0x84, 0x0f, + 0xd8, 0x7c, 0x39, 0x7a, 0xc2, 0x47, 0x79, 0x92, + 0xac, 0x6c, 0xbd, 0x64, 0x31, 0x00, 0xe3, 0xca, + 0xd6, 0x60, 0x37, 0x3b, 0x44, 0xe2, 0xfc, 0x0e, + 0x48, 0x67, 0xb1, 0x5a, 0xcd, 0x9a, 0x07, 0x0a, + 0x32, 0x29, 0xee, 0x40, 0x76, 0xbf, 0x98, 0x51, + 0x7c, 0xcc, 0x65, 0x6f, 0x5b, 0xf1, 0xf8, 0xbb, + 0x41, 0xce, 0x7e, 0x2d, 0x48, 0xdb, 0x67, 0x0f, + 0x1b, 0x29, 0x21, 0xee, 0x46, 0x2d, 0x9c, 0xf1, + 0x98, 0x7e, 0xb9, 0x83, 0xe5, 0xc2, 0xce, 0x4e, + 0xa9, 0xce, 0xea, 0x10, 0xc3, 0x01, 0xdc, 0xca, + 0xf1, 0x6c, 0x4b, 0x57, 0x67, 0xda, 0xa4, 0xbf, + 0x6e, 0xcc, 0x81, 0x61, 0x77, 0xda, 0x31, 0xa5, + 0x9a, 0x9b, 0x19, 0x72, 0x86, 0x25, 0x9b, 0xd6, + 0x59, 0x8d, 0x28, 0x74, 0xa4, 0xf6, 0x05, 0xfb, + 0x87, 0x7b, 0xee, 0x1b, 0x55, 0x29, 0x87, 0x3f + }, + 256 + } + }; + + uint8_t* okm = NULL; + bool result = true; + for(int test_idx = 0; test_idx < sizeof(test_cases)/sizeof(test_cases[0]); ++test_idx) { + ckdf_aes128_expand_test_vector* test_case = &test_cases[test_idx]; + okm = malloc(test_case->L); + + if(!mitosis_ckdf_expand(test_case->prk, sizeof(test_case->prk), test_case->info, test_case->info_len, okm, test_case->L)) { + printf("%s: mitosis_ckdf_expand failed!\n", __func__); + result = false; + goto error; + } + if(!compare_expected(okm, test_case->expected_okm, test_case->L, __func__, "OKM")) { + result = false; + goto error; + } + free(okm); + okm = NULL; + } +error: + if(okm != NULL) { + free(okm); + } + return result; +} + +bool hkdf_kat() { + hkdf_sha256_test_vector test_cases[] = { + { + { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }, + 22, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }, + 13, + { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }, + 10, + { + 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, + 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, + 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, + 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5 + }, + { + 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, + 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, + 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, + 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, + 0x58, 0x65 + }, + 42 + }, + { + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }, + 80, + { + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, + 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, + 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, + 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf + }, + 80, + { + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }, + 80, + { + 0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a, + 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c, + 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01, + 0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44 + }, + { + 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, + 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, + 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, + 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, + 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, + 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, + 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, + 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, + 0x1d, 0x87 + }, + 82 + }, + { + { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }, + 22, + { 0 }, + 0, + { 0 }, + 0, + { + 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, + 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf, + 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, + 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04 + }, + { + 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, + 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, + 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, + 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, + 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, + 0x96, 0xc8 + }, + 42 + }, + { + { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }, + 22, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }, + 13, + { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }, + 10, + { + 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, + 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, + 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, + 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5 + }, + { + 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, + 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90 + }, + 16 + } + }; + + uint8_t* okm = NULL; + bool result = true; + for(int test_idx = 0; test_idx < sizeof(test_cases)/sizeof(test_cases[0]); ++test_idx) { + hkdf_sha256_test_vector* test_case = &test_cases[test_idx]; + uint8_t prk[MITOSIS_HMAC_OUTPUT_SIZE]; + okm = malloc(test_case->L); + + if(!mitosis_hkdf_extract(test_case->ikm, test_case->ikm_len, test_case->salt, test_case->salt_len, prk)) { + printf("%s: mitosis_hkdf_extract failed!\n", __func__); + result = false; + goto error; + } + if(!compare_expected(prk, test_case->expected_prk, sizeof(prk), __func__, "PRK")) { + result = false; + goto error; + } + if(!mitosis_hkdf_expand(prk, sizeof(prk), test_case->info, test_case->info_len, okm, test_case->L)) { + printf("%s: mitosis_hkdf_expand failed!\n", __func__); + result = false; + goto error; + } + if(!compare_expected(okm, test_case->expected_okm, test_case->L, __func__, "OKM")) { + result = false; + goto error; + } + free(okm); + okm = NULL; + } +error: + if(okm != NULL) { + free(okm); + } + return result; +} + +bool aes_ctr_kat() { + aes_ctr_test_vector test_cases[] = { + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, // key + { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }, // nonce + { + 0xec, 0x8c, 0xdf, 0x73, 0x98, 0x60, 0x7c, 0xb0, + 0xf2, 0xd2, 0x16, 0x75, 0xea, 0x9e, 0xa1, 0xe4 + }, // encrypted counter + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, // ctr plaintext + { + 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce + } // expected ctr ciphertext + }, // test case 1 + { + "my very eager mo", // key + "ther just served", // nonce + { + 0xa0, 0xf3, 0x59, 0x59, 0x0a, 0xad, 0x4e, 0xcd, + 0x1b, 0x70, 0x20, 0x38, 0x14, 0xf9, 0x6d, 0x69 + }, // encrypted counter + " us nine pizzas!", // ctr plaintext + { + 0x80, 0x86, 0x2a, 0x79, 0x64, 0xc4, 0x20, 0xa8, + 0x3b, 0x00, 0x49, 0x42, 0x6e, 0x98, 0x1e, 0x48 + } // expected ctr ciphertext + } // test case 2 + }; + bool result = true; + mitosis_encrypt_context_t context; + + for(int test_idx = 0; test_idx < sizeof(test_cases)/sizeof(test_cases[0]); ++test_idx) { + aes_ctr_test_vector* test_case = &test_cases[test_idx]; + uint8_t output[AES_BLOCK_SIZE] = { 0 }; + + result = mitosis_aes_ctr_init(test_case->key, test_case->nonce, &context); + if(!result) { + printf("%s: mitosis_aes_ctr_init failed!\n", __func__); + return false; + } + + // Test encryption + result = mitosis_aes_ctr_encrypt(&context, sizeof(output), test_case->plaintext, output); + if(!result) { + printf("%s: mitosis_aes_ctr_encrypt failed!\n", __func__); + return false; + } + if(!compare_expected(context.ecb.ciphertext, test_case->expected_encrypted_counter, sizeof(test_case->expected_encrypted_counter), __func__, "encrypted counter")) { + return false; + } + if(!compare_expected(output, test_case->expected_ciphertext, sizeof(output), __func__, "encrypted plaintext")) { + return false; + } + + // Test decryption + result = mitosis_aes_ctr_decrypt(&context, sizeof(output), test_case->expected_ciphertext, output); + if(!result) { + printf("%s: mitosis_aes_ctr_decrypt failed!\n", __func__); + return false; + } + if(!compare_expected(context.ecb.ciphertext, test_case->expected_encrypted_counter, sizeof(test_case->expected_encrypted_counter), __func__, "encrypted counter")) { + return false; + } + if(!compare_expected(output, test_case->plaintext, sizeof(output), __func__, "decrypted plaintext")) { + return false; + } + + // Test in-place encryption/decryption + memcpy(output, test_case->plaintext, sizeof(output)); + result = mitosis_aes_ctr_encrypt(&context, sizeof(output), output, output); + if(!result) { + printf("%s: mitosis_aes_ctr_encrypt in-place failed!\n", __func__); + return false; + } + if(!compare_expected(output, test_case->expected_ciphertext, sizeof(output), __func__, "encrypted plaintext in-place")) { + return false; + } + result = mitosis_aes_ctr_decrypt(&context, sizeof(output), output, output); + if(!result) { + printf("%s: mitosis_aes_ctr_decrypt in-place failed!\n", __func__); + return false; + } + if(!compare_expected(output, test_case->plaintext, sizeof(output), __func__, "decrypted plaintext in-place")) { + return false; + } + } + return result; +} + +bool verify_key_generation() { + mitosis_crypto_context_t context; + bool result = true; + + result = mitosis_crypto_init(&context, true); + if(!result) { + printf("%s: %s mitosis_crypto_init failed!\n", __func__, "left"); + return false; + } + + print_hex(" left key", context.encrypt.ctr.key, sizeof(context.encrypt.ctr.key)); + print_hex("left cmac key 1", context.cmac.key1, sizeof(context.cmac.key1)); + print_hex("left cmac key 2", context.cmac.key2, sizeof(context.cmac.key2)); + print_hex(" left nonce", context.encrypt.ctr.iv_bytes, sizeof(context.encrypt.ctr.iv_bytes)); + + result = mitosis_crypto_init(&context, false); + if(!result) { + printf("\n%s: %s mitosis_crypto_init failed!\n", __func__, "right"); + return false; + } + + print_hex("\n right key", context.encrypt.ctr.key, sizeof(context.encrypt.ctr.key)); + print_hex("right cmac key 1", context.cmac.key1, sizeof(context.cmac.key1)); + print_hex("right cmac key 2", context.cmac.key2, sizeof(context.cmac.key2)); + print_hex(" right nonce", context.encrypt.ctr.iv_bytes, sizeof(context.encrypt.ctr.iv_bytes)); + + return result; +} + +bool verify_key_encryption_decryption_test() { + bool result = true; + uint8_t data[] = {'a', 'b', 'c'}; + + mitosis_crypto_context_t keys; + for(int i = 0; i < 2; ++i) { + char* key_half = (i ? "left" : "right"); + + result = mitosis_crypto_init(&keys, i); + if(!result) { + printf("%s: %s mitosis_crypto_init failed!\n", __func__, key_half); + return false; + } + + result = mitosis_aes_ctr_encrypt(&(keys.encrypt), sizeof(data), data, data); + if(!result) { + printf("%s: %s mitosis_aes_ctr_encrypt in-place failed!\n", __func__, key_half); + return false; + } + + result = mitosis_aes_ctr_decrypt(&(keys.encrypt), sizeof(data), data, data); + if(!result) { + printf("%s: %s mitosis_aes_ctr_decrypt in-place failed!\n", __func__, key_half); + return false; + } + + if(!compare_expected(data, (uint8_t*)"abc", sizeof(data), __func__, key_half)) { + return false; + } + } + + return result; +} + +bool end_to_end_test() { + bool result = true; + const uint8_t verify[] = { 'a', 0xaa, 'c', 0x55 }; + const uint32_t counter = 0xe7b00a25; + mitosis_crypto_data_payload_t data; + uint8_t mac_scratch[MITOSIS_CMAC_OUTPUT_SIZE]; + + memcpy(data.data, verify, sizeof(verify)); + data.counter = counter; + + mitosis_crypto_context_t keys; + for(int i = 0; i < 2; ++i) { + char* key_half = (i ? "left" : "right"); + + result = mitosis_crypto_init(&keys, i); + if(!result) { + printf("%s: %s mitosis_crypto_init failed!\n", __func__, key_half); + return false; + } + + keys.encrypt.ctr.iv.counter = data.counter; + + result = mitosis_aes_ctr_encrypt(&keys.encrypt, sizeof(data.data), data.data, data.data); + if(!result) { + printf("%s: %s mitosis_aes_ctr_encrypt in-place failed!\n", __func__, key_half); + return false; + } + + result = mitosis_cmac_compute(&keys.cmac, data.payload, sizeof(data.payload), data.mac); + if(!result) { + printf("%s: %s mitosis_cmac_compute failed!\n", __func__, key_half); + return false; + } + + // reinitialize keys to clear any state they had. + result = mitosis_crypto_init(&keys, i); + if(!result) { + printf("%s: second %s mitosis_crypto_init failed!\n", __func__, key_half); + return false; + } + + result = mitosis_cmac_compute(&keys.cmac, data.payload, sizeof(data.payload), mac_scratch); + if(!result) { + printf("%s: second %s mitosis_cmac_compute failed!\n", __func__, key_half); + return false; + } + + if(!compare_expected(data.mac, mac_scratch, sizeof(data.mac), __func__, key_half)) { + printf("%s: %s mac verify failed!\n", __func__, key_half); + return false; + } + + keys.encrypt.ctr.iv.counter = data.counter; + + result = mitosis_aes_ctr_decrypt(&(keys.encrypt), sizeof(data.data), data.data, data.data); + if(!result) { + printf("%s: %s mitosis_aes_ctr_decrypt in-place failed!\n", __func__, key_half); + return false; + } + + if(!compare_expected(data.data, verify, sizeof(verify), __func__, key_half)) { + printf("%s: %s data verify failed!\n", __func__, key_half); + return false; + } + } + + return result; +} + +int main(int argc, char** argv) { + bool result = true; + int failures = 0; + + RUN_TEST_LOG(hmac_sha256_kat); + RUN_TEST_LOG(cmac_kat); + RUN_TEST_LOG(cmac_reuse_kat); + RUN_TEST_LOG(ckdf_extract_kat); + RUN_TEST_LOG(ckdf_expand_kat); + RUN_TEST_LOG(hkdf_kat); + RUN_TEST_LOG(aes_ctr_kat); + RUN_TEST_LOG(verify_key_generation); + RUN_TEST_LOG(verify_key_encryption_decryption_test); + RUN_TEST_LOG(end_to_end_test); + + if (result) { + printf("All tests passed! :)\n"); + } else { + printf("%d failures! :(\n", failures); + } + return 0; +} diff --git a/mitosis-keyboard-basic/custom/armgcc/Makefile b/mitosis-keyboard-basic/custom/armgcc/Makefile index 71ad644..3a71935 100644 --- a/mitosis-keyboard-basic/custom/armgcc/Makefile +++ b/mitosis-keyboard-basic/custom/armgcc/Makefile @@ -3,7 +3,7 @@ PROJECT_NAME := mitosis-keyboard-basic export OUTPUT_FILENAME #MAKEFILE_NAME := $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) MAKEFILE_NAME := $(MAKEFILE_LIST) -MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) +MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) TEMPLATE_PATH = ../../../../components/toolchain/gcc ifeq ($(OS),Windows_NT) @@ -17,7 +17,7 @@ RM := rm -rf #echo suspend ifeq ("$(VERBOSE)","1") -NO_ECHO := +NO_ECHO := else NO_ECHO := @ endif @@ -38,6 +38,14 @@ remduplicates = $(strip $(if $1,$(firstword $1) $(call remduplicates,$(filter-ou #source common to all targets C_SOURCE_FILES += \ $(abspath ../../../../components/toolchain/system_nrf51.c) \ +$(abspath ../../../../components/libraries/sha256/sha256.c) \ +$(abspath ../../../mitosis-crypto/mitosis-hmac.c) \ +$(abspath ../../../mitosis-crypto/mitosis-hkdf.c) \ +$(abspath ../../../mitosis-crypto/mitosis-keys.c) \ +$(abspath ../../../mitosis-crypto/mitosis-aes-ecb.c) \ +$(abspath ../../../mitosis-crypto/mitosis-cmac.c) \ +$(abspath ../../../mitosis-crypto/mitosis-ckdf.c) \ +$(abspath ../../../mitosis-crypto/mitosis-aes-ctr.c) \ $(abspath ../../main.c) \ $(abspath ../../../../components/drivers_nrf/delay/nrf_delay.c) \ $(abspath ../../../../components/drivers_nrf/clock/nrf_drv_clock.c) \ @@ -54,10 +62,12 @@ LIBS = $(abspath ../../../../components/properitary_rf/gzll/gcc/gzll_gcc.a) #includes common to all targets INC_PATHS = -I$(abspath ../../config) +INC_PATHS += -I$(abspath ../../../mitosis-crypto) INC_PATHS += -I$(abspath ../../../../components/device) INC_PATHS += -I$(abspath ../../../../components/toolchain/CMSIS/Include) INC_PATHS += -I$(abspath ../../../../components/properitary_rf/gzll) INC_PATHS += -I$(abspath ../../../../components/drivers_nrf/hal) +INC_PATHS += -I$(abspath ../../../../components/libraries/sha256) INC_PATHS += -I$(abspath ../../../../components/toolchain/gcc) INC_PATHS += -I$(abspath ../../../../components/drivers_nrf/delay) INC_PATHS += -I$(abspath ../../../../examples/bsp) @@ -90,7 +100,7 @@ CFLAGS += -Wno-unused-variable CFLAGS += -mfloat-abi=soft # keep every function in separate section. This will allow linker to dump unused functions CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing -CFLAGS += -fno-builtin --short-enums +CFLAGS += -fno-builtin --short-enums # keep every function in separate section. This will allow linker to dump unused functions LDFLAGS += -Xlinker -Map=$(LISTING_DIRECTORY)/$(OUTPUT_FILENAME).map LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT) @@ -178,7 +188,7 @@ genbin: $(NO_ECHO)$(OBJCOPY) -O binary $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin ## Create binary .hex file from the .out file -genhex: +genhex: @echo Preparing: $(OUTPUT_FILENAME).hex $(NO_ECHO)$(OBJCOPY) -O ihex $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).hex echosize: @@ -196,4 +206,4 @@ flash: nrf51822_xxac nrfjprog --program $(OUTPUT_BINARY_DIRECTORY)/$<.hex -f nrf51 --chiperase nrfjprog --reset -f nrf51 -## Flash softdevice \ No newline at end of file +## Flash softdevice diff --git a/mitosis-keyboard-basic/main.c b/mitosis-keyboard-basic/main.c index 5706ef6..3e68bb1 100644 --- a/mitosis-keyboard-basic/main.c +++ b/mitosis-keyboard-basic/main.c @@ -1,6 +1,6 @@ -#define COMPILE_RIGHT -//#define COMPILE_LEFT +// #define COMPILE_RIGHT +#define COMPILE_LEFT #include "mitosis.h" #include "nrf_drv_config.h" @@ -9,6 +9,8 @@ #include "nrf_delay.h" #include "nrf_drv_clock.h" #include "nrf_drv_rtc.h" +#include +#include "mitosis-crypto.h" /*****************************************************************************/ @@ -20,11 +22,16 @@ const nrf_drv_rtc_t rtc_deb = NRF_DRV_RTC_INSTANCE(1); /**< Declaring an instanc // Define payload length -#define TX_PAYLOAD_LENGTH 3 ///< 3 byte payload length when transmitting +#define TX_PAYLOAD_LENGTH sizeof(mitosis_crypto_data_payload_t) ///< 24 byte payload length when transmitting // Data and acknowledgement payloads -static uint8_t data_payload[TX_PAYLOAD_LENGTH]; ///< Payload to send to Host. -static uint8_t ack_payload[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; ///< Placeholder for received ACK payloads from Host. +static mitosis_crypto_data_payload_t data_payload; ///< Payload to send to Host. +static mitosis_crypto_seed_payload_t ack_payload; ///< Payloads received in ACKs from Host. + +// Crypto state +static mitosis_crypto_context_t crypto; +static mitosis_crypto_context_t receiver_crypto; +static volatile bool encrypting = false; // Debounce time (dependent on tick frequency) #define DEBOUNCE 5 @@ -36,7 +43,16 @@ static uint32_t debounce_ticks, activity_ticks; static volatile bool debouncing = false; // Debug helper variables -static volatile bool init_ok, enable_ok, push_ok, pop_ok, tx_success; +static uint16_t max_rtx = 0; +static uint32_t rtx_count = 0; +static uint32_t tx_count = 0; +static uint32_t tx_fail = 0; +static volatile uint32_t encrypt_collisions = 0; +static volatile uint32_t encrypt_failure = 0; +static volatile uint32_t cmac_failure = 0; +static volatile uint32_t rekey_cmac_success = 0; +static volatile uint32_t rekey_cmac_failure = 0; +static volatile uint32_t rekey_decrypt_failure = 0; // Setup switch pins with pullups static void gpio_config(void) @@ -75,34 +91,72 @@ static uint32_t read_keys(void) // Assemble packet and send to receiver static void send_data(void) { - data_payload[0] = ((keys & 1<INTENSET = GPIOTE_INTENSET_PORT_Msk; NVIC_EnableIRQ(GPIOTE_IRQn); +#ifdef COMPILE_LEFT + mitosis_crypto_init(&crypto, left_keyboard_crypto_key); +#elif defined(COMPILE_RIGHT) + mitosis_crypto_init(&crypto, right_keyboard_crypto_key); +#else + #error "no keyboard half specified" +#endif + mitosis_crypto_init(&receiver_crypto, receiver_crypto_key); + // Main loop, constantly sleep, waiting for RTC and gpio IRQs while(1) { __SEV(); __WFE(); - __WFE(); + __WFE(); } } @@ -252,19 +315,57 @@ void GPIOTE_IRQHandler(void) void nrf_gzll_device_tx_success(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) { - uint32_t ack_payload_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH; + uint32_t ack_payload_length = sizeof(ack_payload); + uint8_t mac_scratch[MITOSIS_CMAC_OUTPUT_SIZE]; + + if (pipe != PIPE_NUMBER) + { + // Ignore responses from the wrong pipe (shouldn't happen). + return; + } if (tx_info.payload_received_in_ack) { - // Pop packet and write first byte of the payload to the GPIO port. - nrf_gzll_fetch_packet_from_rx_fifo(pipe, ack_payload, &ack_payload_length); + // If the receiver sent back payload, it's a new seed for encryption keys. + // Collect this packet and validate. + nrf_gzll_fetch_packet_from_rx_fifo(pipe, (uint8_t*) &ack_payload, &ack_payload_length); + mitosis_cmac_compute(&receiver_crypto.cmac, ack_payload.payload, sizeof(ack_payload.payload), mac_scratch); + if (memcmp(mac_scratch, ack_payload.mac, sizeof(mac_scratch)) == 0) + { + ++rekey_cmac_success; + receiver_crypto.encrypt.ctr.iv.counter = ack_payload.key_id; + if (mitosis_aes_ctr_decrypt(&receiver_crypto.encrypt, sizeof(ack_payload.seed), ack_payload.seed, mac_scratch)) + { + // The seed packet validates! update the encryption keys. + data_payload.key_id = ack_payload.key_id; + + #ifdef COMPILE_LEFT + mitosis_crypto_rekey(&crypto, left_keyboard_crypto_key, mac_scratch, sizeof(ack_payload.seed)); + #elif defined(COMPILE_RIGHT) + mitosis_crypto_rekey(&crypto, right_keyboard_crypto_key, mac_scratch, sizeof(ack_payload.seed)); + #endif + } + else + { + ++rekey_decrypt_failure; + } + } + else + { + ++rekey_cmac_failure; + } } + if (tx_info.num_tx_attempts > max_rtx) + { + max_rtx = tx_info.num_tx_attempts; + } + rtx_count += tx_info.num_tx_attempts; } // no action is taken when a packet fails to send, this might need to change void nrf_gzll_device_tx_failed(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) { - + } // Callbacks not needed @@ -272,4 +373,3 @@ void nrf_gzll_host_rx_data_ready(uint32_t pipe, nrf_gzll_host_rx_info_t rx_info) {} void nrf_gzll_disabled() {} - diff --git a/mitosis-receiver-basic/config/nrf_drv_config.h b/mitosis-receiver-basic/config/nrf_drv_config.h index c0fb263..d1497bd 100644 --- a/mitosis-receiver-basic/config/nrf_drv_config.h +++ b/mitosis-receiver-basic/config/nrf_drv_config.h @@ -66,7 +66,7 @@ #define TIMER1_INSTANCE_INDEX (TIMER0_ENABLED) #endif - + #define TIMER2_ENABLED 0 #if (TIMER2_ENABLED == 1) diff --git a/mitosis-receiver-basic/custom/armgcc/Makefile b/mitosis-receiver-basic/custom/armgcc/Makefile index 32d1808..ae1623f 100644 --- a/mitosis-receiver-basic/custom/armgcc/Makefile +++ b/mitosis-receiver-basic/custom/armgcc/Makefile @@ -3,7 +3,7 @@ PROJECT_NAME := mitosis-receiver-basic export OUTPUT_FILENAME #MAKEFILE_NAME := $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) MAKEFILE_NAME := $(MAKEFILE_LIST) -MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) +MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) TEMPLATE_PATH = ../../../../components/toolchain/gcc ifeq ($(OS),Windows_NT) @@ -17,7 +17,7 @@ RM := rm -rf #echo suspend ifeq ("$(VERBOSE)","1") -NO_ECHO := +NO_ECHO := else NO_ECHO := @ endif @@ -39,13 +39,21 @@ remduplicates = $(strip $(if $1,$(firstword $1) $(call remduplicates,$(filter-ou C_SOURCE_FILES += \ $(abspath ../../../../components/toolchain/system_nrf51.c) \ $(abspath ../../main.c) \ +$(abspath ../../../../components/libraries/sha256/sha256.c) \ +$(abspath ../../../mitosis-crypto/mitosis-hmac.c) \ +$(abspath ../../../mitosis-crypto/mitosis-hkdf.c) \ +$(abspath ../../../mitosis-crypto/mitosis-keys.c) \ +$(abspath ../../../mitosis-crypto/mitosis-aes-ecb.c) \ +$(abspath ../../../mitosis-crypto/mitosis-cmac.c) \ +$(abspath ../../../mitosis-crypto/mitosis-ckdf.c) \ +$(abspath ../../../mitosis-crypto/mitosis-aes-ctr.c) \ $(abspath ../../../../components/libraries/util/app_error.c) \ $(abspath ../../../../components/libraries/util/app_error_weak.c) \ $(abspath ../../../../components/libraries/fifo/app_fifo.c) \ $(abspath ../../../../components/libraries/util/app_util_platform.c) \ $(abspath ../../../../components/libraries/util/nrf_assert.c) \ $(abspath ../../../../components/libraries/uart/retarget.c) \ -$(abspath ../../../../components/libraries/uart/app_uart_fifo.c) \ +$(abspath ../../../../components/libraries/uart/app_uart.c) \ $(abspath ../../../../components/drivers_nrf/delay/nrf_delay.c) \ $(abspath ../../../../components/drivers_nrf/common/nrf_drv_common.c) \ $(abspath ../../../../components/drivers_nrf/uart/nrf_drv_uart.c) \ @@ -63,9 +71,11 @@ INC_PATHS += -I$(abspath ../../../../components/drivers_nrf/nrf_soc_nosd) INC_PATHS += -I$(abspath ../../../../components/device) INC_PATHS += -I$(abspath ../../../../components/libraries/uart) INC_PATHS += -I$(abspath ../../../../components/drivers_nrf/hal) +INC_PATHS += -I$(abspath ../../../../components/libraries/sha256) INC_PATHS += -I$(abspath ../../../../components/drivers_nrf/delay) INC_PATHS += -I$(abspath ../../../../components/toolchain/CMSIS/Include) INC_PATHS += -I$(abspath ../..) +INC_PATHS += -I$(abspath ../../../mitosis-crypto) INC_PATHS += -I$(abspath ../../../../components/libraries/util) INC_PATHS += -I$(abspath ../../../../components/drivers_nrf/uart) INC_PATHS += -I$(abspath ../../../../components/drivers_nrf/common) @@ -83,6 +93,7 @@ OUTPUT_BINARY_DIRECTORY = $(OBJECT_DIRECTORY) BUILD_DIRECTORIES := $(sort $(OBJECT_DIRECTORY) $(OUTPUT_BINARY_DIRECTORY) $(LISTING_DIRECTORY) ) #flags common to all targets +# CFLAGS = -DDEBUG CFLAGS = -DNRF51 CFLAGS += -DGAZELL_PRESENT CFLAGS += -DBOARD_CUSTOM @@ -95,7 +106,7 @@ CFLAGS += -Wno-unused-variable CFLAGS += -mfloat-abi=soft # keep every function in separate section. This will allow linker to dump unused functions CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing -CFLAGS += -fno-builtin --short-enums +CFLAGS += -fno-builtin --short-enums # keep every function in separate section. This will allow linker to dump unused functions LDFLAGS += -Xlinker -Map=$(LISTING_DIRECTORY)/$(OUTPUT_FILENAME).map LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT) @@ -182,7 +193,7 @@ genbin: $(NO_ECHO)$(OBJCOPY) -O binary $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin ## Create binary .hex file from the .out file -genhex: +genhex: @echo Preparing: $(OUTPUT_FILENAME).hex $(NO_ECHO)$(OBJCOPY) -O ihex $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).hex echosize: @@ -200,4 +211,4 @@ flash: nrf51822_xxac nrfjprog --program $(OUTPUT_BINARY_DIRECTORY)/$<.hex -f nrf51 --chiperase nrfjprog --reset -f nrf51 -## Flash softdevice \ No newline at end of file +## Flash softdevice diff --git a/mitosis-receiver-basic/main.c b/mitosis-receiver-basic/main.c index 5739d13..86869a5 100644 --- a/mitosis-receiver-basic/main.c +++ b/mitosis-receiver-basic/main.c @@ -2,15 +2,17 @@ #include #include #include +#include #include "app_uart.h" #include "nrf_drv_uart.h" #include "app_error.h" #include "nrf_delay.h" #include "nrf.h" #include "nrf_gzll.h" +#include "mitosis-crypto.h" #define MAX_TEST_DATA_BYTES (15U) /**< max number of test bytes to be used for tx and rx. */ -#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */ +#define UART_TX_BUF_SIZE 512 /**< UART TX buffer size. */ #define UART_RX_BUF_SIZE 1 /**< UART RX buffer size. */ @@ -21,11 +23,8 @@ #define HWFC false -// Define payload length -#define TX_PAYLOAD_LENGTH 3 ///< 3 byte payload length - // ticks for inactive keyboard -#define INACTIVE 100000 +#define INACTIVE 10000 // Binary printing #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c" @@ -34,81 +33,99 @@ (byte & 0x08 ? '#' : '.'), \ (byte & 0x04 ? '#' : '.'), \ (byte & 0x02 ? '#' : '.'), \ - (byte & 0x01 ? '#' : '.') + (byte & 0x01 ? '#' : '.') +// Cryptographic keys and state -// Data and acknowledgement payloads -static uint8_t data_payload_left[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; ///< Placeholder for data payload received from host. -static uint8_t data_payload_right[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; ///< Placeholder for data payload received from host. -static uint8_t ack_payload[TX_PAYLOAD_LENGTH]; ///< Payload to attach to ACK sent to device. -static uint8_t data_buffer[10]; +// The three cryptographic contexts for the keyboard. +// Index 0 contains the hard-coded context for key id 0. +// Index 1 contains the generated context for even-numbered key ids. +// Index 2 contains the generated context for odd-numbered key ids. +static mitosis_crypto_context_t left_crypto[3]; +static mitosis_crypto_context_t right_crypto[3]; +static mitosis_crypto_context_t receiver_crypto; -// Debug helper variables -extern nrf_gzll_error_code_t nrf_gzll_error_code; ///< Error code -static bool init_ok, enable_ok, push_ok, pop_ok, packet_received_left, packet_received_right; -uint32_t left_active = 0; -uint32_t right_active = 0; -uint8_t c; +// Whether a encryption/decryption operation is in progress. +static volatile bool decrypting = false; +static bool process_left = true; -void uart_error_handle(app_uart_evt_t * p_event) -{ - if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR) - { - APP_ERROR_HANDLER(p_event->data.error_communication); - } - else if (p_event->evt_type == APP_UART_FIFO_ERROR) - { - APP_ERROR_HANDLER(p_event->data.error_code); - } -} +typedef enum _crypto_rekey_state_t { + key_not_ready, + seed_ready, + new_key_ready, + new_key_payload_ready +} crypto_rekey_state_t; +typedef struct _crypto_rekey_context_t { + // Encrypted and MAC'd material for rekeying. + mitosis_crypto_seed_payload_t ack_payload; -int main(void) -{ - uint32_t err_code; - const app_uart_comm_params_t comm_params = - { - RX_PIN_NUMBER, - TX_PIN_NUMBER, - RTS_PIN_NUMBER, - CTS_PIN_NUMBER, - APP_UART_FLOW_CONTROL_DISABLED, - false, - UART_BAUDRATE_BAUDRATE_Baud1M - }; + // Seed value used to generate new cryptographic contexts. + uint8_t seed[15]; - APP_UART_FIFO_INIT(&comm_params, - UART_RX_BUF_SIZE, - UART_TX_BUF_SIZE, - uart_error_handle, - APP_IRQ_PRIORITY_LOW, - err_code); + // Index into the seed array, used by the RNG when writing the seed. + uint8_t seed_index; - APP_ERROR_CHECK(err_code); + // Current state of new key generation. + crypto_rekey_state_t state; - // Initialize Gazell - nrf_gzll_init(NRF_GZLL_MODE_HOST); + // Key id for the current cryptographic keys and contexts. + uint8_t key_id; - // Addressing - nrf_gzll_set_base_address_0(0x01020304); - nrf_gzll_set_base_address_1(0x05060708); - - // Load data into TX queue - ack_payload[0] = 0x55; - nrf_gzll_add_packet_to_tx_fifo(0, data_payload_left, TX_PAYLOAD_LENGTH); - nrf_gzll_add_packet_to_tx_fifo(1, data_payload_left, TX_PAYLOAD_LENGTH); + // Key id for the generated cryptographic keys and contexts, to be used next. + uint8_t new_key_id; - // Enable Gazell to start sending over the air - nrf_gzll_enable(); + // Flag indicating whether the key id has been confirmed by the keyboard. + // When true, a rekeying may be performed. If false, keykeying may not be + // performed. + bool key_id_confirmed; +} crypto_rekey_context_t; - // main loop - while (true) +crypto_rekey_context_t left_key_state; +crypto_rekey_context_t right_key_state; + + +// Data and acknowledgement payloads +static uint8_t data_payload_left[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; ///< Placeholder for data payload received from host. +static uint8_t data_payload_right[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; ///< Placeholder for data payload received from host. +static uint8_t data_buffer[11]; + +// Debug helper variables +extern nrf_gzll_error_code_t nrf_gzll_error_code; ///< Error code +uint8_t c; + +typedef struct _keyboard_stats_t { + uint32_t cmac_fail; + uint32_t decrypt_fail; + uint32_t decrypt_collisions; + uint32_t active; + bool packet_received; +} keyboard_stats_t; + +keyboard_stats_t left_stats = { 0 }; +keyboard_stats_t right_stats = { 0 }; + +uint64_t counter = 0; + +static inline +void crypto_rekey_context_init(crypto_rekey_context_t *state) +{ + memset(state, 0, sizeof(*state)); + state->state = key_not_ready; + // Key ID 0 is special, and is always confirmed. This is necessary for key update to work. + state->key_id_confirmed = true; +} + +void mitosis_uart_handler(app_uart_evt_t * p_event) +{ + if (p_event->evt_type == APP_UART_DATA) { + c = p_event->data.value; // detecting received packet from interupt, and unpacking - if (packet_received_left) + if (left_stats.packet_received) { - packet_received_left = false; + left_stats.packet_received = false; data_buffer[0] = ((data_payload_left[0] & 1<<3) ? 1:0) << 0 | ((data_payload_left[0] & 1<<4) ? 1:0) << 1 | @@ -139,10 +156,10 @@ int main(void) ((data_payload_left[2] & 1<<4) ? 1:0) << 4; } - if (packet_received_right) + if (right_stats.packet_received) { - packet_received_right = false; - + right_stats.packet_received = false; + data_buffer[1] = ((data_payload_right[0] & 1<<7) ? 1:0) << 0 | ((data_payload_right[0] & 1<<6) ? 1:0) << 1 | ((data_payload_right[0] & 1<<5) ? 1:0) << 2 | @@ -171,20 +188,12 @@ int main(void) ((data_payload_right[2] & 1<<2) ? 1:0) << 2 | ((data_payload_right[2] & 1<<1) ? 1:0) << 3; } - - // checking for a poll request from QMK - if (app_uart_get(&c) == NRF_SUCCESS && c == 's') + if (p_event->data.value == 's') { // sending data to QMK, and an end byte - nrf_drv_uart_tx(data_buffer,10); - app_uart_put(0xE0); - + nrf_drv_uart_tx(data_buffer,11); // debugging help, for printing keystates to a serial console /* - for (uint8_t i = 0; i < 10; i++) - { - app_uart_put(data_buffer[i]); - } printf(BYTE_TO_BINARY_PATTERN " " \ BYTE_TO_BINARY_PATTERN " " \ BYTE_TO_BINARY_PATTERN " " \ @@ -204,35 +213,260 @@ int main(void) BYTE_TO_BINARY(data_buffer[6]), \ BYTE_TO_BINARY(data_buffer[7]), \ BYTE_TO_BINARY(data_buffer[8]), \ - BYTE_TO_BINARY(data_buffer[9])); + BYTE_TO_BINARY(data_buffer[9])); nrf_delay_us(100); */ + // Give the UART time to read the buffer before it changes. + nrf_delay_us(10); } - // allowing UART buffers to clear - nrf_delay_us(10); - // if no packets recieved from keyboards in a few seconds, assume either // out of range, or sleeping due to no keys pressed, update keystates to off - left_active++; - right_active++; - if (left_active > INACTIVE) + left_stats.active++; + right_stats.active++; + if (left_stats.active > INACTIVE) { data_buffer[0] = 0; data_buffer[2] = 0; data_buffer[4] = 0; data_buffer[6] = 0; data_buffer[8] = 0; - left_active = 0; + left_stats.active = 0; } - if (right_active > INACTIVE) + if (right_stats.active > INACTIVE) { data_buffer[1] = 0; data_buffer[3] = 0; data_buffer[5] = 0; data_buffer[7] = 0; data_buffer[9] = 0; - right_active = 0; + right_stats.active = 0; + } + } + else if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR) + { + APP_ERROR_HANDLER(p_event->data.error_communication); + } +} + +static inline +void update_rekey_state( + crypto_rekey_context_t *key_state, + mitosis_crypto_context_t crypto_contexts[], + keyboard_stats_t *stats, + mitosis_crypto_key_type_t key_type) +{ + switch (key_state->state) + { + case key_not_ready: + // Check if a random value is needed and if the RNG is ready and consume it. + if (key_state->seed_index < sizeof(key_state->seed) && NRF_RNG->EVENTS_VALRDY) + { + key_state->seed[key_state->seed_index++] = NRF_RNG->VALUE; + NRF_RNG->EVENTS_VALRDY = 0; + if (key_state->seed_index == sizeof(key_state->seed)) + { + memcpy(key_state->ack_payload.seed, key_state->seed, sizeof(key_state->seed)); + key_state->seed_index = 0; + key_state->state = seed_ready; + key_state->new_key_id = key_state->key_id + 1; + if (key_state->new_key_id == 0) + { + // Key id 0 is special (it's the initial key), so skip it. + key_state->new_key_id = 1; + } + } + } + break; + case seed_ready: + if (!decrypting) + { + decrypting = true; + if (mitosis_crypto_rekey( + &crypto_contexts[(key_state->new_key_id & 0x1) + 1], + key_type, + key_state->ack_payload.seed, + sizeof(key_state->ack_payload.seed))) + { + key_state->state = new_key_ready; + } + decrypting = false; + } + else + { + ++stats->decrypt_collisions; + } + break; + case new_key_ready: + if (!decrypting) + { + decrypting = true; + receiver_crypto.encrypt.ctr.iv.counter = key_state->new_key_id; + key_state->ack_payload.key_id = key_state->new_key_id; + if (mitosis_aes_ctr_encrypt( + &receiver_crypto.encrypt, + sizeof(key_state->ack_payload.seed), + key_state->ack_payload.seed, + key_state->ack_payload.seed) && + mitosis_cmac_compute( + &receiver_crypto.cmac, + key_state->ack_payload.payload, + sizeof(key_state->ack_payload.payload), + key_state->ack_payload.mac)) + { + key_state->state = new_key_payload_ready; + } + decrypting = false; + } + else + { + ++stats->decrypt_collisions; + } + break; + default: + break; + } +} + + +int main(void) +{ + uint32_t err_code; + + // Enable error correction in the RNG module. + NRF_RNG->CONFIG |= RNG_CONFIG_DERCEN_Msk; + // Tell the RNG to start running. + NRF_RNG->EVENTS_VALRDY = 0; + NRF_RNG->TASKS_START = 1; + + // Initialize crypto keys + mitosis_crypto_init(&left_crypto[0], left_keyboard_crypto_key); + mitosis_crypto_init(&right_crypto[0], right_keyboard_crypto_key); + mitosis_crypto_init(&receiver_crypto, receiver_crypto_key); + + crypto_rekey_context_init(&left_key_state); + crypto_rekey_context_init(&right_key_state); + + memset(data_buffer, 0, sizeof(data_buffer)); + data_buffer[10] = 0xE0; + const app_uart_comm_params_t comm_params = + { + RX_PIN_NUMBER, + TX_PIN_NUMBER, + RTS_PIN_NUMBER, + CTS_PIN_NUMBER, + APP_UART_FLOW_CONTROL_DISABLED, + false, + UART_BAUDRATE_BAUDRATE_Baud1M + }; + + APP_UART_INIT(&comm_params, + mitosis_uart_handler, + APP_IRQ_PRIORITY_HIGH, + err_code); + + APP_ERROR_CHECK(err_code); + + // Initialize Gazell + nrf_gzll_init(NRF_GZLL_MODE_HOST); + + // Addressing + nrf_gzll_set_base_address_0(0x01020304); + nrf_gzll_set_base_address_1(0x05060708); + + // Enable Gazell to start sending over the air + nrf_gzll_enable(); + + // main loop + while (true) + { + if (process_left) + { + update_rekey_state(&left_key_state, left_crypto, &left_stats, left_keyboard_crypto_key); + } + else + { + update_rekey_state(&right_key_state, right_crypto, &right_stats, right_keyboard_crypto_key); + } + // This flip/flops between next key generation for the left and right halves. + process_left = !process_left; + counter++; + } +} + +static inline +void process_received_packet( + mitosis_crypto_context_t crypto[], + crypto_rekey_context_t* key_state, + mitosis_crypto_data_payload_t *payload, + keyboard_stats_t *stats, + uint8_t *decrypted_payload, + mitosis_crypto_seed_payload_t **ack_payload, + uint32_t *ack_payload_length) +{ + uint8_t mac_scratch[MITOSIS_CMAC_OUTPUT_SIZE]; + // If a crypto operation is in-progress, just skip the payload and continue. + // This could cause missing keypresses, but since the Gazell packet callback + // runs at high priority, it's unlikely this will happen. + // If it becomes a problem in the future, consider queueing packets and + // processing them in the main loop. + if (!decrypting) + { + decrypting = true; + uint8_t index = (payload->key_id == 0) ? 0 : (payload->key_id & 0x1) + 1; + if (mitosis_cmac_compute( + &crypto[index].cmac, + payload->payload, + sizeof(payload->payload), + mac_scratch) && + memcmp(payload->mac, mac_scratch, sizeof(payload->mac)) == 0) + { + // This is a valid message from the keyboard; decrypt it. + crypto[index].encrypt.ctr.iv.counter = payload->counter; + if (mitosis_aes_ctr_decrypt( + &crypto[index].encrypt, + sizeof(payload->data), + payload->data, + decrypted_payload)) + { + stats->packet_received = true; + stats->active = 0; + // If this packet confirms a key, mark it as confirmed and start + // generating the next key. + if (key_state->new_key_id != key_state->key_id && key_state->new_key_id == payload->key_id) + { + key_state->key_id_confirmed = true; + key_state->key_id = key_state->new_key_id; + // On confirmation, generate new key + key_state->state = key_not_ready; + } + // Tell the keyboard to rekey with this key material. + if ((payload->key_id == 0 || payload->counter > MITOSIS_REKEY_INTERVAL) && + key_state->key_id_confirmed && key_state->state == new_key_payload_ready) + { + *ack_payload = &key_state->ack_payload; + *ack_payload_length = sizeof(key_state->ack_payload); + } + } + else + { + ++stats->decrypt_fail; + } + } + else + { + ++stats->cmac_fail; + if (key_state->state == new_key_payload_ready) + { + // re-send the existing seed in case the keyboard reset and forgot. + *ack_payload = &key_state->ack_payload; + *ack_payload_length = sizeof(key_state->ack_payload); + } } + decrypting = false; + } + else + { + ++stats->decrypt_collisions; } } @@ -242,30 +476,33 @@ void nrf_gzll_device_tx_success(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info void nrf_gzll_device_tx_failed(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info) {} void nrf_gzll_disabled() {} -// If a data packet was received, identify half, and throw flag +// If a data packet was received, identify half, and decrypt it. void nrf_gzll_host_rx_data_ready(uint32_t pipe, nrf_gzll_host_rx_info_t rx_info) -{ - uint32_t data_payload_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH; - +{ + mitosis_crypto_data_payload_t payload; + uint32_t payload_length = sizeof(payload); + uint32_t ack_payload_length = 0; + mitosis_crypto_seed_payload_t *ack_payload = NULL; + if (pipe == 0) { - packet_received_left = true; - left_active = 0; - // Pop packet and write first byte of the payload to the GPIO port. - nrf_gzll_fetch_packet_from_rx_fifo(pipe, data_payload_left, &data_payload_length); + // Pop packet and write payload to temp storage for verification. + nrf_gzll_fetch_packet_from_rx_fifo(pipe, (uint8_t*) &payload, &payload_length); + process_received_packet(left_crypto, &left_key_state, &payload, &left_stats, data_payload_left, &ack_payload, &ack_payload_length); } else if (pipe == 1) { - packet_received_right = true; - right_active = 0; - // Pop packet and write first byte of the payload to the GPIO port. - nrf_gzll_fetch_packet_from_rx_fifo(pipe, data_payload_right, &data_payload_length); + // Pop packet and write payload to temp storage for verification. + nrf_gzll_fetch_packet_from_rx_fifo(pipe, (uint8_t*) &payload, &payload_length); + process_received_packet(right_crypto, &right_key_state, &payload, &right_stats, data_payload_right, &ack_payload, &ack_payload_length); } - + // not sure if required, I guess if enough packets are missed during blocking uart nrf_gzll_flush_rx_fifo(pipe); //load ACK payload into TX queue - ack_payload[0] = 0x55; - nrf_gzll_add_packet_to_tx_fifo(pipe, ack_payload, TX_PAYLOAD_LENGTH); -} \ No newline at end of file + if (ack_payload != NULL) + { + nrf_gzll_add_packet_to_tx_fifo(pipe, (uint8_t*) ack_payload, ack_payload_length); + } +} diff --git a/precompiled/precompiled-crypto-left.hex b/precompiled/precompiled-crypto-left.hex new file mode 100644 index 0000000..271424d --- /dev/null +++ b/precompiled/precompiled-crypto-left.hex @@ -0,0 +1,1125 @@ +:10000000004000202516000065160000671600005D +:1000100000000000000000000000000000000000E0 +:100020000000000000000000000000006916000051 +:1000300000000000000000006B1600006D160000BC +:1000400021130000C53300006F1600006F1600007A +:100050006F16000000000000DD1000006F160000A9 +:100060006F1600006F16000051430000E5140000F9 +:100070006F1600006F1600006F1600006F1600006C +:100080006F160000851500006F1600006F16000047 +:100090001D3700006F1600006F1600006F1600007D +:1000A0006F1600006F160000000000000000000046 +:1000B0000000000000000000000000000000000040 +:1000C00010B5064C2378002B07D1054B002B02D02E +:1000D000044800E000BF0123237010BD8800002009 +:1000E0000000000084450000044B10B5002B03D035 +:1000F0000349044800E000BF10BDC04600000000F6 +:100100008C00002084450000144B002B00D1124BC2 +:100110009D46402292029A1A924600218B460F4633 +:100120001148124A121A00F07BF80D4B002B00D038 +:1001300098470C4B002B00D098470020002104006A +:100140000D000B4800F016F800F046F820002900DA +:1001500000F022FF00F016F8000008000040002028 +:10016000000000000000000088000020C4060020FD +:10017000B1010000002310B501001A00180000F0C2 +:1001800057F810BD084B10B50400002B02D0002119 +:1001900000F0B4F8054B1868836A002B00D098472C +:1001A000200000F007F9C046FD020000A84400004E +:1001B00070B5074D074C641BA410002C02D104F04D +:1001C0006DF970BD013CA300EB589847F5E7C046B8 +:1001D000840000208800002070B500260C4D0D4CD6 +:1001E000641BA410A64209D1002604F051F90A4D5F +:1001F0000A4C641BA410A64205D170BDB300EB5895 +:1002000098470136EEE7B300EB5898470136F2E71E +:10021000800000208000002080000020840000205A +:1002200003008218934200D1704719700133F9E737 +:10023000F0B52D4D85B0060028680192009102931B +:1002400000F0B4F8294A1468002C0AD1284B136036 +:10025000284A1C00002A04D0190012688831039231 +:100260000A6063681F2B06DD286800F0A1F80120F2 +:10027000404205B0F0BD002E29D0270088373868ED +:10028000002812D11C4B002B03D1286800F08FF8F6 +:10029000EDE78420400000E000BF0028F5D0030017 +:1002A0000022FC335A609A6038606168019A8B00C2 +:1002B000C31804C301228A40FC30416811434160E5 +:1002C0000299D967022E02D183681A43826063685B +:1002D00028685A1C62600233009A9B001A5100F091 +:1002E00067F80020C5E7C04660000020300100200C +:1002F000A40000200000000000000000F7B5294B1A +:10030000019018680F0000F051F8274B1D68002D70 +:1003100004D1244B186800F04BF8F7BD2B0088334C +:100320001E686B685C1E002CF3DB002F09D0002ECA +:1003300001D1013CF7E73300A20080339B58BB4258 +:10034000F7D128006968A200083001398358A1421A +:1003500019D16C60002BECD069680091002E08D098 +:10036000FC218C460120B4446146A040496801420A +:100370000CD198470C4B6A6800991B688A42C4D11B +:100380009D42D6D0C1E700218150E3E7B1586246D3 +:100390009268024202D101989847EBE7080098471B +:1003A000E8E7C04660000020300100207047704739 +:1003B00070470000FEE7C0462D4B1B78012B00D094 +:1003C00070472C4B1B681B07FAD12B4AF02312688D +:1003D000110019401A4201D0102946D1274A12684B +:1003E0001A421FD0F022244B1B681340402B29D007 +:1003F000F022214B1B681340A02B01D0D02BDFD162 +:10040000F0231E4A12681A42DAD11D4A1368012BE2 +:1004100004D01C4B13601368012BFCD1C0221A4B73 +:100420001A60CDE7194B1A4A1A608022194B120242 +:100430001A600F4B1B78012BC2D10E4B1B681B0798 +:10044000D0D0BDE70D4B1B681342D1D18022C12310 +:100450000121DB00D205D150054B1B78012BAFD118 +:10046000044B1B681B07C3D0AAE73029B6D0B9E7F5 +:10047000E00F00F0E40F00F0E80F00F0EC0F00F0E8 +:1004800000EC06407593000014EC064004050040A3 +:10049000DFFF07C0186C004030B505000C001000ED +:1004A000190087B0022C02D9002007B030BD1D4BC7 +:1004B000A400E25802AB0093102300F079FB00285F +:1004C000F2D010240F231021174A0194009502A89E +:1004D00000F082FB0028E7D02B001033009310219E +:1004E0001123124A019402A800F076FB0028DBD009 +:1004F0000023EB6102AB0093102108230C4A019406 +:1005000002A800F069FB0028CED02800102202A922 +:10051000303000F059F80028C6D0280000F00AF862 +:10052000C3E7C046D8440000AC440000BC4400000F +:10053000D0440000002804D0034A044BD0500120CE +:1005400070470020FCE7C04600E0004004050000C2 +:1005500070B500282ED0184A184BD158814200D0CF +:10056000D0508224802500238022134964006D002E +:100570000B514B5101330B60520402E0013A002A47 +:1005800018D04B5908590343F8D00D48036801337C +:1005900003600C4803681E0080235B049C46002314 +:1005A0006644B21A02604B510A590120002A00D158 +:1005B00070BD0B510020FBE700E000400405000087 +:1005C0003401002038010020F0B50500C646203572 +:1005D0000400A84600B50F2A00D951E110230020DD +:1005E00020269B1AA055012B3AD00136A055022B8C +:1005F00036D00136A055032B32D00136A055042B3E +:100600002ED00136A055052B2AD00136A055062B39 +:1006100026D00136A055072B22D00136A055082B35 +:100620001ED00136A055092B1AD00136A0550A2B31 +:1006300016D00136A0550B2B12D00136A0550C2B2D +:100640000ED00136A0550D2B0AD00136A0550E2B29 +:1006500006D00136A055102B02D11F33E05441E0E3 +:1006600000200500A71A3437B9424541A61A2F00C9 +:1006700030360D1DAE4240410743BC460827501E90 +:100680008742BF4160467F42074200D1FDE0300013 +:100690000843800700D0F8E00D6890083560012815 +:1006A00005D04D687560032801D18868B0600320CB +:1006B0001500854328005B19AA4213D04E5DE2184D +:1006C000203216705A1C6E1C0F2B0BD08E5DA21898 +:1006D0002032167002309A1C0E2B03D00B5CA2182D +:1006E000203213702000102200213030FFF798FDD7 +:1006F00050223F21A35C40468B43A354FFF728FFC1 +:10070000002800D1B9E04F23E25C5300E3734E238D +:10071000E35CD20959000A43A2734D22A25CDB09B3 +:1007200051000B4363734C23E35CD20959000A4325 +:1007300022734B22A25CDB0951000B43E3724A2374 +:10074000E35CD20959000A43A2724922A25CDB0988 +:1007500051000B4363724823E35CD20959000A43FA +:1007600022724722A25CDB0951000B43E37146234E +:10077000E35CD20959000A43A2714522A25CDB095D +:1007800051000B4363714423E35CD20959000A43CF +:1007900022714322A25CDB0951000B43E370422328 +:1007A000E35CD20959000A43A2704122A25CDB0932 +:1007B00051000B4363704023E15CD2094B001A43A4 +:1007C00022707F2904D97923E27B5B425340E37393 +:1007D000E27B5300E377A37BD20959000A43A27757 +:1007E000627BDB0951000B436377237BD2095900FD +:1007F0000A432277E27ADB0951000B43E376A37ABE +:10080000D20959000A43A276627ADB0951000B43F0 +:100810006376237AD20959000A432276E279DB090A +:1008200051000B43E375A379D20959000A43A2751D +:100830006279DB0951000B4363752379D2095900B2 +:100840000A432275E278DB0951000B43E374A37875 +:10085000D20959000A43A2746278DB0951000B43A4 +:1008600021786374D2094B001A4322747F2904D97A +:100870007923E27F5B425340E37704BC9046F0BDAE +:100880001022280003F0FAFD2CE70878E318203343 +:10089000187011239B1A102B00D123E74878E31816 +:1008A0002033187012239B1A102B00D11AE7887876 +:1008B000E3182033187013239B1A102B00D111E773 +:1008C000C878E3182033187014239B1A102B00D11A +:1008D00008E70879E3182033187015239B1A102BAA +:1008E00000D1FFE64879E3182033187016239B1ACD +:1008F000102B00D1F6E68879E318203318701723FF +:100900009B1A102B00D1EDE6C879E318203318703C +:1009100018239B1A102B00D1E4E6087AE318203341 +:10092000187019239B1A102B00D1DBE6487AE318C4 +:10093000203318701A239B1A102B00D1D2E6887A24 +:10094000E318203318701B239B1A102B00D1C9E623 +:10095000C87AE318203318701C239B1A102B00D17F +:10096000C0E6087BE318203318701D239B1A102B58 +:1009700000D1B7E6487BE318203318700E2A00D167 +:10098000B0E62F238A7BE254ACE6C046F0B51400F3 +:100990003022454657464E469446DE465023E0B543 +:1009A000844410276246C35C83B09B06DB0EFF1AAB +:1009B000060088463D000192BC4263D95022914610 +:1009C000313A93461F329246019A4146D0182A0086 +:1009D00003F054FD4B46F25C51469306DB0EFF18C4 +:1009E0005B463B408A435F0017434A46B754524632 +:1009F000A844641B3A40202A1ED01027FF1A3D004D +:100A0000019AD018AC42DFD82200414603F036FDEF +:100A10005021735C01209A06D20EA4181F221440A4 +:100A20001F32640093432343735403B03CBC90468D +:100A30009946A246AB46F0BDFB0712D430002030E9 +:100A4000FFF786FD0028F0D04B463F22F35C1027CD +:100A50009343012213434A461025B35401980023BF +:100A6000D0E7336B326C53403363726C736B53401B +:100A70007363B26CB36B5340B363F26CF36B53406C +:100A8000F363DBE7D018BFE7F0B550230400C64698 +:100A9000E25C123B0E0000B530301340202B38D101 +:100AA000236B2268534023636268636B5340636324 +:100AB000A268A36B5340A363E268E36B5340E36314 +:100AC0005023E35CDB070FD5236B226C5340236379 +:100AD000626C636B53406363A26CA36B5340A3636C +:100AE000E26CE36B5340E36320002030FFF730FDFE +:100AF000051E0AD050223F21A35C30008B43210009 +:100B0000A3544031403A03F0B9FC280004BC90469D +:100B1000F0BD210092061031D20E032A3AD92700E7 +:100B20000B00043A90469208944614379200BF187E +:100B30001A6A1D6804336A40DA619F42F8D163463D +:100B400062464546013392009B00AA1A012A05D944 +:100B5000CD5AC75A023A7D40C5520233002A03D00B +:100B6000CA5CC55C6A40C2545023E25C9206D20E55 +:100B7000A3181F7C1D0080235B4230357B402B7007 +:100B80000E2A9DD80F23551C49199A1A401903F0B3 +:100B900075FC95E70023D9E770B504001D00FFF749 +:100BA000F5FE002803D029002000FFF76DFF70BD7F +:100BB00030B597B004000D0001A811001A00FFF72E +:100BC00003FD002805D02A0021001A9B01A8FFF789 +:100BD000E3FF17B030BDC046F0B54546DE46574688 +:100BE0004E469B46FF23E0B59BB0259D8046894637 +:100BF00092461B019D4248D82F09FFB22B074CD1CA +:100C00006B46DC1C012300262370002F0FD147E028 +:100C1000102201A903F032FC1036103DB6B2237841 +:100C20000133DBB22370BB423AD8002B38D04A469E +:100C3000414605A8FFF7C8FC002826D02378012BE1 +:100C400006D9102201A905A8FFF7A0FE00281CD094 +:100C50005A46514605A8FFF799FE002815D00122F3 +:100C6000210005A8FFF792FE00280ED001A905A8D3 +:100C7000FFF70AFF002808D0249B9819102DC7D829 +:100C80002A0001A903F0FAFBC9E700201BB03CBC15 +:100C900090469946A246AB46F0BD0137FFB2AFE79A +:100CA0000120F3E7F8B505000C0017001E0010291D +:100CB00001D90020F8BDFFF74BFC0028F9D029002E +:100CC00020318C46032C2ED92B6A3A68534033606E +:100CD000231F032B11D96A6A79684A407260220087 +:100CE000083A032A09D9BA68A96A4A40B260102CA6 +:100CF00003D1EA6AF9684A40F26003229B08013393 +:100D00009B001440012C06D96146FA5ACD5A023C88 +:100D10006A40F2520233002CCCD06146FA5CC95CC6 +:100D20004A40F254C6E70023ECE7C046F8B5012379 +:100D30004E46994657464546DE464846E0B510279A +:100D400008264D4A4D4C13704D4B1B68DA09990823 +:100D50000140D2013F300A439900014080460A43D6 +:100D60002038590E01400A43190D39400A43590EE3 +:100D7000314084460A431C38990901400A43190945 +:100D80008A46022155460D402A4322709D005A088A +:100D90000540D2012A431D0CAA468B464D465146BA +:100DA0000D40D90D2A430D0041460D4019092A4333 +:100DB0000D0061460D4099082A430D003D402A432D +:100DC0001D00190D35402A430D0059460D4041467E +:100DD0002A43654662701A0A0A4059090D40590BA8 +:100DE000C9012A430A43D90A0F4017439A0B1640F8 +:100DF0003E4357465A4638409B0C30431340214EE1 +:100E00000343A3702200230003213000FFF74AFFB1 +:100E100000280CD11C4A1368013313600023164AC2 +:100E200013703CBC90469946A246AB46F8BDF369A8 +:100E300030005A1C63602300F2612100082208334D +:100E40003030FFF7A9FE002804D1104A136801339F +:100E50001360E3E718222100002000F02CFC00289A +:100E600004D00B4A136801331360D7E7094A1368AB +:100E700001331360D2E7C04610020020E8010020D1 +:100E800014020020640100200C02002060010020F8 +:100E9000B4020020B802002070B52C4A1378D9B2F1 +:100EA000002B1DD0A021A223C905DB00C858284B68 +:100EB0001968284B834399422CD000231370A02239 +:100EC000A223D205DB00D258224B93431ED1224AE3 +:100ED000136801331360FA22520093422BD870BD7D +:100EE000A024A2201B4BE4051E00C0002558AE43E1 +:100EF00035001A4E3668AE42E1D02058834314487C +:100F0000036001231370164B1960D8E70022124BBF +:100F10001A60E4E7124A136801331360052BCED13F +:100F20000E4B19600F4B1B78002B0BD00E4A136829 +:100F300001331360C3E70D4800F0B6FA0C4800F027 +:100F4000B3FACCE7FFF7F2FEB9E7C046040200208F +:100F500018020020FFE72F715C010020140200201E +:100F60000002002010020020080200203C45000082 +:100F70003445000010B5064B1B78002B04D0054A01 +:100F800013680133136010BDFFF7D0FEFBE7C046C6 +:100F9000100200200802002070B5002000F094FE2E +:100FA000642000F03BFE364800F0EAFC354800F0D3 +:100FB000FFFC00F05DFB00F065F9002000F080F917 +:100FC000314D0021314A280000F02CFA304C314AD2 +:100FD0000021200000F026FA0121280000F070FA1C +:100FE0002000012100F06CFAA0232B4A2B49DB05DD +:100FF0005A500C395A5068315A5018395A501031D9 +:101000005A5050395A502649264C5A500C395A5089 +:10101000254926485A5026495A5026495A500C39D3 +:101020005A5025495A500C395A5024495A501439AB +:101030005A5023495A5004315A5010395A502149B4 +:101040005A5021495A5004315A5020495A50C1230C +:1010500080211F4A9B000906D15040221D4B0121CF +:101060001A6010232200FFF717FA10232200022132 +:101070001948FFF711FA40BF20BF20BFFBE7C04669 +:1010800004030201080706053C450000750F000037 +:1010900034450000990E00000C0003001C070000FE +:1010A000140700001445000004070000640100203C +:1010B00074070000240700000C070000540700001C +:1010C000340700003C070000440700004C07000004 +:1010D0000060004000E100E020020020BE2310B5C7 +:1010E0000A4A5B00D158002900D110BD00240848ED +:1010F000D45000F0CDF9074800F0CAF9064B1C7037 +:10110000064B1C60064B1C60EFE7C04600600040C9 +:101110003C4500003445000004020020000200208D +:101120005C0100202023F0B58FB0029103920C0CDB +:10113000059300280CD16B461B7A002B0CD13E4B3B +:101140001A88A24206D33D4B1A68944664441C6038 +:101150000FB0F0BD1C80F6E7394D05AA290000F05C +:10116000EDFA384F1022290006AB3800FFF714FDC6 +:1011700029001022103106A803F072F9061E08D0CB +:10118000314A1368013313602B4B1A88A242DAD21A +:10119000E0E738002D4A303813680F21013313601F +:1011A000EB7B2A00C36106ABFFF77CFD002804D16E +:1011B000274A136801331360C1E7EA7B254B0F21EF +:1011C000DA700AAB0093244A102306A8FFF7F0FC5C +:1011D0000028B4D01027214D0F231021204A019759 +:1011E00000950AA8FFF7F8FC0028A8D02B001033C0 +:1011F0000093102111231B4A01970AA8FFF7ECFC6A +:1012000000289CD00AABEE6139000093164A0823EF +:1012100001970AA8FFF7E0FC002800D18FE73A0009 +:1012200012480AA9FFF7D0F9002800D187E7280063 +:10123000FFF780F983E7C0461C020020B0020020BF +:101240003C01002050020020A4020020A80200203F +:10125000AC020020E80100202445000064010020C9 +:10126000AC440000BC440000D044000094010020C5 +:1012700082B002B07047C04682B002B07047C0462C +:101280007047C04670B50D4C237A002B13D16360B4 +:1012900023602361E360AA228023FF210125DB056F +:1012A000D2009950383A00209D50FC3900F086F861 +:1012B0000020257270BD8520FCE7C046BC020020DE +:1012C00070B50400002000F067F8124DAB7A002BD7 +:1012D0000BD0002C02D0012063689847EB680133E3 +:1012E0000020EB6000F060F870BD002C02D02B698C +:1012F0002C612360EB68002BF1D1074A8021136039 +:10130000C1220220C905920088500121034A1160C0 +:10131000E5E7C046BC020020040100400800004090 +:1013200010B51A4B1A68002A14D0002280211A60C6 +:10133000C2220123164CC90592008B506372636868 +:10134000002B07D01A6800205B68626098476368CA +:10135000002BF7D10F4B1A68002A15D000221A6013 +:101360008022C22302219B00D205D1500123084CC8 +:10137000A3722369002B07D01A6801205B682261E1 +:1013800098472369002BF7D110BDC04600010040EB +:10139000BC0200200401004072B6024A1368013307 +:1013A00013607047D0020020034A1368013B1360AA +:1013B000002B00D162B67047D002002030B5FF2567 +:1013C00003232A000340DB009A4089010D40D243E9 +:1013D0009D40C4B2002814DB104B80089C46C023FB +:1013E000800060449B00C1580A401543C5501F232C +:1013F000C0211C401E3BA340084A490053501360C3 +:1014000030BD0F23064923408C46083B9B089B00B8 +:101410006344D9690A401543DD61E8E700E100E073 +:1014200000ED00E070B505000C00002A28D04079DE +:10143000144B8100CA504300002C1CD0124E1B18C4 +:101440009B5D002B15D10420A1782856FFF7B6FF2D +:10145000A12322882968DB00CA506A7921795300C8 +:101460009B18F2185170E1780020917001229A5572 +:1014700070BD0820FCE7054C191849006418DDE729 +:101480000720F5E7DC020020D402002044450000DC +:101490000122022103681A60427953009B18014A15 +:1014A00099547047D4020020012203685A604179A0 +:1014B0004B005B1801495A547047C046D4020020C3 +:1014C0008023002210B504685B00E250D12204683A +:1014D000FF3B9200A350002902D00168403A8B5094 +:1014E00010BDC046C123F0B5C64680249B00002530 +:1014F000984600B5204E214F64024346F3581C42E3 +:1015000010D01F4AAB00944663441A68002A09D0E1 +:10151000D2229200B450403AB4500022E8B21A608D +:101520003B68984701356400042DE6D1C122124B77 +:1015300092009A58D20704D5802252009958002967 +:1015400013D1C1220C4B92009A5892070AD58222DD +:1015500052009958002905D000219950074B0520C9 +:101560001B68984704BC9046F0BD00219950034B7E +:1015700004201B689847E4E700B00040DC0200202C +:1015800040B10040C123F0B5C64680249B00002531 +:10159000984600B5204E214F64024346F3581C4242 +:1015A00010D01F4AAB00944663441A68002A09D041 +:1015B000D2229200B450403AB4500022E8B21A60ED +:1015C0007B68984701356400042DE6D1C122124B97 +:1015D00092009A58D20704D58022520099580029C7 +:1015E00013D1C1220C4B92009A5892070AD582223D +:1015F00052009958002905D000219950074B052029 +:101600005B68984704BC9046F0BD00219950034B9D +:1016100004205B689847E4E700100140DC020020EA +:101620004011014003210A4802680A430260094848 +:1016300002680A4302600849084A094B9B1A03DD05 +:10164000043BC858D050FBDCFEF7B6FEFEF75CFD4D +:101650002405004054050040904500000000002093 +:1016600088000020FEE7FEE7FEE7FEE7FEE7FEE774 +:1016700008B5064B1868002803D1054902220A70F4 +:1016800002E001F049F9012008BDC046E402002053 +:101690002D030020014B1868407E7047E4020020B3 +:1016A00008B500F011FE002802D100F0F8FD01E0BD +:1016B000FFF7E6FD08BDF8B5051C0F1C161C072832 +:1016C00004D904221B4E0020327031E0032200298D +:1016D000F8D00622202EF5D800F04CFE0922022870 +:1016E000F0D8281C00F04AFE0A220228EAD800F0AE +:1016F00049FE08220128E5D900F0F4FD4378041CD6 +:101700000670012003436370391C321CA01C02F0D8 +:10171000B5FEE8B2211C00F0F9FD051C0120002DEA +:1017200006D1054802F0CAFA024F0F213970281C71 +:10173000F8BDC0462D030020DD000500F8B5061CED +:101740000D1C171C00F01AFE002803D1154F0B25A5 +:101750003D7025E00322002D07D0301C00F0FCFD79 +:101760003A6803789A4204D206220E4E0020327064 +:1017700016E0301C00F0E6FD041E0AD00278811C41 +:101780003A60281C02F07AFE201C00F0B5FD012012 +:1017900006E0054802F092FA02490F200870201C6A +:1017A000F8BDC0462D0300200501050008B5072837 +:1017B00004D9044B04221A70002001E000F0DAFD85 +:1017C00008BDC0462D03002008B5072805D9044BE5 +:1017D000042201201A70404201E000F0CFFD08BD54 +:1017E0002D03002008B500F0CDFD0623181A08BD12 +:1017F00010B5041E072C03D90B4B04241C7003E006 +:10180000FFF7D4FF022801DD00200CE0201CFFF7C9 +:10181000DBFF0228F8DCFFF7E5FF0623181A012199 +:1018200081429241504210BD2D03002008B50A4B61 +:1018300019684A7E002A04D0084A0C211170002041 +:1018400009E0072803D9054B04201870F7E7C0B258 +:1018500000F09CFD012008BDE40200202D030020C3 +:1018600008B5072804D9054B04221A70002003E0AC +:10187000C0B200F0A5FD012008BDC0462D03002028 +:1018800010B501280AD0002803D0022808D1002072 +:1018900000E0012001F028F8012005E00220F9E72E +:1018A000024B05221A70002010BDC0462D030020F7 +:1018B00010B500F011FD01280AD00224002808D03C +:1018C000A04201D1012404E0034802F0F7F900E04E +:1018D0000024201C10BDC0467001050038B5134A15 +:1018E000031C10680C1C407E002804D0104D022000 +:1018F0002870002018E001390F2903D90C4907226C +:101900000A7011E0002B03D1094C03232370F0E788 +:10191000084D191C10C5221C281C02F0AFFD281C04 +:10192000211C00F0BDFD012038BDC046E4020020AE +:101930002D030020640000200C4B10B51A680C68C1 +:10194000944201D3102C04D9094C072020700020A8 +:101950000AE0002803D1064903220A7004E00A6065 +:10196000191D02F08BFD012010BDC046640000204F +:101970002D030020014B18687047C046640000200A +:1019800008B5074B19684A7E002A04D0054B02208F +:101990001870002002E000F01DFD012008BDC046C7 +:1019A000E40200202D03002008B500F023FD08BD4F +:1019B00008B5074B19684A7E002A04D0054B02205F +:1019C0001870002002E000F01BFD012008BDC04699 +:1019D000E40200202D03002008B500F01FFD08BD23 +:1019E00008B50A4B1A68537E002B04D0084B02221C +:1019F0001A70002008E0072803D905480421017067 +:101A0000F7E700F011FD012008BDC046E402002008 +:101A10002D03002010B50C1C072804D90422064B06 +:101A200000201A7006E003220029F8D000F028FDFB +:101A30002070012010BDC0462D03002008B5074BC3 +:101A400019684A7E002A04D0054B02201870002035 +:101A500002E000F065FD012008BDC046E402002060 +:101A60002D03002008B500F061FD08BD08B50E4A41 +:101A7000031C1068407E002804D00C48022202702B +:101A800000200FE0012B0AD0002B07D0022B01D140 +:101A9000012004E0054B0E21197003E0022000F044 +:101AA000DDFD012008BDC046E40200202D0300201A +:101AB00008B501F023F80021012801D8014B195C79 +:101AC000081C08BD5045000008B5134B19684A7E34 +:101AD000002A04D0114A0221117000201BE00628C0 +:101AE0000FD802F06BFC12140406080A0C00FC204C +:101AF0000EE0F8200CE0F4200AE0F02008E0EC20F2 +:101B000006E0064B0E201870E7E7042000E00020F6 +:101B100000F046FD012008BDE40200202D03002056 +:101B200008B500F04BFDF02813D004D8042814D0D9 +:101B3000EC2806D10FE0F82807D0FC2803D0F428C1 +:101B400005D001200AE0022008E0032006E004207E +:101B500004E0052002E0062000E0002008BD08B5F2 +:101B6000064B19684A7E002A04D0054B02201870E3 +:101B7000002002E000F0E0FC012008BDE4020020AB +:101B80002D03002008B500F0DDFC08BD08B5074BAB +:101B900019684A7E002A04D0054B022018700020E4 +:101BA00002E000F097FC012008BDC046E4020020DE +:101BB0002D03002008B500F093FC08BD08B5074BC5 +:101BC00019684A7E002A04D0054B022018700020B4 +:101BD00002E000F0CBFC012008BDC046E40200207A +:101BE0002D03002008B500F0C9FC08BD08B5074B5F +:101BF00019684A7E002A04D0054B02201870002084 +:101C000002E000F0A5FC012008BDC046E40200206F +:101C10002D03002008B500F0A3FC08BD08B5074B54 +:101C200019684A7E002A04D0054B02201870002053 +:101C300002E000F0A9FC012008BDC046E40200203B +:101C40002D03002008B500F0A5FC08BD08B50B4B1E +:101C500019684A7E002A04D0094A02211170002026 +:101C60000AE0002805D0012803D0054B0E2018708B +:101C7000F5E700F05BFF012008BDC046E40200204C +:101C80002D03002008B500F057FF013843425841AA +:101C900008BD08B50A4B19684A7E002A04D0094AD3 +:101CA0000221117000200AE0002805D0012803D08D +:101CB000044B0E201870F5E700F050FF012008BD1E +:101CC000E40200202D030020F8B51E4D00241E4E16 +:101CD000071C281C211C0C22083034706C60FEF795 +:101CE0009FFA1A4800F048FE2860A04203D1012064 +:101CF0003070002024E0164B181D1968FFF7EEFD28 +:101D0000051C381CFFF7BCFD0540042000F0EEFB6D +:101D1000201CFFF79BFFEFB207400120FFF7D4FE26 +:101D200007400220FFF7A2FE0740201CFFF7B1FF8B +:101D3000041C01203C4000F0E7FE002CD7D001201D +:101D4000F8BDC046E40200202D030020C71D00009E +:101D50006400002008B500F007FF013843425841F5 +:101D600008BD024B0022DA607047C046E402002042 +:101D7000014BD8687047C046E4020020044B0022A3 +:101D800000B51A72904202D018610120187200BD8D +:101D9000E4020020014B18787047C0462D03002054 +:101DA000014B00221A7070472D030020014B586828 +:101DB0007047C046E4020020014B00225A60704781 +:101DC000E40200207047F0B589B0040C031C060A39 +:101DD00084460190101C039297B2020C0D1C002047 +:101DE00002910092E1B2624606AC069060600590F6 +:101DF000D0B21B0EF6B2052854D802F0DFFA031455 +:101E00002943403D6A4649B2484223701388E08026 +:101E1000281C6780A38000F06FFA301C0699626866 +:101E2000FFF780F941E022490B68587E002802D173 +:101E3000204801F043FF281C6D4600F05DFA6780E2 +:101E40002F88301CA78006996268FFF711FA2CE0F2 +:101E500048B205AC424223706280002B07D0002DAF +:101E600002D1154801F02AFF281C00F045FA301C69 +:101E70000599FFF701FA18E0FFF702FA15E0FFF7FE +:101E8000A1FF12E00A4DE9682B7A0131E960002BCD +:101E90000BD02F69002F02D1FFF702FC05E0013FB4 +:101EA0002F6102E0054801F009FF09B0F0BDC0460E +:101EB000E4020020B5030500C3030500E3030500A9 +:101EC000024B03490F221A70486070472D0300200F +:101ED000E402002000B5064A01231178022903D04C +:101EE0005068421E904100E0181C1840C0B200BD6E +:101EF0003003002008B5FFF7EDFF044B044A00282B +:101F000001D0D06800E09068186008BDFC02002095 +:101F10006803002008B5044B5A68002A01D0013A32 +:101F20005A60FFF7E7FF08BD3003002010B500231B +:101F30001A1C041C1C41012121400724E41AA14061 +:101F40000A430133D2B2082BF3D1101C10BD70B577 +:101F50000024061C251C301CE040C0B2FFF7E6FF41 +:101F60001823191B884008340543202CF3D1281C62 +:101F700070BD38B50D1C01F071FE084C63699D42BF +:101F800002D8074801F09AFE60690122291A054823 +:101F900002F058F90021616138BDC04630030020CD +:101FA0004D0609009D3C000007B5A12303210F4AFF +:101FB0008B40D15001F094FD002815D002280AD999 +:101FC000032811D1002300930193181C191C1A1C1B +:101FD00001F09EFC03E00020011C01F035FD042807 +:101FE00002D0034801F06AFE07BDC04600F0014080 +:101FF000E801090008B501F027FFA1230E4AD90026 +:10200000505001F06DFD012807D001F069FD022854 +:1020100002D00A4801F052FE002001F0B9FA02F0A5 +:1020200093F9074BA221CA0098500648064AC16896 +:102030004868985008BDC046001000401E060900C0 +:1020400000F00140FC0200201405000008B502F079 +:10205000EDF801280FD002F0CDF8074B187F0028CB +:1020600003D180210122CB055A60002001F0F6FD4A +:10207000024A0020506008BD6803002030030020A1 +:1020800010B501F06AFD00281AD00E4B00229A818B +:10209000DA8101F0C5FB0C4C0C49605001F0C0FB2B +:1020A000A62201238340D100635001F0BFFB084CFE +:1020B000206001F0C1FB074B6060E360FFF79AFF0F +:1020C00010BDC04630030020001000402C05000069 +:1020D0004C0300207D21000008B502F0A7F801287C +:1020E00022D101F0D5FD002802D0104801F0E6FD14 +:1020F0001E210F48002202F0A5F80E4B197F00297F +:1021000002D002F06BF80FE00B480C4B012202608A +:1021100059608021C8050260C046C046C046C0461E +:102120005A68002AFCD0ECE708BDC0462C0609001E +:102130009D3C00006803002014050040FC000040A6 +:102140001FB5FFF783FF01F0D9F80A4A002301A861 +:102150000521017043601C1C03814381437083701F +:10216000C3709370537601F09DFA03480470FFF733 +:102170001BFF1FBD3003002064030020F0B53E4B61 +:102180008022D000195887B0012904D03B4C00268A +:102190001D59B54206D13A4E2022776800263B7879 +:1021A0009A427641374C012561692E40281C00294E +:1021B00001D102F041F8284201D10120606101F013 +:1021C0008FFC012802D0304801F078FD2F4DEF68D8 +:1021D0003B7D002B02D02E4801F070FD01F08EF8FF +:1021E000002E47D00120011C01F02EFC042836D817 +:1021F00002F0E4F803321832320001F017FBE289F2 +:10220000071CA689019201F00BFBE9686D46897DE8 +:102210000497AF8803AB00221A701E815F8158704B +:10222000997014E001F002FB071CE089A689019077 +:1022300001F0F6FAEB686D469A7D0497AF8803AB20 +:1022400000219A7019701E815F8158700122DA7026 +:10225000181C01F027FA02E00E4801F02FFD01F0F2 +:1022600019FE0D4E206170696060FFF743FE00208B +:1022700001F016FE07B0F0BD00100040340500006C +:102280004C03002030030020A8060900FC020020B7 +:10229000A9060900C806090068030020704708B5B0 +:1022A000012282F31088074B597E002905D09878C7 +:1022B000002802D19A70FFF70FFF002282F31088E6 +:1022C00008BDC04630030020024B0120597E484023 +:1022D0007047C04630030020014B18787047C04655 +:1022E0003003002008B5012383F3108801F094FC2B +:1022F000002181F3108808BD08B5012383F31088FD +:1023000001F08EFC002080F3108808BD08B5012381 +:1023100083F3108801F0EAFB00280DD0084882788A +:10232000002A04D1417E002901D0FFF7D5FE002309 +:1023300083F31088012001E080F3108808BDC046B7 +:102340003003002008B5012383F3108801F0F6FB69 +:10235000002181F3108808BD08B501F0EAFB08BD33 +:1023600008B5012383F3108801F0D3FB002181F32A +:10237000108808BD08B501F0D8FB08BD08B501F00C +:10238000E7FB08BD08B501F04FFC08BD10B50123FF +:10239000041C83F3108808480278002A05D0417E87 +:1023A000002902D0054801F089FC201C01F0B5FB92 +:1023B000002484F3108810BD30030020FB020900C4 +:1023C00008B5012383F3108801F0BDFB002080F3E2 +:1023D000108808BD08B5044B1862FFF7B8FD034923 +:1023E000034A505008BDC046680300201C05000089 +:1023F00000100040014B186A7047C0466803002077 +:1024000008B5044B5862FFF7A2FDA421024ACB0095 +:10241000D05008BD6803002000100040014B586AEE +:102420007047C04668030020F8B5031C081C072B42 +:102430001AD80F4A03261E40D118F600FF24B440D4 +:102440002831E74308700B4C032B01D80A4D01E0FB +:10245000A525ED0063591F406751FFF767FD6759D8 +:10246000B0400743675102E0044801F027FCF8BD83 +:102470006803002000100040240500003903090013 +:1024800010B5041E072C02D9034801F017FC034BBA +:1024900018192830007810BD410309006803002096 +:1024A00038B5051C0C1E02D1074801F007FC002DB1 +:1024B00002D1064801F002FC054B00209D605C60E3 +:1024C00001F0D6FC38BDC0464803090049030900A5 +:1024D000FC020020014B58617047C0466803002091 +:1024E000014B58697047C04668030020064B074AF5 +:1024F000A32110B55877CB00D458010404482040DC +:102500000843D05010BDC0466803002000100040B2 +:10251000FFFFF8FF014B587F7047C046680300205B +:10252000014B18617047C04668030020014B1869D1 +:102530007047C04668030020014B58607047C04692 +:1025400068030020014B58687047C04668030020AC +:1025500008B5024BD860FFF7CDFC08BD680300202A +:10256000014BD8687047C0466803002008B5024B8D +:102570009860FFF7BFFC08BD68030020014B986816 +:102580007047C04668030020014B58837047C0461F +:1025900068030020014B588B7047C0466803002039 +:1025A000034B0449044A3033187050507047C046FA +:1025B000680300200C05000000100040014B303380 +:1025C0001878704768030020184B10B53133187025 +:1025D000174A184BFF249958A1439950032821D832 +:1025E000995801F0EBFE1D020A1401242143995071 +:1025F0001149FF205850114906E00220014399502B +:102600000F490D4A99500F49A722D20008E0032430 +:10261000214399500C480849A7225850A240002154 +:10262000995002E0094801F049FB10BD6803002001 +:1026300034050000001000403C05000007010000C8 +:10264000FFFF000021100100FFFFFF00C20309008F +:10265000014B313318787047680300201F4B00B5D9 +:1026600032331870012821D0002810D0022834D12C +:10267000A2211B4ACB00D0501A491B481B4A0860B4 +:102680001B4B1C481C491A6008601C4A20E0A2230E +:10269000134AD9005050134B1348154A1860134978 +:1026A0001748154B11601860164A11E0A2230C4A16 +:1026B000D90050500B4B0C480C490D4A1860116062 +:1026C0001148124A0C4B124918601160114A02E07D +:1026D0000E490A60104A1148026000BD68030020DC +:1026E0000010004024170040005000784E000054B5 +:1026F0002817004008800C602C1700408864720086 +:1027000003800C602264720002800C60301700406D +:1027100011646600DEC08F823E420F823417004093 +:10272000F8B5A122334C344B344E354DD000002740 +:1027300003210122F750315067516251E05831496D +:102740000F220140E150E558062095430543E5502E +:10275000E1582D4DC02290020D400543E550A323C2 +:10276000DD006159294A80230A40625160595904A9 +:10277000014361516059FF22904320231843605167 +:1027800061592348C0220840605122485300022169 +:10279000C15001F0D5FD2049204A70507251204DA2 +:1027A000032373511F4800F0E1FD1F4E1F4DF060E1 +:1027B000687FFFF79BFE286AFFF70CFE686AFFF749 +:1027C0001FFEE81928300178381C0137FFF72CFE6E +:1027D000082FF6D12F1C30373978154AA1502C1C00 +:1027E000313420783235FFF7EFFE2878FFF736FFD7 +:1027F000F8BDC046001000401405000000F0014084 +:10280000FC0F0000FFFEFFFFFFFFF0FFFFFFFFFDDB +:10281000FF00FFFF00E100E01C0500000411004084 +:10282000040500004C030020FC0200206803002087 +:102830000C05000070B5274E86B0337872789A4246 +:1028400045D0002B01D1FFF76BFF7078002801D134 +:10285000FFF7AAFB2049214D00246C5000F04EFDEB +:102860001F4D2C606C602C61AC60EC603378012BE8 +:1028700008D101F035F9A04217D0201C211C01F02D +:10288000E3F812E0022B10D100F038FD154A2C615C +:10289000147001F025F9032807D100940194201C3D +:1028A000211C221C231C01F033F8FFF723FB707856 +:1028B0000024307003A8042606704460048144811B +:1028C00044708470C47000F0EDFE012000E0002030 +:1028D00006B070BD300300201405000000F0014078 +:1028E0004C0300206403002008B5012383F3108803 +:1028F00008490A78824208D04870487E002802D1F0 +:10290000FFF798FF01E0FFF7E7FB002383F3108850 +:1029100008BDC0463003002038B5124B5A7E1C1C3F +:10292000002A1DD1FFF7FCFE0F488168051C002915 +:1029300002D10E4801F0C2F96B68002B02D10C489D +:1029400001F0BCF901F098F9002802D0094801F023 +:10295000B5F9002001F082F901226276FFF7BCFB95 +:1029600038BDC04630030020FC0200205E02090092 +:102970005F02090066020900F8B5071C012080F318 +:102980001088544D544B554E0024002203211C60E6 +:102990005C609C60DC601C611A7529702A766A761E +:1029A000B46074606870AC706C60AC60AC81EC81D9 +:1029B0002C616C6101F0D6FB381C00F059FE00F070 +:1029C000F5FE201C01F042F9301C01F07BF9444F68 +:1029D000C2208300F958434AC0260A40FA50B0008A +:1029E0003B584149C522194039509600BB59FF2038 +:1029F000402183430B43BB510120FFF775FF3B4E42 +:102A00003B4B3C48311C3362706228310123301C3F +:102A10000B7029300223311C03702A310320087007 +:102A2000FF22311C32612B3104220A707277321C72 +:102A30002C3205201070321C2D320621301C1170F2 +:102A40002E3007220270301C2F300821321C0170FA +:102A5000303200201070321C0120311C32321070D4 +:102A6000313196229A400B701E2171617260F360C1 +:102A7000FFF740FA0F23B360FFF73CFA012074839D +:102A8000307670760021201C6924317701F0D0F86F +:102A900034606E780124A64202D0174801F00EF986 +:102AA00000262C70AE706E60AE60AE81EE812E613D +:102AB0006E612E766E76FFF733FEC0238021802272 +:102AC0005800CC0053033C503B5086F31088281C20 +:102AD000F8BDC046300300204C030020FC0200205B +:102AE00000E100E0FFFF00FFFF00FFFF68030020A0 +:102AF00004070A0D05080B0E3C020900014B323396 +:102B00001878704768030020054B10B5041CD8687E +:102B1000002802D1034801F0D1F803490C7510BD1B +:102B2000FC020020F60309004C030020014B18763C +:102B30007047C04668030020014B187E7047C046AE +:102B400068030020014B58767047C0466803002098 +:102B5000014B587E7047C04668030020014B187730 +:102B60007047C04668030020014B187F7047C0467D +:102B70006803002008B501F05BF808BD08B50B4BF1 +:102B8000D868417D002906D0012000F05BFB084B8E +:102B90009A8901329A810749074B084A0020585008 +:102BA00051681368C91AFFF7E4F908BDFC02002058 +:102BB000300300201405000000F0014068030020ED +:102BC000084B10B51A781C1C012A02D0064801F0E7 +:102BD00075F80649064A0220002320700B61CA607E +:102BE00010BDC04664030020920509004C0300207C +:102BF000912C000010B500F081FB194819491A4CBE +:102C000000230122027023610869A623174AD90014 +:102C1000505000F065FF00280AD100F075FD012832 +:102C20000DD900F00FFE6060002808D1104804E0C4 +:102C300000F056FF032802D00E4801F03FF80220B2 +:102C400000F0A6FC002000F0FDFA00F049FF032888 +:102C500002D0094801F032F8FFF7B2FF10BDC046BC +:102C600064030020680300204C0300200010004093 +:102C70007B050900800509008805090008B5034B9C +:102C800005221A70FFF7B6FF08BDC0466403002096 +:102C9000F0B5484A8023D800115887B0464C012926 +:102CA00004D0464D002356599E4205D16768002343 +:102CB0003978202088425B41414E032500210127BD +:102CC000357021603B408B4255D08123D800155888 +:102CD0003C4B11583C48D15002A912583B1C009162 +:102CE0000194381C291C00F013FE032841D801F080 +:102CF00065FB1E02204E0298002802D0334800F0E7 +:102D0000DDFF281C00F024FF002802D1304800F02D +:102D1000D5FF304903A8CF680223B97D002703708F +:102D200047603A1C07814781457081701DE02A4841 +:102D30002BE0029A002A02D1284800F0BFFF281C8D +:102D400000F006FF002802D1254800F0B7FF214F10 +:102D500003A8FB68029F997D02220023027047604E +:102D600003814381457081700122C27000F09AFC9A +:102D70000DE01C4809E000930193181C191C1A1C53 +:102D800000F0C6FD042802D0174800F097FF256820 +:102D9000002D06D100F0B2FA65752561FFF72AFF14 +:102DA00005E012480122627520610424347007B0E6 +:102DB000F0BDC046001000404C0300203405000068 +:102DC000640300202C0500000C040000B805090075 +:102DD000B9050900FC020020BD050900C005090075 +:102DE000C1050900C8050900CF0509007D2C0000B8 +:102DF00070B50C4DA124E4002E5901F025F886424F +:102E00000AD001F021F82851FFF7F4FE064900200E +:102E10004968FFF7AEF870BD044B18780028F3D06E +:102E2000F4E7C0460010004068030020640300205F +:102E3000F0B5864C0125636989B0281C002B01D1AF +:102E400001F0FAF90126284000D0D3E02178B14200 +:102E500002D100F04BFA10E0022908D000F042FF46 +:102E6000FFF758F8A678002E00D0A9E00EE0784AC7 +:102E70001378033BDDB2AE4240410028EED0754EE0 +:102E800075487768012279086161CBE0FFF7D2FCD1 +:102E9000704D071E00D08EE020780190061E012E96 +:102EA00006D0002863D0022865D1FFF7A1FF65E0B6 +:102EB00000F024FA00F014FE00281DD100F024FCDC +:102EC000012851D9FFF706F8071E0CD000F0FAFFD1 +:102ED000002849D1287E00280BD100F0DBFF2669AD +:102EE000B04241D105E0206900F0C2FF381C00F07B +:102EF000D7FFFFF7C5F837E0698B002920D0A289FA +:102F00008A421DD3311C381C00F09EFD00F08EFC5F +:102F10000290A2890392E68900F082FC69460A7950 +:102F2000029905AB1A7006910C226946515A5870E5 +:102F3000181C19815E819F70DF7000F0B3FB13E0F5 +:102F400001F07AF9002802D0444800F0B7FEA1232E +:102F50004348DF00C65900F077FF864202D0E1897E +:102F60000131E181FFF746F80120296800E0696836 +:102F7000FEF7FFFF02E03B4800F0A0FE6D7E012D52 +:102F800023D1FEF7A7FF00281FD12478012C07D0FA +:102F9000002C0DD0022C18D0334800F08FFE14E026 +:102FA00000F09EFD002810D100F034FC00280CD168 +:102FB000FFF74CF809E06968301CFEF7DAFF04E01F +:102FC000647E002C01D0FFF7BBF800F09DFB0128C8 +:102FD0000CD905A8002103230370416001814181C0 +:102FE00041708170C17000F05DFB2DE01F4800F062 +:102FF00065FE29E0FEF78EFFA778002F1DD121780E +:10300000022912D1124B1D78033D012D04D900F085 +:1030100069FEFFF7EDFE17E00E4F321C786841089D +:103020000D48616101F00EF90EE000F05BFE094A07 +:10303000381C5168FEF79DFF06E000F053FE607EED +:10304000002801D0FFF77CF809B0F0BD3003002064 +:1030500064030020680300209D3C00000A0509006D +:103060000010004058040900720409008C04090093 +:1030700007B50190C046C046C046C046C046C046DF +:10308000C046C046C046C046C046C046C046C04610 +:10309000019B013B0193002BECD107BD70B5802251 +:1030A000164B910000245C501549C2250E78AD00E6 +:1030B000144A032E07D109267442C1265C51082503 +:1030C000B4001D510AE0012676425E51C0230E4D28 +:1030D00002265B00EE50146103244C700023536001 +:1030E000536193604B600B75984205D007480168A7 +:1030F0000A69002A00D0904770BDC0460010004009 +:103100009C030020FC10004000E100E00C030020C4 +:10311000F8B53F4B1A69012A53D19D693D4C802275 +:1031200096000135032104209D611870C025A1512E +:1031300039496A0002278F50384F00263E61C1226C +:103140007E607E61BE60364E082591006550356810 +:103150002A7D3D1C002A17D0A927F9006258314F5B +:103160009A75A023D9007A58024202D12E4800F065 +:10317000A5FD00200123A12228620421A361D30020 +:10318000F950A927F90060506868002802D0274844 +:1031900000F094FD2D69002D02D0254800F08EFD31 +:1031A000244A536899072DD43768F968002900D05C +:1031B00088473668707D002828D035681E4AA5509B +:1031C00024E0022A1AD1154900250D6111484D61EC +:1031D00080244D6001278D60C221A6007A428C00B8 +:1031E00085511D700251032058705D601D750C4B98 +:1031F0001E683769AF4209D0B84707E00F4800F0B2 +:103200005DFD03E00E4800F059FDCDE7F8BDC04676 +:103210009C0300200010004000E100E0FC10004092 +:103220000C03002000F00140AD020A00B6020A00C3 +:10323000B7020A00FCE100E004050000E7020A0012 +:10324000B8020A0070B51E4D061C6B7D6C78002B11 +:1032500002D11C4800F032FD287D002802D01A4817 +:1032600000F02CFD012200212A756975022C0CD872 +:1032700016482301C318002E01D11E683260621E59 +:10328000012A05D8997A297002E0114800F016FD4C +:10329000104D2868037D002B11D0022C0FD10E4C4D +:1032A0000E4E251C3259530702D40D4800F006FD7E +:1032B0000C494859002802D10B4800F0FFFC70BDB2 +:1032C0009C03002021010A0022010A00544500004D +:1032D0003A010A000C0300200405000000F0014040 +:1032E00040010A000010004041010A00024B9868AA +:1032F0000138434258417047FC100040F8B5164B66 +:10330000164C02200121C027C222D8674D428240BC +:103310007B00134E8021134FA55081400025F050B3 +:10332000012265507D61104D2261A2612C7894428A +:1033300001D1062003E0023C012C00D9101C00241E +:10334000FFF796FE7C61201C2C70FFF7A7FE022081 +:103350006C753060F8BDC04604E100E0001000402C +:1033600000E100E0FC1000409C03002038B50E4B4B +:103370000E4C18600E490F4B0F4A0225201DC567E1 +:1033800099500E48A421CA009850FFF7B7FF0C4887 +:10339000002303210370417043600361037543758B +:1033A0008375256038BDC0460C03002000E100E0B5 +:1033B0001410004000F001402405000004110040FA +:1033C0009C03002070B55C4C2369607D01336578F7 +:1033D0002361002802D0594800F070FC21780329AD +:1033E00048D1574E3269002A44D0012D35D1226987 +:1033F000032A02D0534800F061FCA0690221013089 +:10340000514A8025A06100238D4001202170535135 +:103410004542C22088401550C02568004B4D2950B8 +:103420004B493361096873607361B360032666704A +:1034300063602375087D98420DD0A925E8001658D1 +:103440000125A6753E4C042623629561A124414DB9 +:10345000E4002E511350CA6865E0022D08D123699B +:10346000012B02D03C4800F029FCFFF751FE61E03F +:103470003A485DE0032D5AD0012D3CD12169012944 +:1034800018D12F480021304B0126C22241608160B3 +:1034900070429100C1265850B0001D502C4D304E46 +:1034A0002A68117D002902D02A4D0420A851E46821 +:1034B0009C513FE002293DD1234E214A8023002523 +:1034C00098000221C22315615561556035504A426A +:1034D0009800C12132508B000822F250032626703A +:1034E000656025751A4C2568261C2869002800D0BF +:1034F0008047306816E0022DB7D0657819482B0157 +:10350000C1180E7B0025AE4203D00D4A15696A1E14 +:1035100095418B7A01202370FFF7C0FD002D09D063 +:103520000B4C20688268002A04D0904702E00E48C5 +:1035300000F0C4FB70BDC0469C03002090010A004F +:10354000FC1000409F010A000010004000E100E074 +:103550000C03002000F00140A4010A00A9010A00A8 +:103560000405000054450000D6010A0008B50228F1 +:1035700004D8054B18784342584103E0034800F053 +:103580009DFB002008BDC0469C030020F9020A00F4 +:10359000F8B52B4C0301061C2A4F207DFF1800288C +:1035A00002D0294800F08AFB301CFFF7DFFF00281B +:1035B00002D1264800F082FB0121C222244D0023C3 +:1035C000484291006375C02268502249022052008F +:1035D0008850214866700268116852682361A361AF +:1035E0003B68A160E2606360022E18D8387A8023BD +:1035F0009B00E850F87A194B002805D1E950EA58A9 +:10360000002A08D1164804E0EA50E958002902D1FE +:10361000144800F053FB7F7AC1208300EF500E4D19 +:1036200029680A7D002A07D0022E05D10B480E4BCF +:1036300000260427A6751F5001256575F8BDC046F4 +:103640009C03002054450000DB000A00DD000A0056 +:103650000010004000E100E00C0300200405000021 +:1036600000010A0005010A0000F001407047C04651 +:1036700010B5041E02D1084800F020FB074B0022C1 +:103680001C60191DDA670833CA678020DA67044BAB +:1036900044031C6010BDC04629000B00C00300207D +:1036A00000E100E070B5144C051C2368002B02D12A +:1036B000124800F003FB201C0830C16F092902D911 +:1036C0000F4800F0FBFAE66F0C225643A3190433AF +:1036D00043CD43C3251C0835E86F0130E867E16F2F +:1036E0000131E167E66F092E01D90022E2678024EB +:1036F000044B65035D6070BDC003002034000B0007 +:1037000035000B00FCE100E0034B0A200833D96FC1 +:10371000421AD0B27047C046C0030020F0B587B04F +:10372000012383F31088134C124D0834E06F0028F6 +:103730001BD02A1DD16F0C26714303AB69180431CD +:10374000181CE0C9E0C0E76F0026013FE767D46FAF +:103750000134D467D56F092D00D9D66786F3108858 +:10376000044A176807CBB847DAE780F3108807B038 +:10377000F0BDC046C003002038B50A4C051CE36FFD +:10378000002B02D1084800F099FA291C0831E06F9B +:1037900000F03CFC0021884201D0E1670121081CB7 +:1037A00038BDC046480400206F020C0010B500F080 +:1037B000B7FB0021124A8800002384188818A361EF +:1037C000A363041C80348830237003700D480C18E8 +:1037D000013123700829EDD1111C101C141C9031EB +:1037E00091305834137053609360D3601361536108 +:1037F0000B7003702370D36792320123137010BDD6 +:1038000048040020DC040020014B185C7047C046CF +:10381000DC040020014B90331878704748040020E6 +:10382000014B58687047C04648040020014B986817 +:103830007047C04648040020014BD8687047C04616 +:103840004804002010B5104C2378002B02D00F48FC +:1038500000F034FAE06F002802D100F08BFBE06743 +:10386000E06F00280FD0012143784A4206210B4324 +:10387000437002700023C218FF2101339170202B86 +:10388000F9D10323237010BD480400203B010C0034 +:1038900038B5124C2378002B1ED1201C90300178B3 +:1038A000002919D10825606900F028FC002805D0FE +:1038B000231C6069903301221A7020616169013113 +:1038C000082900D10021231C616190331A78002A55 +:1038D00002D1013D002DE6D138BDC046480400208C +:1038E00038B5094D041C2B1C90331878002804D0DF +:1038F0002969A14201D1FFF7CBFF2A19034B00250B +:10390000803215701D5538BD48040020DC040020AD +:10391000F0B5464D85B00393EB6F061C0C1C171CCD +:10392000002B02D1424800F0C9F92878032802D0C0 +:10393000404800F0C3F9E96F01234A781A4202D1E6 +:1039400092352D786B400425002E61D0500701265A +:10395000810F1E40251C231C0A0608330E353F022A +:103960003249A8003F0A02930B5817430B980A9A52 +:103970000025156005609F4233D0201CFFF7FCFE38 +:103980000190AE4200D0051C01232E1C1E400028D1 +:1039900028D00299254A063188008750039F1D1CB4 +:1039A000002F20D0244F3B5D002B1CD0201C00F0AA +:1039B000A5FB002802D1214800F080F9201C00F06E +:1039C0005BFB051E02D0201CFFF78AFF0A990D60E1 +:1039D000002D02D11A4800F071F900203855022557 +:1039E00001E001950325002E0DD0201C00F06CFB9A +:1039F0000B9E3060002802D1124B336005E00E4F61 +:103A000001223A5501E00B9C26600199002905D15D +:103A1000064CE06F00F0CCFA0020E067034A002675 +:103A20001670FFF735FF281C05B0F0BD48040020D4 +:103A30005B010C005C010C00DC04002091010C0017 +:103A400096010C00A0040020F8B51F4C071C237839 +:103A50000E1C013B012B02D91C4800F02FF9042554 +:103A6000002F19D02078012802D0194800F026F93B +:103A7000E268002A02D1174800F020F9E168002529 +:103A80000F78AF4208D06068FFF776FE0225002865 +:103A900002D1114800F012F9002E0ED06768381CD0 +:103AA00000F0EAFA061E02D0381CFFF719FFA368DF +:103AB0009E4202D0094800F001F900202070FFF773 +:103AC000E7FE281CF8BDC04648040020FC000C009E +:103AD00002010C0003010C000E010C001E010C0081 +:103AE000014B18787047C0464804002038B5041CC4 +:103AF0000D1C00F013FB002801D1002008E0281C59 +:103B0000211C00F083FA0028F7D0FFF7C1FE012046 +:103B100038BD08B500F0D8FA08BD10B5041CFFF791 +:103B2000DFFE201C00F000FB10BD08B500F0E6FA37 +:103B300008BD08B5083000F0C7FA08BD08B5083060 +:103B400000F09AFA08BD08B5083000F0EDFA08BD9B +:103B500008B5083000F0D2FA08BD10B52A4C237819 +:103B6000002B02D0294800F0A9F8201C90300178E1 +:103B7000002927D02069606000F0A6FAA060002824 +:103B800002D1234800F09AF8A2680123507803403C +:103B900004D1211C92310A78002A10D16068FFF705 +:103BA000D7FF02280ED8E36F002B02D100F0E2F914 +:103BB000E067E16FE160002904D0012001E0E360EB +:103BC000022020702278002082421BD0A36883420A +:103BD00002D1104800F072F8206960600630810060 +:103BE0006318DA7803210132D0B2D870A368084094 +:103BF0005A784100062082430A435A7090340023C9 +:103C00002370012010BDC04648040020C3000C00F2 +:103C1000C9000C00E7000C0008B500F0ABF908BDC6 +:103C200008B500F0C5F908BD08B500F077FA08BD81 +:103C3000014B92331870704748040020014B9233B7 +:103C400018787047480400207047C046024B9870AF +:103C5000587018707047C046E404002010B5041E68 +:103C6000012C02D9024800F029F8024B5C7010BD0B +:103C70002A000D00E4040020014B18787047C0466C +:103C8000E4040020014B98787047C046E40400200B +:103C9000014B58787047C046E404002008B5054B36 +:103CA0001A7858789A701870034B8100CA58904758 +:103CB00008BDC046E40400207800002008B5FEF7E7 +:103CC000FFF808BD10B5041E02D10448FFF7F6FF47 +:103CD000034B00221C605A609A6010BD2A0001004C +:103CE00010030020094B00B518689A68016801327A +:103CF0009A608A4208D359684068002201319A606C +:103D00005960814200D35A6000BDC04610030020B4 +:103D1000F8B500282AD0164CA36801280ED12768D0 +:103D200001333A68A360934220D360687968002524 +:103D30000130A5606060884218D316E02668C71875 +:103D40003568A760381C291C00F042FB62683B1CE8 +:103D500080186060AB4201D35B1BFBE7716865684C +:103D6000A3608D4201D36D1AFBE76560F8BDC046C4 +:103D700010030020024B1A6899681068401A7047B7 +:103D80001003002070B50D4D041C2B685868844248 +:103D900002D30B48FFF792FF6E68B4420CD002D8F2 +:103DA00029684A68A418FFF7E5FF2D68F3432E68D9 +:103DB00019197143081800E0002070BD100300209D +:103DC0006800010070B5041C0D1C884202D30B482A +:103DD000FFF774FF0A4E33681868854202D9094814 +:103DE000FFF76CFFB168601AA14206D30020A94218 +:103DF00003D3326815686E1A301970BD7D0001005A +:103E0000100300207E00010038B5041C101C0D1C9E +:103E1000FFF7B8FF002801D0001911E0201C291C71 +:103E2000FFF7D0FF041CFFF7A5FF031C201E9842DC +:103E300006D304490D686A682C68013A5443001996 +:103E400038BDC04610030020074B10B51A685968EA +:103E500050681C1C814202D30448FFF72FFF2368DF +:103E600061689A68505C10BD10030020B200010028 +:103E700038B5064B041C1A681D1C5068844202D3D6 +:103E80000348FFF71BFF6C6038BDC04610030020DD +:103E9000B9000100014B58687047C046100300206C +:103EA00038B5064B041C1A681D1C1068844202D3E6 +:103EB0000348FFF703FFAC6038BDC0461003002085 +:103EC000C5000100014B98687047C04610030020F0 +:103ED00010B50F4B1A68002393420BD20D499C007A +:103EE0006458A04203D10C48FFF7E8FE0CE0013310 +:103EF000DBB2F1E7002422226243084953189842BA +:103F000004D00134062CF6D1002000E0012010BDC1 +:103F1000E8040020EC040020F6000300F405002073 +:103F200010B500220F495000801800230C180132F0 +:103F30006370A3704354102AF4D122225A430A49D1 +:103F40000A485418211C9A0084502231DE22227023 +:103F500001348C42FAD10133062BEED1044C23609C +:103F600010BDC04604050020F4050020EC0400202C +:103F7000E804002038B50A4B1C68002C0ED0621EE5 +:103F8000084990004458084D1A604550201CFFF71E +:103F90009FFF002802D10548FFF790FE201C38BD86 +:103FA000E8040020EC040020ADDEADDE7D0003005F +:103FB00070B5104C051C2368052B02D90E48FFF77D +:103FC0007DFE281CFFF784FF002802D10B48FFF775 +:103FD00075FE21680A488A0011580A4B061C99424E +:103FE00002D00948FFF76AFE206882000130B55010 +:103FF000206070BDE80400208500030086000300F7 +:10400000EC040020ADDEADDE88000300F8B5051C31 +:104010000C1E0F2C02D91448FFF750FE281CFFF786 +:1040200057FF002802D11148FFF748FE10496600EB +:104030003019435C0022022B13D80B185F78C0198B +:104040000C4F8000C5515D780135E8B258705F783B +:10405000022F00D95A7032198C5C0134E6B28E54AA +:104060000122101CF8BDC0468F0003009000030021 +:10407000040500203405002038B5041E0F2C02D999 +:104080000E48FFF71BFE0E4A65002919885C0028C0 +:1040900013D05318987809180A4889000858997855 +:1040A0000131C9B299709978022901D9002199701A +:1040B0002C19155D013DEBB2135538BDA600030068 +:1040C000040500203405002010B5041E0F2C02D971 +:1040D0000748FFF7F3FD074B62001119C85C002881 +:1040E00005D0581884780B1903499A00505810BD10 +:1040F000B7000300040500203405002010B5041E9D +:104100000F2C02D90348FFF7D9FD630002491819A3 +:10411000405C10BDC800030004050020014B186876 +:104120007047C046E804002038B5051E0F2D0CD995 +:104130000948FFF7C3FD08E0084B9C4202D108483C +:10414000FFF7BCFD201CFFF733FF281CFFF794FF8F +:10415000041EF1D138BDC046D7000300ADDEADDE90 +:10416000DB000300164BA12110B50122CC0000207A +:104170005A60DA6018515A64124A1C1C99588142DC +:1041800002D01148FFF79AFD0123C2225842910044 +:104190000E4B60500022A2215A640420CB00E05054 +:1041A0000B490C4C012022602271627108700A4B8D +:1041B0008022C021D40081405C501C6010BDC046EC +:1041C00000A000404405000035000400FCA00040B1 +:1041D000C00600201C03002000E100E0034B04495E +:1041E000012200201A6008707047C04600A00040FD +:1041F000C0060020094A30B501235360084CD36043 +:104200008025084AC0200021ED00984011601171FE +:1042100025505171044A137030BDC04600A00040C3 +:1042200000E100E01C030020C0060020014B1878CC +:104230007047C046C0060020014B18797047C04641 +:104240001C030020F7B5334F0092334C8022C22369 +:104250007E790191051C990050026050002E02D019 +:104260002E48FFF72BFD002D02D12D48FFF726FD2C +:104270003A68002A02D02B48FFF720FD3D60009DE0 +:10428000294E012D0DD0002D03D0022D0DD1A922D4 +:1042900008E00120254B00996064E55820647164B2 +:1042A00007E0A822D500655903E02148FFF706FD85 +:1042B000002501227A71019FA821E81987B2002305 +:1042C000C80073642750275800976264174AA7589C +:1042D000716C1E1C994202D01648FFF7EFFC009B40 +:1042E000AB4205D3AF4201D39F420CD3124808E042 +:1042F000301CAF427041009DAF427641B04202D0C7 +:104300000E48FFF7DBFC8022C12157028E00A75127 +:10431000F7BDC0461C03002000A00040730004004D +:104320007500040076000400FCA000404405000075 +:10433000890004009B000400B0000400C9000400D0 +:104340000048704748A000400048704740A1004026 +:1043500070B58022134C144DC223500299000026E0 +:1043600068506664114C2268B24202D11048FFF7CF +:10437000A5FC104B012166712068A82226606964A3 +:10438000EE58D300EA580C4D1432AE4203D8C02385 +:104390001D02AA4202D8002196424941217180475C +:1043A00070BDC046FCA0004000A000401C030020DF +:1043B000EC00040044050000FF3F000002B4714619 +:1043C00049084900095C49008E4402BC7047C04658 +:1043D000002934D00123002210B488422CD30124B8 +:1043E0002407A14204D2814202D209011B01F8E74D +:1043F000E400A14204D2814202D249005B00F8E706 +:10440000884201D3401A1A434C08A04202D3001B31 +:104410005C0822438C08A04202D3001B9C08224364 +:10442000CC08A04202D3001BDC082243002803D0A2 +:104430001B0901D00909E3E7101C10BC704701B546 +:10444000002000F00BF802BD0029F8D003B5FFF7FB +:10445000C1FF0EBC4243891A1847C0467047C04688 +:1044600030B500240139A24201D1002005E0035DEE +:1044700001340D5DAB42F6D0581B30BD002310B5A2 +:104480009A4200D110BDCC5CC4540133F8E700005F +:10449000F8B5C046F8BC08BC9E467047F8B5C046A3 +:1044A000F8BC08BC9E46704700000020656E637231 +:1044B000797074696F6E206B65790000656E637248 +:1044C000797074696F6E206E6F6E63650000000016 +:1044D0004D4143206B65790004450000E444000031 +:1044E000F4440000A909B09D364DC240EB37CB1310 +:1044F000F3B3E641FFE55DCC7BCE111FB3B6E87E9A +:10450000A381E049993FFC88BF214490F02B532EB2 +:1045100002FF7EC5D4EC881E320E9786F2DB75FA58 +:1045200073DA8A10A909B09D364DC240EB37CB1320 +:10453000F3B3E641001001401101040000B0004057 +:104540000B000400FF0F030000001F000302000027 +:104550000102000000100040101100400310000094 +:104560000100000000100040000000000B020400E9 +:1045700000000000041000400000000007080301D4 +:08458000000000000000000033 +:0845880080BBFF7F0100000071 +:10459000000000000000000000000000000000001B +:1045A000000000000000000000000000000000000B +:1045B00000000000000000000000000000000000FB +:1045C00000000000000000000000000000000000EB +:1045D00000000000000000000000000000000000DB +:1045E00000000000000000000000000000000000CB +:1045F000240300200500000004192A3F4D0000009C +:104600000000000000000000312E00007D2B0000A3 +:08461000E9000000C1000000F8 +:0400000300001625BE +:00000001FF diff --git a/precompiled/precompiled-crypto-receiver.hex b/precompiled/precompiled-crypto-receiver.hex new file mode 100644 index 0000000..7dc9caf --- /dev/null +++ b/precompiled/precompiled-crypto-receiver.hex @@ -0,0 +1,1236 @@ +:1000000000400020DD1C00001D1D00001F1D000021 +:1000100000000000000000000000000000000000E0 +:10002000000000000000000000000000211D000092 +:100030000000000000000000231D0000251D00003E +:10004000271D00007D3A0000411B0000271D000015 +:10005000271D000000000000271D0000271D0000D4 +:10006000271D0000271D0000094A0000271D000071 +:10007000271D0000271D0000271D0000271D000070 +:10008000271D0000271D0000271D0000271D000060 +:10009000D53D0000271D0000271D0000271D000082 +:1000A000271D0000271D00000000000000000000C8 +:1000B0000000000000000000000000000000000040 +:1000C00010B5064C2378002B07D1054B002B02D02E +:1000D000044800E000BF0123237010BD9000002001 +:1000E000000000007C4C0000044B10B5002B03D036 +:1000F0000349044800E000BF10BDC04600000000F6 +:10010000940000207C4C0000144B002B00D1124BBB +:100110009D46402292029A1A924600218B460F4633 +:100120001148124A121A00F07BF80D4B002B00D038 +:1001300098470C4B002B00D098470020002104006A +:100140000D000B4800F016F800F046F820002900DA +:1001500000F0DEFA00F016F8000008000040002071 +:10016000000000000000000090000020D8090020DE +:10017000B1010000002310B501001A00180000F0C2 +:1001800057F810BD084B10B50400002B02D0002119 +:1001900000F0B4F8054B1868836A002B00D098472C +:1001A000200000F007F9C046FD020000604B00008F +:1001B00070B5074D074C641BA410002C02D104F04D +:1001C000C9FC70BD013CA300EB589847F5E7C04659 +:1001D000880000208C00002070B500260C4D0D4CCE +:1001E000641BA410A64209D1002604F0ADFC0A4D00 +:1001F0000A4C641BA410A64205D170BDB300EB5895 +:1002000098470136EEE7B300EB5898470136F2E71E +:10021000840000208400002084000020880000204A +:1002200003008218934200D1704719700133F9E737 +:10023000F0B52D4D85B0060028680192009102931B +:1002400000F0B4F8294A1468002C0AD1284B136036 +:10025000284A1C00002A04D0190012688831039231 +:100260000A6063681F2B06DD286800F0A1F80120F2 +:10027000404205B0F0BD002E29D0270088373868ED +:10028000002812D11C4B002B03D1286800F08FF8F6 +:10029000EDE78420400000E000BF0028F5D0030017 +:1002A0000022FC335A609A6038606168019A8B00C2 +:1002B000C31804C301228A40FC30416811434160E5 +:1002C0000299D967022E02D183681A43826063685B +:1002D00028685A1C62600233009A9B001A5100F091 +:1002E00067F80020C5E7C046600000203801002004 +:1002F000AC0000200000000000000000F7B5294B12 +:10030000019018680F0000F051F8274B1D68002D70 +:1003100004D1244B186800F04BF8F7BD2B0088334C +:100320001E686B685C1E002CF3DB002F09D0002ECA +:1003300001D1013CF7E73300A20080339B58BB4258 +:10034000F7D128006968A200083001398358A1421A +:1003500019D16C60002BECD069680091002E08D098 +:10036000FC218C460120B4446146A040496801420A +:100370000CD198470C4B6A6800991B688A42C4D11B +:100380009D42D6D0C1E700218150E3E7B1586246D3 +:100390009268024202D101989847EBE7080098471B +:1003A000E8E7C04660000020380100207047704731 +:1003B00070470000FEE7C0462D4B1B78012B00D094 +:1003C00070472C4B1B681B07FAD12B4AF02312688D +:1003D000110019401A4201D0102946D1274A12684B +:1003E0001A421FD0F022244B1B681340402B29D007 +:1003F000F022214B1B681340A02B01D0D02BDFD162 +:10040000F0231E4A12681A42DAD11D4A1368012BE2 +:1004100004D01C4B13601368012BFCD1C0221A4B73 +:100420001A60CDE7194B1A4A1A608022194B120242 +:100430001A600F4B1B78012BC2D10E4B1B681B0798 +:10044000D0D0BDE70D4B1B681342D1D18022C12310 +:100450000121DB00D205D150054B1B78012BAFD118 +:10046000044B1B681B07C3D0AAE73029B6D0B9E7F5 +:10047000E00F00F0E40F00F0E80F00F0EC0F00F0E8 +:1004800000EC06407593000014EC064004050040A3 +:10049000DFFF07C0186C0040F0B5DE4657464E46F9 +:1004A0004546E0B5037883B0042B09D0022B00D178 +:1004B00008E103B03CBC90469946A246AB46F0BD6D +:1004C0008C4A017911708C4A127C002A5DD000227E +:1004D00001250224884910260A74884AAC469246AF +:1004E0001278A146D10821405411A4001C40214398 +:1004F000D4102C4021430735D4082C402143140646 +:10050000E4177F4F3440214339705146A846654671 +:100510004C78A1110D4091001940294301914146A9 +:1005200095000D402900019D92000D4332402A4361 +:100530004D462106C91729400A43BA7062082A406D +:100540006546E110890019400A436110294045467B +:100550000A43610829400A43610831400A433A715D +:1005600052464D4692782401110929409511AD005B +:100570002B400B4334401C4343461606F6171E40DF +:10058000163334431A40BC713A725E4C237C002B04 +:1005900024D10379732B00D198E0574B5A49DB687B +:1005A0005A1C554BDA60E3680133E3608A4208D98C +:1005B000002253490A708A700A718A710A724E4980 +:1005C000CA60514A934200D873E700234C4AE36063 +:1005D0005370D3705371D37153726AE700230221B1 +:1005E000042608252374494B884699461B78AC4657 +:1005F0005A090A40D90831400A43D9090A4359081F +:1006000029400A43083559003D4F29400A437A7072 +:100610004A46517852789E1052B20192350001221A +:100620009E001540AB46350004263540AA465D467F +:1006300056463543464633402B4310258E082E4000 +:10064000019D3343EE1165462E4033434646FB7011 +:10065000CB081E40043D4B082B4033434E1116403F +:100660001E43B24666464B00334056460C35C90021 +:10067000294033430B4349467B714B4689789B782D +:1006800049B289460C3D1909294065469E082E400D +:10069000019D3143154029434D464646ED113540F5 +:1006A0002943F97119110A40494602360E40414664 +:1006B00032439E080E4061469B0032430B401A4372 +:1006C0007A7266E7406800F0E5FFF2E60B210C481D +:1006D00001F03EF90A200138C046C046C046C04677 +:1006E000C046C046C046C046C046C046C046C046DA +:1006F000F1D152E7D405002024030020540100204A +:100700004801002048050020102700007401002047 +:10071000F0B5DE46454657464E460124E0B5DA4B75 +:10072000DA4900255A58DA4E22435A5080225200A4 +:100730008DB09D50012132001C60D648102300F07E +:100740005FFB320010230021D34800F059FB102337 +:1007500032000221D14800F053FBD14F3422002156 +:100760003800FFF75DFD3023332698463422002100 +:10077000CC48FD54BC55FFF753FD4246C94B002100 +:100780009C55C94C9D542000253AFFF749FDE023B4 +:1007900005A80200A372C54B32CB32C2012300214F +:1007A000C34A00F0CDFF002800D0DDE1012001F0B8 +:1007B000E7FDC04801F040FCBF4801F055FC01F0E6 +:1007C000B3FABE4BBE4E1C789846BE4B25009A46E7 +:1007D000BD4B9B463023994615E04B46FC5C012CF3 +:1007E00054D0022C00D1E0E0002C00D1A7E001237E +:1007F00001205D40002143461D7032687368121865 +:100800004B4132607360002DE7D14A46A54B9C5C9A +:10081000012C00D1E0E0022C00D1D2E0002CE6D186 +:100820002F341B5D0E2BE2D88021974A4900505887 +:100830000028DCD0A1209B49C0008C4610580390B2 +:10084000581CC0B2085563440399203319708023A3 +:100850005B00D5500F28CAD161460F222031604677 +:1008600004F068F9494601228E4B32205A541D5536 +:1008700031238C49CB5C0133DBB20B54002B5BD1B1 +:100880000B0032215A5443461D78B0E78F4B1B783A +:10089000DDB2002B00D08EE08C4B0F211C70322378 +:1008A000FB5C3800039308AB0093894A102300F0E7 +:1008B00033FE00283DD0039B10211C40013463010E +:1008C0001C19744BA4009C46102364440193814A74 +:1008D0000094013B08A800F033FE002829D0220034 +:1008E0001023103201930092112310217A4A08A894 +:1008F00000F026FE00281CD01023E561019308AB10 +:10090000009310210823754A08A800F019FE00285A +:100910000FD02000102208A9303000F009FB002879 +:1009200007D0200000F0BAFA002802D002234A467D +:10093000BB540023654A137043461D7857E72F23A5 +:100940001900FB5C0E2B00D951E780204E4A400075 +:100950001058002800D14AE7A120C0001058844652 +:10096000581CC0B278546146FB182033197080239C +:100970005B00D4500F2800D039E739000F22203116 +:10098000380004F0D7F82F230122FC544B46FA54C8 +:1009900031233221FB5C0133DBB27B54002BCBD102 +:1009A0003223FA5443461D7821E7484B1B78DDB2C9 +:1009B000002B00D196E0534652469B68013393606A +:1009C00015E7424B1B78002B00D1ABE05B465A4643 +:1009D0009B68013393600AE73C4B1B78002BF5D1F1 +:1009E00032223A4B0F211C702E4B2E489B5C3C4A06 +:1009F000039308AB0093102300F08EFD002898D0DD +:100A0000039B10211C40013463011C19224BA400DC +:100A10009C461023644401932E4A0094013B08A88D +:100A200000F08EFD002884D02200102310320193A4 +:100A3000009211231021284A08A800F081FD002807 +:100A400000D176E71023E561019308AB00931021F4 +:100A50000823224A08A800F073FD002800D168E7A7 +:100A60002000102208A9303000F062FA002800D1DE +:100A70005FE7200000F012FA002800D159E70223B6 +:100A80004946084A535454E700D00040040500008A +:100A90009C4B000098010020BC030020380300207C +:100AA000D80500200C06002048010020904B0000D3 +:100AB00099040000040302010807060564000020F1 +:100AC000400100202403002048050020940100205C +:100AD000AC4B0000644B0000744B0000884B0000DE +:100AE000BC4B0000224A013313703133FB5C214AB6 +:100AF000FB73D3610F213B003A001E4800F086FDD6 +:100B0000002800D115E73B001A48102239001033A5 +:100B1000303000F0F5FC002800D10AE703234A46F4 +:100B2000BB5406E7124A013313703222124B0F21D5 +:100B30009B5C104A0F48D3610F4AD373130000F037 +:100B400065FD002800D1F4E60B4B0A4810220A4943 +:100B50001033303000F0D4FC002800D1E9E6032344 +:100B60004946054A5354E4E600F094FD1EE6C046AB +:100B700094010020380300200C06002082B002B04F +:100B80007047C04682B002B07047C0467047C0464A +:100B9000F0B5CE464746182380B58FB0041E0191AC +:100BA000039308D001283CD001F0B6F90FB00CBC7B +:100BB00090469946F0BD08AD2900002003AA01F037 +:100BC00019F9854E3378002B23D101273770EB7844 +:100BD000002B4DD03B4001335F01FF187F4BBF001E +:100BE000FF1838000822290004AB303000F088FCE0 +:100BF000002853D17A4A136801331360794B3022AD +:100C00009A5C032A36D000230020337001F084F967 +:100C1000CCE7734A002093680133936001F07CF9BC +:100C2000C4E708AD2900012003AA01F0E3F86A4EE9 +:100C30003378002B2AD13470EB78002B5FD16A4FC8 +:100C400038000822290004AB303000F059FC00289D +:100C50005ED1664A136801331360654B30229A5C9B +:100C6000032A07D000230120337001F055F99DE7D6 +:100C70005A4FB6E700221D002000327001F04CF9F7 +:100C800020222900200001F072F88FE7574A012046 +:100C900093680133936001F03FF987E7102204A9BC +:100CA0000AA803F039FF80460028A3D16B682A0008 +:100CB000FB61032138004F4B00F0A8FC002859D0FD +:100CC0000122474B91461A7442463120DA603222A3 +:100CD000444BE9789A5C1F5C974201D08A425BD012 +:100CE000002903D0444A696891428CD933229A5C26 +:100CF000002A84D10020327001F00EF956E723401B +:100D00000133DBB25F01FF18374BBF00FF1897E7D5 +:100D1000102204A90AA803F0FFFE8046002898D1FB +:100D20006B682A00FB6103213800344B00F06EFC35 +:100D3000002828D001222D4B91461A7442463120BA +:100D4000DA6032222A4B995C1F5CEA788F4201D02C +:100D50008A4231D0002A03D0274A6968914281D95A +:100D600033229A5C002A00D078E70120327001F02B +:100D7000D3F81BE71A4A30705368002001335360E0 +:100D800001F0CAF812E7194A3070536801200133A4 +:100D9000536001F0C1F809E733214F461A54404629 +:100DA0005F5403395854002A00D12CE7124A69686D +:100DB000914200D827E722E733214F461A54404694 +:100DC0005F5403395854002A00D14BE70A4A696836 +:100DD000914200D942E745E79401002098010020A4 +:100DE00024030020D8050020BC0300204805002073 +:100DF0000C06002054010020A08601007401002090 +:100E000030B505000C001000190087B0022C02D983 +:100E1000002007B030BD1D4BA400E25802AB009388 +:100E2000102300F079FB0028F2D010240F231021AA +:100E3000174A0194009502A800F082FB0028E7D031 +:100E40002B001033009310211123124A019402A8A1 +:100E500000F076FB0028DBD00023EB6102AB0093AF +:100E6000102108230C4A019402A800F069FB002815 +:100E7000CED02800102202A9303000F059F8002806 +:100E8000C6D0280000F00AF8C3E7C046CC4B0000EB +:100E9000644B0000744B0000884B0000002804D015 +:100EA000034A044BD050012070470020FCE7C046A5 +:100EB00000E000400405000070B500282ED0184A5C +:100EC000184BD158814200D0D05082248025002375 +:100ED0008022134964006D000B514B5101330B60AC +:100EE000520402E0013A002A18D04B590859034332 +:100EF000F8D00D480368013303600C4803681E00F6 +:100F000080235B049C4600236644B21A02604B5166 +:100F10000A590120002A00D170BD0B510020FBE7C7 +:100F200000E00040040500005C0500206005002092 +:100F3000F0B50500C64620350400A84600B50F2AC6 +:100F400000D951E11023002020269B1AA055012B27 +:100F50003AD00136A055022B36D00136A055032BCE +:100F600032D00136A055042B2ED00136A055052BCA +:100F70002AD00136A055062B26D00136A055072BC6 +:100F800022D00136A055082B1ED00136A055092BC2 +:100F90001AD00136A0550A2B16D00136A0550B2BBE +:100FA00012D00136A0550C2B0ED00136A0550D2BBA +:100FB0000AD00136A0550E2B06D00136A055102BB5 +:100FC00002D11F33E05441E000200500A71A343756 +:100FD000B9424541A61A2F0030360D1DAE424041A0 +:100FE0000743BC460827501E8742BF4160467F42E8 +:100FF000074200D1FDE030000843800700D0F8E050 +:101000000D6890083560012805D04D68756003288B +:1010100001D18868B06003201500854328005B1962 +:10102000AA4213D04E5DE218203216705A1C6E1C74 +:101030000F2B0BD08E5DA2182032167002309A1C36 +:101040000E2B03D00B5CA21820321370200010224C +:1010500000213030FFF7E4F850223F21A35C4046E6 +:101060008B43A354FFF728FF002800D1B9E04F239A +:10107000E25C5300E3734E23E35CD20959000A4358 +:10108000A2734D22A25CDB0951000B4363734C2316 +:10109000E35CD20959000A4322734B22A25CDB09AC +:1010A00051000B43E3724A23E35CD20959000A431F +:1010B000A2724922A25CDB0951000B4363724823F0 +:1010C000E35CD20959000A4322724722A25CDB0981 +:1010D00051000B43E3714623E35CD20959000A43F4 +:1010E000A2714522A25CDB0951000B4363714423CA +:1010F000E35CD20959000A4322714322A25CDB0956 +:1011000051000B43E3704223E35CD20959000A43C8 +:10111000A2704122A25CDB0951000B4363704023A3 +:10112000E15CD2094B001A4322707F2904D979234C +:10113000E27B5B425340E373E27B5300E377A37BA4 +:10114000D20959000A43A277627BDB0951000B43A5 +:101150006377237BD20959000A432277E27ADB09BD +:1011600051000B43E376A37AD20959000A43A276D1 +:10117000627ADB0951000B436376237AD209590066 +:101180000A432276E279DB0951000B43E375A37928 +:10119000D20959000A43A2756279DB0951000B4359 +:1011A00063752379D20959000A432275E278DB0975 +:1011B00051000B43E374A378D20959000A43A27487 +:1011C0006278DB0951000B4321786374D2094B002C +:1011D0001A4322747F2904D97923E27F5B4253406A +:1011E000E37704BC9046F0BD1022280003F0A2FC77 +:1011F0002CE70878E3182033187011239B1A102B62 +:1012000000D123E74878E3182033187012239B1A83 +:10121000102B00D11AE78878E318203318701323B5 +:101220009B1A102B00D111E7C878E31820331870EF +:1012300014239B1A102B00D108E70879E3182033F8 +:10124000187015239B1A102B00D1FFE64879E3187C +:101250002033187016239B1A102B00D1F6E68879DC +:10126000E3182033187017239B1A102B00D1EDE6DA +:10127000C879E3182033187018239B1A102B00D15B +:10128000E4E6087AE3182033187019239B1A102B10 +:1012900000D1DBE6487AE318203318701A239B1A32 +:1012A000102B00D1D2E6887AE318203318701B2364 +:1012B0009B1A102B00D1C9E6C87AE31820331870A6 +:1012C0001C239B1A102B00D1C0E6087BE3182033A7 +:1012D00018701D239B1A102B00D1B7E6487BE3182A +:1012E000203318700E2A00D1B0E62F238A7BE254F7 +:1012F000ACE6C046F0B514003022454657464E468F +:101300009446DE465023E0B5844410276246C35C11 +:1013100083B09B06DB0EFF1A060088463D00019253 +:10132000BC4263D950229146313A93461F329246CD +:10133000019A4146D0182A0003F0FCFB4B46F25CB0 +:1013400051469306DB0EFF185B463B408A435F0025 +:1013500017434A46B7545246A844641B3A40202AD1 +:101360001ED01027FF1A3D00019AD018AC42DFD8DA +:101370002200414603F0DEFB5021735C01209A06F7 +:10138000D20EA4181F2214401F326400934323433B +:10139000735403B03CBC90469946A246AB46F0BDA0 +:1013A000FB0712D430002030FFF786FD0028F0D074 +:1013B0004B463F22F35C10279343012213434A46D6 +:1013C0001025B35401980023D0E7336B326C53409F +:1013D0003363726C736B53407363B26CB36B534083 +:1013E000B363F26CF36B5340F363DBE7D018BFE7F2 +:1013F000F0B550230400C646E25C123B0E0000B577 +:1014000030301340202B38D1236B226853402363A4 +:101410006268636B53406363A268A36B5340A3632A +:10142000E268E36B5340E3635023E35CDB070FD5D3 +:10143000236B226C53402363626C636B5340636382 +:10144000A26CA36B5340A363E26CE36B5340E36372 +:1014500020002030FFF730FD051E0AD050223F212A +:10146000A35C30008B432100A3544031403A03F089 +:1014700061FB280004BC9046F0BD210092061031AB +:10148000D20E032A3AD927000B00043A904692085C +:10149000944614379200BF181A6A1D6804336A40D4 +:1014A000DA619F42F8D163466246454601339200B5 +:1014B0009B00AA1A012A05D9CD5AC75A023A7D4083 +:1014C000C5520233002A03D0CA5CC55C6A40C254CC +:1014D0005023E25C9206D20EA3181F7C1D008023CD +:1014E0005B4230357B402B700E2A9DD80F23551C54 +:1014F00049199A1A401903F01DFB95E70023D9E713 +:1015000070B504001D00FFF7F5FE002803D0290088 +:101510002000FFF76DFF70BD30B597B004000D00DF +:1015200001A811001A00FFF703FD002805D02A00CA +:1015300021001A9B01A8FFF7E3FF17B030BDC0469A +:10154000F0B54546DE4657464E469B46FF23E0B57E +:101550009BB0259D8046894692461B019D4248D8F6 +:101560002F09FFB22B074CD16B46DC1C0123002650 +:101570002370002F0FD147E0102201A903F0DAFAFF +:101580001036103DB6B223780133DBB22370BB4274 +:101590003AD8002B38D04A46414605A8FFF7C8FC88 +:1015A000002826D02378012B06D9102201A905A8EE +:1015B000FFF7A0FE00281CD05A46514605A8FFF7A9 +:1015C00099FE002815D00122210005A8FFF792FE00 +:1015D00000280ED001A905A8FFF70AFF002808D0AF +:1015E000249B9819102DC7D82A0001A903F0A2FA4C +:1015F000C9E700201BB03CBC90469946A246AB46CA +:10160000F0BD0137FFB2AFE70120F3E7F8B5050001 +:101610000C0017001E00102901D90020F8BDFFF7AB +:101620004BFC0028F9D0290020318C46032C2ED900 +:101630002B6A3A6853403360231F032B11D96A6A1F +:1016400079684A4072602200083A032A09D9BA68C8 +:10165000A96A4A40B260102C03D1EA6AF9684A408C +:10166000F26003229B0801339B001440012C06D931 +:101670006146FA5ACD5A023C6A40F2520233002CBB +:10168000CCD06146FA5CC95C4A40F254C6E70023FC +:10169000ECE7C046002300B585B001AA90600021A8 +:1016A00003481380536000F005F805B000BDC04644 +:1016B00001400000BFF34F8F034B044ADA60BFF3D1 +:1016C0004F8FC046FDE7C04600ED00E00400FA057C +:1016D00010B5047884B0012C0CD0022C1BD0002C47 +:1016E00006D1032302AA1370124B10001B689847FF +:1016F00004B010BD042302AA1370436801211B78B3 +:101700000D48137100F07EF90C4B02A81C70094BB8 +:101710001B689847ECE702AB1C70C36801210648C0 +:101720000193039300F06EF9024B02A81B689847DF +:10173000DEE7C0466405002068050020690500203A +:10174000F0B589B00400684605001B499C46C8C92D +:10175000C8C5C8C9C8C548C948C5A168634681612C +:101760002579037729004E1EB14101756379591E11 +:101770008B410E215B420B404375E3788360A37875 +:10178000C36023784360637800930C4B1A60002297 +:101790000B4B1A70022D0DD00A4900F04BF80028AF +:1017A00001D009B0F0BD00F0B5F90121064800F004 +:1017B00029F9F6E70620F4E7084C0000640500204C +:1017C00069050020D11600006805002030B5FF250E +:1017D00003232A000340DB009A4089010D40D243D5 +:1017E0009D40C4B2002814DB104B80089C46C023E7 +:1017F000800060449B00C1580A401543C5501F2318 +:10180000C0211C401E3BA340084A490053501360AE +:1018100030BD0F23064923408C46083B9B089B00A4 +:101820006344D9690A401543DD61E8E700E100E05F +:1018300000ED00E0F0B5D6464F464646C0B53A4CFE +:10184000E37E002B6ED1002868D0026801339340FC +:10185000A022A125D205ED005351A9460325036816 +:10186000AA46C133FF339B009D5000254368AC4618 +:10187000C133FF339B009D5087692C4B2C4D5F512A +:10188000077D457D3D432B4FDD5145680768A846E0 +:10189000294D5F514746294D5F51057D012D19D1D5 +:1018A00087683E00E0277F00B8464644B70066469A +:1018B000BE50C668B5404E4695515646C568C135BE +:1018C000FF35AD00AE504E46C26885689A51A222DF +:1018D000D2009D5003696160236000290DD0002370 +:1018E000174A017F1360174A17481360C1230F4A34 +:1018F0009B00D0500220FFF769FFA02304210B4A70 +:10190000DB00D1500023E3822376802300205B009C +:1019100063831CBC90469946A246F0BD80230B48C9 +:101920009B0095E70820F4E76C05002000200040AC +:10193000240500006C0500000C05000014050000E3 +:101940001C2100404421004080000200284C00007F +:10195000F0B5264B9A7D002A16D101259975244CA5 +:1019600024499A8298600A6025600A609A8A224C0B +:10197000855C9A8A2148013292B29A8225505A682F +:10198000002A03D00020F0BD1120FCE7250000272D +:1019900004000132FF329E7D988AB04203D312E0E8 +:1019A000988A904202D008680028F9D0988A90421C +:1019B000F2D00F60988A9E68365C988A013080B2B7 +:1019C00098822E51E7E78022998A520091420AD0EC +:1019D00008490A68002AFCD001210020084A116049 +:1019E00000229A75CFE70F20FAE7C0466C05002069 +:1019F000082000401C210040002000401C05000081 +:101A00000C200040F0B53D4B5A68002A05D0C22496 +:101A100081263B4DA400B6002E51DC7D002C0ED05B +:101A20001C7E002C59D118611976002A18D0C123C8 +:101A300081210020324A9B008900D150F0BDD97528 +:101A4000997ED8605C761C760029EED12D4A116013 +:101A50002D4A116001212A4A11605A68002AE6D1F4 +:101A60002A4FA3253A60274A27499446244EED0081 +:101A70006246146808683A68002809D1002A27D00D +:101A80000021D975002C26D10F20002AD6D114E0D0 +:101A900020001043F4D1DA7D002A16D008605A7E67 +:101AA000DC687059A0545A7E0132D2B25A765A7EFE +:101AB000D87D9042DCD80022DA759B7E002B16D0B0 +:101AC00001220F4B00201A60B8E70A607259EEE756 +:101AD000002CCDD0DA750320B0E7002A0CD0C1234A +:101AE0008121074A9B0089001120D150A6E70122DD +:101AF000074B00201A60A1E711209FE76C0500202A +:101B000000200040242100400821004044210040E2 +:101B100004200040064A937E002B07D105490B6044 +:101B200005490B60054901330B6093767047C04649 +:101B30006C050020242100400821004000200040C6 +:101B4000C12210B55D4B92009A5884B0920557D5CA +:101B50005B4A1168002953D000211160C222812103 +:101B6000920089009950574B9A7E002A02D1012198 +:101B7000554A1160022269460A7090214F48C900F7 +:101B80004258425069460392DA7D68460A72DA6822 +:101B900001920022DA751A760ACB98474B4A1368ED +:101BA000002B10D0474B998A9C7D8C4261D9002133 +:101BB00011609A8A9968895C9A8A013292B29A82F3 +:101BC0003E4A434BD150434B1A68002A16D000229C +:101BD0001A603C4B9A7E002A02D00121374A1160DC +:101BE000DA7D002A0AD0002268460121DA755A7E81 +:101BF00001700272DA680ACB0192984704B010BDF6 +:101C0000C1232E4A9B00D3585B07C7D532490B68C6 +:101C1000002BC3D02B4BD87D002838D00020086083 +:101C2000A320C000597E1258D86842545A7E01320F +:101C3000D2B25A765A7ED97D9142AFD11A7E002A0D +:101C40002AD19A7E002A02D101211F4A1160C222A4 +:101C500081201A49920080008850002268460121A4 +:101C6000DA755A7E01700272DA680ACB01929847DF +:101C700094E700211160002CA5D06A4611701472FF +:101C80009A686846019299750ACB98479BE7086065 +:101C9000A321C9005258CDE7DA751A69D968DA600C +:101CA00000226C46587E1A765A76013220720191D3 +:101CB00068460ACB2270984770E7C0460020004073 +:101CC000242100406C050020042000401C2100401D +:101CD0001C050000442100400821004003210A485F +:101CE00002680A430260094802680A430260084920 +:101CF000084A094B9B1A03DD043BC858D050FBDC53 +:101D0000FEF75AFBFEF700FA240500405405004098 +:101D1000884C00000000002090000020FEE7FEE755 +:101D2000FEE7FEE7FEE7FEE708B5064B1868002869 +:101D300003D1054902220A7002E001F049F90120AD +:101D400008BDC0468805002040060020014B1868E9 +:101D5000407E70478805002008B500F011FE00287D +:101D600002D100F0F8FD01E0FEF710FF08BDF8B564 +:101D7000051C0F1C161C072804D904221B4E00202A +:101D8000327031E003220029F8D00622202EF5D847 +:101D900000F04CFE09220228F0D8281C00F04AFE70 +:101DA0000A220228EAD800F049FE08220128E5D9D3 +:101DB00000F0F4FD4378041C0670012003436370B7 +:101DC000391C321CA01C02F0B5FEE8B2211C00F048 +:101DD000F9FD051C0120002D06D1054802F0CAFAC4 +:101DE000024F0F213970281CF8BDC0464006002064 +:101DF000DD000500F8B5061C0D1C171C00F01AFECE +:101E0000002803D1154F0B253D7025E00322002D3E +:101E100007D0301C00F0FCFD3A6803789A4204D2E7 +:101E200006220E4E0020327016E0301C00F0E6FD57 +:101E3000041E0AD00278811C3A60281C02F07AFE47 +:101E4000201C00F0B5FD012006E0054802F092FAE2 +:101E500002490F200870201CF8BDC0464006002033 +:101E60000501050008B5072804D9044B04221A709F +:101E7000002001E000F0DAFD08BDC0464006002069 +:101E800008B5072805D9044B042201201A704042E6 +:101E900001E000F0CFFD08BD4006002008B500F0CD +:101EA000CDFD0623181A08BD10B5041E072C03D952 +:101EB0000B4B04241C7003E0FFF7D4FF022801DD64 +:101EC00000200CE0201CFFF7DBFF0228F8DCFFF706 +:101ED000E5FF0623181A012181429241504210BDAC +:101EE0004006002008B50A4B19684A7E002A04D033 +:101EF000084A0C211170002009E0072803D9054B7E +:101F000004201870F7E7C0B200F09CFD012008BD66 +:101F1000880500204006002008B5072804D9054B95 +:101F200004221A70002003E0C0B200F0A5FD0120D9 +:101F300008BDC0464006002010B501280AD0002880 +:101F400003D0022808D1002000E0012001F028F889 +:101F5000012005E00220F9E7024B05221A7000205B +:101F600010BDC0464006002010B500F011FD01284C +:101F70000AD00224002808D0A04201D1012404E0A4 +:101F8000034802F0F7F900E00024201C10BDC04611 +:101F90007001050038B5134A031C10680C1C407E04 +:101FA000002804D0104D02202870002018E00139CC +:101FB0000F2903D90C4907220A7011E0002B03D125 +:101FC000094C03232370F0E7084D191C10C5221C8F +:101FD000281C02F0AFFD281C211C00F0BDFD0120D3 +:101FE00038BDC0468805002040060020680000205B +:101FF0000C4B10B51A680C68944201D3102C04D90C +:10200000094C0720207000200AE0002803D106496F +:1020100003220A7004E00A60191D02F08BFD012002 +:1020200010BDC0466800002040060020014B186823 +:102030007047C0466800002008B5074B19684A7E03 +:10204000002A04D0054B02201870002002E000F0A6 +:102050001DFD012008BDC046880500204006002067 +:1020600008B500F023FD08BD08B5074B19684A7E86 +:10207000002A04D0054B02201870002002E000F076 +:102080001BFD012008BDC046880500204006002039 +:1020900008B500F01FFD08BD08B50A4B1A68537E4D +:1020A000002B04D0084B02221A70002008E00728F9 +:1020B00003D9054804210170F7E700F011FD012064 +:1020C00008BDC046880500204006002010B50C1C45 +:1020D000072804D90422064B00201A7006E00322C8 +:1020E0000029F8D000F028FD2070012010BDC04666 +:1020F0004006002008B5074B19684A7E002A04D024 +:10210000054B02201870002002E000F065FD012060 +:1021100008BDC046880500204006002008B500F034 +:1021200061FD08BD08B50E4A031C1068407E0028FA +:1021300004D00C480222027000200FE0012B0AD0CC +:10214000002B07D0022B01D1012004E0054B0E210A +:10215000197003E0022000F0DDFD012008BDC0463B +:10216000880500204006002008B501F023F8002172 +:10217000012801D8014B195C081C08BD484C00001F +:1021800008B5134B19684A7E002A04D0114A02216F +:10219000117000201BE006280FD802F06BFC12140F +:1021A0000406080A0C00FC200EE0F8200CE0F420E5 +:1021B0000AE0F02008E0EC2006E0064B0E20187044 +:1021C000E7E7042000E0002000F046FD012008BD04 +:1021D000880500204006002008B500F04BFDF028DF +:1021E00013D004D8042814D0EC2806D10FE0F82826 +:1021F00007D0FC2803D0F42805D001200AE00220F3 +:1022000008E0032006E0042004E0052002E00620A8 +:1022100000E0002008BD08B5064B19684A7E002A78 +:1022200004D0054B02201870002002E000F0E0FC12 +:10223000012008BD880500204006002008B500F0F8 +:10224000DDFC08BD08B5074B19684A7E002A04D09A +:10225000054B02201870002002E000F097FC0120DE +:1022600008BDC046880500204006002008B500F0E3 +:1022700093FC08BD08B5074B19684A7E002A04D0B4 +:10228000054B02201870002002E000F0CBFC01207A +:1022900008BDC046880500204006002008B500F0B3 +:1022A000C9FC08BD08B5074B19684A7E002A04D04E +:1022B000054B02201870002002E000F0A5FC012070 +:1022C00008BDC046880500204006002008B500F083 +:1022D000A3FC08BD08B5074B19684A7E002A04D044 +:1022E000054B02201870002002E000F0A9FC01203C +:1022F00008BDC046880500204006002008B500F053 +:10230000A5FC08BD08B50B4B19684A7E002A04D00D +:10231000094A0221117000200AE0002805D0012896 +:1023200003D0054B0E201870F5E700F05BFF01208D +:1023300008BDC046880500204006002008B500F012 +:1023400057FF01384342584108BD08B50A4B196888 +:102350004A7E002A04D0094A0221117000200AE0B6 +:10236000002805D0012803D0044B0E201870F5E793 +:1023700000F050FF012008BD880500204006002025 +:10238000F8B51E4D00241E4E071C281C211C0C22D3 +:10239000083034706C60FDF743FF1A4800F048FEC7 +:1023A0002860A04203D101203070002024E0164BA9 +:1023B000181D1968FFF7EEFD051C381CFFF7BCFD62 +:1023C0000540042000F0EEFB201CFFF79BFFEFB25E +:1023D00007400120FFF7D4FE07400220FFF7A2FECE +:1023E0000740201CFFF7B1FF041C01203C4000F017 +:1023F000E7FE002CD7D00120F8BDC046880500209C +:10240000400600207F2400006800002008B500F08E +:1024100007FF01384342584108BD024B0022DA60F1 +:102420007047C04688050020014BD8687047C046F9 +:1024300088050020044B002200B51A72904202D099 +:1024400018610120187200BD88050020014B187822 +:102450007047C04640060020014B00221A707047AA +:1024600040060020014B58687047C0468805002090 +:10247000014B00225A607047880500207047F0B574 +:1024800089B0040C031C060A84460190101C0392B8 +:1024900097B2020C0D1C002002910092E1B262463C +:1024A00006AC069060600590D0B21B0EF6B205280F +:1024B00054D802F0DFFA03142943403D6A4649B27A +:1024C000484223701388E080281C6780A38000F0B6 +:1024D0006FFA301C06996268FEF750FB41E0224912 +:1024E0000B68587E002802D1204801F043FF281CC9 +:1024F0006D4600F05DFA67802F88301CA780069932 +:102500006268FEF73FFB2CE048B205AC4242237004 +:102510006280002B07D0002D02D1154801F02AFF60 +:10252000281C00F045FA301C0599FEF731FB18E035 +:10253000FEF72CFB15E0FFF7A1FF12E00A4DE9685A +:102540002B7A0131E960002B0BD02F69002F02D1CB +:10255000FFF702FC05E0013F2F6102E0054801F0B2 +:1025600009FF09B0F0BDC04688050020B50305008D +:10257000C3030500E3030500024B03490F221A7051 +:1025800048607047400600208805002000B5064AD4 +:1025900001231178022903D05068421E904100E0C7 +:1025A000181C1840C0B200BD4406002008B5FFF753 +:1025B000EDFF044B044A002801D0D06800E0906889 +:1025C000186008BDA00500207C06002008B5044B5B +:1025D0005A68002A01D0013A5A60FFF7E7FF08BDA8 +:1025E0004406002010B500231A1C041C1C410121C4 +:1025F00021400724E41AA1400A430133D2B2082B38 +:10260000F3D1101C10BD70B50024061C251C301C15 +:10261000E040C0B2FFF7E6FF1823191B88400834DA +:102620000543202CF3D1281C70BD38B50D1C01F0DA +:1026300071FE084C63699D4202D8074801F09AFE7A +:1026400060690122291A054802F058F900216161E8 +:1026500038BDC046440600204D0609005543000021 +:1026600007B5A12303210F4A8B40D15001F094FDFF +:10267000002815D002280AD9032811D1002300937D +:102680000193181C191C1A1C01F09EFC03E0002089 +:10269000011C01F035FD042802D0034801F06AFE58 +:1026A00007BDC04600F00140E801090008B501F08F +:1026B00027FFA1230E4AD900505001F06DFD0128DB +:1026C00007D001F069FD022802D00A4801F052FE4D +:1026D000002001F0B9FA02F093F9074BA221CA00D9 +:1026E00098500648064AC1684868985008BDC046D8 +:1026F000001000401E06090000F00140A005002067 +:102700001405000008B502F0EDF801280FD002F022 +:10271000CDF8074B187F002803D180210122CB057B +:102720005A60002001F0F6FD024A0020506008BD0A +:102730007C0600204406002010B501F06AFD002848 +:102740001AD00E4B00229A81DA8101F0C5FB0C4CA5 +:102750000C49605001F0C0FBA62201238340D10048 +:10276000635001F0BFFB084C206001F0C1FB074B38 +:102770006060E360FFF79AFF10BDC046440600208A +:10278000001000402C0500006006002035280000E5 +:1027900008B502F0A7F8012822D101F0D5FD0028E4 +:1027A00002D0104801F0E6FD1E210F48002202F081 +:1027B000A5F80E4B197F002902D002F06BF80FE04C +:1027C0000B480C4B0122026059608021C805026051 +:1027D000C046C046C046C0465A68002AFCD0ECE756 +:1027E00008BDC0462C060900554300007C060020A9 +:1027F00014050040FC0000401FB5FFF783FF01F007 +:10280000D9F80A4A002301A80521017043601C1C65 +:102810000381438143708370C3709370537601F0DA +:102820009DFA03480470FFF71BFF1FBD44060020FC +:1028300078060020F0B53E4B8022D000195887B0B2 +:10284000012904D03B4C00261D59B54206D13A4E11 +:102850002022776800263B789A427641374C012542 +:1028600061692E40281C002901D102F041F828425C +:1028700001D10120606101F08FFC012802D03048B5 +:1028800001F078FD2F4DEF683B7D002B02D02E48E4 +:1028900001F070FD01F08EF8002E47D00120011CE0 +:1028A00001F02EFC042836D802F0E4F80332183286 +:1028B000320001F017FBE289071CA689019201F0A2 +:1028C0000BFBE9686D46897D0497AF8803AB002256 +:1028D0001A701E815F815870997014E001F002FB3C +:1028E000071CE089A689019001F0F6FAEB686D46B5 +:1028F0009A7D0497AF8803AB00219A7019701E81EE +:102900005F8158700122DA70181C01F027FA02E08A +:102910000E4801F02FFD01F019FE0D4E2061706987 +:102920006060FFF743FE002001F016FE07B0F0BD27 +:10293000001000403405000060060020440600201E +:10294000A8060900A0050020A9060900C80609007C +:102950007C060020704708B5012282F31088074BDF +:10296000597E002905D09878002802D19A70FFF787 +:102970000FFF002282F3108808BDC04644060020E5 +:10298000024B0120597E48407047C0464406002053 +:10299000014B18787047C0464406002008B5012353 +:1029A00083F3108801F094FC002181F3108808BDA6 +:1029B00008B5012383F3108801F08EFC002080F31A +:1029C000108808BD08B5012383F3108801F0EAFBE5 +:1029D00000280DD008488278002A04D1417E0029C1 +:1029E00001D0FFF7D5FE002383F31088012001E01A +:1029F00080F3108808BDC0464406002008B50123B6 +:102A000083F3108801F0F6FB002181F3108808BDE4 +:102A100008B501F0EAFB08BD08B5012383F310886F +:102A200001F0D3FB002181F3108808BD08B501F047 +:102A3000D8FB08BD08B501F0E7FB08BD08B501F0FB +:102A40004FFC08BD10B50123041C83F3108808480F +:102A50000278002A05D0417E002902D0054801F005 +:102A600089FC201C01F0B5FB002484F3108810BD04 +:102A700044060020FB02090008B5012383F31088F7 +:102A800001F0BDFB002080F3108808BD08B5044BA1 +:102A90001862FFF7B8FD0349034A505008BDC0460D +:102AA0007C0600201C05000000100040014B186A45 +:102AB0007047C0467C06002008B5044B5862FFF7FB +:102AC000A2FDA421024ACB00D05008BD7C06002004 +:102AD00000100040014B586A7047C0467C06002039 +:102AE000F8B5031C081C072B1AD80F4A03261E40F2 +:102AF000D118F600FF24B4402831E74308700B4C8E +:102B0000032B01D80A4D01E0A525ED0063591F40B4 +:102B10006751FFF767FD6759B0400743675102E00F +:102B2000044801F027FCF8BD7C060020001000409E +:102B3000240500003903090010B5041E072C02D932 +:102B4000034801F017FC034B18192830007810BD1A +:102B5000410309007C06002038B5051C0C1E02D17B +:102B6000074801F007FC002D02D1064801F002FCE5 +:102B7000054B00209D605C6001F0D6FC38BDC0466E +:102B80004803090049030900A0050020014B5861D2 +:102B90007047C0467C060020014B58697047C0460C +:102BA0007C060020064B074AA32110B55877CB00BE +:102BB000D4580104044820400843D05010BDC046FA +:102BC0007C06002000100040FFFFF8FF014B587FFB +:102BD0007047C0467C060020014B18617047C04614 +:102BE0007C060020014B18697047C0467C06002017 +:102BF000014B58607047C0467C060020014B586866 +:102C00007047C0467C06002008B5024BD860FFF72D +:102C1000CDFC08BD7C060020014BD8687047C0463B +:102C20007C06002008B5024B9860FFF7BFFC08BD8A +:102C30007C060020014B98687047C0467C06002047 +:102C4000014B58837047C0467C060020014B588BCF +:102C50007047C0467C060020034B0449044A3033C9 +:102C6000187050507047C0467C0600200C050000CC +:102C700000100040014B3033187870477C0600206C +:102C8000184B10B531331870174A184BFF24995858 +:102C9000A1439950032821D8995801F0EBFE1D0259 +:102CA0000A140124214399501149FF205850114919 +:102CB00006E00220014399500F490D4A99500F49EF +:102CC000A722D20008E00324214399500C48084968 +:102CD000A7225850A2400021995002E0094801F073 +:102CE00049FB10BD7C0600203405000000100040A8 +:102CF0003C05000007010000FFFF0000211001005B +:102D0000FFFFFF00C2030900014B31331878704701 +:102D10007C0600201F4B00B532331870012821D0EB +:102D2000002810D0022834D1A2211B4ACB00D05059 +:102D30001A491B481B4A08601B4B1C481C491A6057 +:102D400008601C4A20E0A223134AD9005050134BBC +:102D50001348154A186013491748154B116018603D +:102D6000164A11E0A2230C4AD90050500B4B0C48D4 +:102D70000C490D4A186011601148124A0C4B124957 +:102D800018601160114A02E00E490A60104A1148A9 +:102D9000026000BD7C0600200010004024170040A7 +:102DA000005000784E0000542817004008800C6046 +:102DB0002C1700408864720003800C60226472004B +:102DC00002800C603017004011646600DEC08F8204 +:102DD0003E420F8234170040F8B5A122334C344BE9 +:102DE000344E354DD000002703210122F7503150D9 +:102DF00067516251E05831490F220140E150E558D6 +:102E0000062095430543E550E1582D4DC022900220 +:102E10000D400543E550A323DD006159294A802375 +:102E20000A40625160595904014361516059FF22BF +:102E3000904320231843605161592348C022084021 +:102E40006051224853000221C15001F0D5FD2049B4 +:102E5000204A70507251204D032373511F4800F0D7 +:102E6000E1FD1F4E1F4DF060687FFFF79BFE286A53 +:102E7000FFF70CFE686AFFF71FFEE819283001789B +:102E8000381C0137FFF72CFE082FF6D12F1C3037E6 +:102E90003978154AA1502C1C313420783235FFF78F +:102EA000EFFE2878FFF736FFF8BDC046001000405F +:102EB0001405000000F00140FC0F0000FFFEFFFFC2 +:102EC000FFFFF0FFFFFFFFFDFF00FFFF00E100E05D +:102ED0001C050000041100400405000060060020ED +:102EE000A00500207C0600200C05000070B5274ED0 +:102EF00086B0337872789A4245D0002B01D1FFF723 +:102F00006BFF7078002801D1FFF7AAFB2049214D03 +:102F100000246C5000F04EFD1F4D2C606C602C6145 +:102F2000AC60EC603378012B08D101F035F9A04298 +:102F300017D0201C211C01F0E3F812E0022B10D165 +:102F400000F038FD154A2C61147001F025F90328B2 +:102F500007D100940194201C211C221C231C01F089 +:102F600033F8FFF723FB70780024307003A80426A1 +:102F7000067044600481448144708470C47000F021 +:102F8000EDFE012000E0002006B070BD44060020E8 +:102F90001405000000F001406006002078060020C3 +:102FA00008B5012383F3108808490A78824208D0C3 +:102FB0004870487E002802D1FFF798FF01E0FFF734 +:102FC000E7FB002383F3108808BDC04644060020B9 +:102FD00038B5124B5A7E1C1C002A1DD1FFF7FCFE8F +:102FE0000F488168051C002902D10E4801F0C2F982 +:102FF0006B68002B02D10C4801F0BCF901F098F984 +:10300000002802D0094801F0B5F9002001F082F94A +:1030100001226276FFF7BCFB38BDC04644060020A3 +:10302000A00500205E0209005F0209006602090097 +:10303000F8B5071C012080F31088544D544B554EB1 +:103040000024002203211C605C609C60DC601C6129 +:103050001A7529702A766A76B46074606870AC70EC +:103060006C60AC60AC81EC812C616C6101F0D6FBD2 +:10307000381C00F059FE00F0F5FE201C01F042F96A +:10308000301C01F07BF9444FC2208300F958434AB9 +:10309000C0260A40FA50B0003B584149C5221940A9 +:1030A00039509600BB59FF20402183430B43BB514D +:1030B0000120FFF775FF3B4E3B4B3C48311C336210 +:1030C000706228310123301C0B7029300223311C1F +:1030D00003702A3103200870FF22311C32612B312A +:1030E00004220A707277321C2C3205201070321CB8 +:1030F0002D320621301C11702E3007220270301C38 +:103100002F300821321C0170303200201070321C28 +:103110000120311C32321070313196229A400B70EE +:103120001E2171617260F360FFF740FA0F23B360F4 +:10313000FFF73CFA01207483307670760021201C62 +:103140006924317701F0D0F834606E780124A6420A +:1031500002D0174801F00EF900262C70AE706E6098 +:10316000AE60AE81EE812E616E612E766E76FFF7D7 +:1031700033FEC023802180225800CC0053033C50F2 +:103180003B5086F31088281CF8BDC046440600203A +:1031900060060020A005002000E100E0FFFF00FF26 +:1031A000FF00FFFF7C06002004070A0D05080B0E38 +:1031B0003C020900014B3233187870477C0600202E +:1031C000054B10B5041CD868002802D1034801F053 +:1031D000D1F803490C7510BDA0050020F6030900C5 +:1031E00060060020014B18767047C0467C06002020 +:1031F000014B187E7047C0467C060020014B587674 +:103200007047C0467C060020014B587E7047C04680 +:103210007C060020014B18777047C0467C060020D2 +:10322000014B187F7047C0467C06002008B501F0AE +:103230005BF808BD08B50B4BD868417D002906D066 +:10324000012000F05BFB084B9A8901329A81074903 +:10325000074B084A0020585051681368C91AFFF7F5 +:10326000E4F908BDA0050020440600201405000074 +:1032700000F001407C060020084B10B51A781C1C99 +:10328000012A02D0064801F075F80649064A0220D4 +:10329000002320700B61CA6010BDC0467806002074 +:1032A00092050900600600204933000010B500F0C7 +:1032B00081FB194819491A4C00230122027023612D +:1032C0000869A623174AD900505000F065FF00286E +:1032D0000AD100F075FD01280DD900F00FFE6060E5 +:1032E000002808D1104804E000F056FF032802D05F +:1032F0000E4801F03FF8022000F0A6FC002000F08C +:10330000FDFA00F049FF032802D0094801F032F825 +:10331000FFF7B2FF10BDC046780600207C060020F3 +:1033200060060020001000407B05090080050900B0 +:103330008805090008B5034B05221A70FFF7B6FF90 +:1033400008BDC04678060020F0B5484A8023D80062 +:10335000115887B0464C012904D0464D00235659D8 +:103360009E4205D1676800233978202088425B415E +:10337000414E032500210127357021603B408B42DF +:1033800055D08123D80015583C4B11583C48D1509A +:1033900002A912583B1C00910194381C291C00F012 +:1033A00013FE032841D801F065FB1E02204E02984F +:1033B000002802D0334800F0DDFF281C00F024FF75 +:1033C000002802D1304800F0D5FF304903A8CF686B +:1033D0000223B97D0027037047603A1C07814781AB +:1033E000457081701DE02A482BE0029A002A02D124 +:1033F000284800F0BFFF281C00F006FF002802D17B +:10340000254800F0B7FF214F03A8FB68029F997D74 +:10341000022200230270476003814381457081705E +:103420000122C27000F09AFC0DE01C4809E00093F4 +:103430000193181C191C1A1C00F0C6FD042802D0A8 +:10344000174800F097FF2568002D06D100F0B2FA6A +:1034500065752561FFF72AFF05E0124801226275B4 +:1034600020610424347007B0F0BDC0460010004055 +:103470006006002034050000780600202C050000BE +:103480000C040000B8050900B9050900A0050020DA +:10349000BD050900C0050900C1050900C8050900EE +:1034A000CF0509003533000070B50C4DA124E400B0 +:1034B0002E5901F025F886420AD001F021F8285152 +:1034C000FFF7F4FE064900204968FFF7AEF870BD2B +:1034D000044B18780028F3D0F4E7C04600100040F1 +:1034E0007C06002078060020F0B5864C0125636933 +:1034F00089B0281C002B01D101F0FAF901262840DF +:1035000000D0D3E02178B14202D100F04BFA10E0B4 +:10351000022908D000F042FFFFF758F8A678002EE5 +:1035200000D0A9E00EE0784A1378033BDDB2AE424A +:1035300040410028EED0754E754877680122790821 +:103540006161CBE0FFF7D2FC704D071E00D08EE02A +:1035500020780190061E012E06D0002863D0022894 +:1035600065D1FFF7A1FF65E000F024FA00F014FE3A +:1035700000281DD100F024FC012851D9FFF706F8DE +:10358000071E0CD000F0FAFF002849D1287E002841 +:103590000BD100F0DBFF2669B04241D105E0206984 +:1035A00000F0C2FF381C00F0D7FFFFF7C5F837E086 +:1035B000698B002920D0A2898A421DD3311C381C76 +:1035C00000F09EFD00F08EFC0290A2890392E68935 +:1035D00000F082FC69460A79029905AB1A700691DF +:1035E0000C226946515A5870181C19815E819F70CF +:1035F000DF7000F0B3FB13E001F07AF9002802D08D +:10360000444800F0B7FEA1234348DF00C65900F04C +:1036100077FF864202D0E1890131E181FFF746F868 +:103620000120296800E06968FEF7FFFF02E03B48DF +:1036300000F0A0FE6D7E012D23D1FEF7A7FF00282C +:103640001FD12478012C07D0002C0DD0022C18D0CB +:10365000334800F08FFE14E000F09EFD002810D1EA +:1036600000F034FC00280CD1FFF74CF809E0696841 +:10367000301CFEF7DAFF04E0647E002C01D0FFF777 +:10368000BBF800F09DFB01280CD905A800210323FD +:10369000037041600181418141708170C17000F00F +:1036A0005DFB2DE01F4800F065FE29E0FEF78EFF70 +:1036B000A778002F1DD12178022912D1124B1D7835 +:1036C000033D012D04D900F069FEFFF7EDFE17E080 +:1036D0000E4F321C786841080D48616101F00EF907 +:1036E0000EE000F05BFE094A381C5168FEF79DFFB2 +:1036F00006E000F053FE607E002801D0FFF77CF862 +:1037000009B0F0BD44060020780600207C060020A9 +:10371000554300000A050900001000405804090044 +:10372000720409008C04090007B50190C046C04628 +:10373000C046C046C046C046C046C046C046C04659 +:10374000C046C046C046C046019B013B0193002BCA +:10375000ECD107BD70B58022164B910000245C505F +:103760001549C2250E78AD00144A032E07D109264B +:103770007442C1265C510825B4001D510AE001269F +:1037800076425E51C0230E4D02265B00EE5014615E +:1037900003244C7000235360536193604B600B759E +:1037A000984205D0074801680A69002A00D090476E +:1037B00070BDC04600100040B0060020FC10004064 +:1037C00000E100E0B0050020F8B53F4B1A69012A7E +:1037D00053D19D693D4C8022960001350321042080 +:1037E0009D611870C025A15139496A0002278F5088 +:1037F000384F00263E61C1227E607E61BE60364E3B +:1038000008259100655035682A7D3D1C002A17D097 +:10381000A927F9006258314F9A75A023D9007A5828 +:10382000024202D12E4800F0A5FD00200123A12272 +:1038300028620421A361D300F950A927F900605040 +:103840006868002802D0274800F094FD2D69002DFB +:1038500002D0254800F08EFD244A536899072DD4E4 +:103860003768F968002900D088473668707D0028DD +:1038700028D035681E4AA55024E0022A1AD11549DD +:1038800000250D6111484D6180244D6001278D6038 +:10389000C221A6007A428C0085511D70025103207E +:1038A00058705D601D750C4B1E683769AF4209D0BA +:1038B000B84707E00F4800F05DFD03E00E4800F058 +:1038C00059FDCDE7F8BDC046B0060020001000400D +:1038D00000E100E0FC100040B005002000F00140D5 +:1038E000AD020A00B6020A00B7020A00FCE100E0DD +:1038F00004050000E7020A00B8020A0070B51E4D78 +:10390000061C6B7D6C78002B02D11C4800F032FD48 +:10391000287D002802D01A4800F02CFD0122002149 +:103920002A756975022C0CD816482301C318002E7D +:1039300001D11E683260621E012A05D8997A297069 +:1039400002E0114800F016FD104D2868037D002BA1 +:1039500011D0022C0FD10E4C0E4E251C325953079C +:1039600002D40D4800F006FD0C494859002802D148 +:103970000B4800F0FFFC70BDB006002021010A00DA +:1039800022010A004C4C00003A010A00B005002058 +:103990000405000000F0014040010A000010004052 +:1039A00041010A00024B9868013843425841704770 +:1039B000FC100040F8B5164B164C02200121C02720 +:1039C000C222D8674D4282407B00134E8021134FA4 +:1039D000A55081400025F050012265507D61104DB9 +:1039E0002261A2612C78944201D1062003E0023CBE +:1039F000012C00D9101C0024FFF796FE7C61201CCE +:103A00002C70FFF7A7FE02206C753060F8BDC04631 +:103A100004E100E00010004000E100E0FC10004084 +:103A2000B006002038B50E4B0E4C18600E490F4BF7 +:103A30000F4A0225201DC56799500E48A421CA00CF +:103A40009850FFF7B7FF0C48002303210370417023 +:103A500043600361037543758375256038BDC046B7 +:103A6000B005002000E100E01410004000F001402B +:103A70002405000004110040B006002070B55C4C25 +:103A80002369607D013365782361002802D059489D +:103A900000F070FC2178032948D1574E3269002A82 +:103AA00044D0012D35D12269032A02D0534800F0B9 +:103AB00061FCA06902210130514A8025A0610023E8 +:103AC0008D400120217053514542C220884015503D +:103AD000C02568004B4D29504B493361096873601C +:103AE0007361B3600326667063602375087D984236 +:103AF0000DD0A925E80016580125A6753E4C0426D0 +:103B000023629561A124414DE4002E511350CA68EF +:103B100065E0022D08D12369012B02D03C4800F05A +:103B200029FCFFF751FE61E03A485DE0032D5AD0D1 +:103B3000012D3CD12169012918D12F480021304B9A +:103B40000126C2224160816070429100C126585016 +:103B5000B0001D502C4D304E2A68117D002902D036 +:103B60002A4D0420A851E4689C513FE002293DD130 +:103B7000234E214A8023002598000221C22315618B +:103B80005561556035504A429800C12132508B0032 +:103B90000822F25003262670656025751A4C2568A8 +:103BA000261C2869002800D08047306816E0022DC6 +:103BB000B7D0657819482B01C1180E7B0025AE429D +:103BC00003D00D4A15696A1E95418B7A0120237036 +:103BD000FFF7C0FD002D09D00B4C20688268002A39 +:103BE00004D0904702E00E4800F0C4FB70BDC04610 +:103BF000B006002090010A00FC1000409F010A005E +:103C00000010004000E100E0B005002000F001409D +:103C1000A4010A00A9010A00040500004C4C0000A0 +:103C2000D6010A0008B5022804D8054B187843428B +:103C3000584103E0034800F09DFB002008BDC0464A +:103C4000B0060020F9020A00F8B52B4C0301061C4F +:103C50002A4F207DFF18002802D0294800F08AFB57 +:103C6000301CFFF7DFFF002802D1264800F082FB5E +:103C70000121C222244D0023484291006375C022D5 +:103C8000685022490220520088502148667002681C +:103C9000116852682361A3613B68A160E2606360C0 +:103CA000022E18D8387A80239B00E850F87A194BF6 +:103CB000002805D1E950EA58002A08D1164804E046 +:103CC000EA50E958002902D1144800F053FB7F7AEA +:103CD000C1208300EF500E4D29680A7D002A07D0CD +:103CE000022E05D10B480E4B00260427A6751F5047 +:103CF00001256575F8BDC046B00600204C4C00009B +:103D0000DB000A00DD000A000010004000E100E0D6 +:103D1000B00500200405000000010A0005010A00AA +:103D200000F001407047C04610B5041E02D108489B +:103D300000F020FB074B00221C60191DDA670833D6 +:103D4000CA678020DA67044B44031C6010BDC0467C +:103D500029000B00D406002000E100E070B5144CEF +:103D6000051C2368002B02D1124800F003FB201C25 +:103D70000830C16F092902D90F4800F0FBFAE66F3D +:103D80000C225643A319043343CD43C3251C0835E5 +:103D9000E86F0130E867E16F0131E167E66F092EF6 +:103DA00001D90022E2678024044B65035D6070BD89 +:103DB000D406002034000B0035000B00FCE100E0CD +:103DC000034B0A200833D96F421AD0B27047C0465D +:103DD000D4060020F0B587B0012383F31088134C7C +:103DE000124D0834E06F00281BD02A1DD16F0C261D +:103DF000714303AB69180431181CE0C9E0C0E76FD8 +:103E00000026013FE767D46F0134D467D56F092DD1 +:103E100000D9D66786F31088044A176807CBB847DD +:103E2000DAE780F3108807B0F0BDC046D406002062 +:103E300038B50A4C051CE36F002B02D1084800F08E +:103E400099FA291C0831E06F00F03CFC00218842FF +:103E500001D0E1670121081C38BDC0465C07002085 +:103E60006F020C0010B500F0B7FB0021124A880069 +:103E7000002384188818A361A363041C803488304D +:103E8000237003700D480C18013123700829EDD1FF +:103E9000111C101C141C9031913058341370536055 +:103EA0009360D360136153610B7003702370D36709 +:103EB00092320123137010BD5C070020F007002030 +:103EC000014B185C7047C046F0070020014B90334F +:103ED000187870475C070020014B58687047C0464F +:103EE0005C070020014B98687047C0465C070020C3 +:103EF000014BD8687047C0465C07002010B5104CD5 +:103F00002378002B02D00F4800F034FAE06F00282D +:103F100002D100F08BFBE067E06F00280FD0012199 +:103F200043784A4206210B43437002700023C218B3 +:103F3000FF2101339170202BF9D10323237010BD91 +:103F40005C0700203B010C0038B5124C2378002B95 +:103F50001ED1201C90300178002919D108256069F4 +:103F600000F028FC002805D0231C60699033012252 +:103F70001A70206161690131082900D10021231CD8 +:103F8000616190331A78002A02D1013D002DE6D1FB +:103F900038BDC0465C07002038B5094D041C2B1CF9 +:103FA00090331878002804D02969A14201D1FFF785 +:103FB000CBFF2A19034B0025803215701D5538BDE3 +:103FC0005C070020F0070020F0B5464D85B0039354 +:103FD000EB6F061C0C1C171C002B02D1424800F092 +:103FE000C9F92878032802D0404800F0C3F9E96FE6 +:103FF00001234A781A4202D192352D786B4004256C +:10400000002E61D050070126810F1E40251C231C65 +:104010000A0608330E353F023249A8003F0A0293D0 +:104020000B5817430B980A9A0025156005609F42AC +:1040300033D0201CFFF7FCFE0190AE4200D0051CDF +:1040400001232E1C1E40002828D00299254A063143 +:1040500088008750039F1D1C002F20D0244F3B5DFC +:10406000002B1CD0201C00F0A5FB002802D1214809 +:1040700000F080F9201C00F05BFB051E02D0201C24 +:10408000FFF78AFF0A990D60002D02D11A4800F04F +:1040900071F900203855022501E001950325002E15 +:1040A0000DD0201C00F06CFB0B9E3060002802D16C +:1040B000124B336005E00E4F01223A5501E00B9C94 +:1040C00026600199002905D1064CE06F00F0CCFA7A +:1040D0000020E067034A00261670FFF735FF281C12 +:1040E00005B0F0BD5C0700205B010C005C010C001A +:1040F000F007002091010C0096010C00B40700208D +:10410000F8B51F4C071C23780E1C013B012B02D96C +:104110001C4800F02FF90425002F19D02078012821 +:1041200002D0194800F026F9E268002A02D11748A7 +:1041300000F020F9E16800250F78AF4208D06068F0 +:10414000FFF776FE0225002802D1114800F012F98F +:10415000002E0ED06768381C00F0EAFA061E02D066 +:10416000381CFFF719FFA3689E4202D0094800F0EF +:1041700001F900202070FFF7E7FE281CF8BDC046BB +:104180005C070020FC000C0002010C0003010C0085 +:104190000E010C001E010C00014B18787047C04640 +:1041A0005C07002038B5041C0D1C00F013FB002830 +:1041B00001D1002008E0281C211C00F083FA00280F +:1041C000F7D0FFF7C1FE012038BD08B500F0D8FADE +:1041D00008BD10B5041CFFF7DFFE201C00F000FB3B +:1041E00010BD08B500F0E6FA08BD08B5083000F0CB +:1041F000C7FA08BD08B5083000F09AFA08BD08B53E +:10420000083000F0EDFA08BD08B5083000F0D2FA29 +:1042100008BD10B52A4C2378002B02D0294800F0A5 +:10422000A9F8201C90300178002927D0206960600F +:1042300000F0A6FAA060002802D1234800F09AF806 +:10424000A26801235078034004D1211C92310A78DE +:10425000002A10D16068FFF7D7FF02280ED8E36F5D +:10426000002B02D100F0E2F9E067E16FE160002984 +:1042700004D0012001E0E3600220207022780020B9 +:1042800082421BD0A368834202D1104800F072F82A +:1042900020696060063081006318DA7803210132FA +:1042A000D0B2D870A36808405A78410006208243F3 +:1042B0000A435A70903400232370012010BDC04679 +:1042C0005C070020C3000C00C9000C00E7000C00D4 +:1042D00008B500F0ABF908BD08B500F0C5F908BD98 +:1042E00008B500F077FA08BD014B9233187070479B +:1042F0005C070020014B9233187870475C07002060 +:104300007047C046024B9870587018707047C0468E +:10431000F807002010B5041E012C02D9024800F055 +:1043200029F8024B5C7010BD2A000D00F807002030 +:10433000014B18787047C046F8070020014B987869 +:104340007047C046F8070020014B58787047C046B8 +:10435000F807002008B5054B1A7858789A7018703D +:10436000034B8100CA58904708BDC046F80700209B +:104370007C00002008B5FEF7FFF808BD10B5041E4C +:1043800002D10448FFF7F6FF034B00221C605A607D +:104390009A6010BD2A000100B4050020094B00B549 +:1043A00018689A68016801329A608A4208D359688D +:1043B0004068002201319A605960814200D35A60FE +:1043C00000BDC046B4050020F8B500282AD0164C20 +:1043D000A36801280ED1276801333A68A36093428D +:1043E00020D36068796800250130A560606088424C +:1043F00018D316E02668C7183568A760381C291C32 +:1044000000F042FB62683B1C80186060AB4201D345 +:104410005B1BFBE771686568A3608D4201D36D1A71 +:10442000FBE76560F8BDC046B4050020024B1A6882 +:1044300099681068401A7047B405002070B50D4D9A +:10444000041C2B685868844202D30B48FFF792FF84 +:104450006E68B4420CD002D829684A68A418FFF7E5 +:10446000E5FF2D68F3432E6819197143081800E021 +:10447000002070BDB40500206800010070B5041C68 +:104480000D1C884202D30B48FFF774FF0A4E3368B5 +:104490001868854202D90948FFF76CFFB168601AB5 +:1044A000A14206D30020A94203D3326815686E1AD0 +:1044B000301970BD7D000100B40500207E000100B0 +:1044C00038B5041C101C0D1CFFF7B8FF002801D0E4 +:1044D000001911E0201C291CFFF7D0FF041CFFF776 +:1044E000A5FF031C201E984206D304490D686A6884 +:1044F0002C68013A5443001938BDC046B405002069 +:10450000074B10B51A68596850681C1C814202D3C9 +:104510000448FFF72FFF236861689A68505C10BD5C +:10452000B4050020B200010038B5064B041C1A681F +:104530001D1C5068844202D30348FFF71BFF6C60C8 +:1045400038BDC046B4050020B9000100014B5868D1 +:104550007047C046B405002038B5064B041C1A68E5 +:104560001D1C1068844202D30348FFF703FFAC60B0 +:1045700038BDC046B4050020C5000100014B986855 +:104580007047C046B405002010B50F4B1A680023D1 +:1045900093420BD20D499C006458A04203D10C48B1 +:1045A000FFF7E8FE0CE00133DBB2F1E70024222242 +:1045B000624308495318984204D00134062CF6D1BE +:1045C000002000E0012010BDFC07002000080020B2 +:1045D000F60003000809002010B500220F49500022 +:1045E000801800230C1801326370A3704354102A02 +:1045F000F4D122225A430A490A485418211C9A002D +:1046000084502231DE22227001348C42FAD10133EF +:10461000062BEED1044C236010BDC04618080020C4 +:104620000809002000080020FC07002038B50A4BCC +:104630001C68002C0ED0621E084990004458084D9A +:104640001A604550201CFFF79FFF002802D1054843 +:10465000FFF790FE201C38BDFC070020000800205A +:10466000ADDEADDE7D00030070B5104C051C236887 +:10467000052B02D90E48FFF77DFE281CFFF784FFAB +:10468000002802D10B48FFF775FE21680A488A000E +:1046900011580A4B061C994202D00948FFF76AFEDE +:1046A000206882000130B550206070BDFC070020FA +:1046B000850003008600030000080020ADDEADDEAB +:1046C00088000300F8B5051C0C1E0F2C02D91448F5 +:1046D000FFF750FE281CFFF757FF002802D11148B2 +:1046E000FFF748FE104966003019435C0022022B98 +:1046F00013D80B185F78C0190C4F8000C5515D7836 +:104700000135E8B258705F78022F00D95A7032191B +:104710008C5C0134E6B28E540122101CF8BDC046F8 +:104720008F000300900003001808002048080020B4 +:1047300038B5041E0F2C02D90E48FFF71BFE0E4A97 +:1047400065002919885C002813D053189878091837 +:104750000A488900085899780131C9B29970997846 +:10476000022901D9002199702C19155D013DEBB288 +:10477000135538BDA6000300180800204808002083 +:1047800010B5041E0F2C02D90748FFF7F3FD074BA5 +:1047900062001119C85C002805D0581884780B19DC +:1047A00003499A00505810BDB700030018080020B4 +:1047B0004808002010B5041E0F2C02D90348FFF74B +:1047C000D9FD630002491819405C10BDC800030000 +:1047D00018080020014B18687047C046FC070020ED +:1047E00038B5051E0F2D0CD90948FFF7C3FD08E0A9 +:1047F000084B9C4202D10848FFF7BCFD201CFFF784 +:1048000033FF281CFFF794FF041EF1D138BDC046CA +:10481000D7000300ADDEADDEDB000300164BA121A7 +:1048200010B50122CC0000205A60DA6018515A6499 +:10483000124A1C1C9958814202D01148FFF79AFD78 +:104840000123C222584291000E4B60500022A22147 +:104850005A640420CB00E0500B490C4C012022602C +:104860002271627108700A4B8022C021D4008140FD +:104870005C501C6010BDC04600A000404405000014 +:1048800035000400FCA00040D4090020C005002031 +:1048900000E100E0034B0449012200201A60087087 +:1048A0007047C04600A00040D4090020094A30B536 +:1048B00001235360084CD3608025084AC0200021A2 +:1048C000ED0098401160117125505171044A137028 +:1048D00030BDC04600A0004000E100E0C00500205F +:1048E000D4090020014B18787047C046D409002035 +:1048F000014B18797047C046C0050020F7B5334F0B +:104900000092334C8022C2237E790191051C9900CC +:1049100050026050002E02D02E48FFF72BFD002DD4 +:1049200002D12D48FFF726FD3A68002A02D02B4815 +:10493000FFF720FD3D60009D294E012D0DD0002D7B +:1049400003D0022D0DD1A92208E00120254B0099AA +:104950006064E5582064716407E0A822D5006559B9 +:1049600003E02148FFF706FD002501227A71019F2F +:10497000A821E81987B20023C8007364275027587C +:1049800000976264174AA758716C1E1C994202D0A6 +:104990001648FFF7EFFC009BAB4205D3AF4201D3B3 +:1049A0009F420CD3124808E0301CAF427041009D7A +:1049B000AF427641B04202D00E48FFF7DBFC8022C6 +:1049C000C12157028E00A751F7BDC046C005002087 +:1049D00000A000407300040075000400760004008D +:1049E000FCA0004044050000890004009B00040076 +:1049F000B0000400C90004000048704748A000400F +:104A00000048704740A1004070B58022134C144DFF +:104A1000C22350029900002668506664114C226837 +:104A2000B24202D11048FFF7A5FC104B012166717C +:104A30002068A82226606964EE58D300EA580C4D1D +:104A40001432AE4203D8C0231D02AA4202D800216C +:104A5000964249412171804770BDC046FCA000408C +:104A600000A00040C0050020EC0004004405000048 +:104A7000FF3F000002B4714649084900095C490043 +:104A80008E4402BC7047C046002934D00123002266 +:104A900010B488422CD301242407A14204D28142BD +:104AA00002D209011B01F8E7E400A14204D28142CD +:104AB00002D249005B00F8E7884201D3401A1A434A +:104AC0004C08A04202D3001B5C0822438C08A04281 +:104AD00002D3001B9C082243CC08A04202D3001B37 +:104AE000DC082243002803D01B0901D00909E3E7B1 +:104AF000101C10BC704701B5002000F00BF802BD7F +:104B00000029F8D003B5FFF7C1FF0EBC4243891A54 +:104B10001847C0467047C04630B500240139A2424C +:104B200001D1002005E0035D01340D5DAB42F6D0FC +:104B3000581B30BD002310B59A4200D110BDCC5C8B +:104B4000C4540133F8E70000F8B5C046F8BC08BC0F +:104B50009E467047F8B5C046F8BC08BC9E467047F4 +:104B600000000020656E6372797074696F6E206B4F +:104B700065790000656E6372797074696F6E206E7E +:104B80006F6E6365000000004D4143206B65790046 +:104B9000191816170000000000000010D4EC881E41 +:104BA000320E9786F2DB75FA73DA8A10A909B09D86 +:104BB000364DC240EB37CB13F3B3E641993FFC8847 +:104BC000BF214490F02B532E02FF7EC5F84B00000E +:104BD000D84B0000E84B0000A909B09D364DC240FB +:104BE000EB37CB13F3B3E641FFE55DCC7BCE111F72 +:104BF000B3B6E87EA381E049993FFC88BF21449089 +:104C0000F02B532E02FF7EC5090000000B000000B0 +:104C10000A00000008000000000000000000000082 +:104C200000E0D70103000000090000000B000000B5 +:104C30000A00000008000000000000000000000062 +:104C400000E0D70103000000010200000010004056 +:104C5000101100400310000001000000001000408F +:104C6000000000000B0204000000000004100040DF +:104C70000000000007080301000000000000000021 +:084C800088B4FF7F0100000071 +:104C8800000000000000000000000000000000001C +:104C9800000000000000000000000000000000000C +:104CA80000000000000000000000000000000000FC +:104CB80000000000000000000000000000000000EC +:104CC80000000000000000000000000000000000DC +:104CD80000000000000000000000000000000000CC +:104CE800C8050020010000000500000004192A3F43 +:104CF8004D0000000000000000000000E934000042 +:0C4D080035320000E9000000C10000008E +:0400000300001CDD00 +:00000001FF diff --git a/precompiled/precompiled-crypto-right.hex b/precompiled/precompiled-crypto-right.hex new file mode 100644 index 0000000..db2e40c --- /dev/null +++ b/precompiled/precompiled-crypto-right.hex @@ -0,0 +1,1125 @@ +:10000000004000202516000065160000671600005D +:1000100000000000000000000000000000000000E0 +:100020000000000000000000000000006916000051 +:1000300000000000000000006B1600006D160000BC +:1000400021130000C53300006F1600006F1600007A +:100050006F16000000000000DD1000006F160000A9 +:100060006F1600006F16000051430000E5140000F9 +:100070006F1600006F1600006F1600006F1600006C +:100080006F160000851500006F1600006F16000047 +:100090001D3700006F1600006F1600006F1600007D +:1000A0006F1600006F160000000000000000000046 +:1000B0000000000000000000000000000000000040 +:1000C00010B5064C2378002B07D1054B002B02D02E +:1000D000044800E000BF0123237010BD8800002009 +:1000E0000000000084450000044B10B5002B03D035 +:1000F0000349044800E000BF10BDC04600000000F6 +:100100008C00002084450000144B002B00D1124BC2 +:100110009D46402292029A1A924600218B460F4633 +:100120001148124A121A00F07BF80D4B002B00D038 +:1001300098470C4B002B00D098470020002104006A +:100140000D000B4800F016F800F046F820002900DA +:1001500000F020FF00F016F800000800004000202A +:10016000000000000000000088000020C4060020FD +:10017000B1010000002310B501001A00180000F0C2 +:1001800057F810BD084B10B50400002B02D0002119 +:1001900000F0B4F8054B1868836A002B00D098472C +:1001A000200000F007F9C046FD020000A84400004E +:1001B00070B5074D074C641BA410002C02D104F04D +:1001C0006DF970BD013CA300EB589847F5E7C046B8 +:1001D000840000208800002070B500260C4D0D4CD6 +:1001E000641BA410A64209D1002604F051F90A4D5F +:1001F0000A4C641BA410A64205D170BDB300EB5895 +:1002000098470136EEE7B300EB5898470136F2E71E +:10021000800000208000002080000020840000205A +:1002200003008218934200D1704719700133F9E737 +:10023000F0B52D4D85B0060028680192009102931B +:1002400000F0B4F8294A1468002C0AD1284B136036 +:10025000284A1C00002A04D0190012688831039231 +:100260000A6063681F2B06DD286800F0A1F80120F2 +:10027000404205B0F0BD002E29D0270088373868ED +:10028000002812D11C4B002B03D1286800F08FF8F6 +:10029000EDE78420400000E000BF0028F5D0030017 +:1002A0000022FC335A609A6038606168019A8B00C2 +:1002B000C31804C301228A40FC30416811434160E5 +:1002C0000299D967022E02D183681A43826063685B +:1002D00028685A1C62600233009A9B001A5100F091 +:1002E00067F80020C5E7C04660000020300100200C +:1002F000A40000200000000000000000F7B5294B1A +:10030000019018680F0000F051F8274B1D68002D70 +:1003100004D1244B186800F04BF8F7BD2B0088334C +:100320001E686B685C1E002CF3DB002F09D0002ECA +:1003300001D1013CF7E73300A20080339B58BB4258 +:10034000F7D128006968A200083001398358A1421A +:1003500019D16C60002BECD069680091002E08D098 +:10036000FC218C460120B4446146A040496801420A +:100370000CD198470C4B6A6800991B688A42C4D11B +:100380009D42D6D0C1E700218150E3E7B1586246D3 +:100390009268024202D101989847EBE7080098471B +:1003A000E8E7C04660000020300100207047704739 +:1003B00070470000FEE7C0462D4B1B78012B00D094 +:1003C00070472C4B1B681B07FAD12B4AF02312688D +:1003D000110019401A4201D0102946D1274A12684B +:1003E0001A421FD0F022244B1B681340402B29D007 +:1003F000F022214B1B681340A02B01D0D02BDFD162 +:10040000F0231E4A12681A42DAD11D4A1368012BE2 +:1004100004D01C4B13601368012BFCD1C0221A4B73 +:100420001A60CDE7194B1A4A1A608022194B120242 +:100430001A600F4B1B78012BC2D10E4B1B681B0798 +:10044000D0D0BDE70D4B1B681342D1D18022C12310 +:100450000121DB00D205D150054B1B78012BAFD118 +:10046000044B1B681B07C3D0AAE73029B6D0B9E7F5 +:10047000E00F00F0E40F00F0E80F00F0EC0F00F0E8 +:1004800000EC06407593000014EC064004050040A3 +:10049000DFFF07C0186C004030B505000C001000ED +:1004A000190087B0022C02D9002007B030BD1D4BC7 +:1004B000A400E25802AB0093102300F079FB00285F +:1004C000F2D010240F231021174A0194009502A89E +:1004D00000F082FB0028E7D02B001033009310219E +:1004E0001123124A019402A800F076FB0028DBD009 +:1004F0000023EB6102AB0093102108230C4A019406 +:1005000002A800F069FB0028CED02800102202A922 +:10051000303000F059F80028C6D0280000F00AF862 +:10052000C3E7C046D8440000AC440000BC4400000F +:10053000D0440000002804D0034A044BD0500120CE +:1005400070470020FCE7C04600E0004004050000C2 +:1005500070B500282ED0184A184BD158814200D0CF +:10056000D0508224802500238022134964006D002E +:100570000B514B5101330B60520402E0013A002A47 +:1005800018D04B5908590343F8D00D48036801337C +:1005900003600C4803681E0080235B049C46002314 +:1005A0006644B21A02604B510A590120002A00D158 +:1005B00070BD0B510020FBE700E000400405000087 +:1005C0003401002038010020F0B50500C646203572 +:1005D0000400A84600B50F2A00D951E110230020DD +:1005E00020269B1AA055012B3AD00136A055022B8C +:1005F00036D00136A055032B32D00136A055042B3E +:100600002ED00136A055052B2AD00136A055062B39 +:1006100026D00136A055072B22D00136A055082B35 +:100620001ED00136A055092B1AD00136A0550A2B31 +:1006300016D00136A0550B2B12D00136A0550C2B2D +:100640000ED00136A0550D2B0AD00136A0550E2B29 +:1006500006D00136A055102B02D11F33E05441E0E3 +:1006600000200500A71A3437B9424541A61A2F00C9 +:1006700030360D1DAE4240410743BC460827501E90 +:100680008742BF4160467F42074200D1FDE0300013 +:100690000843800700D0F8E00D6890083560012815 +:1006A00005D04D687560032801D18868B0600320CB +:1006B0001500854328005B19AA4213D04E5DE2184D +:1006C000203216705A1C6E1C0F2B0BD08E5DA21898 +:1006D0002032167002309A1C0E2B03D00B5CA2182D +:1006E000203213702000102200213030FFF798FDD7 +:1006F00050223F21A35C40468B43A354FFF728FFC1 +:10070000002800D1B9E04F23E25C5300E3734E238D +:10071000E35CD20959000A43A2734D22A25CDB09B3 +:1007200051000B4363734C23E35CD20959000A4325 +:1007300022734B22A25CDB0951000B43E3724A2374 +:10074000E35CD20959000A43A2724922A25CDB0988 +:1007500051000B4363724823E35CD20959000A43FA +:1007600022724722A25CDB0951000B43E37146234E +:10077000E35CD20959000A43A2714522A25CDB095D +:1007800051000B4363714423E35CD20959000A43CF +:1007900022714322A25CDB0951000B43E370422328 +:1007A000E35CD20959000A43A2704122A25CDB0932 +:1007B00051000B4363704023E15CD2094B001A43A4 +:1007C00022707F2904D97923E27B5B425340E37393 +:1007D000E27B5300E377A37BD20959000A43A27757 +:1007E000627BDB0951000B436377237BD2095900FD +:1007F0000A432277E27ADB0951000B43E376A37ABE +:10080000D20959000A43A276627ADB0951000B43F0 +:100810006376237AD20959000A432276E279DB090A +:1008200051000B43E375A379D20959000A43A2751D +:100830006279DB0951000B4363752379D2095900B2 +:100840000A432275E278DB0951000B43E374A37875 +:10085000D20959000A43A2746278DB0951000B43A4 +:1008600021786374D2094B001A4322747F2904D97A +:100870007923E27F5B425340E37704BC9046F0BDAE +:100880001022280003F0FAFD2CE70878E318203343 +:10089000187011239B1A102B00D123E74878E31816 +:1008A0002033187012239B1A102B00D11AE7887876 +:1008B000E3182033187013239B1A102B00D111E773 +:1008C000C878E3182033187014239B1A102B00D11A +:1008D00008E70879E3182033187015239B1A102BAA +:1008E00000D1FFE64879E3182033187016239B1ACD +:1008F000102B00D1F6E68879E318203318701723FF +:100900009B1A102B00D1EDE6C879E318203318703C +:1009100018239B1A102B00D1E4E6087AE318203341 +:10092000187019239B1A102B00D1DBE6487AE318C4 +:10093000203318701A239B1A102B00D1D2E6887A24 +:10094000E318203318701B239B1A102B00D1C9E623 +:10095000C87AE318203318701C239B1A102B00D17F +:10096000C0E6087BE318203318701D239B1A102B58 +:1009700000D1B7E6487BE318203318700E2A00D167 +:10098000B0E62F238A7BE254ACE6C046F0B51400F3 +:100990003022454657464E469446DE465023E0B543 +:1009A000844410276246C35C83B09B06DB0EFF1AAB +:1009B000060088463D000192BC4263D95022914610 +:1009C000313A93461F329246019A4146D0182A0086 +:1009D00003F054FD4B46F25C51469306DB0EFF18C4 +:1009E0005B463B408A435F0017434A46B754524632 +:1009F000A844641B3A40202A1ED01027FF1A3D004D +:100A0000019AD018AC42DFD82200414603F036FDEF +:100A10005021735C01209A06D20EA4181F221440A4 +:100A20001F32640093432343735403B03CBC90468D +:100A30009946A246AB46F0BDFB0712D430002030E9 +:100A4000FFF786FD0028F0D04B463F22F35C1027CD +:100A50009343012213434A461025B35401980023BF +:100A6000D0E7336B326C53403363726C736B53401B +:100A70007363B26CB36B5340B363F26CF36B53406C +:100A8000F363DBE7D018BFE7F0B550230400C64698 +:100A9000E25C123B0E0000B530301340202B38D101 +:100AA000236B2268534023636268636B5340636324 +:100AB000A268A36B5340A363E268E36B5340E36314 +:100AC0005023E35CDB070FD5236B226C5340236379 +:100AD000626C636B53406363A26CA36B5340A3636C +:100AE000E26CE36B5340E36320002030FFF730FDFE +:100AF000051E0AD050223F21A35C30008B43210009 +:100B0000A3544031403A03F0B9FC280004BC90469D +:100B1000F0BD210092061031D20E032A3AD92700E7 +:100B20000B00043A90469208944614379200BF187E +:100B30001A6A1D6804336A40DA619F42F8D163463D +:100B400062464546013392009B00AA1A012A05D944 +:100B5000CD5AC75A023A7D40C5520233002A03D00B +:100B6000CA5CC55C6A40C2545023E25C9206D20E55 +:100B7000A3181F7C1D0080235B4230357B402B7007 +:100B80000E2A9DD80F23551C49199A1A401903F0B3 +:100B900075FC95E70023D9E770B504001D00FFF749 +:100BA000F5FE002803D029002000FFF76DFF70BD7F +:100BB00030B597B004000D0001A811001A00FFF72E +:100BC00003FD002805D02A0021001A9B01A8FFF789 +:100BD000E3FF17B030BDC046F0B54546DE46574688 +:100BE0004E469B46FF23E0B59BB0259D8046894637 +:100BF00092461B019D4248D82F09FFB22B074CD1CA +:100C00006B46DC1C012300262370002F0FD147E028 +:100C1000102201A903F032FC1036103DB6B2237841 +:100C20000133DBB22370BB423AD8002B38D04A469E +:100C3000414605A8FFF7C8FC002826D02378012BE1 +:100C400006D9102201A905A8FFF7A0FE00281CD094 +:100C50005A46514605A8FFF799FE002815D00122F3 +:100C6000210005A8FFF792FE00280ED001A905A8D3 +:100C7000FFF70AFF002808D0249B9819102DC7D829 +:100C80002A0001A903F0FAFBC9E700201BB03CBC15 +:100C900090469946A246AB46F0BD0137FFB2AFE79A +:100CA0000120F3E7F8B505000C0017001E0010291D +:100CB00001D90020F8BDFFF74BFC0028F9D029002E +:100CC00020318C46032C2ED92B6A3A68534033606E +:100CD000231F032B11D96A6A79684A407260220087 +:100CE000083A032A09D9BA68A96A4A40B260102CA6 +:100CF00003D1EA6AF9684A40F26003229B08013393 +:100D00009B001440012C06D96146FA5ACD5A023C88 +:100D10006A40F2520233002CCCD06146FA5CC95CC6 +:100D20004A40F254C6E70023ECE7C046F8B5012379 +:100D30004E46994657464546DE464846E0B510279A +:100D400008264C4A4C4C13704C4B1B689A08D90926 +:100D50000140D2013F300A435900014080460A4316 +:100D60002038590901400A43D90A39400A43D90AAF +:100D7000314084460A431C38590001400A43D908CF +:100D80008A46022155468B460D4061462A43227011 +:100D90005D011A0A0D40D2012A434D46590E0D40FD +:100DA0008A46D9092A430D0041460D4059002A437D +:100DB0000D00D9083D402A430D00D90935402A438A +:100DC0000D00990C05402A430D0059460D4041463F +:100DD0002A4362709A0D0A40654651460D40590FEC +:100DE000C9012A430A43190D0F400B0017435A4605 +:100DF0000E403E43084030431340214E0343A3704E +:100E00002200230003213000FFF74CFF00280CD103 +:100E10001C4A1368013313600023164A13703CBC4C +:100E200090469946A246AB46F8BDF36930005A1C7D +:100E300063602300F2612100082208333030FFF79D +:100E4000ABFE002804D1104A136801331360E3E7B6 +:100E500018222100012000F02EFC002804D00B4AAB +:100E6000136801331360D7E7094A1368013313602D +:100E7000D2E7C04610020020E80100201402002042 +:100E8000640100200C02002060010020B402002058 +:100E9000B802002070B52C4A1378D9B2002B1DD0AF +:100EA000A021A223C905DB00C858284B1968284B8C +:100EB000834399422CD000231370A022A223D20591 +:100EC000DB00D258224B93431ED1224A13680133D0 +:100ED0001360FA22520093422BD870BDA024A220A6 +:100EE0001B4BE4051E00C0002558AE4335001A4ECA +:100EF0003668AE42E1D02058834314480360012392 +:100F00001370164B1960D8E70022124B1A60E4E701 +:100F1000124A136801331360052BCED10E4B1960B2 +:100F20000F4B1B78002B0BD00E4A13680133136054 +:100F3000C3E70D4800F0B8FA0C4800F0B5FACCE76A +:100F4000FFF7F4FEB9E7C0460402002018020020B3 +:100F5000FFE7E8735C01002014020020000200207B +:100F600010020020080200203C450000344500002B +:100F700010B5064B1B78002B04D0054A13680133CB +:100F8000136010BDFFF7D2FEFBE7C0461002002041 +:100F90000802002070B5002000F096FE642000F0EA +:100FA0003DFE364800F0ECFC354800F001FD00F055 +:100FB0005FFB00F067F9002000F082F9314D00215D +:100FC000314A280000F02EFA304C314A002120002E +:100FD00000F028FA0121280000F072FA2000012117 +:100FE00000F06EFAA023E1212A4ADB05C9005A501D +:100FF00029492A4C5A5014315A50294929485A50E3 +:1010000004395A5028495A500C315A5027495A50DD +:1010100004315A5026495A5034395A5025495A50A9 +:101020000C315A5024495A5024495A5024495A5094 +:1010300024495A5004395A5008315A5018395A50D4 +:1010400021495A5004395A5020495A50C12380210D +:101050001F4A9B000906D15040221E4B00211A60F6 +:1010600010232200FFF718FA1023220002211A4849 +:10107000FFF712FA40BF20BF20BFFBE704030201C5 +:10108000080706053C450000710F000034450000CC +:10109000950E00000C00030014070000144500002A +:1010A0003C07000064010020040700001C0700004A +:1010B000340700000C070000240700004C07000064 +:1010C00064070000740700005C070000540700007C +:1010D0000060004000E100E020020020BE2310B5C7 +:1010E0000A4A5B00D158002900D110BD00240848ED +:1010F000D45000F0CDF9074800F0CAF9064B1C7037 +:10110000064B1C60064B1C60EFE7C04600600040C9 +:101110003C4500003445000004020020000200208D +:101120005C0100202023F0B58FB0029103920C0CDB +:10113000059301280CD16B461B7A002B0CD13E4B3A +:101140001A88A24206D33D4B1A68944664441C6038 +:101150000FB0F0BD1C80F6E7394D05AA290000F05C +:10116000EDFA384F1022290006AB3800FFF714FDC6 +:1011700029001022103106A803F072F9061E08D0CB +:10118000314A1368013313602B4B1A88A242DAD21A +:10119000E0E738002D4A303813680F21013313601F +:1011A000EB7B2A00C36106ABFFF77CFD002804D16E +:1011B000274A136801331360C1E7EA7B254B0F21EF +:1011C000DA700AAB0093244A102306A8FFF7F0FC5C +:1011D0000028B4D01027214D0F231021204A019759 +:1011E00000950AA8FFF7F8FC0028A8D02B001033C0 +:1011F0000093102111231B4A01970AA8FFF7ECFC6A +:1012000000289CD00AABEE6139000093164A0823EF +:1012100001970AA8FFF7E0FC002800D18FE73A0009 +:1012200012480AA9FFF7D0F9002800D187E7280063 +:10123000FFF780F983E7C0461C020020B0020020BF +:101240003C01002050020020A4020020A80200203F +:10125000AC020020E80100202445000064010020C9 +:10126000AC440000BC440000D044000094010020C5 +:1012700082B002B07047C04682B002B07047C0462C +:101280007047C04670B50D4C237A002B13D16360B4 +:1012900023602361E360AA228023FF210125DB056F +:1012A000D2009950383A00209D50FC3900F086F861 +:1012B0000020257270BD8520FCE7C046BC020020DE +:1012C00070B50400002000F067F8124DAB7A002BD7 +:1012D0000BD0002C02D0012063689847EB680133E3 +:1012E0000020EB6000F060F870BD002C02D02B698C +:1012F0002C612360EB68002BF1D1074A8021136039 +:10130000C1220220C905920088500121034A1160C0 +:10131000E5E7C046BC020020040100400800004090 +:1013200010B51A4B1A68002A14D0002280211A60C6 +:10133000C2220123164CC90592008B506372636868 +:10134000002B07D01A6800205B68626098476368CA +:10135000002BF7D10F4B1A68002A15D000221A6013 +:101360008022C22302219B00D205D1500123084CC8 +:10137000A3722369002B07D01A6801205B682261E1 +:1013800098472369002BF7D110BDC04600010040EB +:10139000BC0200200401004072B6024A1368013307 +:1013A00013607047D0020020034A1368013B1360AA +:1013B000002B00D162B67047D002002030B5FF2567 +:1013C00003232A000340DB009A4089010D40D243E9 +:1013D0009D40C4B2002814DB104B80089C46C023FB +:1013E000800060449B00C1580A401543C5501F232C +:1013F000C0211C401E3BA340084A490053501360C3 +:1014000030BD0F23064923408C46083B9B089B00B8 +:101410006344D9690A401543DD61E8E700E100E073 +:1014200000ED00E070B505000C00002A28D04079DE +:10143000144B8100CA504300002C1CD0124E1B18C4 +:101440009B5D002B15D10420A1782856FFF7B6FF2D +:10145000A12322882968DB00CA506A7921795300C8 +:101460009B18F2185170E1780020917001229A5572 +:1014700070BD0820FCE7054C191849006418DDE729 +:101480000720F5E7DC020020D402002044450000DC +:101490000122022103681A60427953009B18014A15 +:1014A00099547047D4020020012203685A604179A0 +:1014B0004B005B1801495A547047C046D4020020C3 +:1014C0008023002210B504685B00E250D12204683A +:1014D000FF3B9200A350002902D00168403A8B5094 +:1014E00010BDC046C123F0B5C64680249B00002530 +:1014F000984600B5204E214F64024346F3581C42E3 +:1015000010D01F4AAB00944663441A68002A09D0E1 +:10151000D2229200B450403AB4500022E8B21A608D +:101520003B68984701356400042DE6D1C122124B77 +:1015300092009A58D20704D5802252009958002967 +:1015400013D1C1220C4B92009A5892070AD58222DD +:1015500052009958002905D000219950074B0520C9 +:101560001B68984704BC9046F0BD00219950034B7E +:1015700004201B689847E4E700B00040DC0200202C +:1015800040B10040C123F0B5C64680249B00002531 +:10159000984600B5204E214F64024346F3581C4242 +:1015A00010D01F4AAB00944663441A68002A09D041 +:1015B000D2229200B450403AB4500022E8B21A60ED +:1015C0007B68984701356400042DE6D1C122124B97 +:1015D00092009A58D20704D58022520099580029C7 +:1015E00013D1C1220C4B92009A5892070AD582223D +:1015F00052009958002905D000219950074B052029 +:101600005B68984704BC9046F0BD00219950034B9D +:1016100004205B689847E4E700100140DC020020EA +:101620004011014003210A4802680A430260094848 +:1016300002680A4302600849084A094B9B1A03DD05 +:10164000043BC858D050FBDCFEF7B6FEFEF75CFD4D +:101650002405004054050040904500000000002093 +:1016600088000020FEE7FEE7FEE7FEE7FEE7FEE774 +:1016700008B5064B1868002803D1054902220A70F4 +:1016800002E001F049F9012008BDC046E402002053 +:101690002D030020014B1868407E7047E4020020B3 +:1016A00008B500F011FE002802D100F0F8FD01E0BD +:1016B000FFF7E6FD08BDF8B5051C0F1C161C072832 +:1016C00004D904221B4E0020327031E0032200298D +:1016D000F8D00622202EF5D800F04CFE0922022870 +:1016E000F0D8281C00F04AFE0A220228EAD800F0AE +:1016F00049FE08220128E5D900F0F4FD4378041CD6 +:101700000670012003436370391C321CA01C02F0D8 +:10171000B5FEE8B2211C00F0F9FD051C0120002DEA +:1017200006D1054802F0CAFA024F0F213970281C71 +:10173000F8BDC0462D030020DD000500F8B5061CED +:101740000D1C171C00F01AFE002803D1154F0B25A5 +:101750003D7025E00322002D07D0301C00F0FCFD79 +:101760003A6803789A4204D206220E4E0020327064 +:1017700016E0301C00F0E6FD041E0AD00278811C41 +:101780003A60281C02F07AFE201C00F0B5FD012012 +:1017900006E0054802F092FA02490F200870201C6A +:1017A000F8BDC0462D0300200501050008B5072837 +:1017B00004D9044B04221A70002001E000F0DAFD85 +:1017C00008BDC0462D03002008B5072805D9044BE5 +:1017D000042201201A70404201E000F0CFFD08BD54 +:1017E0002D03002008B500F0CDFD0623181A08BD12 +:1017F00010B5041E072C03D90B4B04241C7003E006 +:10180000FFF7D4FF022801DD00200CE0201CFFF7C9 +:10181000DBFF0228F8DCFFF7E5FF0623181A012199 +:1018200081429241504210BD2D03002008B50A4B61 +:1018300019684A7E002A04D0084A0C211170002041 +:1018400009E0072803D9054B04201870F7E7C0B258 +:1018500000F09CFD012008BDE40200202D030020C3 +:1018600008B5072804D9054B04221A70002003E0AC +:10187000C0B200F0A5FD012008BDC0462D03002028 +:1018800010B501280AD0002803D0022808D1002072 +:1018900000E0012001F028F8012005E00220F9E72E +:1018A000024B05221A70002010BDC0462D030020F7 +:1018B00010B500F011FD01280AD00224002808D03C +:1018C000A04201D1012404E0034802F0F7F900E04E +:1018D0000024201C10BDC0467001050038B5134A15 +:1018E000031C10680C1C407E002804D0104D022000 +:1018F0002870002018E001390F2903D90C4907226C +:101900000A7011E0002B03D1094C03232370F0E788 +:10191000084D191C10C5221C281C02F0AFFD281C04 +:10192000211C00F0BDFD012038BDC046E4020020AE +:101930002D030020640000200C4B10B51A680C68C1 +:10194000944201D3102C04D9094C072020700020A8 +:101950000AE0002803D1064903220A7004E00A6065 +:10196000191D02F08BFD012010BDC046640000204F +:101970002D030020014B18687047C046640000200A +:1019800008B5074B19684A7E002A04D0054B02208F +:101990001870002002E000F01DFD012008BDC046C7 +:1019A000E40200202D03002008B500F023FD08BD4F +:1019B00008B5074B19684A7E002A04D0054B02205F +:1019C0001870002002E000F01BFD012008BDC04699 +:1019D000E40200202D03002008B500F01FFD08BD23 +:1019E00008B50A4B1A68537E002B04D0084B02221C +:1019F0001A70002008E0072803D905480421017067 +:101A0000F7E700F011FD012008BDC046E402002008 +:101A10002D03002010B50C1C072804D90422064B06 +:101A200000201A7006E003220029F8D000F028FDFB +:101A30002070012010BDC0462D03002008B5074BC3 +:101A400019684A7E002A04D0054B02201870002035 +:101A500002E000F065FD012008BDC046E402002060 +:101A60002D03002008B500F061FD08BD08B50E4A41 +:101A7000031C1068407E002804D00C48022202702B +:101A800000200FE0012B0AD0002B07D0022B01D140 +:101A9000012004E0054B0E21197003E0022000F044 +:101AA000DDFD012008BDC046E40200202D0300201A +:101AB00008B501F023F80021012801D8014B195C79 +:101AC000081C08BD5045000008B5134B19684A7E34 +:101AD000002A04D0114A0221117000201BE00628C0 +:101AE0000FD802F06BFC12140406080A0C00FC204C +:101AF0000EE0F8200CE0F4200AE0F02008E0EC20F2 +:101B000006E0064B0E201870E7E7042000E00020F6 +:101B100000F046FD012008BDE40200202D03002056 +:101B200008B500F04BFDF02813D004D8042814D0D9 +:101B3000EC2806D10FE0F82807D0FC2803D0F428C1 +:101B400005D001200AE0022008E0032006E004207E +:101B500004E0052002E0062000E0002008BD08B5F2 +:101B6000064B19684A7E002A04D0054B02201870E3 +:101B7000002002E000F0E0FC012008BDE4020020AB +:101B80002D03002008B500F0DDFC08BD08B5074BAB +:101B900019684A7E002A04D0054B022018700020E4 +:101BA00002E000F097FC012008BDC046E4020020DE +:101BB0002D03002008B500F093FC08BD08B5074BC5 +:101BC00019684A7E002A04D0054B022018700020B4 +:101BD00002E000F0CBFC012008BDC046E40200207A +:101BE0002D03002008B500F0C9FC08BD08B5074B5F +:101BF00019684A7E002A04D0054B02201870002084 +:101C000002E000F0A5FC012008BDC046E40200206F +:101C10002D03002008B500F0A3FC08BD08B5074B54 +:101C200019684A7E002A04D0054B02201870002053 +:101C300002E000F0A9FC012008BDC046E40200203B +:101C40002D03002008B500F0A5FC08BD08B50B4B1E +:101C500019684A7E002A04D0094A02211170002026 +:101C60000AE0002805D0012803D0054B0E2018708B +:101C7000F5E700F05BFF012008BDC046E40200204C +:101C80002D03002008B500F057FF013843425841AA +:101C900008BD08B50A4B19684A7E002A04D0094AD3 +:101CA0000221117000200AE0002805D0012803D08D +:101CB000044B0E201870F5E700F050FF012008BD1E +:101CC000E40200202D030020F8B51E4D00241E4E16 +:101CD000071C281C211C0C22083034706C60FEF795 +:101CE0009FFA1A4800F048FE2860A04203D1012064 +:101CF0003070002024E0164B181D1968FFF7EEFD28 +:101D0000051C381CFFF7BCFD0540042000F0EEFB6D +:101D1000201CFFF79BFFEFB207400120FFF7D4FE26 +:101D200007400220FFF7A2FE0740201CFFF7B1FF8B +:101D3000041C01203C4000F0E7FE002CD7D001201D +:101D4000F8BDC046E40200202D030020C71D00009E +:101D50006400002008B500F007FF013843425841F5 +:101D600008BD024B0022DA607047C046E402002042 +:101D7000014BD8687047C046E4020020044B0022A3 +:101D800000B51A72904202D018610120187200BD8D +:101D9000E4020020014B18787047C0462D03002054 +:101DA000014B00221A7070472D030020014B586828 +:101DB0007047C046E4020020014B00225A60704781 +:101DC000E40200207047F0B589B0040C031C060A39 +:101DD00084460190101C039297B2020C0D1C002047 +:101DE00002910092E1B2624606AC069060600590F6 +:101DF000D0B21B0EF6B2052854D802F0DFFA031455 +:101E00002943403D6A4649B2484223701388E08026 +:101E1000281C6780A38000F06FFA301C0699626866 +:101E2000FFF780F941E022490B68587E002802D173 +:101E3000204801F043FF281C6D4600F05DFA6780E2 +:101E40002F88301CA78006996268FFF711FA2CE0F2 +:101E500048B205AC424223706280002B07D0002DAF +:101E600002D1154801F02AFF281C00F045FA301C69 +:101E70000599FFF701FA18E0FFF702FA15E0FFF7FE +:101E8000A1FF12E00A4DE9682B7A0131E960002BCD +:101E90000BD02F69002F02D1FFF702FC05E0013FB4 +:101EA0002F6102E0054801F009FF09B0F0BDC0460E +:101EB000E4020020B5030500C3030500E3030500A9 +:101EC000024B03490F221A70486070472D0300200F +:101ED000E402002000B5064A01231178022903D04C +:101EE0005068421E904100E0181C1840C0B200BD6E +:101EF0003003002008B5FFF7EDFF044B044A00282B +:101F000001D0D06800E09068186008BDFC02002095 +:101F10006803002008B5044B5A68002A01D0013A32 +:101F20005A60FFF7E7FF08BD3003002010B500231B +:101F30001A1C041C1C41012121400724E41AA14061 +:101F40000A430133D2B2082BF3D1101C10BD70B577 +:101F50000024061C251C301CE040C0B2FFF7E6FF41 +:101F60001823191B884008340543202CF3D1281C62 +:101F700070BD38B50D1C01F071FE084C63699D42BF +:101F800002D8074801F09AFE60690122291A054823 +:101F900002F058F90021616138BDC04630030020CD +:101FA0004D0609009D3C000007B5A12303210F4AFF +:101FB0008B40D15001F094FD002815D002280AD999 +:101FC000032811D1002300930193181C191C1A1C1B +:101FD00001F09EFC03E00020011C01F035FD042807 +:101FE00002D0034801F06AFE07BDC04600F0014080 +:101FF000E801090008B501F027FFA1230E4AD90026 +:10200000505001F06DFD012807D001F069FD022854 +:1020100002D00A4801F052FE002001F0B9FA02F0A5 +:1020200093F9074BA221CA0098500648064AC16896 +:102030004868985008BDC046001000401E060900C0 +:1020400000F00140FC0200201405000008B502F079 +:10205000EDF801280FD002F0CDF8074B187F0028CB +:1020600003D180210122CB055A60002001F0F6FD4A +:10207000024A0020506008BD6803002030030020A1 +:1020800010B501F06AFD00281AD00E4B00229A818B +:10209000DA8101F0C5FB0C4C0C49605001F0C0FB2B +:1020A000A62201238340D100635001F0BFFB084CFE +:1020B000206001F0C1FB074B6060E360FFF79AFF0F +:1020C00010BDC04630030020001000402C05000069 +:1020D0004C0300207D21000008B502F0A7F801287C +:1020E00022D101F0D5FD002802D0104801F0E6FD14 +:1020F0001E210F48002202F0A5F80E4B197F00297F +:1021000002D002F06BF80FE00B480C4B012202608A +:1021100059608021C8050260C046C046C046C0461E +:102120005A68002AFCD0ECE708BDC0462C0609001E +:102130009D3C00006803002014050040FC000040A6 +:102140001FB5FFF783FF01F0D9F80A4A002301A861 +:102150000521017043601C1C03814381437083701F +:10216000C3709370537601F09DFA03480470FFF733 +:102170001BFF1FBD3003002064030020F0B53E4B61 +:102180008022D000195887B0012904D03B4C00268A +:102190001D59B54206D13A4E2022776800263B7879 +:1021A0009A427641374C012561692E40281C00294E +:1021B00001D102F041F8284201D10120606101F013 +:1021C0008FFC012802D0304801F078FD2F4DEF68D8 +:1021D0003B7D002B02D02E4801F070FD01F08EF8FF +:1021E000002E47D00120011C01F02EFC042836D817 +:1021F00002F0E4F803321832320001F017FBE289F2 +:10220000071CA689019201F00BFBE9686D46897DE8 +:102210000497AF8803AB00221A701E815F8158704B +:10222000997014E001F002FB071CE089A689019077 +:1022300001F0F6FAEB686D469A7D0497AF8803AB20 +:1022400000219A7019701E815F8158700122DA7026 +:10225000181C01F027FA02E00E4801F02FFD01F0F2 +:1022600019FE0D4E206170696060FFF743FE00208B +:1022700001F016FE07B0F0BD00100040340500006C +:102280004C03002030030020A8060900FC020020B7 +:10229000A9060900C806090068030020704708B5B0 +:1022A000012282F31088074B597E002905D09878C7 +:1022B000002802D19A70FFF70FFF002282F31088E6 +:1022C00008BDC04630030020024B0120597E484023 +:1022D0007047C04630030020014B18787047C04655 +:1022E0003003002008B5012383F3108801F094FC2B +:1022F000002181F3108808BD08B5012383F31088FD +:1023000001F08EFC002080F3108808BD08B5012381 +:1023100083F3108801F0EAFB00280DD0084882788A +:10232000002A04D1417E002901D0FFF7D5FE002309 +:1023300083F31088012001E080F3108808BDC046B7 +:102340003003002008B5012383F3108801F0F6FB69 +:10235000002181F3108808BD08B501F0EAFB08BD33 +:1023600008B5012383F3108801F0D3FB002181F32A +:10237000108808BD08B501F0D8FB08BD08B501F00C +:10238000E7FB08BD08B501F04FFC08BD10B50123FF +:10239000041C83F3108808480278002A05D0417E87 +:1023A000002902D0054801F089FC201C01F0B5FB92 +:1023B000002484F3108810BD30030020FB020900C4 +:1023C00008B5012383F3108801F0BDFB002080F3E2 +:1023D000108808BD08B5044B1862FFF7B8FD034923 +:1023E000034A505008BDC046680300201C05000089 +:1023F00000100040014B186A7047C0466803002077 +:1024000008B5044B5862FFF7A2FDA421024ACB0095 +:10241000D05008BD6803002000100040014B586AEE +:102420007047C04668030020F8B5031C081C072B42 +:102430001AD80F4A03261E40D118F600FF24B440D4 +:102440002831E74308700B4C032B01D80A4D01E0FB +:10245000A525ED0063591F406751FFF767FD6759D8 +:10246000B0400743675102E0044801F027FCF8BD83 +:102470006803002000100040240500003903090013 +:1024800010B5041E072C02D9034801F017FC034BBA +:1024900018192830007810BD410309006803002096 +:1024A00038B5051C0C1E02D1074801F007FC002DB1 +:1024B00002D1064801F002FC054B00209D605C60E3 +:1024C00001F0D6FC38BDC0464803090049030900A5 +:1024D000FC020020014B58617047C0466803002091 +:1024E000014B58697047C04668030020064B074AF5 +:1024F000A32110B55877CB00D458010404482040DC +:102500000843D05010BDC0466803002000100040B2 +:10251000FFFFF8FF014B587F7047C046680300205B +:10252000014B18617047C04668030020014B1869D1 +:102530007047C04668030020014B58607047C04692 +:1025400068030020014B58687047C04668030020AC +:1025500008B5024BD860FFF7CDFC08BD680300202A +:10256000014BD8687047C0466803002008B5024B8D +:102570009860FFF7BFFC08BD68030020014B986816 +:102580007047C04668030020014B58837047C0461F +:1025900068030020014B588B7047C0466803002039 +:1025A000034B0449044A3033187050507047C046FA +:1025B000680300200C05000000100040014B303380 +:1025C0001878704768030020184B10B53133187025 +:1025D000174A184BFF249958A1439950032821D832 +:1025E000995801F0EBFE1D020A1401242143995071 +:1025F0001149FF205850114906E00220014399502B +:102600000F490D4A99500F49A722D20008E0032430 +:10261000214399500C480849A7225850A240002154 +:10262000995002E0094801F049FB10BD6803002001 +:1026300034050000001000403C05000007010000C8 +:10264000FFFF000021100100FFFFFF00C20309008F +:10265000014B313318787047680300201F4B00B5D9 +:1026600032331870012821D0002810D0022834D12C +:10267000A2211B4ACB00D0501A491B481B4A0860B4 +:102680001B4B1C481C491A6008601C4A20E0A2230E +:10269000134AD9005050134B1348154A1860134978 +:1026A0001748154B11601860164A11E0A2230C4A16 +:1026B000D90050500B4B0C480C490D4A1860116062 +:1026C0001148124A0C4B124918601160114A02E07D +:1026D0000E490A60104A1148026000BD68030020DC +:1026E0000010004024170040005000784E000054B5 +:1026F0002817004008800C602C1700408864720086 +:1027000003800C602264720002800C60301700406D +:1027100011646600DEC08F823E420F823417004093 +:10272000F8B5A122334C344B344E354DD000002740 +:1027300003210122F750315067516251E05831496D +:102740000F220140E150E558062095430543E5502E +:10275000E1582D4DC02290020D400543E550A323C2 +:10276000DD006159294A80230A40625160595904A9 +:10277000014361516059FF22904320231843605167 +:1027800061592348C0220840605122485300022169 +:10279000C15001F0D5FD2049204A70507251204DA2 +:1027A000032373511F4800F0E1FD1F4E1F4DF060E1 +:1027B000687FFFF79BFE286AFFF70CFE686AFFF749 +:1027C0001FFEE81928300178381C0137FFF72CFE6E +:1027D000082FF6D12F1C30373978154AA1502C1C00 +:1027E000313420783235FFF7EFFE2878FFF736FFD7 +:1027F000F8BDC046001000401405000000F0014084 +:10280000FC0F0000FFFEFFFFFFFFF0FFFFFFFFFDDB +:10281000FF00FFFF00E100E01C0500000411004084 +:10282000040500004C030020FC0200206803002087 +:102830000C05000070B5274E86B0337872789A4246 +:1028400045D0002B01D1FFF76BFF7078002801D134 +:10285000FFF7AAFB2049214D00246C5000F04EFDEB +:102860001F4D2C606C602C61AC60EC603378012BE8 +:1028700008D101F035F9A04217D0201C211C01F02D +:10288000E3F812E0022B10D100F038FD154A2C615C +:10289000147001F025F9032807D100940194201C3D +:1028A000211C221C231C01F033F8FFF723FB707856 +:1028B0000024307003A8042606704460048144811B +:1028C00044708470C47000F0EDFE012000E0002030 +:1028D00006B070BD300300201405000000F0014078 +:1028E0004C0300206403002008B5012383F3108803 +:1028F00008490A78824208D04870487E002802D1F0 +:10290000FFF798FF01E0FFF7E7FB002383F3108850 +:1029100008BDC0463003002038B5124B5A7E1C1C3F +:10292000002A1DD1FFF7FCFE0F488168051C002915 +:1029300002D10E4801F0C2F96B68002B02D10C489D +:1029400001F0BCF901F098F9002802D0094801F023 +:10295000B5F9002001F082F901226276FFF7BCFB95 +:1029600038BDC04630030020FC0200205E02090092 +:102970005F02090066020900F8B5071C012080F318 +:102980001088544D544B554E0024002203211C60E6 +:102990005C609C60DC601C611A7529702A766A761E +:1029A000B46074606870AC706C60AC60AC81EC81D9 +:1029B0002C616C6101F0D6FB381C00F059FE00F070 +:1029C000F5FE201C01F042F9301C01F07BF9444F68 +:1029D000C2208300F958434AC0260A40FA50B0008A +:1029E0003B584149C522194039509600BB59FF2038 +:1029F000402183430B43BB510120FFF775FF3B4E42 +:102A00003B4B3C48311C3362706228310123301C3F +:102A10000B7029300223311C03702A310320087007 +:102A2000FF22311C32612B3104220A707277321C72 +:102A30002C3205201070321C2D320621301C1170F2 +:102A40002E3007220270301C2F300821321C0170FA +:102A5000303200201070321C0120311C32321070D4 +:102A6000313196229A400B701E2171617260F360C1 +:102A7000FFF740FA0F23B360FFF73CFA012074839D +:102A8000307670760021201C6924317701F0D0F86F +:102A900034606E780124A64202D0174801F00EF986 +:102AA00000262C70AE706E60AE60AE81EE812E613D +:102AB0006E612E766E76FFF733FEC0238021802272 +:102AC0005800CC0053033C503B5086F31088281C20 +:102AD000F8BDC046300300204C030020FC0200205B +:102AE00000E100E0FFFF00FFFF00FFFF68030020A0 +:102AF00004070A0D05080B0E3C020900014B323396 +:102B00001878704768030020054B10B5041CD8687E +:102B1000002802D1034801F0D1F803490C7510BD1B +:102B2000FC020020F60309004C030020014B18763C +:102B30007047C04668030020014B187E7047C046AE +:102B400068030020014B58767047C0466803002098 +:102B5000014B587E7047C04668030020014B187730 +:102B60007047C04668030020014B187F7047C0467D +:102B70006803002008B501F05BF808BD08B50B4BF1 +:102B8000D868417D002906D0012000F05BFB084B8E +:102B90009A8901329A810749074B084A0020585008 +:102BA00051681368C91AFFF7E4F908BDFC02002058 +:102BB000300300201405000000F0014068030020ED +:102BC000084B10B51A781C1C012A02D0064801F0E7 +:102BD00075F80649064A0220002320700B61CA607E +:102BE00010BDC04664030020920509004C0300207C +:102BF000912C000010B500F081FB194819491A4CBE +:102C000000230122027023610869A623174AD90014 +:102C1000505000F065FF00280AD100F075FD012832 +:102C20000DD900F00FFE6060002808D1104804E0C4 +:102C300000F056FF032802D00E4801F03FF80220B2 +:102C400000F0A6FC002000F0FDFA00F049FF032888 +:102C500002D0094801F032F8FFF7B2FF10BDC046BC +:102C600064030020680300204C0300200010004093 +:102C70007B050900800509008805090008B5034B9C +:102C800005221A70FFF7B6FF08BDC0466403002096 +:102C9000F0B5484A8023D800115887B0464C012926 +:102CA00004D0464D002356599E4205D16768002343 +:102CB0003978202088425B41414E032500210127BD +:102CC000357021603B408B4255D08123D800155888 +:102CD0003C4B11583C48D15002A912583B1C009162 +:102CE0000194381C291C00F013FE032841D801F080 +:102CF00065FB1E02204E0298002802D0334800F0E7 +:102D0000DDFF281C00F024FF002802D1304800F02D +:102D1000D5FF304903A8CF680223B97D002703708F +:102D200047603A1C07814781457081701DE02A4841 +:102D30002BE0029A002A02D1284800F0BFFF281C8D +:102D400000F006FF002802D1254800F0B7FF214F10 +:102D500003A8FB68029F997D02220023027047604E +:102D600003814381457081700122C27000F09AFC9A +:102D70000DE01C4809E000930193181C191C1A1C53 +:102D800000F0C6FD042802D0174800F097FF256820 +:102D9000002D06D100F0B2FA65752561FFF72AFF14 +:102DA00005E012480122627520610424347007B0E6 +:102DB000F0BDC046001000404C0300203405000068 +:102DC000640300202C0500000C040000B805090075 +:102DD000B9050900FC020020BD050900C005090075 +:102DE000C1050900C8050900CF0509007D2C0000B8 +:102DF00070B50C4DA124E4002E5901F025F886424F +:102E00000AD001F021F82851FFF7F4FE064900200E +:102E10004968FFF7AEF870BD044B18780028F3D06E +:102E2000F4E7C0460010004068030020640300205F +:102E3000F0B5864C0125636989B0281C002B01D1AF +:102E400001F0FAF90126284000D0D3E02178B14200 +:102E500002D100F04BFA10E0022908D000F042FF46 +:102E6000FFF758F8A678002E00D0A9E00EE0784AC7 +:102E70001378033BDDB2AE4240410028EED0754EE0 +:102E800075487768012279086161CBE0FFF7D2FCD1 +:102E9000704D071E00D08EE020780190061E012E96 +:102EA00006D0002863D0022865D1FFF7A1FF65E0B6 +:102EB00000F024FA00F014FE00281DD100F024FCDC +:102EC000012851D9FFF706F8071E0CD000F0FAFFD1 +:102ED000002849D1287E00280BD100F0DBFF2669AD +:102EE000B04241D105E0206900F0C2FF381C00F07B +:102EF000D7FFFFF7C5F837E0698B002920D0A289FA +:102F00008A421DD3311C381C00F09EFD00F08EFC5F +:102F10000290A2890392E68900F082FC69460A7950 +:102F2000029905AB1A7006910C226946515A5870E5 +:102F3000181C19815E819F70DF7000F0B3FB13E0F5 +:102F400001F07AF9002802D0444800F0B7FEA1232E +:102F50004348DF00C65900F077FF864202D0E1897E +:102F60000131E181FFF746F80120296800E0696836 +:102F7000FEF7FFFF02E03B4800F0A0FE6D7E012D52 +:102F800023D1FEF7A7FF00281FD12478012C07D0FA +:102F9000002C0DD0022C18D0334800F08FFE14E026 +:102FA00000F09EFD002810D100F034FC00280CD168 +:102FB000FFF74CF809E06968301CFEF7DAFF04E01F +:102FC000647E002C01D0FFF7BBF800F09DFB0128C8 +:102FD0000CD905A8002103230370416001814181C0 +:102FE00041708170C17000F05DFB2DE01F4800F062 +:102FF00065FE29E0FEF78EFFA778002F1DD121780E +:10300000022912D1124B1D78033D012D04D900F085 +:1030100069FEFFF7EDFE17E00E4F321C786841089D +:103020000D48616101F00EF90EE000F05BFE094A07 +:10303000381C5168FEF79DFF06E000F053FE607EED +:10304000002801D0FFF77CF809B0F0BD3003002064 +:1030500064030020680300209D3C00000A0509006D +:103060000010004058040900720409008C04090093 +:1030700007B50190C046C046C046C046C046C046DF +:10308000C046C046C046C046C046C046C046C04610 +:10309000019B013B0193002BECD107BD70B5802251 +:1030A000164B910000245C501549C2250E78AD00E6 +:1030B000144A032E07D109267442C1265C51082503 +:1030C000B4001D510AE0012676425E51C0230E4D28 +:1030D00002265B00EE50146103244C700023536001 +:1030E000536193604B600B75984205D007480168A7 +:1030F0000A69002A00D0904770BDC0460010004009 +:103100009C030020FC10004000E100E00C030020C4 +:10311000F8B53F4B1A69012A53D19D693D4C802275 +:1031200096000135032104209D611870C025A1512E +:1031300039496A0002278F50384F00263E61C1226C +:103140007E607E61BE60364E082591006550356810 +:103150002A7D3D1C002A17D0A927F9006258314F5B +:103160009A75A023D9007A58024202D12E4800F065 +:10317000A5FD00200123A12228620421A361D30020 +:10318000F950A927F90060506868002802D0274844 +:1031900000F094FD2D69002D02D0254800F08EFD31 +:1031A000244A536899072DD43768F968002900D05C +:1031B00088473668707D002828D035681E4AA5509B +:1031C00024E0022A1AD1154900250D6111484D61EC +:1031D00080244D6001278D60C221A6007A428C00B8 +:1031E00085511D700251032058705D601D750C4B98 +:1031F0001E683769AF4209D0B84707E00F4800F0B2 +:103200005DFD03E00E4800F059FDCDE7F8BDC04676 +:103210009C0300200010004000E100E0FC10004092 +:103220000C03002000F00140AD020A00B6020A00C3 +:10323000B7020A00FCE100E004050000E7020A0012 +:10324000B8020A0070B51E4D061C6B7D6C78002B11 +:1032500002D11C4800F032FD287D002802D01A4817 +:1032600000F02CFD012200212A756975022C0CD872 +:1032700016482301C318002E01D11E683260621E59 +:10328000012A05D8997A297002E0114800F016FD4C +:10329000104D2868037D002B11D0022C0FD10E4C4D +:1032A0000E4E251C3259530702D40D4800F006FD7E +:1032B0000C494859002802D10B4800F0FFFC70BDB2 +:1032C0009C03002021010A0022010A00544500004D +:1032D0003A010A000C0300200405000000F0014040 +:1032E00040010A000010004041010A00024B9868AA +:1032F0000138434258417047FC100040F8B5164B66 +:10330000164C02200121C027C222D8674D428240BC +:103310007B00134E8021134FA55081400025F050B3 +:10332000012265507D61104D2261A2612C7894428A +:1033300001D1062003E0023C012C00D9101C00241E +:10334000FFF796FE7C61201C2C70FFF7A7FE022081 +:103350006C753060F8BDC04604E100E0001000402C +:1033600000E100E0FC1000409C03002038B50E4B4B +:103370000E4C18600E490F4B0F4A0225201DC567E1 +:1033800099500E48A421CA009850FFF7B7FF0C4887 +:10339000002303210370417043600361037543758B +:1033A0008375256038BDC0460C03002000E100E0B5 +:1033B0001410004000F001402405000004110040FA +:1033C0009C03002070B55C4C2369607D01336578F7 +:1033D0002361002802D0594800F070FC21780329AD +:1033E00048D1574E3269002A44D0012D35D1226987 +:1033F000032A02D0534800F061FCA0690221013089 +:10340000514A8025A06100238D4001202170535135 +:103410004542C22088401550C02568004B4D2950B8 +:103420004B493361096873607361B360032666704A +:1034300063602375087D98420DD0A925E8001658D1 +:103440000125A6753E4C042623629561A124414DB9 +:10345000E4002E511350CA6865E0022D08D123699B +:10346000012B02D03C4800F029FCFFF751FE61E03F +:103470003A485DE0032D5AD0012D3CD12169012944 +:1034800018D12F480021304B0126C22241608160B3 +:1034900070429100C1265850B0001D502C4D304E46 +:1034A0002A68117D002902D02A4D0420A851E46821 +:1034B0009C513FE002293DD1234E214A8023002523 +:1034C00098000221C22315615561556035504A426A +:1034D0009800C12132508B000822F250032626703A +:1034E000656025751A4C2568261C2869002800D0BF +:1034F0008047306816E0022DB7D0657819482B0157 +:10350000C1180E7B0025AE4203D00D4A15696A1E14 +:1035100095418B7A01202370FFF7C0FD002D09D063 +:103520000B4C20688268002A04D0904702E00E48C5 +:1035300000F0C4FB70BDC0469C03002090010A004F +:10354000FC1000409F010A000010004000E100E074 +:103550000C03002000F00140A4010A00A9010A00A8 +:103560000405000054450000D6010A0008B50228F1 +:1035700004D8054B18784342584103E0034800F053 +:103580009DFB002008BDC0469C030020F9020A00F4 +:10359000F8B52B4C0301061C2A4F207DFF1800288C +:1035A00002D0294800F08AFB301CFFF7DFFF00281B +:1035B00002D1264800F082FB0121C222244D0023C3 +:1035C000484291006375C02268502249022052008F +:1035D0008850214866700268116852682361A361AF +:1035E0003B68A160E2606360022E18D8387A8023BD +:1035F0009B00E850F87A194B002805D1E950EA58A9 +:10360000002A08D1164804E0EA50E958002902D1FE +:10361000144800F053FB7F7AC1208300EF500E4D19 +:1036200029680A7D002A07D0022E05D10B480E4BCF +:1036300000260427A6751F5001256575F8BDC046F4 +:103640009C03002054450000DB000A00DD000A0056 +:103650000010004000E100E00C0300200405000021 +:1036600000010A0005010A0000F001407047C04651 +:1036700010B5041E02D1084800F020FB074B0022C1 +:103680001C60191DDA670833CA678020DA67044BAB +:1036900044031C6010BDC04629000B00C00300207D +:1036A00000E100E070B5144C051C2368002B02D12A +:1036B000124800F003FB201C0830C16F092902D911 +:1036C0000F4800F0FBFAE66F0C225643A3190433AF +:1036D00043CD43C3251C0835E86F0130E867E16F2F +:1036E0000131E167E66F092E01D90022E2678024EB +:1036F000044B65035D6070BDC003002034000B0007 +:1037000035000B00FCE100E0034B0A200833D96FC1 +:10371000421AD0B27047C046C0030020F0B587B04F +:10372000012383F31088134C124D0834E06F0028F6 +:103730001BD02A1DD16F0C26714303AB69180431CD +:10374000181CE0C9E0C0E76F0026013FE767D46FAF +:103750000134D467D56F092D00D9D66786F3108858 +:10376000044A176807CBB847DAE780F3108807B038 +:10377000F0BDC046C003002038B50A4C051CE36FFD +:10378000002B02D1084800F099FA291C0831E06F9B +:1037900000F03CFC0021884201D0E1670121081CB7 +:1037A00038BDC046480400206F020C0010B500F080 +:1037B000B7FB0021124A8800002384188818A361EF +:1037C000A363041C80348830237003700D480C18E8 +:1037D000013123700829EDD1111C101C141C9031EB +:1037E00091305834137053609360D3601361536108 +:1037F0000B7003702370D36792320123137010BDD6 +:1038000048040020DC040020014B185C7047C046CF +:10381000DC040020014B90331878704748040020E6 +:10382000014B58687047C04648040020014B986817 +:103830007047C04648040020014BD8687047C04616 +:103840004804002010B5104C2378002B02D00F48FC +:1038500000F034FAE06F002802D100F08BFBE06743 +:10386000E06F00280FD0012143784A4206210B4324 +:10387000437002700023C218FF2101339170202B86 +:10388000F9D10323237010BD480400203B010C0034 +:1038900038B5124C2378002B1ED1201C90300178B3 +:1038A000002919D10825606900F028FC002805D0FE +:1038B000231C6069903301221A7020616169013113 +:1038C000082900D10021231C616190331A78002A55 +:1038D00002D1013D002DE6D138BDC046480400208C +:1038E00038B5094D041C2B1C90331878002804D0DF +:1038F0002969A14201D1FFF7CBFF2A19034B00250B +:10390000803215701D5538BD48040020DC040020AD +:10391000F0B5464D85B00393EB6F061C0C1C171CCD +:10392000002B02D1424800F0C9F92878032802D0C0 +:10393000404800F0C3F9E96F01234A781A4202D1E6 +:1039400092352D786B400425002E61D0500701265A +:10395000810F1E40251C231C0A0608330E353F022A +:103960003249A8003F0A02930B5817430B980A9A52 +:103970000025156005609F4233D0201CFFF7FCFE38 +:103980000190AE4200D0051C01232E1C1E400028D1 +:1039900028D00299254A063188008750039F1D1CB4 +:1039A000002F20D0244F3B5D002B1CD0201C00F0AA +:1039B000A5FB002802D1214800F080F9201C00F06E +:1039C0005BFB051E02D0201CFFF78AFF0A990D60E1 +:1039D000002D02D11A4800F071F900203855022557 +:1039E00001E001950325002E0DD0201C00F06CFB9A +:1039F0000B9E3060002802D1124B336005E00E4F61 +:103A000001223A5501E00B9C26600199002905D15D +:103A1000064CE06F00F0CCFA0020E067034A002675 +:103A20001670FFF735FF281C05B0F0BD48040020D4 +:103A30005B010C005C010C00DC04002091010C0017 +:103A400096010C00A0040020F8B51F4C071C237839 +:103A50000E1C013B012B02D91C4800F02FF9042554 +:103A6000002F19D02078012802D0194800F026F93B +:103A7000E268002A02D1174800F020F9E168002529 +:103A80000F78AF4208D06068FFF776FE0225002865 +:103A900002D1114800F012F9002E0ED06768381CD0 +:103AA00000F0EAFA061E02D0381CFFF719FFA368DF +:103AB0009E4202D0094800F001F900202070FFF773 +:103AC000E7FE281CF8BDC04648040020FC000C009E +:103AD00002010C0003010C000E010C001E010C0081 +:103AE000014B18787047C0464804002038B5041CC4 +:103AF0000D1C00F013FB002801D1002008E0281C59 +:103B0000211C00F083FA0028F7D0FFF7C1FE012046 +:103B100038BD08B500F0D8FA08BD10B5041CFFF791 +:103B2000DFFE201C00F000FB10BD08B500F0E6FA37 +:103B300008BD08B5083000F0C7FA08BD08B5083060 +:103B400000F09AFA08BD08B5083000F0EDFA08BD9B +:103B500008B5083000F0D2FA08BD10B52A4C237819 +:103B6000002B02D0294800F0A9F8201C90300178E1 +:103B7000002927D02069606000F0A6FAA060002824 +:103B800002D1234800F09AF8A2680123507803403C +:103B900004D1211C92310A78002A10D16068FFF705 +:103BA000D7FF02280ED8E36F002B02D100F0E2F914 +:103BB000E067E16FE160002904D0012001E0E360EB +:103BC000022020702278002082421BD0A36883420A +:103BD00002D1104800F072F8206960600630810060 +:103BE0006318DA7803210132D0B2D870A368084094 +:103BF0005A784100062082430A435A7090340023C9 +:103C00002370012010BDC04648040020C3000C00F2 +:103C1000C9000C00E7000C0008B500F0ABF908BDC6 +:103C200008B500F0C5F908BD08B500F077FA08BD81 +:103C3000014B92331870704748040020014B9233B7 +:103C400018787047480400207047C046024B9870AF +:103C5000587018707047C046E404002010B5041E68 +:103C6000012C02D9024800F029F8024B5C7010BD0B +:103C70002A000D00E4040020014B18787047C0466C +:103C8000E4040020014B98787047C046E40400200B +:103C9000014B58787047C046E404002008B5054B36 +:103CA0001A7858789A701870034B8100CA58904758 +:103CB00008BDC046E40400207800002008B5FEF7E7 +:103CC000FFF808BD10B5041E02D10448FFF7F6FF47 +:103CD000034B00221C605A609A6010BD2A0001004C +:103CE00010030020094B00B518689A68016801327A +:103CF0009A608A4208D359684068002201319A606C +:103D00005960814200D35A6000BDC04610030020B4 +:103D1000F8B500282AD0164CA36801280ED12768D0 +:103D200001333A68A360934220D360687968002524 +:103D30000130A5606060884218D316E02668C71875 +:103D40003568A760381C291C00F042FB62683B1CE8 +:103D500080186060AB4201D35B1BFBE7716865684C +:103D6000A3608D4201D36D1AFBE76560F8BDC046C4 +:103D700010030020024B1A6899681068401A7047B7 +:103D80001003002070B50D4D041C2B685868844248 +:103D900002D30B48FFF792FF6E68B4420CD002D8F2 +:103DA00029684A68A418FFF7E5FF2D68F3432E68D9 +:103DB00019197143081800E0002070BD100300209D +:103DC0006800010070B5041C0D1C884202D30B482A +:103DD000FFF774FF0A4E33681868854202D9094814 +:103DE000FFF76CFFB168601AA14206D30020A94218 +:103DF00003D3326815686E1A301970BD7D0001005A +:103E0000100300207E00010038B5041C101C0D1C9E +:103E1000FFF7B8FF002801D0001911E0201C291C71 +:103E2000FFF7D0FF041CFFF7A5FF031C201E9842DC +:103E300006D304490D686A682C68013A5443001996 +:103E400038BDC04610030020074B10B51A685968EA +:103E500050681C1C814202D30448FFF72FFF2368DF +:103E600061689A68505C10BD10030020B200010028 +:103E700038B5064B041C1A681D1C5068844202D3D6 +:103E80000348FFF71BFF6C6038BDC04610030020DD +:103E9000B9000100014B58687047C046100300206C +:103EA00038B5064B041C1A681D1C1068844202D3E6 +:103EB0000348FFF703FFAC6038BDC0461003002085 +:103EC000C5000100014B98687047C04610030020F0 +:103ED00010B50F4B1A68002393420BD20D499C007A +:103EE0006458A04203D10C48FFF7E8FE0CE0013310 +:103EF000DBB2F1E7002422226243084953189842BA +:103F000004D00134062CF6D1002000E0012010BDC1 +:103F1000E8040020EC040020F6000300F405002073 +:103F200010B500220F495000801800230C180132F0 +:103F30006370A3704354102AF4D122225A430A49D1 +:103F40000A485418211C9A0084502231DE22227023 +:103F500001348C42FAD10133062BEED1044C23609C +:103F600010BDC04604050020F4050020EC0400202C +:103F7000E804002038B50A4B1C68002C0ED0621EE5 +:103F8000084990004458084D1A604550201CFFF71E +:103F90009FFF002802D10548FFF790FE201C38BD86 +:103FA000E8040020EC040020ADDEADDE7D0003005F +:103FB00070B5104C051C2368052B02D90E48FFF77D +:103FC0007DFE281CFFF784FF002802D10B48FFF775 +:103FD00075FE21680A488A0011580A4B061C99424E +:103FE00002D00948FFF76AFE206882000130B55010 +:103FF000206070BDE80400208500030086000300F7 +:10400000EC040020ADDEADDE88000300F8B5051C31 +:104010000C1E0F2C02D91448FFF750FE281CFFF786 +:1040200057FF002802D11148FFF748FE10496600EB +:104030003019435C0022022B13D80B185F78C0198B +:104040000C4F8000C5515D780135E8B258705F783B +:10405000022F00D95A7032198C5C0134E6B28E54AA +:104060000122101CF8BDC0468F0003009000030021 +:10407000040500203405002038B5041E0F2C02D999 +:104080000E48FFF71BFE0E4A65002919885C0028C0 +:1040900013D05318987809180A4889000858997855 +:1040A0000131C9B299709978022901D9002199701A +:1040B0002C19155D013DEBB2135538BDA600030068 +:1040C000040500203405002010B5041E0F2C02D971 +:1040D0000748FFF7F3FD074B62001119C85C002881 +:1040E00005D0581884780B1903499A00505810BD10 +:1040F000B7000300040500203405002010B5041E9D +:104100000F2C02D90348FFF7D9FD630002491819A3 +:10411000405C10BDC800030004050020014B186876 +:104120007047C046E804002038B5051E0F2D0CD995 +:104130000948FFF7C3FD08E0084B9C4202D108483C +:10414000FFF7BCFD201CFFF733FF281CFFF794FF8F +:10415000041EF1D138BDC046D7000300ADDEADDE90 +:10416000DB000300164BA12110B50122CC0000207A +:104170005A60DA6018515A64124A1C1C99588142DC +:1041800002D01148FFF79AFD0123C2225842910044 +:104190000E4B60500022A2215A640420CB00E05054 +:1041A0000B490C4C012022602271627108700A4B8D +:1041B0008022C021D40081405C501C6010BDC046EC +:1041C00000A000404405000035000400FCA00040B1 +:1041D000C00600201C03002000E100E0034B04495E +:1041E000012200201A6008707047C04600A00040FD +:1041F000C0060020094A30B501235360084CD36043 +:104200008025084AC0200021ED00984011601171FE +:1042100025505171044A137030BDC04600A00040C3 +:1042200000E100E01C030020C0060020014B1878CC +:104230007047C046C0060020014B18797047C04641 +:104240001C030020F7B5334F0092334C8022C22369 +:104250007E790191051C990050026050002E02D019 +:104260002E48FFF72BFD002D02D12D48FFF726FD2C +:104270003A68002A02D02B48FFF720FD3D60009DE0 +:10428000294E012D0DD0002D03D0022D0DD1A922D4 +:1042900008E00120254B00996064E55820647164B2 +:1042A00007E0A822D500655903E02148FFF706FD85 +:1042B000002501227A71019FA821E81987B2002305 +:1042C000C80073642750275800976264174AA7589C +:1042D000716C1E1C994202D01648FFF7EFFC009B40 +:1042E000AB4205D3AF4201D39F420CD3124808E042 +:1042F000301CAF427041009DAF427641B04202D0C7 +:104300000E48FFF7DBFC8022C12157028E00A75127 +:10431000F7BDC0461C03002000A00040730004004D +:104320007500040076000400FCA000404405000075 +:10433000890004009B000400B0000400C9000400D0 +:104340000048704748A000400048704740A1004026 +:1043500070B58022134C144DC223500299000026E0 +:1043600068506664114C2268B24202D11048FFF7CF +:10437000A5FC104B012166712068A82226606964A3 +:10438000EE58D300EA580C4D1432AE4203D8C02385 +:104390001D02AA4202D8002196424941217180475C +:1043A00070BDC046FCA0004000A000401C030020DF +:1043B000EC00040044050000FF3F000002B4714619 +:1043C00049084900095C49008E4402BC7047C04658 +:1043D000002934D00123002210B488422CD30124B8 +:1043E0002407A14204D2814202D209011B01F8E74D +:1043F000E400A14204D2814202D249005B00F8E706 +:10440000884201D3401A1A434C08A04202D3001B31 +:104410005C0822438C08A04202D3001B9C08224364 +:10442000CC08A04202D3001BDC082243002803D0A2 +:104430001B0901D00909E3E7101C10BC704701B546 +:10444000002000F00BF802BD0029F8D003B5FFF7FB +:10445000C1FF0EBC4243891A1847C0467047C04688 +:1044600030B500240139A24201D1002005E0035DEE +:1044700001340D5DAB42F6D0581B30BD002310B5A2 +:104480009A4200D110BDCC5CC4540133F8E700005F +:10449000F8B5C046F8BC08BC9E467047F8B5C046A3 +:1044A000F8BC08BC9E46704700000020656E637231 +:1044B000797074696F6E206B65790000656E637248 +:1044C000797074696F6E206E6F6E63650000000016 +:1044D0004D4143206B65790004450000E444000031 +:1044E000F4440000A909B09D364DC240EB37CB1310 +:1044F000F3B3E641FFE55DCC7BCE111FB3B6E87E9A +:10450000A381E049993FFC88BF214490F02B532EB2 +:1045100002FF7EC5D4EC881E320E9786F2DB75FA58 +:1045200073DA8A10993FFC88BF214490F02B532EF8 +:1045300002FF7EC5001001401101040000B00040E0 +:104540000B000400FF0F030000001F000302000027 +:104550000102000000100040101100400310000094 +:104560000100000000100040000000000B020400E9 +:1045700000000000041000400000000007080301D4 +:08458000000000000000000033 +:0845880080BBFF7F0100000071 +:10459000000000000000000000000000000000001B +:1045A000000000000000000000000000000000000B +:1045B00000000000000000000000000000000000FB +:1045C00000000000000000000000000000000000EB +:1045D00000000000000000000000000000000000DB +:1045E00000000000000000000000000000000000CB +:1045F000240300200500000004192A3F4D0000009C +:104600000000000000000000312E00007D2B0000A3 +:08461000E9000000C1000000F8 +:0400000300001625BE +:00000001FF