From 9972c2b471ecca0fd3697b09c955d9fd07154927 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 3 Sep 2024 04:31:23 +1200 Subject: [PATCH 01/50] SGX powHSM initial implementation (#193) - SGX docker image for building - powHSM layer adjustments - Factored out Ledger Signer difficulty and initial block hash argument parsing - HAL adjustments and additional x86 functions - SGX implementation - Added SGX build (debug and non debug) scripts - Added SGX support to firmware test framework - Added HAL layer common sources unit tests to our CI test runner --- .github/workflows/run-tests.yml | 5 +- docker/sgx/Dockerfile | 42 ++ docker/sgx/build | 3 + docker/sgx/do | 33 ++ docker/sgx/do-notty | 1 + docker/sgx/rebuild | 3 + docker/sgx/term | 3 + firmware/build/build-sgx | 36 ++ firmware/build/build-sgx-debug | 36 ++ .../src/{powhsm => common}/src/bigdigits.c | 9 +- .../src/{powhsm => common}/src/bigdigits.h | 0 firmware/src/common/src/bigdigits_helper.c | 53 +++ firmware/src/common/src/bigdigits_helper.h | 64 +++ .../src/{powhsm => common}/src/bigdtypes.h | 0 firmware/src/common/src/runtime.h | 13 + firmware/src/common/test/run-all.sh | 2 +- firmware/src/hal/common/.gitkeep | 0 firmware/src/hal/common/src/communication.c | 14 +- firmware/src/hal/common/test/common.mk | 30 ++ firmware/src/hal/common/test/run-all.sh | 13 + .../common}/test/sha256/Makefile | 4 +- .../common}/test/sha256/test_sha256.c | 0 firmware/src/hal/include/hal/access.h | 94 +++++ firmware/src/hal/include/hal/endorsement.h | 9 + firmware/src/hal/include/hal/exceptions.h | 6 +- firmware/src/hal/include/hal/hash.h | 5 +- firmware/src/hal/include/hal/log.h | 37 +- firmware/src/hal/include/hal/nvmem.h | 26 +- firmware/src/hal/include/hal/seed.h | 28 +- firmware/src/hal/ledger/src/access.c | 31 ++ firmware/src/hal/ledger/src/communication.c | 2 +- firmware/src/hal/ledger/src/hash.c | 1 - firmware/src/hal/sgx/src/trusted/access.c | 177 ++++++++ firmware/src/hal/sgx/src/trusted/bip32.c | 1 + firmware/src/hal/sgx/src/trusted/bip32.h | 1 + .../src/hal/sgx/src/trusted/communication.c | 1 + firmware/src/hal/sgx/src/trusted/endian.c | 1 + firmware/src/hal/sgx/src/trusted/endian.h | 1 + .../src/hal/sgx/src/trusted/endorsement.c | 180 ++++++++ firmware/src/hal/sgx/src/trusted/exceptions.c | 1 + firmware/src/hal/sgx/src/trusted/hash.c | 1 + .../src/hal/sgx/src/trusted/hmac_sha256.c | 1 + .../src/hal/sgx/src/trusted/hmac_sha256.h | 1 + .../src/hal/sgx/src/trusted/hmac_sha512.c | 1 + .../src/hal/sgx/src/trusted/hmac_sha512.h | 1 + firmware/src/hal/sgx/src/trusted/keccak256.c | 1 + firmware/src/hal/sgx/src/trusted/keccak256.h | 1 + firmware/src/hal/sgx/src/trusted/log.c | 44 ++ firmware/src/hal/sgx/src/trusted/nvmem.c | 123 ++++++ firmware/src/hal/sgx/src/trusted/platform.c | 1 + firmware/src/hal/sgx/src/trusted/random.c | 30 ++ firmware/src/hal/sgx/src/trusted/random.h | 41 ++ .../src/hal/sgx/src/trusted/secret_store.c | 274 ++++++++++++ .../src/hal/sgx/src/trusted/secret_store.h | 90 ++++ firmware/src/hal/sgx/src/trusted/seed.c | 212 ++++++++++ firmware/src/hal/sgx/src/trusted/sha256.c | 1 + firmware/src/hal/sgx/src/trusted/sha256.h | 1 + firmware/src/hal/x86/src/access.c | 31 ++ firmware/src/hal/x86/src/bip32.c | 171 +++++++- firmware/src/hal/x86/src/bip32.h | 18 + firmware/src/hal/x86/src/endian.c | 77 ++++ firmware/src/hal/x86/src/endian.h | 72 ++++ firmware/src/hal/x86/src/endorsement.c | 6 +- firmware/src/hal/x86/src/exceptions.c | 4 - firmware/src/hal/x86/src/hash.c | 2 - firmware/src/hal/x86/src/hmac_sha256.c | 2 +- firmware/src/hal/x86/src/hmac_sha256.h | 2 +- firmware/src/hal/x86/src/hmac_sha512.c | 397 ++++++++++++++++++ firmware/src/hal/x86/src/hmac_sha512.h | 77 ++++ firmware/src/hal/x86/src/log.c | 7 +- firmware/src/hal/x86/src/random.c | 2 +- firmware/src/hal/x86/src/random.h | 2 +- firmware/src/hal/x86/src/seed.c | 3 +- firmware/src/hal/x86/test/bip32/Makefile | 6 +- firmware/src/hal/x86/test/common.mk | 6 +- firmware/src/hal/x86/test/run-all.sh | 7 +- firmware/src/ledger/signer/Makefile | 27 +- firmware/src/powhsm/src/attestation.c | 2 + firmware/src/powhsm/src/auth_receipt.c | 2 + firmware/src/powhsm/src/bc_advance.c | 5 +- firmware/src/powhsm/src/bc_diff.c | 59 +-- firmware/src/powhsm/src/bc_diff.h | 35 +- firmware/src/powhsm/src/bc_err.c | 2 +- firmware/src/powhsm/src/bc_state.c | 5 +- firmware/src/powhsm/src/err.h | 3 + firmware/src/powhsm/src/hsm.c | 34 +- firmware/src/powhsm/src/hsm.h | 26 ++ firmware/src/powhsm/src/instructions.h | 7 + firmware/src/powhsm/src/srlp.c | 4 +- firmware/src/powhsm/src/trie.c | 2 +- firmware/src/powhsm/test/difficulty/Makefile | 2 +- .../powhsm/test/difficulty/test_difficulty.c | 6 +- firmware/src/powhsm/test/run-all.sh | 2 +- firmware/src/sgx/.gitignore | 11 + firmware/src/sgx/Makefile | 181 ++++++++ firmware/src/sgx/src/hsm-debug.conf | 16 + firmware/src/sgx/src/hsm.conf | 11 + firmware/src/sgx/src/hsm.edl | 30 ++ firmware/src/sgx/src/trusted/ecall.c | 47 +++ firmware/src/sgx/src/trusted/ecall.h | 45 ++ firmware/src/sgx/src/trusted/sync.c | 38 ++ firmware/src/sgx/src/trusted/sync.h | 63 +++ firmware/src/sgx/src/trusted/system.c | 205 +++++++++ firmware/src/sgx/src/trusted/system.h | 48 +++ .../src/sgx/src/untrusted/enclave_provider.c | 70 +++ .../src/sgx/src/untrusted/enclave_provider.h | 52 +++ .../src/sgx/src/untrusted/enclave_proxy.c | 88 ++++ .../src/sgx/src/untrusted/enclave_proxy.h | 16 + firmware/src/sgx/src/untrusted/io.c | 202 +++++++++ firmware/src/sgx/src/untrusted/io.h | 66 +++ .../src/sgx/src/untrusted/keyvalue_store.c | 131 ++++++ .../src/sgx/src/untrusted/keyvalue_store.h | 68 +++ firmware/src/sgx/src/untrusted/log.c | 66 +++ firmware/src/sgx/src/untrusted/log.h | 56 +++ firmware/src/sgx/src/untrusted/main.c | 169 ++++++++ firmware/src/tcpsigner/Makefile | 1 - firmware/src/tcpsigner/src/hsmsim_io.c | 53 +-- firmware/src/tcpsigner/src/tcpsigner.c | 17 +- .../signer => util}/make-difficulty.py | 0 .../make-initial-block-hash.py | 0 firmware/src/util/signer.mk | 28 ++ firmware/test/.gitignore | 7 + firmware/test/README.md | 39 +- firmware/test/cases/case.py | 5 +- firmware/test/cases/reconnect.py | 25 +- firmware/test/options.py | 15 +- firmware/test/package/Dockerfile | 1 + firmware/test/package/build-runner | 25 ++ firmware/test/package/generate | 24 ++ firmware/test/package/run-with-docker | 7 + .../test/resources/307-reconnect-dongle.json | 2 +- .../resources/308-get-after-reconnection.json | 2 +- .../resources/602-sign-long-redeemscript.json | 2 +- .../610-sign-tx-with-many-inputs.json | 2 +- .../resources/612-sign-sample-mainnet-tx.json | 2 +- .../613-sign-sample-testnet-tx-erp.json | 2 +- .../614-sign-match-not-last-log.json | 2 +- .../resources/615-sign-match-long-proof.json | 2 +- .../616-sign-3input-5output-testnet.json | 2 +- .../test/resources/620-sign-segwit-basic.json | 2 +- .../621-sign-segwit-with-many-inputs.json | 2 +- .../622-sign-segwit-long-witnessscript.json | 2 +- .../700-dongle-fake-receipt-root-fails.json | 2 +- .../resources/900-set-is-onboarded-no.json | 2 +- .../901-no-onboarded-sign-noauth-fails.json | 2 +- .../902-no-onboard-sign-auth-fails.json | 2 +- .../903-no-onboarded-get-bs-fails.json | 2 +- .../904-no-onboarded-advance-fails.json | 2 +- .../905-no-onboard-update-fails.json | 2 +- .../resources/906-set-is-onboarded-yes.json | 2 +- .../907-dongle-set-is-onboarded-fails.json | 2 +- .../resources/nvm/01-nvm-stats-reset.json | 2 +- .../resources/nvm/20-nvm-stats-print.json | 2 +- firmware/test/run.py | 22 +- firmware/test/sgx | 1 + firmware/test/test-all | 33 +- middleware/sgx/__init__.py | 21 + middleware/sgx/hsm2dongle.py | 46 ++ 158 files changed, 4716 insertions(+), 284 deletions(-) create mode 100644 docker/sgx/Dockerfile create mode 100755 docker/sgx/build create mode 100755 docker/sgx/do create mode 120000 docker/sgx/do-notty create mode 100755 docker/sgx/rebuild create mode 100755 docker/sgx/term create mode 100755 firmware/build/build-sgx create mode 100755 firmware/build/build-sgx-debug rename firmware/src/{powhsm => common}/src/bigdigits.c (96%) rename firmware/src/{powhsm => common}/src/bigdigits.h (100%) create mode 100644 firmware/src/common/src/bigdigits_helper.c create mode 100644 firmware/src/common/src/bigdigits_helper.h rename firmware/src/{powhsm => common}/src/bigdtypes.h (100%) delete mode 100644 firmware/src/hal/common/.gitkeep create mode 100644 firmware/src/hal/common/test/common.mk create mode 100755 firmware/src/hal/common/test/run-all.sh rename firmware/src/{powhsm => hal/common}/test/sha256/Makefile (94%) rename firmware/src/{powhsm => hal/common}/test/sha256/test_sha256.c (100%) create mode 100644 firmware/src/hal/include/hal/access.h create mode 100644 firmware/src/hal/ledger/src/access.c create mode 100644 firmware/src/hal/sgx/src/trusted/access.c create mode 120000 firmware/src/hal/sgx/src/trusted/bip32.c create mode 120000 firmware/src/hal/sgx/src/trusted/bip32.h create mode 120000 firmware/src/hal/sgx/src/trusted/communication.c create mode 120000 firmware/src/hal/sgx/src/trusted/endian.c create mode 120000 firmware/src/hal/sgx/src/trusted/endian.h create mode 100644 firmware/src/hal/sgx/src/trusted/endorsement.c create mode 120000 firmware/src/hal/sgx/src/trusted/exceptions.c create mode 120000 firmware/src/hal/sgx/src/trusted/hash.c create mode 120000 firmware/src/hal/sgx/src/trusted/hmac_sha256.c create mode 120000 firmware/src/hal/sgx/src/trusted/hmac_sha256.h create mode 120000 firmware/src/hal/sgx/src/trusted/hmac_sha512.c create mode 120000 firmware/src/hal/sgx/src/trusted/hmac_sha512.h create mode 120000 firmware/src/hal/sgx/src/trusted/keccak256.c create mode 120000 firmware/src/hal/sgx/src/trusted/keccak256.h create mode 100644 firmware/src/hal/sgx/src/trusted/log.c create mode 100644 firmware/src/hal/sgx/src/trusted/nvmem.c create mode 120000 firmware/src/hal/sgx/src/trusted/platform.c create mode 100644 firmware/src/hal/sgx/src/trusted/random.c create mode 100644 firmware/src/hal/sgx/src/trusted/random.h create mode 100644 firmware/src/hal/sgx/src/trusted/secret_store.c create mode 100644 firmware/src/hal/sgx/src/trusted/secret_store.h create mode 100644 firmware/src/hal/sgx/src/trusted/seed.c create mode 120000 firmware/src/hal/sgx/src/trusted/sha256.c create mode 120000 firmware/src/hal/sgx/src/trusted/sha256.h create mode 100644 firmware/src/hal/x86/src/access.c create mode 100644 firmware/src/hal/x86/src/endian.c create mode 100644 firmware/src/hal/x86/src/endian.h create mode 100644 firmware/src/hal/x86/src/hmac_sha512.c create mode 100644 firmware/src/hal/x86/src/hmac_sha512.h create mode 100644 firmware/src/sgx/.gitignore create mode 100644 firmware/src/sgx/Makefile create mode 100644 firmware/src/sgx/src/hsm-debug.conf create mode 100644 firmware/src/sgx/src/hsm.conf create mode 100644 firmware/src/sgx/src/hsm.edl create mode 100644 firmware/src/sgx/src/trusted/ecall.c create mode 100644 firmware/src/sgx/src/trusted/ecall.h create mode 100644 firmware/src/sgx/src/trusted/sync.c create mode 100644 firmware/src/sgx/src/trusted/sync.h create mode 100644 firmware/src/sgx/src/trusted/system.c create mode 100644 firmware/src/sgx/src/trusted/system.h create mode 100644 firmware/src/sgx/src/untrusted/enclave_provider.c create mode 100644 firmware/src/sgx/src/untrusted/enclave_provider.h create mode 100644 firmware/src/sgx/src/untrusted/enclave_proxy.c create mode 100644 firmware/src/sgx/src/untrusted/enclave_proxy.h create mode 100644 firmware/src/sgx/src/untrusted/io.c create mode 100644 firmware/src/sgx/src/untrusted/io.h create mode 100644 firmware/src/sgx/src/untrusted/keyvalue_store.c create mode 100644 firmware/src/sgx/src/untrusted/keyvalue_store.h create mode 100644 firmware/src/sgx/src/untrusted/log.c create mode 100644 firmware/src/sgx/src/untrusted/log.h create mode 100644 firmware/src/sgx/src/untrusted/main.c rename firmware/src/{ledger/signer => util}/make-difficulty.py (100%) rename firmware/src/{ledger/signer => util}/make-initial-block-hash.py (100%) create mode 100644 firmware/src/util/signer.mk create mode 100644 firmware/test/package/Dockerfile create mode 100755 firmware/test/package/build-runner create mode 100755 firmware/test/package/generate create mode 100755 firmware/test/package/run-with-docker create mode 120000 firmware/test/sgx create mode 100644 middleware/sgx/__init__.py create mode 100644 middleware/sgx/hsm2dongle.py diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 336d189d..3694fdd9 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -23,7 +23,10 @@ jobs: - name: Firmware tests using TCPSigner run: firmware/test/test-all - - name: Firmware HAL's unit tests + - name: Firmware HAL's common unit tests + run: firmware/src/hal/common/test/run-all.sh + + - name: Firmware HAL's x86 unit tests run: firmware/src/hal/x86/test/run-all.sh - name: Firmware common lib unit tests diff --git a/docker/sgx/Dockerfile b/docker/sgx/Dockerfile new file mode 100644 index 00000000..881f8bd7 --- /dev/null +++ b/docker/sgx/Dockerfile @@ -0,0 +1,42 @@ +FROM openenclavedockerregistry.azurecr.io/oetools-20.04:2023.11.21100 + +# Install dependencies +RUN apt-get update && \ + apt-get install -y apt-utils vim && \ + apt-get install -y tar && \ + apt-get install -y xz-utils && \ + apt-get install -y curl && \ + apt-get install -y git && \ + apt-get install -y clang-11 && \ + apt-get install -y libssl-dev && \ + apt-get install -y gdb && \ + apt-get install -y libsgx-enclave-common && \ + apt-get install -y libsgx-quote-ex && \ + apt-get install -y libprotobuf17 && \ + apt-get install -y libsgx-dcap-ql && \ + apt-get install -y libsgx-dcap-ql-dev && \ + apt-get install -y az-dcap-client && \ + apt-get install -y open-enclave && \ + apt-get install -y gcc && \ + apt-get install -y make + +# Create directory to host symlinks to Open Enclave static libraries +ENV SGX_STATIC_LIBS=/opt/openenclave-libs +ENV SGX_SECP256K1=/opt/secp256k1 + +# Build libsecp256k1 for Open Enclave +RUN curl -L -o secp256k1.tar.gz \ + https://github.com/bitcoin-core/secp256k1/archive/refs/tags/v0.4.0.tar.gz && \ + mkdir -p $SGX_SECP256K1 && \ + tar -xzf secp256k1.tar.gz --strip-components=1 -C $SGX_SECP256K1 && \ + rm -f secp256k1.tar.gz && \ + cd $SGX_SECP256K1 && \ + ./autogen.sh && \ + . /opt/openenclave/share/openenclave/openenclaverc && \ + ./configure --disable-tests --disable-benchmark --disable-exhaustive-tests CC=gcc CFLAGS="-std=c11 $(pkg-config oeenclave-gcc --cflags)" && \ + make && \ + mkdir -p $SGX_STATIC_LIBS && \ + ln -s $(realpath .libs/libsecp256k1.a) $SGX_STATIC_LIBS/libsecp256k1.a + +# SGX environment setup command +ENV SGX_ENVSETUP="source /opt/openenclave/share/openenclave/openenclaverc" diff --git a/docker/sgx/build b/docker/sgx/build new file mode 100755 index 00000000..3a0de234 --- /dev/null +++ b/docker/sgx/build @@ -0,0 +1,3 @@ +#!/bin/bash + +docker build -t hsm:sgx $(dirname $0) diff --git a/docker/sgx/do b/docker/sgx/do new file mode 100755 index 00000000..0ec3b41d --- /dev/null +++ b/docker/sgx/do @@ -0,0 +1,33 @@ +#!/bin/bash + +if [[ -z "$1" ]]; then + echo "No workdir specified" + exit 1 +fi + +if [[ -z "$2" ]]; then + echo "No script specified" + exit 1 +fi + +# Script directory +pushd $(dirname $0) > /dev/null +DOCKER_ROOT=$(pwd) +popd > /dev/null + +# Root directory +HSM_ROOT=$DOCKER_ROOT/../../ + +# Check docker image exists +DOCKER_IMAGE=hsm:sgx +source $DOCKER_ROOT/../check-image + +DOCKER_USER="$(id -u):$(id -g)" + +if [[ "$(basename $0)" == "do" ]]; then + INTERACTIVE="-i" +else + INTERACTIVE="" +fi + +docker run -t $INTERACTIVE --rm -p7777:7777 --name hsm-sgx --user $DOCKER_USER -v $HSM_ROOT:/hsm2 -w $1 $DOCKER_IMAGE $2 diff --git a/docker/sgx/do-notty b/docker/sgx/do-notty new file mode 120000 index 00000000..7d46b283 --- /dev/null +++ b/docker/sgx/do-notty @@ -0,0 +1 @@ +do \ No newline at end of file diff --git a/docker/sgx/rebuild b/docker/sgx/rebuild new file mode 100755 index 00000000..71494713 --- /dev/null +++ b/docker/sgx/rebuild @@ -0,0 +1,3 @@ +#!/bin/bash + +docker build -t hsm:sgx --no-cache $(dirname $0) diff --git a/docker/sgx/term b/docker/sgx/term new file mode 100755 index 00000000..fad72667 --- /dev/null +++ b/docker/sgx/term @@ -0,0 +1,3 @@ +#!/bin/bash + +$(dirname $0)/do /hsm2 /bin/bash diff --git a/firmware/build/build-sgx b/firmware/build/build-sgx new file mode 100755 index 00000000..4452f612 --- /dev/null +++ b/firmware/build/build-sgx @@ -0,0 +1,36 @@ +#! /usr/bin/env bash + +if [[ $# -lt 3 ]]; then + echo "Usage: $0 " + exit 1 +fi + +if [[ "$3" == "regtest" ]]; then + NETWORK="REGTEST" +elif [[ "$3" == "testnet" ]]; then + NETWORK="TESTNET" +elif [[ "$3" == "mainnet" ]]; then + NETWORK="" +else + echo "Invalid network '$3'" + exit 1 +fi + +pushd $(dirname $0) > /dev/null +BUILD_ROOT=$(pwd) +popd > /dev/null + +HSM_ROOT=$(realpath $BUILD_ROOT/../../) + +DOCKER_IMAGE=hsm:sgx +source $BUILD_ROOT/../../docker/check-image + +BUILD_TARGET=build +if [[ "$(basename $0)" == "build-sgx-debug" ]]; then + BUILD_TARGET=build-debug +fi +BUILD_CMD="\$SGX_ENVSETUP && make clean $BUILD_TARGET CHECKPOINT=$1 TARGET_DIFFICULTY=$2 NETWORK=$NETWORK" + +DOCKER_USER="$(id -u):$(id -g)" + +docker run -t --rm --user $DOCKER_USER -w /hsm2/firmware/src/sgx -v ${HSM_ROOT}:/hsm2 ${DOCKER_IMAGE} /bin/bash -c "$BUILD_CMD" diff --git a/firmware/build/build-sgx-debug b/firmware/build/build-sgx-debug new file mode 100755 index 00000000..4452f612 --- /dev/null +++ b/firmware/build/build-sgx-debug @@ -0,0 +1,36 @@ +#! /usr/bin/env bash + +if [[ $# -lt 3 ]]; then + echo "Usage: $0 " + exit 1 +fi + +if [[ "$3" == "regtest" ]]; then + NETWORK="REGTEST" +elif [[ "$3" == "testnet" ]]; then + NETWORK="TESTNET" +elif [[ "$3" == "mainnet" ]]; then + NETWORK="" +else + echo "Invalid network '$3'" + exit 1 +fi + +pushd $(dirname $0) > /dev/null +BUILD_ROOT=$(pwd) +popd > /dev/null + +HSM_ROOT=$(realpath $BUILD_ROOT/../../) + +DOCKER_IMAGE=hsm:sgx +source $BUILD_ROOT/../../docker/check-image + +BUILD_TARGET=build +if [[ "$(basename $0)" == "build-sgx-debug" ]]; then + BUILD_TARGET=build-debug +fi +BUILD_CMD="\$SGX_ENVSETUP && make clean $BUILD_TARGET CHECKPOINT=$1 TARGET_DIFFICULTY=$2 NETWORK=$NETWORK" + +DOCKER_USER="$(id -u):$(id -g)" + +docker run -t --rm --user $DOCKER_USER -w /hsm2/firmware/src/sgx -v ${HSM_ROOT}:/hsm2 ${DOCKER_IMAGE} /bin/bash -c "$BUILD_CMD" diff --git a/firmware/src/powhsm/src/bigdigits.c b/firmware/src/common/src/bigdigits.c similarity index 96% rename from firmware/src/powhsm/src/bigdigits.c rename to firmware/src/common/src/bigdigits.c index cf2f7128..250a6900 100644 --- a/firmware/src/powhsm/src/bigdigits.c +++ b/firmware/src/common/src/bigdigits.c @@ -47,7 +47,6 @@ #define assert(x) #include "bigdigits.h" -#include "hal/log.h" #define BITS_PER_HALF_DIGIT (BITS_PER_DIGIT / 2) #define LOHALF(x) ((DIGIT_T)((x) & MAX_HALF_DIGIT)) @@ -768,12 +767,15 @@ DIGIT_T spDivide(DIGIT_T *q, DIGIT_T *r, const DIGIT_T u[2], DIGIT_T v) // Platform-dependent code #ifndef HSM_PLATFORM_LEDGER +#include "hal/log.h" + void LOG_BIGD_HEX(const char *prefix, const DIGIT_T *a, size_t len, const char *suffix) { - if (prefix) + if (prefix) { LOG("%s", prefix); + } /* Trim leading digits which are zero */ while (len--) { if (a[len] != 0) @@ -787,8 +789,9 @@ void LOG_BIGD_HEX(const char *prefix, while (len--) { LOG("%08" PRIxBIGD, a[len]); } - if (suffix) + if (suffix) { LOG("%s", suffix); + } } #endif \ No newline at end of file diff --git a/firmware/src/powhsm/src/bigdigits.h b/firmware/src/common/src/bigdigits.h similarity index 100% rename from firmware/src/powhsm/src/bigdigits.h rename to firmware/src/common/src/bigdigits.h diff --git a/firmware/src/common/src/bigdigits_helper.c b/firmware/src/common/src/bigdigits_helper.c new file mode 100644 index 00000000..32f740f2 --- /dev/null +++ b/firmware/src/common/src/bigdigits_helper.c @@ -0,0 +1,53 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "bigdigits_helper.h" + +void parse_bigint_be(const uint8_t* buf, + uint16_t buf_size, + DIGIT_T target[], + uint16_t target_digits) { + + mpSetZero(target, target_digits); + int j = 0, k = 0; + DIGIT_T curr = 0; + for (int i = buf_size - 1; i >= 0; i--) { + curr = buf[i]; + target[j] |= (curr << (k * 8)); + if (++k == sizeof(DIGIT_T)) { + ++j; + k = 0; + } + } +} + +void dump_bigint_be(uint8_t* buf, const DIGIT_T n[], const size_t digits) { + int k = 0; + for (int i = digits - 1; i >= 0; i--) { + buf[k++] = (uint8_t)((n[i] & 0xff000000) >> 24); + buf[k++] = (uint8_t)((n[i] & 0x00ff0000) >> 16); + buf[k++] = (uint8_t)((n[i] & 0x0000ff00) >> 8); + buf[k++] = (uint8_t)((n[i] & 0x000000ff) >> 0); + } +} \ No newline at end of file diff --git a/firmware/src/common/src/bigdigits_helper.h b/firmware/src/common/src/bigdigits_helper.h new file mode 100644 index 00000000..54ca900d --- /dev/null +++ b/firmware/src/common/src/bigdigits_helper.h @@ -0,0 +1,64 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __BIGDIGITS_HELPER_H +#define __BIGDIGITS_HELPER_H + +#include "bigdigits.h" + +/* + * Initialize a big integer. This is kind of tricky because the way big + * integers are modeled in memory. Here goes an example: + * + * For the number: + * + * [1c, 24, a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3] + * + * (that is, 0x1c24a0a1a2a3b0b1b2b3c0c1c2c3), we must build the following + * array of uin32_t numbers: + * + * [0xc0c1c2c3, 0xb0b1b2b3, 0xa0a1a2a3, 0x00001c24] + * + * This function implements exactly the conversion exemplified above. + * + * @arg[in] buf buffer holding big integer bytes in big-endian order + * @arg[in] buf_size buffer size in bytes + * @arg[out] target big integer to initialize + * @arg[in] target_digits number of 32-byte integers comprising the big integer + */ +void parse_bigint_be(const uint8_t* buf, + uint16_t buf_size, + DIGIT_T target[], + uint16_t target_digits); + +/* + * Dump a bigint to given buffer (big-endian). + * + * @arg[in] buf pointer to destination buffer + * @arg[in] n big integer to dump + * @arg[in] size number of 32-byte integers comprising n + */ +void dump_bigint_be(uint8_t* buf, const DIGIT_T n[], const size_t digits); + +#endif // __BIGDIGITS_HELPER_H \ No newline at end of file diff --git a/firmware/src/powhsm/src/bigdtypes.h b/firmware/src/common/src/bigdtypes.h similarity index 100% rename from firmware/src/powhsm/src/bigdtypes.h rename to firmware/src/common/src/bigdtypes.h diff --git a/firmware/src/common/src/runtime.h b/firmware/src/common/src/runtime.h index 0746bfba..eac5d88b 100644 --- a/firmware/src/common/src/runtime.h +++ b/firmware/src/common/src/runtime.h @@ -44,6 +44,19 @@ #define NON_VOLATILE +#define UNUSED(x) (void)(x) + +#elif defined(HSM_PLATFORM_SGX) + +#include "hal/platform.h" +#include "hal/exceptions.h" + +#define PIC(x) (x) + +#define NON_VOLATILE + +#define UNUSED(x) (void)(x) + #else #error "HSM Platform undefined" #endif diff --git a/firmware/src/common/test/run-all.sh b/firmware/src/common/test/run-all.sh index 02c31213..bcf2cf68 100755 --- a/firmware/src/common/test/run-all.sh +++ b/firmware/src/common/test/run-all.sh @@ -1,6 +1,6 @@ #!/bin/bash BASEDIR=$(dirname $0) -TESTDIRS="memutil ints" +TESTDIRS="ints memutil" TESTDIRS=${1:-"$TESTDIRS"} for d in $TESTDIRS; do diff --git a/firmware/src/hal/common/.gitkeep b/firmware/src/hal/common/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/firmware/src/hal/common/src/communication.c b/firmware/src/hal/common/src/communication.c index ebad7b21..c0aa7c37 100644 --- a/firmware/src/hal/common/src/communication.c +++ b/firmware/src/hal/common/src/communication.c @@ -24,21 +24,21 @@ #include "hal/communication.h" -static unsigned char* msg_buffer; -static size_t msg_buffer_size; +static unsigned char* G_msg_buffer; +static size_t G_msg_buffer_size; // HAL implementation -bool communication_init(unsigned char* _msg_buffer, size_t _msg_buffer_size) { +bool communication_init(unsigned char* msg_buffer, size_t msg_buffer_size) { // Setup the exchange buffer - msg_buffer = _msg_buffer; - msg_buffer_size = _msg_buffer_size; + G_msg_buffer = msg_buffer; + G_msg_buffer_size = msg_buffer_size; return true; } unsigned char* communication_get_msg_buffer() { - return msg_buffer; + return G_msg_buffer; } size_t communication_get_msg_buffer_size() { - return msg_buffer_size; + return G_msg_buffer_size; } diff --git a/firmware/src/hal/common/test/common.mk b/firmware/src/hal/common/test/common.mk new file mode 100644 index 00000000..e9526815 --- /dev/null +++ b/firmware/src/hal/common/test/common.mk @@ -0,0 +1,30 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +SRCDIR = ../../src +CFLAGS = -iquote $(SRCDIR) + +include ../../../../../coverage/coverage.mk + +CFLAGS += $(COVFLAGS) + +VPATH += $(SRCDIR) diff --git a/firmware/src/hal/common/test/run-all.sh b/firmware/src/hal/common/test/run-all.sh new file mode 100755 index 00000000..4278c458 --- /dev/null +++ b/firmware/src/hal/common/test/run-all.sh @@ -0,0 +1,13 @@ +#!/bin/bash +BASEDIR=$(dirname $0) +TESTDIRS="sha256" +TESTDIRS=${1:-"$TESTDIRS"} + +for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null +done diff --git a/firmware/src/powhsm/test/sha256/Makefile b/firmware/src/hal/common/test/sha256/Makefile similarity index 94% rename from firmware/src/powhsm/test/sha256/Makefile rename to firmware/src/hal/common/test/sha256/Makefile index 220e9e67..3c6651fa 100644 --- a/firmware/src/powhsm/test/sha256/Makefile +++ b/firmware/src/hal/common/test/sha256/Makefile @@ -20,10 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -include ../common/common.mk +include ../common.mk PROG = test.out -OBJS = test_fwk.o sha256.o test_sha256.o +OBJS = sha256.o test_sha256.o all: $(PROG) diff --git a/firmware/src/powhsm/test/sha256/test_sha256.c b/firmware/src/hal/common/test/sha256/test_sha256.c similarity index 100% rename from firmware/src/powhsm/test/sha256/test_sha256.c rename to firmware/src/hal/common/test/sha256/test_sha256.c diff --git a/firmware/src/hal/include/hal/access.h b/firmware/src/hal/include/hal/access.h new file mode 100644 index 00000000..1b27efc0 --- /dev/null +++ b/firmware/src/hal/include/hal/access.h @@ -0,0 +1,94 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __HAL_ACCESS_H +#define __HAL_ACCESS_H + +#include + +/** + * @brief Returns whether the module is locked + * + * @returns whether the module is locked + */ +bool access_is_locked(); + +// BEGINNING of platform-dependent code +#if defined(HSM_PLATFORM_SGX) + +#include + +typedef void (*access_wiped_callback_t)(); + +/** + * @brief Initializes the access module + * + * @param wiped_callback function to call when the module is wiped + * + * @returns whether the initialisation succeeded + */ +bool access_init(access_wiped_callback_t wiped_callback); + +/** + * @brief Unlocks the access module + * + * @param password + * @param password_length + * + * @returns whether the unlock was successful + */ +bool access_unlock(char* password, uint8_t password_length); + +/** + * @brief Returns the number of unlocking retries available + */ +uint8_t access_get_retries(); + +/** + * @brief Returns whether the module is in a wiped state + * + * @returns whether the module is in a wiped state + */ +bool access_is_wiped(); + +/** + * @brief Wipes the module + */ +bool access_wipe(); + +/** + * @brief Changes the password. + * The module needs to be in an unlocked or wiped state. + * + * @param password + * @param password_length + * + * @returns whether the password change was successful + */ +bool access_set_password(char* password, uint8_t password_length); + +#endif +// END of platform-dependent code + +#endif // __HAL_ACCESS_H diff --git a/firmware/src/hal/include/hal/endorsement.h b/firmware/src/hal/include/hal/endorsement.h index 489a8bf7..8b43ccde 100644 --- a/firmware/src/hal/include/hal/endorsement.h +++ b/firmware/src/hal/include/hal/endorsement.h @@ -99,6 +99,15 @@ extern attestation_id_t attestation_id; */ bool endorsement_init(char* att_file_path); +#elif defined(HSM_PLATFORM_SGX) + +/** + * @brief Initializes the endorsement module + * + * @returns whether the initialisation succeeded + */ +bool endorsement_init(); + #endif // END of platform-dependent code diff --git a/firmware/src/hal/include/hal/exceptions.h b/firmware/src/hal/include/hal/exceptions.h index d5f374e2..3932e1c1 100644 --- a/firmware/src/hal/include/hal/exceptions.h +++ b/firmware/src/hal/include/hal/exceptions.h @@ -46,7 +46,7 @@ #include "os.h" // This includes the exception engine -#elif defined(HSM_PLATFORM_X86) +#elif defined(HSM_PLATFORM_X86) || defined(HSM_PLATFORM_SGX) /** * Modified try...catch exception implementation (taken from nanos-secure-sdk) @@ -214,6 +214,8 @@ void os_longjmp(jmp_buf b, unsigned int exception); #endif -#endif // HSM_PLATFORM_X86 +#else +#error "HSM Platform undefined" +#endif // HSM_PLATFORM_XXXX #endif // __HAL_EXCEPTIONS_H diff --git a/firmware/src/hal/include/hal/hash.h b/firmware/src/hal/include/hal/hash.h index 0514324a..ee09660a 100644 --- a/firmware/src/hal/include/hal/hash.h +++ b/firmware/src/hal/include/hal/hash.h @@ -30,20 +30,19 @@ #include #include "hal/constants.h" +#include "sha256.h" // BEGINNING of platform-dependent code #if defined(HSM_PLATFORM_LEDGER) #include "os.h" -#include "sha256.h" typedef cx_sha256_t hash_sha256_ctx_t; typedef cx_sha3_t hash_keccak256_ctx_t; typedef SHA256_CTX hash_sha256_ms_ctx_t; -#elif defined(HSM_PLATFORM_X86) +#elif defined(HSM_PLATFORM_X86) || defined(HSM_PLATFORM_SGX) -#include "sha256.h" #include "keccak256.h" typedef SHA256_CTX hash_sha256_ctx_t; diff --git a/firmware/src/hal/include/hal/log.h b/firmware/src/hal/include/hal/log.h index 88549759..9c3f9d6f 100644 --- a/firmware/src/hal/include/hal/log.h +++ b/firmware/src/hal/include/hal/log.h @@ -42,7 +42,42 @@ void LOG(const char *format, ...); * @param buffer the buffer containing the bytes to output as hex chars * @param size the size of buffer in bytes */ -void LOG_HEX(const char *prefix, void *buffer, size_t size); +void LOG_HEX(const char *prefix, const void *buffer, const size_t size); + +#elif defined(HSM_PLATFORM_SGX) + +// #ifdef DEBUG_BUILD +#if 1 // For now, we always output enclave logs + +#include + +#define TRUSTED_LOG_PREFIX "[Enclave] " + +/** + * @brief Works just like printf, but prepends + * a prefix to every message + */ +#define LOG(...) \ + { \ + fprintf(stderr, TRUSTED_LOG_PREFIX); \ + fprintf(stderr, __VA_ARGS__); \ + } + +/** + * @brief Print buffer in hex format with prefix + * + * @param prefix the log prefix (the general log prefix will be prepended too) + * @param buffer the buffer containing the bytes to output as hex chars + * @param size the size of buffer in bytes + */ +void LOG_HEX(const char *prefix, const void *buffer, const size_t size); + +#else // DEBUG_BUILD + +#define LOG(...) +#define LOG_HEX(...) + +#endif // DEBUG_BUILD #elif defined(HSM_PLATFORM_LEDGER) diff --git a/firmware/src/hal/include/hal/nvmem.h b/firmware/src/hal/include/hal/nvmem.h index f7c89701..e6daeead 100644 --- a/firmware/src/hal/include/hal/nvmem.h +++ b/firmware/src/hal/include/hal/nvmem.h @@ -32,7 +32,8 @@ /** * @brief Write to non volatile memory * - * @param dst The destination address in non volatile memory + * @param key The key of the destination in non volatile memory + * @param dst The destination address in (non volatile) memory * @param src The source address to write from * @param length The amount of bytes to write * @@ -59,6 +60,29 @@ void nvmem_stats_reset(); */ nvmmem_stats_t nvmem_get_stats(); +#elif defined(HSM_PLATFORM_SGX) + +/** + * @brief Initializes the nvmem module + */ +void nvmem_init(); + +/** + * @brief Registers a memory block as non volatile + * + * @param key a string key to uniquely identify the block + * @param addr the base address of the block + * @param size the size of the block in bytes + */ +void nvmem_register_block(char* key, void* addr, size_t size); + +/** + * @brief Loads registered blocks into memory + * + * @returns whether loading was successful + */ +bool nvmem_load(); + #endif // END of platform-dependent code diff --git a/firmware/src/hal/include/hal/seed.h b/firmware/src/hal/include/hal/seed.h index 022d79a4..6c05452f 100644 --- a/firmware/src/hal/include/hal/seed.h +++ b/firmware/src/hal/include/hal/seed.h @@ -77,7 +77,6 @@ bool seed_sign(uint32_t* path, typedef struct seed_data_s { bool is_onboarded; - } seed_data_t; /** @@ -116,6 +115,33 @@ bool seed_init(const char* key_file_path, const char* bip32_paths[], const size_t bip32_paths_count); +#elif defined(HSM_PLATFORM_SGX) + +/** + * @brief Initializes the seed module + * + * @returns whether the initialisation was successful + */ +bool seed_init(); + +/** + * @brief Wipes the existing seed, if any + * + * @returns whether the wipe was successful + */ +bool seed_wipe(); + +/** + * @brief Generates and persists a new random seed + * + * @param client_seed the client-provided seed + * (should be randomly generated) + * @param client_seed_size the size of the client-provided seed + * + * @returns whether the seed generation was successful + */ +bool seed_generate(uint8_t* client_seed, uint8_t client_seed_size); + #endif // END of platform-dependent code diff --git a/firmware/src/hal/ledger/src/access.c b/firmware/src/hal/ledger/src/access.c new file mode 100644 index 00000000..80ac67d4 --- /dev/null +++ b/firmware/src/hal/ledger/src/access.c @@ -0,0 +1,31 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "hal/access.h" + +bool access_is_locked() { + // This will only ever be used from within the signer, + // which means the device will always be unlocked + return false; +} diff --git a/firmware/src/hal/ledger/src/communication.c b/firmware/src/hal/ledger/src/communication.c index 2bf128f3..6b73fb84 120000 --- a/firmware/src/hal/ledger/src/communication.c +++ b/firmware/src/hal/ledger/src/communication.c @@ -1 +1 @@ -../../common/src/communication.c \ No newline at end of file +../../x86/src/communication.c \ No newline at end of file diff --git a/firmware/src/hal/ledger/src/hash.c b/firmware/src/hal/ledger/src/hash.c index 0169015c..f9de0cdc 100644 --- a/firmware/src/hal/ledger/src/hash.c +++ b/firmware/src/hal/ledger/src/hash.c @@ -23,7 +23,6 @@ */ #include "hal/hash.h" -#include "sha256.h" #include "os.h" // *** sha256 *** diff --git a/firmware/src/hal/sgx/src/trusted/access.c b/firmware/src/hal/sgx/src/trusted/access.c new file mode 100644 index 00000000..aa544fe8 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/access.c @@ -0,0 +1,177 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "hal/access.h" +#include "hal/log.h" + +#include "secret_store.h" + +#define MIN_PASSWORD_LENGTH 4 +#define MAX_PASSWORD_LENGTH 10 +#define MAX_RETRIES 3 + +#define SEST_PASSWORD_KEY "password" +#define SEST_RETRIES_KEY "retries" + +// Globals +static bool G_wiped; +static bool G_locked; +static uint8_t G_available_retries; +static char G_password[MAX_PASSWORD_LENGTH]; +static uint8_t G_password_length; +static access_wiped_callback_t G_wiped_callback; + +bool access_init(access_wiped_callback_t wiped_callback) { + G_locked = true; + G_wiped = true; + G_wiped_callback = wiped_callback; + + if (!sest_exists(SEST_PASSWORD_KEY) && !sest_exists(SEST_RETRIES_KEY)) { + // Module is in a wiped and locked state. Nothing left to do + return true; + } + + // Read password + if (!(G_password_length = sest_read( + SEST_PASSWORD_KEY, (uint8_t*)G_password, sizeof(G_password)))) { + LOG("Could not load the current password\n"); + return false; + } + + // Make sure password is sound + if (G_password_length < MIN_PASSWORD_LENGTH || + G_password_length > MAX_PASSWORD_LENGTH) { + LOG("Detected invalid password\n"); + return false; + } + + // Read retries + if (sest_read(SEST_RETRIES_KEY, + (uint8_t*)&G_available_retries, + sizeof(G_available_retries)) != sizeof(G_available_retries)) { + LOG("Could not read the current retries\n"); + return false; + } + + // Make sure number of retries read is sound + if (!G_available_retries || G_available_retries > MAX_RETRIES) { + LOG("Detected invalid retries\n"); + return false; + } + + G_wiped = false; + LOG("Password loaded. Access is locked\n"); + return true; +} + +bool access_wipe() { + G_wiped = true; + G_locked = true; + + bool success = true; + success &= sest_remove(SEST_PASSWORD_KEY); + success &= sest_remove(SEST_RETRIES_KEY); + + return success; +} + +bool access_unlock(char* password, uint8_t password_length) { + if (G_wiped) { + LOG("Access module is wiped\n"); + return false; + } + + if (!G_locked) { + LOG("Access module already unlocked\n"); + return true; + } + + if (password_length != G_password_length || + memcmp(password, G_password, G_password_length)) { + LOG("Invalid password\n"); + G_available_retries--; + sest_write(SEST_RETRIES_KEY, + (uint8_t*)&G_available_retries, + sizeof(G_available_retries)); + if (G_available_retries == 0) { + LOG("Too many unlock retries. Forcing wipe...\n"); + access_wipe(); + G_wiped_callback(); + } + return false; + } + + LOG("Access module unlocked\n"); + G_locked = false; + G_available_retries = MAX_RETRIES; + sest_write(SEST_RETRIES_KEY, + (uint8_t*)&G_available_retries, + sizeof(G_available_retries)); + return true; +} + +uint8_t access_get_retries() { + return G_available_retries; +} + +bool access_is_wiped() { + return G_wiped; +} + +bool access_is_locked() { + return G_locked; +} + +bool access_set_password(char* password, uint8_t password_length) { + if (G_locked && !G_wiped) { + LOG("Access module is locked, password change not possible\n"); + return false; + } + + if (password_length < MIN_PASSWORD_LENGTH || + password_length > MAX_PASSWORD_LENGTH) { + LOG("Invalid password\n"); + return false; + } + + if (!sest_write(SEST_PASSWORD_KEY, (uint8_t*)password, password_length)) { + LOG("Error writing password\n"); + return false; + } + + G_password_length = password_length; + memcpy(G_password, password, password_length); + G_wiped = false; + G_available_retries = MAX_RETRIES; + sest_write(SEST_RETRIES_KEY, + (uint8_t*)&G_available_retries, + sizeof(G_available_retries)); + G_locked = true; + LOG("Password set, access locked\n"); + return true; +} diff --git a/firmware/src/hal/sgx/src/trusted/bip32.c b/firmware/src/hal/sgx/src/trusted/bip32.c new file mode 120000 index 00000000..6bb570cb --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/bip32.c @@ -0,0 +1 @@ +../../../x86/src/bip32.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/bip32.h b/firmware/src/hal/sgx/src/trusted/bip32.h new file mode 120000 index 00000000..b57dfb7d --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/bip32.h @@ -0,0 +1 @@ +../../../x86/src/bip32.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/communication.c b/firmware/src/hal/sgx/src/trusted/communication.c new file mode 120000 index 00000000..096d96b1 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/communication.c @@ -0,0 +1 @@ +../../../x86/src/communication.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/endian.c b/firmware/src/hal/sgx/src/trusted/endian.c new file mode 120000 index 00000000..153fd780 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/endian.c @@ -0,0 +1 @@ +../../../x86/src/endian.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/endian.h b/firmware/src/hal/sgx/src/trusted/endian.h new file mode 120000 index 00000000..213c0feb --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/endian.h @@ -0,0 +1 @@ +../../../x86/src/endian.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/endorsement.c b/firmware/src/hal/sgx/src/trusted/endorsement.c new file mode 100644 index 00000000..4d995e2b --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/endorsement.c @@ -0,0 +1,180 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +// TODO: remove usage of secp256k1 here upon final implementation +// (only needed here for mock implementation) +#include + +#include "hal/constants.h" +#include "hal/endorsement.h" +#include "hal/seed.h" +#include "hal/exceptions.h" +#include "hal/log.h" + +#include "random.h" + +// TODO: remove HMAC-SHA256 entirely upon final implementation, +// (only needed for mock implementation) +#include "hmac_sha256.h" + +static secp256k1_context* sp_ctx = NULL; + +// Test key for mock implementation +static const uint8_t attestation_key[] = { + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, +}; +// Test code hash for mock implementation +static const uint8_t attestation_code_hash[] = { + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, +}; +static uint8_t attestation_pubkey[PUBKEY_UNCMP_LENGTH]; + +static size_t tweak_sign(const unsigned char* key, + const unsigned char* tweak, + const unsigned char* hash, + unsigned char* sig) { + unsigned char tweaked_key[PRIVATE_KEY_LENGTH]; + secp256k1_ecdsa_signature sp_sig; + size_t sig_serialized_size = MAX_SIGNATURE_LENGTH; + + // Tweak private key + memmove(tweaked_key, key, sizeof(tweaked_key)); + if (!secp256k1_ec_seckey_tweak_add(sp_ctx, tweaked_key, tweak)) + return 0; + + // Sign and serialize as DER + secp256k1_ecdsa_sign(sp_ctx, &sp_sig, hash, tweaked_key, NULL, NULL); + secp256k1_ecdsa_signature_serialize_der( + sp_ctx, sig, &sig_serialized_size, &sp_sig); + + return (int)sig_serialized_size; +} + +static uint8_t derive_pubkey_uncmp(const unsigned char* key, + unsigned char* dest) { + secp256k1_pubkey pubkey; + size_t dest_size = PUBKEY_UNCMP_LENGTH; + + // Calculate the public key and serialize it according to + // the compressed argument + if (!secp256k1_ec_pubkey_create(sp_ctx, &pubkey, key)) { + return 0; + } + + secp256k1_ec_pubkey_serialize( + sp_ctx, dest, &dest_size, &pubkey, SECP256K1_EC_UNCOMPRESSED); + + return (uint8_t)dest_size; +} + +bool endorsement_init() { + // Init the secp256k1 context + if (!sp_ctx) + sp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + // Compute attestation public key + if (derive_pubkey_uncmp(attestation_key, attestation_pubkey) != + PUBKEY_UNCMP_LENGTH) { + LOG("Error getting uncompressed public key for mock attestation key\n"); + return false; + } + LOG("Loaded mock attestation key:\n"); + LOG_HEX("\tKey: ", attestation_key, sizeof(attestation_key)); + LOG_HEX("\tPublic key: ", attestation_pubkey, sizeof(attestation_pubkey)); + + return true; +} + +bool endorsement_sign(uint8_t* msg, + size_t msg_size, + uint8_t* signature_out, + uint8_t* signature_out_length) { + + uint8_t tweak[HMAC_SHA256_SIZE]; + uint8_t hash[HASH_LENGTH]; + + if (*signature_out_length < MAX_SIGNATURE_LENGTH) { + return false; + } + + sha256(msg, msg_size, hash, sizeof(hash)); + + if (hmac_sha256(attestation_code_hash, + sizeof(attestation_code_hash), + attestation_pubkey, + sizeof(attestation_pubkey), + tweak, + sizeof(tweak)) != sizeof(tweak)) { + LOG("Error computing tweak for endorsement\n"); + return false; + } + + if (*signature_out_length < MAX_SIGNATURE_LENGTH) { + LOG("Output buffer for signature too small: %u bytes\n", + *signature_out_length); + return false; + } + + *signature_out_length = + tweak_sign(attestation_key, tweak, hash, signature_out); + + return true; +} + +bool endorsement_get_code_hash(uint8_t* code_hash_out, + uint8_t* code_hash_out_length) { + + if (*code_hash_out_length < HASH_LENGTH) { + LOG("Output buffer for code hash too small: %u bytes\n", + *code_hash_out_length); + return false; + } + + memmove( + code_hash_out, attestation_code_hash, sizeof(attestation_code_hash)); + *code_hash_out_length = sizeof(attestation_code_hash); + + return true; +} + +bool endorsement_get_public_key(uint8_t* public_key_out, + uint8_t* public_key_out_length) { + if (*public_key_out_length < PUBKEY_UNCMP_LENGTH) { + LOG("Output buffer for public key too small: %u bytes\n", + *public_key_out_length); + return false; + } + + memcpy(public_key_out, attestation_pubkey, sizeof(attestation_pubkey)); + *public_key_out_length = sizeof(attestation_pubkey); + + return true; +} \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/exceptions.c b/firmware/src/hal/sgx/src/trusted/exceptions.c new file mode 120000 index 00000000..e5affcf0 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/exceptions.c @@ -0,0 +1 @@ +../../../x86/src/exceptions.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/hash.c b/firmware/src/hal/sgx/src/trusted/hash.c new file mode 120000 index 00000000..095bbd93 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/hash.c @@ -0,0 +1 @@ +../../../x86/src/hash.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/hmac_sha256.c b/firmware/src/hal/sgx/src/trusted/hmac_sha256.c new file mode 120000 index 00000000..f260ff64 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/hmac_sha256.c @@ -0,0 +1 @@ +../../../x86/src/hmac_sha256.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/hmac_sha256.h b/firmware/src/hal/sgx/src/trusted/hmac_sha256.h new file mode 120000 index 00000000..9fd6de87 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/hmac_sha256.h @@ -0,0 +1 @@ +../../../x86/src/hmac_sha256.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/hmac_sha512.c b/firmware/src/hal/sgx/src/trusted/hmac_sha512.c new file mode 120000 index 00000000..5e2c42e7 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/hmac_sha512.c @@ -0,0 +1 @@ +../../../x86/src/hmac_sha512.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/hmac_sha512.h b/firmware/src/hal/sgx/src/trusted/hmac_sha512.h new file mode 120000 index 00000000..c4a537a5 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/hmac_sha512.h @@ -0,0 +1 @@ +../../../x86/src/hmac_sha512.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/keccak256.c b/firmware/src/hal/sgx/src/trusted/keccak256.c new file mode 120000 index 00000000..a7432b9e --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/keccak256.c @@ -0,0 +1 @@ +../../../x86/src/keccak256.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/keccak256.h b/firmware/src/hal/sgx/src/trusted/keccak256.h new file mode 120000 index 00000000..52e5a8c8 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/keccak256.h @@ -0,0 +1 @@ +../../../x86/src/keccak256.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/log.c b/firmware/src/hal/sgx/src/trusted/log.c new file mode 100644 index 00000000..12393df2 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/log.c @@ -0,0 +1,44 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "hal/log.h" + +// #ifdef DEBUG_BUILD +#if 1 // For now, we always output enclave logs + +void LOG_HEX(const char *prefix, const void *buffer, const size_t size) { + fprintf(stderr, TRUSTED_LOG_PREFIX); + fprintf(stderr, "%s ", prefix); + if (size > 0) { + fprintf(stderr, "0x"); + for (unsigned int i = 0; i < size; i++) { + fprintf(stderr, "%02x", ((unsigned char *)buffer)[i]); + } + } else { + fprintf(stderr, "EMPTY"); + } + fprintf(stderr, "\n"); +} + +#endif \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/nvmem.c b/firmware/src/hal/sgx/src/trusted/nvmem.c new file mode 100644 index 00000000..015e039f --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/nvmem.c @@ -0,0 +1,123 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "hal/nvmem.h" +#include "hal/log.h" + +#include "secret_store.h" + +#define MAX_NVM_BLOCKS 5 + +typedef struct { + char* key; + void* addr; + size_t size; +} nvm_block_t; + +static nvm_block_t nvm_blocks[MAX_NVM_BLOCKS]; +static unsigned int nvm_blocks_count; + +#define STORE_PREFIX "nvmem-" + +static char* store_key_for(char* key) { + size_t key_size = strlen(STORE_PREFIX) + strlen(key); + char* store_key = malloc(key_size + 1); + strcpy(store_key, ""); + strcat(store_key, STORE_PREFIX); + strcat(store_key, key); + return store_key; +} + +void nvmem_init() { + memset(nvm_blocks, 0, sizeof(nvm_blocks)); + nvm_blocks_count = 0; +} + +void nvmem_register_block(char* key, void* addr, size_t size) { + nvm_blocks[nvm_blocks_count].key = key; + nvm_blocks[nvm_blocks_count].addr = addr; + nvm_blocks[nvm_blocks_count].size = size; + nvm_blocks_count++; +} + +static void clear_blocks() { + for (unsigned int i = 0; i < nvm_blocks_count; i++) { + memset((uint8_t*)nvm_blocks[i].addr, 0, nvm_blocks[i].size); + } +} + +bool nvmem_load() { + LOG("Loading NVM blocks...\n"); + for (unsigned int i = 0; i < nvm_blocks_count; i++) { + char* key = store_key_for(nvm_blocks[i].key); + if (sest_exists(key)) { + uint8_t* tmp = malloc(nvm_blocks[i].size); + if (sest_read(key, tmp, nvm_blocks[i].size) == nvm_blocks[i].size) { + memcpy((uint8_t*)nvm_blocks[i].addr, tmp, nvm_blocks[i].size); + } else { + LOG("Error loading NVM block <%s>\n", nvm_blocks[i].key); + clear_blocks(); + free(key); + return false; + } + free(tmp); + } else { + LOG("No record found for NVM block <%s>\n", nvm_blocks[i].key); + memset((uint8_t*)nvm_blocks[i].addr, 0, nvm_blocks[i].size); + } + free(key); + } + return true; +} + +static bool nvmem_flush() { + LOG("Flushing NVM blocks...\n"); + for (unsigned int i = 0; i < nvm_blocks_count; i++) { + char* key = store_key_for(nvm_blocks[i].key); + if (!sest_write( + key, (uint8_t*)nvm_blocks[i].addr, nvm_blocks[i].size)) { + LOG("Error flushing NVM block <%s>\n", nvm_blocks[i].key); + free(key); + return false; + } + free(key); + } + return true; +} + +bool nvmem_write(void* dst, void* src, unsigned int length) { + if (src == NULL) { + // Treat as memory reset + memset(dst, 0, length); + } else { + // Treat as normal copy + memmove(dst, src, length); + } + // Flush to disk + return nvmem_flush(); +} \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/platform.c b/firmware/src/hal/sgx/src/trusted/platform.c new file mode 120000 index 00000000..ddeafb2f --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/platform.c @@ -0,0 +1 @@ +../../../x86/src/platform.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/random.c b/firmware/src/hal/sgx/src/trusted/random.c new file mode 100644 index 00000000..6fc2752a --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/random.c @@ -0,0 +1,30 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "random.h" +#include "hsm_t.h" + +bool random_getrandom(void *buffer, size_t length) { + return oe_random(buffer, length) == OE_OK; +} \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/random.h b/firmware/src/hal/sgx/src/trusted/random.h new file mode 100644 index 00000000..6b16f4f3 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/random.h @@ -0,0 +1,41 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __SGX_RANDOM_H +#define __SGX_RANDOM_H + +#include +#include + +/** + * @brief Get length random bytes into buffer + * + * @param buffer the buffer to which to output the random bytes + * @param length the number of bytes to output + * + * @returns whether random generation was successful + */ +bool random_getrandom(void *buffer, size_t length); + +#endif // __SGX_RANDOM_H \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/secret_store.c b/firmware/src/hal/sgx/src/trusted/secret_store.c new file mode 100644 index 00000000..f2a41d64 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/secret_store.c @@ -0,0 +1,274 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "hal/platform.h" +#include "hal/log.h" +#include "secret_store.h" +#include "hsm_t.h" + +#define SEAL_POLICY_UNIQUE 1 +#define SEAL_POLICY_PRODUCT 2 + +#ifdef DEBUG_BUILD +#define SEAL_POLICY SEAL_POLICY_PRODUCT +#else +#define SEAL_POLICY SEAL_POLICY_UNIQUE +#endif + +#define SEST_ERROR (0) + +#define MAX_BLOB_SIZE (1024 * 1024) + +// To avoid performing dynamic memory allocation whenever we need to read a +// secret, we use this static buffer to temporarily store the sealed blobs we +// read from the untrusted modules. +static uint8_t G_secrets_buffer[MAX_BLOB_SIZE]; + +// The file format of the sealed secrets. This is the format we use to read and +// write sealed the data to disk. +typedef struct { + size_t blob_size; + uint8_t* blob; +} sealed_secret_t; + +/** + * @brief Obtains the plaintext data from a sealed secret. + * + * @param sealed_secret The sealed secret to unseal. + * @param dest The destination buffer for the unsealed data. This must be + * pre-allocated and large enough to hold the unsealed data. + * @param dest_length The length of the pre-allocated destination buffer. + * + * @returns the length of the unsealed data, or SEST_ERROR upon error + */ +static uint8_t unseal_data(const sealed_secret_t* sealed_secret, + uint8_t* dest, + size_t dest_length) { + if (sealed_secret->blob_size > MAX_BLOB_SIZE) { + LOG("Sealed blob size is too large\n"); + goto unseal_data_error; + } + + uint8_t* plaintext = NULL; + size_t plaintext_size = 0; + oe_result_t result = oe_unseal(sealed_secret->blob, + sealed_secret->blob_size, + NULL, + 0, + &plaintext, + &plaintext_size); + if (result != OE_OK) { + LOG("Unsealing failed with result=%u (%s)\n", + result, + oe_result_str(result)); + goto unseal_data_error; + } + + if (plaintext_size > dest_length) { + LOG("Unsealed data is too large\n"); + goto unseal_data_error; + } + + platform_memmove(dest, plaintext, plaintext_size); + oe_free(plaintext); + return plaintext_size; + +unseal_data_error: + if (plaintext) + oe_free(plaintext); + return SEST_ERROR; +} + +/** + * @brief Seals the given data into a sealed secret. + * + * @param data The data to seal. + * @param data_length The length of the data to seal. + * @param sealed_secret The destination for the sealed secret. + */ +static bool seal_data(uint8_t* data, + size_t data_length, + sealed_secret_t* sealed_secret) { + uint8_t* blob = NULL; + size_t blob_size = 0; + const oe_seal_setting_t settings[] = {OE_SEAL_SET_POLICY(SEAL_POLICY)}; + oe_result_t result = oe_seal(NULL, + settings, + sizeof(settings) / sizeof(settings[0]), + data, + data_length, + NULL, + 0, + &blob, + &blob_size); + if (result != OE_OK) { + LOG("Sealing failed with result=%u (%s)\n", + result, + oe_result_str(result)); + oe_free(blob); + return false; + } + + sealed_secret->blob = blob; + sealed_secret->blob_size = blob_size; + return true; +} + +// Public API +bool sest_init() { + explicit_bzero(G_secrets_buffer, sizeof(G_secrets_buffer)); + return true; +} + +bool sest_exists(char* key) { + LOG("Attempting determine secret existence for <%s>...\n", key); + + bool exists; + oe_result_t oe_result = ocall_kvstore_exists(&exists, key); + + if (oe_result != OE_OK) { + LOG("Key-value store exists query failed with result=%u (%s)\n", + oe_result, + oe_result_str(oe_result)); + return false; + } + + return exists; +} + +uint8_t sest_read(char* key, uint8_t* dest, size_t dest_length) { + LOG("Attempting to read secret for <%s>...\n", key); + + size_t blob_size = 0; + oe_result_t oe_result = ocall_kvstore_get( + &blob_size, key, G_secrets_buffer, sizeof(G_secrets_buffer)); + if (oe_result != OE_OK) { + LOG("Key-value store read failed with result=%u (%s)\n", + oe_result, + oe_result_str(oe_result)); + return SEST_ERROR; + } + + if (!blob_size) { + LOG("No secret found for key <%s>\n", key); + return SEST_ERROR; + } + + // This is just an extra sanity check, this can never happen in + // practice since the ocall will fail if the blob size + // is too large for the buffer. + if (blob_size > sizeof(G_secrets_buffer)) { + LOG("Sealed blob too large\n"); + return SEST_ERROR; + } + + sealed_secret_t sealed_secret = { + .blob_size = blob_size, + .blob = G_secrets_buffer, + }; + + uint8_t plaintext_length = unseal_data(&sealed_secret, dest, dest_length); + if (plaintext_length == SEST_ERROR) { + LOG("Unable to read secret stored in key <%s>\n", key); + return SEST_ERROR; + } + + // Clean up the buffer just in case. + explicit_bzero(G_secrets_buffer, sizeof(G_secrets_buffer)); + + return plaintext_length; +} + +bool sest_write(char* key, uint8_t* secret, size_t secret_length) { + LOG("Attempting to write secret for <%s>...\n", key); + if (!secret_length) { + LOG("Invalid zero-length secret given for key <%s>\n", key); + return false; + } + + sealed_secret_t sealed_secret = { + .blob_size = 0, + .blob = NULL, + }; + + if (!seal_data(secret, secret_length, &sealed_secret)) { + LOG("Error sealing secret for key <%s>\n", key); + return false; + } + + if (sealed_secret.blob_size > MAX_BLOB_SIZE) { + LOG("Sealed blob too large\n"); + goto sest_write_error; + } + + bool save_success = false; + oe_result_t oe_result = ocall_kvstore_save( + &save_success, key, sealed_secret.blob, sealed_secret.blob_size); + if (oe_result != OE_OK) { + LOG("Key-value store write failed with result=%u (%s)\n", + oe_result, + oe_result_str(oe_result)); + goto sest_write_error; + } + + if (!save_success) { + LOG("Error saving secret for key <%s>\n", key); + goto sest_write_error; + } + + oe_free(sealed_secret.blob); + return true; + +sest_write_error: + if (sealed_secret.blob) + oe_free(sealed_secret.blob); + return false; +} + +bool sest_remove(char* key) { + bool remove_success = false; + oe_result_t oe_result = ocall_kvstore_remove(&remove_success, key); + if (oe_result != OE_OK) { + LOG("ocall_oestore_remove_secret() failed with result=%u (%s)\n", + oe_result, + oe_result_str(oe_result)); + return false; + } + + if (!remove_success) { + LOG("Error removing secret for key <%s>\n", key); + return false; + } + + return true; +} diff --git a/firmware/src/hal/sgx/src/trusted/secret_store.h b/firmware/src/hal/sgx/src/trusted/secret_store.h new file mode 100644 index 00000000..ee2483ce --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/secret_store.h @@ -0,0 +1,90 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __TRUSTED_SECRET_STORE_H +#define __TRUSTED_SECRET_STORE_H + +#include +#include + +/** + * @brief Initializes the secret store + * + * @returns whether the secret store was successfully initialized + */ +bool sest_init(); + +/** + * @brief Determine whether a secret exists in the store + * + * @param key the key for the secret + * + * @returns whether the secret exists. Note that this doesn't + * indicate whether attempting to read the secret will yield an + * error, only whether a potential secret can be read at the + * given key. + */ +bool sest_exists(char* key); + +/** + * @brief Read a secret from the store + * + * @param key the key for the secret + * @param dest the destination buffer for the read secret + * @param dest_length the length of the destination buffer + * + * @returns the length of the secret read, or ZERO upon error + */ +uint8_t sest_read(char* key, uint8_t* dest, size_t dest_length); + +/** + * @brief Write a secret to the store + * + * @param key the key for the secret + * @param secret the secret to write + * @param secret_length the secret length + * + * @returns whether the write was successful + */ +bool sest_write(char* key, uint8_t* secret, size_t secret_length); + +/** + * @brief Write protect a secret in the store + * + * @param key the key to protect + * + * @returns whether the write protection was successfully applied + */ +bool sest_protect(char* key); + +/** + * @brief Remove a stored secret + * + * @param the key for the secret + * + * @returns whether the deletion was successful + */ +bool sest_remove(char* key); + +#endif // __TRUSTED_SECRET_STORE_H diff --git a/firmware/src/hal/sgx/src/trusted/seed.c b/firmware/src/hal/sgx/src/trusted/seed.c new file mode 100644 index 00000000..8fa0168c --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/seed.c @@ -0,0 +1,212 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "hal/hash.h" +#include "hal/seed.h" +#include "hal/constants.h" +#include "hal/log.h" + +#include "secret_store.h" +#include "bip32.h" +#include "random.h" + +#define SEST_SEED_KEY "seed" + +// Globals +static bool G_seed_available; +static uint8_t G_seed[SEED_LENGTH]; + +static secp256k1_context* sp_ctx = NULL; + +bool seed_init() { + // Init the secp256k1 context + if (!sp_ctx) + sp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + memset(G_seed, 0, sizeof(G_seed)); + G_seed_available = false; + + if (!sest_exists(SEST_SEED_KEY)) { + // Module is in a wiped state + return true; + } + + // Read seed + uint8_t seed_length = 0; + if (!(seed_length = sest_read(SEST_SEED_KEY, G_seed, sizeof(G_seed)))) { + LOG("Could not load the current seed\n"); + return false; + } + + // Make sure seed is sound + if (seed_length != sizeof(G_seed)) { + LOG("Detected invalid seed\n"); + return false; + } + + G_seed_available = true; + LOG("Seed loaded\n"); + + return true; +} + +bool seed_wipe() { + bool success = sest_remove(SEST_SEED_KEY); + memset(G_seed, 0, sizeof(G_seed)); + G_seed_available = false; + + return success; +} + +bool seed_generate(uint8_t* client_seed, uint8_t client_seed_size) { + if (G_seed_available) { + LOG("Seed already exists\n"); + return false; + } + + if (client_seed_size != SEED_LENGTH) { + LOG("Invalid client seed size\n"); + return false; + } + + uint8_t random_bytes[SEED_LENGTH]; + if (!random_getrandom(random_bytes, sizeof(random_bytes))) { + LOG("Error generating random seed\n"); + return false; + } + + for (size_t i = 0; i < SEED_LENGTH; i++) { + G_seed[i] = random_bytes[i] ^ client_seed[i]; + } + + if (!sest_write(SEST_SEED_KEY, G_seed, SEED_LENGTH)) { + LOG("Error persisting generated seed\n"); + memset(G_seed, 0, sizeof(G_seed)); + return false; + } + + G_seed_available = true; + printf("Seed generated\n"); + return true; +} + +static bool derive_privkey(uint32_t* path, + uint8_t path_length, + uint8_t* privkey_out) { + if (!bip32_derive_private( + privkey_out, G_seed, sizeof(G_seed), path, path_length)) { + return false; + } + + return true; +} + +bool seed_available() { + return G_seed_available; +} + +bool seed_derive_pubkey(uint32_t* path, + uint8_t path_length, + uint8_t* pubkey_out, + uint8_t* pubkey_out_length) { + secp256k1_pubkey sp_pubkey; + uint8_t derived_privkey[PRIVATE_KEY_LENGTH]; + + LOG("Deriving public key for path...\n"); + + // Derive the private key + if (!derive_privkey(path, path_length, derived_privkey)) { + LOG("Error deriving private key for public key gathering\n"); + return false; + } + + // Derive the public key and serialize it uncompressed + if (!secp256k1_ec_pubkey_create(sp_ctx, &sp_pubkey, derived_privkey)) { + LOG("Error deriving public key\n"); + return false; + } + + if (*pubkey_out_length < PUBKEY_UNCMP_LENGTH) { + LOG("Overflow while deriving public key\n"); + return false; + } + size_t temp_length = *pubkey_out_length; + secp256k1_ec_pubkey_serialize(sp_ctx, + pubkey_out, + &temp_length, + &sp_pubkey, + SECP256K1_EC_UNCOMPRESSED); + + if (temp_length != PUBKEY_UNCMP_LENGTH) { + LOG("Unexpected error while deriving public key\n"); + return false; + } + *pubkey_out_length = (uint8_t)temp_length; + + LOG_HEX("Pubkey for path is:", pubkey_out, *pubkey_out_length); + + return true; +} + +bool seed_sign(uint32_t* path, + uint8_t path_length, + uint8_t* hash32, + uint8_t* sig_out, + uint8_t* sig_out_length) { + secp256k1_ecdsa_signature sp_sig; + uint8_t derived_privkey[PRIVATE_KEY_LENGTH]; + + if (*sig_out_length < MAX_SIGNATURE_LENGTH) { + LOG("Overflow while signing\n"); + return false; + } + + LOG_HEX("Signing hash:", hash32, HASH_LENGTH); + + // Derive the private key + if (!derive_privkey(path, path_length, derived_privkey)) { + LOG("Error deriving private key for signing\n"); + return false; + } + + // Sign and serialize as DER + secp256k1_ecdsa_sign(sp_ctx, &sp_sig, hash32, derived_privkey, NULL, NULL); + size_t temp_length = *sig_out_length; + secp256k1_ecdsa_signature_serialize_der( + sp_ctx, sig_out, &temp_length, &sp_sig); + if (temp_length > MAX_SIGNATURE_LENGTH) { + LOG("Overflow while signing\n"); + return false; + } + *sig_out_length = (uint8_t)temp_length; + + LOG_HEX("Signature is: ", sig_out, *sig_out_length); + + return true; +} diff --git a/firmware/src/hal/sgx/src/trusted/sha256.c b/firmware/src/hal/sgx/src/trusted/sha256.c new file mode 120000 index 00000000..4feddbd1 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/sha256.c @@ -0,0 +1 @@ +../../../common/src/sha256.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/sha256.h b/firmware/src/hal/sgx/src/trusted/sha256.h new file mode 120000 index 00000000..b7a70b63 --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/sha256.h @@ -0,0 +1 @@ +../../../common/src/sha256.h \ No newline at end of file diff --git a/firmware/src/hal/x86/src/access.c b/firmware/src/hal/x86/src/access.c new file mode 100644 index 00000000..66fbeed9 --- /dev/null +++ b/firmware/src/hal/x86/src/access.c @@ -0,0 +1,31 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "hal/access.h" + +bool access_is_locked() { + // For now, the x86 implementation does not have a "locked" + // state + return false; +} diff --git a/firmware/src/hal/x86/src/bip32.c b/firmware/src/hal/x86/src/bip32.c index 7ccd8460..e3c25545 100644 --- a/firmware/src/hal/x86/src/bip32.c +++ b/firmware/src/hal/x86/src/bip32.c @@ -1,16 +1,46 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #include "bip32.h" #include "hal/constants.h" #include "hal/log.h" +#include "hmac_sha512.h" +#include "endian.h" +#include "bigdigits.h" +#include "bigdigits_helper.h" #include #include #include #include +#include #define BIP32_PREFIX "m/" #define MIN_PATH_LENGTH (strlen("m/0/0/0/0/0")) #define MAX_PART_DECIMAL_DIGITS 10 #define EXPECTED_PARTS BIP32_PATH_NUMPARTS +#define NODE_LENGTH 64 #ifdef DEBUG_BIP32 #define DEBUG_LOG(...) LOG(__VA_ARGS__) @@ -18,6 +48,13 @@ #define DEBUG_LOG(...) #endif +static const uint8_t secp256k1_order[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, + 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41}; + +static secp256k1_context* sp_ctx = NULL; + size_t bip32_parse_path(const char* path, uint8_t* out) { size_t pos, start, pathlen; int parts; @@ -73,7 +110,7 @@ size_t bip32_parse_path(const char* path, uint8_t* out) { } index += indexint; // Output the index in LE - for (int i = 0; i < sizeof(uint32_t); i++) { + for (int i = 0; i < (int)sizeof(uint32_t); i++) { out[1 + (parts * sizeof(uint32_t)) + i] = (index >> (8 * i)) & 0xFF; } @@ -96,3 +133,135 @@ size_t bip32_parse_path(const char* path, uint8_t* out) { DEBUG_LOG("Unexpected code path reached for path: %s\n", path); return 0; } + +/** + * Following portion taken from + * https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#define PRIVATE_KEY_DIGITS (PRIVATE_KEY_LENGTH / sizeof(DIGIT_T)) + +static void seed_to_node(uint8_t* master_node, + const uint8_t* seed, + const unsigned int seed_length) { + hmac_sha512( + master_node, (const uint8_t*)"Bitcoin seed", 12, seed, seed_length); +} + +bool bip32_derive_private(uint8_t* out, + const uint8_t* seed, + const unsigned int seed_length, + const uint32_t* path, + const unsigned int path_length) { + uint8_t current_node[NODE_LENGTH]; + uint8_t temp[NODE_LENGTH]; + DIGIT_T tempbig_a[PRIVATE_KEY_DIGITS + 1], + tempbig_b[PRIVATE_KEY_DIGITS + 1]; + DIGIT_T tempbig_c[PRIVATE_KEY_DIGITS + 1], + tempbig_d[PRIVATE_KEY_DIGITS + 1]; + uint8_t hmac_data[1 + 32 + 4]; // prefix + private key + i + secp256k1_pubkey pubkey; + size_t pubkey_serialised_size; + + // Init the secp256k1 context + if (!sp_ctx) + sp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + // Compute the master node from the seed + seed_to_node(current_node, seed, seed_length); + + for (unsigned int i = 0; i < path_length; i++) { + if (path[i] & 0x80000000) { + // Hardened derivation. + hmac_data[0] = 0x00; + memcpy(&hmac_data[1], current_node, 32); + } else { + // Non-hardened derivation. + if (!secp256k1_ec_pubkey_create(sp_ctx, &pubkey, current_node)) { + DEBUG_LOG("Error deriving public key from private key\n"); + return false; + } + + pubkey_serialised_size = PUBKEY_CMP_LENGTH; + secp256k1_ec_pubkey_serialize(sp_ctx, + hmac_data, + &pubkey_serialised_size, + &pubkey, + SECP256K1_EC_COMPRESSED); + + if (pubkey_serialised_size != PUBKEY_CMP_LENGTH) { + DEBUG_LOG("Unexpected serialised public key size\n"); + return false; + } + } + write_uint32_be(&hmac_data[33], path[i]); + + // Need to write to temp here (instead of current_node) because part of + // current_node is used as the key. + hmac_sha512(temp, ¤t_node[32], 32, hmac_data, sizeof(hmac_data)); + + // First 32 bytes of temp = I_L. Compute k_i + if (!secp256k1_ec_seckey_verify(sp_ctx, temp)) { + DEBUG_LOG( + "Overflow during derivation, use a different one (I_L)\n"); + return false; + } + parse_bigint_be(temp, 32, tempbig_a, PRIVATE_KEY_DIGITS + 1); + + if (!secp256k1_ec_seckey_verify(sp_ctx, current_node)) { + DEBUG_LOG("Invalid key during derivation, use a different path " + "(invalid k_par)\n"); + return false; + } + parse_bigint_be(current_node, 32, tempbig_b, PRIVATE_KEY_DIGITS + 1); + + mpAdd(tempbig_a, tempbig_a, tempbig_b, PRIVATE_KEY_DIGITS + 1); + parse_bigint_be(secp256k1_order, 32, tempbig_b, PRIVATE_KEY_DIGITS + 1); + mpDivide(tempbig_d, + tempbig_c, + tempbig_a, + PRIVATE_KEY_DIGITS + 1, + tempbig_b, + PRIVATE_KEY_DIGITS + 1); + dump_bigint_be(current_node, tempbig_c, PRIVATE_KEY_DIGITS); + if (!secp256k1_ec_seckey_verify(sp_ctx, current_node)) { + DEBUG_LOG( + "Invalid derived key, use a different path (invalid k_i)\n"); + return false; + } + + // Last 32 bytes = I_R = c_i + memcpy(¤t_node[32], &temp[32], 32); + } + memcpy(out, current_node, 32); + return true; // success +} diff --git a/firmware/src/hal/x86/src/bip32.h b/firmware/src/hal/x86/src/bip32.h index 29af0251..a80bafef 100644 --- a/firmware/src/hal/x86/src/bip32.h +++ b/firmware/src/hal/x86/src/bip32.h @@ -27,6 +27,7 @@ #include #include +#include #include "hal/constants.h" @@ -44,4 +45,21 @@ */ size_t bip32_parse_path(const char* path, uint8_t* out); +/** + * @brief Derive a private key from the given seed and bip32 path + * + * @param out the destination buffer for the derived key + * @param seed the seed to use for derivation + * @param seed_length the seed length in bytes + * @param path the bip32 path + * @param path_length the bip32 path length in derivation steps + * + * @returns whether derivation succeeded + */ +bool bip32_derive_private(uint8_t* out, + const uint8_t* seed, + const unsigned int seed_length, + const uint32_t* path, + const unsigned int path_length); + #endif // __HAL_BIP32_H diff --git a/firmware/src/hal/x86/src/endian.c b/firmware/src/hal/x86/src/endian.c new file mode 100644 index 00000000..2d72da7f --- /dev/null +++ b/firmware/src/hal/x86/src/endian.c @@ -0,0 +1,77 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Taken from https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file endian.c + * + * \brief Contains functions which perform endian-specific type conversion. + * + * This file is licensed as described by the file LICENCE. + */ + +#include "endian.h" + +/** Write 32 bit unsigned integer into a byte array in big-endian format. + * \param out The destination byte array. This must have space for at + * least 4 bytes. + * \param in The source integer. + */ +void write_uint32_be(uint8_t *out, uint32_t in) { + out[0] = (uint8_t)(in >> 24); + out[1] = (uint8_t)(in >> 16); + out[2] = (uint8_t)(in >> 8); + out[3] = (uint8_t)in; +} diff --git a/firmware/src/hal/x86/src/endian.h b/firmware/src/hal/x86/src/endian.h new file mode 100644 index 00000000..7e982d81 --- /dev/null +++ b/firmware/src/hal/x86/src/endian.h @@ -0,0 +1,72 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Taken from https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HAL_ENDIAN_H +#define __HAL_ENDIAN_H + +#include + +/** + * @brief Dump the given 32-bit unsigned integer + * into the given buffer as big-endian + * + * @param out the destination buffer + * @param in the unsigned integer to dump + */ +void write_uint32_be(uint8_t *out, uint32_t in); + +#endif // #ifndef __HAL_ENDIAN_H diff --git a/firmware/src/hal/x86/src/endorsement.c b/firmware/src/hal/x86/src/endorsement.c index 8bf7c6fa..f127660f 100644 --- a/firmware/src/hal/x86/src/endorsement.c +++ b/firmware/src/hal/x86/src/endorsement.c @@ -118,9 +118,9 @@ bool endorsement_init(char* att_file_path) { "random endorsement id (key and code hash pair)\n"); // Init new random key and code hash - random_getrandom(attestation_id.key, sizeof(attestation_id.key), 0); - random_getrandom( - attestation_id.code_hash, sizeof(attestation_id.code_hash), 0); + random_getrandom(attestation_id.key, sizeof(attestation_id.key)); + random_getrandom(attestation_id.code_hash, + sizeof(attestation_id.code_hash)); // Write attestation id to the file if (!write_attestation_id_file(att_file_path)) { diff --git a/firmware/src/hal/x86/src/exceptions.c b/firmware/src/hal/x86/src/exceptions.c index 64269f06..e114bbba 100644 --- a/firmware/src/hal/x86/src/exceptions.c +++ b/firmware/src/hal/x86/src/exceptions.c @@ -44,10 +44,6 @@ * (https://github.com/LedgerHQ/nanos-secure-sdk/blob/nanos-1314/include/os.h) */ -#ifndef HSM_PLATFORM_X86 -#define HSM_PLATFORM_X86 -#endif - #include "hal/exceptions.h" static try_context_t G_try_last_open_context_var; diff --git a/firmware/src/hal/x86/src/hash.c b/firmware/src/hal/x86/src/hash.c index 39b43f93..4dff8843 100644 --- a/firmware/src/hal/x86/src/hash.c +++ b/firmware/src/hal/x86/src/hash.c @@ -23,8 +23,6 @@ */ #include "hal/hash.h" -#include "sha256.h" -#include "keccak256.h" // *** sha256 *** bool hash_sha256_init(hash_sha256_ctx_t* ctx) { diff --git a/firmware/src/hal/x86/src/hmac_sha256.c b/firmware/src/hal/x86/src/hmac_sha256.c index 05292e9c..4ffa5506 100644 --- a/firmware/src/hal/x86/src/hmac_sha256.c +++ b/firmware/src/hal/x86/src/hmac_sha256.c @@ -24,7 +24,7 @@ /** * Taken from https://github.com/h5p9sl/hmac_sha256 and - * adapted for use with the TCPSigner by RSK Labs Ltd + * adapted for use with the powHSM HAL by RSK Labs Ltd */ /* diff --git a/firmware/src/hal/x86/src/hmac_sha256.h b/firmware/src/hal/x86/src/hmac_sha256.h index ad2f7fc4..46bf7ff2 100644 --- a/firmware/src/hal/x86/src/hmac_sha256.h +++ b/firmware/src/hal/x86/src/hmac_sha256.h @@ -24,7 +24,7 @@ /** * Taken from https://github.com/h5p9sl/hmac_sha256 and - * adapted for use with the TCPSigner by RSK Labs Ltd + * adapted for use with the powHSM HAL by RSK Labs Ltd */ /* diff --git a/firmware/src/hal/x86/src/hmac_sha512.c b/firmware/src/hal/x86/src/hmac_sha512.c new file mode 100644 index 00000000..aaf9a121 --- /dev/null +++ b/firmware/src/hal/x86/src/hmac_sha512.c @@ -0,0 +1,397 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Taken from https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file hmac_sha512.c + * + * \brief Calculates HMAC-SHA512 hashes. + * + * This file contains an implementation of SHA-512, as well as a wrapper + * around the SHA-512 implementation which converts it into a keyed + * message authentication code. + * + * The SHA-512 implementation is based on the formulae and pseudo-code in + * FIPS PUB 180-4. The HMAC wrapper is based on the pseudo-code in + * FIPS PUB 198. + * + * Since SHA-512 is based on 64 bit operations, the code in sha256.c and + * hash.c cannot be re-used here, despite the essentially identical structure + * of SHA-256 and SHA-512. + */ + +#include "endian.h" +#include "hmac_sha512.h" + +#include +#include +#include +#include + +/** Get maximum of a and b. + * \warning Do not use this if the evaluation of a and b has side effects. + */ +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +/** Get minimum of a and b. + * \warning Do not use this if the evaluation of a and b has side effects. + */ +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define NOINLINE + +#define PROGMEM +/** Use this to access #PROGMEM lookup tables which have dword (32 bit) + * entries. For example, normally you would use `r = dword_table[i];` but + * for a #PROGMEM table, use `r = LOOKUP_DWORD(dword_table[i]);`. */ +#define LOOKUP_DWORD(x) (x) +/** Use this to access #PROGMEM lookup tables which have byte (8 bit) + * entries. For example, normally you would use `r = byte_table[i];` but + * for a #PROGMEM table, use `r = LOOKUP_BYTE(byte_table[i]);`. */ +#define LOOKUP_BYTE(x) (x) +/** Use this to access #PROGMEM lookup tables which have qword (64 bit) + * entries. For example, normally you would use `r = qword_table[i];` but + * for a #PROGMEM table, use `r = LOOKUP_QWORD(qword_table[i]);`. */ +#define LOOKUP_QWORD(x) (x) + +/** Container for 64 bit hash state. */ +typedef struct HashState64Struct { + /** Where final hash value will be placed. */ + uint64_t h[8]; + /** Current index into HashState64#m, ranges from 0 to 15. */ + uint8_t index_m; + /** Current byte within (64 bit) double word of HashState64#m. 0 = most + * significant byte, 7 = least significant byte. */ + uint8_t byte_position_m; + /** 1024 bit message buffer. */ + uint64_t m[16]; + /** Total length of message; updated as bytes are written. */ + uint32_t message_length; +} HashState64; + +/** Constants for SHA-512. See section 4.2.3 of FIPS PUB 180-4. */ +static const uint64_t k[80] PROGMEM = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, + 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, + 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, + 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817}; + +/** 64 bit rotate right. + * \param x The integer to rotate right. + * \param n Number of times to rotate right. + * \return The rotated integer. + */ +static uint64_t rotateRight(const uint64_t x, const uint8_t n) { + return (x >> n) | (x << (64 - n)); +} + +/** Function defined as (4.8) in section 4.1.3 of FIPS PUB 180-4. + * \param x First input integer. + * \param y Second input integer. + * \param z Third input integer. + * \return Non-linear combination of x, y and z. + */ +static uint64_t ch(const uint64_t x, const uint64_t y, const uint64_t z) { + return (x & y) ^ ((~x) & z); +} + +/** Function defined as (4.9) in section 4.1.3 of FIPS PUB 180-4. + * \param x First input integer. + * \param y Second input integer. + * \param z Third input integer. + * \return Non-linear combination of x, y and z. + */ +static uint64_t maj(const uint64_t x, const uint64_t y, const uint64_t z) { + return (x & y) ^ (x & z) ^ (y & z); +} + +/** Function defined as (4.10) in section 4.1.3 of FIPS PUB 180-4. + * \param x Input integer. + * \return Transformed integer. + */ +static uint64_t bigSigma0(const uint64_t x) { + return rotateRight(x, 28) ^ rotateRight(x, 34) ^ rotateRight(x, 39); +} + +/** Function defined as (4.11) in section 4.1.3 of FIPS PUB 180-4. + * \param x Input integer. + * \return Transformed integer. + */ +static uint64_t bigSigma1(const uint64_t x) { + return rotateRight(x, 14) ^ rotateRight(x, 18) ^ rotateRight(x, 41); +} + +/** Function defined as (4.12) in section 4.1.3 of FIPS PUB 180-4. + * \param x Input integer. + * \return Transformed integer. + */ +static uint64_t littleSigma0(const uint64_t x) { + return rotateRight(x, 1) ^ rotateRight(x, 8) ^ (x >> 7); +} + +/** Function defined as (4.13) in section 4.1.3 of FIPS PUB 180-4. + * \param x Input integer. + * \return Transformed integer. + */ +static uint64_t littleSigma1(const uint64_t x) { + return rotateRight(x, 19) ^ rotateRight(x, 61) ^ (x >> 6); +} + +/** Update hash value based on the contents of a full message buffer. + * This implements the pseudo-code in section 6.4.2 of FIPS PUB 180-4. + * \param hs64 The 64 bit hash state to update. + */ +static void sha512Block(HashState64 *hs64) { + uint64_t a, b, c, d, e, f, g, h; + uint64_t t1, t2; + uint8_t t; + uint64_t w[80]; + + for (t = 0; t < 16; t++) { + w[t] = hs64->m[t]; + } + for (t = 16; t < 80; t++) { + w[t] = littleSigma1(w[t - 2]) + w[t - 7] + littleSigma0(w[t - 15]) + + w[t - 16]; + } + a = hs64->h[0]; + b = hs64->h[1]; + c = hs64->h[2]; + d = hs64->h[3]; + e = hs64->h[4]; + f = hs64->h[5]; + g = hs64->h[6]; + h = hs64->h[7]; + for (t = 0; t < 80; t++) { + t1 = h + bigSigma1(e) + ch(e, f, g) + LOOKUP_QWORD(k[t]) + w[t]; + t2 = bigSigma0(a) + maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + hs64->h[0] += a; + hs64->h[1] += b; + hs64->h[2] += c; + hs64->h[3] += d; + hs64->h[4] += e; + hs64->h[5] += f; + hs64->h[6] += g; + hs64->h[7] += h; +} + +/** Clear the message buffer. + * \param hs64 The 64 bit hash state to act on. + */ +static void clearM(HashState64 *hs64) { + hs64->index_m = 0; + hs64->byte_position_m = 0; + memset(hs64->m, 0, sizeof(hs64->m)); +} + +/** Begin calculating hash for new message. + * See section 5.3.5 of FIPS PUB 180-4. + * \param hs64 The 64 bit hash state to initialise. + */ +static void sha512Begin(HashState64 *hs64) { + hs64->message_length = 0; + hs64->h[0] = 0x6a09e667f3bcc908; + hs64->h[1] = 0xbb67ae8584caa73b; + hs64->h[2] = 0x3c6ef372fe94f82b; + hs64->h[3] = 0xa54ff53a5f1d36f1; + hs64->h[4] = 0x510e527fade682d1; + hs64->h[5] = 0x9b05688c2b3e6c1f; + hs64->h[6] = 0x1f83d9abfb41bd6b; + hs64->h[7] = 0x5be0cd19137e2179; + clearM(hs64); +} + +/** Add one more byte to the message buffer and call sha512Block() + * if the message buffer is full. + * \param hs64 The 64 bit hash state to act on. + * \param byte The byte to add. + */ +static void sha512WriteByte(HashState64 *hs64, const uint8_t byte) { + unsigned int pos; + unsigned int shift_amount; + + hs64->message_length++; + pos = (unsigned int)(7 - hs64->byte_position_m); + shift_amount = pos << 3; + hs64->m[hs64->index_m] |= ((uint64_t)byte << shift_amount); + + if (hs64->byte_position_m == 7) { + hs64->index_m++; + } + hs64->byte_position_m = (uint8_t)((hs64->byte_position_m + 1) & 7); + if (hs64->index_m == 16) { + sha512Block(hs64); + clearM(hs64); + } +} + +/** Finalise the hashing of a message by writing appropriate padding and + * length bytes, then write the hash value into a byte array. + * \param out A byte array where the final SHA-512 hash value will be written + * into. This must have space for #SHA512_HASH_LENGTH bytes. + * \param hs64 The 64 bit hash state to act on. + */ +static void sha512Finish(uint8_t *out, HashState64 *hs64) { + uint32_t length_bits; + uint8_t i; + uint8_t buffer[16]; + + // Subsequent calls to sha512WriteByte() will keep incrementing + // message_length, so the calculation of length (in bits) must be + // done before padding. + length_bits = hs64->message_length << 3; + + // Pad using a 1 bit followed by enough 0 bits to get the message buffer + // to exactly 896 bits full. + sha512WriteByte(hs64, (uint8_t)0x80); + while ((hs64->index_m != 14) || (hs64->byte_position_m != 0)) { + sha512WriteByte(hs64, 0); + } + // Write 128 bit length (in bits). + memset(buffer, 0, 16); + write_uint32_be(&(buffer[12]), length_bits); + for (i = 0; i < 16; i++) { + sha512WriteByte(hs64, buffer[i]); + } + for (i = 0; i < 8; i++) { + write_uint32_be(&(out[i * 8]), (uint32_t)(hs64->h[i] >> 32)); + write_uint32_be(&(out[i * 8 + 4]), (uint32_t)hs64->h[i]); + } +} + +/** Calculate a 64 byte HMAC of an arbitrary message and key using SHA-512 as + * the hash function. + * The code in here is based on the description in section 5 + * ("HMAC SPECIFICATION") of FIPS PUB 198. + * \param out A byte array where the HMAC-SHA512 hash value will be written. + * This must have space for #SHA512_HASH_LENGTH bytes. + * \param key A byte array containing the key to use in the HMAC-SHA512 + * calculation. The key can be of any length. + * \param key_length The length, in bytes, of the key. + * \param text A byte array containing the message to use in the HMAC-SHA512 + * calculation. The message can be of any length. + * \param text_length The length, in bytes, of the message. + */ +void hmac_sha512(uint8_t *out, + const uint8_t *key, + const unsigned int key_length, + const uint8_t *text, + const unsigned int text_length) { + unsigned int i; + uint8_t hash[SHA512_HASH_LENGTH]; + uint8_t padded_key[128]; + HashState64 hs64; + + // Determine key. + memset(padded_key, 0, sizeof(padded_key)); + if (key_length <= sizeof(padded_key)) { + memcpy(padded_key, key, key_length); + } else { + sha512Begin(&hs64); + for (i = 0; i < key_length; i++) { + sha512WriteByte(&hs64, key[i]); + } + sha512Finish(padded_key, &hs64); + } + // Calculate hash = H((K_0 XOR ipad) || text). + sha512Begin(&hs64); + for (i = 0; i < sizeof(padded_key); i++) { + sha512WriteByte(&hs64, (uint8_t)(padded_key[i] ^ 0x36)); + } + for (i = 0; i < text_length; i++) { + sha512WriteByte(&hs64, text[i]); + } + sha512Finish(hash, &hs64); + // Calculate H((K_0 XOR opad) || hash). + sha512Begin(&hs64); + for (i = 0; i < sizeof(padded_key); i++) { + sha512WriteByte(&hs64, (uint8_t)(padded_key[i] ^ 0x5c)); + } + for (i = 0; i < sizeof(hash); i++) { + sha512WriteByte(&hs64, hash[i]); + } + sha512Finish(out, &hs64); +} diff --git a/firmware/src/hal/x86/src/hmac_sha512.h b/firmware/src/hal/x86/src/hmac_sha512.h new file mode 100644 index 00000000..6b6fb586 --- /dev/null +++ b/firmware/src/hal/x86/src/hmac_sha512.h @@ -0,0 +1,77 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Taken from https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file hmac_sha512.h + * + * \brief Describes constants and functions exported by hmac_sha512.c. + */ + +#ifndef __HMAC_SHA512_H +#define __HMAC_SHA512_H + +#include + +/** Number of bytes a SHA-512 hash requires. */ +#define SHA512_HASH_LENGTH 64 + +extern void hmac_sha512(uint8_t *out, + const uint8_t *key, + const unsigned int key_length, + const uint8_t *text, + const unsigned int text_length); + +#endif // #ifndef __HMAC_SHA512_H diff --git a/firmware/src/hal/x86/src/log.c b/firmware/src/hal/x86/src/log.c index 3eb673cd..93c2dda4 100644 --- a/firmware/src/hal/x86/src/log.c +++ b/firmware/src/hal/x86/src/log.c @@ -22,10 +22,7 @@ * IN THE SOFTWARE. */ -#ifdef HSM_PLATFORM_X86 - #include -#include #include void LOG(const char *format, ...) { @@ -37,7 +34,7 @@ void LOG(const char *format, ...) { va_end(args); } -void LOG_HEX(const char *prefix, void *buffer, size_t size) { +void LOG_HEX(const char *prefix, const void *buffer, const size_t size) { printf("%s ", prefix); if (size > 0) { printf("0x"); @@ -49,5 +46,3 @@ void LOG_HEX(const char *prefix, void *buffer, size_t size) { } printf("\n"); } - -#endif \ No newline at end of file diff --git a/firmware/src/hal/x86/src/random.c b/firmware/src/hal/x86/src/random.c index c01c6554..8ef18579 100644 --- a/firmware/src/hal/x86/src/random.c +++ b/firmware/src/hal/x86/src/random.c @@ -27,6 +27,6 @@ #include #include -void random_getrandom(void *buffer, size_t length, unsigned int flags) { +void random_getrandom(void *buffer, size_t length) { syscall(SYS_getrandom, buffer, length, 0); } \ No newline at end of file diff --git a/firmware/src/hal/x86/src/random.h b/firmware/src/hal/x86/src/random.h index f20fa992..860ef42a 100644 --- a/firmware/src/hal/x86/src/random.h +++ b/firmware/src/hal/x86/src/random.h @@ -27,6 +27,6 @@ #include -void random_getrandom(void *buffer, size_t length, unsigned int flags); +void random_getrandom(void *buffer, size_t length); #endif // __HAL_RANDOM_H \ No newline at end of file diff --git a/firmware/src/hal/x86/src/seed.c b/firmware/src/hal/x86/src/seed.c index 7d291b29..df8705e3 100644 --- a/firmware/src/hal/x86/src/seed.c +++ b/firmware/src/hal/x86/src/seed.c @@ -152,8 +152,7 @@ bool seed_init(const char* key_file_path, "random set of keys\n"); // Init new random keys for (int i = 0; i < total_private_keys; i++) { - random_getrandom( - private_keys[i].key, sizeof(private_keys[i].key), 0); + random_getrandom(private_keys[i].key, sizeof(private_keys[i].key)); } // Write keys to the file diff --git a/firmware/src/hal/x86/test/bip32/Makefile b/firmware/src/hal/x86/test/bip32/Makefile index d6b661c3..a0ffc42a 100644 --- a/firmware/src/hal/x86/test/bip32/Makefile +++ b/firmware/src/hal/x86/test/bip32/Makefile @@ -27,12 +27,14 @@ ifneq ($(DEBUG),) endif PROG = test.out -OBJS = bip32.o test_bip32.o log.o +OBJS = bip32.o hmac_sha512.o endian.o bigdigits.o bigdigits_helper.o +OBJS += test_bip32.o log.o + all: $(PROG) $(PROG): $(OBJS) - $(CC) $(COVFLAGS) -o $@ $^ + $(CC) $(COVFLAGS) -o $@ $^ -lsecp256k1 .PHONY: clean test clean: diff --git a/firmware/src/hal/x86/test/common.mk b/firmware/src/hal/x86/test/common.mk index 412e9cac..3117b0c8 100644 --- a/firmware/src/hal/x86/test/common.mk +++ b/firmware/src/hal/x86/test/common.mk @@ -21,8 +21,10 @@ # SOFTWARE. INCDIR = ../../../include -SRCDIR = ../../src -CFLAGS = -iquote $(INCDIR) -iquote $(SRCDIR) +X86SRCDIR = ../../src +COMMONSRCDIR = ../../../../common/src +SRCDIR = $(X86SRCDIR):$(COMMONSRCDIR) +CFLAGS = -iquote $(INCDIR) -iquote $(X86SRCDIR) -iquote $(COMMONSRCDIR) CFLAGS += -DHSM_PLATFORM_X86 include ../../../../../coverage/coverage.mk diff --git a/firmware/src/hal/x86/test/run-all.sh b/firmware/src/hal/x86/test/run-all.sh index 48b5e871..e7cc9829 100755 --- a/firmware/src/hal/x86/test/run-all.sh +++ b/firmware/src/hal/x86/test/run-all.sh @@ -1,5 +1,6 @@ #!/bin/bash -BASEDIR=$(dirname $0) +ROOTDIR=$(dirname $0)/../../../../.. +TESTDIR=$(realpath $(dirname $0) --relative-to $ROOTDIR) TESTDIRS="bip32 hmac_sha256" TESTDIRS=${1:-"$TESTDIRS"} @@ -7,7 +8,5 @@ for d in $TESTDIRS; do echo "******************************" echo "Testing $d..." echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null + $ROOTDIR/docker/mware/do-notty-nousb /hsm2/$TESTDIR/$d "make clean test" || exit $? done diff --git a/firmware/src/ledger/signer/Makefile b/firmware/src/ledger/signer/Makefile index 380a4c87..3b439156 100755 --- a/firmware/src/ledger/signer/Makefile +++ b/firmware/src/ledger/signer/Makefile @@ -67,30 +67,9 @@ CFLAGS += -O0 -I$(GCC_INCLUDE) CFLAGS += -Werror CFLAGS += -DHSM_PLATFORM_LEDGER -# Convert min required difficulty to what the compiler expects -ifneq ($(TARGET_DIFFICULTY),) -CONVERTED_MRD = $(shell python make-difficulty.py $(TARGET_DIFFICULTY)) -$(info Building with min required difficulty set to "$(CONVERTED_MRD)") -CFLAGS += -DPARAM_MIN_REQUIRED_DIFFICULTY="$(CONVERTED_MRD)" -endif - -# Convert checkpoint to what the compiler expects -ifneq ($(CHECKPOINT),) -CONVERTED_CHKP = $(shell python make-initial-block-hash.py $(CHECKPOINT)) -$(info Building with checkpoint set to "$(CONVERTED_CHKP)") -CFLAGS += -DPARAM_INITIAL_BLOCK_HASH="$(CONVERTED_CHKP)" -endif - -# Specify target network (i.e., REGTEST or TESTNET). Otherwise it defaults to MAINNET. -ifeq ($(NETWORK),REGTEST) -$(info Building for Regtest) -CFLAGS += -DREGTEST -endif - -ifeq ($(NETWORK),TESTNET) -$(info Building for Testnet) -CFLAGS += -DTESTNET -endif +UTIL_DIR = ../../util +include $(UTIL_DIR)/signer.mk +CFLAGS += $(SIGNER_FLAGS) AS := $(GCCPATH)arm-none-eabi-gcc AFLAGS += diff --git a/firmware/src/powhsm/src/attestation.c b/firmware/src/powhsm/src/attestation.c index 9c9130c4..06399384 100644 --- a/firmware/src/powhsm/src/attestation.c +++ b/firmware/src/powhsm/src/attestation.c @@ -124,6 +124,8 @@ static unsigned int generate_message_to_sign(att_t* att_ctx) { * @ret number of transmited bytes to the host */ unsigned int get_attestation(volatile unsigned int rx, att_t* att_ctx) { + UNUSED(rx); + unsigned int message_size; uint8_t code_hash_size; diff --git a/firmware/src/powhsm/src/auth_receipt.c b/firmware/src/powhsm/src/auth_receipt.c index 48c0dc4c..1683fdb5 100644 --- a/firmware/src/powhsm/src/auth_receipt.c +++ b/firmware/src/powhsm/src/auth_receipt.c @@ -147,6 +147,8 @@ static void list_end() { } static void str_start(const uint16_t size) { + UNUSED(size); + // Top level must be a list if (auth.receipt.level == 0) { LOG("[E] Receipt not a list\n"); diff --git a/firmware/src/powhsm/src/bc_advance.c b/firmware/src/powhsm/src/bc_advance.c index d95a61d3..d4f19f1b 100644 --- a/firmware/src/powhsm/src/bc_advance.c +++ b/firmware/src/powhsm/src/bc_advance.c @@ -53,7 +53,8 @@ // 0x000001d5, 0, 0, 0, 0, 0, 0 }; // Here we take it from an external definition (see Makefile for details) -#if defined(HSM_PLATFORM_LEDGER) && defined(PARAM_MIN_REQUIRED_DIFFICULTY) +#if (defined(HSM_PLATFORM_LEDGER) || defined(HSM_PLATFORM_SGX)) && \ + defined(PARAM_MIN_REQUIRED_DIFFICULTY) static const DIGIT_T MIN_REQUIRED_DIFFICULTY[BIGINT_LEN] = PARAM_MIN_REQUIRED_DIFFICULTY; #elif defined(HSM_PLATFORM_X86) @@ -1018,7 +1019,7 @@ static uint8_t dump_min_req_difficulty(int offset) { // Make sure the minimum required difficulty fits into the output buffer if (APDU_TOTAL_DATA_SIZE_OUT < sizeof(MIN_REQUIRED_DIFFICULTY) + offset) FAIL(BUFFER_OVERFLOW); - dump_bigint(APDU_DATA_PTR + offset, MIN_REQUIRED_DIFFICULTY, BIGINT_LEN); + dump_bigint_be(APDU_DATA_PTR + offset, MIN_REQUIRED_DIFFICULTY, BIGINT_LEN); return sizeof(MIN_REQUIRED_DIFFICULTY); } diff --git a/firmware/src/powhsm/src/bc_diff.c b/firmware/src/powhsm/src/bc_diff.c index a765da17..c289d5de 100644 --- a/firmware/src/powhsm/src/bc_diff.c +++ b/firmware/src/powhsm/src/bc_diff.c @@ -39,44 +39,6 @@ DIGIT_T MAX_BLOCK_DIFFICULTY[BIGINT_LEN]; static const DIGIT_T MAX_BLOCK_DIFFICULTY[BIGINT_LEN] = BCDIFF_MBD_MAINNET; #endif -/* - * Initialize a big integer. This is kind of tricky because the way big - * integers are modeled in memory. Here goes an example: - * - * For the number: - * - * [1c, 24, a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3] - * - * (that is, 0x1c24a0a1a2a3b0b1b2b3c0c1c2c3), we must build the following - * array of uin32_t numbers: - * - * [0xc0c1c2c3, 0xb0b1b2b3, 0xa0a1a2a3, 0x00001c24] - * - * This function implements exactly the conversion exemplified above. - * - * @arg[in] buf buffer holding big integer bytes in big-endian order - * @arg[in] buf_size buffer size in bytes - * @arg[out] target big integer to initialize - * @arg[in] target_size number of 32-byte integers comprising the big integer - */ -void bigint(const uint8_t* buf, - uint16_t buf_size, - DIGIT_T target[], - uint16_t target_size) { - - mpSetZero(target, target_size); - int j = 0, k = 0; - DIGIT_T curr = 0; - for (int i = buf_size - 1; i >= 0; i--) { - curr = buf[i]; - target[j] |= (curr << (k * 8)); - if (++k == sizeof(DIGIT_T)) { - ++j; - k = 0; - } - } -} - /* * Store the given difficulty in the given big integer. * @@ -87,24 +49,7 @@ void bigint(const uint8_t* buf, void store_difficulty(uint8_t* diff_bytes, uint8_t diff_size, DIGIT_T difficulty[]) { - bigint(diff_bytes, diff_size, difficulty, BIGINT_LEN); -} - -/* - * Debug: dump a bigint to given buffer. - * - * @arg[in] buf pointer to destination buffer - * @arg[in] n big integer to dump - * @arg[in] size number of 32-byte integers comprising n - */ -void dump_bigint(uint8_t* buf, const DIGIT_T n[], const size_t size) { - int k = 0; - for (int i = size - 1; i >= 0; i--) { - buf[k++] = (uint8_t)((n[i] & 0xff000000) >> 24); - buf[k++] = (uint8_t)((n[i] & 0x00ff0000) >> 16); - buf[k++] = (uint8_t)((n[i] & 0x0000ff00) >> 8); - buf[k++] = (uint8_t)((n[i] & 0x000000ff) >> 0); - } + parse_bigint_be(diff_bytes, diff_size, difficulty, BIGINT_LEN); } static const DIGIT_T _2e256[] = { @@ -161,7 +106,7 @@ diff_result check_difficulty(DIGIT_T difficulty[], const uint8_t* mm_hdr_hash) { } // Turn BTC MM block hash into a big int - bigint(mm_hdr_hash, HASH_SIZE, aux, BIGINT_LEN); + parse_bigint_be(mm_hdr_hash, HASH_SIZE, aux, BIGINT_LEN); // Block difficulty is invalid iif BTC MM block hash > target // BTC merge mining header (aux) matches block difficulty if diff --git a/firmware/src/powhsm/src/bc_diff.h b/firmware/src/powhsm/src/bc_diff.h index e268f398..8182840f 100644 --- a/firmware/src/powhsm/src/bc_diff.h +++ b/firmware/src/powhsm/src/bc_diff.h @@ -28,6 +28,7 @@ #include #include "bigdigits.h" +#include "bigdigits_helper.h" #include "bc.h" // Block difficulty caps for each network @@ -47,31 +48,6 @@ extern DIGIT_T MAX_BLOCK_DIFFICULTY[BIGINT_LEN]; #define BCDIFF_ERR_INVALID (2) #define BCDIFF_ERR_CAPPING (3) -/* - * Initialize a big integer. This is kind of tricky because the way big - * integers are modeled in memory. Here goes an example: - * - * For the number: - * - * [1c, 24, a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3] - * - * (that is, 0x1c24a0a1a2a3b0b1b2b3c0c1c2c3), we must build the following - * array of uin32_t numbers: - * - * [0xc0c1c2c3, 0xb0b1b2b3, 0xa0a1a2a3, 0x00001c24] - * - * This function implements exactly the conversion exemplified above. - * - * @arg[in] buf buffer holding big integer bytes in big-endian order - * @arg[in] buf_size buffer size in bytes - * @arg[out] target big integer to initialize - * @arg[in] target_size number of 32-byte integers comprising the big integer - */ -void bigint(const uint8_t* buf, - uint16_t buf_size, - DIGIT_T target[], - uint16_t target_size); - /* * Store the given difficulty in the given big integer. * @@ -83,15 +59,6 @@ void store_difficulty(uint8_t* diff_bytes, uint8_t diff_size, DIGIT_T difficulty[]); -/* - * Debug: dump a bigint to given buffer. - * - * @arg[in] buf pointer to destination buffer - * @arg[in] n big integer to dump - * @arg[in] size number of 32-byte integers comprising n - */ -void dump_bigint(uint8_t* buf, const DIGIT_T n[], const size_t size); - typedef enum { DIFF_MATCH = 1, DIFF_MISMATCH, DIFF_ZERO } diff_result; /* diff --git a/firmware/src/powhsm/src/bc_err.c b/firmware/src/powhsm/src/bc_err.c index e06b2dae..5fcbd53f 100644 --- a/firmware/src/powhsm/src/bc_err.c +++ b/firmware/src/powhsm/src/bc_err.c @@ -24,7 +24,7 @@ #include "bc_err.h" -#ifdef HSM_PLATFORM_X86 +#if defined(HSM_PLATFORM_X86) || defined(HSM_PLATFORM_SGX) #include "hal/log.h" diff --git a/firmware/src/powhsm/src/bc_state.c b/firmware/src/powhsm/src/bc_state.c index 633a5857..726390fb 100644 --- a/firmware/src/powhsm/src/bc_state.c +++ b/firmware/src/powhsm/src/bc_state.c @@ -42,7 +42,8 @@ // ----------------------------------------------------------------------- // Here we take it from an external definition (see Makefile for details) -#if defined(HSM_PLATFORM_LEDGER) && defined(PARAM_INITIAL_BLOCK_HASH) +#if (defined(HSM_PLATFORM_LEDGER) || defined(HSM_PLATFORM_SGX)) && \ + defined(PARAM_INITIAL_BLOCK_HASH) static const uint8_t INITIAL_BLOCK_HASH[] = PARAM_INITIAL_BLOCK_HASH; #elif defined(HSM_PLATFORM_X86) uint8_t INITIAL_BLOCK_HASH[HASH_LENGTH]; @@ -166,7 +167,7 @@ uint8_t dump_hash(uint8_t hash_code) { */ uint8_t dump_difficulty() { uint8_t buf[sizeof(bc_st_updating.total_difficulty)]; - dump_bigint(buf, bc_st_updating.total_difficulty, BIGINT_LEN); + dump_bigint_be(buf, bc_st_updating.total_difficulty, BIGINT_LEN); unsigned int start = 0; for (; start < sizeof(buf) && buf[start] == 0; start++) continue; diff --git a/firmware/src/powhsm/src/err.h b/firmware/src/powhsm/src/err.h index 93f8055f..fbadb3a3 100644 --- a/firmware/src/powhsm/src/err.h +++ b/firmware/src/powhsm/src/err.h @@ -32,6 +32,9 @@ typedef enum { ERR_INTERNAL = 0x6A99, ERR_INVALID_CLA = 0x6E11, ERR_DEVICE_NOT_ONBOARDED = 0x6BEE, + ERR_DEVICE_ONBOARDED = 0x6BEF, + ERR_ONBOARDING = 0x6BF0, + ERR_DEVICE_LOCKED = 0x6BF1, } err_code_signer_t; #endif // __ERR_H diff --git a/firmware/src/powhsm/src/hsm.c b/firmware/src/powhsm/src/hsm.c index 1318705e..6bb98e13 100644 --- a/firmware/src/powhsm/src/hsm.c +++ b/firmware/src/powhsm/src/hsm.c @@ -50,18 +50,15 @@ #include "hal/log.h" -// Macro that throws an error unless -// the device is onboarded -#define REQUIRE_ONBOARDED() \ - if (!seed_available()) \ - THROW(ERR_DEVICE_NOT_ONBOARDED); - // Operation being currently executed static unsigned char curr_cmd; // Whether exit has been requested static bool _hsm_exit_requested; +// External processor +static external_processor_t external_processor; + /* * Reset shared memory state. */ @@ -112,6 +109,14 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { THROW(ERR_INVALID_CLA); } + if (external_processor) { + external_processor_result_t epr = external_processor(rx); + if (epr.handled) { + reset_if_starting(0); + return epr.tx; + } + } + switch (APDU_CMD()) { // Reports the current mode (i.e., always reports signer mode) case RSK_MODE_CMD: @@ -133,6 +138,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { // Derives and returns the corresponding public key for the given path case INS_GET_PUBLIC_KEY: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); reset_if_starting(INS_GET_PUBLIC_KEY); @@ -175,6 +181,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { break; case INS_SIGN: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); reset_if_starting(INS_SIGN); @@ -182,6 +189,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { break; case INS_ATTESTATION: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); reset_if_starting(INS_ATTESTATION); @@ -189,6 +197,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { break; case INS_HEARTBEAT: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); reset_if_starting(INS_HEARTBEAT); @@ -197,6 +206,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { // Get blockchain state case INS_GET_STATE: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); // Get blockchain state is considered part of the @@ -207,6 +217,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { // Reset blockchain state case INS_RESET_STATE: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); reset_if_starting(INS_RESET_STATE); @@ -215,6 +226,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { // Advance blockchain case INS_ADVANCE: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); reset_if_starting(INS_ADVANCE); @@ -223,6 +235,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { // Advance blockchain precompiled parameters case INS_ADVANCE_PARAMS: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); reset_if_starting(INS_ADVANCE_PARAMS); @@ -231,6 +244,7 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { // Update ancestor case INS_UPD_ANCESTOR: + REQUIRE_UNLOCKED(); REQUIRE_ONBOARDED(); reset_if_starting(INS_UPD_ANCESTOR); @@ -238,6 +252,8 @@ static unsigned int hsm_process_command(volatile unsigned int rx) { break; case INS_EXIT: + REQUIRE_UNLOCKED(); + bc_backup_partial_state(); app_exit(); tx = TX_FOR_DATA_SIZE(0); @@ -292,6 +308,9 @@ void hsm_init() { // No exit requested _hsm_exit_requested = false; + // No external processor + external_processor = NULL; + // Blockchain state initialization bc_init_state(); } @@ -319,3 +338,6 @@ bool hsm_exit_requested() { return _hsm_exit_requested; } +void hsm_set_external_processor(external_processor_t _external_processor) { + external_processor = _external_processor; +} \ No newline at end of file diff --git a/firmware/src/powhsm/src/hsm.h b/firmware/src/powhsm/src/hsm.h index df8529c5..f6850f9b 100644 --- a/firmware/src/powhsm/src/hsm.h +++ b/firmware/src/powhsm/src/hsm.h @@ -27,10 +27,36 @@ #include +#include "hal/access.h" +#include "hal/seed.h" + +#include "err.h" + +typedef struct { + bool handled; + unsigned int tx; +} external_processor_result_t; + +// Macro that throws an error unless +// the device is onboarded +#define REQUIRE_ONBOARDED() \ + if (!seed_available()) \ + THROW(ERR_DEVICE_NOT_ONBOARDED); + +// Macro that throws an error unless +// the device is unlocked +#define REQUIRE_UNLOCKED() \ + if (access_is_locked()) \ + THROW(ERR_DEVICE_LOCKED); + +typedef external_processor_result_t (*external_processor_t)(unsigned int); + void hsm_init(); unsigned int hsm_process_apdu(unsigned int rx); bool hsm_exit_requested(); +void hsm_set_external_processor(external_processor_t external_processor); + #endif // __HSM_H diff --git a/firmware/src/powhsm/src/instructions.h b/firmware/src/powhsm/src/instructions.h index df0d96fb..65b25d2e 100644 --- a/firmware/src/powhsm/src/instructions.h +++ b/firmware/src/powhsm/src/instructions.h @@ -51,6 +51,13 @@ typedef enum { // Exit INS_EXIT = 0xff, + + // SGX-only (don't hurt to have them all here) + SGX_ONBOARD = 0xA0, + SGX_IS_LOCKED = 0xA1, + SGX_RETRIES = 0xA2, + SGX_UNLOCK = 0xA3, + SGX_ECHO = 0xA4, } apdu_instruction_t; #endif // __INSTRUCTIONS_H diff --git a/firmware/src/powhsm/src/srlp.c b/firmware/src/powhsm/src/srlp.c index b01cb638..c587706c 100644 --- a/firmware/src/powhsm/src/srlp.c +++ b/firmware/src/powhsm/src/srlp.c @@ -153,7 +153,7 @@ void rlp_start(const rlp_callbacks_t* cbs) { RLP_PUSH_CTX(RLP_STR, *b - 0x80); \ ((rlp_start_cb_t)PIC(rlp_callbacks->bytearray_start))(*b - 0x80); \ } else if (*b <= 0xBF) { \ - if (*b - 0xB7 > sizeof(uint16_t)) { \ + if (*b - 0xB7 > (int)sizeof(uint16_t)) { \ return RLP_TOO_LONG; \ } \ RLP_PUSH_CTX(RLP_STR_LEN, *b - 0xB7); \ @@ -161,7 +161,7 @@ void rlp_start(const rlp_callbacks_t* cbs) { RLP_PUSH_CTX(RLP_LIST, *b - 0xC0 + 1); \ ((rlp_start_cb_t)PIC(rlp_callbacks->list_start))(*b - 0xC0); \ } else { \ - if (*b - 0xF7 > sizeof(uint16_t)) { \ + if (*b - 0xF7 > (int)sizeof(uint16_t)) { \ return RLP_TOO_LONG; \ } \ RLP_PUSH_CTX(RLP_LIST_LEN, *b - 0xF7); \ diff --git a/firmware/src/powhsm/src/trie.c b/firmware/src/powhsm/src/trie.c index 011f222d..78f6b166 100644 --- a/firmware/src/powhsm/src/trie.c +++ b/firmware/src/powhsm/src/trie.c @@ -127,7 +127,7 @@ uint8_t trie_consume(uint8_t *buf, const uint8_t len) { ctx->raw_size = 1; --ctx->remaining_bytes; ctx->state = TRIE_ST_SHARED_PREFIX; - if (buf[i] >= 0 && buf[i] <= 31) { + if (/*buf[i] >= 0 &&*/ buf[i] <= 31) { ctx->length = buf[i] + 1; ctx->callback(TRIE_EV_SHARED_PREFIX_LENGTH); SHARED_PREFIX_TO_BYTES(); diff --git a/firmware/src/powhsm/test/difficulty/Makefile b/firmware/src/powhsm/test/difficulty/Makefile index 0ce518cb..a9add9c9 100644 --- a/firmware/src/powhsm/test/difficulty/Makefile +++ b/firmware/src/powhsm/test/difficulty/Makefile @@ -23,7 +23,7 @@ include ../common/common.mk PROG = test.out -OBJS = test_fwk.o bigdigits.o bc_diff.o test_difficulty.o platform.o log.o +OBJS = test_fwk.o bigdigits.o bigdigits_helper.o bc_diff.o test_difficulty.o platform.o log.o all: $(PROG) diff --git a/firmware/src/powhsm/test/difficulty/test_difficulty.c b/firmware/src/powhsm/test/difficulty/test_difficulty.c index a59f0afe..8915ec79 100644 --- a/firmware/src/powhsm/test/difficulty/test_difficulty.c +++ b/firmware/src/powhsm/test/difficulty/test_difficulty.c @@ -45,9 +45,9 @@ void test_conversions() { const uint8_t src_bytes[] = {0x02, 0x00, 0x00}; DIGIT_T bi[BIGINT_LEN]; - bigint(src_bytes, sizeof(src_bytes), bi, BIGINT_LEN); + parse_bigint_be(src_bytes, sizeof(src_bytes), bi, BIGINT_LEN); uint8_t dst_bytes[sizeof(bi)]; - dump_bigint(dst_bytes, bi, BIGINT_LEN); + dump_bigint_be(dst_bytes, bi, BIGINT_LEN); int start = 0; for (; dst_bytes[start] == 0; start++) @@ -85,7 +85,7 @@ void test_difficulty() { }; DIGIT_T difficulty[BIGINT_LEN]; - bigint(block_diff, sizeof(block_diff), difficulty, BIGINT_LEN); + parse_bigint_be(block_diff, sizeof(block_diff), difficulty, BIGINT_LEN); size_t size = sizeof(mm_hdr_hash) / sizeof(mm_hdr_hash[0]); for (int i = 0; i < size; i++) { diff --git a/firmware/src/powhsm/test/run-all.sh b/firmware/src/powhsm/test/run-all.sh index 1bcc013d..3eb6b08e 100755 --- a/firmware/src/powhsm/test/run-all.sh +++ b/firmware/src/powhsm/test/run-all.sh @@ -1,6 +1,6 @@ #!/bin/bash BASEDIR=$(dirname $0) -TESTDIRS="difficulty sha256 srlp svarint btcscript btctx trie" +TESTDIRS="btcscript btctx difficulty srlp svarint trie" TESTDIRS=${1:-"$TESTDIRS"} for d in $TESTDIRS; do diff --git a/firmware/src/sgx/.gitignore b/firmware/src/sgx/.gitignore new file mode 100644 index 00000000..1aa71878 --- /dev/null +++ b/firmware/src/sgx/.gitignore @@ -0,0 +1,11 @@ +# Private key file +private.pem + +# OE generated files +src/trusted/hsm_args.h +src/trusted/hsm_t.c +src/trusted/hsm_t.h +src/untrusted/hsm_args.h +src/untrusted/hsm_u.c +src/untrusted/hsm_u.h + diff --git a/firmware/src/sgx/Makefile b/firmware/src/sgx/Makefile new file mode 100644 index 00000000..598fa39f --- /dev/null +++ b/firmware/src/sgx/Makefile @@ -0,0 +1,181 @@ +# Values accepted: gcc, clang +CC = gcc + +## Flags generated by the open enclave SDK +OE_CRYPTO_LIB = mbedtls +OE_CRYPTO_LDFLAGS = $(shell pkg-config oeenclave-$(CC) --variable=${OE_CRYPTO_LIB}libs) +OE_CFLAGS = $(shell pkg-config oeenclave-$(CC) --cflags) +OE_LDFLAGS=$(shell pkg-config oeenclave-$(CC) --libs) +OE_INCDIR = $(shell pkg-config oeenclave-$(CC) --variable=includedir) +OE_LIBDIR = $(shell pkg-config oeenclave-$(CC) --variable=libdir)/openenclave +OE_HOST_LDFLAGS=$(shell pkg-config oehost-$(CC) --libs) + +## General environment and binary variables +ENCLAVE_NAME = hsm +PLATFORM_NAME = sgx +TRUSTED_NAME = trusted +UNTRUSTED_NAME = untrusted +EXEC_NAME = hsmsgx +BIN_DIR = bin +EXEC_FILE = $(BIN_DIR)/$(EXEC_NAME) +ENCLAVE_UNSIGNED_FILE = $(BIN_DIR)/$(EXEC_NAME)_enclave +ENCLAVE_SIGNED_FILE = $(ENCLAVE_UNSIGNED_FILE).signed + +## Sources +SGX_SRC_DIR = src +SGX_TRUSTED_SRC_DIR = $(SGX_SRC_DIR)/$(TRUSTED_NAME) +SGX_UNTRUSTED_SRC_DIR = $(SGX_SRC_DIR)/$(UNTRUSTED_NAME) + +## HAL sources +HAL_SRC_DIR = ../hal/$(PLATFORM_NAME)/src +HAL_TRUSTED_SRC_DIR = $(HAL_SRC_DIR)/$(TRUSTED_NAME) +HAL_INCLUDE_DIR = ../hal/include + +## PowHSM sources +POWHSM_SRC_DIR = ../powhsm/src + +## Common sources +COMMON_SRC_DIR = ../common/src + +## Untrusted source files +UNTRUSTED_SRC = $(wildcard $(SGX_UNTRUSTED_SRC_DIR)/*.c) + +## Trusted source files +TRUSTED_SRC = $(wildcard $(SGX_TRUSTED_SRC_DIR)/*.c) +TRUSTED_SRC += $(wildcard $(HAL_TRUSTED_SRC_DIR)/*.c) +TRUSTED_SRC += $(wildcard $(POWHSM_SRC_DIR)/*.c) +TRUSTED_SRC += $(wildcard $(COMMON_SRC_DIR)/*.c) + +# Enclave definition files +EDL_FILE = $(SGX_SRC_DIR)/$(ENCLAVE_NAME).edl +CONF_FILE = $(SGX_SRC_DIR)/$(ENCLAVE_NAME).conf + +## Object directories +OBJ_DIR = obj + +OBJ_TRUSTED_DIR = $(OBJ_DIR)/$(TRUSTED_NAME) +OBJ_TRUSTED_SGX_DIR = $(OBJ_DIR)/$(TRUSTED_NAME)/sgx +OBJ_TRUSTED_HAL_DIR = $(OBJ_DIR)/$(TRUSTED_NAME)/hal +OBJ_TRUSTED_POWHSM_DIR = $(OBJ_DIR)/$(TRUSTED_NAME)/powhsm +OBJ_TRUSTED_COMMON_DIR = $(OBJ_DIR)/$(TRUSTED_NAME)/common + +OBJ_UNTRUSTED_DIR = obj/$(UNTRUSTED_NAME) + +## Objects +UNTRUSTED_OBJS = $(patsubst %.c,$(OBJ_UNTRUSTED_DIR)/%.o,$(notdir $(UNTRUSTED_SRC))) +TRUSTED_OBJS = $(patsubst $(POWHSM_SRC_DIR)/%.c, $(OBJ_TRUSTED_POWHSM_DIR)/%.o,\ + $(patsubst $(COMMON_SRC_DIR)/%.c, $(OBJ_TRUSTED_COMMON_DIR)/%.o,\ + $(patsubst $(HAL_TRUSTED_SRC_DIR)/%.c,$(OBJ_TRUSTED_HAL_DIR)/%.o,\ + $(patsubst $(SGX_TRUSTED_SRC_DIR)/%.c,$(OBJ_TRUSTED_SGX_DIR)/%.o,$(TRUSTED_SRC))))) + +## Files generated automatically by the open enclave SDK (and their objects) +# Files used by trusted code +TRUSTED_GENERATED = $(addprefix $(SGX_TRUSTED_SRC_DIR)/$(ENCLAVE_NAME), _t.c _t.h _args.h) +TRUSTED_GENERATED_OBJ = $(OBJ_TRUSTED_SGX_DIR)/$(ENCLAVE_NAME)_t.o +# Files used by untrusted code +UNTRUSTED_GENERATED = $(addprefix $(SGX_UNTRUSTED_SRC_DIR)/$(ENCLAVE_NAME), _u.c _u.h _args.h) +UNTRUSTED_GENERATED_OBJ = $(OBJ_UNTRUSTED_DIR)/$(ENCLAVE_NAME)_u.o + +## Trusted and untrusted flags and include directories +CFLAGS_COMMON = -Wall -Wextra -Werror -DHSM_PLATFORM_SGX + +INCLUDE_TRUSTED = -iquote $(HAL_INCLUDE_DIR) -iquote $(SGX_TRUSTED_SRC_DIR) +INCLUDE_TRUSTED += -iquote $(HAL_TRUSTED_SRC_DIR) -iquote $(COMMON_SRC_DIR) +INCLUDE_TRUSTED += -iquote $(POWHSM_SRC_DIR) -I$(SGX_SECP256K1)/include +CFLAGS_TRUSTED = $(CFLAGS_COMMON) $(INCLUDE_TRUSTED) +CFLAGS_TRUSTED += $(OE_CFLAGS) -DOE_API_VERSION=2 + +UTIL_DIR = ../util +include $(UTIL_DIR)/signer.mk +CFLAGS_TRUSTED += $(SIGNER_FLAGS) + +INCLUDE_UNTRUSTED = -I$(OE_INCDIR) -iquote $(SGX_UNTRUSTED_SRC_DIR) +CFLAGS_UNTRUSTED = $(CFLAGS_COMMON) $(INCLUDE_UNTRUSTED) + +# The seal plugin is what implements the oe_seal APIs. It needs to be linked against the +# enclave to provide the seal/unseal functionality. +# TODO: the path for the seal plugin is hardcoded to its path whithin the SDK instalation. +# We probably want to include a specific version of the seal plugin in a specific location +# within the Docker image. +SEAL_PLUGIN=$(OE_LIBDIR)/enclave/objects-RelWithDebInfo/oeseal_gcmaes-lvi-cfg/seal_gcmaes.c.o + +.PHONY: clean + +all: build + +# We always force a clean when building to avoid accidentally using debug builds in +# production. The build is fast enough so we should be alright. +build: clean check-private-key $(ENCLAVE_SIGNED_FILE) $(EXEC_FILE) + +build-debug: CFLAGS_COMMON += -DDEBUG_BUILD +build-debug: CONF_FILE = $(SGX_SRC_DIR)/$(ENCLAVE_NAME)-debug.conf +build-debug: build + +check-private-key: + @if [ ! -f private.pem ]; then \ + echo "Private key not found! Please place your private key in a private.pem file."; \ + echo "You can generate a new key by running make generate-private-key"; \ + exit 1; \ + fi \ + +generate-private-key: + openssl genrsa -out private.pem -3 3072 + +$(EXEC_FILE): LDFLAGS += $(OE_HOST_LDFLAGS) +$(EXEC_FILE): $(UNTRUSTED_OBJS) $(UNTRUSTED_GENERATED_OBJ) + @mkdir -p $(shell dirname $@) + $(CC) -o $@ $^ $(LDFLAGS) + +$(ENCLAVE_SIGNED_FILE): $(ENCLAVE_UNSIGNED_FILE) private.pem + @mkdir -p $(shell dirname $@) + oesign sign -e $< -c $(CONF_FILE) -k private.pem + +$(ENCLAVE_UNSIGNED_FILE): LDFLAGS += $(OE_LDFLAGS) $(OE_CRYPTO_LDFLAGS) -lsecp256k1 -L$(SGX_STATIC_LIBS) +$(ENCLAVE_UNSIGNED_FILE): $(TRUSTED_OBJS) $(TRUSTED_GENERATED_OBJ) $(SEAL_PLUGIN) + @mkdir -p $(shell dirname $@) + $(CC) -o $@ $^ $(LDFLAGS) + +$(TRUSTED_GENERATED_OBJ): $(TRUSTED_GENERATED) + @mkdir -p $(shell dirname $@) + $(CC) -c $(CFLAGS_TRUSTED) $< -o $@ + +$(UNTRUSTED_GENERATED_OBJ): $(UNTRUSTED_GENERATED) + @mkdir -p $(shell dirname $@) + $(CC) -c $(CFLAGS_UNTRUSTED) $< -o $@ + +$(OBJ_TRUSTED_SGX_DIR)/%.o: $(SGX_TRUSTED_SRC_DIR)/%.c $(TRUSTED_GENERATED) + @mkdir -p $(shell dirname $@) + $(CC) -c $(CFLAGS_TRUSTED) $< -o $@ + +$(OBJ_TRUSTED_HAL_DIR)/%.o: $(HAL_TRUSTED_SRC_DIR)/%.c $(TRUSTED_GENERATED) + @mkdir -p $(shell dirname $@) + $(CC) -c $(CFLAGS_TRUSTED) $< -o $@ + +$(OBJ_TRUSTED_POWHSM_DIR)/%.o: $(POWHSM_SRC_DIR)/%.c $(TRUSTED_GENERATED) + @mkdir -p $(shell dirname $@) + $(CC) -c $(CFLAGS_TRUSTED) $< -o $@ + +$(OBJ_TRUSTED_COMMON_DIR)/%.o: $(COMMON_SRC_DIR)/%.c $(TRUSTED_GENERATED) + @mkdir -p $(shell dirname $@) + $(CC) -c $(CFLAGS_TRUSTED) $< -o $@ + +$(OBJ_UNTRUSTED_DIR)/%.o: $(SGX_UNTRUSTED_SRC_DIR)/%.c $(UNTRUSTED_GENERATED) + @mkdir -p $(shell dirname $@) + $(CC) -c $(CFLAGS_UNTRUSTED) $< -o $@ + +$(TRUSTED_GENERATED): $(EDL_FILE) + @mkdir -p $(shell dirname $@) + oeedger8r $< --trusted \ + --search-path $(OE_INCDIR) \ + --search-path $(OE_INCDIR)/openenclave/edl/sgx \ + --trusted-dir $(shell dirname $@) + +$(UNTRUSTED_GENERATED): $(EDL_FILE) + @mkdir -p $(shell dirname $@) + oeedger8r $< --untrusted \ + --search-path $(OE_INCDIR) \ + --search-path $(OE_INCDIR)/openenclave/edl/sgx \ + --untrusted-dir $(shell dirname $@) + +clean: + rm -rf $(BIN_DIR) $(OBJ_DIR) $(DEP_DIR) $(TRUSTED_GENERATED) $(UNTRUSTED_GENERATED) diff --git a/firmware/src/sgx/src/hsm-debug.conf b/firmware/src/sgx/src/hsm-debug.conf new file mode 100644 index 00000000..b6758d78 --- /dev/null +++ b/firmware/src/sgx/src/hsm-debug.conf @@ -0,0 +1,16 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +############################################################################## +## Warning: this configuration file is FOR DEBUGGING PURPOSES ONLY, and should +## not be used in production environments +############################################################################## + +# Enclave settings: +Debug=1 +NumHeapPages=1024 +NumStackPages=1024 +NumTCS=1 +ProductID=100 +SecurityVersion=1 +CapturePFGPExceptions=1 diff --git a/firmware/src/sgx/src/hsm.conf b/firmware/src/sgx/src/hsm.conf new file mode 100644 index 00000000..8d0f73f2 --- /dev/null +++ b/firmware/src/sgx/src/hsm.conf @@ -0,0 +1,11 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +# Enclave settings: +Debug=0 +NumHeapPages=1024 +NumStackPages=1024 +NumTCS=1 +ProductID=1 +SecurityVersion=1 +CapturePFGPExceptions=1 diff --git a/firmware/src/sgx/src/hsm.edl b/firmware/src/sgx/src/hsm.edl new file mode 100644 index 00000000..9f62a8ba --- /dev/null +++ b/firmware/src/sgx/src/hsm.edl @@ -0,0 +1,30 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + + +enclave { + from "openenclave/edl/syscall.edl" import *; + from "platform.edl" import *; + + trusted { + public bool ecall_system_init(unsigned char *msg_buffer, size_t msg_buffer_size); + + public unsigned int ecall_system_process_apdu(unsigned int rx); + }; + + untrusted { + bool ocall_kvstore_save( + [string, in] char *key, + [in, size=data_size] uint8_t *data, + size_t data_size); + + bool ocall_kvstore_exists([string, in] char *key); + + size_t ocall_kvstore_get( + [string, in] char *key, + [out, size=buffer_size] uint8_t *data_buf, + size_t buffer_size); + + bool ocall_kvstore_remove([string, in] char *key); + }; +}; diff --git a/firmware/src/sgx/src/trusted/ecall.c b/firmware/src/sgx/src/trusted/ecall.c new file mode 100644 index 00000000..cf5c89d4 --- /dev/null +++ b/firmware/src/sgx/src/trusted/ecall.c @@ -0,0 +1,47 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "ecall.h" + +#include "hsm_t.h" +#include "sync.h" + +#include "system.h" + +#include "hal/log.h" + +bool ecall_system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { + SYNC_AQUIRE_LOCK(); + bool success = system_init(msg_buffer, msg_buffer_size); + SYNC_RELEASE_LOCK(); + return success; +} + +unsigned int ecall_system_process_apdu(unsigned int rx) { + SYNC_AQUIRE_LOCK(); + unsigned int result = system_process_apdu(rx); + SYNC_RELEASE_LOCK(); + return result; +} + diff --git a/firmware/src/sgx/src/trusted/ecall.h b/firmware/src/sgx/src/trusted/ecall.h new file mode 100644 index 00000000..f5373272 --- /dev/null +++ b/firmware/src/sgx/src/trusted/ecall.h @@ -0,0 +1,45 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __TRUSTED_ECALL_H +#define __TRUSTED_ECALL_H + +#include +#include + +/** + * Trusted functions declared in hsm.edl must be these and exactly these + */ + +/** + * @brief See system_init in system.h + */ +bool ecall_system_init(unsigned char *msg_buffer, size_t msg_buffer_size); + +/** + * @brief See system_process_apdu in system.h + */ +unsigned int ecall_system_process_apdu(unsigned int rx); + +#endif // __TRUSTED_ECALL_H diff --git a/firmware/src/sgx/src/trusted/sync.c b/firmware/src/sgx/src/trusted/sync.c new file mode 100644 index 00000000..078c9eee --- /dev/null +++ b/firmware/src/sgx/src/trusted/sync.c @@ -0,0 +1,38 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "sync.h" + +// Globals +static bool G_locked = false; + +bool sync_try_aqcuire_lock() { + if (G_locked) return false; + G_locked = true; + return true; +} + +void sync_release_lock() { + G_locked = false; +} diff --git a/firmware/src/sgx/src/trusted/sync.h b/firmware/src/sgx/src/trusted/sync.h new file mode 100644 index 00000000..853925ff --- /dev/null +++ b/firmware/src/sgx/src/trusted/sync.h @@ -0,0 +1,63 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __TRUSTED_SYNC_H +#define __TRUSTED_SYNC_H + +#include +#include "hal/log.h" + +#define SYNC_AQUIRE_LOCK() \ + if (!sync_try_aqcuire_lock()) { \ + LOG("Failed to acquire lock, ecall %s was not executed!\n", __func__); \ + return false; \ + } + +#define SYNC_RELEASE_LOCK() sync_release_lock() + +/** + * @brief Tries to aqcuire the lock. This function will verify if the lock is + * currently available and if so, it will aqcuire it and return true. If the + * lock is already taken, it will return false. + * + * @return true if the lock was aqcuired, false otherwise. + * + * @note This function is not thread safe and should be called only from a + * single thread. All trusted modules need to aqcuire the lock before calling + * any ecalls or ocalls. This is to ensure that only one single ecall or ocall + * is executed at a time, preventing nested ecals. + */ +bool sync_try_aqcuire_lock(); + +/** + * @brief Releases the lock. This function will release the lock if it was + * aqcuired. If the lock was not aqcuired, this function will do nothing. + * + * @note This function is not thread safe and should be called only from a + * single thread. All trusted modules need to release the lock after calling any + * ecalls or ocalls. + */ +void sync_release_lock(); + +#endif // __TRUSTED_SYNC_H diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c new file mode 100644 index 00000000..d2bffa63 --- /dev/null +++ b/firmware/src/sgx/src/trusted/system.c @@ -0,0 +1,205 @@ +#include + +#include "hal/constants.h" +#include "hal/communication.h" +#include "hal/seed.h" +#include "hal/access.h" +#include "hal/endorsement.h" +#include "hal/nvmem.h" +#include "hal/exceptions.h" +#include "hal/log.h" + +#include "secret_store.h" +#include "hsm.h" +#include "apdu.h" +#include "instructions.h" +#include "modes.h" +#include "bc_state.h" +#include "err.h" +#include "bc_err.h" + +/** + * APDU buffer + */ +#define EXPECTED_APDU_BUFFER_SIZE 85 +static unsigned char* apdu_buffer; +static size_t apdu_buffer_size; + +static void wipe_system() { + seed_wipe(); + access_wipe(); +} + +static void on_access_wiped() { + if (!seed_wipe()) { + LOG("Error wiping seed module\n"); + } + LOG("Seed wiped\n"); +} + +static unsigned int do_onboard(unsigned int rx) { + // Validations + if (seed_available()) { + THROW(ERR_DEVICE_ONBOARDED); + } + + // Require seed plus a nonblank password + if (APDU_DATA_SIZE(rx) < SEED_LENGTH + 1) { + THROW(ERR_INVALID_DATA_SIZE); + } + + // Onboarding + uint8_t tmp_buffer[apdu_buffer_size]; + memcpy(tmp_buffer, APDU_DATA_PTR, SEED_LENGTH); + if (!seed_generate(tmp_buffer, SEED_LENGTH)) { + wipe_system(); + THROW(ERR_ONBOARDING); + } + + size_t password_length = APDU_DATA_SIZE(rx) - SEED_LENGTH; + memcpy(tmp_buffer, APDU_DATA_PTR + SEED_LENGTH, password_length); + if (!access_set_password((char*)tmp_buffer, password_length)) { + wipe_system(); + THROW(ERR_ONBOARDING); + } + + SET_APDU_OP(1); + return TX_NO_DATA(); +} + +static unsigned int do_unlock(unsigned int rx) { + if (!access_is_locked()) { + SET_APDU_OP(1); + return TX_NO_DATA(); + } + + if (APDU_DATA_SIZE(rx) == 0) { + THROW(ERR_INVALID_DATA_SIZE); + } + + SET_APDU_OP( + access_unlock((char*)APDU_DATA_PTR, APDU_DATA_SIZE(rx)) ? 1 : 0); + return TX_NO_DATA(); +} + +static unsigned int do_echo(unsigned int rx) { + return rx; +} + +static external_processor_result_t system_do_process_apdu(unsigned int rx) { + external_processor_result_t result = { + .handled = true, + .tx = 0, + }; + + switch (APDU_CMD()) { + // Reports the bootloader mode only if the device is locked + // Otherwise command is ignored and the powHSM handler will + // take over instead. + case RSK_MODE_CMD: + if (access_is_locked()) { + SET_APDU_CMD(APP_MODE_BOOTLOADER); + result.tx = 2; + break; + } + result.handled = false; + break; + case SGX_ONBOARD: + result.tx = do_onboard(rx); + break; + case SGX_IS_LOCKED: + REQUIRE_ONBOARDED(); + SET_APDU_OP(access_is_locked() ? 1 : 0); + result.tx = TX_NO_DATA(); + break; + case SGX_RETRIES: + REQUIRE_ONBOARDED(); + SET_APDU_OP(access_get_retries()); + result.tx = TX_NO_DATA(); + break; + case SGX_UNLOCK: + REQUIRE_ONBOARDED(); + result.tx = do_unlock(rx); + break; + case SGX_ECHO: + result.tx = do_echo(rx); + break; + default: + result.handled = false; + } + + return result; +} + +unsigned int system_process_apdu(unsigned int rx) { + return hsm_process_apdu(rx); +} + +bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { + // Setup the shared APDU buffer + if (msg_buffer_size != EXPECTED_APDU_BUFFER_SIZE) { + LOG("Expected APDU buffer size to be %u but got %lu\n", + EXPECTED_APDU_BUFFER_SIZE, msg_buffer_size); + return false; + } + apdu_buffer = msg_buffer; + apdu_buffer_size = msg_buffer_size; + + // Initialize modules + LOG("Initializing modules...\n"); + if (!sest_init()) { + LOG("Error initializing secret store module\n"); + return false; + } + + if (!access_init(on_access_wiped)) { + LOG("Error initializing access module\n"); + return false; + } + + if (!seed_init()) { + LOG("Error initializing seed module\n"); + return false; + } + + // Make sure both access and init are in the same state + if (!seed_available() ^ access_is_wiped()) { + LOG("Inconsistent system state detected\n"); + if (!access_wipe() || !seed_wipe()) { + LOG("System wipe failed\n"); + return false; + } + LOG("System wiped\n"); + } + + if (!communication_init(apdu_buffer, apdu_buffer_size)) { + LOG("Error initializing communication module\n"); + return false; + } + + if (!endorsement_init()) { + LOG("Error initializing endorsement module\n"); + return false; + } + + nvmem_init(); + nvmem_register_block("bcstate", + &N_bc_state_var, + sizeof(N_bc_state_var)); + nvmem_register_block("bcstate_updating", + &N_bc_state_updating_backup_var, + sizeof(N_bc_state_updating_backup_var)); + if (!nvmem_load()) { + LOG("Error loading nvmem\n"); + return false; + } + + LOG("Modules initialized\n"); + + LOG("Initializing powHSM...\n"); + hsm_init(); + hsm_set_external_processor(system_do_process_apdu); + LOG("powHSM initialized\n"); + + return true; +} diff --git a/firmware/src/sgx/src/trusted/system.h b/firmware/src/sgx/src/trusted/system.h new file mode 100644 index 00000000..e571e136 --- /dev/null +++ b/firmware/src/sgx/src/trusted/system.h @@ -0,0 +1,48 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __TRUSTED_SYSTEM_H +#define __TRUSTED_SYSTEM_H + +/** + * @brief Initializes the system module + * + * @param msg_buffer the APDU buffer to use + * @param msg_buffer_size the size of the APDU buffer in bytes + * + * @returns whether the initialisation succeeded + */ +bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size); + +/** + * @brief Process an APDU message + * + * @param rx number of received bytes + * + * @returns number of bytes to transmit + */ +unsigned int system_process_apdu(unsigned int rx); + + +#endif // __TRUSTED_SYSTEM_H diff --git a/firmware/src/sgx/src/untrusted/enclave_provider.c b/firmware/src/sgx/src/untrusted/enclave_provider.c new file mode 100644 index 00000000..ce30f851 --- /dev/null +++ b/firmware/src/sgx/src/untrusted/enclave_provider.c @@ -0,0 +1,70 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#include + +#include "hsm_u.h" +#include "enclave_provider.h" +#include "log.h" + +// Global pointer to the enclave. This should be the only global pointer to the enclave +static char* G_enclave_path = NULL; +static oe_enclave_t* G_enclave = NULL; + +bool epro_init(char* enclave_path) { + G_enclave_path = enclave_path; + if (access(G_enclave_path, F_OK) != 0) { + LOG("Invalid enclave path given: %s\n", G_enclave_path); + return false; + } + return true; +} + +oe_enclave_t* epro_get_enclave() { + if (NULL == G_enclave) { + oe_enclave_t *enclave = NULL; + LOG("Creating HSM enclave...\n"); + oe_result_t result = oe_create_hsm_enclave(G_enclave_path, + OE_ENCLAVE_TYPE_AUTO, + 0, NULL, 0, &enclave); + if (OE_OK != result) { + LOG("Failed to create enclave: oe_result=%u (%s)\n", result, oe_result_str(result)); + return NULL; + } + + LOG("HSM enclave created\n"); + G_enclave = enclave; + } + + return G_enclave; +} + +void epro_finalize_enclave() { + if (NULL != G_enclave) { + oe_terminate_enclave(G_enclave); + LOG("HSM enclave terminated\n"); + G_enclave = NULL; + } +} diff --git a/firmware/src/sgx/src/untrusted/enclave_provider.h b/firmware/src/sgx/src/untrusted/enclave_provider.h new file mode 100644 index 00000000..37a31f91 --- /dev/null +++ b/firmware/src/sgx/src/untrusted/enclave_provider.h @@ -0,0 +1,52 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __ENCLAVE_PROVIDER_H +#define __ENCLAVE_PROVIDER_H + +#include + +/** + * @brief Initializes the enclave provider with the given enclave binary path + * + * @returns Whether initialization succeeded + */ +bool epro_init(char* enclave_path); + +/** + * @brief Returns a pointer to the HSM enclave. This function should always + * return a valid pointer to the enclave, which can be used to perform + * ecall operations. + * + * @returns A valid pointer to the HSM enclave, or NULL if an error occurred + */ +oe_enclave_t* epro_get_enclave(); + +/** + * @brief Terminates the HSM enclave. After this function is called, + * all ecall operations will fail. + */ +void epro_finalize_enclave(); + +#endif // __ENCLAVE_PROVIDER_H diff --git a/firmware/src/sgx/src/untrusted/enclave_proxy.c b/firmware/src/sgx/src/untrusted/enclave_proxy.c new file mode 100644 index 00000000..6e402b56 --- /dev/null +++ b/firmware/src/sgx/src/untrusted/enclave_proxy.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#include "enclave_proxy.h" + +#include "hsm_u.h" +#include "enclave_provider.h" +#include "keyvalue_store.h" +#include "log.h" + +#define CHECK_ECALL_RESULT(oe_result, error_msg, ret) \ + { \ + if (OE_OK != oe_result) { \ + LOG(error_msg); \ + LOG(": oe_result=%u (%s)\n", oe_result, oe_result_str(oe_result)); \ + return (ret); \ + } \ + } + +/** + * ECALLS + */ + +bool eprx_system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { + oe_enclave_t *enclave = epro_get_enclave(); + if (enclave == NULL) { + LOG("Failed to retrieve the enclave. " + "Unable to call system_init().\n"); + return false; + } + + bool result; + oe_result_t oe_result = ecall_system_init(enclave, &result, + msg_buffer, msg_buffer_size); + CHECK_ECALL_RESULT(oe_result, "Failed to call system_init()", false); + return result; +} + +unsigned int eprx_system_process_apdu(unsigned int rx) { + oe_enclave_t *enclave = epro_get_enclave(); + if (enclave == NULL) { + LOG("Failed to retrieve the enclave. " + "Unable to call system_process_command().\n"); + return false; + } + + unsigned int result; + oe_result_t oe_result = ecall_system_process_apdu(enclave, &result, rx); + + CHECK_ECALL_RESULT(oe_result, "Failed to call ecall_system_process_apdu()", false); + return result; +} + +/** + * OCALLS + */ + +#define OCALL_PREFIX "[Ocall] " + +bool ocall_kvstore_save(char* key, uint8_t* data, size_t data_size) { + log_set_prefix(OCALL_PREFIX); + bool retval = kvstore_save(key, data, data_size); + log_clear_prefix(); + return retval; +} + +bool ocall_kvstore_exists(char* key) { + log_set_prefix(OCALL_PREFIX); + bool retval = kvstore_exists(key); + log_clear_prefix(); + return retval; +} + +size_t ocall_kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size) { + log_set_prefix(OCALL_PREFIX); + size_t retval = kvstore_get(key, data_buf, buffer_size); + log_clear_prefix(); + return retval; +} + +bool ocall_kvstore_remove(char* key) { + log_set_prefix(OCALL_PREFIX); + bool retval = kvstore_remove(key); + log_clear_prefix(); + return retval; +} + diff --git a/firmware/src/sgx/src/untrusted/enclave_proxy.h b/firmware/src/sgx/src/untrusted/enclave_proxy.h new file mode 100644 index 00000000..4565ab12 --- /dev/null +++ b/firmware/src/sgx/src/untrusted/enclave_proxy.h @@ -0,0 +1,16 @@ +#ifndef __HSM_PROXY +#define __HSM_PROXY + +#include + +/** + * @brief See system_init in system.h within the trusted sources + */ +bool eprx_system_init(unsigned char *msg_buffer, size_t msg_buffer_size); + +/** + * @brief See system_process_apdu in system.h within the trusted sources + */ +unsigned int eprx_system_process_apdu(unsigned int rx); + +#endif // __HSM_PROXY \ No newline at end of file diff --git a/firmware/src/sgx/src/untrusted/io.c b/firmware/src/sgx/src/untrusted/io.c new file mode 100644 index 00000000..b5dd84b4 --- /dev/null +++ b/firmware/src/sgx/src/untrusted/io.c @@ -0,0 +1,202 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "io.h" +#include "log.h" + +/** + * APDU buffer + */ +unsigned char io_apdu_buffer[APDU_BUFFER_SIZE]; + +/** + * For the TCP server + */ +int serverfd; +int connfd; +struct sockaddr_in servaddr, cliaddr; + +static int start_server(int port, const char *host) { + int sockfd; + struct hostent *hostinfo; + hostinfo = gethostbyname(host); + + if (hostinfo == NULL) { + LOG("Host not found.\n"); + return 0; + } + + // socket create and verification + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) { + LOG("Socket creation failed...\n"); + return 0; + } + + explicit_bzero(&servaddr, sizeof(servaddr)); + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < + 0) { + LOG("Socket option setting failed failed\n"); + return 0; + } + + if (setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &(int){1}, sizeof(int)) < 0) { + LOG("Socket option setting failed failed\n"); + return 0; + } + + // Set address and port + servaddr.sin_family = AF_INET; + memcpy(&servaddr.sin_addr, hostinfo->h_addr_list[0], hostinfo->h_length); + servaddr.sin_port = htons(port); + + // Binding newly created socket to given IP and verification + if ((bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) != 0) { + LOG("Socket bind failed...\n"); + return 0; + } + + // Now server is ready to listen and verification + if ((listen(sockfd, 5)) != 0) { + LOG("Listen failed...\n"); + return 0; + } + + LOG("Server listening...\n"); + return sockfd; +} + +static bool accept_connection() { + socklen_t len = sizeof(cliaddr); + connfd = accept(serverfd, (struct sockaddr *)&cliaddr, &len); + if (connfd == -1) { + LOG("Client connection failed...\n"); + return 0; + } + + LOG("Client connected...\n"); + return connfd != -1; +} + +bool io_init(int port, const char *host) { + connfd = 0; + serverfd = start_server(port, host); + return serverfd; +} + +void io_finalise() { + if (connfd) { + close(connfd); + connfd = 0; + } + if (serverfd) { + close(serverfd); + serverfd = 0; + } +} + +unsigned short io_exchange(unsigned short tx) { + uint32_t tx_net, rx_net; + unsigned int rx; + int readlen; + + while (true) { + if (!connfd) { + if (!accept_connection()) { + LOG("Error accepting client connection\n"); + return 0; + } + tx = 0; + } + + // Write len (Compatibility with LegerBlue commTCP.py) + if (tx > 0) { + // Write APDU length minus two bytes of the sw + // (encoded in 4 bytes network byte-order) + // (compatibility with LegerBlue commTCP.py) + tx_net = tx - 2; + tx_net = htonl(tx_net); + if (send(connfd, &tx_net, sizeof(tx_net), MSG_NOSIGNAL) == -1) { + LOG("Connection closed by the client\n"); + connfd = 0; + continue; + } + // Write APDU + if (send(connfd, io_apdu_buffer, tx, MSG_NOSIGNAL) == -1) { + LOG("Connection closed by the client\n"); + connfd = 0; + continue; + } + LOG_HEX("I/O =>", io_apdu_buffer, tx); + } + + // Read APDU length + // (encoded in 4 bytes network byte-order) + // (compatibility with LedgerBlue commTCP.py) + readlen = read(connfd, &rx_net, sizeof(rx_net)); + if (readlen == sizeof(rx_net)) { + rx = ntohl(rx_net); + if (rx > 0) { + // Read APDU from socket + readlen = read(connfd, io_apdu_buffer, sizeof(io_apdu_buffer)); + if (readlen < 0 || (unsigned int)readlen != rx) { + LOG("Error reading APDU (got %d bytes != %d bytes). " + "Disconnected\n", + readlen, + rx); + close(connfd); + connfd = 0; + continue; + } + LOG_HEX("I/O <=", io_apdu_buffer, rx); + } else { + // Empty packet + LOG("I/O <= \n"); + } + + return rx; + } else if (readlen == 0) { + // EOF => socket closed + LOG("Connection closed by the client\n"); + } else if (readlen == -1) { + // Error reading + LOG("Error reading from socket. Disconnected\n"); + } else { + // Invalid packet header + LOG("Error reading APDU length (got %d bytes != %ld bytes). " + "Disconnected\n", + readlen, + sizeof(rx_net)); + } + close(connfd); + connfd = 0; + } +} diff --git a/firmware/src/sgx/src/untrusted/io.h b/firmware/src/sgx/src/untrusted/io.h new file mode 100644 index 00000000..405fe86a --- /dev/null +++ b/firmware/src/sgx/src/untrusted/io.h @@ -0,0 +1,66 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __IO_H +#define __IO_H + +#include + +/** + * APDU buffer + */ +#define APDU_BUFFER_SIZE 85 +extern unsigned char io_apdu_buffer[APDU_BUFFER_SIZE]; + +/** + * @brief Initializes the I/O module. Starts a TCP server at the given host and + * port. + * + * @param port the port on which to listen for connections + * @param host the interface to bind to + * + */ +bool io_init(int port, const char *host); + +/** + * @brief Exchanges bytes with the host. This function blocks until the host + * sends a message. + * + * The message exchanges data with the host using the msg_buffer. If there are + * any bytes to transmit, they are transmitted first. After that the function + * blocks until a new message is received from the host. + * + * @param tx The number of bytes to send to the host + * + * @returns the number of bytes received from the host + */ +unsigned short io_exchange(unsigned short tx); + +/** + * @brief Finalises the I/O module. Closes any outstanding connections and shuts + * the server down. + */ +void io_finalise(); + +#endif // __IO_H \ No newline at end of file diff --git a/firmware/src/sgx/src/untrusted/keyvalue_store.c b/firmware/src/sgx/src/untrusted/keyvalue_store.c new file mode 100644 index 00000000..b743a7ec --- /dev/null +++ b/firmware/src/sgx/src/untrusted/keyvalue_store.c @@ -0,0 +1,131 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include "hsm_u.h" +#include "log.h" + +#define KVSTORE_PREFIX "./kvstore-" +#define KVSTORE_SUFFIX ".dat" + +static char* filename_for(char* key) { + size_t filename_size = strlen(KVSTORE_PREFIX) + + strlen(KVSTORE_SUFFIX) + + strlen(key); + char* filename = malloc(filename_size+1); + strcpy(filename, ""); + strcat(filename, KVSTORE_PREFIX); + strcat(filename, key); + strcat(filename, KVSTORE_SUFFIX); + return filename; +} + +static FILE* open_file_for(char* key, char* mode, size_t* file_size) { + char* filename = filename_for(key); + struct stat fst; + stat(filename, &fst); + if (file_size) *file_size = fst.st_size; + FILE* file = fopen(filename, mode); + free(filename); + return file; +} + +bool kvstore_save(char* key, uint8_t* data, size_t data_size) { + LOG("Attempting to write data for %s...\n", key); + if (!data_size) { + LOG("Invalid zero-length data given for key <%s>\n", key); + return false; + } + + FILE* file = open_file_for(key, "wb", NULL); + if (!file) { + LOG("Could not open file for key <%s>\n", key); + return false; + } + + if (fwrite(data, + sizeof(data[0]), + data_size, + file) != data_size) { + LOG("Error writing secret payload for key <%s>\n", key); + fclose(file); + return false; + }; + + fclose(file); + return true; +} + +bool kvstore_exists(char* key) { + LOG("Attempting to determine existence for key <%s>...\n", key); + size_t file_size = 0; + FILE* file = open_file_for(key, "rb", &file_size); + if (file) { + fclose(file); + return true; + } + return false; +} + +size_t kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size) { + LOG("Attempting to read data for key <%s>...\n", key); + size_t file_size = 0; + FILE* file = open_file_for(key, "rb", &file_size); + if (!file) { + LOG("Could not open file for key <%s>\n", key); + return 0; + } + + if (file_size > buffer_size) { + LOG("Payload too big for destination for key <%s>\n", key); + fclose(file); + return 0; + } + + if (!file_size) { + LOG("Invalid zero-length secret stored for key <%s>\n", key); + fclose(file); + return 0; + } + + if (fread(data_buf, + sizeof(data_buf[0]), + file_size, + file) != file_size) { + LOG("Could not read payload for key <%s>\n", key); + fclose(file); + return 0; + }; + + fclose(file); + return file_size; +} + +bool kvstore_remove(char* key) { + char* filename = filename_for(key); + int result = remove(filename); + if (result) LOG("Error removing file for key <%s>\n", key); + free(filename); + return !result; +} diff --git a/firmware/src/sgx/src/untrusted/keyvalue_store.h b/firmware/src/sgx/src/untrusted/keyvalue_store.h new file mode 100644 index 00000000..359d8010 --- /dev/null +++ b/firmware/src/sgx/src/untrusted/keyvalue_store.h @@ -0,0 +1,68 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __KEYVALUE_STORE_H +#define __KEYVALUE_STORE_H + +/** + * @brief Tell whether a given key currently exists + * + * @param key the key to check for + * + * @returns whether the key exists + */ +bool kvstore_exists(char* key); + +/** + * @brief Save the given data to the given key + * + * @param key the key to save the data to + * @param data the buffer containing the data to write + * @param data_size the data size in bytes + * + * @returns whether saving succeeded + */ +bool kvstore_save(char* key, uint8_t* data, size_t data_size); + +/** + * @brief Read the given key into the given buffer + * + * @param key the key to read from + * @param data_buf the buffer to read the data to + * @param buffer_size the buffer size in bytes + * + * @returns the number of bytes read, or ZERO upon error + */ +size_t kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size); + +/** + * @brief Remove any data associated with the given key + * + * @param key the key to remove + * + * @returns whether key removal was successful + */ +bool kvstore_remove(char* key); + +#endif // __KEYVALUE_STORE_H \ No newline at end of file diff --git a/firmware/src/sgx/src/untrusted/log.c b/firmware/src/sgx/src/untrusted/log.c new file mode 100644 index 00000000..f8aa9e47 --- /dev/null +++ b/firmware/src/sgx/src/untrusted/log.c @@ -0,0 +1,66 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "log.h" + +static char* log_prefix = (char*)NULL; + +void LOG(const char *format, ...) { + va_list args; + va_start(args, format); + + if (log_prefix) { + printf("%s", log_prefix); + } + vprintf(format, args); + + va_end(args); +} + +void LOG_HEX(const char *prefix, const void *buffer, const size_t size) { + if (log_prefix) { + printf("%s", log_prefix); + } + printf("%s ", prefix); + if (size > 0) { + printf("0x"); + for (unsigned int i = 0; i < size; i++) { + printf("%02x", ((unsigned char *)buffer)[i]); + } + } else { + printf("EMPTY"); + } + printf("\n"); +} + +void log_set_prefix(const char* prefix) { + log_prefix = (char*)prefix; +} + +void log_clear_prefix() { + log_prefix = (char*)NULL; +} \ No newline at end of file diff --git a/firmware/src/sgx/src/untrusted/log.h b/firmware/src/sgx/src/untrusted/log.h new file mode 100644 index 00000000..99f16a1d --- /dev/null +++ b/firmware/src/sgx/src/untrusted/log.h @@ -0,0 +1,56 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __LOG_H +#define __LOG_H + +#include + +/** + * @brief Works just like printf + */ +void LOG(const char *format, ...); + +/** + * @brief Print buffer in hex format with prefix + * + * @param prefix the log prefix (the general log prefix will be prepended too) + * @param buffer the buffer containing the bytes to output as hex chars + * @param size the size of buffer in bytes + */ +void LOG_HEX(const char *prefix, const void *buffer, const size_t size); + +/** + * @brief Set a prefix for all logs + * + * @param prefix the prefix to use for logs + */ +void log_set_prefix(const char* prefix); + +/** + * @brief Clear any prefix set for logs + */ +void log_clear_prefix(); + +#endif // __LOG_H diff --git a/firmware/src/sgx/src/untrusted/main.c b/firmware/src/sgx/src/untrusted/main.c new file mode 100644 index 00000000..56dfc1fd --- /dev/null +++ b/firmware/src/sgx/src/untrusted/main.c @@ -0,0 +1,169 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/******************************************************************************* + * powHSM + * + * Main SGX source file + ********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "io.h" +#include "enclave_proxy.h" +#include "enclave_provider.h" +#include "log.h" + +// Argp option spec +static struct argp_option options[] = { + {"bind", 'b', "ADDRESS", 0, "Address to bind to", 0}, + {"port", 'p', "PORT", 0, "Port to listen on", 0}, + {0} +}; + +// Argument definitions for argp +struct arguments { + char *bind; + int port; + char *enclave_path; +}; + +// Argp individual option parsing function +static error_t parse_opt(int key, char *arg, struct argp_state *state) { + struct arguments *arguments = state->input; + + switch (key) { + case 'b': + arguments->bind = arg; + break; + case 'p': + if (!(arguments->port = atoi(arg))) { + argp_failure(state, 1, 0, "Invalid numeric port given: %s", arg); + } + break; + case ARGP_KEY_ARG: + if (arguments->enclave_path) { + argp_failure(state, 1, 0, "Too many arguments given"); + } + arguments->enclave_path = arg; + break; + case ARGP_KEY_END: + if (!arguments->enclave_path) { + argp_failure(state, 1, 0, "No enclave path given"); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +// The argp parser +static struct argp argp = { + options, + parse_opt, + "ENCLAVE_PATH", + "SGX powHSM", + NULL, NULL, NULL, +}; + +static void finalise_with(int exit_code) { + printf("Terminating...\n"); + io_finalise(); + // TODO: finalize enclave, i/o + printf("Done. Bye.\n"); + exit(exit_code); +} + +static void finalise() { + finalise_with(0); +} + +static void set_signal_handlers() { + signal(SIGINT, finalise); + signal(SIGTERM, finalise); + signal(SIGHUP, finalise); + signal(SIGABRT, finalise); +} + +int main(int argc, char **argv) { + set_signal_handlers(); + + // Arguments (with default values) + struct arguments arguments = { + "127.0.0.1", // Bind address + 7777, // Port + NULL, // Enclave path + }; + + // Parse arguments + argp_parse(&argp, argc, argv, 0, 0, &arguments); + + LOG("SGX powHSM starting...\n"); + + LOG("Initialising enclave provider...\n"); + if (!epro_init(arguments.enclave_path)) { + LOG("Error initialising enclave provider\n"); + goto main_error; + } + + LOG("Initialising system...\n"); + if (!eprx_system_init(io_apdu_buffer, sizeof(io_apdu_buffer))) { + LOG("Error initialising system\n"); + goto main_error; + } + LOG("System initialised\n"); + + LOG("Initialising server...\n"); + if (!io_init(arguments.port, arguments.bind)) { + LOG("Error initialising server\n"); + goto main_error; + } + LOG("Server initialised\n"); + + LOG("HSM running...\n"); + + unsigned int rx = 0; + unsigned int tx = 0; + + while (true) { + rx = io_exchange(tx); + + if (rx) { + tx = eprx_system_process_apdu(rx); + } + } + + LOG("Exited main loop unexpectedly\n"); + +main_error: + finalise_with(1); + return 1; +} diff --git a/firmware/src/tcpsigner/Makefile b/firmware/src/tcpsigner/Makefile index 248ab31b..607bdeb0 100644 --- a/firmware/src/tcpsigner/Makefile +++ b/firmware/src/tcpsigner/Makefile @@ -63,7 +63,6 @@ SIM_OBJS = $(patsubst $(SRCPATH)/%.c, $(OBJDIR)/%.o, $(SIM_SRCS)) SRCS = $(SIGN_SRCS) $(COMMON_SRCS) $(HAL_SRCS) $(SIM_SRCS) OBJS = $(SIGN_OBJS) $(SIM_OBJS) - all: $(PROG) $(PROG): $(OBJS) $(CC) $(COVFLAGS) -o $@ $(CFLAGS) $(OBJS) $(LDFLAGS) diff --git a/firmware/src/tcpsigner/src/hsmsim_io.c b/firmware/src/tcpsigner/src/hsmsim_io.c index 9f80c92d..76782367 100644 --- a/firmware/src/tcpsigner/src/hsmsim_io.c +++ b/firmware/src/tcpsigner/src/hsmsim_io.c @@ -41,7 +41,7 @@ * APDU buffer */ #define IO_APDU_BUFFER_SIZE 85 -static unsigned char apdu_buffer[IO_APDU_BUFFER_SIZE]; +static unsigned char io_apdu_buffer[IO_APDU_BUFFER_SIZE]; #define MAX_FUZZ_TRANSFER IO_APDU_BUFFER_SIZE @@ -52,8 +52,8 @@ enum io_mode_e io_mode; * For the TCP server */ int server; -int socketfd; -struct sockaddr_in servaddr, cli; +int connfd; +struct sockaddr_in servaddr, cliaddr; /** * For the file input mode @@ -150,8 +150,8 @@ static int start_server(int port, const char *host) { * @returns connection file descriptor */ static int accept_connection(int sockfd) { - int len = sizeof(cli); - int connfd = accept(sockfd, (struct sockaddr *)&cli, &len); + int len = sizeof(cliaddr); + int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len); if (connfd < 0) { LOG("Client connection failed...\n"); exit(1); @@ -162,12 +162,12 @@ static int accept_connection(int sockfd) { } void hsmsim_io_init() { - communication_init(apdu_buffer, sizeof(apdu_buffer)); + communication_init(io_apdu_buffer, sizeof(io_apdu_buffer)); } void hsmsim_io_set_and_start_server(int port, const char *host) { server = start_server(port, host); - socketfd = 0; + connfd = 0; io_mode = IO_MODE_SERVER; io_exchange_write_only = false; } @@ -187,8 +187,8 @@ void hsmsim_io_set_replica_file(FILE *_replica_file) { */ void hsmsim_io_reply() { io_exchange_write_only = true; - apdu_buffer[0] = (APDU_OK & 0xff00) >> 8; - apdu_buffer[1] = APDU_OK & 0xff; + io_apdu_buffer[0] = (APDU_OK & 0xff00) >> 8; + io_apdu_buffer[1] = APDU_OK & 0xff; hsmsim_io_exchange(2); } @@ -203,8 +203,8 @@ static unsigned short io_exchange_server(unsigned short tx) { int readlen; while (true) { - if (!socketfd) { - socketfd = accept_connection(server); + if (!connfd) { + connfd = accept_connection(server); tx = 0; } @@ -216,18 +216,18 @@ static unsigned short io_exchange_server(unsigned short tx) { tx_net = tx - 2; tx_net = htonl(tx_net); size_t written; - if (send(socketfd, &tx_net, sizeof(tx_net), MSG_NOSIGNAL) == -1) { + if (send(connfd, &tx_net, sizeof(tx_net), MSG_NOSIGNAL) == -1) { LOG("Connection closed by the client\n"); - socketfd = 0; + connfd = 0; continue; } // Write APDU - if (send(socketfd, apdu_buffer, tx, MSG_NOSIGNAL) == -1) { + if (send(connfd, io_apdu_buffer, tx, MSG_NOSIGNAL) == -1) { LOG("Connection closed by the client\n"); - socketfd = 0; + connfd = 0; continue; } - LOG_HEX("Dongle =>", apdu_buffer, tx); + LOG_HEX("Dongle =>", io_apdu_buffer, tx); } // Only write? We're done @@ -239,21 +239,21 @@ static unsigned short io_exchange_server(unsigned short tx) { // Read APDU length // (encoded in 4 bytes network byte-order) // (compatibility with LegerBlue commTCP.py) - readlen = read(socketfd, &rx_net, sizeof(rx_net)); + readlen = read(connfd, &rx_net, sizeof(rx_net)); if (readlen == sizeof(rx_net)) { rx = ntohl(rx_net); if (rx > 0) { // Read APDU from socket - readlen = read(socketfd, apdu_buffer, sizeof(apdu_buffer)); + readlen = read(connfd, io_apdu_buffer, sizeof(io_apdu_buffer)); if (readlen != rx) { LOG("Error reading APDU (got %d bytes != %d bytes). " "Disconnected\n", readlen, rx); - socketfd = 0; + connfd = 0; continue; } - LOG_HEX("Dongle <=", apdu_buffer, rx); + LOG_HEX("Dongle <=", io_apdu_buffer, rx); } else { // Empty packet LOG("Dongle <= \n"); @@ -273,7 +273,7 @@ static unsigned short io_exchange_server(unsigned short tx) { readlen, sizeof(rx_net)); } - socketfd = 0; + connfd = 0; } } @@ -285,7 +285,7 @@ static unsigned short io_exchange_server(unsigned short tx) { static unsigned short io_exchange_file(unsigned char tx, FILE *input_file) { // File input format: |1 byte length| |len bytes data| static unsigned long file_index = 0; - LOG_HEX("Dongle => ", apdu_buffer, tx); + LOG_HEX("Dongle => ", io_apdu_buffer, tx); // Only write? We're done if (io_exchange_write_only) { @@ -315,7 +315,8 @@ static unsigned short io_exchange_file(unsigned char tx, FILE *input_file) { capped_rx, announced_rx, file_index); - unsigned short rx = fread(apdu_buffer, sizeof(char), capped_rx, input_file); + unsigned short rx = + fread(io_apdu_buffer, sizeof(char), capped_rx, input_file); if (rx != capped_rx) { // if we reach EOF while reading the data portion it means @@ -344,7 +345,7 @@ static unsigned short io_exchange_file(unsigned char tx, FILE *input_file) { } file_index += index_offset; - LOG_HEX("Dongle <= ", apdu_buffer, rx); + LOG_HEX("Dongle <= ", io_apdu_buffer, rx); return capped_rx; } @@ -355,9 +356,9 @@ static unsigned short io_exchange_file(unsigned char tx, FILE *input_file) { */ static unsigned int replicate_to_file(FILE *replica_file, unsigned short rx) { unsigned char rx_byte = rx; - LOG_HEX("Replica =>", apdu_buffer, rx_byte); + LOG_HEX("Replica =>", io_apdu_buffer, rx_byte); unsigned int written = fwrite(&rx_byte, sizeof(char), 1, replica_file); - written += fwrite(apdu_buffer, sizeof(char), rx_byte, replica_file); + written += fwrite(io_apdu_buffer, sizeof(char), rx_byte, replica_file); // XXX: This should not be necessary. We are correctly closing the file // at the end of the process. But for whatever reason, this does not seem diff --git a/firmware/src/tcpsigner/src/tcpsigner.c b/firmware/src/tcpsigner/src/tcpsigner.c index 4eb7c7ac..8ff39700 100644 --- a/firmware/src/tcpsigner/src/tcpsigner.c +++ b/firmware/src/tcpsigner/src/tcpsigner.c @@ -204,10 +204,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { dest_size = sizeof(arguments->difficulty) / sizeof(arguments->difficulty[0]); } - bigint(arguments->difficulty_b, - sizeof(arguments->difficulty_b), - dest, - dest_size); + parse_bigint_be(arguments->difficulty_b, + sizeof(arguments->difficulty_b), + dest, + dest_size); break; case 'n': arguments->network = arg; @@ -321,10 +321,11 @@ void main(int argc, char **argv) { arguments.difficulty_b + (sizeof(arguments.difficulty_b) - strlen(arguments.difficulty_s + 2 /* Skip 0x */) / 2)); - bigint(arguments.difficulty_b, - sizeof(arguments.difficulty_b), - arguments.difficulty, - sizeof(arguments.difficulty) / sizeof(arguments.difficulty[0])); + parse_bigint_be(arguments.difficulty_b, + sizeof(arguments.difficulty_b), + arguments.difficulty, + sizeof(arguments.difficulty) / + sizeof(arguments.difficulty[0])); // Convert default network arguments.network_identifier = get_network_identifier_by_name(arguments.network); diff --git a/firmware/src/ledger/signer/make-difficulty.py b/firmware/src/util/make-difficulty.py similarity index 100% rename from firmware/src/ledger/signer/make-difficulty.py rename to firmware/src/util/make-difficulty.py diff --git a/firmware/src/ledger/signer/make-initial-block-hash.py b/firmware/src/util/make-initial-block-hash.py similarity index 100% rename from firmware/src/ledger/signer/make-initial-block-hash.py rename to firmware/src/util/make-initial-block-hash.py diff --git a/firmware/src/util/signer.mk b/firmware/src/util/signer.mk new file mode 100644 index 00000000..b5dee8d4 --- /dev/null +++ b/firmware/src/util/signer.mk @@ -0,0 +1,28 @@ +SIGNER_FLAGS = + +# Convert min required difficulty to what the compiler expects +ifneq ($(TARGET_DIFFICULTY),) +CONVERTED_MRD = $(shell python $(UTIL_DIR)/make-difficulty.py $(TARGET_DIFFICULTY)) +$(info Building with min required difficulty set to "$(CONVERTED_MRD)") +SIGNER_FLAGS += -DPARAM_MIN_REQUIRED_DIFFICULTY="$(CONVERTED_MRD)" +endif + +# Convert checkpoint to what the compiler expects +ifneq ($(CHECKPOINT),) +CONVERTED_CHKP = $(shell python $(UTIL_DIR)/make-initial-block-hash.py $(CHECKPOINT)) +$(info Building with checkpoint set to "$(CONVERTED_CHKP)") +SIGNER_FLAGS += -DPARAM_INITIAL_BLOCK_HASH="$(CONVERTED_CHKP)" +endif + +# Specify target network (i.e., REGTEST or TESTNET). Otherwise it defaults to MAINNET. +ifeq ($(NETWORK),REGTEST) +$(info Building for Regtest) +SIGNER_FLAGS += -DREGTEST +endif + +ifeq ($(NETWORK),TESTNET) +$(info Building for Testnet) +SIGNER_FLAGS += -DTESTNET +endif + +$(info $(SIGNER_FLAGS)) \ No newline at end of file diff --git a/firmware/test/.gitignore b/firmware/test/.gitignore index b57b8c52..bf4d7d86 100644 --- a/firmware/test/.gitignore +++ b/firmware/test/.gitignore @@ -1,3 +1,10 @@ # Ignore compiled python modules and cache **/*.pyc **/__pycache__ + + +# Ignore package artifacts +package/bin +package/build +package/run.spec +package/bundle.tgz diff --git a/firmware/test/README.md b/firmware/test/README.md index 0b85768d..e380e2b5 100644 --- a/firmware/test/README.md +++ b/firmware/test/README.md @@ -1,12 +1,12 @@ # powHSM firmware test suite -## Build parameters for a physical Ledger Nano S +## Blockchain parameters to run the tests on any implementation (i.e., Ledger, SGX, TCPSigner, etc) *Checkpoint:* 0xbdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b *Difficulty:* 0x32 (50) *Network:* regtest -### Example command to build a signer to run the tests against +### Example command to build a ledger signer to run the tests against ```bash ~/repo> firmware/build/build-ledger-signer 0xbdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b 50 regtest @@ -25,3 +25,38 @@ To test against a physical dongle, issue: ```bash ~/repo> firmware/test/test-all dongle ``` + +To test against an SGX instance, there are a few more steps involved, since normally the +instance will be running in an SGX-enabled server elsewhere. Therefore, there are some +prerequisites for this: + +- Your server must have Docker installed +- Have a running SGX powHSM instance on your server +- Said instance MUST be already onboarded +- The instance MUST be running with the server bound to `0.0.0.0` +- We'll assume that the instance is listening on port `7777` + +To run the tests, follow these steps: +- Package the tests: + +```bash +~/repo> firmware/test/package/generate +``` + +- Copy the generated `firmware/test/package/bundle.tgx` to the server on which the SGX + powHSM instance is running +- On the server, decompress the bundle to a directory of your choice (say + `~/powhsm-tests`) +- Run the tests: + +```bash +~/powhsm-tests> ./run-with-docker -dsgx -p7777 -shost.docker.internal -m +``` + +The above command will run the tests in "manual unlocking" mode. You can change this to +automatic unlocking replacing the `-m` option with `-P `. Also, to see the test +runner options, issue: + +```bash +~/powhsm-tests> ./run-with-docker --help +``` diff --git a/firmware/test/cases/case.py b/firmware/test/cases/case.py index 5e8314b8..d24c044d 100644 --- a/firmware/test/cases/case.py +++ b/firmware/test/cases/case.py @@ -29,11 +29,12 @@ class TestCase: RUN_ON_KEY = "runOn" RUN_ON_VALUE_BOTH = "both" - RUN_ON_VALUE_TCPSIGNER = "tcpsigner" - RUN_ON_VALUE_DONGLE = "dongle" + RUN_ON_VALUE_SIMULATOR = "simulator" + RUN_ON_VALUE_DEVICE = "device" RUN_ARGS_PIN_KEY = "pin" RUN_ARGS_MANUAL_KEY = "manual" + RUN_ARGS_DEVICE_KIND_KEY = "deviceKind" op_mapping = None PATHS = None diff --git a/firmware/test/cases/reconnect.py b/firmware/test/cases/reconnect.py index 3adfe51d..bf01e4d6 100644 --- a/firmware/test/cases/reconnect.py +++ b/firmware/test/cases/reconnect.py @@ -42,8 +42,8 @@ def wait_for_reconnection(self): def assert_dongle_mode(self, dongle, expected_mode): curr_mode = dongle.get_current_mode() if curr_mode != expected_mode: - raise TestCaseError(f'Unexpected dongle mode: {curr_mode} ' - f'(expected {expected_mode})') + raise TestCaseError(f"Unexpected dongle mode: {curr_mode} " + f"(expected {expected_mode})") def run(self, dongle, debug, run_args): try: @@ -67,26 +67,35 @@ def run(self, dongle, debug, run_args): # Unlock device (can be performed automatically or manually by user) if manual_unlock: - output.prompt_user('Please disconnect and re-connect the device, ' - 'unlock it and open the signer', wait_confirm=True) + if run_args[TestCase.RUN_ARGS_DEVICE_KIND_KEY] == "ledger": + output.prompt_user("Please disconnect and re-connect the device, " + "unlock it and make sure the signer is running", + wait_confirm=True) + else: + output.prompt_user("Please restart the powHSM and unlock it", + wait_confirm=True) self.wait_for_reconnection() dongle.connect() else: - output.prompt_user('Please disconnect and re-connect the device.', - wait_confirm=True) + if run_args[TestCase.RUN_ARGS_DEVICE_KIND_KEY] == "ledger": + output.prompt_user("Please disconnect and re-connect the device.", + wait_confirm=True) + else: + output.prompt_user("Please restart the powHSM", + wait_confirm=True) self.wait_for_reconnection() dongle.connect() self.assert_dongle_mode(dongle, HSM2Dongle.MODE.BOOTLOADER) if not dongle.echo(): raise TestCaseError("Echo error") if not dongle.unlock(pin): - raise TestCaseError('Failed to unlock device') + raise TestCaseError("Failed to unlock device") try: dongle.exit_menu(autoexec=True) except Exception: # exit_menu() always throws due to USB disconnection. we don't care pass - output.debug('Device unlocked') + output.debug("Device unlocked") # Disconnect from bootloader, connect to app dongle.disconnect() self.wait_for_reconnection() diff --git a/firmware/test/options.py b/firmware/test/options.py index 3d44c2c0..bba1348c 100644 --- a/firmware/test/options.py +++ b/firmware/test/options.py @@ -41,11 +41,12 @@ def parse(self): parser.add_argument( "-d", - "--dongle", - dest="dongle", - action="store_true", - default=False, - help="Run with a physical dongle (defaults to no)", + "--device", + dest="device", + choices=["tcpsigner", "ledger", "sgx"], + default="tcpsigner", + help="Type of device to run with (one of \"tcpsigner\", \"ledger\" or " + "\"sgx\", defaults to \"tcpsigner\")", ) parser.add_argument( "-r", @@ -70,8 +71,8 @@ def parse(self): help=f"Listening port (default {self.default_port})", ) parser.add_argument( - "-b", - "--bind", + "-s", + "--server", dest="host", default=self.default_host, help=f"IP to bind to (default '{self.default_host}')", diff --git a/firmware/test/package/Dockerfile b/firmware/test/package/Dockerfile new file mode 100644 index 00000000..5b3f593e --- /dev/null +++ b/firmware/test/package/Dockerfile @@ -0,0 +1 @@ +FROM python:3.12-slim-bookworm diff --git a/firmware/test/package/build-runner b/firmware/test/package/build-runner new file mode 100755 index 00000000..d902d488 --- /dev/null +++ b/firmware/test/package/build-runner @@ -0,0 +1,25 @@ +#!/bin/bash + +if [[ $1 == "exec" ]]; then + # Directories + PACKAGE_DIR=$(dirname $0) + BIN_DIR=bin + + # Remove existing build + + # Build + echo "Building test runner..." + + cd $PACKAGE_DIR + rm -rf $BIN_DIR + mkdir $BIN_DIR + pyinstaller --distpath $BIN_DIR --onefile ../run.py + rm -rf build run.spec + + echo "Done." +else + REPO_ROOT=$(dirname $0)/../../.. + TESTS_DIR=$(realpath $(dirname $0)/.. --relative-to=$REPO_ROOT) + + $REPO_ROOT/docker/mware/do-notty-nousb /hsm2/$TESTS_DIR "./package/$(basename $0) exec" +fi diff --git a/firmware/test/package/generate b/firmware/test/package/generate new file mode 100755 index 00000000..7cb8cf27 --- /dev/null +++ b/firmware/test/package/generate @@ -0,0 +1,24 @@ +#!/bin/bash + +# Directories and files +PACKAGE_DIR=$(dirname $0) +BIN_DIR=$PACKAGE_DIR/bin +RUNNER_FILE=$BIN_DIR/run +RESOURCES_DIR=$PACKAGE_DIR/../resources +TARGET_DIR=$PACKAGE_DIR/bundle +BUNDLE_FILE=$PACKAGE_DIR/bundle.tgz + +rm -rf $TARGET_DIR +mkdir $TARGET_DIR +$PACKAGE_DIR/build-runner +mkdir $TARGET_DIR/bin +cp $RUNNER_FILE $TARGET_DIR/bin +echo "Copying files..." +cp -R $RESOURCES_DIR $TARGET_DIR +cp $PACKAGE_DIR/Dockerfile $TARGET_DIR +cp $PACKAGE_DIR/run-with-docker $TARGET_DIR +echo "Generating package..." +tar -czf $BUNDLE_FILE -C $TARGET_DIR . +echo "Cleaning up..." +rm -rf $TARGET_DIR $BIN_DIR +echo "Done." diff --git a/firmware/test/package/run-with-docker b/firmware/test/package/run-with-docker new file mode 100755 index 00000000..71c412ce --- /dev/null +++ b/firmware/test/package/run-with-docker @@ -0,0 +1,7 @@ +#!/bin/bash + +SCRIPT_DIR=$(realpath $(dirname $0)) +DOCKER_IMAGE=powhsm:tests + +docker build -t $DOCKER_IMAGE . +docker run -ti --rm -v $SCRIPT_DIR:/tests --add-host=host.docker.internal:host-gateway -w /tests $DOCKER_IMAGE ./bin/run $@ diff --git a/firmware/test/resources/307-reconnect-dongle.json b/firmware/test/resources/307-reconnect-dongle.json index 2b0a011f..7ddb3ce8 100644 --- a/firmware/test/resources/307-reconnect-dongle.json +++ b/firmware/test/resources/307-reconnect-dongle.json @@ -2,5 +2,5 @@ "name": "Reconnect dongle", "operation": "reconnectDongle", "exitSigner": true, - "runOn": "dongle" + "runOn": "device" } diff --git a/firmware/test/resources/308-get-after-reconnection.json b/firmware/test/resources/308-get-after-reconnection.json index 1bca9a9d..0183c966 100644 --- a/firmware/test/resources/308-get-after-reconnection.json +++ b/firmware/test/resources/308-get-after-reconnection.json @@ -1,7 +1,7 @@ { "name": "Get blockchain state after reconnection", "operation": "getState", - "runOn": "dongle", + "runOn": "device", "expected": { "best_block": "b4d586b2c2f51d6dcb6e7870df329e780d8e4b85517b91a822dc52c04d801f4b", "newest_valid_block": "05cf1ca3197482828cfa5d1777350996593bdd62f73ce388a280a9e08b69dac9", diff --git a/firmware/test/resources/602-sign-long-redeemscript.json b/firmware/test/resources/602-sign-long-redeemscript.json index d1f382d4..4274a850 100644 --- a/firmware/test/resources/602-sign-long-redeemscript.json +++ b/firmware/test/resources/602-sign-long-redeemscript.json @@ -1,7 +1,7 @@ { "name": "Sign with a long redeemScript", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "b669533aad43aca9bb1f12a29d3cf8852fa7279747c503eb6632c98faf46871c", "btcTx": "0100000001ea0972997fabb54841aea288b81fe5c337b997bca3874cc8c2ba00b743c5d7c164000000fd13020000000000000000000000000000004d010258210271df73590582950f35db74b143d5b33d236b85c4879b843b72501ec6a2848938210235f05d65271026dee084dfa85b4e1d9003d7222e41b77ff7a9d96dde1c1df4b621021af9a946169d37fe597a8f18ae24bab5f1d67389b4969e3b2968d83a89ddb77221035a1991fea6c84847cfcd744c2b2ceda52068ee6121ab45d401d589946586399821038dab9d13aab76fb67dae25ff3444e5fa034e92abd734813193c808fef1f3c4402103a4729c1b5985797db6d6684b1d6ed20799bd2907583522a60849cad2aafa38132102d6b7d281af02859e6ba4f7e17284ea5e9ff6f8ab499ecbbc15a716497491d9be21034e85baa81c962d5649beff5c8df9f615369e7e7a107ce3e4a13b8ffbb2fbf906210271e5df883f5ba4e741c97bbcaca3d6c76c5a290db4b04554a99bbba5834ead6b2102f9994a4066656e8d31da1bdf68da7443d0160805c378ec068d03ced7b94d15142102d7582f433664a6b3ed5ad4ce8c62fb9771c1b73306faa2ea8183ff4a325193ce2102a036e410405eb60f6637e0f23507ef8414083ac4c3b1f295268b4ee96dd19411210203e012375a9cd95c9e35e1e084b567941b5961e9cc1679cde20ed2fa53af2ab521020001c24db69a74345f8b16b318b19c87da14b3e5cb7583be9a902aead6084b3321025c587d630165a13a6fe9460ea572e42f0bacf5f66270e7440c100775821d38a65faeffffffff02b011e111000000001976a91447a5bfd415108c37e918e8b114b83f8d5ae9834988ac00bbeea00000000017a914896ed9f3446d51b5510f7f0b6ef81b2bde55140e8700000000", diff --git a/firmware/test/resources/610-sign-tx-with-many-inputs.json b/firmware/test/resources/610-sign-tx-with-many-inputs.json index 9d7b318c..63105f2e 100644 --- a/firmware/test/resources/610-sign-tx-with-many-inputs.json +++ b/firmware/test/resources/610-sign-tx-with-many-inputs.json @@ -1,7 +1,7 @@ { "name": "Sign with a BTC tx with many inputs", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "ab9080a57266f6bf12656ca540ca59192bfe8e619e3394be1b98027d9923c787", "btcTx": "01000000fc208393eed3f5e4952ee809fb8976dea39994d35f8af16a683df073b7e37acb91300000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffdb5a526cf8e20fb00cfe88ed01041bd49992a6426005fe8a53629f8b154b0fb0a00000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3bec19bab0ad389adb52d339350858f6d3ea81d566dfa324d228d2abb4b08abf7d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff96b616b29a71b829d04e0781410304f70b4f931d776eb5db157d3816d7b76a6db60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff9bdcd1bd9e53354bcefaaf576a5c9999120300a704e08d6c0b33bb2190fad933610000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff838a64df688e1baf0bcf479f6cde3dd2a577f9f736ad7f0dc96dc016c0274690080000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff866c236c1c98e8a7d63571cd038a90d4f15da63b04113263793ec62fd066aa961f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc466796d245040ac945d7af542caf15a400c2d5b98523aa8fd2ff771524e39d6530000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff001ff1969be15958052e6220409b7a029c89eaa82647b76e29f36c2a7bf158ecaa0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3c46742a75f2f5d9b9a2543126e642f5cdbad20b92e53a6d43fa66f07723f552440000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff20c1613672f0ef9c036094a4992a4d322313756cb50a995470f532c3fbc5f06dd00000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff650a2885dce9423544c4357da26fe18bcc88ce0fdcfc01c8a21a2ea5ba218277fd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff60f7d77c55d6f79e0e6949804c76a39487345d6b3ef276e88b9e670925ae8238160000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffbbe42315ea341105c82525f00ac05855f925698007e4dbb754b5bcb36322b245250000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff38af7d4a9a3690ef73262b8e22fc500e65ff1251980aea9cdea03d62f540843a650000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffd5f1439ce8454383576e9b69b9cf336b74eb188f4402c035e02cc4cd01353d29960000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff22314b7a254e524341eb316d46f3e5873068944bc06d284d8a8898713591847adf0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff896dfcb27e791349f9e06db7da8d8bc1b1680d8833b1e28499de7270bac2566e1e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffffdb372b56cd12c68480ee5e59820b3332694b0cac3f3c2b7182b9ffaab9b2327320000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff740c8461bf9b6363582a189b91fa5c3f8138ddaa5a339103bd011591d033bbfb800000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff35db4c8ba2d9bb613a293b4ee3cc08e8500025db4a0fa2f17659317827e987ac6b0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff9dc5116c995bb6fe84272f8bbadce7a6bf6b693172b992206390a00c7a75e49c1a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffddbf801ed39cecdc9c6cf996800af267b41808892aa977d53b193d64bfb2256f060000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff456f97e065b1753f391ee02c83230a1057245dac74772456f2b56b3418ceb705580000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff13a8f80f436b2aaf316b3ee4f58244427ead812185a94ce6c13d5569004a5985a50000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffb5c8f337cee7db201a08ac70699d3719c2ec8e2078f7eed9249ea54ff45ad3540c0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff99cd6885a17c488c35d678a1f92a5bcc8fbf9585f2c867c44a14a677b6012d78980000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffec59b4bde6c6e2c595c8134adc0c40511352d26287bf2c1cbd3eb9f2a1b901bffb0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff8b200973ad2e0e972a717bce05afb64cd86a22f32615b1ab38d1326ac11c7baf030000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe171a0d2bc948086a6320c3238c13520f8e5d855ec679a413a0078b9fb1bc1cbdf0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4df6ec68787280d39f7f39359b9c9612f3d1fe90de3cb9c694227682b328c6ec610000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1d0586fa7fd353a85daf4603bb860ca6ad4c64e7ac9824164a4790507930d3ca7b0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffbfc42cc9bc57409d7d4bef67780f356099c39a1593927a31cf14c59fafdac03c960000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe2011fe5121c24404ad283e8b8f1a3c67b79e023d27f82dbece3e5afdfeb23984e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff196e09ec1779825794584bdf7c199bd20d300808c3120727ffa9a51bc427f021fb0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff6ba1a69b1505784e1c427811cb2b0a35947cfcddd7d1fdc766789e2e78e6d1a3660000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7ce8b8ef8bbedce1a5316427f55802a7adae296b88c23474e589366ef634c7ce770000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7f1a54fa0f655a29f3bf25bde2a9cca21c22430fc15c1b29d81913c4118face3cb0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1db0fcf2e89271b01a76ed5ff3cd40fe8107eb7cee9587d055d02976e6411c793e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4d41dc4a74e6077cf458e88e558197f13428c05a0e1daa0c1cedb4155b8cd56d580000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffd22dc3dd384c29c78bfaf29b1569b06e0d40e457e4e7df9ad6ed6b5958a32208280000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff5ca7b28fa1960c50a235a6c607fa3c1410da9d257c1aba0c6822012989ea4fb2720000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1ed49ca83c361450e315ae838118647c7b9e84a60d21f4eb45dc33a4b305d2a04a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffda9de78bbc5e2fada30737d3b2205a434c0f76cbd9c67d233dfa5f843d4cbf1b7f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff3c0f8dbd1fc94169494a82aeb9cecb79233fa731aa2c08e420f560138176a397d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1057bad591f1d4a70d0405cac990a410413d0ea21db42290a4f7230103edefe8c60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff2a73adac6022bc9d4a71359c2a8d1cd451dd83d87bb6f77c7145be2e4aef1f641d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff8b8ff7cded51f82b63a1e5197eaecdaf82a206367d6c210a8c90d46515bca3f4130000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffeb4eb038bd905fa80aa73298f0e49fddc10091ae9389620bbcc6ce2b812d8c891e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff29a703b214c8344a872525f7891017490b6bc9458ec28edfef99c9b1a50279e9fd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff17fac595af95dc63c7462f6237db65afbd6604463e9be05aed9bb9f44b26f34ba0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff736f6a72fff2dbf5884d51865603602075573838fea94ea59e0cd76e3560659dbc0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff2c5c164ad75c9fb44e5f9a97dec2a572a0870b4cb663c6f46858386057e03dfb4e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff653eeeca3885c3e817ff24b3f6ad2362a6250ad7dd65195d90e16c55df0e3086440000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffed3a0db1bd0246b7c9c8dd364ed69c090af7376c18c18773c0ea271c8903e19e460000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff479c3c9dd2881a9faa0fcb3a68b8712cc4cbe9aa83eda397747c24aff40c6ee99a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff3d4b6e3ddfa7fbe6cb13ede7ef64a2c5e3b625dea41d5fab6d5c44471c87bff8c0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffb2a1982f068a6d23f29aee03232089039700406e66f288ef56371a6a39538b98230000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffbd97f7b700e6c4f217f2cd0a48fb02b05e9a42357a0fb81b415adea0051ab3ae8d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7dc21621497ea6dd9945ecaa736e0cb63168976b927049512f59bab60b2c7ce5270000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff121c0b5b496ea58e76d0d046b39e35c91b64038fad04634dd3020b1cf795bcd0350000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff057ec13725eff2b2acb6bf365dae44793a8492c465e1500c68ccd16fd8fb90e3510000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4bd56b93479cf637025d2320ab0d66081ccfde7e539550d2ae13211b5b62d6d12e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff0ae0170d070b4ea71d7fa03d6bd46729080a1fd3e8796d94aa40f5815b67ba58710000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffffbdeb7a9f470dd5a6357be1f379c1de00dce811e73cd7640410bc13acafcad6ac80000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa1dfaa00fb5aa769d37d940de7c385ad896fbb7a5b0af4cc79497dbf94b229be400000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff01f51183c1a3e60dece5a0634252c64c70bf896df3ff847c802aff175fd13d1abe0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7a84b406f84e3109d250237d7b304e26240ca9d6743b437f4e2fd50caeded2c7f30000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffbcd044d34a17aaf896e79771d15a1757e94249c40ef6a4bf2c1b27fdeaecc098550000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff12c15ad37d90ae705fe5eca57fe71b99f1ee08045505418067152b0abae9d5ae340000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff5fb3e4109340eaba35353f53547930785c182e9aaf12cfbeb3f0b84d03bc9828dd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff27dad98494ace9d31d66b43becdeb0c396163219a7c50ef19d7eeba684fcf2733e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffbf07ca17e2ba3aa2ec9141d1445d6ccb97ed0c4b3c324c8b28875f03c1511cbe210000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff5aea78368739a0a99f857e5bd5c67c9d15fdbcab20c969efc88ba16fbb59ecb0470000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff06eb17c61530b9e3de4229da3d1cc547764fa1ac8cf8daebcafb464c32a75c061d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa2140ce19132cf7568ed66a5a5d350beba936d8ef721ab5cacd9da48b99fd589040000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff8d8ae25e2a9d51a963590c6a150370dcfd21c6192d01263c9cbc2a26bbbef50f3c0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7da660dfd104f937379df3f91b3247dd6a1e7350c9b4e97ae31860fb4b2e50124e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffdc949413250fc8d658faab45657294ea5e17e6847068d5507f079439886f4377050000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffddff8fd77acf3e36c9a17e77438c2f5dd24cdd979d00d0cd6f24b81b52d429c8550000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff093eea44d3c6ec664086b486554f5d9522ec793a6e23de8023e43cdc8e5437e1a10000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff399cb648d0f1694b739c85e4a07d1669e99a13b895ad36771197c8820c5e85df8b0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff7f58cfe7ccd2e7c1ee7c2949e420676946c98b0131fbc70701a1d833084de6ccd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc2c42c7c0cf0c0e4bc36e3bd82d462c199300980c53d41985ed51323a1fcf86c2a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff34fda05b7bafb0552d3c799afbc8aa1b7df48fece6ada860239551ea13dd8e6a5f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa0e7b50a187982a5e9cba03d66dbc11da899133a7886d5340fd3beedd9020c777a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3131971adc42849302cf6b5be0389b6d6d6455801dc14d0fe8435ce87ba0cd2c0f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff62be83b2e045735ec20553c098461810e6b377bdf985f4e96a79358f0add9000130000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff8f8049bea641d8c7c5aba8d89f92068c1cd8ee0b2239191e958e1ff2164bce73db0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffddb7c635dbb40c34f604f59f560b329eaadeed0f6d5d34cbf6721d8c68a5cc0eea0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3aede035a47c0f3923907bf4e4d8ecc5fbb9287451b25c42fe6f1adf134f37b2610000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1b0480c8356857bf411b4c35efad3590f836f884671fac09fc34791e8f37b2f85f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc6a4ae2abcac03e78a6d3f3fe4d07c6e75e2e344064434c161085a7388be4caa270000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffbc01556be797cee3e8e6a853e982a0394310731c7956a97dd3ea5f71692bc3caee0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff9ac04670b00019b03de7cf83c8de383331e700138fa9d455c46317f2c7fd307d170000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc94a3ca138dc2c7c9b5ea6c668ab6267b406e4646090428cc583c6347bfeb63ef80000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffbffc8f36f7033f3b8f1f6961d29c3ccbff789b4f6906c3f899f97ab39e2cc379a80000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff15b58d5689af77e10425f2233b8c7862533340115cd12dc5ca8be3819f049862950000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff40695075ec0801bab187809ae2e4f4f05fef896ef4812dc6fa4884a15c58a5aa270000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffb8a4fac59edcff10f95f85d8cb3bd08cbc5e6b3a32d89404c57be162d12fdcf83e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffabfda27b2402c3cdd9ced27c1ad817f7b9d66e5fe4bda3a730076cd1b390b62fcd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffffdba1b98014583c1910127ca0b2bebc866c182e7cbd625e057fec48993ae3a15f50000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe6c07631157d0a59de4f709f851cdf011ffc791e97458b979c47e803b17c8ac6120000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa33560970083ead4a1b4811637d0214821d273f76689063e70e5cdad445619f02a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa6cb6b5fa8e7e16a17a939a589ba56509968b0a4a0a524edca1ff5f87135a485ce0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff10c18592edfa0527921870c43d6c370184c8d736bf8f257a3a26af640ff0c70f00000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7c95becdfe24c0056b283539c9512d9b59ab4abef612719af64257fcd6f59ff19d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe05fb119dadb6b81b8767f90b29c5cbc1c9b37df7eb8635fe594f76a9df1b7bc7b0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4aa7ce52246e6ca1b666a04e2f169bb9ce7c4fee96f0791e1a8e41019079aa90640000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff21e8dac66a09014c42dc6c266529600ed2ab2dccecaa690c54adfa970a3751c1ba0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa0831ab9fa3d2280dd94e560baec4e9907516120c7369f56ecfbb61c0c4a9d471f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff5e875a75162a6f06c2218d0abb277d23960b405990d27bff155bb1027595556a230000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff9dfc50f70c5c8d258e56570dc733db059352c95623d05ec5f77b6abaaf5b1187340000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffad8b8d49010eadd905bcbf59d230631b8765a14cd446207515483a36ecdf69d8510000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff937375a0ade6fe025dc44b396cc677dc95a99c338c0a5a7d2e10cbf3bfaa6bf0400000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff2cc3f50dcc03f09710caebf7b40a9eca8ead0244e985a935149d5d3bf92313a55e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff0d1bfda37d4880a1a7ace585032e15baa213695ea80c4e0da1bce4cd3d3708ef880000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff766fe1d4c5d50e67483550a292f5613dbbd87873f1b348a41a4591a13f006174e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe41089062699c802bc7d1f1ee7a7edece087712b2c4d96195df1bd1c1b96e22f600000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe95821ec6aba3bb2bc2bbb05fbdcf5938c45151474378e284c0da71a4f42598eb40000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc8de2b8165f3d6452e554f210c3feee78752f6458a7cc8e686c50409b09ba0868d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff658979574f78b48840529d0c2f724fdc5d468874d3f2d7b42efb06d51be79ac8580000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff87386d3df36046fce4fbb1761623957ae37bcc9a3c12e5783827114e0e15d9ae750000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1b93848666086943a90ed8c967a00d02a79518e217937446492d875cc4ead94a570000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff066539257aa490471a6c92cb88d76e3a2ce44da361c3a02ea394b4427f72d187bb0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff35fecb7b00b46107feaee3c7431ea0f4d9a3bfae636a002b24f0c7981b9867b2b90000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa609c79b9cbbd4a229dd68c3a360d496641d0919cd16844523e2779eb16a002daf0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff11ddd213375e285b5e0ec3f122c222a5f6044ec48b91f1b5129c83b10abbbc33230000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff73a4e7b67d767ce5fbb7ffff25b7aa8483cc30d3dfd891c3df468ea42ec5a397ca0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffd72d23504dd108821a7c6c5f87be28d93dab7fdc6f73736d4543fb6e3af6d2b5ab0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1e7bae5194b0ad5eff39e3102c8e27087f6a28aa21f3b5f54c851123a94ad080500000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa6c895b0a5814030aed7c533dd64186b13706e35edfb4b753e564b6e25c901d84e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff732a838db68e72ea526a3341d74156a36434a062c736be243da3d5321f05365de80000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff7044be9391252383eba2d3686b152860c841bc794e32f2d09ae1008f73c411abb0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff86343b3ea233c734e288cacd24fb16e284f41c4a2840005edb0f7616453f90bdcd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa1673b717368f55044cbf7aa905c9e94bee6189d90fccfeaabe344ee8e8cea35d60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff64c6711bc20592a7d4d11a3834c2eada42e9c4130021a9a605741fd78187543c890000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff04440deb058de4cf02aaedea0df9fb51111afecd302b51c79fe5ece595c1efbac80000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff4888a894b93e63c3f322a4b1cf767e2168f745cfa688a120e0e9ab5b8815718b60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffcf5afa912658236776d2c0c0a5ab5c1bd36b6e45ec7fbb6790d015393c507af74c0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa9251b1e5918f1dc5e41a113f44740045d056ecb38840bcad2b696a3aab5400d200000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff46c0ff4f35db23c80747afa0d0347170f95c82a5f58992fca5201db8f6b39c0b060000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff56e8d4d6b0903a742ab7e629570388c2cc57b49ec8bcef9891dbea2ee583393ef80000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffffb602c59d9e49411395df5a1036baaccbbc6a9c99ebeb94d1cd3c3fcbaab0f2be30000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff011df19242e8394e8e0f59e722dd6e5001e9d7d6a7bcb0afa5a4a45839c1a5092f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa2c3fcb925ac5b1a6f3969db050d37fca5bd1f14cac21711efc8b0349628993e900000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff55296d17f30d6b0f5bb8ded480fba5bc3cec9b0d7aab7d58a924d297bba47cbf6a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc1372c52f283db9be8bfc7e0c4a676b60acf7aaf108de882c37452ea9889f47a6d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff2667fdb89d372cae0b1a732b999dadf4360eefebebeaf5eec18bb6aad91bbc3d8e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3eafc1cc4c6a1f472a0ffd2eb14bb39e839f7822c83f9f60eca70367ab4126d6410000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff0b60c29a454b56d100bca2f067401786a14ff1b61115477a1356e1732814c364980000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc943b46f31be09eae4ec7379eae7c2cef2b0e431dbb32fcca7d70d4044894952b50000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff25a3307443653a547c7e9c5c917bc8c10135e083c5e90b887550922a94fadae0ba0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa075b8b1a76eb6ac9f790f012cd7a1b3eb10bee63fd9a45eac8bed012231c4d0e60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff666c31c166baf98d1004aac77b6e7738b24a9cce6fd8a9fb25835e172c3c2bb9ec0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff330bdc880a3907b41e2604ea4d0edc098912fe160ff79a5a5e4ef6f7e84bbef4110000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa143a820c2a986105fe0056b11ac272f738248fd452bc979ab1e05ac7cbcdb26800000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff09133953681a83e6f3a1d7add885b2ecd4f6fe07aa81077e0397a62cf580f6d3e70000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7d631e6eb195c1c9ddaa905d047a0700c95e2943f6756c23b5597e28dd7a172ecd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff89ee6813e36ea1f17985c7bf474a0f1a26179f1c1eb2df9e6ad44a8e22dc6388140000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff769e39ae93cd03f91da1e9cb59be9bf388394093900d7eec5a32d59859d0401f880000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff70cec86733e88836b3f8cacb80b77ebc42dfd20c3186146ebd10ab5ecf19c978580000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1ebd4a8fa281fc7a7f9f1101f40fa2466c186845640ec7da27184908d43ed6ca660000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff450e1e903149f8af45c366c8a5a8920de1b9bc28c6f4362d3d959a60e5bd5331d20000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4c5551d18e239587f9c4a0ffa515277c26550beea8a3ad21b1b3c4bd68f93be64c0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff98fd89a096ee7d8febae4754f8eaaabc94d506f1a16e28d3d257a15125364638fb0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff705616163ab8db57d2d8fc321c12021facb1a0b9b8293780e1e2854d116f4c6b920000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1f50ee861556453ed783244d4baed5d53186124aef77f48f6442199039662ddb890000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffd7ec31327e91053b58397ffdd19687466a0f860261a7de2dd4150ade69fb16462b0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3fc4af9492022016d044e77bf12caac4248e1dca7b5c3a1d0a326d6e79617013bd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7a15115f4eb2c7ca210b49d84a6491ec05ee9522fd49efdeea6b291a4d227d2cb90000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff8568a729013377a77f394f63e360f7b68c7ae05fe3ecb0b251b0c18a50a42add830000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff77a0ac19aa26fca7e41dc9503d693d4272f7a99da1f18cc42e4610fa30c02073b20000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffb9d2a85be9b5719db843aeee052c0c4a42bbda7029cb9c14be9f048a0f8cd657ce0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff9a45c65122d733d7414d6da55660b573965022b8c805fb2de18e089dee64c541690000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe3150e7c9285ebab6f2fb38a6b4230bb4a29a166f27e4799820c2ba80a37502a600000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff2668542ddbd3eb274f0942dd08355037c4e86cc63f59d31fb8bc691acf31b91f5e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7243209b521af3c507936a23a790f14a607b04cf4139743506c087cce1b48cceed0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff0b6e7adc897c76239cfa3fde80ebc16af3beb7115708654e3d68b758aa51385d810000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe2b7b21c7c14b76fcbf2b89bab64f57bb82a1cbcb73e2cbfde7fdf1991c66ea9c40000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe76bd641d6bbcda5e29a9880476b82dd1f5ab032712faea0e68bc471a930ffa1b40000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff34a9b23e5d925c69b71c8389bb96ddb7f6475de49138371a22c28808588c7f9b70000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff0ed81d34e4fc687428608e594d00aa4494d59d355e3a0e5d681030ab5e0c750f900000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa9ecca8db8de629150aa73a7c12185540944acc0fc8074c7814780cd5cabace6450000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa1562da4f71ad7e41f1292193cf0c0b243f064bbc42ae0986ea42cebd0d5a36bd90000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffb9002847e3cd484a5d834a9d664ab88a2a6532088393d3a2a65c33387d8b985d390000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3431c0425294130ef249fb3bbc596b566b28d45276b8120d0d2893de3477f7bb110000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3fb87db0e818689642abeefb072c4e13c87cd6fda97fbc83600ccec766a624d7e00000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff80109b5dea29ca9e215ebaa99929363c09da6f9fbc7277c34dcb27d0c933b8fa8a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff8064c913a942915da588d99c2092d879701e0794438bd3b9e36e93566ac1d710fb0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc58fcb1c1ddd6dd38a824585bf092a78fb00ab3d5c7198108973c2a78c9a29ab3e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffffa24f6316ff87defa5149e203cb545ba79371f04c2a153c2518061b378a72f53400000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff999131d946bcfaacf1b0a24d669a25cb671628795bb4d4db664f3bf7222a76d0090000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff7c131083a77ac9085f98ff77ae758d25e00eecf1b7fed38fcc45eebd0e0a09d1a60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4d781feff1859672d0f80feac9e895d993caf874f9bf2d62362486c6342bcf84a70000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffb1d25a7fe98f2f4c9d81f9a35beaf00b43bead9cda052024a91e422f2ed792055f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff06da95d2b9b2224dcfc4f587c8f2fe696e5e1b1247074ca9bcf20fbdd159a2b5ee0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffeabb91e256e87701fea35640b71802e926ed2ae617145d4a611acb77d19027b0560000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc7c14e744714e5b754c7b672fb65129b5b7c1ed6fc12c2d4d1204a4cfb3e6555b30000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffba88cf31bfe8ee6cf07925cf39c6af02bc423e98a534ed70d7254e44727023903e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc105ef3019d2571b41e4f6ccaeb7dc254e9226367bd9076fe403d1c07b05e59db20000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe50ffec58b9c04949ef5910f1f6a248c136aeb48b69c6f92e58c84d4bf391779ac0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc4f4ecd79da3b21e14f651a8062969d6f3f69ea50245dee2a03318fb5058c6c4960000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff52d43b8f47e68d820ee8b68d3d332432c73be1aab9b3394d393592af8e545fa87e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc72b0fd30a1785da55fe010ec282cec03597a366afb5b2aa67adbb0afb92a83a630000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff7b13b76f78d9567de203227f1fe09ba3e471c86584393d0eeca1ebd066e3a6f3b0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffea0712a840628959e9576aecf15c498524bbb56e8f5ec496e505fc317e2a933f220000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff9a2491a8aa83c4752b468dc9ca3bcc475b8586c18549f12a706a9cb1780bac74960000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3e25171ac386191d41066e5d8760f839af0a89883106e9894bbfd4b984fbcde81f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff6736d107bde130e24f84c157f5d8967e4080538aa0277ffdc6f1043870bd6c38bd0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffd7acd128d7c1756753c2a1eeebdf97b5e47ff40a5f83c17df4f801abb42d2308b10000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffd84b5b41ca9d3ba5fe7fafaf7efca767b64c36de5714aa11f38f5f220c36c347380000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3548d078005be576bb9b5f8d2fbcdd6fa0c27286a6e522c5d91bd502b4ff3a99d00000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffd3e15289c42ad461d1791ba1a50fdd5b844c5cd6e7b6f1c6f0c9fe7a372bcec8180000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff917cbe4c538efb0f2348cbe0282edd9b1a67b0feef5944a095971ecbd6eab72fa60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4eaaa576284a09c388574ce550eebfd93c4c6d251cb27ee11c51e55515ebad15f90000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff2e3e3b81183132b5643f2a9d483a19741eb58d997b96e7046b6597323725a6db350000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff235d54a505af5e77a3c75893c5e57f928ef3968af59df3fa7d70e0ecc62be0a7050000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4e99d4e158d1d52939c2a0ba3986c8edd46e4571c4c7da41eb63f7243e10f022520000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffb973d2616685d733b183cd4ed765b543719305177a5347078414d4cb4feb3466af0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1c6f0f2438d67821dbb5585557be11412ea37e0e6ec895b8de729f8cb459e7218e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff68b4a9f79b204506acd50d9c79bf3c504b6eb51a47f00b2a3b59690d93ff2bc1770000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff4acccc270a088eb03bd2c2ebd6b9d37570a896da273dbf1aa7b3d4ba2397563e9f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff124f52ee6b8a5c434b62ffeff07f42207017d66e1ebfc041ef195b7e33657e16a70000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff9abca12e1fdca561e4b2632d933c68f0a5d672bad44be66d203a0b826ee35a600f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff834c0cbaf07167439a51be3615f6eede4eb106d5c9d6e920c10368287aa0ddd45e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff1bbdc148b5d18ba6fd32bedd6ffa23aa63e67cecd8d31970396d91f9e50cf48c5e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff9969cc1ff45869d37ef23ca0c9bbc3785c3fbedbf1804c330487eafd9380de0da40000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffdb01b777bcb2812383c5f2f59eb95c315a6e3759ee5dfc62554e981727f8d3a8140000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffbf22d9e4eaf0dbeef0df490c937535bf09d39be26d34007ee35a7000e1137be16f0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffca77d7274bd39338de909a99746b716376a599bfb8e894dcab8cc019b83ea4e96e0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff6d43cdb90f143f81e0121c3386465d89ccd0d9c6e4f69997f84e3cbbad59ab39b20000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff34851160b061363ea69a2c408a9c249f5297999aea9f74475be06a5542bbc936030000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffa9a08f1cbc433fcc1651ffe3c3fc02048dffeb8e454198fb40d5aae89ebe713e360000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffff9fde960a912cae0955275cc0e6bd7acc14fc7778111f5846c5b20a61173e8160c0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff3dd9c6e61ea7d8b720669d521fa93c3eac92f9ca152000b066e2e599257ba135a00000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffffade6bbdddd7e73edb548b25b85dd2014d743115c132789656385fd11ac71b20180000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff58d2337c847d7c14a83ab53b6267f13a88838b482f8c372401b26f5c63e808b85c0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff51d759c2f8a914f888ae67b9eba783ef2fcd5848a48a094ece8d3081fe1310fd590000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff8b80b65479565e15862c5d73be3af4f4b0541f4672ad1f14aaea665d38c4d8d85a0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffce8a6b9d9bb7fbb3abd518eab3b1790cd46949e45d7b1fd56e9405f0ffd120e12d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffffe75a609dae169296b8fd7dd844d2f8bc5b24db0c2ed21ef9057b8af2b422d3bb30000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff6db7b6f7c68468c2680a986b385ac4efa0049914cf018d6878560b2a02caa940c60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aefffffffffa5de771814369a1025d7cae422d08273b4e86bdcc97f7c9eec22d9b6577e9b9080000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe66a96c77d47f4e9190110f968c3e292b9621973a28afedbd7c417f58de0242f3d0000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff83487c0ebe945a8914f080d45e226c98a9c07a0f3315d1cc0580be053c8cdd45750000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffe39be6805d17388b820fe2d2b29c004c3199b06e75c7acc680af4df0af16b764e50000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc7bfd02e083bbc913286c99806a4605999abade373bb165f9708b71409e902ebb60000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff27864946b0965ee2b98fff35b6929c8ca96ed0237ed8410c861d743f5c459c1ab10000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff98935aea579000241d855c51fd2e2e1ce402e035de14e6c94096b70b4db575d7160000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff45b436e28e5e7f2190b1b4f0d3533b2a0cf9d3ed6198a634f8c832ffa4a92185450000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffffc4faec9d54317455d805e0e25d60d9c7568b241384b1fd451eeb3ed278c18360d70000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff02b011e111000000001976a91447a5bfd415108c37e918e8b114b83f8d5ae9834988ac00bbeea00000000017a914896ed9f3446d51b5510f7f0b6ef81b2bde55140e8700000000", diff --git a/firmware/test/resources/612-sign-sample-mainnet-tx.json b/firmware/test/resources/612-sign-sample-mainnet-tx.json index 2edf6fd7..eeb486f5 100644 --- a/firmware/test/resources/612-sign-sample-mainnet-tx.json +++ b/firmware/test/resources/612-sign-sample-mainnet-tx.json @@ -1,7 +1,7 @@ { "name": "Sign with a sample mainnet BTC tx (49b52b570d7b3fb5428fb90da0b03fa48712569353291b86c8627515300c6eb7)", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "b0c9d5840ff55a2c06c3969e4d5ac05f39c2fb2f8867b1b934af4896b5bc0348", "btcTx": "0200000001c36068f22ad1285b0e8c75547e634a7df21d7bf3e23788b8942e3ad14bd7ab8a01000000fdc80100000000000000004dbd0157210231a395e332dde8688800a0025cccc5771ea1aa874a633b8ab6e5c89d300c7c3621026b472f7d59d201ff1f540f111b6eb329e071c30a9d23e3d2bcd128fe73dc254c21027319afb15481dbeb3c426bcc37f9a30e7f51ceff586936d85548d9395bcc2344210294c817150f78607566e961b3c71df53a22022a80acbb982f83c0c8baac040adc2103250c11be0561b1d7ae168b1f59e39cbc1fd1ba3cf4d2140c1a365b2723a2bf9321033ada6ef3b1d93a1978b595c7a9e2aa613860b26d4f5a7abb88576aa42b3432ad210357f7ed4c118e581f49cd3b4d9dd1edb4295f4def49d6dcf2faaaaac87a1a0a42210372cd46831f3b6afd4c044d160b7667e8ebf659d6cb51a825a3104df6ee0638c62103ae72827d25030818c4947a800187b1fbcc33ae751e248ae60094cc989fb880f62103b3a7aa25702000c5c1faa300600e8e2bd89cde2be7fb1ec898a39c50d9de90d12103b53899c390573471ba30e5054f78376c5f797fda26dde7a760789f02908cbad22103e05bf6002b62651378b1954820539c36ca405cbb778c225395dd9ebff67802992103ecd8af1e93c57a1b8c7f917bd9980af798adeb0205e9687865673353eb041e8d5daeffffffff02bb57eb0b000000001976a9147e8784d8b1e299d8f55c9977fbfa9c1821eb472188ace274a04c0000000017a914596cff92a275960df9cb2ab9df0ff69faa2b1d8a8700000000", diff --git a/firmware/test/resources/613-sign-sample-testnet-tx-erp.json b/firmware/test/resources/613-sign-sample-testnet-tx-erp.json index 3784f8b7..96f25e40 100644 --- a/firmware/test/resources/613-sign-sample-testnet-tx-erp.json +++ b/firmware/test/resources/613-sign-sample-testnet-tx-erp.json @@ -1,7 +1,7 @@ { "name": "Sign with a sample ERP testnet BTC tx (ef48d91ca32d694c36826c74a21191e6528f11f6beaa10bc8dc0c51de38f930c)", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "fa0cfbb9525f7b3a5a78fec0b5c4acb7c50eb13583affbb7c80290cffa09101b", "btcTx": "020000000101724031bd8b47b66d05158a1aa8f737aee95bfdbad0592270198f38cd68c2ff01000000de000000004cd8645221024c759affafc5589872d218ca30377e6d97211c039c375672c169ba76ce7fad6a21031f4aa4943fa2b731cd99c551d6992021555877b3b32c125385600fbc1b89c2a92103767a0994daa8babee7215b2371916d09fc1158de3c23feeefaae2dfe5baf483053670132b275522102132685d71b0109fecef0160f1efcab0187eff916f4d472289741bff2666d0e1c2102ed498022f9d618a96f272b1990a640d9f24fb97d2648f8716f9ee22dc008eba721036f66639295ca8e4294c24d63e3fbc11247f6ba6a27b6b4de9a3492f414152d9b5368ae3c00000001e0930400000000001976a9140a4f09cbd39d5d8072b24385e1a9eb1c84ae544688ac00000000", diff --git a/firmware/test/resources/614-sign-match-not-last-log.json b/firmware/test/resources/614-sign-match-not-last-log.json index f967cc65..f7ca3ede 100644 --- a/firmware/test/resources/614-sign-match-not-last-log.json +++ b/firmware/test/resources/614-sign-match-not-last-log.json @@ -1,7 +1,7 @@ { "name": "Sign when the matching log is not the last one", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "dbab9d8e87550d4a3ccb496b25326403b1d339e487e342bf43469c622d693ca1", "btcTx": "01000000010c25db7dc67a51c2aa406514373c83a87b25cb313f530fbfa5210007fa65e1f0000000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff02b011e111000000001976a91447a5bfd415108c37e918e8b114b83f8d5ae9834988ac00bbeea00000000017a914896ed9f3446d51b5510f7f0b6ef81b2bde55140e8700000000", diff --git a/firmware/test/resources/615-sign-match-long-proof.json b/firmware/test/resources/615-sign-match-long-proof.json index 4f2a1e13..20d6f534 100644 --- a/firmware/test/resources/615-sign-match-long-proof.json +++ b/firmware/test/resources/615-sign-match-long-proof.json @@ -1,7 +1,7 @@ { "name": "Sign with a long partial receipt merkle proof", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "5609cc9ca4e1379222c35bc54b9be88d69d53c9fe1c4e422815db890339951ff", "btcTx": "01000000010c25db7dc67a51c2aa406514373c83a87b25cb313f530fbfa5210007fa65e1f0000000006e0000004c69522102cd53fc53a07f211641a677d250f6de99caf620e8e77071e811a28b3bcddf0be1210362634ab57dae9cb373a5d536e66a8c4f67468bbcfb063809bab643072d78a1242103c5946b3fbae03a654237da863c9ed534e0878657175b132b8ca630f245df04db53aeffffffff02b011e111000000001976a91447a5bfd415108c37e918e8b114b83f8d5ae9834988ac00bbeea00000000017a914896ed9f3446d51b5510f7f0b6ef81b2bde55140e8700000000", diff --git a/firmware/test/resources/616-sign-3input-5output-testnet.json b/firmware/test/resources/616-sign-3input-5output-testnet.json index f840f9d2..2ab5a72f 100644 --- a/firmware/test/resources/616-sign-3input-5output-testnet.json +++ b/firmware/test/resources/616-sign-3input-5output-testnet.json @@ -1,7 +1,7 @@ { "name": "Sign a 3-input, 5-output testnet transaction", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "736a36d733f0faff88dbd36332e773a82e8e5ce9829a34b4d5750c91d641fc74", "btcTx": "020000000396f1ed3e9075af583e8e1e2b50bd5e37c761f677418db75a295901380864d95e01000000fd270100000000004d1f016453210225e892391625854128c5c4ea4340de0c2a70570f33db53426fc9c746597a03f421025a2f522aea776fab5241ad72f7f05918e8606676461cb6ce38265a52d4ca9ed62102afc230c2d355b1a577682b07bc2646041b5d0177af0f98395a46018da699b6da21032822626c45fc1c4e3a3def5b4983636d6291a7a6677f66874c337e78bc3b77842103fb8e1d5d0392d35ca8c3656acb6193dbf392b3e89b9b7b86693f5c80f7ce858155ae670350cd00b27552210216c23b2ea8e4f11c3f9e22711addb1d16a93964796913830856b568cc3ea21d3210275562901dd8faae20de0a4166362a4f82188db77dbed4ca887422ea1ec185f1421034db69f2112f4fb1bb6141bf6e2bd6631f0484d0bd95b16767902c9fe219d4a6f53ae68ffffffff375b0696785b04a56b6a9f3f84a0fc3715837f7a2ab427f220ef2932b64a93ae01000000fd270100000000004d1f016453210225e892391625854128c5c4ea4340de0c2a70570f33db53426fc9c746597a03f421025a2f522aea776fab5241ad72f7f05918e8606676461cb6ce38265a52d4ca9ed62102afc230c2d355b1a577682b07bc2646041b5d0177af0f98395a46018da699b6da21032822626c45fc1c4e3a3def5b4983636d6291a7a6677f66874c337e78bc3b77842103fb8e1d5d0392d35ca8c3656acb6193dbf392b3e89b9b7b86693f5c80f7ce858155ae670350cd00b27552210216c23b2ea8e4f11c3f9e22711addb1d16a93964796913830856b568cc3ea21d3210275562901dd8faae20de0a4166362a4f82188db77dbed4ca887422ea1ec185f1421034db69f2112f4fb1bb6141bf6e2bd6631f0484d0bd95b16767902c9fe219d4a6f53ae68ffffffff8797d86f4653e0c778e54f527d4d9bd2b1b57715d0a0ae4dd7918ab7b468a2b002000000fd270100000000004d1f016453210225e892391625854128c5c4ea4340de0c2a70570f33db53426fc9c746597a03f421025a2f522aea776fab5241ad72f7f05918e8606676461cb6ce38265a52d4ca9ed62102afc230c2d355b1a577682b07bc2646041b5d0177af0f98395a46018da699b6da21032822626c45fc1c4e3a3def5b4983636d6291a7a6677f66874c337e78bc3b77842103fb8e1d5d0392d35ca8c3656acb6193dbf392b3e89b9b7b86693f5c80f7ce858155ae670350cd00b27552210216c23b2ea8e4f11c3f9e22711addb1d16a93964796913830856b568cc3ea21d3210275562901dd8faae20de0a4166362a4f82188db77dbed4ca887422ea1ec185f1421034db69f2112f4fb1bb6141bf6e2bd6631f0484d0bd95b16767902c9fe219d4a6f53ae68ffffffff05bbed0600000000001976a9148394379a5ab5974f2bd6368ce479e28fca91631e88acbbed0600000000001976a91409197f6153cb3a91bb51eec373360a1cb3b7c0e088acbbed0600000000001976a91409197f6153cb3a91bb51eec373360a1cb3b7c0e088acbbed0600000000001976a91409197f6153cb3a91bb51eec373360a1cb3b7c0e088ac061e5f000000000017a9145e6cf80958803e9b3c81cd90422152520d2a505c8700000000", diff --git a/firmware/test/resources/620-sign-segwit-basic.json b/firmware/test/resources/620-sign-segwit-basic.json index 4fb3d628..e63a7a19 100644 --- a/firmware/test/resources/620-sign-segwit-basic.json +++ b/firmware/test/resources/620-sign-segwit-basic.json @@ -1,7 +1,7 @@ { "name": "Sign with a basic segwit tx", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "eabbc877b16f4f484beadb403a9a65e04a9c8c8a5cea57315f729ceedbc0d6a7", "txType": "segwit", diff --git a/firmware/test/resources/621-sign-segwit-with-many-inputs.json b/firmware/test/resources/621-sign-segwit-with-many-inputs.json index f03ea364..5d3226ff 100644 --- a/firmware/test/resources/621-sign-segwit-with-many-inputs.json +++ b/firmware/test/resources/621-sign-segwit-with-many-inputs.json @@ -1,7 +1,7 @@ { "name": "Sign with a segwit BTC tx with many inputs", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "b550311160cd59f4d912fa7246a21332dda29ba54ff782a76d19fe26ed2ab533", "txType": "segwit", diff --git a/firmware/test/resources/622-sign-segwit-long-witnessscript.json b/firmware/test/resources/622-sign-segwit-long-witnessscript.json index bbae348c..998cd74d 100644 --- a/firmware/test/resources/622-sign-segwit-long-witnessscript.json +++ b/firmware/test/resources/622-sign-segwit-long-witnessscript.json @@ -1,7 +1,7 @@ { "name": "Sign with a segwit BTC tx with a long witness script", "operation": "signAuthorized", - "runOn": "tcpsigner", + "runOn": "simulator", "expected": true, "fake_ancestor_receipts_root": "8d87508bb18f696e2e41fef9abe7d25555899ff69e8310c706aaaa35ff7443bd", "txType": "segwit", diff --git a/firmware/test/resources/700-dongle-fake-receipt-root-fails.json b/firmware/test/resources/700-dongle-fake-receipt-root-fails.json index 03fd3f87..05055b7f 100644 --- a/firmware/test/resources/700-dongle-fake-receipt-root-fails.json +++ b/firmware/test/resources/700-dongle-fake-receipt-root-fails.json @@ -1,7 +1,7 @@ { "name": "Attempt to fake the ancestor receipts root on a physical dongle fails", "operation": "signAuthorized", - "runOn": "dongle", + "runOn": "device", "expected": "0x6e11", "fake_ancestor_receipts_root": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "btcTx": "", diff --git a/firmware/test/resources/900-set-is-onboarded-no.json b/firmware/test/resources/900-set-is-onboarded-no.json index 1d9ee47a..8fc37a4e 100644 --- a/firmware/test/resources/900-set-is-onboarded-no.json +++ b/firmware/test/resources/900-set-is-onboarded-no.json @@ -2,5 +2,5 @@ "name": "Set is onboarded to false", "operation": "adminIsOnboarded", "value": false, - "runOn": "tcpsigner" + "runOn": "simulator" } diff --git a/firmware/test/resources/901-no-onboarded-sign-noauth-fails.json b/firmware/test/resources/901-no-onboarded-sign-noauth-fails.json index 6b9bfd17..20c52a72 100644 --- a/firmware/test/resources/901-no-onboarded-sign-noauth-fails.json +++ b/firmware/test/resources/901-no-onboarded-sign-noauth-fails.json @@ -3,5 +3,5 @@ "operation": "signUnauthorized", "expected": "0x6bee", "hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "runOn": "tcpsigner" + "runOn": "simulator" } diff --git a/firmware/test/resources/902-no-onboard-sign-auth-fails.json b/firmware/test/resources/902-no-onboard-sign-auth-fails.json index d873f34d..bcc58ecb 100644 --- a/firmware/test/resources/902-no-onboard-sign-auth-fails.json +++ b/firmware/test/resources/902-no-onboard-sign-auth-fails.json @@ -9,5 +9,5 @@ "7006002c05a0d7d85908466fdd3e6896af6c88a588701d4aa19769600875a7aa9a64a0000203", "4f2670060290077e20feb9ffb4ed5abdcb42dc4e034fe2496cca6b38fd479dcd598cfa151b000388267006002c05a0d7d85908466fdd3e6896af6c88a588701d4aa19769600875a7aa9a64a0000203fdd705" ], - "runOn": "tcpsigner" + "runOn": "simulator" } diff --git a/firmware/test/resources/903-no-onboarded-get-bs-fails.json b/firmware/test/resources/903-no-onboarded-get-bs-fails.json index b12a097f..57016cf2 100644 --- a/firmware/test/resources/903-no-onboarded-get-bs-fails.json +++ b/firmware/test/resources/903-no-onboarded-get-bs-fails.json @@ -2,5 +2,5 @@ "name": "Non-onboarded get blockchain state fails", "operation": "getState", "expected": "0x6bee", - "runOn": "tcpsigner" + "runOn": "simulator" } diff --git a/firmware/test/resources/904-no-onboarded-advance-fails.json b/firmware/test/resources/904-no-onboarded-advance-fails.json index 45d091c4..086a5ead 100644 --- a/firmware/test/resources/904-no-onboarded-advance-fails.json +++ b/firmware/test/resources/904-no-onboarded-advance-fails.json @@ -6,5 +6,5 @@ "f9035ea0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa02ea4245bc5f44a747156f9b54ddf5e883594f7e98ad79e3a1f1d12a24c3269c2945b2427729a74667f6cc9ece0b850004c1b75c636a025a798601329c5547a9625b421196d6bcf2f4a2b02e1f504feb0daeb4daaaf48a098124835d3fdb6388f0ec7850ffbe2c2518d6e1a3c1b59ce1c4aa8274309f9fba0fecd2dbfdfef790e31c92fe06f06875805edea30ca1ef51b179e24fd7fe04263b9010000000000000000000000000000000008000000002000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000004000000001000000000000004000100000080000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000010000000000000080200000080000000100000000000000000000000000000000002001000000000020000000001000000000000018000000000000020000000000000200040100000000000000000000000000000000000100000000000000000000000000000000000038204b28367c28080845f35c01f92d1018f504150595255532d6566613161306480000380b85071110100000000000000000000000000000000000000000000000000000000000000000016d2a2eb54b026c07488ed349219c74ef2b8fb079cb582aa72b02d3c00bab84122c0355fffff7f2100000004b8a06e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459adbc1b4c900ffe48d575b5da5c638040125f65db0fe3e24494b76ea986457d986084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff29c5e52d9c508c502347344d8c07ad91cbd6068afc75ff6292f062a09ca381c89e71b8860000000000000400f1f2c62bc5bfded2c12c1696ff5ecd3d8ee4867bf5b0b5d42b8ed2433fe4dec552534b424c4f434b3ab272e052df3230497966b8bd9347c2031f2a88e70000000000000000000004b2ffffffff0100f2052a01000000232103afcefd7798b549c7d178bac0ecb93c270f39d688a439a642a6b2458962e5cd65ac00000000" ], "brothers": [[]], - "runOn": "tcpsigner" + "runOn": "simulator" } diff --git a/firmware/test/resources/905-no-onboard-update-fails.json b/firmware/test/resources/905-no-onboard-update-fails.json index f5fc97c5..9cf7d4b5 100644 --- a/firmware/test/resources/905-no-onboard-update-fails.json +++ b/firmware/test/resources/905-no-onboard-update-fails.json @@ -5,5 +5,5 @@ "blocks": [ "f90234a0f899db73b9fa342be52307f44bb390e0c4bfe85317a94d791d6fc402dee640c3a0c3f3e6d602ffa6b067a91dff63b63df2959c9b61b34dde09d6e9cfb52b9e6f81945b2427729a74667f6cc9ece0b850004c1b75c636a025a798601329c5547a9625b421196d6bcf2f4a2b02e1f504feb0daeb4daaaf48a098124835d3fdb6388f0ec7850ffbe2c2518d6e1a3c1b59ce1c4aa8274309f9fba0fecd2dbfdfef790e31c92fe06f06875805edea30ca1ef51b179e24fd7fe04263b9010000000000000000000000000000000008000000002000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000004000000001000000000000004000100000080000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000010000000000000080200000080000000100000000000000000000000000000000002001000000000020000000001000000000000018000000000000020000000000000200040100000000000000000000000000000000000100000000000000000000000000000000000038204b28367c28080845f35c01f92d1018f504150595255532d6566613161306480000380b8507111010000000000000000000000000000000000000000000000000000000000000000003ffadf855194306850a15e3850d164ac2942094d725405e06cba9e6537af0f3122c0355fffff7f2100000005" ], - "runOn": "tcpsigner" + "runOn": "simulator" } \ No newline at end of file diff --git a/firmware/test/resources/906-set-is-onboarded-yes.json b/firmware/test/resources/906-set-is-onboarded-yes.json index 86d988c9..344cfc06 100644 --- a/firmware/test/resources/906-set-is-onboarded-yes.json +++ b/firmware/test/resources/906-set-is-onboarded-yes.json @@ -2,5 +2,5 @@ "name": "Set is onboarded to true", "operation": "adminIsOnboarded", "value": true, - "runOn": "tcpsigner" + "runOn": "simulator" } diff --git a/firmware/test/resources/907-dongle-set-is-onboarded-fails.json b/firmware/test/resources/907-dongle-set-is-onboarded-fails.json index f956db49..999bbb48 100644 --- a/firmware/test/resources/907-dongle-set-is-onboarded-fails.json +++ b/firmware/test/resources/907-dongle-set-is-onboarded-fails.json @@ -3,5 +3,5 @@ "operation": "adminIsOnboarded", "value": true, "expected": "0x6e11", - "runOn": "dongle" + "runOn": "device" } diff --git a/firmware/test/resources/nvm/01-nvm-stats-reset.json b/firmware/test/resources/nvm/01-nvm-stats-reset.json index f637994e..be883eb1 100644 --- a/firmware/test/resources/nvm/01-nvm-stats-reset.json +++ b/firmware/test/resources/nvm/01-nvm-stats-reset.json @@ -2,5 +2,5 @@ "name": "Reset NVM stats", "operation": "nvmStats", "subop": "reset", - "runOn": "tcpsigner" + "runOn": "simulator" } diff --git a/firmware/test/resources/nvm/20-nvm-stats-print.json b/firmware/test/resources/nvm/20-nvm-stats-print.json index ca367883..6deef604 100644 --- a/firmware/test/resources/nvm/20-nvm-stats-print.json +++ b/firmware/test/resources/nvm/20-nvm-stats-print.json @@ -2,5 +2,5 @@ "name": "Print NVM stats", "operation": "nvmStats", "subop": "print", - "runOn": "tcpsigner" + "runOn": "simulator" } diff --git a/firmware/test/run.py b/firmware/test/run.py index b0942904..1599d82a 100644 --- a/firmware/test/run.py +++ b/firmware/test/run.py @@ -25,6 +25,7 @@ from cases import TestSuite, TestCase from ledger.hsm2dongle import HSM2Dongle from ledger.hsm2dongle_tcp import HSM2DongleTCP +from sgx.hsm2dongle import HSM2DongleSGX import output import logging @@ -47,20 +48,27 @@ def debug_dongle_exchange(dongle, bs, timeout): try: output.header("Setup") - run_args = {} + run_args = { + TestCase.RUN_ARGS_DEVICE_KIND_KEY: options.device + } - if options.dongle: - if not options.manual_unlock and options.pin is None: + if options.device in ["ledger", "sgx"]: + if not options.manual_unlock and \ + options.pin is None: raise RuntimeError("Auto unlock requires 'pin' argument") - - dongle = HSM2Dongle(options.dongle_verbose) - run_on = TestCase.RUN_ON_VALUE_DONGLE + run_on = TestCase.RUN_ON_VALUE_DEVICE run_args[TestCase.RUN_ARGS_MANUAL_KEY] = options.manual_unlock run_args[TestCase.RUN_ARGS_PIN_KEY] = options.pin + + if options.device == "ledger": + dongle = HSM2Dongle(options.dongle_verbose) output.info("Running against a USB device", nl=True) + elif options.device == "sgx": + dongle = HSM2DongleSGX(options.host, options.port, options.dongle_verbose) + output.info("Running against an SGX device", nl=True) else: dongle = HSM2DongleTCP(options.host, options.port, options.dongle_verbose) - run_on = TestCase.RUN_ON_VALUE_TCPSIGNER + run_on = TestCase.RUN_ON_VALUE_SIMULATOR output.info("Running against a TCP device", nl=True) output.info(f"Loading test cases from {options.tests_path}") diff --git a/firmware/test/sgx b/firmware/test/sgx new file mode 120000 index 00000000..820ca04b --- /dev/null +++ b/firmware/test/sgx @@ -0,0 +1 @@ +../../middleware/sgx \ No newline at end of file diff --git a/firmware/test/test-all b/firmware/test/test-all index 239ba396..82ccd089 100755 --- a/firmware/test/test-all +++ b/firmware/test/test-all @@ -1,26 +1,35 @@ #!/usr/bin/env bash # Run against a physical dongle? -WITH_DONGLE="no" +WITH_DEVICE="no" RUN_ARGS="" MANUAL_UNLOCK="" if [[ "$1" == "help" ]]; then - echo "Usage: $0 [dongle] [pin] [manual]" + echo "Usage: $0 [ledger [pin|manual] | sgx host port]" echo "Example (using tcpsigner): $0" - echo "Example (using dongle - auto unlock): $0 dongle 12345678" - echo "Example (using dongle - manual unlock): $0 dongle manual" + echo "Example (using ledger - auto unlock): $0 ledger 12345678" + echo "Example (using ledger - manual unlock): $0 ledger manual" + echo "Example (using sgx): $0 sgx 123.40.55.67 6666" exit 1 -elif [[ "$1" == "dongle" ]]; then +elif [[ "$1" == "ledger" ]]; then if [ "$#" -lt 2 ]; then - echo -e "\e[1;31mInvalid usage for 'dongle' option. Issue '$0 help' for help.\e[0m" + echo -e "\e[1;31mInvalid usage for 'ledger' option. Issue '$0 help' for help.\e[0m" exit 1 fi - WITH_DONGLE="yes" + WITH_DEVICE="yes" + RUN_ARGS="-dledger" if [[ "$2" == "manual" ]]; then - RUN_ARGS="-m" + RUN_ARGS="$RUN_ARGS -m" else - RUN_ARGS="-P $2" + RUN_ARGS="$RUN_ARGS -P $2" fi +elif [[ "$1" == "sgx" ]]; then + if [ "$#" -lt 3 ]; then + echo -e "\e[1;31mInvalid usage for 'sgx' option. Issue '$0 help' for help.\e[0m" + exit 1 + fi + WITH_DEVICE="yes" + RUN_ARGS="-dsgx -s$2 -p$3" elif [[ "$1" != "" ]]; then echo -e "\e[1;31mInvalid or unknown option '$1'. Issue '$0 help' for help.\e[0m" exit 1 @@ -31,7 +40,7 @@ pushd $(dirname $0) > /dev/null TEST_ROOT=$(pwd) popd > /dev/null -if [[ "$WITH_DONGLE" == "no" ]]; then +if [[ "$WITH_DEVICE" == "no" ]]; then # Build and run tcp signer $TEST_ROOT/../build/build-tcpsigner @@ -45,8 +54,8 @@ if [[ "$WITH_DONGLE" == "no" ]]; then # Kill (and remove) container docker kill hsm-mware-notty > /dev/null else - # Run tests against a dongle - $TEST_ROOT/../../docker/mware/do /hsm2/firmware/test "python run.py -d ${RUN_ARGS}" + # Run tests against a device + $TEST_ROOT/../../docker/mware/do /hsm2/firmware/test "python run.py ${RUN_ARGS}" err_code=$? fi diff --git a/middleware/sgx/__init__.py b/middleware/sgx/__init__.py new file mode 100644 index 00000000..11284d93 --- /dev/null +++ b/middleware/sgx/__init__.py @@ -0,0 +1,21 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. diff --git a/middleware/sgx/hsm2dongle.py b/middleware/sgx/hsm2dongle.py new file mode 100644 index 00000000..1126581f --- /dev/null +++ b/middleware/sgx/hsm2dongle.py @@ -0,0 +1,46 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from enum import IntEnum +from ledger.hsm2dongle_tcp import HSM2DongleTCP + + +class SgxCommand(IntEnum): + SGX_UNLOCK = 0xA3, + SGX_ECHO = 0xA4, + + +class HSM2DongleSGX(HSM2DongleTCP): + # Echo message + def echo(self): + message = bytes([0x41, 0x42, 0x43]) + result = bytes(self._send_command(SgxCommand.SGX_ECHO, message)) + # Result should be the command plus the message + expected_result = bytes([self.CLA, SgxCommand.SGX_ECHO]) + message + return result == expected_result + + # Unlock the device with the given pin + def unlock(self, pin): + response = self._send_command(SgxCommand.SGX_UNLOCK, bytes([0]) + pin) + + # Nonzero indicates device unlocked + return response[2] != 0 From 0d9f726db533ec115d1b3f15e038c0f6281f4be0 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Thu, 5 Sep 2024 01:05:19 +1200 Subject: [PATCH 02/50] SGX simulation build (#196) - Added simulator-only seal and unseal implementations (seal/unseal is unsupported in simulation mode and errors out) - Added simulation build script - Added separate simulation configuration file - Ignoring SGX data files --- .gitignore | 3 ++ firmware/build/build-sgx | 14 +++++-- firmware/build/build-sgx-debug | 37 +------------------ firmware/build/build-sgx-sim | 1 + .../src/hal/sgx/src/trusted/secret_store.c | 31 ++++++++++++++++ firmware/src/sgx/Makefile | 4 ++ firmware/src/sgx/src/hsm-sim.conf | 16 ++++++++ .../src/sgx/src/untrusted/enclave_provider.c | 9 ++++- 8 files changed, 74 insertions(+), 41 deletions(-) mode change 100755 => 120000 firmware/build/build-sgx-debug create mode 120000 firmware/build/build-sgx-sim create mode 100644 firmware/src/sgx/src/hsm-sim.conf diff --git a/.gitignore b/.gitignore index 1d02b745..1608c803 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ # Ignore fuzz artifacts firmware/fuzz/.coverage-build firmware/fuzz/output + +# Ignore SGX data files +**/kvstore-*.dat diff --git a/firmware/build/build-sgx b/firmware/build/build-sgx index 4452f612..cbe70d31 100755 --- a/firmware/build/build-sgx +++ b/firmware/build/build-sgx @@ -1,5 +1,15 @@ #! /usr/bin/env bash +BUILD_TARGET=build +if [[ "$(basename $0)" == "build-sgx-debug" ]]; then + BUILD_TARGET=build-debug +elif [[ "$(basename $0)" == "build-sgx-sim" ]]; then + BUILD_TARGET=build-sim +elif [[ "$(basename $0)" != "build-sgx" ]]; then + echo "Invalid build script" + exit 1 +fi + if [[ $# -lt 3 ]]; then echo "Usage: $0 " exit 1 @@ -25,10 +35,6 @@ HSM_ROOT=$(realpath $BUILD_ROOT/../../) DOCKER_IMAGE=hsm:sgx source $BUILD_ROOT/../../docker/check-image -BUILD_TARGET=build -if [[ "$(basename $0)" == "build-sgx-debug" ]]; then - BUILD_TARGET=build-debug -fi BUILD_CMD="\$SGX_ENVSETUP && make clean $BUILD_TARGET CHECKPOINT=$1 TARGET_DIFFICULTY=$2 NETWORK=$NETWORK" DOCKER_USER="$(id -u):$(id -g)" diff --git a/firmware/build/build-sgx-debug b/firmware/build/build-sgx-debug deleted file mode 100755 index 4452f612..00000000 --- a/firmware/build/build-sgx-debug +++ /dev/null @@ -1,36 +0,0 @@ -#! /usr/bin/env bash - -if [[ $# -lt 3 ]]; then - echo "Usage: $0 " - exit 1 -fi - -if [[ "$3" == "regtest" ]]; then - NETWORK="REGTEST" -elif [[ "$3" == "testnet" ]]; then - NETWORK="TESTNET" -elif [[ "$3" == "mainnet" ]]; then - NETWORK="" -else - echo "Invalid network '$3'" - exit 1 -fi - -pushd $(dirname $0) > /dev/null -BUILD_ROOT=$(pwd) -popd > /dev/null - -HSM_ROOT=$(realpath $BUILD_ROOT/../../) - -DOCKER_IMAGE=hsm:sgx -source $BUILD_ROOT/../../docker/check-image - -BUILD_TARGET=build -if [[ "$(basename $0)" == "build-sgx-debug" ]]; then - BUILD_TARGET=build-debug -fi -BUILD_CMD="\$SGX_ENVSETUP && make clean $BUILD_TARGET CHECKPOINT=$1 TARGET_DIFFICULTY=$2 NETWORK=$NETWORK" - -DOCKER_USER="$(id -u):$(id -g)" - -docker run -t --rm --user $DOCKER_USER -w /hsm2/firmware/src/sgx -v ${HSM_ROOT}:/hsm2 ${DOCKER_IMAGE} /bin/bash -c "$BUILD_CMD" diff --git a/firmware/build/build-sgx-debug b/firmware/build/build-sgx-debug new file mode 120000 index 00000000..1dc34c39 --- /dev/null +++ b/firmware/build/build-sgx-debug @@ -0,0 +1 @@ +build-sgx \ No newline at end of file diff --git a/firmware/build/build-sgx-sim b/firmware/build/build-sgx-sim new file mode 120000 index 00000000..1dc34c39 --- /dev/null +++ b/firmware/build/build-sgx-sim @@ -0,0 +1 @@ +build-sgx \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/secret_store.c b/firmware/src/hal/sgx/src/trusted/secret_store.c index f2a41d64..427b3e29 100644 --- a/firmware/src/hal/sgx/src/trusted/secret_store.c +++ b/firmware/src/hal/sgx/src/trusted/secret_store.c @@ -74,6 +74,7 @@ typedef struct { static uint8_t unseal_data(const sealed_secret_t* sealed_secret, uint8_t* dest, size_t dest_length) { +#ifndef SIM_BUILD if (sealed_secret->blob_size > MAX_BLOB_SIZE) { LOG("Sealed blob size is too large\n"); goto unseal_data_error; @@ -107,6 +108,25 @@ static uint8_t unseal_data(const sealed_secret_t* sealed_secret, if (plaintext) oe_free(plaintext); return SEST_ERROR; +#else + // *************************************************** // + // UNSAFE SIMULATOR-ONLY UNSEAL IMPLEMENTATION // + // NOT FOR PRODUCTION USE // + if (sealed_secret->blob_size > MAX_BLOB_SIZE) { + LOG("Sealed blob size is too large\n"); + return SEST_ERROR; + } + + if (sealed_secret->blob_size > dest_length) { + LOG("Unsealed data is too large\n"); + return SEST_ERROR; + } + + platform_memmove(dest, sealed_secret->blob, sealed_secret->blob_size); + + return sealed_secret->blob_size; + // *************************************************** // +#endif } /** @@ -119,6 +139,7 @@ static uint8_t unseal_data(const sealed_secret_t* sealed_secret, static bool seal_data(uint8_t* data, size_t data_length, sealed_secret_t* sealed_secret) { +#ifndef SIM_BUILD uint8_t* blob = NULL; size_t blob_size = 0; const oe_seal_setting_t settings[] = {OE_SEAL_SET_POLICY(SEAL_POLICY)}; @@ -142,6 +163,16 @@ static bool seal_data(uint8_t* data, sealed_secret->blob = blob; sealed_secret->blob_size = blob_size; return true; +#else + // *************************************************** // + // UNSAFE SIMULATOR-ONLY SEAL IMPLEMENTATION // + // NOT FOR PRODUCTION USE // + sealed_secret->blob = oe_malloc(data_length); + memcpy(sealed_secret->blob, data, data_length); + sealed_secret->blob_size = data_length; + return true; + // *************************************************** // +#endif } // Public API diff --git a/firmware/src/sgx/Makefile b/firmware/src/sgx/Makefile index 598fa39f..ba906f93 100644 --- a/firmware/src/sgx/Makefile +++ b/firmware/src/sgx/Makefile @@ -111,6 +111,10 @@ build-debug: CFLAGS_COMMON += -DDEBUG_BUILD build-debug: CONF_FILE = $(SGX_SRC_DIR)/$(ENCLAVE_NAME)-debug.conf build-debug: build +build-sim: CFLAGS_COMMON += -DSIM_BUILD -DDEBUG_BUILD +build-sim: CONF_FILE = $(SGX_SRC_DIR)/$(ENCLAVE_NAME)-sim.conf +build-sim: build + check-private-key: @if [ ! -f private.pem ]; then \ echo "Private key not found! Please place your private key in a private.pem file."; \ diff --git a/firmware/src/sgx/src/hsm-sim.conf b/firmware/src/sgx/src/hsm-sim.conf new file mode 100644 index 00000000..ff834d74 --- /dev/null +++ b/firmware/src/sgx/src/hsm-sim.conf @@ -0,0 +1,16 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +############################################################################## +## Warning: this configuration file is FOR DEBUGGING PURPOSES ONLY, and should +## not be used in production environments +############################################################################## + +# Enclave settings: +Debug=1 +NumHeapPages=1024 +NumStackPages=1024 +NumTCS=1 +ProductID=200 +SecurityVersion=1 +CapturePFGPExceptions=1 diff --git a/firmware/src/sgx/src/untrusted/enclave_provider.c b/firmware/src/sgx/src/untrusted/enclave_provider.c index ce30f851..20ac295c 100644 --- a/firmware/src/sgx/src/untrusted/enclave_provider.c +++ b/firmware/src/sgx/src/untrusted/enclave_provider.c @@ -29,6 +29,13 @@ #include "enclave_provider.h" #include "log.h" +// Simulation build +#ifndef SIM_BUILD +#define CREATE_ENCLAVE_FLAGS 0 +#else +#define CREATE_ENCLAVE_FLAGS OE_ENCLAVE_FLAG_SIMULATE +#endif + // Global pointer to the enclave. This should be the only global pointer to the enclave static char* G_enclave_path = NULL; static oe_enclave_t* G_enclave = NULL; @@ -48,7 +55,7 @@ oe_enclave_t* epro_get_enclave() { LOG("Creating HSM enclave...\n"); oe_result_t result = oe_create_hsm_enclave(G_enclave_path, OE_ENCLAVE_TYPE_AUTO, - 0, NULL, 0, &enclave); + CREATE_ENCLAVE_FLAGS, NULL, 0, &enclave); if (OE_OK != result) { LOG("Failed to create enclave: oe_result=%u (%s)\n", result, oe_result_str(result)); return NULL; From 8d6295d1c015153343d77f23a65e1cce9fbd42db Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Thu, 12 Sep 2024 01:37:04 +1200 Subject: [PATCH 03/50] SGX middleware manager (#198) - Renamed manager and adm to manager_ledger and adm_ledger - Renamed manager-tcp to manager_tcp for consistency (python doesn't like hyphens in module names) - Renamed build scripts - Protocol now accepts configurable "restart the powHSM" messages - Updated tcpsigner bundle artifacts - Updated unit tests - Updated documentation - Updated github workflows - Updated .gitignore(s) - Incidentally removed unnecessary file - Added password changing capabilities to the SGX powHSM implementation - Added main SGX manager script - Added build script for the SGX manager - Added password change and password retries getter commands to the HSM2DongleSGX - Updated user options to make names more generic - Added unit tests - Updated middleware docker do script to expose the host to the container (allowing for running tests against e.g. an SGX powHSM simulator) --- .github/workflows/run-tests.yml | 8 +- build-dist => build-dist-ledger | 6 +- dist/scripts/setup | 4 +- dist/scripts/upgrade-existing | 4 +- docker/mware/do | 2 +- docs/attestation.md | 2 +- docs/protocol-v1.md | 2 +- firmware/src/powhsm/src/err.h | 1 + firmware/src/powhsm/src/instructions.h | 1 + firmware/src/sgx/src/trusted/system.c | 23 +++++ middleware/README.md | 16 ++-- middleware/{adm.py => adm_ledger.py} | 2 +- middleware/build/adm | 2 - middleware/build/adm_ledger | 2 + middleware/build/all | 6 +- middleware/build/{dist => dist_ledger} | 10 +-- middleware/build/manager | 2 - middleware/build/manager-tcp | 2 - middleware/build/manager_ledger | 2 + middleware/build/manager_sgx | 2 + middleware/build/manager_tcp | 2 + middleware/ledger/protocol.py | 14 +-- middleware/{manager.py => manager_ledger.py} | 12 ++- middleware/manager_sgx.py | 61 +++++++++++++ middleware/{manager-tcp.py => manager_tcp.py} | 19 ++-- middleware/mgr/runner.py | 5 +- middleware/sgx/hsm2dongle.py | 14 +++ middleware/test_sigaut.json | 11 --- .../admin/{test_adm.py => test_adm_ledger.py} | 47 +++++----- middleware/tests/sgx/test_hsm2dongle.py | 90 +++++++++++++++++++ middleware/user/options.py | 43 ++++----- utils/tcpsigner-bundle/.gitignore | 2 +- utils/tcpsigner-bundle/README.md | 4 +- utils/tcpsigner-bundle/build.sh | 4 +- utils/tcpsigner-bundle/dist/Dockerfile | 6 +- utils/tcpsigner-bundle/dist/bin/entrypoint.sh | 4 +- 36 files changed, 322 insertions(+), 115 deletions(-) rename build-dist => build-dist-ledger (95%) rename middleware/{adm.py => adm_ledger.py} (98%) delete mode 100755 middleware/build/adm create mode 100755 middleware/build/adm_ledger rename middleware/build/{dist => dist_ledger} (51%) delete mode 100755 middleware/build/manager delete mode 100755 middleware/build/manager-tcp create mode 100755 middleware/build/manager_ledger create mode 100755 middleware/build/manager_sgx create mode 100755 middleware/build/manager_tcp rename middleware/{manager.py => manager_ledger.py} (83%) create mode 100644 middleware/manager_sgx.py rename middleware/{manager-tcp.py => manager_tcp.py} (80%) delete mode 100644 middleware/test_sigaut.json rename middleware/tests/admin/{test_adm.py => test_adm_ledger.py} (88%) create mode 100644 middleware/tests/sgx/test_hsm2dongle.py diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 3694fdd9..e9067073 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -56,7 +56,7 @@ jobs: run: | docker/mware/build docker/packer/build - middleware/build/manager-tcp + middleware/build/manager_tcp firmware/build/build-tcpsigner - name: Checkout hsm-integration-test repo @@ -69,9 +69,9 @@ jobs: - name: Copy required files run: | - mkdir hsm-integration-test/docker/manager/manager-tcp - tar -xzf rsk-powhsm/middleware/bin/manager-tcp.tgz \ - -C hsm-integration-test/docker/manager/manager-tcp + mkdir hsm-integration-test/docker/manager/manager_tcp + tar -xzf rsk-powhsm/middleware/bin/manager_tcp.tgz \ + -C hsm-integration-test/docker/manager/manager_tcp cp rsk-powhsm/firmware/src/tcpsigner/tcpsigner \ hsm-integration-test/docker/tcpsigner/ diff --git a/build-dist b/build-dist-ledger similarity index 95% rename from build-dist rename to build-dist-ledger index 995eecad..ed487a8e 100755 --- a/build-dist +++ b/build-dist-ledger @@ -48,10 +48,10 @@ rm -f $DEST_DIR/attestation.json $DEST_DIR/device_attestation.json echo echo -e "\e[33mBuilding middleware...\e[0m" -$ROOT_DIR/middleware/build/dist -cp $ROOT_DIR/middleware/bin/adm.tgz $BIN_DIR +$ROOT_DIR/middleware/build/dist_ledger +cp $ROOT_DIR/middleware/bin/adm_ledger.tgz $BIN_DIR cp $ROOT_DIR/middleware/bin/lbutils.tgz $BIN_DIR -cp $ROOT_DIR/middleware/bin/manager.tgz $BIN_DIR +cp $ROOT_DIR/middleware/bin/manager_ledger.tgz $BIN_DIR cp $ROOT_DIR/middleware/bin/signapp.tgz $BIN_DIR echo diff --git a/dist/scripts/setup b/dist/scripts/setup index ce3fef40..7d91a3d0 100755 --- a/dist/scripts/setup +++ b/dist/scripts/setup @@ -13,9 +13,9 @@ TARGET_ID="$(cat $ROOT_DIR/scripts/target.id)" LBUTILS_DIR="$ROOT_DIR/bin/lbutils" LBUTILS_BUNDLE="$LBUTILS_DIR.tgz" LBUTILS="$LBUTILS_DIR/lbutils" -ADMIN_DIR="$ROOT_DIR/bin/adm" +ADMIN_DIR="$ROOT_DIR/bin/adm_ledger" ADMIN_BUNDLE="$ADMIN_DIR.tgz" -ADMIN="$ADMIN_DIR/adm" +ADMIN="$ADMIN_DIR/adm_ledger" function cleanBinaries() { rm -rf $LBUTILS_DIR diff --git a/dist/scripts/upgrade-existing b/dist/scripts/upgrade-existing index 71435d53..5e1c33c2 100755 --- a/dist/scripts/upgrade-existing +++ b/dist/scripts/upgrade-existing @@ -10,9 +10,9 @@ TARGET_ID="$(cat $ROOT_DIR/scripts/target.id)" LBUTILS_DIR="$ROOT_DIR/bin/lbutils" LBUTILS_BUNDLE="$LBUTILS_DIR.tgz" LBUTILS="$LBUTILS_DIR/lbutils" -ADMIN_DIR="$ROOT_DIR/bin/adm" +ADMIN_DIR="$ROOT_DIR/bin/adm_ledger" ADMIN_BUNDLE="$ADMIN_DIR.tgz" -ADMIN="$ADMIN_DIR/adm" +ADMIN="$ADMIN_DIR/adm_ledger" function cleanBinaries() { rm -rf $LBUTILS_DIR diff --git a/docker/mware/do b/docker/mware/do index 1959920e..ec52f546 100755 --- a/docker/mware/do +++ b/docker/mware/do @@ -29,4 +29,4 @@ WORKDIR=$1; shift BINARY=$1; shift ARGS=$@ -docker run -ti --rm --name hsm-mware -v $HSM_ROOT:/hsm2 -v /dev/bus/usb:/dev/bus/usb --privileged -p$PORT:$PORT -w $WORKDIR $DOCKER_IMAGE $BINARY $ARGS +docker run -ti --rm --name hsm-mware -v $HSM_ROOT:/hsm2 -v /dev/bus/usb:/dev/bus/usb --privileged --add-host=host.docker.internal:host-gateway -p$PORT:$PORT -w $WORKDIR $DOCKER_IMAGE $BINARY $ARGS diff --git a/docs/attestation.md b/docs/attestation.md index 9d30255c..b4bf091b 100644 --- a/docs/attestation.md +++ b/docs/attestation.md @@ -142,7 +142,7 @@ The validation process _for each of the targets_ is fairly straightforward, and For completion's sake, a validation tool is provided within the administration toolset. So, for example, if the file depicted above was at `/a/path/to/the/attestation.json`, the JSON-formatted public keys generated at onboarding time were at `/a/path/to/the/public-keys.json` and we knew the issuer public key was `0490f5c9d15a0134bb019d2afd0bf297149738459706e7ac5be4abc350a1f818057224fce12ec9a65de18ec34d6e8c24db927835ea1692b14c32e9836a75dad609` (the actual ledger issuer public key, found in [ledger's endorsement setup tooling](https://github.com/LedgerHQ/blue-loader-python/blob/0.1.31/ledgerblue/endorsementSetup.py#L138)), we could issue: ```bash -middleware/term> python adm.py verify_attestation -t /a/path/to/the/attestation.json -r 0490f5c9d15a0134bb019d2afd0bf297149738459706e7ac5be4abc350a1f818057224fce12ec9a65de18ec34d6e8c24db927835ea1692b14c32e9836a75dad609 -b /a/path/to/the/public-keys.json +middleware/term> python adm_ledger.py verify_attestation -t /a/path/to/the/attestation.json -r 0490f5c9d15a0134bb019d2afd0bf297149738459706e7ac5be4abc350a1f818057224fce12ec9a65de18ec34d6e8c24db927835ea1692b14c32e9836a75dad609 -b /a/path/to/the/public-keys.json ``` to then obtain the following sample output: diff --git a/docs/protocol-v1.md b/docs/protocol-v1.md index 94668866..a5b78419 100644 --- a/docs/protocol-v1.md +++ b/docs/protocol-v1.md @@ -2,7 +2,7 @@ ## About -This document describes the legacy protocol used in version 1 of the HSM. The purpose is to provide a reference for the usage of the legacy mode in the manager and TCP manager (with modifier `--version-one`). +This document describes the legacy protocol used in version 1 of the HSM. The purpose is to provide a reference for the usage of the legacy mode in the Ledger manager and TCP manager (with modifier `--version-one`). ## Definitions diff --git a/firmware/src/powhsm/src/err.h b/firmware/src/powhsm/src/err.h index fbadb3a3..9e1addb1 100644 --- a/firmware/src/powhsm/src/err.h +++ b/firmware/src/powhsm/src/err.h @@ -35,6 +35,7 @@ typedef enum { ERR_DEVICE_ONBOARDED = 0x6BEF, ERR_ONBOARDING = 0x6BF0, ERR_DEVICE_LOCKED = 0x6BF1, + ERR_PASSWORD_CHANGE = 0x6BF2, } err_code_signer_t; #endif // __ERR_H diff --git a/firmware/src/powhsm/src/instructions.h b/firmware/src/powhsm/src/instructions.h index 65b25d2e..077680bc 100644 --- a/firmware/src/powhsm/src/instructions.h +++ b/firmware/src/powhsm/src/instructions.h @@ -58,6 +58,7 @@ typedef enum { SGX_RETRIES = 0xA2, SGX_UNLOCK = 0xA3, SGX_ECHO = 0xA4, + SGX_CHANGE_PASSWORD = 0xA5, } apdu_instruction_t; #endif // __INSTRUCTIONS_H diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c index d2bffa63..9cc80815 100644 --- a/firmware/src/sgx/src/trusted/system.c +++ b/firmware/src/sgx/src/trusted/system.c @@ -67,6 +67,24 @@ static unsigned int do_onboard(unsigned int rx) { return TX_NO_DATA(); } +static unsigned int do_change_password(unsigned int rx) { + // Require a nonblank password + if (APDU_DATA_SIZE(rx) < 1) { + THROW(ERR_INVALID_DATA_SIZE); + } + + // Password change + uint8_t tmp_buffer[apdu_buffer_size]; + size_t password_length = APDU_DATA_SIZE(rx); + memcpy(tmp_buffer, APDU_DATA_PTR, password_length); + if (!access_set_password((char*)tmp_buffer, password_length)) { + THROW(ERR_PASSWORD_CHANGE); + } + + SET_APDU_OP(1); + return TX_NO_DATA(); +} + static unsigned int do_unlock(unsigned int rx) { if (!access_is_locked()) { SET_APDU_OP(1); @@ -124,6 +142,11 @@ static external_processor_result_t system_do_process_apdu(unsigned int rx) { case SGX_ECHO: result.tx = do_echo(rx); break; + case SGX_CHANGE_PASSWORD: + REQUIRE_ONBOARDED(); + REQUIRE_UNLOCKED(); + result.tx = do_change_password(rx); + break; default: result.handled = false; } diff --git a/middleware/README.md b/middleware/README.md index fd6f2e93..a1f182e2 100644 --- a/middleware/README.md +++ b/middleware/README.md @@ -40,36 +40,36 @@ Throughout the rest of the document, we will refer to a middleware development e ## Middleware breakdown -### Manager +### Ledger Manager -The manager is the main middleware component. Its role is to provide a high-level abstraction layer over the low-level powHSM dongle USB interface. It does this by starting a TCP service in a certain interface and port and implementing the [protocol](../docs/protocol.md) on top by means of interactions with the connected powHSM dongle. The entrypoint to the powHSM manager is the `manager.py` script. In order to start it, issue: +The Ledger manager is the main middleware component for the Ledger powHSM implementation. Its role is to provide a high-level abstraction layer over the low-level powHSM dongle USB interface. It does this by starting a TCP service in a certain interface and port and implementing the [protocol](../docs/protocol.md) on top by means of interactions with the connected powHSM dongle. The entrypoint to the powHSM manager is the `manager_ledger.py` script. In order to start it, issue: ``` -(mware)> python manager.py +(mware)> python manager_ledger.py ``` Hit CTRL-C at any time to stop it. ### TCP Manager -This is an implementation of the Manager that connects to a dongle via a TCP/IP connection. Its main use is along the TCPSigner (an x86 implementation of the Signer component) for integration tests and the like. It's important to mention that Manager and TCP Manager share most of the code, and that the main difference lies in the dongle proxy used and available user options. The entrypoint to the TCP manager is the `manager-tcp.py` script. In order to start it, issue: +This is an implementation of the Manager that connects to a dongle via a TCP/IP connection. Its main use is along the TCPSigner (an x86 implementation of the Signer component) for integration tests and the like. It's important to mention that Manager and TCP Manager share most of the code, and that the main difference lies in the dongle proxy used and available user options. The entrypoint to the TCP manager is the `manager_tcp.py` script. In order to start it, issue: ``` -(mware)> python manager-tcp.py +(mware)> python manager_tcp.py ``` Hit CTRL-C at any time to stop it. ### Administrative utilities -Aside from the main `manager.py` and `manager-tcp.py` scripts, there are other three scripts to consider: +Aside from the main `manager_ledger.py` and `manager_tcp.py` scripts, there are other three scripts to consider: -- `adm.py`: administrative utility for a powHSM dongle. It provides common utilities that can be performed on a powHSM dongle. +- `adm_ledger.py`: administrative utility for a Ledger powHSM dongle. It provides common utilities that can be performed on a powHSM dongle. - `lbutils.py`: common frontend to some of the `ledgerblue` modules. In particular, it ultimately serves the purpose of being able to build a binary for these utilities. - `signapp.py`: signer authorization generator. Serves the purpose of generating authorization files for Signer versions (see [the signer authorization documentation](../docs/signer-authorization.md) for details). It can be used to add externally generated signatures, or to sign with a manually input key (intended for testing purposes only). It can also be used to calculate the message to be signed to authorize a specific signer version (so that then the signature can be generated on a third-party application, e.g., MetaMask). Last, it has an option to calculate and output a Ledger app's hash. - `signonetime.py`: ledger app signer. Serves the purpose of signing Ledger Nano S firmware builds with a securely generated random one-time key. It is used in the distribution building process targeting the initial device setup process. -The remaining `client.py` is a shorthand client utility for manually testing communication with a running manager or TCP manager. +The remaining `client.py` is a shorthand client utility for manually testing communication with a running Ledger manager or TCP manager. ## Unit tests diff --git a/middleware/adm.py b/middleware/adm_ledger.py similarity index 98% rename from middleware/adm.py rename to middleware/adm_ledger.py index fbba3243..4865341b 100644 --- a/middleware/adm.py +++ b/middleware/adm_ledger.py @@ -51,7 +51,7 @@ def main(): "authorize_signer": do_authorize_signer, } - parser = ArgumentParser(description="powHSM Administrative tool") + parser = ArgumentParser(description="Ledger powHSM Administrative tool") parser.add_argument("operation", choices=list(actions.keys())) parser.add_argument("-p", "--pin", dest="pin", help="PIN.") parser.add_argument( diff --git a/middleware/build/adm b/middleware/build/adm deleted file mode 100755 index 3ccf6a23..00000000 --- a/middleware/build/adm +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -source $(dirname $0)/bld-docker adm diff --git a/middleware/build/adm_ledger b/middleware/build/adm_ledger new file mode 100755 index 00000000..b8fa5eb6 --- /dev/null +++ b/middleware/build/adm_ledger @@ -0,0 +1,2 @@ +#!/bin/bash +source $(dirname $0)/bld-docker adm_ledger diff --git a/middleware/build/all b/middleware/build/all index 6c4b8bd0..b54b0f87 100755 --- a/middleware/build/all +++ b/middleware/build/all @@ -5,9 +5,9 @@ BINDIR=$(realpath $BUILDDIR/../bin/) echo "Building all..." -QUIET=1 $BUILDDIR/manager && \ -QUIET=1 $BUILDDIR/manager-tcp && \ -QUIET=1 $BUILDDIR/adm && \ +QUIET=1 $BUILDDIR/manager_ledger && \ +QUIET=1 $BUILDDIR/manager_tcp && \ +QUIET=1 $BUILDDIR/adm_ledger && \ QUIET=1 $BUILDDIR/lbutils && \ QUIET=1 $BUILDDIR/signapp && \ echo "" && sha256sum $BINDIR/*.tgz diff --git a/middleware/build/dist b/middleware/build/dist_ledger similarity index 51% rename from middleware/build/dist rename to middleware/build/dist_ledger index befba2e2..7150e738 100755 --- a/middleware/build/dist +++ b/middleware/build/dist_ledger @@ -3,14 +3,14 @@ BUILDDIR=$(dirname $0) BINDIR=$(realpath $BUILDDIR/../bin/) -echo "Building distribution binaries..." +echo "Building Ledger distribution binaries..." -QUIET=1 $BUILDDIR/manager && \ -QUIET=1 $BUILDDIR/adm && \ +QUIET=1 $BUILDDIR/manager_ledger && \ +QUIET=1 $BUILDDIR/adm_ledger && \ QUIET=1 $BUILDDIR/lbutils && \ QUIET=1 $BUILDDIR/signapp && \ echo "" && \ -sha256sum $BINDIR/manager.tgz && \ -sha256sum $BINDIR/adm.tgz && \ +sha256sum $BINDIR/manager_ledger.tgz && \ +sha256sum $BINDIR/adm_ledger.tgz && \ sha256sum $BINDIR/lbutils.tgz sha256sum $BINDIR/signapp.tgz diff --git a/middleware/build/manager b/middleware/build/manager deleted file mode 100755 index ab53b2e4..00000000 --- a/middleware/build/manager +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -source $(dirname $0)/bld-docker manager diff --git a/middleware/build/manager-tcp b/middleware/build/manager-tcp deleted file mode 100755 index 79c2f6b5..00000000 --- a/middleware/build/manager-tcp +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -source $(dirname $0)/bld-docker manager-tcp diff --git a/middleware/build/manager_ledger b/middleware/build/manager_ledger new file mode 100755 index 00000000..8a225742 --- /dev/null +++ b/middleware/build/manager_ledger @@ -0,0 +1,2 @@ +#!/bin/bash +source $(dirname $0)/bld-docker manager_ledger diff --git a/middleware/build/manager_sgx b/middleware/build/manager_sgx new file mode 100755 index 00000000..c750daee --- /dev/null +++ b/middleware/build/manager_sgx @@ -0,0 +1,2 @@ +#!/bin/bash +source $(dirname $0)/bld-docker manager_sgx diff --git a/middleware/build/manager_tcp b/middleware/build/manager_tcp new file mode 100755 index 00000000..3345c1ef --- /dev/null +++ b/middleware/build/manager_tcp @@ -0,0 +1,2 @@ +#!/bin/bash +source $(dirname $0)/bld-docker manager_tcp diff --git a/middleware/ledger/protocol.py b/middleware/ledger/protocol.py index 53d6dcad..ec6976cf 100644 --- a/middleware/ledger/protocol.py +++ b/middleware/ledger/protocol.py @@ -46,6 +46,11 @@ class HSM2ProtocolLedger(HSM2Protocol): # Required minimum number of pin retries available to proceed with unlocking MIN_AVAILABLE_RETRIES = 2 + # Default user messages + MESSAGES = { + "restart": "restart the powHSM" + } + def __init__(self, pin, dongle): super().__init__() self.hsm2dongle = dongle @@ -73,7 +78,7 @@ def initialize_device(self): self.logger.info( "Could not determine onboarded status. If unlocked, " + "please enter the signing app and rerun the manager. Otherwise," - + "disconnect and reconnect the ledger nano and try again" + + f"{self.MESSAGES["restart"]} and try again" ) raise HSM2ProtocolInterrupt() @@ -196,14 +201,13 @@ def _handle_bootloader(self): raise Exception("Dongle reported fail to change pin. Pin invalid?") self.pin.commit_change() self.logger.info( - "PIN changed. Please disconnect and reconnect the ledger nano" + f"PIN changed. Please {self.MESSAGES["restart"]}" ) except Exception as e: self.pin.abort_change() self.logger.error( - "Error changing PIN: %s. Please disconnect and " - "reconnect the ledger nano and try again", - format(e), + f"Error changing PIN: %s. Please {self.MESSAGES["restart"]} " + "and try again", format(e), ) finally: raise HSM2ProtocolInterrupt() diff --git a/middleware/manager.py b/middleware/manager_ledger.py similarity index 83% rename from middleware/manager.py rename to middleware/manager_ledger.py index 658ec798..c88f3602 100644 --- a/middleware/manager.py +++ b/middleware/manager_ledger.py @@ -39,12 +39,18 @@ def load_pin(user_options): return pin +def configure_protocol_messages(protocol): + protocol.MESSAGES = { + "restart": "disconnect and reconnect the ledger nano", + } + + if __name__ == "__main__": - user_options = UserOptionParser("Start the powHSM manager", + user_options = UserOptionParser("Start the powHSM manager for Ledger", with_pin=True).parse() runner = ManagerRunner("powHSM manager", - lambda options: HSM2Dongle(options.dongle_debug), - load_pin) + lambda options: HSM2Dongle(options.io_debug), + load_pin, configure_protocol_messages) runner.run(user_options) diff --git a/middleware/manager_sgx.py b/middleware/manager_sgx.py new file mode 100644 index 00000000..9b443181 --- /dev/null +++ b/middleware/manager_sgx.py @@ -0,0 +1,61 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +from sgx.hsm2dongle import HSM2DongleSGX +from mgr.runner import ManagerRunner +from ledger.pin import FileBasedPin +from user.options import UserOptionParser + + +def load_pin(user_options): + env_pin = os.environ.get("PIN", None) + if env_pin is not None: + env_pin = env_pin.encode() + pin = FileBasedPin( + user_options.pin_file, + default_pin=env_pin, + force_change=user_options.force_pin_change, + ) + return pin + + +def configure_protocol_messages(protocol): + protocol.MESSAGES = { + "restart": "restart the SGX powHSM", + } + + +if __name__ == "__main__": + user_options = UserOptionParser("Start the powHSM manager for SGX", + with_pin=True, + with_tcpconn=True, + host_name="SGX", + default_tcpconn_port=7777).parse() + + runner = ManagerRunner("powHSM manager for SGX", + lambda options: HSM2DongleSGX(options.tcpconn_host, + options.tcpconn_port, + options.io_debug), + load_pin, configure_protocol_messages) + + runner.run(user_options) diff --git a/middleware/manager-tcp.py b/middleware/manager_tcp.py similarity index 80% rename from middleware/manager-tcp.py rename to middleware/manager_tcp.py index b7977093..de3d73db 100644 --- a/middleware/manager-tcp.py +++ b/middleware/manager_tcp.py @@ -24,15 +24,24 @@ from mgr.runner import ManagerRunner from user.options import UserOptionParser + +def configure_protocol_messages(protocol): + protocol.MESSAGES = { + "restart": "restart the TCPSigner", + } + + if __name__ == "__main__": user_options = UserOptionParser("Start the powHSM manager for TCPSigner", with_pin=False, - with_tcpsigner=True).parse() + with_tcpconn=True, + host_name="TCPSigner").parse() runner = ManagerRunner("powHSM manager for TCPSigner", - lambda options: HSM2DongleTCP(options.tcpsigner_host, - options.tcpsigner_port, - options.dongle_debug), - load_pin=lambda options: None) + lambda options: HSM2DongleTCP(options.tcpconn_host, + options.tcpconn_port, + options.io_debug), + load_pin=lambda options: None, + configure_protocol=configure_protocol_messages) runner.run(user_options) diff --git a/middleware/mgr/runner.py b/middleware/mgr/runner.py index df65e535..95647ca9 100644 --- a/middleware/mgr/runner.py +++ b/middleware/mgr/runner.py @@ -29,10 +29,11 @@ class ManagerRunner: - def __init__(self, name, create_dongle, load_pin): + def __init__(self, name, create_dongle, load_pin, configure_protocol=None): self.name = name self.create_dongle = create_dongle self.load_pin = load_pin + self.configure_protocol = configure_protocol def run(self, user_options): configure_logging(user_options.logconfigfilepath) @@ -51,6 +52,8 @@ def run(self, user_options): else: logger.info("Using protocol version 2") protocol = HSM2ProtocolLedger(pin, dongle) + if self.configure_protocol: + self.configure_protocol(protocol) server = TCPServer(user_options.host, user_options.port, protocol) server.run() except PinError as e: diff --git a/middleware/sgx/hsm2dongle.py b/middleware/sgx/hsm2dongle.py index 1126581f..4a463907 100644 --- a/middleware/sgx/hsm2dongle.py +++ b/middleware/sgx/hsm2dongle.py @@ -25,8 +25,10 @@ class SgxCommand(IntEnum): + SGX_RETRIES = 0xA2, SGX_UNLOCK = 0xA3, SGX_ECHO = 0xA4, + SGX_CHANGE_PASSWORD = 0xA5, class HSM2DongleSGX(HSM2DongleTCP): @@ -44,3 +46,15 @@ def unlock(self, pin): # Nonzero indicates device unlocked return response[2] != 0 + + # change pin + def new_pin(self, pin): + response = self._send_command(SgxCommand.SGX_CHANGE_PASSWORD, bytes([0]) + pin) + + # One indicates pin changed + return response[2] == 1 + + # returns the number of pin retries available + def get_retries(self): + apdu_rcv = self._send_command(SgxCommand.SGX_RETRIES) + return apdu_rcv[2] diff --git a/middleware/test_sigaut.json b/middleware/test_sigaut.json deleted file mode 100644 index 1ebee596..00000000 --- a/middleware/test_sigaut.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": 1, - "signer": { - "hash": "7b4dd003a0c675013360082d9474b5f0062e6ab8ad8f2793dcba1bae05aabbcc", - "iteration": 61098 - }, - "signatures": [ - "304402201be9a51e95818384d18cc05b76490cfbce672e452475f831dcfeb6af8f199ef702207933b4405a71ca36f2327f116a92585f6e4c0817069517a3c822fa80c5859cce", - "30440220083012fbb4e0a43c2ec82719e9ee10a372f0c83e81b140c570df38e0ac4c9cb80220251d18b9d6eab5598cf28c7f4f01ff1f82c217cf36d38924f326b61bfdf2e80a" - ] -} diff --git a/middleware/tests/admin/test_adm.py b/middleware/tests/admin/test_adm_ledger.py similarity index 88% rename from middleware/tests/admin/test_adm.py rename to middleware/tests/admin/test_adm_ledger.py index 7528b2f3..d1b06b14 100644 --- a/middleware/tests/admin/test_adm.py +++ b/middleware/tests/admin/test_adm_ledger.py @@ -24,13 +24,13 @@ from argparse import Namespace from unittest import TestCase from unittest.mock import call, patch -from adm import main, DEFAULT_ATT_UD_SOURCE +from adm_ledger import main, DEFAULT_ATT_UD_SOURCE import logging logging.disable(logging.CRITICAL) -class TestAdm(TestCase): +class TestAdmLedger(TestCase): def setUp(self): self.old_stderr = sys.stderr # sys.stderr = Mock() @@ -56,7 +56,7 @@ def tearDown(self): sys.stderr = self.old_stderr sys.stdout = self.old_stdout - @patch("adm.do_unlock") + @patch("adm_ledger.do_unlock") def test_unlock(self, do_unlock): expected_options = { **self.DEFAULT_OPTIONS, @@ -68,12 +68,12 @@ def test_unlock(self, do_unlock): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm.py', '-p', 'a-pin', 'unlock']): + with patch('sys.argv', ['adm_ledger.py', '-p', 'a-pin', 'unlock']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) - with patch('sys.argv', ['adm.py', '--pin', 'a-pin', 'unlock']): + with patch('sys.argv', ['adm_ledger.py', '--pin', 'a-pin', 'unlock']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) @@ -82,7 +82,7 @@ def test_unlock(self, do_unlock): self.assertEqual(do_unlock.call_count, 2) self.assertEqual(expected_call_args_list, do_unlock.call_args_list) - @patch("adm.do_onboard") + @patch("adm_ledger.do_onboard") def test_onboard(self, do_onboard): expected_options = { **self.DEFAULT_OPTIONS, @@ -96,13 +96,14 @@ def test_onboard(self, do_onboard): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm.py', '-p', 'a-pin', '-o', 'a-path', 'onboard']): + with patch('sys.argv', + ['adm_ledger.py', '-p', 'a-pin', '-o', 'a-path', 'onboard']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) with patch('sys.argv', - ['adm.py', '--pin', 'a-pin', '--output', 'a-path', 'onboard']): + ['adm_ledger.py', '--pin', 'a-pin', '--output', 'a-path', 'onboard']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) @@ -110,7 +111,7 @@ def test_onboard(self, do_onboard): self.assertTrue(do_onboard.called) self.assertEqual(expected_call_args_list, do_onboard.call_args_list) - @patch("adm.do_get_pubkeys") + @patch("adm_ledger.do_get_pubkeys") def test_pubkeys(self, do_get_pubkeys): expected_options = { **self.DEFAULT_OPTIONS, @@ -125,14 +126,14 @@ def test_pubkeys(self, do_get_pubkeys): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm.py', '-p', 'a-pin', '-o', 'a-path', '-u', + with patch('sys.argv', ['adm_ledger.py', '-p', 'a-pin', '-o', 'a-path', '-u', 'pubkeys']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) with patch('sys.argv', - ['adm.py', + ['adm_ledger.py', '--pin', 'a-pin', '--output', 'a-path', '--nounlock', @@ -144,7 +145,7 @@ def test_pubkeys(self, do_get_pubkeys): self.assertTrue(do_get_pubkeys.called) self.assertEqual(expected_call_args_list, do_get_pubkeys.call_args_list) - @patch("adm.do_changepin") + @patch("adm_ledger.do_changepin") def test_changepin(self, do_changepin): expected_options = { **self.DEFAULT_OPTIONS, @@ -158,13 +159,13 @@ def test_changepin(self, do_changepin): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm.py', '-p', 'old-pin', '-n', 'new-pin', + with patch('sys.argv', ['adm_ledger.py', '-p', 'old-pin', '-n', 'new-pin', '-a', 'changepin']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) - with patch('sys.argv', ['adm.py', + with patch('sys.argv', ['adm_ledger.py', '--newpin', 'new-pin', '--anypin', 'changepin', '--pin', 'old-pin']): with self.assertRaises(SystemExit) as e: @@ -175,7 +176,7 @@ def test_changepin(self, do_changepin): self.assertEqual(do_changepin.call_count, 2) self.assertEqual(expected_call_args_list, do_changepin.call_args_list) - @patch("adm.do_attestation") + @patch("adm_ledger.do_attestation") def test_attestation(self, do_attestation): expected_options = { **self.DEFAULT_OPTIONS, @@ -190,7 +191,7 @@ def test_attestation(self, do_attestation): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm.py', + with patch('sys.argv', ['adm_ledger.py', '-p', 'a-pin', '-o', 'out-path', '-t', 'certification-path', @@ -200,7 +201,7 @@ def test_attestation(self, do_attestation): main() self.assertEqual(e.exception.code, 0) - with patch('sys.argv', ['adm.py', + with patch('sys.argv', ['adm_ledger.py', '--pin', 'a-pin', '--output', 'out-path', '--attcert', 'certification-path', @@ -214,7 +215,7 @@ def test_attestation(self, do_attestation): self.assertEqual(do_attestation.call_count, 2) self.assertEqual(expected_call_args_list, do_attestation.call_args_list) - @patch("adm.do_verify_attestation") + @patch("adm_ledger.do_verify_attestation") def test_verify_attestation(self, do_verify_attestation): expected_options = { **self.DEFAULT_OPTIONS, @@ -229,7 +230,7 @@ def test_verify_attestation(self, do_verify_attestation): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm.py', + with patch('sys.argv', ['adm_ledger.py', '-p', 'a-pin', '-t', 'certification-path', '-r', 'root-authority', @@ -239,7 +240,7 @@ def test_verify_attestation(self, do_verify_attestation): main() self.assertEqual(e.exception.code, 0) - with patch('sys.argv', ['adm.py', + with patch('sys.argv', ['adm_ledger.py', '--pin', 'a-pin', '--attcert', 'certification-path', '--root', 'root-authority', @@ -253,7 +254,7 @@ def test_verify_attestation(self, do_verify_attestation): self.assertEqual(do_verify_attestation.call_count, 2) self.assertEqual(expected_call_args_list, do_verify_attestation.call_args_list) - @patch("adm.do_authorize_signer") + @patch("adm_ledger.do_authorize_signer") def test_authorize_signer(self, do_authorize_signer): expected_options = { **self.DEFAULT_OPTIONS, @@ -266,7 +267,7 @@ def test_authorize_signer(self, do_authorize_signer): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm.py', + with patch('sys.argv', ['adm_ledger.py', '-p', 'a-pin', '-z', 'a-file-path', 'authorize_signer']): @@ -274,7 +275,7 @@ def test_authorize_signer(self, do_authorize_signer): main() self.assertEqual(e.exception.code, 0) - with patch('sys.argv', ['adm.py', + with patch('sys.argv', ['adm_ledger.py', '--pin', 'a-pin', '--signauth', 'a-file-path', 'authorize_signer']): diff --git a/middleware/tests/sgx/test_hsm2dongle.py b/middleware/tests/sgx/test_hsm2dongle.py new file mode 100644 index 00000000..b3a48ba4 --- /dev/null +++ b/middleware/tests/sgx/test_hsm2dongle.py @@ -0,0 +1,90 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from unittest import TestCase +from unittest.mock import Mock, patch +from sgx.hsm2dongle import HSM2DongleSGX +from ledger.hsm2dongle import HSM2DongleError + +import logging + +logging.disable(logging.CRITICAL) + + +class TestHSM2DongleSGX(TestCase): + EXPECTED_DONGLE_TIMEOUT = 10 + + @patch("ledger.hsm2dongle_tcp.getDongle") + def setUp(self, getDongleMock): + self.dongle = Mock() + self.getDongleMock = getDongleMock + self.getDongleMock.return_value = self.dongle + self.hsm2dongle = HSM2DongleSGX("a-host", 1234, "a-debug-value") + + self.getDongleMock.assert_not_called() + self.hsm2dongle.connect() + self.getDongleMock.assert_called_with("a-host", 1234, "a-debug-value") + self.assertEqual(self.hsm2dongle.dongle, self.dongle) + + def assert_exchange_called(self, bs): + self.dongle.exchange.assert_called_with(bs, timeout=self.EXPECTED_DONGLE_TIMEOUT) + + def test_echo_ok(self): + self.dongle.exchange.return_value = bytes([0x80, 0xA4, 0x41, 0x42, 0x43]) + self.assertTrue(self.hsm2dongle.echo()) + self.assert_exchange_called(bytes([0x80, 0xA4, 0x41, 0x42, 0x43])) + + def test_echo_response_differs(self): + self.dongle.exchange.return_value = bytes([1, 2, 3]) + self.assertFalse(self.hsm2dongle.echo()) + self.assert_exchange_called(bytes([0x80, 0xA4, 0x41, 0x42, 0x43])) + + def test_echo_error_triggered(self): + self.dongle.exchange.side_effect = RuntimeError("SomethingWentWrong") + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.echo() + self.assert_exchange_called(bytes([0x80, 0xA4, 0x41, 0x42, 0x43])) + + def test_unlock_ok(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0xCC, 0xDD]) + self.assertTrue(self.hsm2dongle.unlock(b'a-password')) + self.assert_exchange_called(bytes([0x80, 0xA3, 0x00]) + b'a-password') + + def test_unlock_wrong_pass(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x00, 0xDD]) + self.assertFalse(self.hsm2dongle.unlock(b'wrong-pass')) + self.assert_exchange_called(bytes([0x80, 0xA3, 0x00]) + b'wrong-pass') + + def test_newpin_ok(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01, 0xDD]) + self.assertTrue(self.hsm2dongle.new_pin(b'new-password')) + self.assert_exchange_called(bytes([0x80, 0xA5, 0x00]) + b'new-password') + + def test_newpin_error(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x55, 0xDD]) + self.assertFalse(self.hsm2dongle.new_pin(b'new-password')) + self.assert_exchange_called(bytes([0x80, 0xA5, 0x00]) + b'new-password') + + def test_get_retries(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x05, 0xDD]) + self.assertEqual(5, self.hsm2dongle.get_retries()) + self.assert_exchange_called(bytes([0x80, 0xA2])) diff --git a/middleware/user/options.py b/middleware/user/options.py index 468ef46d..71c920d2 100644 --- a/middleware/user/options.py +++ b/middleware/user/options.py @@ -28,23 +28,25 @@ def __init__( self, description, with_pin, - with_tcpsigner=False, + with_tcpconn=False, + host_name="", default_port=9999, default_host="localhost", default_pin_file="pin.txt", default_logging_config_path="logging.cfg", - default_tcpsigner_host="localhost", - default_tcpsigner_port=8888, + default_tcpconn_host="localhost", + default_tcpconn_port=8888, ): self.description = description self.with_pin = with_pin - self.with_tcpsigner = with_tcpsigner + self.with_tcpconn = with_tcpconn + self.host_name = host_name self.default_port = default_port self.default_host = default_host self.default_pin_file = default_pin_file self.default_logging_config_path = default_logging_config_path - self.default_tcpsigner_port = default_tcpsigner_port - self.default_tcpsigner_host = default_tcpsigner_host + self.default_tcpconn_port = default_tcpconn_port + self.default_tcpconn_host = default_tcpconn_host def parse(self): parser = ArgumentParser(description=self.description) @@ -65,10 +67,10 @@ def parse(self): ) parser.add_argument( "-D", - "--dongledebug", - dest="dongle_debug", + "--iodebug", + dest="io_debug", action="store_true", - help="Low level dongle debug. (defaults to no)", + help="Low level I/O debug. (defaults to no)", ) if self.with_pin: @@ -102,21 +104,22 @@ def parse(self): help="Run in version 1 mode. (defaults to no)", ) - if self.with_tcpsigner: + if self.with_tcpconn: parser.add_argument( - "-tp", - "--tcpsigner-port", - dest="tcpsigner_port", - help=f"TCPSigner listening port (default {self.default_tcpsigner_port})", + f"-{self.host_name.lower()[0]}p", + f"--{self.host_name.lower()}-port", + dest="tcpconn_port", + help=f"{self.host_name} listening port (default " + f"{self.default_tcpconn_port})", type=int, - default=self.default_tcpsigner_port, + default=self.default_tcpconn_port, ) parser.add_argument( - "-th", - "--tcpsigner-host", - dest="tcpsigner_host", - help=f"TCPSigner host. (default '{self.default_tcpsigner_host}')", - default=self.default_tcpsigner_host, + f"-{self.host_name.lower()[0]}h", + f"--{self.host_name.lower()}-host", + dest="tcpconn_host", + help=f"{self.host_name} host. (default '{self.default_tcpconn_host}')", + default=self.default_tcpconn_host, ) options = parser.parse_args() diff --git a/utils/tcpsigner-bundle/.gitignore b/utils/tcpsigner-bundle/.gitignore index f2ff071d..25bd9a7f 100644 --- a/utils/tcpsigner-bundle/.gitignore +++ b/utils/tcpsigner-bundle/.gitignore @@ -1,4 +1,4 @@ dist/key.secp256 dist/tcpsigner.log dist/bin/tcpsigner -dist/bin/manager-tcp.tgz +dist/bin/manager_tcp.tgz diff --git a/utils/tcpsigner-bundle/README.md b/utils/tcpsigner-bundle/README.md index c4f7ad19..c7a365a3 100644 --- a/utils/tcpsigner-bundle/README.md +++ b/utils/tcpsigner-bundle/README.md @@ -23,8 +23,8 @@ docker/packer/build ### Building and bundling -Before using the TCPSigner bundle (i.e., TCPSigner + Manager combo), both the TCPSigner -and the TCPManager binaries must be built. In order to do that, within this document's +Before using the TCPSigner bundle (i.e., TCPSigner + TCP Manager combo), both the TCPSigner +and the TCP Manager binaries must be built. In order to do that, within this document's directory, issue: ``` diff --git a/utils/tcpsigner-bundle/build.sh b/utils/tcpsigner-bundle/build.sh index b3198bda..8f29df64 100755 --- a/utils/tcpsigner-bundle/build.sh +++ b/utils/tcpsigner-bundle/build.sh @@ -13,7 +13,7 @@ cp $ROOTDIR/firmware/src/tcpsigner/tcpsigner $DESTDIR echo "Building TCPManager..." -$ROOTDIR/middleware/build/manager-tcp > /dev/null 2>&1 -cp $ROOTDIR/middleware/bin/manager-tcp.tgz $DESTDIR +$ROOTDIR/middleware/build/manager_tcp > /dev/null 2>&1 +cp $ROOTDIR/middleware/bin/manager_tcp.tgz $DESTDIR echo "Done." diff --git a/utils/tcpsigner-bundle/dist/Dockerfile b/utils/tcpsigner-bundle/dist/Dockerfile index c228a37c..b7d52856 100644 --- a/utils/tcpsigner-bundle/dist/Dockerfile +++ b/utils/tcpsigner-bundle/dist/Dockerfile @@ -7,9 +7,9 @@ WORKDIR /bundle COPY bin/tcpsigner /bins/ -COPY bin/manager-tcp.tgz /bins/manager-tcp.tgz -RUN tar xzf /bins/manager-tcp.tgz -C /bins > /dev/null 2>&1 -RUN rm -f /bins/manager-tcp.tgz +COPY bin/manager_tcp.tgz /bins/manager_tcp.tgz +RUN tar xzf /bins/manager_tcp.tgz -C /bins > /dev/null 2>&1 +RUN rm -f /bins/manager_tcp.tgz COPY bin/entrypoint.sh /bins RUN chmod ugo+x /bins/entrypoint.sh diff --git a/utils/tcpsigner-bundle/dist/bin/entrypoint.sh b/utils/tcpsigner-bundle/dist/bin/entrypoint.sh index 7a6096d3..4fe13a33 100644 --- a/utils/tcpsigner-bundle/dist/bin/entrypoint.sh +++ b/utils/tcpsigner-bundle/dist/bin/entrypoint.sh @@ -17,7 +17,7 @@ help() { } stop() { - killall -q manager-tcp + killall -q manager_tcp killall -q tcpsigner exit @@ -47,7 +47,7 @@ done sleep 2 # Start the manager for the TCPSigner -/bins/manager-tcp -b0.0.0.0 -p$PORT & +/bins/manager_tcp -b0.0.0.0 -p$PORT & # Wait for any process to exit wait -n From 2487b4e80a4dd51b60a46f82203f5dc7005a264d Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Thu, 19 Sep 2024 02:33:34 +1200 Subject: [PATCH 04/50] Middleware SGX admin tooling (#199) * Added onboard method to HSM2DongleSGX * Added Platform abstraction to manage common platform parameters * Replaced protocol platform-specific configuration for text messages with Platform messages * Implemented SGX admin tool - Implemented main SGX admin tool entrypoint with onboard, unlock, pin change and public key gathering commands - Misc get_hsm function now accounts for current Platform to acquire a connection - Updated specific admin modules to account for difference between platforms for specific operations - Now setting Platform within Ledger admin tool * Updated build scripts to account for SGX manager and admin * Added and updated unit tests --- middleware/adm_ledger.py | 4 +- middleware/adm_sgx.py | 128 +++++++++++++++++ middleware/admin/changepin.py | 14 +- middleware/admin/misc.py | 10 +- middleware/admin/onboard.py | 17 ++- middleware/admin/pubkeys.py | 3 +- middleware/admin/unlock.py | 8 +- middleware/build/adm_sgx | 2 + middleware/build/all | 2 + middleware/comm/platform.py | 65 +++++++++ middleware/ledger/protocol.py | 12 +- middleware/manager_ledger.py | 10 +- middleware/manager_sgx.py | 10 +- middleware/manager_tcp.py | 11 +- middleware/mgr/runner.py | 5 +- middleware/sgx/hsm2dongle.py | 18 +++ middleware/tests/admin/test_adm_sgx.py | 171 +++++++++++++++++++++++ middleware/tests/admin/test_changepin.py | 19 ++- middleware/tests/admin/test_onboard.py | 51 ++++++- middleware/tests/admin/test_unlock.py | 2 + 20 files changed, 508 insertions(+), 54 deletions(-) create mode 100644 middleware/adm_sgx.py create mode 100755 middleware/build/adm_sgx create mode 100644 middleware/comm/platform.py create mode 100644 middleware/tests/admin/test_adm_sgx.py diff --git a/middleware/adm_ledger.py b/middleware/adm_ledger.py index 4865341b..da484038 100644 --- a/middleware/adm_ledger.py +++ b/middleware/adm_ledger.py @@ -24,6 +24,7 @@ from argparse import ArgumentParser import logging from ledger.hsm2dongle import HSM2DongleError +from comm.platform import Platform from admin.misc import not_implemented, info, AdminError from admin.unlock import do_unlock from admin.onboard import do_onboard @@ -33,8 +34,6 @@ from admin.verify_attestation import do_verify_attestation from admin.authorize_signer import do_authorize_signer -DEFAULT_PIN_FILE = "pin.txt" -DEFAULT_PIN_CHANGE_FILE = "changePIN" DEFAULT_ATT_UD_SOURCE = "https://public-node.rsk.co" @@ -144,6 +143,7 @@ def main(): try: options = parser.parse_args() + Platform.set(Platform.LEDGER) actions.get(options.operation, not_implemented)(options) sys.exit(0) except AdminError as e: diff --git a/middleware/adm_sgx.py b/middleware/adm_sgx.py new file mode 100644 index 00000000..6a4dcf0c --- /dev/null +++ b/middleware/adm_sgx.py @@ -0,0 +1,128 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys +from argparse import ArgumentParser +import logging +from ledger.hsm2dongle import HSM2DongleError +from comm.platform import Platform +from admin.misc import not_implemented, info, AdminError +from admin.unlock import do_unlock +from admin.onboard import do_onboard +from admin.pubkeys import do_get_pubkeys +from admin.changepin import do_changepin + + +def main(): + logging.disable(logging.CRITICAL) + + actions = { + "unlock": do_unlock, + "onboard": do_onboard, + "pubkeys": do_get_pubkeys, + "changepin": do_changepin, + } + + parser = ArgumentParser(description="SGX powHSM Administrative tool") + parser.add_argument("operation", choices=list(actions.keys())) + parser.add_argument( + "-r", + "--port", + dest="sgx_port", + help="SGX powHSM listening port (default 7777)", + type=int, + default=7777, + ) + parser.add_argument( + "-s", + "--host", + dest="sgx_host", + help="SGX powHSM host. (default 'localhost')", + default="localhost", + ) + parser.add_argument("-p", "--pin", dest="pin", help="PIN.") + parser.add_argument( + "-n", + "--newpin", + dest="new_pin", + help="New PIN (only valid for 'changepin' operation).", + ) + parser.add_argument( + "-a", + "--anypin", + dest="any_pin", + action="store_const", + help="Allow any pin (only valid for 'changepin' operation).", + default=False, + const=True, + ) + parser.add_argument( + "-o", + "--output", + dest="output_file_path", + help="Output file (only valid for 'onboard' and 'pubkeys' " + "operations).", + ) + parser.add_argument( + "-u", + "--nounlock", + dest="no_unlock", + action="store_const", + help="Do not attempt to unlock (only valid for 'changepin' and 'pubkeys' " + "operations).", + default=False, + const=True, + ) + parser.add_argument( + "-v", + "--verbose", + dest="verbose", + action="store_const", + help="Enable verbose mode", + default=False, + const=True, + ) + + try: + options = parser.parse_args() + Platform.set(Platform.SGX, { + "sgx_host": options.sgx_host, + "sgx_port": options.sgx_port, + }) + actions.get(options.operation, not_implemented)(options) + sys.exit(0) + except AdminError as e: + info(str(e)) + sys.exit(1) + except HSM2DongleError as e: + info(str(e)) + sys.exit(2) + except KeyboardInterrupt: + info("Interrupted by user!") + sys.exit(3) + except Exception as e: + info(str(e)) + sys.exit(4) + + +if __name__ == "__main__": + main() diff --git a/middleware/admin/changepin.py b/middleware/admin/changepin.py index 61be97c5..78ae4230 100644 --- a/middleware/admin/changepin.py +++ b/middleware/admin/changepin.py @@ -32,6 +32,7 @@ AdminError, ) from .unlock import do_unlock +from comm.platform import Platform def do_changepin(options): @@ -62,10 +63,10 @@ def do_changepin(options): mode = hsm.get_current_mode() info(f"Mode: {mode.name.capitalize()}") - # We can only change the pin while in bootloader mode - if mode != HSM2Dongle.MODE.BOOTLOADER: - raise AdminError("Device not in bootloader mode. Disconnect and re-connect the " - "ledger and try again") + # In Ledger, we can only change the pin while in bootloader mode + if Platform.is_ledger() and mode != HSM2Dongle.MODE.BOOTLOADER: + raise AdminError("Device not in bootloader mode. " + f"{Platform.message("restart").capitalize()} and try again") # Ask the user for a new pin if one has not been given if new_pin is None: @@ -76,6 +77,9 @@ def do_changepin(options): info("Changing pin... ", options.verbose) if not hsm.new_pin(new_pin): raise AdminError("Failed to change pin") - info("Pin changed. Please disconnect and re-connect the ledger.") + info("Pin changed.", nl=Platform.is_sgx()) + # We require a restart in Ledger only + if Platform.is_ledger(): + info(f" Please {Platform.message("restart")}.") dispose_hsm(hsm) diff --git a/middleware/admin/misc.py b/middleware/admin/misc.py index b0780aa5..c8dcd59b 100644 --- a/middleware/admin/misc.py +++ b/middleware/admin/misc.py @@ -24,9 +24,11 @@ import time from getpass import getpass from ledger.hsm2dongle import HSM2Dongle +from sgx.hsm2dongle import HSM2DongleSGX from ledger.pin import BasePin from .dongle_admin import DongleAdmin from .dongle_eth import DongleEth +from comm.platform import Platform PIN_ERROR_MESSAGE = ("Invalid pin given. It must be exactly 8 alphanumeric " "characters with at least one alphabetic character.") @@ -68,7 +70,13 @@ def not_implemented(options): def get_hsm(debug): info("Connecting to HSM... ", False) - hsm = HSM2Dongle(debug) + if Platform.is_ledger(): + hsm = HSM2Dongle(debug) + elif Platform.is_sgx(): + hsm = HSM2DongleSGX(Platform.options("sgx_host"), + Platform.options("sgx_port"), debug) + else: + raise AdminError("Platform not set or unknown platform") hsm.connect() info("OK") return hsm diff --git a/middleware/admin/onboard.py b/middleware/admin/onboard.py index f1a2df05..7eb480b9 100644 --- a/middleware/admin/onboard.py +++ b/middleware/admin/onboard.py @@ -39,6 +39,7 @@ from .dongle_admin import DongleAdmin from .unlock import do_unlock from .certificate import HSMCertificate, HSMCertificateElement +from comm.platform import Platform # TODO: this could perhaps be done with a different value. # Currently unused but necessary for the attestation setup process. @@ -50,8 +51,8 @@ def do_onboard(options): head("### -> Onboarding and attestation setup", fill="#") hsm = None - # Require an output file - if options.output_file_path is None: + # Ledger-only: require an output file + if Platform.is_ledger() and options.output_file_path is None: raise AdminError("No output file path given") # Validate pin (if given) @@ -71,8 +72,8 @@ def do_onboard(options): # Require bootloader mode for onboarding if mode != HSM2Dongle.MODE.BOOTLOADER: - raise AdminError("Device not in bootloader mode. Disconnect and re-connect the " - "ledger and try again") + raise AdminError("Device not in bootloader mode. " + f"{Platform.message("restart").capitalize()} and try again") # Echo check info("Sending echo... ", options.verbose) @@ -120,6 +121,14 @@ def do_onboard(options): dispose_hsm(hsm) + if Platform.is_sgx(): + head(["Onboarding done"]) + return + + if not Platform.is_ledger(): + raise AdminError("Unsupported platform") + + # **** Attestation setup is Ledger only (for now) **** head( [ "Onboarding done", diff --git a/middleware/admin/pubkeys.py b/middleware/admin/pubkeys.py index 38b42490..cb49d457 100644 --- a/middleware/admin/pubkeys.py +++ b/middleware/admin/pubkeys.py @@ -27,6 +27,7 @@ from .misc import info, get_hsm, dispose_hsm, AdminError, wait_for_reconnection from .unlock import do_unlock from comm.bip32 import BIP32Path +from comm.platform import Platform SIGNER_WAIT_TIME = 1 # second @@ -65,7 +66,7 @@ def do_get_pubkeys(options): # Modes for which we can't get the public keys if mode in [HSM2Dongle.MODE.UNKNOWN, HSM2Dongle.MODE.BOOTLOADER]: raise AdminError( - "Device not in app mode. Disconnect and re-connect the ledger and try again") + f"Device not in app mode. {Platform.message("restart").capitalize()}") # Gather public keys pubkeys = {} diff --git a/middleware/admin/unlock.py b/middleware/admin/unlock.py index 6c9c8e9a..61ca64cf 100644 --- a/middleware/admin/unlock.py +++ b/middleware/admin/unlock.py @@ -32,6 +32,7 @@ AdminError, ask_for_pin, ) +from comm.platform import Platform def do_unlock(options, exit=True, no_exec=False, label=True): @@ -65,8 +66,8 @@ def do_unlock(options, exit=True, no_exec=False, label=True): # Modes for which we can't unlock if mode == HSM2Dongle.MODE.UNKNOWN: - raise AdminError("Device mode unknown. Already unlocked? Otherwise disconnect " - "and re-connect the ledger and try again") + raise AdminError("Device mode unknown. Already unlocked? Otherwise " + f"{Platform.message("restart")} and try again") if mode == HSM2Dongle.MODE.SIGNER or mode == HSM2Dongle.MODE.UI_HEARTBEAT: raise AdminError("Device already unlocked") @@ -87,9 +88,10 @@ def do_unlock(options, exit=True, no_exec=False, label=True): raise AdminError("Unable to unlock: PIN mismatch") info("PIN accepted") + # **** Ledger only **** # Exit the bootloader, go into menu (or, if app is properly signed, into # the app) - if exit: + if Platform.is_ledger() and exit: autoexec = not (options.no_exec or no_exec) info(f"Exiting to menu/app (execute signer: {bls(autoexec)})... ", options.verbose) diff --git a/middleware/build/adm_sgx b/middleware/build/adm_sgx new file mode 100755 index 00000000..e8deba1b --- /dev/null +++ b/middleware/build/adm_sgx @@ -0,0 +1,2 @@ +#!/bin/bash +source $(dirname $0)/bld-docker adm_sgx diff --git a/middleware/build/all b/middleware/build/all index b54b0f87..baeb373d 100755 --- a/middleware/build/all +++ b/middleware/build/all @@ -6,8 +6,10 @@ BINDIR=$(realpath $BUILDDIR/../bin/) echo "Building all..." QUIET=1 $BUILDDIR/manager_ledger && \ +QUIET=1 $BUILDDIR/manager_sgx && \ QUIET=1 $BUILDDIR/manager_tcp && \ QUIET=1 $BUILDDIR/adm_ledger && \ +QUIET=1 $BUILDDIR/adm_sgx && \ QUIET=1 $BUILDDIR/lbutils && \ QUIET=1 $BUILDDIR/signapp && \ echo "" && sha256sum $BINDIR/*.tgz diff --git a/middleware/comm/platform.py b/middleware/comm/platform.py new file mode 100644 index 00000000..b161ac25 --- /dev/null +++ b/middleware/comm/platform.py @@ -0,0 +1,65 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +class Platform: + LEDGER = "Ledger" + SGX = "SGX" + X86 = "X86" + VALID_PLATFORMS = [LEDGER, SGX, X86] + + MESSAGES = { + LEDGER: { + "restart": "disconnect and re-connect the ledger nano", + }, + SGX: { + "restart": "restart the SGX powHSM", + }, + X86: { + "restart": "restart the TCPSigner", + } + } + + _platform = None + _options = None + + @classmethod + def set(klass, plf, options={}): + if plf not in klass.VALID_PLATFORMS: + raise RuntimeError("Invalid platform given") + klass._platform = plf + klass._options = options + + @classmethod + def is_ledger(klass): + return klass._platform == Platform.LEDGER + + @classmethod + def is_sgx(klass): + return klass._platform == Platform.SGX + + @classmethod + def options(klass, key): + return klass._options[key] + + @classmethod + def message(klass, key): + return klass.MESSAGES[klass._platform][key] diff --git a/middleware/ledger/protocol.py b/middleware/ledger/protocol.py index ec6976cf..4e6af5cc 100644 --- a/middleware/ledger/protocol.py +++ b/middleware/ledger/protocol.py @@ -22,6 +22,7 @@ import time from comm.protocol import HSM2Protocol, HSM2ProtocolError, HSM2ProtocolInterrupt +from comm.platform import Platform from ledger.hsm2dongle import ( HSM2Dongle, HSM2DongleBaseError, @@ -46,11 +47,6 @@ class HSM2ProtocolLedger(HSM2Protocol): # Required minimum number of pin retries available to proceed with unlocking MIN_AVAILABLE_RETRIES = 2 - # Default user messages - MESSAGES = { - "restart": "restart the powHSM" - } - def __init__(self, pin, dongle): super().__init__() self.hsm2dongle = dongle @@ -78,7 +74,7 @@ def initialize_device(self): self.logger.info( "Could not determine onboarded status. If unlocked, " + "please enter the signing app and rerun the manager. Otherwise," - + f"{self.MESSAGES["restart"]} and try again" + + f"{Platform.message("restart")} and try again" ) raise HSM2ProtocolInterrupt() @@ -201,12 +197,12 @@ def _handle_bootloader(self): raise Exception("Dongle reported fail to change pin. Pin invalid?") self.pin.commit_change() self.logger.info( - f"PIN changed. Please {self.MESSAGES["restart"]}" + f"PIN changed. Please {Platform.message("restart")}" ) except Exception as e: self.pin.abort_change() self.logger.error( - f"Error changing PIN: %s. Please {self.MESSAGES["restart"]} " + f"Error changing PIN: %s. Please {Platform.message("restart")} " "and try again", format(e), ) finally: diff --git a/middleware/manager_ledger.py b/middleware/manager_ledger.py index c88f3602..335cfdcf 100644 --- a/middleware/manager_ledger.py +++ b/middleware/manager_ledger.py @@ -25,6 +25,7 @@ from mgr.runner import ManagerRunner from ledger.pin import FileBasedPin from user.options import UserOptionParser +from comm.platform import Platform def load_pin(user_options): @@ -39,18 +40,13 @@ def load_pin(user_options): return pin -def configure_protocol_messages(protocol): - protocol.MESSAGES = { - "restart": "disconnect and reconnect the ledger nano", - } - - if __name__ == "__main__": + Platform.set(Platform.LEDGER) user_options = UserOptionParser("Start the powHSM manager for Ledger", with_pin=True).parse() runner = ManagerRunner("powHSM manager", lambda options: HSM2Dongle(options.io_debug), - load_pin, configure_protocol_messages) + load_pin) runner.run(user_options) diff --git a/middleware/manager_sgx.py b/middleware/manager_sgx.py index 9b443181..010f16ba 100644 --- a/middleware/manager_sgx.py +++ b/middleware/manager_sgx.py @@ -25,6 +25,7 @@ from mgr.runner import ManagerRunner from ledger.pin import FileBasedPin from user.options import UserOptionParser +from comm.platform import Platform def load_pin(user_options): @@ -39,13 +40,8 @@ def load_pin(user_options): return pin -def configure_protocol_messages(protocol): - protocol.MESSAGES = { - "restart": "restart the SGX powHSM", - } - - if __name__ == "__main__": + Platform.set(Platform.SGX) user_options = UserOptionParser("Start the powHSM manager for SGX", with_pin=True, with_tcpconn=True, @@ -56,6 +52,6 @@ def configure_protocol_messages(protocol): lambda options: HSM2DongleSGX(options.tcpconn_host, options.tcpconn_port, options.io_debug), - load_pin, configure_protocol_messages) + load_pin) runner.run(user_options) diff --git a/middleware/manager_tcp.py b/middleware/manager_tcp.py index de3d73db..11ce1e05 100644 --- a/middleware/manager_tcp.py +++ b/middleware/manager_tcp.py @@ -23,15 +23,11 @@ from ledger.hsm2dongle_tcp import HSM2DongleTCP from mgr.runner import ManagerRunner from user.options import UserOptionParser - - -def configure_protocol_messages(protocol): - protocol.MESSAGES = { - "restart": "restart the TCPSigner", - } +from comm.platform import Platform if __name__ == "__main__": + Platform.set(Platform.X86) user_options = UserOptionParser("Start the powHSM manager for TCPSigner", with_pin=False, with_tcpconn=True, @@ -41,7 +37,6 @@ def configure_protocol_messages(protocol): lambda options: HSM2DongleTCP(options.tcpconn_host, options.tcpconn_port, options.io_debug), - load_pin=lambda options: None, - configure_protocol=configure_protocol_messages) + load_pin=lambda options: None) runner.run(user_options) diff --git a/middleware/mgr/runner.py b/middleware/mgr/runner.py index 95647ca9..df65e535 100644 --- a/middleware/mgr/runner.py +++ b/middleware/mgr/runner.py @@ -29,11 +29,10 @@ class ManagerRunner: - def __init__(self, name, create_dongle, load_pin, configure_protocol=None): + def __init__(self, name, create_dongle, load_pin): self.name = name self.create_dongle = create_dongle self.load_pin = load_pin - self.configure_protocol = configure_protocol def run(self, user_options): configure_logging(user_options.logconfigfilepath) @@ -52,8 +51,6 @@ def run(self, user_options): else: logger.info("Using protocol version 2") protocol = HSM2ProtocolLedger(pin, dongle) - if self.configure_protocol: - self.configure_protocol(protocol) server = TCPServer(user_options.host, user_options.port, protocol) server.run() except PinError as e: diff --git a/middleware/sgx/hsm2dongle.py b/middleware/sgx/hsm2dongle.py index 4a463907..8e2d8bb8 100644 --- a/middleware/sgx/hsm2dongle.py +++ b/middleware/sgx/hsm2dongle.py @@ -21,10 +21,12 @@ # SOFTWARE. from enum import IntEnum +from ledger.hsm2dongle import HSM2DongleError from ledger.hsm2dongle_tcp import HSM2DongleTCP class SgxCommand(IntEnum): + SGX_ONBOARD = 0xA0, SGX_RETRIES = 0xA2, SGX_UNLOCK = 0xA3, SGX_ECHO = 0xA4, @@ -58,3 +60,19 @@ def new_pin(self, pin): def get_retries(self): apdu_rcv = self._send_command(SgxCommand.SGX_RETRIES) return apdu_rcv[2] + + # Attempt to onboard the device using the given seed and pin + def onboard(self, seed, pin): + if type(seed) != bytes or len(seed) != self.ONBOARDING.SEED_LENGTH: + raise HSM2DongleError("Invalid seed given") + + if type(pin) != bytes: + raise HSM2DongleError("Invalid pin given") + + self.logger.info("Sending onboard command") + response = self._send_command(SgxCommand.SGX_ONBOARD, bytes([0x0]) + seed + pin) + + if response[2] != 1: + raise HSM2DongleError("Error onboarding. Got '%s'" % response.hex()) + + return True diff --git a/middleware/tests/admin/test_adm_sgx.py b/middleware/tests/admin/test_adm_sgx.py new file mode 100644 index 00000000..d5a5f5cb --- /dev/null +++ b/middleware/tests/admin/test_adm_sgx.py @@ -0,0 +1,171 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys +from argparse import Namespace +from unittest import TestCase +from unittest.mock import call, patch +from adm_sgx import main +import logging + +logging.disable(logging.CRITICAL) + + +class TestAdmLedger(TestCase): + def setUp(self): + self.old_stdout = sys.stdout + self.DEFAULT_OPTIONS = { + "sgx_host": "localhost", + "sgx_port": 7777, + "any_pin": False, + "new_pin": None, + "no_unlock": False, + "operation": None, + "output_file_path": None, + "pin": None, + "verbose": False, + } + + def tearDown(self): + sys.stdout = self.old_stdout + + @patch("adm_sgx.do_unlock") + def test_unlock(self, do_unlock): + expected_options = { + **self.DEFAULT_OPTIONS, + 'operation': 'unlock', + 'pin': 'a-pin', + } + expected_call_args_list = [ + call(Namespace(**expected_options)), + call(Namespace(**expected_options)) + ] + + with patch('sys.argv', ['adm_sgx.py', '-p', 'a-pin', 'unlock']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + with patch('sys.argv', ['adm_sgx.py', '--pin', 'a-pin', 'unlock']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + self.assertTrue(do_unlock.called) + self.assertEqual(do_unlock.call_count, 2) + self.assertEqual(expected_call_args_list, do_unlock.call_args_list) + + @patch("adm_sgx.do_onboard") + def test_onboard(self, do_onboard): + expected_options = { + **self.DEFAULT_OPTIONS, + 'operation': 'onboard', + 'pin': 'a-pin', + } + + expected_call_args_list = [ + call(Namespace(**expected_options)), + call(Namespace(**expected_options)) + ] + + with patch('sys.argv', + ['adm_sgx.py', '-p', 'a-pin', 'onboard']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + with patch('sys.argv', + ['adm_sgx.py', '--pin', 'a-pin', 'onboard']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + self.assertTrue(do_onboard.called) + self.assertEqual(expected_call_args_list, do_onboard.call_args_list) + + @patch("adm_sgx.do_get_pubkeys") + def test_pubkeys(self, do_get_pubkeys): + expected_options = { + **self.DEFAULT_OPTIONS, + 'no_unlock': True, + 'operation': 'pubkeys', + 'output_file_path': 'a-path', + 'pin': 'a-pin', + 'sgx_host': '1.2.3.4', + } + + expected_call_args_list = [ + call(Namespace(**expected_options)), + call(Namespace(**expected_options)) + ] + + with patch('sys.argv', ['adm_sgx.py', '-p', 'a-pin', '-o', 'a-path', '-u', + '-s', '1.2.3.4', 'pubkeys']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + with patch('sys.argv', + ['adm_sgx.py', + '--host', '1.2.3.4', + '--pin', 'a-pin', + '--output', 'a-path', + '--nounlock', + 'pubkeys']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + self.assertTrue(do_get_pubkeys.called) + self.assertEqual(expected_call_args_list, do_get_pubkeys.call_args_list) + + @patch("adm_sgx.do_changepin") + def test_changepin(self, do_changepin): + expected_options = { + **self.DEFAULT_OPTIONS, + 'any_pin': True, + 'new_pin': 'new-pin', + 'operation': 'changepin', + 'pin': 'old-pin', + 'sgx_port': 4567, + } + expected_call_args_list = [ + call(Namespace(**expected_options)), + call(Namespace(**expected_options)) + ] + + with patch('sys.argv', ['adm_sgx.py', '-p', 'old-pin', '-n', 'new-pin', + '-r', '4567', '-a', 'changepin']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + with patch('sys.argv', ['adm_sgx.py', + '--newpin', 'new-pin', '--anypin', 'changepin', + '--port', '4567', '--pin', 'old-pin']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + self.assertTrue(do_changepin.called) + self.assertEqual(do_changepin.call_count, 2) + self.assertEqual(expected_call_args_list, do_changepin.call_args_list) diff --git a/middleware/tests/admin/test_changepin.py b/middleware/tests/admin/test_changepin.py index 033e5592..1d5dc24d 100644 --- a/middleware/tests/admin/test_changepin.py +++ b/middleware/tests/admin/test_changepin.py @@ -25,6 +25,7 @@ from unittest.mock import Mock, call, patch from admin.changepin import do_changepin from admin.misc import AdminError +from comm.platform import Platform from ledger.hsm2dongle import HSM2Dongle import logging @@ -48,6 +49,7 @@ def setUp(self): } self.default_options = SimpleNamespace(**options) self.dongle = Mock() + Platform.set(Platform.LEDGER) @patch("admin.changepin.do_unlock") def test_changepin(self, do_unlock_mock, get_hsm, _): @@ -77,7 +79,7 @@ def test_changepin_unlock_error(self, do_unlock_mock, get_hsm, _): self.assertEqual('Failed to unlock device: unlock-error', str(e.exception)) @patch("admin.changepin.do_unlock") - def test_changepin_invalid_mode(self, do_unlock_mock, get_hsm, _): + def test_changepin_invalid_mode_ledger(self, do_unlock_mock, get_hsm, _): get_hsm.return_value = self.dongle self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) self.dongle.is_onboarded = Mock(return_value=True) @@ -90,6 +92,21 @@ def test_changepin_invalid_mode(self, do_unlock_mock, get_hsm, _): self.assertTrue(str(e.exception).startswith('Device not in bootloader mode.')) self.assertFalse(self.dongle.new_pin.called) + @patch("admin.changepin.do_unlock") + def test_changepin_signer_mode_sgx(self, do_unlock_mock, get_hsm, _): + Platform.set(Platform.SGX) + get_hsm.return_value = self.dongle + self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) + self.dongle.is_onboarded = Mock(return_value=True) + self.dongle.new_pin = Mock(return_value=True) + + do_changepin(self.default_options) + + self.assertTrue(do_unlock_mock.called) + self.assertTrue(self.dongle.new_pin.called) + self.assertEqual([call(self.VALID_PIN.encode())], + self.dongle.new_pin.call_args_list) + def test_changepin_invalid_pin(self, get_hsm, _): get_hsm.return_value = self.dongle diff --git a/middleware/tests/admin/test_onboard.py b/middleware/tests/admin/test_onboard.py index 0f9abd23..c7ab698b 100644 --- a/middleware/tests/admin/test_onboard.py +++ b/middleware/tests/admin/test_onboard.py @@ -25,6 +25,7 @@ from unittest.mock import Mock, call, patch, mock_open from admin.certificate import HSMCertificate, HSMCertificateElement from admin.misc import AdminError +from comm.platform import Platform from admin.onboard import do_onboard import json from ledger.hsm2dongle import HSM2Dongle, HSM2DongleError @@ -62,6 +63,7 @@ class TestOnboard(TestCase): } def setUp(self): + Platform.set(Platform.LEDGER) self.certificate_path = "cert-path" options = { "pin": self.VALID_PIN, @@ -95,8 +97,8 @@ def setUp(self): @patch("admin.onboard.get_admin_hsm") @patch("admin.unlock.get_hsm") @patch("sys.stdin.readline") - def test_onboard(self, readline, get_hsm_unlock, get_admin_hsm, - get_hsm_onboard, info_mock, *_): + def test_onboard_ledger(self, readline, get_hsm_unlock, get_admin_hsm, + get_hsm_onboard, info_mock, *_): get_hsm_onboard.return_value = self.dongle get_hsm_unlock.return_value = self.dongle get_admin_hsm.return_value = self.dongle @@ -125,6 +127,32 @@ def test_onboard(self, readline, get_hsm_unlock, get_admin_hsm, self.assertTrue(self.dongle.onboard.called) self.assertTrue(self.dongle.handshake.called) + @patch("admin.onboard.get_admin_hsm") + @patch("admin.unlock.get_hsm") + @patch("sys.stdin.readline") + def test_onboard_sgx(self, readline, get_hsm_unlock, get_admin_hsm, + get_hsm_onboard, info_mock, *_): + Platform.set(Platform.SGX) + + get_hsm_onboard.return_value = self.dongle + get_hsm_unlock.return_value = self.dongle + + self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.BOOTLOADER) + self.dongle.is_onboarded = Mock(side_effect=[False, True]) + self.dongle.onboard = Mock() + readline.return_value = "yes\n" + + with patch("builtins.open", mock_open()): + do_onboard(self.default_options) + + self.assertEqual(info_mock.call_args_list[5][0][0], "Onboarded: No") + self.assertEqual(info_mock.call_args_list[10][0][0], "Onboarded") + + self.assertTrue(self.dongle.onboard.called) + self.assertFalse(self.dongle.get_device_key.called) + self.assertFalse(self.dongle.setup_endorsement_key.called) + self.assertFalse(self.dongle.handshake.called) + @patch("admin.onboard.get_admin_hsm") @patch("admin.unlock.get_hsm") @patch("sys.stdin.readline") @@ -280,7 +308,7 @@ def test_onboard_user_cancelled(self, readline, hsm_unlock, hsm_admin, self.assertFalse(file_mock.return_value.write.called) @patch("sys.stdin.readline") - def test_onboard_no_output_file(self, readline, get_hsm, *_): + def test_onboard_no_output_file_ledger(self, readline, get_hsm, *_): readline.return_value = "yes\n" get_hsm.return_value = self.dongle @@ -296,6 +324,23 @@ def test_onboard_no_output_file(self, readline, get_hsm, *_): self.assertEqual("No output file path given", str(e.exception)) self.assertFalse(self.dongle.onboard.called) + @patch("sys.stdin.readline") + def test_onboard_no_output_file_sgx(self, readline, get_hsm, *_): + Platform.set(Platform.SGX) + readline.return_value = "yes\n" + get_hsm.return_value = self.dongle + + self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.BOOTLOADER) + self.dongle.is_onboarded = Mock(return_value=False) + self.dongle.onboard = Mock() + + options = self.default_options + options.output_file_path = None + + do_onboard(options) + + self.assertTrue(self.dongle.onboard.called) + def test_onboard_invalid_pin(self, *_): options = self.default_options options.pin = self.INVALID_PIN diff --git a/middleware/tests/admin/test_unlock.py b/middleware/tests/admin/test_unlock.py index f90cfa31..153500cf 100644 --- a/middleware/tests/admin/test_unlock.py +++ b/middleware/tests/admin/test_unlock.py @@ -24,6 +24,7 @@ from unittest import TestCase from unittest.mock import Mock, call, patch from admin.misc import AdminError +from comm.platform import Platform from admin.unlock import do_unlock from ledger.hsm2dongle import HSM2Dongle from parameterized import parameterized @@ -37,6 +38,7 @@ @patch("admin.unlock.get_hsm") class TestUnlock(TestCase): def setUp(self): + Platform.set(Platform.LEDGER) self.valid_pin = '1234ABCD' self.invalid_pin = '123456789' From 07859f71799a0456314be6162e20efcd9f1eced6 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Thu, 26 Sep 2024 00:02:45 +1200 Subject: [PATCH 05/50] SGX distribution scripts (#201) - Moved dist to dist/ledger - Added dist/sgx with setup and run scripts - New SGX distribution building script (build-dist-sgx) - Added and updated distribution documentation for both Leger and SGX - Additional HSM2DongleSGX unit tests for the onboarding operation --- build-dist-ledger | 2 +- build-dist-sgx | 58 ++++++++ dist/{ => ledger}/.gitignore | 1 + dist/{ => ledger}/Dockerfile | 0 dist/{ => ledger}/README-cli.md | 2 +- dist/{ => ledger}/README.md | 8 +- dist/{ => ledger}/scripts/run_with_docker | 2 +- dist/{ => ledger}/scripts/setup | 2 +- dist/{ => ledger}/scripts/target.id | 0 dist/{ => ledger}/scripts/upgrade-existing | 2 +- dist/{ => ledger}/setup-new-device | 0 dist/{ => ledger}/upgrade-existing-device | 0 dist/sgx/.gitignore | 3 + dist/sgx/Dockerfile | 17 +++ dist/sgx/README-cli.md | 17 +++ dist/sgx/README.md | 41 ++++++ dist/sgx/hsm/run | 27 ++++ dist/sgx/scripts/run_with_docker | 24 ++++ dist/sgx/scripts/setup | 157 +++++++++++++++++++++ dist/sgx/setup-new-powhsm | 3 + middleware/build/dist_sgx | 12 ++ middleware/tests/sgx/test_hsm2dongle.py | 51 +++++++ 22 files changed, 420 insertions(+), 9 deletions(-) create mode 100755 build-dist-sgx rename dist/{ => ledger}/.gitignore (93%) rename dist/{ => ledger}/Dockerfile (100%) rename dist/{ => ledger}/README-cli.md (94%) rename dist/{ => ledger}/README.md (88%) rename dist/{ => ledger}/scripts/run_with_docker (94%) rename dist/{ => ledger}/scripts/setup (98%) rename dist/{ => ledger}/scripts/target.id (100%) rename dist/{ => ledger}/scripts/upgrade-existing (98%) rename dist/{ => ledger}/setup-new-device (100%) rename dist/{ => ledger}/upgrade-existing-device (100%) create mode 100644 dist/sgx/.gitignore create mode 100644 dist/sgx/Dockerfile create mode 100644 dist/sgx/README-cli.md create mode 100644 dist/sgx/README.md create mode 100755 dist/sgx/hsm/run create mode 100755 dist/sgx/scripts/run_with_docker create mode 100755 dist/sgx/scripts/setup create mode 100755 dist/sgx/setup-new-powhsm create mode 100755 middleware/build/dist_sgx diff --git a/build-dist-ledger b/build-dist-ledger index ed487a8e..c62d0297 100755 --- a/build-dist-ledger +++ b/build-dist-ledger @@ -34,7 +34,7 @@ fi echo -e "\e[32mBuilding into \e[93m$DEST_DIR\e[32m with checkpoint \e[93m$CHECKPOINT\e[32m, minimum difficulty \e[93m$DIFFICULTY\e[32m, network \e[93m$NETWORK\e[32m and UI iteration \e[93m$UI_ITERATION\e[32m...\e[0m" echo -e "\e[33mCopying files and creating directories...\e[0m" rm -rf $DEST_DIR -cp -Rf $ROOT_DIR/dist $DEST_DIR +cp -Rf $ROOT_DIR/dist/ledger $DEST_DIR rm -rf $FIRMWARE_DIR mkdir -p $FIRMWARE_DIR diff --git a/build-dist-sgx b/build-dist-sgx new file mode 100755 index 00000000..31052197 --- /dev/null +++ b/build-dist-sgx @@ -0,0 +1,58 @@ +#!/bin/bash + +pushd $(dirname $0) > /dev/null +ROOT_DIR=$(pwd) + +if [[ $# -lt 4 ]]; then + echo "Usage: $0 " + exit 1 +fi + +# Check docker images exist +CHECK_IMAGE=$ROOT_DIR/docker/check-image + +for img in hsm:sgx hsm:mware hsm:packer; do + DOCKER_IMAGE=$img + source $CHECK_IMAGE +done + +DEST_DIR=$1 +CHECKPOINT=$2 +DIFFICULTY=$3 +NETWORK=$4 +HSM_DIR=$DEST_DIR/hsm +BIN_DIR=$DEST_DIR/bin +SCRIPTS_DIR=$DEST_DIR/scripts + +if [[ -e $DEST_DIR ]]; then + echo -e "\e[31mDestination directory $DEST_DIR exists" + exit 1 +fi + +echo -e "\e[32mBuilding into \e[93m$DEST_DIR\e[32m with checkpoint \e[93m$CHECKPOINT\e[32m, minimum difficulty \e[93m$DIFFICULTY\e[32m, network \e[93m$NETWORK\e[32m and UI iteration \e[93m$UI_ITERATION\e[32m...\e[0m" +echo -e "\e[33mCopying files and creating directories...\e[0m" +rm -rf $DEST_DIR +cp -Rf $ROOT_DIR/dist/sgx $DEST_DIR + +rm -rf $BIN_DIR +mkdir -p $BIN_DIR + +echo +echo -e "\e[33mBuilding middleware...\e[0m" +$ROOT_DIR/middleware/build/dist_sgx +cp $ROOT_DIR/middleware/bin/adm_sgx.tgz $BIN_DIR +cp $ROOT_DIR/middleware/bin/manager_sgx.tgz $BIN_DIR +echo + +echo -e "\e[33mBuilding SGX apps...\e[0m" +# TODO: decide what to do with the enclave signing key +#(randomizing seems like a reasonable option +# since we don't actually need it in our current scheme) +$ROOT_DIR/firmware/build/build-sgx $CHECKPOINT $DIFFICULTY $NETWORK > /dev/null +cp $ROOT_DIR/firmware/src/sgx/bin/hsmsgx $HSM_DIR/ +cp $ROOT_DIR/firmware/src/sgx/bin/hsmsgx_enclave.signed $HSM_DIR/ + +echo +echo -e "\e[32mBuild complete.\e[0m" + +popd > /dev/null diff --git a/dist/.gitignore b/dist/ledger/.gitignore similarity index 93% rename from dist/.gitignore rename to dist/ledger/.gitignore index 7ecf1847..685f5b90 100644 --- a/dist/.gitignore +++ b/dist/ledger/.gitignore @@ -1,5 +1,6 @@ bin firmware +export public-keys.txt public-keys.json pin.txt diff --git a/dist/Dockerfile b/dist/ledger/Dockerfile similarity index 100% rename from dist/Dockerfile rename to dist/ledger/Dockerfile diff --git a/dist/README-cli.md b/dist/ledger/README-cli.md similarity index 94% rename from dist/README-cli.md rename to dist/ledger/README-cli.md index 171126f8..95e2bffb 100644 --- a/dist/README-cli.md +++ b/dist/ledger/README-cli.md @@ -1,4 +1,4 @@ -# powHSM Setup and onboarding +# powHSM for Ledger Nano S Setup and onboarding ## Prerequisites diff --git a/dist/README.md b/dist/ledger/README.md similarity index 88% rename from dist/README.md rename to dist/ledger/README.md index f970ceea..4bd9e5f6 100644 --- a/dist/README.md +++ b/dist/ledger/README.md @@ -1,17 +1,17 @@ -# powHSM distribution +# powHSM for Ledger Nano S distribution This document describes the artifacts provided to build a distributable version of the powHSM software for Ledger Nano S. This distributable version includes both Ledger apps and middleware binaries, as well as scripts for both setting up and onboarding a brand new Ledger Nano S; and also for upgrading an existing Ledger Nano S with powHSM to a newer Signer version. ## Prerequisites -You will need all of the docker images built (see the [quickstart guide](../QUICKSTART.md) for details on this). +You will need all of the docker images built (see the [quickstart guide](../../QUICKSTART.md) for details on this). ## Generating a distribution To generate a full distribution into a fresh directory, issue: ``` -~/repo> ./build-dist +~/repo> ./build-dist-ledger ``` where `` is the target directory (which must not exist); ``, `` and `` are the build parameters for the signer app; `` is the signer version iteration with which the UI must be built; and `` is the basename of the authorizers header file. The script will build the Ledger apps (signer and UI) as well as the required middleware. Then it will output all of the necessary distribution artifacts, including the aforementioned builds, to the destination path given. @@ -19,7 +19,7 @@ where `` is the target directory (which must not exist); ` ./build-dist /path/to/output 0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac 0x7c50933098 testnet 43 testing +~/repo> ./build-dist-ledger /path/to/output 0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac 0x7c50933098 testnet 43 testing ``` ## Using a distribution diff --git a/dist/scripts/run_with_docker b/dist/ledger/scripts/run_with_docker similarity index 94% rename from dist/scripts/run_with_docker rename to dist/ledger/scripts/run_with_docker index 446803b5..c7fab848 100755 --- a/dist/scripts/run_with_docker +++ b/dist/ledger/scripts/run_with_docker @@ -3,7 +3,7 @@ pushd $(dirname $0)/.. > /dev/null DIST_DIR=$(pwd) popd > /dev/null -DOCKER_IMAGE=hsm2:setup +DOCKER_IMAGE=powhsmledger:setup QUIET="" echo -e "\e[96mBuilding docker image $DOCKER_IMAGE (this will take a few minutes)..." diff --git a/dist/scripts/setup b/dist/ledger/scripts/setup similarity index 98% rename from dist/scripts/setup rename to dist/ledger/scripts/setup index 7d91a3d0..2f0fa29c 100755 --- a/dist/scripts/setup +++ b/dist/ledger/scripts/setup @@ -160,7 +160,7 @@ function verify_attestation() { error } -echo -e "\e[1;32mWelcome to the powHSM Setup for RSK \e[0m" +echo -e "\e[1;32mWelcome to the Ledger Nano S powHSM Setup for RSK \e[0m" echo checkForPinFile checkFirmware diff --git a/dist/scripts/target.id b/dist/ledger/scripts/target.id similarity index 100% rename from dist/scripts/target.id rename to dist/ledger/scripts/target.id diff --git a/dist/scripts/upgrade-existing b/dist/ledger/scripts/upgrade-existing similarity index 98% rename from dist/scripts/upgrade-existing rename to dist/ledger/scripts/upgrade-existing index 5e1c33c2..7e8bd339 100755 --- a/dist/scripts/upgrade-existing +++ b/dist/ledger/scripts/upgrade-existing @@ -134,7 +134,7 @@ function verify_attestation() { error } -echo -e "\e[1;32mWelcome to the powHSM Upgrade for RSK \e[0m" +echo -e "\e[1;32mWelcome to the Ledger Nano S powHSM Upgrade for RSK \e[0m" echo -e "\e[1;32mPlease make sure your HSM is onboarded before continuing with the firmware upgrade.\e[0m" echo checkFirmware diff --git a/dist/setup-new-device b/dist/ledger/setup-new-device similarity index 100% rename from dist/setup-new-device rename to dist/ledger/setup-new-device diff --git a/dist/upgrade-existing-device b/dist/ledger/upgrade-existing-device similarity index 100% rename from dist/upgrade-existing-device rename to dist/ledger/upgrade-existing-device diff --git a/dist/sgx/.gitignore b/dist/sgx/.gitignore new file mode 100644 index 00000000..0c8fd78d --- /dev/null +++ b/dist/sgx/.gitignore @@ -0,0 +1,3 @@ +bin +export +hsm/hsmsgx* diff --git a/dist/sgx/Dockerfile b/dist/sgx/Dockerfile new file mode 100644 index 00000000..1805e567 --- /dev/null +++ b/dist/sgx/Dockerfile @@ -0,0 +1,17 @@ +FROM debian:bookworm-slim + +WORKDIR /hsm2 + +RUN apt-get update && \ + apt-get install -y binutils gnupg2 curl + +# Download and install libssl1.1 from debian main repository +RUN curl -L -o libssl1.1.deb https://ftp.debian.org/debian/pool/main/o/openssl/libssl1.1_1.1.1w-0+deb11u1_amd64.deb && \ + dpkg -i libssl1.1.deb && \ + rm libssl1.1.deb + +# Install SGX runtime dependencies +RUN echo 'deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main' | tee /etc/apt/sources.list.d/intel-sgx.list && \ + curl -fsSL https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | apt-key add - && \ + apt-get update && \ + apt-get install -y libsgx-enclave-common diff --git a/dist/sgx/README-cli.md b/dist/sgx/README-cli.md new file mode 100644 index 00000000..4d7cdf4d --- /dev/null +++ b/dist/sgx/README-cli.md @@ -0,0 +1,17 @@ +# powHSM for SGX Setup and onboarding + +## Prerequisites + +The computer on which the powHSM setup and onboarding is to be executed needs the following installed: + +- Docker + +### Setup + +To setup a brand new powHSM, within the `/path/to/dist` directory, issue: + +``` +/path/to/dist> ./setup-new-powhsm +``` + +and follow the instructions. diff --git a/dist/sgx/README.md b/dist/sgx/README.md new file mode 100644 index 00000000..14e18af6 --- /dev/null +++ b/dist/sgx/README.md @@ -0,0 +1,41 @@ +# powHSM for SGX distribution + +This document describes the artifacts provided to build a distributable version of the powHSM software for Intel SGX. This distributable version includes both SGX apps and middleware binaries, as well as scripts for setting up and onboarding a brand new installation. + +## Prerequisites + +You will need all of the docker images built (see the [quickstart guide](../QUICKSTART.md) for details on this). + +## Generating a distribution + +To generate a full distribution into a fresh directory, issue: + +``` +~/repo> ./build-dist-sgx +``` + +where `` is the target directory (which must not exist); ``, `` and `` are the build parameters for the SGX enclave application. The script will build the SGX apps (host and enclave) as well as the required middleware. Then it will output all of the necessary distribution artifacts, including the aforementioned builds, to the destination path given. + +For example, to build a distribution with checkpoint `0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac`, minimum cumulative difficulty of `0x7c50933098` and `testnet` network, issue: + +``` +~/repo> ./build-dist-sgx /path/to/output 0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac 0x7c50933098 testnet +``` + +## Using a distribution + +### Prerequisites + +The computer on which the distrbution is to be used needs the following installed: + +- Docker + +### Scripts + +As mentioned, a distribution can be used to setup a new device. To setup a brand new installation, within the `/path/to/dist` directory, issue: + +``` +/path/to/dist> ./setup-new-powhsm +``` + +and follow the instructions. diff --git a/dist/sgx/hsm/run b/dist/sgx/hsm/run new file mode 100755 index 00000000..44d972af --- /dev/null +++ b/dist/sgx/hsm/run @@ -0,0 +1,27 @@ +#!/bin/bash + +BINDIR=$(realpath $(dirname $0)) +WORKDIR=$(realpath $BINDIR/..) +DOCKER_IMAGE=powhsmsgx:runner + +QUIET="" +echo -e "\e[96mBuilding docker image $DOCKER_IMAGE (this will take a few minutes)..." +if [[ "$2" != "-v" ]]; then + QUIET="-q" + echo -e "Run with '-v' if you want to see progress detail\e[94m" +fi +docker build -t $DOCKER_IMAGE $BINDIR $QUIET +echo -e "\e[96mDocker image build done.\e[0m" +echo + +DOCKER_CNT=powhsmsgx-runner +DOCKER_USER="$(id -u):$(id -g)" +PORT=7777 +DOCKER_PORT="$PORT:$PORT" + +docker run -ti --rm --name $DOCKER_CNT --user $DOCKER_USER -v $WORKDIR:/hsm \ + --device=/dev/sgx_enclave:/dev/sgx_enclave \ + --device=/dev/sgx_provision:/dev/sgx_provision \ + -w /hsm -p$DOCKER_PORT $DOCKER_IMAGE \ + bin/hsmsgx ./bin/hsmsgx_enclave.signed -p$PORT -b0.0.0.0 + # TODO: We need to resolve binding so that not everyone can connect to the service! diff --git a/dist/sgx/scripts/run_with_docker b/dist/sgx/scripts/run_with_docker new file mode 100755 index 00000000..d0eeb75f --- /dev/null +++ b/dist/sgx/scripts/run_with_docker @@ -0,0 +1,24 @@ +#!/bin/bash + +pushd $(dirname $0)/.. > /dev/null +DIST_DIR=$(pwd) +popd > /dev/null +DOCKER_IMAGE=powhsmsgx:setup + +QUIET="" +echo -e "\e[96mBuilding docker image $DOCKER_IMAGE (this will take a few minutes)..." +if [[ "$2" != "-v" ]]; then + QUIET="-q" + echo -e "Run with '-v' if you want to see progress detail\e[94m" +fi +docker build -t $DOCKER_IMAGE $DIST_DIR $QUIET +echo -e "\e[96mDocker image build done.\e[0m" +echo + +DOCKER_USER="$(id -u):$(id -g)" + +docker run -ti --rm --user $DOCKER_USER \ + --device=/dev/sgx_enclave:/dev/sgx_enclave \ + --device=/dev/sgx_provision:/dev/sgx_provision \ + -v $DIST_DIR:/setup -v /:/fs -w /setup \ + $DOCKER_IMAGE $1 diff --git a/dist/sgx/scripts/setup b/dist/sgx/scripts/setup new file mode 100755 index 00000000..b118e26f --- /dev/null +++ b/dist/sgx/scripts/setup @@ -0,0 +1,157 @@ +#!/bin/bash + +pushd $(dirname $0)/.. > /dev/null +ROOT_DIR="$(pwd)" +popd > /dev/null + +# HSM binaries directory +HSMBIN_DIR=$ROOT_DIR/hsm + +# HSM binaries +HSMSGX_BINARY=hsmsgx +HSMSGX_ENCLAVE_BINARY=hsmsgx_enclave.signed + +# Middleware binaries +ADMIN_DIR="$ROOT_DIR/bin/adm_sgx" +ADMIN_BUNDLE="$ADMIN_DIR.tgz" +ADMIN="$ADMIN_DIR/adm_sgx" + +function cleanBinaries() { + rm -rf $ADMIN_DIR +} + +function expandBinaries() { + cleanBinaries + + mkdir -p $ADMIN_DIR + tar -xzmf $ADMIN_BUNDLE -C $ADMIN_DIR +} + +# Potentially existing file with an existing pin +PIN_FILE="$ROOT_DIR/pin.txt" + +# Directory where public keys will be saved after onboarding is done +EXPORT_DIR="$ROOT_DIR/export" +PUBLIC_KEY_FILE="$EXPORT_DIR/public-keys.txt" +PUBLIC_KEY_FILE_JSON="$EXPORT_DIR/public-keys.json" + +function checkHsmBinaries() { + # Check for HSM binary files + FILES="$HSMBIN_DIR/hsmsgx $HSMBIN_DIR/hsmsgx_enclave.signed" + for f in ${FILES}; do + if [[ ! -e $f ]]; then + echo -e "\e[1;31m HSM binary file '$(basename $f)' does not exist. \e[0m" + cleanBinaries + exit 1 + fi + done +} + +function error() { + if [ $? -ne 0 ]; then + echo -e "\e[1;31m Error comunicating with the dongle. Please check connection and restart the process. \e[0m" + cleanBinaries + exit 1 + fi +} + +function checkForPinFile() { + if [[ -e $PIN_FILE ]]; then + echo -e "\e[1;31m Legacy pin file '$(basename $PIN_FILE)' found. Please backup and remove before continuing. \e[0m" + cleanBinaries + exit 1 + fi +} + +function selectInstallationDir() { + while true; do + echo -e "\e[1;32mEnter the absolute path to the installation directory (empty directory name to abort)\e[0m" + while true; do + read -p "> " INSTALL_DIR + if [[ "$INSTALL_DIR" == "" ]]; then + echo -e "\e[1;31mAborted.\e[0m" + exit 1 + fi + REAL_INSTALL_DIR=$(realpath /fs/$INSTALL_DIR) + INSTALL_DIR=/$(realpath $REAL_INSTALL_DIR --relative-to=/fs/) + + if [ -d "$REAL_INSTALL_DIR" ]; then + echo -e "\e[1;31mDirectory exists: $INSTALL_DIR. Try again or enter empty directory name to abort.\e[0m" + else + if ! mkdir "$REAL_INSTALL_DIR"; then + echo -e "\e[1;31mCould not create directory: $INSTALL_DIR. Try again or enter empty directory name to abort.\e[0m" + else + echo -e "\e[1;33mpowHSM will be installed to $INSTALL_DIR\e[0m" + break + fi + fi + done + echo -e "\e[1;32mProceed? [Y/N]\e[0m" + read -p "> " proceed + if [[ "Y" == "$proceed" ]] || [[ "y" == "$proceed" ]]; then + break; + else + rmdir $REAL_INSTALL_DIR + fi + done +} + +function installPowHsm() { + mkdir $REAL_INSTALL_DIR/bin + cp -R $HSMBIN_DIR/* $REAL_INSTALL_DIR/bin + cp -R $ROOT_DIR/Dockerfile $REAL_INSTALL_DIR/bin +} + +function startPowHsm() { + pushd $REAL_INSTALL_DIR > /dev/null + bin/$HSMSGX_BINARY bin/$HSMSGX_ENCLAVE_BINARY > /dev/null 2> /dev/null & + HSMSGX_PID=$! + popd > /dev/null +} + +function stopPowHsm() { + kill $HSMSGX_PID +} + +function createOutputDir() { + rm -rf $EXPORT_DIR + mkdir -p $EXPORT_DIR +} + +function onboard() { + $ADMIN onboard + error +} + +function keys() { + $ADMIN pubkeys -o $PUBLIC_KEY_FILE + error +} + + +echo -e "\e[1;32mWelcome to the SGX powHSM Setup for RSK \e[0m" +checkForPinFile +checkHsmBinaries +expandBinaries +selectInstallationDir +echo +echo -e "\e[1;32mInstalling the powHSM...\e[0m" +installPowHsm +echo +echo -e "\e[1;32mStarting the powHSM...\e[0m" +startPowHsm +echo +echo -e "\e[1;33mOnboarding the powHSM... \e[0m" +onboard +echo -e "\e[1;33mOnboarding complete.\e[0m" +echo +echo -e "\e[1;32mGathering public keys\e[0m" +createOutputDir +keys +echo +echo -e "\e[1;32mStopping the powHSM...\e[0m" +stopPowHsm +cleanBinaries +echo +echo -e "\e[1;32mpowHSM Setup complete. Find the installation in $INSTALL_DIR.\e[0m" +exit 0 diff --git a/dist/sgx/setup-new-powhsm b/dist/sgx/setup-new-powhsm new file mode 100755 index 00000000..1398782a --- /dev/null +++ b/dist/sgx/setup-new-powhsm @@ -0,0 +1,3 @@ +#!/bin/bash + +$(dirname $0)/scripts/run_with_docker ./scripts/setup $1 diff --git a/middleware/build/dist_sgx b/middleware/build/dist_sgx new file mode 100755 index 00000000..a2b6c432 --- /dev/null +++ b/middleware/build/dist_sgx @@ -0,0 +1,12 @@ +#!/bin/bash + +BUILDDIR=$(dirname $0) +BINDIR=$(realpath $BUILDDIR/../bin/) + +echo "Building SGX distribution binaries..." + +QUIET=1 $BUILDDIR/manager_sgx && \ +QUIET=1 $BUILDDIR/adm_sgx && \ +echo "" && \ +sha256sum $BINDIR/manager_sgx.tgz && \ +sha256sum $BINDIR/adm_sgx.tgz diff --git a/middleware/tests/sgx/test_hsm2dongle.py b/middleware/tests/sgx/test_hsm2dongle.py index b3a48ba4..81a5779d 100644 --- a/middleware/tests/sgx/test_hsm2dongle.py +++ b/middleware/tests/sgx/test_hsm2dongle.py @@ -88,3 +88,54 @@ def test_get_retries(self): self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x05, 0xDD]) self.assertEqual(5, self.hsm2dongle.get_retries()) self.assert_exchange_called(bytes([0x80, 0xA2])) + + def test_onboard_ok(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01]) + self.assertTrue(self.hsm2dongle.onboard(bytes.fromhex("aa"*32), b"12345678")) + self.assert_exchange_called(bytes([0x80, 0xA0, 0x00]) + + bytes.fromhex("aa"*32) + + b"12345678") + + def test_onboard_seed_invalid_type(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01]) + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(1234, b"12345678") + + self.assertFalse(self.dongle.exchange.called) + + def test_onboard_seed_invalid_length(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01]) + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(b"abcd", b"12345678") + + self.assertFalse(self.dongle.exchange.called) + + def test_onboard_pin_invalid_type(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01]) + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(bytes.fromhex("aa"*32), 4444) + + self.assertFalse(self.dongle.exchange.called) + + def test_onboard_error_result(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0xCC]) + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(bytes.fromhex("aa"*32), b'12345678') + + self.assert_exchange_called(bytes([0x80, 0xA0, 0x00]) + + bytes.fromhex("aa"*32) + + b"12345678") + + def test_onboard_error_xchg(self): + self.dongle.exchange.side_effect = RuntimeError("SomethingWentWrong") + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(bytes.fromhex("aa"*32), b'12345678') + + self.assert_exchange_called(bytes([0x80, 0xA0, 0x00]) + + bytes.fromhex("aa"*32) + + b"12345678") From 55a0f1da0f8e07c9bccee1afa0937842fae04eb9 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 2 Oct 2024 06:23:16 +1300 Subject: [PATCH 06/50] SGX integration tests - Added integration tests for SGX simulator to the testing workflow - Bumped integration tests version to 5.3.0.plus --- .github/workflows/run-tests.yml | 57 +++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index e9067073..70737d2d 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -41,8 +41,8 @@ jobs: - name: Ledger Signer's unit tests run: firmware/src/ledger/signer/test/run-all.sh - run-integration-tests: - name: Integration tests + run-integration-tests-tcpsigner: + name: Integration tests for TCPSigner runs-on: ubuntu-20.04 steps: @@ -63,7 +63,7 @@ jobs: uses: actions/checkout@v3 with: repository: rootstock/hsm-integration-test - ref: 5.1.0.plus + ref: 5.3.0.plus path: hsm-integration-test ssh-key: ${{ secrets.HSM_INTEGRATION_TEST_SSH_KEY }} @@ -78,3 +78,54 @@ jobs: - name: Run HSM integration tests working-directory: hsm-integration-test run: sh smoke-test.sh + + run-integration-tests-sgx: + name: Integration tests for SGX simulator + runs-on: ubuntu-20.04 + + steps: + - name: Checkout rsk-powhsm repo + uses: actions/checkout@v3 + with: + path: rsk-powhsm + + - name: Build required software + working-directory: rsk-powhsm + run: | + docker/mware/build + docker/packer/build + docker/sgx/build + middleware/build/manager_sgx + docker/sgx/do-notty /hsm2/firmware/src/sgx "make generate-private-key" + firmware/build/build-sgx-sim \ + 0xe108960a242ad7bd45c21aff9c7ed9c516789e9cffacdd895502727d8f460d2c \ + 0x6E regtest + + - name: Checkout hsm-integration-test repo + uses: actions/checkout@v3 + with: + repository: rootstock/hsm-integration-test + ref: 5.3.0.plus + path: hsm-integration-test + ssh-key: ${{ secrets.HSM_INTEGRATION_TEST_SSH_KEY }} + + - name: Copy required files + run: | + mkdir hsm-integration-test/docker/manager/manager_sgx + tar -xzf rsk-powhsm/middleware/bin/manager_sgx.tgz \ + -C hsm-integration-test/docker/manager/manager_sgx + cp rsk-powhsm/firmware/src/sgx/bin/hsmsgx \ + hsm-integration-test/docker/sgx + cp rsk-powhsm/firmware/src/sgx/bin/hsmsgx_enclave.signed \ + hsm-integration-test/docker/sgx + echo abcd1234 > hsm-integration-test/docker/manager/pin.txt + echo -n abcd1234 > hsm-integration-test/docker/sgx/kvstore-password.dat + echo -en "\x03" > hsm-integration-test/docker/sgx/kvstore-retries.dat + echo -en "\x03" > hsm-integration-test/docker/sgx/kvstore-retries.dat + dd if=/dev/urandom bs=1 count=32 \ + of=hsm-integration-test/docker/sgx/kvstore-seed.dat + echo "SGX_SIM=yes" >> "$GITHUB_ENV" + + - name: Run HSM integration tests + working-directory: hsm-integration-test + run: sh smoke-test.sh From fb941b3a214ff9d75d090e283040305772f4bd59 Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:11:23 -0300 Subject: [PATCH 07/50] Added unit tests for the nvmem module (#203) * Added unit tests for SGX HAL nvmem module * Added SGX HAL unit tests to the CI * Added check to avoid for buffer overrun on nvmem.c --- .github/workflows/run-tests.yml | 3 + firmware/coverage/gen-coverage | 1 + firmware/src/hal/include/hal/nvmem.h | 5 +- firmware/src/hal/sgx/src/trusted/nvmem.c | 9 +- .../src/hal/sgx/test/common/assert_utils.h | 1 + firmware/src/hal/sgx/test/common/common.mk | 37 +++ firmware/src/hal/sgx/test/mock/mock.h | 30 ++ .../src/hal/sgx/test/mock/mock_secret_store.c | 99 +++++++ .../src/hal/sgx/test/mock/mock_secret_store.h | 93 ++++++ firmware/src/hal/sgx/test/nvmem/Makefile | 38 +++ firmware/src/hal/sgx/test/nvmem/test_nvmem.c | 271 ++++++++++++++++++ firmware/src/hal/sgx/test/run-all.sh | 13 + .../src/ledger/ui/test/mock/assert_utils.h | 5 + firmware/src/sgx/src/trusted/system.c | 19 +- 14 files changed, 615 insertions(+), 9 deletions(-) create mode 120000 firmware/src/hal/sgx/test/common/assert_utils.h create mode 100644 firmware/src/hal/sgx/test/common/common.mk create mode 100644 firmware/src/hal/sgx/test/mock/mock.h create mode 100644 firmware/src/hal/sgx/test/mock/mock_secret_store.c create mode 100644 firmware/src/hal/sgx/test/mock/mock_secret_store.h create mode 100644 firmware/src/hal/sgx/test/nvmem/Makefile create mode 100644 firmware/src/hal/sgx/test/nvmem/test_nvmem.c create mode 100755 firmware/src/hal/sgx/test/run-all.sh diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 70737d2d..9ad08746 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -28,6 +28,9 @@ jobs: - name: Firmware HAL's x86 unit tests run: firmware/src/hal/x86/test/run-all.sh + + - name: Firmware HAL's SGX unit tests + run: firmware/src/hal/sgx/test/run-all.sh - name: Firmware common lib unit tests run: firmware/src/common/test/run-all.sh diff --git a/firmware/coverage/gen-coverage b/firmware/coverage/gen-coverage index 210004a0..4fd85d76 100755 --- a/firmware/coverage/gen-coverage +++ b/firmware/coverage/gen-coverage @@ -15,6 +15,7 @@ if [[ $1 == "exec" ]]; then COVERAGE=y $REPOROOT/firmware/src/ledger/ui/test/run-all.sh COVERAGE=y $REPOROOT/firmware/src/ledger/signer/test/run-all.sh COVERAGE=y $REPOROOT/firmware/src/tcpsigner/test/run-all.sh + COVERAGE=y $REPOROOT/firmware/src/hal/sgx/test/run-all.sh # Run tcpsigner test suite pushd $REPOROOT/firmware/src/tcpsigner > /dev/null diff --git a/firmware/src/hal/include/hal/nvmem.h b/firmware/src/hal/include/hal/nvmem.h index e6daeead..2237d26b 100644 --- a/firmware/src/hal/include/hal/nvmem.h +++ b/firmware/src/hal/include/hal/nvmem.h @@ -32,7 +32,6 @@ /** * @brief Write to non volatile memory * - * @param key The key of the destination in non volatile memory * @param dst The destination address in (non volatile) memory * @param src The source address to write from * @param length The amount of bytes to write @@ -73,8 +72,10 @@ void nvmem_init(); * @param key a string key to uniquely identify the block * @param addr the base address of the block * @param size the size of the block in bytes + * + * @return whether the block was successfully registered */ -void nvmem_register_block(char* key, void* addr, size_t size); +bool nvmem_register_block(char* key, void* addr, size_t size); /** * @brief Loads registered blocks into memory diff --git a/firmware/src/hal/sgx/src/trusted/nvmem.c b/firmware/src/hal/sgx/src/trusted/nvmem.c index 015e039f..f37344ea 100644 --- a/firmware/src/hal/sgx/src/trusted/nvmem.c +++ b/firmware/src/hal/sgx/src/trusted/nvmem.c @@ -58,11 +58,18 @@ void nvmem_init() { nvm_blocks_count = 0; } -void nvmem_register_block(char* key, void* addr, size_t size) { +bool nvmem_register_block(char* key, void* addr, size_t size) { + if (nvm_blocks_count >= MAX_NVM_BLOCKS) { + LOG("Error registering NVM block <%s>: too many blocks\n", key); + return false; + } + nvm_blocks[nvm_blocks_count].key = key; nvm_blocks[nvm_blocks_count].addr = addr; nvm_blocks[nvm_blocks_count].size = size; nvm_blocks_count++; + + return true; } static void clear_blocks() { diff --git a/firmware/src/hal/sgx/test/common/assert_utils.h b/firmware/src/hal/sgx/test/common/assert_utils.h new file mode 120000 index 00000000..68276815 --- /dev/null +++ b/firmware/src/hal/sgx/test/common/assert_utils.h @@ -0,0 +1 @@ +../../../../ledger/ui/test/mock/assert_utils.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/common/common.mk b/firmware/src/hal/sgx/test/common/common.mk new file mode 100644 index 00000000..71522536 --- /dev/null +++ b/firmware/src/hal/sgx/test/common/common.mk @@ -0,0 +1,37 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +SRCDIR = ../../src/trusted +MOCKDIR = ../mock +HALINCDIR = ../../../../hal/include +TESTCOMMONDIR = ../common +CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function +CFLAGS += -iquote $(SRCDIR) -iquote $(HALINCDIR) +CFLAGS += -iquote $(TESTCOMMONDIR) +CFLAGS += -iquote $(MOCKDIR) +CFLAGS += -DHSM_PLATFORM_SGX + +VPATH += $(MOCKDIR):$(SRCDIR) + +include ../../../../../coverage/coverage.mk + +CFLAGS += $(COVFLAGS) diff --git a/firmware/src/hal/sgx/test/mock/mock.h b/firmware/src/hal/sgx/test/mock/mock.h new file mode 100644 index 00000000..c263ce1b --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/mock.h @@ -0,0 +1,30 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCK_H +#define __MOCK_H + +#include "mock_secret_store.h" + +#endif // #ifndef __MOCK_H diff --git a/firmware/src/hal/sgx/test/mock/mock_secret_store.c b/firmware/src/hal/sgx/test/mock/mock_secret_store.c new file mode 100644 index 00000000..6fa2fd7d --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/mock_secret_store.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include + +#include "mock_secret_store.h" + +typedef struct mock_sest_register { + char *key; + uint8_t *secret; + size_t secret_length; +} mock_sest_register_t; + +#define MOCK_SEST_MAX_REGISTERS 10 +typedef struct mock_secret_store { + mock_sest_register_t registers[MOCK_SEST_MAX_REGISTERS]; + size_t num_registers; + bool fail_next_read; + bool fail_next_write; +} mock_secret_store_t; + +static mock_secret_store_t g_mock_secret_store; + +bool mock_sest_exists(char *key) { + for (size_t i = 0; i < g_mock_secret_store.num_registers; i++) { + if (strcmp(g_mock_secret_store.registers[i].key, key) == 0) { + return true; + } + } + return false; +} + +bool mock_sest_write(char *key, uint8_t *secret, size_t secret_length) { + if (g_mock_secret_store.fail_next_write) { + g_mock_secret_store.fail_next_write = false; + return false; + } + int register_index = -1; + for (size_t i = 0; i < g_mock_secret_store.num_registers; i++) { + if (strcmp(g_mock_secret_store.registers[i].key, key) == 0) { + register_index = i; + break; + } + } + if (register_index == -1) { + assert(g_mock_secret_store.num_registers < MOCK_SEST_MAX_REGISTERS); + register_index = g_mock_secret_store.num_registers; + } + + mock_sest_register_t *new_register = + &g_mock_secret_store.registers[register_index]; + new_register->key = malloc(strlen(key) + 1); + strcpy(new_register->key, key); + new_register->secret = malloc(secret_length); + memcpy(new_register->secret, secret, secret_length); + new_register->secret_length = secret_length; + g_mock_secret_store.num_registers++; + + return true; +} + +uint8_t mock_sest_read(char *key, uint8_t *dest, size_t dest_length) { + if (g_mock_secret_store.fail_next_read) { + g_mock_secret_store.fail_next_read = false; + return 0; + } + for (size_t i = 0; i < g_mock_secret_store.num_registers; i++) { + if (strcmp(g_mock_secret_store.registers[i].key, key) == 0) { + assert(dest_length >= + g_mock_secret_store.registers[i].secret_length); + memcpy(dest, + g_mock_secret_store.registers[i].secret, + g_mock_secret_store.registers[i].secret_length); + return g_mock_secret_store.registers[i].secret_length; + } + } + return 0; +} + +void mock_sest_init() { + memset(&g_mock_secret_store, 0, sizeof(g_mock_secret_store)); +} + +void mock_sest_reset() { + for (size_t i = 0; i < g_mock_secret_store.num_registers; i++) { + free(g_mock_secret_store.registers[i].key); + free(g_mock_secret_store.registers[i].secret); + } + memset(&g_mock_secret_store, 0, sizeof(g_mock_secret_store)); +} + +void mock_sest_fail_next_read(bool fail) { + g_mock_secret_store.fail_next_read = fail; +} + +void mock_sest_fail_next_write(bool fail) { + g_mock_secret_store.fail_next_write = fail; +} diff --git a/firmware/src/hal/sgx/test/mock/mock_secret_store.h b/firmware/src/hal/sgx/test/mock/mock_secret_store.h new file mode 100644 index 00000000..39e58510 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/mock_secret_store.h @@ -0,0 +1,93 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCK_SECRET_STORE_H +#define __MOCK_SECRET_STORE_H + +#include +#include +#include + +/** + * @brief Initializes the mock secret store + */ +void mock_sest_init(); + +/** + * @brief Mock implementation of sest_exists + * + * @param key the key for the secret + * + * @returns whether the provided key corresponds to a secret in the store + */ +bool mock_sest_exists(char *key); + +/** + * @brief Mock implementation of sest_write + * + * @param key the key for the secret + * @param secret the secret to write + * @param secret_length the length of the secret + * + * @returns Whether the write was successful. + * + * NOTE: This mock implementation will always return true unless the + * fail_next_write flag is set. + */ +bool mock_sest_write(char *key, uint8_t *secret, size_t secret_length); + +/** + * @brief Mock implementation of sest_read + * + * @param key the key for the secret + * @param dest the destination buffer for the read secret + * @param dest_length the length of the destination buffer + * + * @returns the length of the secret read, or ZERO upon error. + * + * NOTE: This mock implementation will fail if the fail_next_read flag is set, + * regardless of the key provided. + */ +uint8_t mock_sest_read(char *key, uint8_t *dest, size_t dest_length); + +/** + * @brief Resets the mock secret store to its initial state + */ +void mock_sest_reset(); + +/** + * @brief Sets the value of the fail_next_read flag + * + * @param fail whether the next call to sest_read should fail + */ +void mock_sest_fail_next_read(bool fail); + +/** + * @brief Sets the value of the fail_next_write flag + * + * @param fail whether the next call to sest_write should fail + */ +void mock_sest_fail_next_write(bool fail); + +#endif // #ifndef __MOCK_SECRET_STORE_H diff --git a/firmware/src/hal/sgx/test/nvmem/Makefile b/firmware/src/hal/sgx/test/nvmem/Makefile new file mode 100644 index 00000000..010ce60d --- /dev/null +++ b/firmware/src/hal/sgx/test/nvmem/Makefile @@ -0,0 +1,38 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +PROG = test.out +OBJS = nvmem.o test_nvmem.o mock_secret_store.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) *.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/hal/sgx/test/nvmem/test_nvmem.c b/firmware/src/hal/sgx/test/nvmem/test_nvmem.c new file mode 100644 index 00000000..b2bc1993 --- /dev/null +++ b/firmware/src/hal/sgx/test/nvmem/test_nvmem.c @@ -0,0 +1,271 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "hal/nvmem.h" +#include "assert_utils.h" +#include "mock.h" + +#define TEST_NVMEM_NUM_BLOCKS 5 +// FIXME: sest_read will not work with blocks larger than 255 bytes. For this +// reason we have to keep the block size below this limit for the nvmem tests. +#define TEST_NVMEM_BLOCK_SIZE 255 +#define TEST_NVMEM_KEY_SIZE 32 + +// Hand over the secret store calls to the mock implementation +bool sest_exists(char *key) { + return mock_sest_exists(key); +} + +uint8_t sest_read(char *key, uint8_t *dest, size_t dest_length) { + return mock_sest_read(key, dest, dest_length); +} + +bool sest_write(char *key, uint8_t *secret, size_t secret_length) { + return mock_sest_write(key, secret, secret_length); +} + +// Helper functions +static void setup() { + mock_sest_init(); + nvmem_init(); +} + +static void teardown() { + mock_sest_reset(); +} + +// Test cases +void test_register_single_block() { + setup(); + printf("Test nvmem register a single block...\n"); + + char block[TEST_NVMEM_BLOCK_SIZE]; + assert(nvmem_register_block("key", block, sizeof(block))); + teardown(); +} + +void test_register_multiple_blocks() { + setup(); + printf("Test nvmem register multiple blocks...\n"); + + int num_blocks = TEST_NVMEM_NUM_BLOCKS; + char blocks[num_blocks][TEST_NVMEM_BLOCK_SIZE]; + for (int i = 0; i < num_blocks; i++) { + char key[TEST_NVMEM_KEY_SIZE]; + sprintf(key, "key-%d", i); + assert(nvmem_register_block(key, blocks[i], sizeof(blocks[i]))); + } +} + +void test_register_blocks_over_limit() { + setup(); + printf("Test nvmem register blocks over the allowed limit...\n"); + + int num_blocks = TEST_NVMEM_NUM_BLOCKS + 1; + char blocks[num_blocks][TEST_NVMEM_BLOCK_SIZE]; + for (int i = 0; i < num_blocks; i++) { + char key[TEST_NVMEM_KEY_SIZE]; + sprintf(key, "key-%d", i); + if (i < TEST_NVMEM_NUM_BLOCKS) { + assert(nvmem_register_block(key, blocks[i], sizeof(blocks[i]))); + } else { + assert(!nvmem_register_block(key, blocks[i], sizeof(blocks[i]))); + } + } + teardown(); +} + +void test_write_single_block() { + setup(); + printf("Test nvmem write and load single block...\n"); + + // Register the block with a key and write data to it + uint8_t block[TEST_NVMEM_BLOCK_SIZE]; + assert(nvmem_register_block("key", block, sizeof(block))); + char data[] = "INITIAL TEST DATA"; + assert(nvmem_write(block, data, sizeof(data))); + // The block should now contain the data + ASSERT_MEMCMP(block, data, sizeof(data)); + // Create a copy for comparison and overwrite the original block + char block_copy[TEST_NVMEM_BLOCK_SIZE]; + memcpy(block_copy, block, sizeof(block)); + memset(block, 0, sizeof(block)); + // The block should now have been entirely overwritten + ASSERT_ARRAY_CLEARED(block); + // Load the block from nvmem + assert(nvmem_load()); + // The block should now contain the original data + ASSERT_MEMCMP(block, block_copy, sizeof(block_copy)); + teardown(); +} + +void test_reset_single_block() { + setup(); + printf("Test reset single block...\n"); + + // Register the address block with a key and reset it + uint8_t block[TEST_NVMEM_BLOCK_SIZE]; + assert(nvmem_register_block("key", block, sizeof(block))); + assert(nvmem_write(block, NULL, sizeof(block))); + ASSERT_ARRAY_CLEARED(block); + // Overwrite the block with a magic number + memset(block, 0x42, sizeof(block)); + ASSERT_ARRAY_VALUE(block, 0x42); + // Now load the block from nvmem + assert(nvmem_load()); + // The block should now be cleared + ASSERT_ARRAY_CLEARED(block); + teardown(); +} + +void test_multiple_writes_single_block() { + setup(); + printf("Test multiple writes to a single block...\n"); + + char *test_data[] = { + "Some test data", + "Some more test data", + "Another test string", + }; + int num_writes = sizeof(test_data) / sizeof(test_data[0]); + // Register the address block with a key + uint8_t block[TEST_NVMEM_BLOCK_SIZE]; + assert(nvmem_register_block("key", block, sizeof(block))); + for (int i = 0; i < num_writes; i++) { + // Write the data to the block + assert(nvmem_write(block, test_data[i], strlen(test_data[i]))); + // The block should now contain the data + ASSERT_MEMCMP(block, test_data[i], strlen(test_data[i])); + } + // Overwrite the local copy of the block with zeros + memset(block, 0, sizeof(block)); + // Load the block from nvmem + assert(nvmem_load()); + // The block should now contain the last written data + char *expected_data = test_data[num_writes - 1]; + ASSERT_MEMCMP(block, expected_data, strlen(expected_data)); + teardown(); +} + +void test_write_block_without_register() { + setup(); + printf("Test write block without registering it...\n"); + + uint8_t block[TEST_NVMEM_BLOCK_SIZE]; + // Write some data to the block without registering it + char data[] = "TEST DATA"; + assert(nvmem_write(block, data, strlen(data))); + // The block should have been updated with the data + ASSERT_MEMCMP(block, data, strlen(data)); + // Now overwrite the block with a magic number and try to load it back + memset(block, 0x42, sizeof(block)); + ASSERT_ARRAY_VALUE(block, 0x42); + assert(nvmem_load()); + // The block's contents should be unchanged + ASSERT_ARRAY_VALUE(block, 0x42); + + teardown(); +} + +void test_load_single_block_without_writing() { + setup(); + printf("Test load single block without writing...\n"); + + uint8_t block[TEST_NVMEM_BLOCK_SIZE]; + // Register the block but don't write any data to it + assert(nvmem_register_block("key", block, sizeof(block))); + // Initialize the block with a magic number + memset(block, 0x42, sizeof(block)); + ASSERT_ARRAY_VALUE(block, 0x42); + // Load the block from nvmem + assert(nvmem_load()); + // The block should now contain only zeros + ASSERT_ARRAY_CLEARED(block); + teardown(); +} + +void test_write_on_sest_failure() { + setup(); + printf("Test write fails when secret store write fails...\n"); + + // Register the block and write initial data + uint8_t block[TEST_NVMEM_BLOCK_SIZE]; + char initial_data[] = "INITIAL NVMEM DATA"; + assert(nvmem_register_block("key", block, sizeof(block))); + assert(nvmem_write(block, initial_data, strlen(initial_data))); + ASSERT_MEMCMP(block, initial_data, strlen(initial_data)); + // Forces the mock secret store to fail on the next write operation + mock_sest_fail_next_write(true); + // Attempt to write new data to the nvmem, and fail + char new_data[] = "NEW NVMEM DATA"; + assert(!nvmem_write(block, new_data, strlen(new_data))); + // The local copy was updated, but the nvmem was not + ASSERT_MEMCMP(block, new_data, strlen(new_data)); + assert(nvmem_load()); + ASSERT_MEMCMP(block, initial_data, strlen(initial_data)); + teardown(); +} + +void test_load_fails_on_sest_failure() { + setup(); + printf("Test load fails when secret store read fails...\n"); + + // Register the block and write initial data + uint8_t block[TEST_NVMEM_BLOCK_SIZE]; + char initial_data[] = "INITIAL NVMEM DATA"; + assert(nvmem_register_block("key", block, sizeof(block))); + assert(nvmem_write(block, initial_data, strlen(initial_data))); + ASSERT_MEMCMP(block, initial_data, strlen(initial_data)); + // Overwrite the block with a magic number + memset(block, 0x42, sizeof(block)); + ASSERT_ARRAY_VALUE(block, 0x42); + // Forces the mock secret store to fail on the next read operation + mock_sest_fail_next_read(true); + // Attempt to load the nvmem, and fail + assert(!nvmem_load()); + // The load error should cause the block to be cleared + ASSERT_ARRAY_CLEARED(block); + teardown(); +} + +int main() { + test_register_single_block(); + test_register_multiple_blocks(); + test_register_blocks_over_limit(); + test_write_single_block(); + test_reset_single_block(); + test_multiple_writes_single_block(); + test_write_block_without_register(); + test_load_single_block_without_writing(); + test_write_on_sest_failure(); + test_load_fails_on_sest_failure(); + + return 0; +} diff --git a/firmware/src/hal/sgx/test/run-all.sh b/firmware/src/hal/sgx/test/run-all.sh new file mode 100755 index 00000000..2a4217fe --- /dev/null +++ b/firmware/src/hal/sgx/test/run-all.sh @@ -0,0 +1,13 @@ +#!/bin/bash +BASEDIR=$(dirname $0) +TESTDIRS="nvmem" +TESTDIRS=${1:-"$TESTDIRS"} + +for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null +done diff --git a/firmware/src/ledger/ui/test/mock/assert_utils.h b/firmware/src/ledger/ui/test/mock/assert_utils.h index b5432db0..a136cc9c 100644 --- a/firmware/src/ledger/ui/test/mock/assert_utils.h +++ b/firmware/src/ledger/ui/test/mock/assert_utils.h @@ -35,6 +35,11 @@ #define ASSERT_MEMCMP(a, b, n) assert(0 == memcmp(a, b, n)) +#define ASSERT_ARRAY_VALUE(arr, value) \ + for (size_t i = 0; i < sizeof(arr); i++) { \ + assert((arr)[i] == (value)); \ + } + #define ASSERT_ARRAY_CLEARED(arr) \ assert(memcmp(arr, (char[sizeof(arr)]){0}, sizeof(arr)) == 0) diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c index 9cc80815..4017d207 100644 --- a/firmware/src/sgx/src/trusted/system.c +++ b/firmware/src/sgx/src/trusted/system.c @@ -206,12 +206,19 @@ bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { } nvmem_init(); - nvmem_register_block("bcstate", - &N_bc_state_var, - sizeof(N_bc_state_var)); - nvmem_register_block("bcstate_updating", - &N_bc_state_updating_backup_var, - sizeof(N_bc_state_updating_backup_var)); + if (!nvmem_register_block("bcstate", + &N_bc_state_var, + sizeof(N_bc_state_var))) { + LOG("Error registering bcstate block\n"); + return false; + } + if (!nvmem_register_block("bcstate_updating", + &N_bc_state_updating_backup_var, + sizeof(N_bc_state_updating_backup_var))) { + LOG("Error registering bcstate_updating block\n"); + return false; + } + if (!nvmem_load()) { LOG("Error loading nvmem\n"); return false; From a271c8c428ed7927a0ffc4e0c9eab4280ccdb333 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 8 Oct 2024 02:18:48 +1300 Subject: [PATCH 08/50] Added SGX documentation (#205) --- QUICKSTART.md | 27 ++++++++++++++++++----- README.md | 21 ++++++++++++------ docs/attestation.md | 10 ++++++--- docs/blockchain-bookkeeping.md | 2 +- docs/heartbeat.md | 4 ++++ docs/protocol-v1.md | 2 +- docs/signer-authorization.md | 10 +++++++++ firmware/README.md | 40 +++++++++++++++++++++++----------- firmware/build/README.md | 35 +++++++++++++++++++++++++++++ middleware/README.md | 30 +++++++++++++++++-------- 10 files changed, 142 insertions(+), 39 deletions(-) diff --git a/QUICKSTART.md b/QUICKSTART.md index 4406a373..d015eb16 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -10,6 +10,7 @@ Whether new to the project or just wanting to quickly get an environment up and ``` ~/repo> docker/mware/build # Middleware image ~/repo> docker/ledger/build # Ledger image +~/repo> docker/sgx/build # SGX image ~/repo> docker/packer/build # Middleware binary packer image ``` @@ -27,13 +28,19 @@ Unless otherwise stated, only x86 platforms are supported for building this proj ~/repo> firmware/src/ledger/signer/test/run-all.sh # Ledger Signer application unit tests ~/repo> firmware/src/common/test/run-all.sh # Common code unit tests ~/repo> firmware/src/powhsm/test/run-all.sh # powHSM logic unit tests -~/repo> firmware/src/hal/test/run-all.sh # HAL unit tests +~/repo> firmware/src/hal/common/test/run-all.sh # HAL common code unit tests +~/repo> firmware/src/hal/x86/test/run-all.sh # HAL x86 implementation unit tests ``` - Build Ledger Nano S application binaries: ``` -~/repo> firmware/build/build-signer # Build signer -~/repo> firmware/build/build-ui # Build UI +~/repo> firmware/build/build-ledger-signer # Build signer +~/repo> firmware/build/build-ledger-ui # Build UI +``` + +- Build SGX binaries (both host and enclave): +``` +~/repo> firmware/build/build-sgx ``` - Build middleware binaries: @@ -41,12 +48,22 @@ Unless otherwise stated, only x86 platforms are supported for building this proj ~/repo> middleware/build/all ``` -- Build a complete powHSM distribution: +- Build a complete Ledger powHSM distribution: ``` -~/repo> ./build-dist +~/repo> ./build-dist-ledger +``` + +- Build a complete SGX powHSM distribution: +``` +~/repo> ./build-dist-sgx ``` - Build the TCPSigner: ``` ~/repo> firmware/build/build-tcpsigner ``` + +- Build the SGX simulator: +``` +~/repo> firmware/build/build-sgx-sim +``` diff --git a/README.md b/README.md index b4f7c6b6..ee086462 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ The RSK Powpeg protects private keys stored in special purpose PowHSMs based on tamper-proof secure elements (SE). The PowHSM runs an RSK node in SPV mode, and signatures can only be commanded by chain cumulative proof of work. -This repository hosts the powHSM firmware. The stable versions are the tags published in the [releases tab](https://github.com/rsksmart/rsk-powhsm/releases). +This repository hosts the powHSM firmware and middleware. The stable versions are the tags published in the [releases tab](https://github.com/rsksmart/rsk-powhsm/releases). ## Notation @@ -22,23 +22,30 @@ Throughout the repository READMEs, the prompt `~/repo>` is used to denote a `bas Refer to our [quickstart guide](./QUICKSTART.md) to learn about environment setup and common tasks without further ado. +## Firmware platforms + +PowHSM can run both on Ledger Nano S devices and Intel SGX servers. At any given time, a PowPeg can be composed of a mix of members running PowHSM on either platform. The decision of which platform to run on each member is ultimately up to the member itself and the Rootstock network maintainers. + ## Supported platforms Unless otherwise stated, only x86 platforms are supported for building this project and running the tools provided. It is possible, however, to build and run the [TCPSigner bundle](./utils/tcpsigner-bundle/README.md) on arm64 platforms. This is provided for development and testing purposes. ## Concepts overview -powHSM is a solution designed specifically for the [RSK network](https://www.rsk.co/) powPeg. Its main role is to safekeep and prevent the unauthorized usage of each of the powPeg's members' private keys. powHSM is currently implemented as a pair of applications for the [Ledger Nano S](https://shop.ledger.com/products/ledger-nano-s), namely a UI and a Signer, and it strongly depends on the device's security features to implement the aforementioned safekeeping. +powHSM is a solution designed specifically for the [RSK network](https://www.rsk.co/) powPeg. Its main role is to safekeep and prevent the unauthorized usage of each of the powPeg's members' private keys. powHSM has currenty got two implementations that target two different platforms. + +1. The first implementation consists of a pair of applications for the [Ledger Nano S](https://shop.ledger.com/products/ledger-nano-s), namely a UI and a Signer, and it strongly depends on the device's security features to implement the aforementioned safekeeping. This implementation requires a physical Ledger Nano S device and a self-managed physical standalone server. +2. The second implementation consists of both a host and an enclave binary targetting the Intel SGX architecture. Just as the Ledger Nano S implementation, it strongly depends on the Intel SGX security features in order to keep the private keys safe. This implementation can run both on standalone SGX-enabled servers as well as on SGX-enabled cloud computing providers (e.g., Microsoft Azure). -Each powPeg member runs an individual physical device on which a transparent installation and onboarding process is carried. Amongst other things, this process safely generates the root key, that never leaves the device. There is an [attestation process](./docs/attestation.md) that serves the purpose of testifying and guaranteeing this key generation process, and ultimately the fact that the key is only ever known to the device. +Each powPeg member runs an individual physical device or SGX enclave on which a transparent installation and onboarding process is carried. Amongst other things, this process safely generates the root key, that either never leaves the device (Ledger) or can only ever be decrypted by the enclave (SGX). There is an [attestation process](./docs/attestation.md) that serves the purpose of testifying and guaranteeing this key generation process, and ultimately the fact that the key is only ever known to the device (attestation is currently only supported on the Ledger implementation). -After onboarding, each device is physically connected to and interacts with its corresponding powPeg node by means of a middleware layer that exposes a [high-level protocol](./docs/protocol.md) for its operation. +After onboarding, each powHSM runs either on its host (SGX) or is physically connected to it (Ledger), and interacts with its corresponding powPeg node by means of a middleware layer that exposes a [high-level protocol](./docs/protocol.md) for its operation. -The signer application running within each device enables the usage of two sets of keypairs by its owner powPeg node: an _unauthorized_ and an _authorized_ set. These keys are generated from the root key using a standard [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) derivation path (following [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)). +The signer application running within each powHSM enables the usage of two sets of keypairs by its owner powPeg node: an _unauthorized_ and an _authorized_ set. These keys are generated from the root key using a standard [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) derivation path (following [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)). -The _unauthorized_ keyset can be used to sign arbitrary hashes, and its security scheme relies solely on the knowledge of the device's pin (akin to owning a Ledger Nano S for personal usage). This keyset is used by the powPeg members for non critical operations (e.g., signing powPeg-only transactions within the RSK network). +The _unauthorized_ keyset can be used to sign arbitrary hashes, and its security scheme relies solely on the knowledge of the powHSM's pin (in the Ledger Nano S case, akin to owning a device for personal usage). This keyset is used by the powPeg members for non critical operations (e.g., signing powPeg-only transactions within the RSK network). -The _authorized_ keyset is the main security focus of the solution. It can _only_ ever be used to sign BTC transactions that correspond to pegOuts within the RSK network, i.e., the release of Bitcoin funds held within RSK's bridge mechanism. This authorization is enforced by means of events that the [Bridge contract](https://explorer.rsk.co/address/0x0000000000000000000000000000000001000006) emits whenever a pegOut request is generated, and that are included in RSK's blocks by means of transaction receipts, and ultimately mined and secured by actual Bitcoin miners. This implies that without a mined pegOut request with a minimum amount of hashing power on top, the device emits no signature. This powerful feature gives the project its name: _powHSM_ - Proof of Work Hardware Security Module. +The _authorized_ keyset is the main security focus of the solution. It can _only_ ever be used to sign BTC transactions that correspond to pegOuts within the RSK network, i.e., the release of Bitcoin funds held within RSK's bridge mechanism. This authorization is enforced by means of events that the [Bridge contract](https://explorer.rsk.co/address/0x0000000000000000000000000000000001000006) emits whenever a pegOut request is generated, and that are included in RSK's blocks by means of transaction receipts, and ultimately mined and secured by actual Bitcoin miners. This implies that, without a mined pegOut request with a minimum amount of hashing power on top, the powHSM emits no signature. This powerful feature gives the project its name: _powHSM_ - Proof of Work Hardware Security Module. ## Digging deeper diff --git a/docs/attestation.md b/docs/attestation.md index b4bf091b..3cc0ac25 100644 --- a/docs/attestation.md +++ b/docs/attestation.md @@ -1,12 +1,16 @@ # powHSM attestation +## Foreword + +Currently, attestation is a feature supported only in the Ledger version of powHSM. An attestation implementation for the SGX version of powHSM is currently under development. Therefore, all the information contained herein must be interpreted as applying exclusively to the Ledger version of powHSM. + ## Abstract -This document describes the mechanisms through which a powHSM installation can prove to an end user that it is actually installed on an authentic physical Ledger device with a specific UI and Signer versions, along with its currently authorized signer version and generated public keys. +This document describes the mechanisms through which a powHSM installation can prove to an end user that it is actually installed on an authentic physical Ledger device with specific UI and Signer versions, along with its currently authorized signer version and generated public keys. ## Preliminaries, native support and assumptions -Each device currently used to run powHSM on, namely Ledger Nano S, ships with a mechanism to prove its authenticity and that also enables and leverages some basic additional support for user application attestation. For powHSM attestation we make extensive use of these mechanisms, assuming it is robust enough for our purpose. +Each Ledger device currently used to run powHSM on, namely Ledger Nano S, ships with a mechanism to prove its authenticity and that also enables and leverages some basic additional support for user application attestation. For powHSM attestation we make extensive use of these mechanisms, assuming it is robust enough for our purpose. ## Device key and authenticity @@ -174,4 +178,4 @@ Installed Signer hash: e1baa18564fc0c2c70ac4019609c6db643adbf12711c8b319f838e6a7 --------------------------------------------------------------------------------------- ``` -and verify that the reported custom CA and UI and Signer hashes match the expected values. \ No newline at end of file +and verify that the reported UI and Signer application hashes match the expected value. Additionally, the user should check that each additional reported value corresponds with an expected or reasonable value (e.g., verify that the UD value corresponds to an RSK block header hash that was mined on or after the time of setup/update; or that in the case of an update, the public keys correspond to those of the powPeg member and have not been altered from the values obtained at setup). \ No newline at end of file diff --git a/docs/blockchain-bookkeeping.md b/docs/blockchain-bookkeeping.md index 22147087..5e702f01 100644 --- a/docs/blockchain-bookkeeping.md +++ b/docs/blockchain-bookkeeping.md @@ -243,7 +243,7 @@ At any point in time, the only block that is considered to be included in the bl ## Implementation considerations -The implementation must take into account the limited resources available on the actual hardware, and thus implement the described algorithms as a set of request-response incremental operations without compromising the integrity of the update processes. For example, to process just a single block, many request-response operations might be needed, and that would correspond to a single iteration in either of the above algorithms. +The implementation must take into account any potential limited resources available on the actual hardware, and thus implement the described algorithms as a set of request-response incremental operations without compromising the integrity of the update processes. For example, to process just a single block, many request-response operations might be needed, and that would correspond to a single iteration in either of the above algorithms. ## Miscellaneous diff --git a/docs/heartbeat.md b/docs/heartbeat.md index 1d521ad6..6d4f5fdf 100644 --- a/docs/heartbeat.md +++ b/docs/heartbeat.md @@ -1,5 +1,9 @@ # powHSM heartbeat +## Foreword + +Currently, just like what happens in the case of [attestation](./attestation.md), heartbeat is a feature supported only in the Ledger version of powHSM. A heartbeat implementation for the SGX version of powHSM is currently under development. Therefore, all the information contained herein must be interpreted as applying exclusively to the Ledger version of powHSM. + ## Abstract This document describes the feature known as "heartbeat", which allows an end user to diff --git a/docs/protocol-v1.md b/docs/protocol-v1.md index a5b78419..f0d03b18 100644 --- a/docs/protocol-v1.md +++ b/docs/protocol-v1.md @@ -2,7 +2,7 @@ ## About -This document describes the legacy protocol used in version 1 of the HSM. The purpose is to provide a reference for the usage of the legacy mode in the Ledger manager and TCP manager (with modifier `--version-one`). +This document describes the legacy protocol used in version 1 of the HSM. The purpose is to provide a reference for the usage of the legacy mode in the Ledger, SGX and TCP managers (with modifier `--version-one`). ## Definitions diff --git a/docs/signer-authorization.md b/docs/signer-authorization.md index 8ac1e796..a2e35cce 100644 --- a/docs/signer-authorization.md +++ b/docs/signer-authorization.md @@ -1,5 +1,15 @@ # powHSM signer authorization and upgrade +## Foreword + +Signer authorization and upgrading is a feature designed exclusively for the Ledger +version of powHSM. Therefore, all the information contained herein must be interpreted as +applying exclusively to this implementation. + +The only other implementation of powHSM, written for the Intel SGX platform, has currently +got no support for upgrading, and thus an equivalent document to describe such a process +does not exist. + ## Abstract This document describes the mechanisms by which the Ledger Nano S UI application diff --git a/firmware/README.md b/firmware/README.md index fbb391dc..6fbba69f 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -2,13 +2,14 @@ ## Overview and source code -By firmware, we collectively refer to the group of applications that comprise the main powHSM logic and its different implementations (currently and namely, powHSM for Ledger Nano S and powHSM for x86 -- codenamed TCPSigner). The source code under this document's directory is located within the `src` directory, and is organised as follows: +By firmware, we collectively refer to the group of applications that comprise the main powHSM logic and its different implementations (currently and namely, powHSM for Ledger Nano S, powHSM for Intel SGX and powHSM for x86 -- codenamed TCPSigner). The source code under this document's directory is located within the `src` directory, and is organised as follows: -- `hal`: contains header and source files for the Hardware Abstraction Layer, on top of which the powHSM logic is built. Currently implemented for Ledger Nano S and x86. +- `hal`: contains header and source files for the Hardware Abstraction Layer, on top of which the powHSM logic is built. Currently implemented for Ledger Nano S, Intel SGX and x86. - `powhsm`: contains the powHSM logic. - `ledger`: contains the Ledger Nano S apps. +- `sgx`: contains the Intel SGX implementation of powHSM (host and enclave). - `tcpsigner`: contains the x86 implementation of powHSM. -- `common`: contains some common headers used both in powHSM and the Ledger Nano S apps (note that the Ledger UI app does not use the HAL layer). +- `common`: contains some common headers used both in powHSM, the Ledger Nano S apps and the Intel SGX host and enclave. ## powHSM for Ledger Nano S @@ -46,26 +47,39 @@ Refer to [firmware/build/README.md](./build/README.md) for instructions on build See [Ledger's documentation](http://ledger.readthedocs.io) to get a reference on developing for the platform. +## powHSM for Intel SGX -## powHSM for x86 +### Host and Enclave -Besides the Ledger implementation, there is also an x86 based implementation of the powHSM, which we call _TCPSigner_. This is used to smoke test, fuzz (see [the fuzzing documentation](./fuzz/README.md) for details) and debug & test new features on before we jump onto testing on a physical Ledger Nano S device. With the exception of fuzzing, this component creates a TCP/IP server that serves the purpose of enabling the otherwise USB-based interactions with a given client. +There are two parts to the Intel SGX powHSM implementation: a host and an enclave. The enclave is responsible for hosting the core powHSM business logic, as well as for managing all secrets (e.g., private keys). This enclave runs in a reserved memory area and cannot be tampered with or accessed by any other entities than itself. Its only link with the outside world is the host, with which it shares a limited, well defined, communication protocol. The host, then, is responsible for managing the enclave creation, destruction, and all its interactions with the outside world -- including, but not limited to, disk and network access. Once built, both host and enclave take the form of binaries that must be deployed together to the Intel SGX server on which they are set to run. -## Tests +### Prerequisites + +Before starting, you must have the following installed on your system: + +- Docker -There are some tests written in Python that serve the purpose of smoke testing the powHSM signer when either installed and running on a Ledger Nano S or via a fresh TCPSigner build. To run them against a TCPSigner, issue: +The first time, you must build the docker image that will serve as the SGX build environment. Issue: ``` -~/repo/firmware/test> ./test-all +~/repo> docker/sgx/build ``` -To run them against a Ledger Nano S, issue: +that should build (or rebuild in case any of the `Dockerfile`s have changed) the corresponding docker image. -``` -~/repo/firmware/test> ./test-all dongle -``` +### Common tasks and documentation + +Refer to [firmware/build/README.md](./build/README.md) for instructions on building. + +See [Open Enclave](https://openenclave.io/sdk/) for development documentation and reference, and [Intel SGX](https://www.intel.com/content/www/us/en/products/docs/accelerator-engines/software-guard-extensions.html) for information about the underlying platform. + +## powHSM for x86 + +Besides the Ledger implementation, there is also an x86 based implementation of the powHSM, which we call _TCPSigner_. This is used to smoke test, fuzz (see [the fuzzing documentation](./fuzz/README.md) for details) and debug & test new features on before we jump onto testing on a physical Ledger Nano S device. With the exception of fuzzing, this component creates a TCP/IP server that serves the purpose of enabling the otherwise USB-based interactions with a given client. + +## Tests -Make sure that the Ledger is unlocked and with the signer app running for the tests to run correctly. +There is a test framework written in Python with a rather large set of tests that serve the purpose of smoke testing the main powHSM signing business logic when either installed and running on a Ledger Nano S, an Intel SGX server or via a fresh TCPSigner build. Refer to [the firmware testing documentation](./test/README.md) for details on how to run these tests on each supported platform. ## Troubleshooting diff --git a/firmware/build/README.md b/firmware/build/README.md index ed50833c..267f8ab5 100644 --- a/firmware/build/README.md +++ b/firmware/build/README.md @@ -43,6 +43,41 @@ Once the build is complete, you will get the hash of the build as output, and th It is *very important* to mention that both the Signer and the UI builds are bitwise reproducible. That is, two independent builds of the same code will yield the exact same hex files (and thus, the same app hashes). This is of remarkable importance for the [attestation process](../../docs/attestation.md). +## Building the SGX host and enclave + +The following instructions indicate how to build both the host and enclave applications for +Intel SGX. The Docker image for SGX builds (see [the firmware readme](../README.md)) provides an environment suitable to build (and sign) both the host and the enclave applications. This way new developers don't have to struggle setting up the build toolchain, and all of them will have exactly the same toolchain (no different compiler versions and related nuisances). This image must be built beforehand. + +Before building, an enclave signing key must exist in `~/repo/firmware/src/sgx/private.pem` in order to sign the produced enclave binary. This key is not kept in the repository for obvious reasons, and must be created the first time. In order to generate such a key, one could leverage the `generate-private-key` target of the SGX `Makefile` within a running SGX docker container. Just issue: + +```bash +~/repo> docker/sgx/do /hsm2/firmware/src/sgx "make generate-private-key" +``` + +Other alternative ways of generating this private key are completely valid, and the user is encouraged to use a method of his liking, security and convenience. + +Once the private key already exists in the required disk location, the binaries are ready to be built. To build host and enclave (both are built simultaneously), just issue: + +```bash +~/repo> firmware/build/build-sgx +``` + +where `` is the desired blockchain checkpoint hash, `` is the minimum required difficulty (can be specified as a decimal number or as a hexadecimal - prefixed with `0x`), and `` is the desired network the build is to target (one of `mainnet`, `testnet` or `regtest`). + +For example, to build host and enclave with checkpoint `0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac`, minimum cumulative difficulty of `0x7c50933098` and the `testnet` network, issue: + +```bash +~/repo> firmware/build/build-sgx 0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac 0x7c50933098 testnet +``` + +Once the build is complete, the binaries will be placed under `/firmware/src/sgx/bin` with the names `hsmsgx` for the host and `hsmsgx_enclave.signed` for the signed enclave. + +### Simulation and debug builds + +There are also debug and simulation builds available for development and testing purposes. Just replace the use of the `build-sgx` script with either `build-sgx-debug` or `build-sgx-sim` to obtain a debug or simulation version. The debug version has got a slightly different OpenEnclave configuration file and logging settings, and the simulation version can be ran on non-SGX environments (this latter version extremely useful for local development and testing). + +The use of any of these is highly discouraged in production environments. + ## Building the TCPSigner The Docker image for the middleware (see [the middleware readme](../../middleware/README.md)) provides a suitable environment to build, run and test the TCPSigner. This image must be built beforehand. To then build the TCPSigner, just issue: diff --git a/middleware/README.md b/middleware/README.md index a1f182e2..e0f3fcdf 100644 --- a/middleware/README.md +++ b/middleware/README.md @@ -42,7 +42,7 @@ Throughout the rest of the document, we will refer to a middleware development e ### Ledger Manager -The Ledger manager is the main middleware component for the Ledger powHSM implementation. Its role is to provide a high-level abstraction layer over the low-level powHSM dongle USB interface. It does this by starting a TCP service in a certain interface and port and implementing the [protocol](../docs/protocol.md) on top by means of interactions with the connected powHSM dongle. The entrypoint to the powHSM manager is the `manager_ledger.py` script. In order to start it, issue: +The Ledger manager is the main middleware component for the Ledger powHSM implementation. Its role is to provide a high-level abstraction layer over the low-level powHSM dongle USB interface. It does this by starting a TCP service in a certain interface and port and implementing the [protocol](../docs/protocol.md) on top by means of interactions with the connected powHSM dongle. The entrypoint to the Ledger powHSM manager is the `manager_ledger.py` script. In order to start it, issue: ``` (mware)> python manager_ledger.py @@ -50,9 +50,19 @@ The Ledger manager is the main middleware component for the Ledger powHSM implem Hit CTRL-C at any time to stop it. +### SGX Manager + +The SGX manager is the main middleware component for the SGX powHSM implementation. It is essentially an implementation of the Ledger manager that connects to an SGX powHSM by means of a TCP/IP connection. The entrypoint to the SGX powHSM manager is the `manager_sgx.py` script. You can use the SGX manager to run against a real SGX instance in an Intel SGX enabled server, or against an SGX simulation build on your local. For the former, make sure you build a `manager_sgx` binary package (see the corresponding section below for details) and then copy it over to the SGX server in order to run it there alongside the SGX powHSM. For the latter, and assuming an SGX simulation build is running in the same container, you can just issue: + +``` +(mware)> python manager_sgx.py +``` + +Hit CTRL-C at any time to stop it. + ### TCP Manager -This is an implementation of the Manager that connects to a dongle via a TCP/IP connection. Its main use is along the TCPSigner (an x86 implementation of the Signer component) for integration tests and the like. It's important to mention that Manager and TCP Manager share most of the code, and that the main difference lies in the dongle proxy used and available user options. The entrypoint to the TCP manager is the `manager_tcp.py` script. In order to start it, issue: +This is an implementation of the Manager that connects to a powHSM via a TCP/IP connection. Its main use is along the TCPSigner (an x86 implementation of the Signer component) for integration tests and the like. It's important to mention that Ledger, SGX and TCP Manager share most of the code, and that the main difference lies in the powHSM proxy used and available user options. The entrypoint to the TCP manager is the `manager_tcp.py` script. In order to start it, issue: ``` (mware)> python manager_tcp.py @@ -62,14 +72,15 @@ Hit CTRL-C at any time to stop it. ### Administrative utilities -Aside from the main `manager_ledger.py` and `manager_tcp.py` scripts, there are other three scripts to consider: +Aside from the main `manager_ledger.py`, `manager_sgx.py` and `manager_tcp.py` scripts, there are other three scripts to consider: - `adm_ledger.py`: administrative utility for a Ledger powHSM dongle. It provides common utilities that can be performed on a powHSM dongle. -- `lbutils.py`: common frontend to some of the `ledgerblue` modules. In particular, it ultimately serves the purpose of being able to build a binary for these utilities. -- `signapp.py`: signer authorization generator. Serves the purpose of generating authorization files for Signer versions (see [the signer authorization documentation](../docs/signer-authorization.md) for details). It can be used to add externally generated signatures, or to sign with a manually input key (intended for testing purposes only). It can also be used to calculate the message to be signed to authorize a specific signer version (so that then the signature can be generated on a third-party application, e.g., MetaMask). Last, it has an option to calculate and output a Ledger app's hash. -- `signonetime.py`: ledger app signer. Serves the purpose of signing Ledger Nano S firmware builds with a securely generated random one-time key. It is used in the distribution building process targeting the initial device setup process. +- `adm_sgx.py`: administrative utility for an SGX powHSM. It provides common utilities that can be performed on a running SGX powHSM instance. +- `lbutils.py`: common frontend to some of the `ledgerblue` modules. In particular, it ultimately serves the purpose of being able to build a binary for these utilities. This is used for Ledger exclusively. +- `signapp.py`: signer authorization generator. Serves the purpose of generating authorization files for Signer versions (see [the signer authorization documentation](../docs/signer-authorization.md) for details). It can be used to add externally generated signatures, or to sign with a manually input key (intended for testing purposes only). It can also be used to calculate the message to be signed to authorize a specific signer version (so that then the signature can be generated on a third-party application, e.g., MetaMask). Last, it has an option to calculate and output a Ledger app's hash. This is used for Ledger exclusively. +- `signonetime.py`: ledger app signer. Serves the purpose of signing Ledger Nano S firmware builds with a securely generated random one-time key. It is used in the distribution building process targeting the initial device setup process. This is used for Ledger exclusively. -The remaining `client.py` is a shorthand client utility for manually testing communication with a running Ledger manager or TCP manager. +The remaining `client.py` is a shorthand client utility for manually testing communication with a running Ledger, SGX or TCP manager. ## Unit tests @@ -101,9 +112,10 @@ that should build (or rebuild in case the `Dockerfile` has changed) the correspo ### Building -Distribution of the middleware is done in the form of `.tgz` archives containing the binaries - main file and dependencies -, which are first built using the python tool [pyinstaller](https://www.pyinstaller.org/) and then packed for distribution. Scripts for building binaries for each main tool can be found under the `middleware/build` directory. These scripts place the output under the `middleware/bin` directory. There are also two scripts that are shorthand for serial building: +Distribution of the middleware is done in the form of `.tgz` archives containing the binaries - main file and dependencies -, which are first built using the python tool [pyinstaller](https://www.pyinstaller.org/) and then packed for distribution. Scripts for building binaries for each main tool can be found under the `middleware/build` directory. These scripts place the output under the `middleware/bin` directory. There are also three scripts that are shorthand for serial building: - `middleware/build/all`: builds all the tools. -- `middleware/build/dist`: builds all the tools that are meant for distribution. +- `middleware/build/dist_ledger`: builds all the tools that are meant for Ledger distribution. +- `middleware/build/dist_sgx`: builds all the tools that are meant for SGX distribution. Within the same docker image, utility builds are bytewise reproducible. From bd71e316c5ea83dfc29087412bd08b6603618ec2 Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:59:14 -0300 Subject: [PATCH 09/50] Added unit tests for secret_store module (#206) - Added secret store unit tests - Minor changes to secret_store.c to allow for easier unit testing - Removed mock files from test coverage report --- firmware/coverage/gen-coverage | 3 +- .../src/hal/sgx/src/trusted/secret_store.c | 6 - firmware/src/hal/sgx/test/common/common.mk | 2 +- firmware/src/hal/sgx/test/mock/hsm_t.h | 47 ++ firmware/src/hal/sgx/test/mock/mock.h | 2 + firmware/src/hal/sgx/test/mock/mock_ocall.c | 124 +++++ firmware/src/hal/sgx/test/mock/mock_ocall.h | 82 ++++ firmware/src/hal/sgx/test/mock/mock_seal.c | 167 +++++++ firmware/src/hal/sgx/test/mock/mock_seal.h | 98 ++++ .../src/hal/sgx/test/mock/mock_secret_store.c | 24 + .../hal/sgx/test/mock/openenclave/common.h | 35 ++ .../test/mock/openenclave/corelibc/stdlib.h | 30 ++ .../src/hal/sgx/test/mock/openenclave/seal.h | 58 +++ firmware/src/hal/sgx/test/run-all.sh | 2 +- .../src/hal/sgx/test/secret_store/Makefile | 38 ++ .../sgx/test/secret_store/test_secret_store.c | 455 ++++++++++++++++++ 16 files changed, 1164 insertions(+), 9 deletions(-) create mode 100644 firmware/src/hal/sgx/test/mock/hsm_t.h create mode 100644 firmware/src/hal/sgx/test/mock/mock_ocall.c create mode 100644 firmware/src/hal/sgx/test/mock/mock_ocall.h create mode 100644 firmware/src/hal/sgx/test/mock/mock_seal.c create mode 100644 firmware/src/hal/sgx/test/mock/mock_seal.h create mode 100644 firmware/src/hal/sgx/test/mock/openenclave/common.h create mode 100644 firmware/src/hal/sgx/test/mock/openenclave/corelibc/stdlib.h create mode 100644 firmware/src/hal/sgx/test/mock/openenclave/seal.h create mode 100644 firmware/src/hal/sgx/test/secret_store/Makefile create mode 100644 firmware/src/hal/sgx/test/secret_store/test_secret_store.c diff --git a/firmware/coverage/gen-coverage b/firmware/coverage/gen-coverage index 4fd85d76..d4a647b1 100755 --- a/firmware/coverage/gen-coverage +++ b/firmware/coverage/gen-coverage @@ -33,10 +33,11 @@ if [[ $1 == "exec" ]]; then # Capture coverage data lcov --capture --directory $SRCDIR --list-full-path --output-file $BASEDIR/coverage.info - # Remove unwanted coverage info (test files, tcpsigner, x86 HAL implementation) + # Remove unwanted coverage info (test files, tcpsigner, x86 HAL implementation, mock files) lcov --remove $BASEDIR/coverage.info "*/test_*.c" --output-file $BASEDIR/coverage.info lcov --remove $BASEDIR/coverage.info "*/tcpsigner/src/*" --output-file $BASEDIR/coverage.info lcov --remove $BASEDIR/coverage.info "*/hal/src/x86/*" --output-file $BASEDIR/coverage.info + lcov --remove $BASEDIR/coverage.info "*/mock_*.c" --output-file $BASEDIR/coverage.info # Generate report and summary genhtml $BASEDIR/coverage.info --output $BASEDIR/output -p $SRCDIR -t "powHSM firmware" lcov --summary $BASEDIR/coverage.info | grep lines | sed -e "s/.\+lines.\+: \([[:digit:].]\+\).\+/\1/g" > $BASEDIR/output/total diff --git a/firmware/src/hal/sgx/src/trusted/secret_store.c b/firmware/src/hal/sgx/src/trusted/secret_store.c index 427b3e29..ebea7f77 100644 --- a/firmware/src/hal/sgx/src/trusted/secret_store.c +++ b/firmware/src/hal/sgx/src/trusted/secret_store.c @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -75,11 +74,6 @@ static uint8_t unseal_data(const sealed_secret_t* sealed_secret, uint8_t* dest, size_t dest_length) { #ifndef SIM_BUILD - if (sealed_secret->blob_size > MAX_BLOB_SIZE) { - LOG("Sealed blob size is too large\n"); - goto unseal_data_error; - } - uint8_t* plaintext = NULL; size_t plaintext_size = 0; oe_result_t result = oe_unseal(sealed_secret->blob, diff --git a/firmware/src/hal/sgx/test/common/common.mk b/firmware/src/hal/sgx/test/common/common.mk index 71522536..eb2f23f7 100644 --- a/firmware/src/hal/sgx/test/common/common.mk +++ b/firmware/src/hal/sgx/test/common/common.mk @@ -27,7 +27,7 @@ TESTCOMMONDIR = ../common CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function CFLAGS += -iquote $(SRCDIR) -iquote $(HALINCDIR) CFLAGS += -iquote $(TESTCOMMONDIR) -CFLAGS += -iquote $(MOCKDIR) +CFLAGS += -I$(MOCKDIR) CFLAGS += -DHSM_PLATFORM_SGX VPATH += $(MOCKDIR):$(SRCDIR) diff --git a/firmware/src/hal/sgx/test/mock/hsm_t.h b/firmware/src/hal/sgx/test/mock/hsm_t.h new file mode 100644 index 00000000..5f639f43 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/hsm_t.h @@ -0,0 +1,47 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCK_HSM_T_H +#define __MOCK_HSM_T_H + +#include +#include +#include +#include "openenclave/common.h" + +oe_result_t ocall_kvstore_save(bool* _retval, + char* key, + uint8_t* data, + size_t data_size); + +oe_result_t ocall_kvstore_exists(bool* _retval, char* key); + +oe_result_t ocall_kvstore_get(size_t* _retval, + char* key, + uint8_t* data_buf, + size_t buffer_size); + +oe_result_t ocall_kvstore_remove(bool* _retval, char* key); + +#endif // __MOCK_HSM_T_H \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/mock.h b/firmware/src/hal/sgx/test/mock/mock.h index c263ce1b..1cd47890 100644 --- a/firmware/src/hal/sgx/test/mock/mock.h +++ b/firmware/src/hal/sgx/test/mock/mock.h @@ -26,5 +26,7 @@ #define __MOCK_H #include "mock_secret_store.h" +#include "mock_seal.h" +#include "mock_ocall.h" #endif // #ifndef __MOCK_H diff --git a/firmware/src/hal/sgx/test/mock/mock_ocall.c b/firmware/src/hal/sgx/test/mock/mock_ocall.c new file mode 100644 index 00000000..24a05e7c --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/mock_ocall.c @@ -0,0 +1,124 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include "assert_utils.h" +#include "openenclave/common.h" +#include "mock_ocall.h" + +// Trivial key-value store implementation for testing purposes +// This key-value store is only capable of storing a single key-value pair +#define MOCK_KVSTORE_MAX_KEY_SIZE (256) +#define MOCK_KVSTORE_MAX_DATA_SIZE (2 * 1024 * 1024) +static char G_kvstore_key[MOCK_KVSTORE_MAX_KEY_SIZE]; +static uint8_t G_kvstore_data[MOCK_KVSTORE_MAX_DATA_SIZE]; +static size_t G_kvstore_data_size; +// The type of failure to simulate on the next call to the mock implementation +static mock_kvstore_failure_type_t G_next_failure; + +void mock_ocall_init() { + memset(G_kvstore_key, 0, sizeof(G_kvstore_key)); + memset(G_kvstore_data, 0, sizeof(G_kvstore_data)); + G_kvstore_data_size = 0; + G_next_failure = KVSTORE_FAILURE_NONE; +} + +oe_result_t mock_ocall_kvstore_save(bool* _retval, + char* key, + uint8_t* data, + size_t data_size) { + if (G_next_failure == KVSTORE_FAILURE_SAVE) { + G_next_failure = KVSTORE_FAILURE_NONE; + *_retval = false; + return OE_OK; + } else if (G_next_failure == KVSTORE_FAILURE_OE_FAILURE) { + G_next_failure = KVSTORE_FAILURE_NONE; + return OE_FAILURE; + } + + strcpy(G_kvstore_key, key); + assert(data_size <= sizeof(G_kvstore_data)); + memcpy(G_kvstore_data, data, data_size); + G_kvstore_data_size = data_size; + *_retval = true; + return OE_OK; +} + +oe_result_t mock_ocall_kvstore_exists(bool* _retval, char* key) { + if (G_next_failure == KVSTORE_FAILURE_OE_FAILURE) { + G_next_failure = KVSTORE_FAILURE_NONE; + return OE_FAILURE; + } + + *_retval = mock_ocall_kstore_key_exists(key); + return OE_OK; +} + +oe_result_t mock_ocall_kvstore_get(size_t* _retval, + char* key, + uint8_t* data_buf, + size_t buffer_size) { + if (G_next_failure == KVSTORE_FAILURE_OE_FAILURE) { + G_next_failure = KVSTORE_FAILURE_NONE; + return OE_FAILURE; + } + + if (strcmp(key, G_kvstore_key) == 0) { + *_retval = G_kvstore_data_size; + memcpy(data_buf, G_kvstore_data, G_kvstore_data_size); + } else { + *_retval = 0; + } + return OE_OK; +} + +oe_result_t mock_ocall_kvstore_remove(bool* _retval, char* key) { + if (G_next_failure == KVSTORE_FAILURE_OE_FAILURE) { + G_next_failure = KVSTORE_FAILURE_NONE; + return OE_FAILURE; + } + if (strcmp(key, G_kvstore_key) == 0) { + memset(G_kvstore_key, 0, sizeof(G_kvstore_key)); + memset(G_kvstore_data, 0, sizeof(G_kvstore_data)); + G_kvstore_data_size = 0; + *_retval = true; + } else { + *_retval = false; + } + return OE_OK; +} + +void mock_ocall_kvstore_fail_next(mock_kvstore_failure_type_t failure) { + G_next_failure = failure; +} + +void mock_ocall_kstore_assert_value(char* key, const uint8_t* value) { + ASSERT_STR_EQUALS(key, G_kvstore_key); + ASSERT_STR_EQUALS(value, G_kvstore_data); +} + +bool mock_ocall_kstore_key_exists(char* key) { + return (strcmp(key, G_kvstore_key) == 0); +} diff --git a/firmware/src/hal/sgx/test/mock/mock_ocall.h b/firmware/src/hal/sgx/test/mock/mock_ocall.h new file mode 100644 index 00000000..afefa187 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/mock_ocall.h @@ -0,0 +1,82 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCK_OCALL_H +#define __MOCK_OCALL_H + +#include +#include +#include +#include "openenclave/common.h" + +// Types of failures that can be simulated in this mock implementation +typedef enum mock_kvstore_failure_type { + KVSTORE_FAILURE_NONE, + KVSTORE_FAILURE_SAVE, + KVSTORE_FAILURE_OE_FAILURE, +} mock_kvstore_failure_type_t; + +/** + * @brief Initializes the mock ocall implementation + */ +void mock_ocall_init(); + +/** + * @brief Mock implementation of ocall_kvstore_save + */ +oe_result_t mock_ocall_kvstore_save(bool* _retval, + char* key, + uint8_t* data, + size_t data_size); + +/** + * @brief Mock implementation of ocall_kvstore_exists + */ +oe_result_t mock_ocall_kvstore_exists(bool* _retval, char* key); + +/** + * @brief Mock implementation of ocall_kvstore_get + */ +oe_result_t mock_ocall_kvstore_get(size_t* _retval, + char* key, + uint8_t* data_buf, + size_t buffer_size); + +/** + * @brief Mock implementation of ocall_kvstore_remove + */ +oe_result_t mock_ocall_kvstore_remove(bool* _retval, char* key); + +/** + * @brief Simulates a failure on the next call to this mock implementation + * + * @param failure the type of failure to simulate + */ +void mock_ocall_kvstore_fail_next(mock_kvstore_failure_type_t failure); + +void mock_ocall_kstore_assert_value(char* key, const uint8_t* value); + +bool mock_ocall_kstore_key_exists(char* key); + +#endif // __MOCK_OCALL_H \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/mock_seal.c b/firmware/src/hal/sgx/test/mock/mock_seal.c new file mode 100644 index 00000000..88decc16 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/mock_seal.c @@ -0,0 +1,167 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include "mock_seal.h" +#include "assert_utils.h" + +// A prefix added to sealed blobs in this mock implementation. +// This is just to keep things simple and easily distinguishable. +#define SEALED_PREFIX "SEALED - " + +// Captures the arguments passed to oe_seal +typedef struct oe_seal_args { + const void* plugin_id; + oe_seal_setting_t settings; + size_t settings_count; + const uint8_t* plaintext; + size_t plaintext_size; + const uint8_t* additional_data; + size_t additional_data_size; +} oe_seal_args_t; + +// Captures the arguments passed to oe_unseal +typedef struct oe_unseal_args { + uint8_t blob[BUFSIZ]; + size_t blob_size; + const uint8_t* additional_data; + size_t additional_data_size; +} oe_unseal_args_t; + +// Global variables to capture the arguments passed to oe_seal and oe_unseal +static oe_seal_args_t G_oe_seal_args; +static oe_unseal_args_t G_oe_unseal_args; +// Simulates a OE_FAILURE in the next call to this mock implementation +static bool G_fail_next = false; + +void mock_seal_init() { + memset(&G_oe_seal_args, 0, sizeof(G_oe_seal_args)); + memset(&G_oe_unseal_args, 0, sizeof(G_oe_unseal_args)); + G_fail_next = false; +} + +oe_result_t mock_oe_seal(const void* plugin_id, + const oe_seal_setting_t* settings, + size_t settings_count, + const uint8_t* plaintext, + size_t plaintext_size, + const uint8_t* additional_data, + size_t additional_data_size, + uint8_t** blob, + size_t* blob_size) { + G_oe_seal_args.plugin_id = plugin_id; + memcpy(&G_oe_seal_args.settings, settings, sizeof(oe_seal_setting_t)); + G_oe_seal_args.settings_count = settings_count; + G_oe_seal_args.plaintext = plaintext; + G_oe_seal_args.plaintext_size = plaintext_size; + G_oe_seal_args.additional_data = additional_data; + G_oe_seal_args.additional_data_size = additional_data_size; + + if (G_fail_next) { + G_fail_next = false; + return OE_FAILURE; + } + + size_t prefix_length = strlen(SEALED_PREFIX); + *blob_size = plaintext_size + prefix_length; + *blob = malloc(*blob_size); + assert(*blob != NULL); + memcpy(*blob, SEALED_PREFIX, prefix_length); + memcpy(*blob + prefix_length, plaintext, plaintext_size); + + return OE_OK; +} + +oe_result_t mock_oe_unseal(const uint8_t* blob, + size_t blob_size, + const uint8_t* additional_data, + size_t additional_data_size, + uint8_t** plaintext, + size_t* plaintext_size) { + memcpy(G_oe_unseal_args.blob, blob, blob_size); + G_oe_unseal_args.blob_size = blob_size; + G_oe_unseal_args.additional_data = additional_data; + G_oe_unseal_args.additional_data_size = additional_data_size; + + if (G_fail_next) { + G_fail_next = false; + return OE_FAILURE; + } + + *plaintext_size = blob_size - strlen(SEALED_PREFIX); + *plaintext = malloc(*plaintext_size); + assert(*plaintext != NULL); + memcpy(*plaintext, blob + strlen(SEALED_PREFIX), *plaintext_size); + + return OE_OK; +} + +void assert_oe_seal_called_with(const void* plugin_id, + const oe_seal_setting_t* settings, + size_t settings_count, + const uint8_t* plaintext, + size_t plaintext_size, + const uint8_t* additional_data, + size_t additional_data_size) { + assert(G_oe_seal_args.plugin_id == plugin_id && + memcmp(&G_oe_seal_args.settings, settings, sizeof(*settings)) == 0 && + G_oe_seal_args.settings_count == settings_count && + G_oe_seal_args.plaintext == plaintext && + G_oe_seal_args.plaintext_size == plaintext_size && + G_oe_seal_args.additional_data == additional_data && + G_oe_seal_args.additional_data_size == additional_data_size); +} + +void assert_oe_unseal_called_with(const uint8_t* blob, + size_t blob_size, + const uint8_t* additional_data, + size_t additional_data_size) { + assert((memcmp(blob, G_oe_unseal_args.blob, blob_size) == 0) && + G_oe_unseal_args.blob_size == blob_size && + G_oe_unseal_args.additional_data == additional_data && + G_oe_unseal_args.additional_data_size == additional_data_size); +} + +void assert_oe_unseal_not_called() { + ASSERT_ARRAY_CLEARED(G_oe_unseal_args.blob); + assert(G_oe_unseal_args.blob_size == 0); + assert(G_oe_unseal_args.additional_data == NULL); + assert(G_oe_unseal_args.additional_data_size == 0); +} + +void assert_oe_seal_not_called() { + assert(G_oe_seal_args.plugin_id == NULL); + assert(G_oe_seal_args.settings.policy == 0); + assert(G_oe_seal_args.settings_count == 0); + assert(G_oe_seal_args.plaintext == NULL); + assert(G_oe_seal_args.plaintext_size == 0); + assert(G_oe_seal_args.additional_data == NULL); + assert(G_oe_seal_args.additional_data_size == 0); +} + +void mock_seal_fail_next() { + G_fail_next = true; +} diff --git a/firmware/src/hal/sgx/test/mock/mock_seal.h b/firmware/src/hal/sgx/test/mock/mock_seal.h new file mode 100644 index 00000000..cc968565 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/mock_seal.h @@ -0,0 +1,98 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCK_SEAL_H +#define __MOCK_SEAL_H + +#include +#include +#include +#include "openenclave/common.h" +#include "openenclave/seal.h" + +/** + * @brief Initializes the mock seal implementation + */ +void mock_seal_init(); + +/** + * @brief Mock implementation of oe_seal API function + */ +oe_result_t mock_oe_seal(const void* plugin_id, + const oe_seal_setting_t* settings, + size_t settings_count, + const uint8_t* plaintext, + size_t plaintext_size, + const uint8_t* additional_data, + size_t additional_data_size, + uint8_t** blob, + size_t* blob_size); + +/** + * @brief Mock implementation of oe_unseal API function + */ +oe_result_t mock_oe_unseal(const uint8_t* blob, + size_t blob_size, + const uint8_t* additional_data, + size_t additional_data_size, + uint8_t** plaintext, + size_t* plaintext_size); + +/** + * @brief Asserts that the last call to oe_seal was made with the expected + * parameters + */ +void assert_oe_seal_called_with(const void* plugin_id, + const oe_seal_setting_t* settings, + size_t settings_count, + const uint8_t* plaintext, + size_t plaintext_size, + const uint8_t* additional_data, + size_t additional_data_size); + +/** + * @brief Asserts that the last call to oe_unseal was made with the expected + * parameters + */ +void assert_oe_unseal_called_with(const uint8_t* blob, + size_t blob_size, + const uint8_t* additional_data, + size_t additional_data_size); + +/** + * @brief Asserts that oe_unseal was not called since the mock was initialized + */ +void assert_oe_unseal_not_called(); + +/** + * @brief Asserts that oe_seal was not called since the mock was initialized + */ +void assert_oe_seal_not_called(); + +/** + * @brief Simulates a failure on the next call to this mock implementation + */ +void mock_seal_fail_next(); + +#endif // #ifndef __MOCK_SEAL_H diff --git a/firmware/src/hal/sgx/test/mock/mock_secret_store.c b/firmware/src/hal/sgx/test/mock/mock_secret_store.c index 6fa2fd7d..0239b873 100644 --- a/firmware/src/hal/sgx/test/mock/mock_secret_store.c +++ b/firmware/src/hal/sgx/test/mock/mock_secret_store.c @@ -1,3 +1,27 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + #include #include #include diff --git a/firmware/src/hal/sgx/test/mock/openenclave/common.h b/firmware/src/hal/sgx/test/mock/openenclave/common.h new file mode 100644 index 00000000..54a3fc35 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/common.h @@ -0,0 +1,35 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCK_OE_COMMON_H +#define __MOCK_OE_COMMON_H + +typedef enum oe_result { + OE_OK, + OE_FAILURE, +} oe_result_t; + +#define oe_result_str(result) ((result) == OE_OK ? "OE_OK" : "OE_FAILURE") + +#endif // #ifndef __MOCK_OE_COMMON_H \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/openenclave/corelibc/stdlib.h b/firmware/src/hal/sgx/test/mock/openenclave/corelibc/stdlib.h new file mode 100644 index 00000000..482a7661 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/corelibc/stdlib.h @@ -0,0 +1,30 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCK_OE_STDLIB_H +#define __MOCK_OE_STDLIB_H + +#define oe_free(ptr) free(ptr) + +#endif // #ifndef __MOCK_OE_STDLIB_H \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/openenclave/seal.h b/firmware/src/hal/sgx/test/mock/openenclave/seal.h new file mode 100644 index 00000000..21e3d657 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/seal.h @@ -0,0 +1,58 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCK_OE_SEAL_H +#define __MOCK_OE_SEAL_H + +#include +#include +#include "common.h" + +// Simplified version of the seal settings type. This is only used to ensure +// that the API was called with the expected parameters. +typedef struct { + int policy; +} oe_seal_setting_t; + +#define OE_SEAL_SET_POLICY(policy) \ + { (int)(policy) } + +oe_result_t oe_seal(const void* plugin_id, + const oe_seal_setting_t* settings, + size_t settings_count, + const uint8_t* plaintext, + size_t plaintext_size, + const uint8_t* additional_data, + size_t additional_data_size, + uint8_t** blob, + size_t* blob_size); + +oe_result_t oe_unseal(const uint8_t* blob, + size_t blob_size, + const uint8_t* additional_data, + size_t additional_data_size, + uint8_t** plaintext, + size_t* plaintext_size); + +#endif // #ifndef __MOCK_OE_SEAL_H \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/run-all.sh b/firmware/src/hal/sgx/test/run-all.sh index 2a4217fe..8a7c782d 100755 --- a/firmware/src/hal/sgx/test/run-all.sh +++ b/firmware/src/hal/sgx/test/run-all.sh @@ -1,6 +1,6 @@ #!/bin/bash BASEDIR=$(dirname $0) -TESTDIRS="nvmem" +TESTDIRS="nvmem secret_store" TESTDIRS=${1:-"$TESTDIRS"} for d in $TESTDIRS; do diff --git a/firmware/src/hal/sgx/test/secret_store/Makefile b/firmware/src/hal/sgx/test/secret_store/Makefile new file mode 100644 index 00000000..4ed0fb95 --- /dev/null +++ b/firmware/src/hal/sgx/test/secret_store/Makefile @@ -0,0 +1,38 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +PROG = test.out +OBJS = secret_store.o test_secret_store.o platform.o mock_seal.o mock_ocall.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) *.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/hal/sgx/test/secret_store/test_secret_store.c b/firmware/src/hal/sgx/test/secret_store/test_secret_store.c new file mode 100644 index 00000000..51e9a919 --- /dev/null +++ b/firmware/src/hal/sgx/test/secret_store/test_secret_store.c @@ -0,0 +1,455 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "assert_utils.h" +#include "secret_store.h" +#include "mock_seal.h" +#include "mock_ocall.h" + +// Error code for the sest API as defined in secret_store.c +#define SEST_ERROR (0) +// The maximum value that can be returned by sest_read +#define MAX_SEST_READ_SIZE (255) +// The maximum blob_size for a sealed secret, as defined in secret_store.c +#define MAX_BLOB_SIZE (1024 * 1024) +// Utility macro that converts a plaintext secret into the sealed version +#define SEALED(str) ("SEALED - " str) + +// Hand over the seal API calls to the mock implementation +oe_result_t oe_seal(const void* plugin_id, + const oe_seal_setting_t* settings, + size_t settings_count, + const uint8_t* plaintext, + size_t plaintext_size, + const uint8_t* additional_data, + size_t additional_data_size, + uint8_t** blob, + size_t* blob_size) { + return mock_oe_seal(plugin_id, + settings, + settings_count, + plaintext, + plaintext_size, + additional_data, + additional_data_size, + blob, + blob_size); +} + +oe_result_t oe_unseal(const uint8_t* blob, + size_t blob_size, + const uint8_t* additional_data, + size_t additional_data_size, + uint8_t** plaintext, + size_t* plaintext_size) { + return mock_oe_unseal(blob, + blob_size, + additional_data, + additional_data_size, + plaintext, + plaintext_size); +} + +// Hand over the kvstore calls to the mock implementation +oe_result_t ocall_kvstore_save(bool* _retval, + char* key, + uint8_t* data, + size_t data_size) { + return mock_ocall_kvstore_save(_retval, key, data, data_size); +} + +oe_result_t ocall_kvstore_exists(bool* _retval, char* key) { + return mock_ocall_kvstore_exists(_retval, key); +} + +oe_result_t ocall_kvstore_get(size_t* _retval, + char* key, + uint8_t* data_buf, + size_t buffer_size) { + return mock_ocall_kvstore_get(_retval, key, data_buf, buffer_size); +} + +oe_result_t ocall_kvstore_remove(bool* _retval, char* key) { + return mock_ocall_kvstore_remove(_retval, key); +} + +// Helper functions +void save_to_mock_kvstore(char* key, uint8_t* value, size_t value_size) { + bool save_success = false; + mock_ocall_kvstore_save(&save_success, key, value, value_size); + mock_ocall_kstore_assert_value(key, value); + assert(save_success); +} + +void setup() { + mock_seal_init(); + mock_ocall_init(); + assert(sest_init()); +} + +// Test cases +void test_secret_exists_after_write() { + setup(); + printf("Test secret exists after write...\n"); + + char* key = "key"; + uint8_t secret[] = "secret"; + uint8_t sealed_secret[] = SEALED("secret"); + // Ensure the secret doesn't exist before the write + assert(!sest_exists(key)); + assert(!mock_ocall_kstore_key_exists(key)); + // Write the secret and ensure it now exists + assert(sest_write(key, secret, sizeof(secret))); + assert_oe_seal_called_with( + NULL, + (const oe_seal_setting_t[]){OE_SEAL_SET_POLICY(1)}, + 1, + secret, + sizeof(secret), + NULL, + 0); + mock_ocall_kstore_assert_value(key, sealed_secret); + assert(sest_exists(key)); +} + +void test_write_and_retrieve_secret() { + setup(); + printf("Test write and retrieve secret...\n"); + + char* key = "key"; + uint8_t secret[] = "secret"; + uint8_t sealed_secret[] = SEALED("secret"); + // Write the secret and make sure the seal API is called with the correct + // arguments + assert(sest_write(key, secret, sizeof(secret))); + assert_oe_seal_called_with( + NULL, + (const oe_seal_setting_t[]){OE_SEAL_SET_POLICY(1)}, + 1, + secret, + sizeof(secret), + NULL, + 0); + mock_ocall_kstore_assert_value(key, sealed_secret); + // Retrieve the secret and make sure the unseal API is called with the + // correct arguments + uint8_t retrieved[MAX_SEST_READ_SIZE]; + uint8_t retrieved_length = sest_read(key, retrieved, sizeof(retrieved)); + assert_oe_unseal_called_with(sealed_secret, sizeof(sealed_secret), NULL, 0); + assert(retrieved_length == sizeof(secret)); + ASSERT_MEMCMP(retrieved, secret, retrieved_length); +} + +void test_write_and_remove_secret() { + setup(); + printf("Test write and remove secret...\n"); + + char* key = "key"; + uint8_t secret[] = "secret"; + uint8_t sealed_secret[] = SEALED("secret"); + assert(sest_write(key, secret, sizeof(secret))); + assert_oe_seal_called_with( + NULL, + (const oe_seal_setting_t[]){OE_SEAL_SET_POLICY(1)}, + 1, + secret, + sizeof(secret), + NULL, + 0); + mock_ocall_kstore_assert_value(key, sealed_secret); + assert(sest_exists(key)); + assert(sest_remove(key)); + assert(!sest_exists(key)); + assert(!mock_ocall_kstore_key_exists(key)); +} + +void test_exists_fails_when_kvstore_exists_fails() { + setup(); + printf("Test sest_exists fails when ocall_kvstore_exists fails...\n"); + + // Write a valid secret to the kvstore and ensure it exists + char* key = "key"; + uint8_t sealed_secret[] = SEALED("secret"); + save_to_mock_kvstore(key, sealed_secret, sizeof(sealed_secret)); + assert(sest_exists(key)); + + // Force the next call to ocall_kvstore_exists to fail + mock_ocall_kvstore_fail_next(KVSTORE_FAILURE_OE_FAILURE); + assert(!sest_exists(key)); +} + +void test_read_fails_when_oe_unseal_fails() { + setup(); + printf("Test read fails when oe_unseal fails (OE_FAILURE)...\n"); + + // Write a valid secret to the kvstore and ensure it exists + char* key = "key"; + uint8_t sealed_secret[] = SEALED("secret"); + save_to_mock_kvstore(key, sealed_secret, sizeof(sealed_secret)); + assert(sest_exists(key)); + + // Force the next call to oe_unseal to fail with OE_FAILURE + mock_seal_fail_next(); + uint8_t retrieved[MAX_SEST_READ_SIZE]; + memset(retrieved, 0, sizeof(retrieved)); + uint8_t retrieved_length = sest_read(key, retrieved, sizeof(retrieved)); + assert_oe_unseal_called_with(sealed_secret, sizeof(sealed_secret), NULL, 0); + assert(retrieved_length == SEST_ERROR); + ASSERT_ARRAY_CLEARED(retrieved); +} + +void test_read_fails_when_plaintext_is_too_large() { + setup(); + printf("Test read fails when unsealed secret is too large...\n"); + + // Write a valid secret to the kvstore and ensure it exists + char* key = "key"; + uint8_t secret[] = "secret"; + uint8_t sealed_secret[] = SEALED("secret"); + save_to_mock_kvstore(key, sealed_secret, sizeof(sealed_secret)); + assert(sest_exists(key)); + // The retrieved buffer is one byte too short to fit the original secret + uint8_t retrieved[sizeof(secret) - 1]; + memset(retrieved, 0, sizeof(retrieved)); + uint8_t retrieved_length = sest_read(key, retrieved, sizeof(retrieved)); + assert_oe_unseal_called_with(sealed_secret, sizeof(sealed_secret), NULL, 0); + assert(retrieved_length == SEST_ERROR); + ASSERT_ARRAY_CLEARED(retrieved); +} + +void test_write_zero_length_secret_fails() { + setup(); + printf("Test write zero length secret fails...\n"); + + char* key = "key"; + // Ensure the secret doesn't exist before the write + assert(!sest_exists(key)); + assert(!mock_ocall_kstore_key_exists(key)); + // Write the secret and ensure it fails + assert(!sest_write(key, NULL, 0)); + // Make sure the seal API was never reached + assert_oe_seal_not_called(); + assert(!sest_exists(key)); + assert(!mock_ocall_kstore_key_exists(key)); +} + +void test_write_fails_when_oe_seal_fails() { + setup(); + printf("Test write fails when oe_seal fails (OE_FAILURE)...\n"); + + // Force the next call to oe_seal to fail + mock_seal_fail_next(); + char* key = "key"; + uint8_t secret[] = "secret"; + assert(!sest_exists(key)); + assert(!sest_write(key, secret, sizeof(secret))); + assert_oe_seal_called_with( + NULL, + (const oe_seal_setting_t[]){OE_SEAL_SET_POLICY(1)}, + 1, + secret, + sizeof(secret), + NULL, + 0); + assert(!sest_exists(key)); + assert(!mock_ocall_kstore_key_exists(key)); +} + +void test_write_fails_when_kvstore_save_fails() { + setup(); + printf("Test write fails when ocall_kvstore_save fails...\n"); + + char* key = "key"; + uint8_t secret[] = "secret"; + assert(!sest_exists(key)); + // Force the next call to ocall_kvstore_save to fail + mock_ocall_kvstore_fail_next(KVSTORE_FAILURE_SAVE); + assert(!sest_write(key, secret, sizeof(secret))); + assert_oe_seal_called_with( + NULL, + (const oe_seal_setting_t[]){OE_SEAL_SET_POLICY(1)}, + 1, + secret, + sizeof(secret), + NULL, + 0); + assert(!sest_exists(key)); + assert(!mock_ocall_kstore_key_exists(key)); +} + +void test_write_fails_when_kvstore_save_fails_oe_failure() { + setup(); + printf("Test write fails when ocall_kvstore_save fails (OE_FAILURE)...\n"); + + char* key = "key"; + uint8_t secret[] = "secret"; + assert(!sest_exists(key)); + // Force the next call to ocall_kvstore_save to fail with OE_FAILURE + mock_ocall_kvstore_fail_next(KVSTORE_FAILURE_OE_FAILURE); + assert(!sest_write(key, secret, sizeof(secret))); + assert_oe_seal_called_with( + NULL, + (const oe_seal_setting_t[]){OE_SEAL_SET_POLICY(1)}, + 1, + secret, + sizeof(secret), + NULL, + 0); + assert(!sest_exists(key)); + assert(!mock_ocall_kstore_key_exists(key)); +} + +void test_write_fails_when_secret_too_large() { + setup(); + printf("Test write fails when secret is too large...\n"); + + // Attempt to write a secret that is too large + char* key = "key"; + size_t secret_size = MAX_BLOB_SIZE + 1; + uint8_t secret[secret_size]; + assert(!sest_exists(key)); + assert(!sest_write(key, secret, secret_size)); + assert_oe_seal_called_with( + NULL, + (const oe_seal_setting_t[]){OE_SEAL_SET_POLICY(1)}, + 1, + secret, + secret_size, + NULL, + 0); + assert(!sest_exists(key)); + assert(!mock_ocall_kstore_key_exists(key)); +} + +void test_read_with_invalid_key_fails() { + setup(); + printf("Test read with invalid key fails...\n"); + + // Write a valid secret to the kvstore and ensure it exists + char* valid_key = "valid key"; + uint8_t sealed_secret[] = SEALED("secret"); + save_to_mock_kvstore(valid_key, sealed_secret, sizeof(sealed_secret)); + assert(sest_exists(valid_key)); + + char* invalid_key = "invalid key"; + uint8_t retrieved[MAX_SEST_READ_SIZE]; + uint8_t retrieved_length = + sest_read(invalid_key, retrieved, sizeof(retrieved)); + assert_oe_unseal_not_called(); + assert(retrieved_length == SEST_ERROR); +} + +void test_read_fails_when_kvstore_get_fails() { + setup(); + printf("Test read fails when ocall_kvstore_get fails (OE_FAILURE)...\n"); + + // Write a valid secret to the kvstore and ensure it exists + char* key = "key"; + uint8_t sealed_secret[] = SEALED("secret"); + save_to_mock_kvstore(key, sealed_secret, sizeof(sealed_secret)); + assert(sest_exists(key)); + + // Force OE_FAILURE on the next call to ocall_kvstore_get + mock_ocall_kvstore_fail_next(KVSTORE_FAILURE_OE_FAILURE); + uint8_t retrieved[MAX_SEST_READ_SIZE]; + memset(retrieved, 0, sizeof(retrieved)); + uint8_t retrieved_length = sest_read(key, retrieved, sizeof(retrieved)); + assert_oe_unseal_not_called(); + assert(retrieved_length == SEST_ERROR); + ASSERT_ARRAY_CLEARED(retrieved); +} + +void test_read_fails_when_blob_is_too_large() { + setup(); + printf("Test read fails sealed blob is too large...\n"); + + // Pre-load the kvstore with a secret that is larger than the maximum + // allowed blob size + char* key = "key"; + uint8_t secret[MAX_BLOB_SIZE + 1]; + save_to_mock_kvstore(key, secret, sizeof(secret)); + + assert(sest_exists(key)); + uint8_t retrieved[MAX_SEST_READ_SIZE]; + memset(retrieved, 0, sizeof(retrieved)); + uint8_t retrieved_length = sest_read(key, retrieved, sizeof(retrieved)); + assert_oe_unseal_not_called(); + assert(retrieved_length == SEST_ERROR); + ASSERT_ARRAY_CLEARED(retrieved); +} + +void test_remove_with_invalid_key_fails() { + setup(); + printf("Test remove invalid key fails...\n"); + + char* valid_key = "valid key"; + uint8_t sealed_secret[] = SEALED("secret"); + save_to_mock_kvstore(valid_key, sealed_secret, sizeof(sealed_secret)); + assert(sest_exists(valid_key)); + + char* invalid_key = "invalid key"; + assert(!sest_remove(invalid_key)); + // Make sure the valid key still exists + assert(sest_exists(valid_key)); + mock_ocall_kstore_assert_value(valid_key, sealed_secret); +} + +void test_remove_fails_when_kvstore_remove_fails() { + setup(); + printf("Test remove fails when ocall_kvstore_remove fails...\n"); + + char* key = "key"; + uint8_t sealed_secret[] = SEALED("secret"); + save_to_mock_kvstore(key, sealed_secret, sizeof(sealed_secret)); + assert(sest_exists(key)); + // Force the next call to ocall_kvstore_remove to fail + mock_ocall_kvstore_fail_next(KVSTORE_FAILURE_OE_FAILURE); + assert(!sest_remove(key)); + assert(sest_exists(key)); + mock_ocall_kstore_assert_value(key, sealed_secret); +} + +int main() { + test_secret_exists_after_write(); + test_write_and_retrieve_secret(); + test_write_and_remove_secret(); + test_write_zero_length_secret_fails(); + test_write_fails_when_oe_seal_fails(); + test_write_fails_when_secret_too_large(); + test_write_fails_when_kvstore_save_fails(); + test_write_fails_when_kvstore_save_fails_oe_failure(); + test_read_with_invalid_key_fails(); + test_read_fails_when_plaintext_is_too_large(); + test_read_fails_when_kvstore_get_fails(); + test_read_fails_when_blob_is_too_large(); + test_read_fails_when_oe_unseal_fails(); + test_exists_fails_when_kvstore_exists_fails(); + test_remove_with_invalid_key_fails(); + test_remove_fails_when_kvstore_remove_fails(); +} From b60a8d5b84a06a797419ddb893e74f82a1446f27 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Fri, 11 Oct 2024 02:18:28 +1300 Subject: [PATCH 10/50] Unit testing endian and keccak256 (#207) Unit testing endian and keccak256 modules --- firmware/src/hal/x86/test/endian/Makefile | 39 +++++ .../src/hal/x86/test/endian/test_endian.c | 60 +++++++ firmware/src/hal/x86/test/keccak256/Makefile | 38 +++++ .../hal/x86/test/keccak256/test_keccak256.c | 159 ++++++++++++++++++ firmware/src/hal/x86/test/run-all.sh | 2 +- 5 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 firmware/src/hal/x86/test/endian/Makefile create mode 100644 firmware/src/hal/x86/test/endian/test_endian.c create mode 100644 firmware/src/hal/x86/test/keccak256/Makefile create mode 100644 firmware/src/hal/x86/test/keccak256/test_keccak256.c diff --git a/firmware/src/hal/x86/test/endian/Makefile b/firmware/src/hal/x86/test/endian/Makefile new file mode 100644 index 00000000..6047e5ba --- /dev/null +++ b/firmware/src/hal/x86/test/endian/Makefile @@ -0,0 +1,39 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common.mk + +PROG = test.out +OBJS = test_endian.o endian.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test + +clean: + rm -f $(PROG) ./*.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/hal/x86/test/endian/test_endian.c b/firmware/src/hal/x86/test/endian/test_endian.c new file mode 100644 index 00000000..eb8e9ee1 --- /dev/null +++ b/firmware/src/hal/x86/test/endian/test_endian.c @@ -0,0 +1,60 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "endian.h" + +void assert_write_uint32_be(const uint32_t n, const uint8_t exp[]) { + uint8_t dest[sizeof(uint32_t)]; + + memset(dest, 0, sizeof(dest)); + write_uint32_be(dest, n); + + for (int i = 0; i < sizeof(dest); i++) { + assert(dest[i] == exp[i]); + } +} + +void test_write_uint32_be() { + printf("Testing write_uint32_be... "); + + assert_write_uint32_be(0xaabbccdd, + (const uint8_t[]){0xaa, 0xbb, 0xcc, 0xdd}); + + assert_write_uint32_be(0x44, (const uint8_t[]){0x0, 0x0, 0x0, 0x44}); + + assert_write_uint32_be(0x4455, (const uint8_t[]){0x0, 0x0, 0x44, 0x55}); + + assert_write_uint32_be(0x445566, (const uint8_t[]){0x0, 0x44, 0x55, 0x66}); + + printf("OK\n"); +} + +int main() { + test_write_uint32_be(); + return 0; +} diff --git a/firmware/src/hal/x86/test/keccak256/Makefile b/firmware/src/hal/x86/test/keccak256/Makefile new file mode 100644 index 00000000..acfdf22b --- /dev/null +++ b/firmware/src/hal/x86/test/keccak256/Makefile @@ -0,0 +1,38 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common.mk + +PROG = test.out +OBJS = test_keccak256.o keccak256.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) *.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/hal/x86/test/keccak256/test_keccak256.c b/firmware/src/hal/x86/test/keccak256/test_keccak256.c new file mode 100644 index 00000000..d410bf02 --- /dev/null +++ b/firmware/src/hal/x86/test/keccak256/test_keccak256.c @@ -0,0 +1,159 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "keccak256.h" + +#define KECCAK256_HASH_SIZE 32 + +void assert_keccak256(const uint8_t* data, + const uint16_t data_size, + const uint8_t* expected) { + SHA3_CTX ctx; + uint8_t hash[KECCAK256_HASH_SIZE]; + + keccak_init(&ctx); + keccak_update(&ctx, data, data_size); + keccak_final(&ctx, hash); + + printf("Expected hash: "); + for (int i = 0; i < KECCAK256_HASH_SIZE; i++) { + printf("%02x", expected[i]); + } + printf("\n"); + + printf("Computed hash: "); + for (int i = 0; i < KECCAK256_HASH_SIZE; i++) { + printf("%02x", hash[i]); + } + printf("\n"); + + assert(memcmp(hash, expected, KECCAK256_HASH_SIZE) == 0); +} + +int main() { + { + uint8_t data[] = { + 0xbd, 0x47, 0x7c, 0xdb, 0xd1, 0x03, 0xf2, 0xf3, 0xe1, 0xce, 0x10, + 0x0d, 0xe2, 0xc8, 0xd7, 0x59, 0xea, 0x55, 0xa9, 0xed, 0x16, 0xf7, + 0xe1, 0x07, 0xba, 0x75, 0x46, 0x52, 0x53, 0x4b, 0x42, 0x4c, 0x4f, + 0x43, 0x4b, 0x3a, 0x77, 0x87, 0xe3, 0xb6, 0xa2, 0x26, 0x24, 0x61, + 0x48, 0x66, 0xc2, 0x1d, 0xee, 0x14, 0x62, 0xcc, 0xa6, 0x7a, 0x82, + 0x0d, 0xae, 0xfc, 0x51, 0x34, 0x98, 0xdd, 0xe3, 0xf6, 0xc4, 0x70, + 0xc8, 0xa4, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, 0x2a, + 0x01, 0x00, 0x00, 0x00, 0x23, 0x21, 0x02, 0x98, 0x58, 0xd5, 0x67, + 0x01, 0xbf, 0x60, 0x7d, 0x66, 0xb5, 0x2a, 0xf1, 0xbe, 0x2b, 0xdb, + 0xeb, 0xc9, 0x06, 0xe4, 0x28, 0x89, 0xa7, 0x4a, 0x12, 0x44, 0x6e, + 0x94, 0x0a, 0x68, 0x40, 0xc8, 0x6a, 0xac, 0x00, 0x00, 0x00, 0x00, + }; + + uint8_t expected[] = { + 0x00, 0x70, 0x1a, 0x12, 0x0f, 0x86, 0x03, 0x52, 0x87, 0x3c, 0xa8, + 0x94, 0xb0, 0x25, 0xa0, 0x88, 0xed, 0x1d, 0x41, 0xb3, 0x84, 0xbe, + 0xaf, 0x3d, 0x1c, 0x18, 0xaf, 0xb9, 0x91, 0x83, 0x28, 0xfb, + }; + printf("Case 1:\n"); + assert_keccak256(data, sizeof(data), expected); + } + + { + uint8_t data[] = "thisisamessage"; + + uint8_t expected[] = {0x34, 0x8f, 0x3f, 0xcb, 0x24, 0x99, 0x30, 0x86, + 0x7d, 0x7c, 0x88, 0xdb, 0x8a, 0x47, 0xfa, 0x49, + 0xe5, 0x09, 0x0f, 0xbd, 0xbc, 0x1e, 0x8c, 0xcc, + 0x95, 0x06, 0x2a, 0x18, 0x4d, 0x41, 0xce, 0xa2}; + printf("Case 2:\n"); + assert_keccak256(data, sizeof(data) - 1, expected); + } + + { + uint8_t data[] = { + 0xf9, 0x02, 0x34, 0xa0, 0x8d, 0xa9, 0x6f, 0x21, 0x20, 0xc2, 0xc4, + 0x65, 0x39, 0x69, 0x77, 0x6a, 0xa2, 0x38, 0x82, 0x42, 0xc4, 0xd2, + 0x47, 0x62, 0x0d, 0x68, 0x66, 0xfe, 0xcf, 0x2a, 0x2b, 0x27, 0x7e, + 0x6b, 0xfd, 0x6c, 0xa0, 0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, + 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, + 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, + 0xd4, 0x93, 0x47, 0x94, 0x5b, 0x24, 0x27, 0x72, 0x9a, 0x74, 0x66, + 0x7f, 0x6c, 0xc9, 0xec, 0xe0, 0xb8, 0x50, 0x00, 0x4c, 0x1b, 0x75, + 0xc6, 0x36, 0xa0, 0x25, 0xa7, 0x98, 0x60, 0x13, 0x29, 0xc5, 0x54, + 0x7a, 0x96, 0x25, 0xb4, 0x21, 0x19, 0x6d, 0x6b, 0xcf, 0x2f, 0x4a, + 0x2b, 0x02, 0xe1, 0xf5, 0x04, 0xfe, 0xb0, 0xda, 0xeb, 0x4d, 0xaa, + 0xaf, 0x48, 0xa0, 0x98, 0x12, 0x48, 0x35, 0xd3, 0xfd, 0xb6, 0x38, + 0x8f, 0x0e, 0xc7, 0x85, 0x0f, 0xfb, 0xe2, 0xc2, 0x51, 0x8d, 0x6e, + 0x1a, 0x3c, 0x1b, 0x59, 0xce, 0x1c, 0x4a, 0xa8, 0x27, 0x43, 0x09, + 0xf9, 0xfb, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x82, 0x04, + 0xe2, 0x83, 0x67, 0xc2, 0x80, 0x80, 0x84, 0x5f, 0x35, 0xc0, 0x1f, + 0x92, 0xd1, 0x01, 0x8f, 0x50, 0x41, 0x50, 0x59, 0x52, 0x55, 0x53, + 0x2d, 0x65, 0x66, 0x61, 0x31, 0x61, 0x30, 0x64, 0x80, 0x00, 0x80, + 0x80, 0xb8, 0x50, 0x71, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xa5, 0xa4, 0xc1, 0x10, + 0x74, 0x6d, 0x62, 0x15, 0x31, 0x6f, 0xaf, 0x7c, 0x0c, 0xdd, 0x06, + 0x28, 0x16, 0x2b, 0xea, 0x46, 0xc7, 0x5d, 0xdb, 0x8b, 0x08, 0xb1, + 0x6a, 0xc0, 0xe4, 0x5a, 0x2d, 0x22, 0xc0, 0x35, 0x5f, 0xff, 0xff, + 0x7f, 0x21, 0x00, 0x00, 0x00, 0x06}; + + uint8_t expected[] = {0x98, 0x72, 0x8e, 0x67, 0x93, 0xf9, 0xe9, 0x55, + 0x7a, 0x42, 0xf1, 0x14, 0xb2, 0x55, 0x67, 0xb5, + 0x88, 0x46, 0xae, 0x68, 0xfa, 0xbf, 0xd7, 0x6a, + 0xd6, 0x24, 0xa6, 0x2b, 0x4f, 0x38, 0x57, 0xb8}; + printf("Case 3:\n"); + assert_keccak256(data, sizeof(data), expected); + } + + return 0; +} + diff --git a/firmware/src/hal/x86/test/run-all.sh b/firmware/src/hal/x86/test/run-all.sh index e7cc9829..1a466aa5 100755 --- a/firmware/src/hal/x86/test/run-all.sh +++ b/firmware/src/hal/x86/test/run-all.sh @@ -1,7 +1,7 @@ #!/bin/bash ROOTDIR=$(dirname $0)/../../../../.. TESTDIR=$(realpath $(dirname $0) --relative-to $ROOTDIR) -TESTDIRS="bip32 hmac_sha256" +TESTDIRS="bip32 endian hmac_sha256 keccak256" TESTDIRS=${1:-"$TESTDIRS"} for d in $TESTDIRS; do From c495d5e6eb21e82d5e6883381ae63468ea0aeaeb Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:22:44 -0300 Subject: [PATCH 11/50] Added unit tests for seed module (#209) --- .../src/hal/sgx/test/mock/mock_secret_store.c | 16 + .../src/hal/sgx/test/mock/mock_secret_store.h | 9 + firmware/src/hal/sgx/test/run-all.sh | 9 +- firmware/src/hal/sgx/test/seed/Makefile | 39 ++ firmware/src/hal/sgx/test/seed/test_seed.c | 424 ++++++++++++++++++ 5 files changed, 492 insertions(+), 5 deletions(-) create mode 100644 firmware/src/hal/sgx/test/seed/Makefile create mode 100644 firmware/src/hal/sgx/test/seed/test_seed.c diff --git a/firmware/src/hal/sgx/test/mock/mock_secret_store.c b/firmware/src/hal/sgx/test/mock/mock_secret_store.c index 0239b873..ec335678 100644 --- a/firmware/src/hal/sgx/test/mock/mock_secret_store.c +++ b/firmware/src/hal/sgx/test/mock/mock_secret_store.c @@ -102,6 +102,22 @@ uint8_t mock_sest_read(char *key, uint8_t *dest, size_t dest_length) { return 0; } +bool mock_sest_remove(char *key) { + for (size_t i = 0; i < g_mock_secret_store.num_registers; i++) { + if (strcmp(g_mock_secret_store.registers[i].key, key) == 0) { + free(g_mock_secret_store.registers[i].key); + free(g_mock_secret_store.registers[i].secret); + for (size_t j = i; j < g_mock_secret_store.num_registers - 1; j++) { + g_mock_secret_store.registers[j] = + g_mock_secret_store.registers[j + 1]; + } + g_mock_secret_store.num_registers--; + return true; + } + } + return false; +} + void mock_sest_init() { memset(&g_mock_secret_store, 0, sizeof(g_mock_secret_store)); } diff --git a/firmware/src/hal/sgx/test/mock/mock_secret_store.h b/firmware/src/hal/sgx/test/mock/mock_secret_store.h index 39e58510..d84918ec 100644 --- a/firmware/src/hal/sgx/test/mock/mock_secret_store.h +++ b/firmware/src/hal/sgx/test/mock/mock_secret_store.h @@ -71,6 +71,15 @@ bool mock_sest_write(char *key, uint8_t *secret, size_t secret_length); */ uint8_t mock_sest_read(char *key, uint8_t *dest, size_t dest_length); +/** + * @brief Mock implementation of sest_remove + * + * @param key the key for the secret + * + * @returns whether the secret was successfully removed + */ +bool mock_sest_remove(char *key); + /** * @brief Resets the mock secret store to its initial state */ diff --git a/firmware/src/hal/sgx/test/run-all.sh b/firmware/src/hal/sgx/test/run-all.sh index 8a7c782d..c7ce071e 100755 --- a/firmware/src/hal/sgx/test/run-all.sh +++ b/firmware/src/hal/sgx/test/run-all.sh @@ -1,13 +1,12 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="nvmem secret_store" +ROOTDIR=$(dirname $0)/../../../../.. +TESTDIR=$(realpath $(dirname $0) --relative-to $ROOTDIR) +TESTDIRS="nvmem secret_store seed" TESTDIRS=${1:-"$TESTDIRS"} for d in $TESTDIRS; do echo "******************************" echo "Testing $d..." echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null + $ROOTDIR/docker/mware/do-notty-nousb /hsm2/$TESTDIR/$d "make clean test" || exit $? done diff --git a/firmware/src/hal/sgx/test/seed/Makefile b/firmware/src/hal/sgx/test/seed/Makefile new file mode 100644 index 00000000..f1ee7d7a --- /dev/null +++ b/firmware/src/hal/sgx/test/seed/Makefile @@ -0,0 +1,39 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +PROG = test.out +OBJS = seed.o test_seed.o mock_secret_store.o log.o +LIBS = -lsecp256k1 + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ $(LIBS) + +.PHONY: clean test +clean: + rm -f $(PROG) *.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/hal/sgx/test/seed/test_seed.c b/firmware/src/hal/sgx/test/seed/test_seed.c new file mode 100644 index 00000000..a8a12897 --- /dev/null +++ b/firmware/src/hal/sgx/test/seed/test_seed.c @@ -0,0 +1,424 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include "assert_utils.h" +#include "hal/constants.h" +#include "hal/seed.h" +#include "bip32.h" +#include "mock.h" + +// The key used to store the seed in the secret store +#define SEST_SEED_KEY "seed" + +// The key pair that will be used throughout the tests +uint8_t G_privkey[PRIVATE_KEY_LENGTH] = { + 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}; + +uint8_t G_pubkey[PUBKEY_UNCMP_LENGTH] = { + 0x04, 0x6a, 0x04, 0xab, 0x98, 0xd9, 0xe4, 0x77, 0x4a, 0xd8, 0x06, + 0xe3, 0x02, 0xdd, 0xde, 0xb6, 0x3b, 0xea, 0x16, 0xb5, 0xcb, 0x5f, + 0x22, 0x3e, 0xe7, 0x74, 0x78, 0xe8, 0x61, 0xbb, 0x58, 0x3e, 0xb3, + 0x36, 0xb6, 0xfb, 0xcb, 0x60, 0xb5, 0xb3, 0xd4, 0xf1, 0x55, 0x1a, + 0xc4, 0x5e, 0x5f, 0xfc, 0x49, 0x36, 0x46, 0x6e, 0x7d, 0x98, 0xf6, + 0xc7, 0xc0, 0xec, 0x73, 0x65, 0x39, 0xf7, 0x46, 0x91, 0xa6}; + +// This is the only path that will generate a valid private key +uint32_t G_valid_path[] = {0x8000002c, 0x80000000, 0x80000000, 0, 0}; + +// A fixed client seed that will be used throughout the tests +uint8_t G_client_seed[SEED_LENGTH] = { + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb}; + +// The hash256 of the string "a-test-message", used to test seed_sign +uint8_t G_hash[HASH_LENGTH] = {0xb4, 0xeb, 0x5c, 0xa8, 0xd8, 0x05, 0x33, 0xa2, + 0xec, 0xc1, 0x32, 0xd9, 0xaf, 0x5e, 0x96, 0x95, + 0x34, 0xe7, 0x2e, 0xa5, 0xb2, 0xd9, 0x9f, 0x99, + 0xf0, 0x0a, 0xb4, 0x0b, 0x60, 0x5a, 0xc6, 0x7b}; + +// A buffer containing the random bytes that will be used to generate the seed +// This buffer is overwritten for each test +uint8_t G_random_buffer[SEED_LENGTH]; +// See setup() for the computaion of the valid seed +// A distinct valid seed is generated for each test +uint8_t G_valid_seed[SEED_LENGTH]; +// Injects an error in the next call to random_getrandom +bool G_getrandom_fail_next = false; +// Forces the next call to bip32_derive_private to return success, even if the +// derived private key is invalid +bool G_force_derive_private_success = false; + +// Mock implementations +bool bip32_derive_private(uint8_t *out, + const uint8_t *seed, + const unsigned int seed_length, + const uint32_t *path, + const unsigned int path_length) { + assert(out != NULL); + assert(path != NULL); + assert(path_length > 0); + assert(seed_length == SEED_LENGTH); + ASSERT_MEMCMP(seed, G_valid_seed, seed_length); + + // If the provided path is exactly the same as the expected, the valid + // private key is generated. Otherwise, the private key is set to all zeros + bool success = true; + if ((memcmp(path, G_valid_path, sizeof(G_valid_path)) == 0)) { + memcpy(out, G_privkey, sizeof(G_privkey)); + } else { + memset(out, 0, PRIVATE_KEY_LENGTH); + success = false; + } + + // We also want to be able to force the function to return success, even if + // the derived private key is invalid to test seed_derive_pubkey + bool force_success = G_force_derive_private_success; + G_force_derive_private_success = false; + return success || force_success; +} + +bool random_getrandom(void *buffer, size_t length) { + assert(length <= sizeof(G_random_buffer)); + bool ret = true; + if (G_getrandom_fail_next) { + ret = false; + G_getrandom_fail_next = false; + } + memcpy(buffer, G_random_buffer, length); + return ret; +} + +// Mock SEST functions +bool sest_exists(char *key) { + return mock_sest_exists(key); +} + +uint8_t sest_read(char *key, uint8_t *dest, size_t dest_length) { + return mock_sest_read(key, dest, dest_length); +} + +bool sest_write(char *key, uint8_t *secret, size_t secret_length) { + return mock_sest_write(key, secret, secret_length); +} + +bool sest_remove(char *key) { + return mock_sest_remove(key); +} + +// Helper functions +static void setup() { + mock_sest_init(); + // Set up the random buffer and compute the valid seed. The same random + // bytes wil be used by the seed module to derive the internal seed + syscall(SYS_getrandom, G_random_buffer, sizeof(G_random_buffer), 0); + for (size_t i = 0; i < SEED_LENGTH; i++) { + G_valid_seed[i] = G_client_seed[i] ^ G_random_buffer[i]; + } +} + +static void teardown() { + mock_sest_reset(); + memset(G_random_buffer, 0, sizeof(G_random_buffer)); + memset(G_valid_seed, 0, sizeof(G_valid_seed)); +} + +static void load_valid_seed() { + mock_sest_write(SEST_SEED_KEY, G_valid_seed, sizeof(G_valid_seed)); +} + +static void assert_seed_valid() { + assert(mock_sest_exists(SEST_SEED_KEY)); + uint8_t seed[SEED_LENGTH]; + mock_sest_read(SEST_SEED_KEY, seed, sizeof(seed)); + ASSERT_MEMCMP(seed, G_valid_seed, sizeof(G_valid_seed)); + assert(seed_available()); +} + +static void assert_seed_wiped() { + assert(!mock_sest_exists(SEST_SEED_KEY)); + assert(!seed_available()); +} + +static void init_wiped() { + assert(seed_init()); + assert_seed_wiped(); +} + +static void init_with_valid_seed() { + load_valid_seed(); + assert(seed_init()); + assert_seed_valid(); +} + +static void assert_seed_generate_fails(uint8_t *client_seed, + size_t client_seed_size) { + assert(!seed_generate(client_seed, client_seed_size)); + assert_seed_wiped(); +} + +static void assert_seed_derive_pubkey_fails(uint32_t *path, + size_t path_length) { + uint8_t pubkey[PUBKEY_UNCMP_LENGTH] = {0}; + uint8_t pubkey_length = sizeof(pubkey); + assert(!seed_derive_pubkey(path, path_length, pubkey, &pubkey_length)); + ASSERT_ARRAY_CLEARED(pubkey); +} + +static void assert_signature_valid(uint8_t *hash, + uint8_t *pubkey, + uint8_t *sig, + size_t sig_length) { + secp256k1_context *sp_ctx = + secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_ecdsa_signature sp_sig; + secp256k1_pubkey sp_pubkey; + assert(1 == secp256k1_ecdsa_signature_parse_der( + sp_ctx, &sp_sig, sig, sig_length)); + assert(1 == secp256k1_ec_pubkey_parse( + sp_ctx, &sp_pubkey, pubkey, PUBKEY_UNCMP_LENGTH)); + assert(1 == secp256k1_ecdsa_verify(sp_ctx, &sp_sig, hash, &sp_pubkey)); + secp256k1_context_destroy(sp_ctx); +} + +// Test cases +void test_seed_init_success() { + setup(); + printf("Test seed_init success...\n"); + + init_wiped(); + teardown(); +} + +void test_seed_init_fails_when_sest_read_fails() { + setup(); + printf("Test seed_init fails when seed exists but sest_read fails...\n"); + + load_valid_seed(); + mock_sest_fail_next_read(true); + assert(!seed_init()); + assert(!seed_available()); + teardown(); +} + +void test_seed_init_fails_when_seed_is_invalid() { + setup(); + printf("Test seed_init fails when an invalid seed exists...\n"); + + uint8_t *invalid_seed = (uint8_t *)"an-invalid-seed"; + mock_sest_write(SEST_SEED_KEY, invalid_seed, sizeof(invalid_seed)); + assert(!seed_init()); + assert(!seed_available()); + teardown(); +} + +void test_seed_wipe_succeedes_when_seed_present() { + setup(); + printf("Test seed_wipe succeedes when the seed is present...\n"); + + init_with_valid_seed(); + assert(seed_wipe()); + assert_seed_wiped(); + teardown(); +} + +void test_seed_wipe_fails_when_seed_already_wiped() { + setup(); + printf("Test seed_wipe fails when the seed is already wiped...\n"); + + init_wiped(); + assert(!seed_wipe()); + assert_seed_wiped(); + teardown(); +} + +void test_seed_generate_sucess() { + setup(); + printf("Test seed_generate succeeds...\n"); + + init_wiped(); + assert(seed_generate(G_client_seed, sizeof(G_client_seed))); + assert_seed_valid(); + teardown(); +} + +void test_seed_generate_fails_when_seed_available() { + setup(); + printf("Test seed_generate fails when the seed is already available...\n"); + + init_with_valid_seed(); + assert(!seed_generate(G_client_seed, sizeof(G_client_seed))); + assert_seed_valid(); + teardown(); +} + +void test_seed_generate_fails_when_getrandom_fails() { + setup(); + printf("Test seed_generate fails when getrandom fails...\n"); + + init_wiped(); + G_getrandom_fail_next = true; + assert_seed_generate_fails(G_client_seed, sizeof(G_client_seed)); + teardown(); +} + +void test_seed_generate_fails_when_client_seed_invalid() { + setup(); + printf("Test seed_generate fails when the client seed is invalid...\n"); + + init_wiped(); + assert_seed_generate_fails(G_client_seed, SEED_LENGTH - 1); + teardown(); +} + +void test_seed_generate_fails_when_sest_write_fails() { + setup(); + printf("Test seed_generate fails when sest_write fails...\n"); + + init_wiped(); + mock_sest_fail_next_write(true); + assert_seed_generate_fails(G_client_seed, sizeof(G_client_seed)); + teardown(); +} + +void test_seed_derive_pubkey_success() { + setup(); + printf("Test derive_pubkey success...\n"); + + init_with_valid_seed(); + uint8_t pubkey[PUBKEY_UNCMP_LENGTH]; + uint8_t pubkey_length = sizeof(pubkey); + assert(seed_derive_pubkey( + G_valid_path, sizeof(G_valid_path), pubkey, &pubkey_length)); + assert(pubkey_length == PUBKEY_UNCMP_LENGTH); + ASSERT_MEMCMP(pubkey, G_pubkey, pubkey_length); + teardown(); +} + +void test_seed_derive_pubkey_fails_when_bip32_derive_fails() { + setup(); + printf("Test derive_pubkey fails when bip32_derive_private fails...\n"); + + init_with_valid_seed(); + uint32_t invalid_path[] = {0, 0, 0, 0, 0}; + assert_seed_derive_pubkey_fails(invalid_path, sizeof(invalid_path)); + teardown(); +} + +void test_seed_derive_pubkey_fails_when_privkey_is_invalid() { + setup(); + printf("Test derive_pubkey fails when the private key is invalid...\n"); + + init_with_valid_seed(); + // The invalid path will make bip32_derive_private return an invalid private + // key, but we will force it to return success anyway + uint32_t invalid_path[] = {0, 0, 0, 0, 0}; + G_force_derive_private_success = true; + assert_seed_derive_pubkey_fails(invalid_path, sizeof(invalid_path)); + teardown(); +} + +void test_seed_derive_pubkey_fails_when_pubkey_buf_too_small() { + setup(); + printf("Test derive_pubkey fails when the pubkey buffer is too small...\n"); + + init_with_valid_seed(); + uint8_t pubkey[PUBKEY_UNCMP_LENGTH] = {0}; + uint8_t pubkey_length = sizeof(pubkey) - 1; + assert(!seed_derive_pubkey( + G_valid_path, sizeof(G_valid_path), pubkey, &pubkey_length)); + ASSERT_ARRAY_CLEARED(pubkey); + teardown(); +} + +void test_seed_sign_success() { + setup(); + printf("Test seed_sign success...\n"); + + init_with_valid_seed(); + uint8_t sig[MAX_SIGNATURE_LENGTH]; + uint8_t sig_length = sizeof(sig); + assert(seed_sign( + G_valid_path, sizeof(G_valid_path), G_hash, sig, &sig_length)); + assert(sig_length <= MAX_SIGNATURE_LENGTH); + assert_signature_valid(G_hash, G_pubkey, sig, sig_length); + teardown(); +} + +void test_seed_sign_fails_when_sig_buffer_too_small() { + setup(); + printf("Test seed_sign fails when the signature buffer is too small...\n"); + + init_with_valid_seed(); + uint8_t sig[MAX_SIGNATURE_LENGTH] = {0}; + uint8_t sig_length = sizeof(sig) - 1; + assert(!seed_sign( + G_valid_path, sizeof(G_valid_path), G_hash, sig, &sig_length)); + ASSERT_ARRAY_CLEARED(sig); + teardown(); +} + +void test_seed_sign_fails_when_bip32_derive_fails() { + setup(); + printf("Test seed_sign fails when bip32_derive_private fails...\n"); + + init_with_valid_seed(); + uint8_t sig[MAX_SIGNATURE_LENGTH]; + uint8_t sig_length = sizeof(sig); + uint32_t invalid_path[] = {0, 0, 0, 0, 0}; + assert(!seed_sign( + invalid_path, sizeof(invalid_path), G_hash, sig, &sig_length)); + ASSERT_ARRAY_CLEARED(sig); + teardown(); +} + +int main() { + test_seed_init_success(); + test_seed_init_fails_when_sest_read_fails(); + test_seed_init_fails_when_seed_is_invalid(); + test_seed_wipe_succeedes_when_seed_present(); + test_seed_wipe_fails_when_seed_already_wiped(); + test_seed_generate_sucess(); + test_seed_generate_fails_when_seed_available(); + test_seed_generate_fails_when_getrandom_fails(); + test_seed_generate_fails_when_client_seed_invalid(); + test_seed_generate_fails_when_sest_write_fails(); + test_seed_derive_pubkey_success(); + test_seed_derive_pubkey_fails_when_bip32_derive_fails(); + test_seed_derive_pubkey_fails_when_privkey_is_invalid(); + test_seed_derive_pubkey_fails_when_pubkey_buf_too_small(); + test_seed_sign_success(); + test_seed_sign_fails_when_sig_buffer_too_small(); + test_seed_sign_fails_when_bip32_derive_fails(); + + return 0; +} From 524a46e1146f0058f1f271e7f4d0a3586cec08fa Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 16 Oct 2024 03:15:07 +1300 Subject: [PATCH 12/50] Bigdigits helper unit tests (#208) --- .../src/common/test/bigdigits_helper/Makefile | 39 ++++ .../common/test/bigdigits_helper/hal/log.h | 25 +++ .../bigdigits_helper/test_bigdigits_helper.c | 175 ++++++++++++++++++ firmware/src/common/test/common.mk | 2 + firmware/src/common/test/run-all.sh | 2 +- 5 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 firmware/src/common/test/bigdigits_helper/Makefile create mode 100644 firmware/src/common/test/bigdigits_helper/hal/log.h create mode 100644 firmware/src/common/test/bigdigits_helper/test_bigdigits_helper.c diff --git a/firmware/src/common/test/bigdigits_helper/Makefile b/firmware/src/common/test/bigdigits_helper/Makefile new file mode 100644 index 00000000..f274ac23 --- /dev/null +++ b/firmware/src/common/test/bigdigits_helper/Makefile @@ -0,0 +1,39 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common.mk + +PROG = test.out +OBJS = test_bigdigits_helper.o bigdigits_helper.o bigdigits.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test + +clean: + rm -f $(PROG) ./*.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/common/test/bigdigits_helper/hal/log.h b/firmware/src/common/test/bigdigits_helper/hal/log.h new file mode 100644 index 00000000..6d2c7f90 --- /dev/null +++ b/firmware/src/common/test/bigdigits_helper/hal/log.h @@ -0,0 +1,25 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#define LOG(...) diff --git a/firmware/src/common/test/bigdigits_helper/test_bigdigits_helper.c b/firmware/src/common/test/bigdigits_helper/test_bigdigits_helper.c new file mode 100644 index 00000000..62d9bd02 --- /dev/null +++ b/firmware/src/common/test/bigdigits_helper/test_bigdigits_helper.c @@ -0,0 +1,175 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "bigdigits_helper.h" + +#define MAX_DIGITS 10 +#define MAX_BYTES (MAX_DIGITS * sizeof(DIGIT_T)) + +void assert_parse_bigint_be(const uint8_t buf[], + const size_t buf_size, + const DIGIT_T exp[], + const size_t exp_digits) { + DIGIT_T dest[MAX_DIGITS]; + + parse_bigint_be(buf, buf_size, dest, sizeof(dest) / sizeof(dest[0])); + + for (int i = 0; i < sizeof(dest) / sizeof(dest[0]); i++) { + assert(dest[i] == (i < exp_digits ? exp[i] : 0)); + } +} + +void test_parse_bigint_be() { + printf("Testing parse_bigint_be... "); + + assert_parse_bigint_be( + (const uint8_t[]){0x1c, + 0x24, + 0xa0, + 0xa1, + 0xa2, + 0xa3, + 0xb0, + 0xb1, + 0xb2, + 0xb3, + 0xc0, + 0xc1, + 0xc2, + 0xc3}, + 14, + (const DIGIT_T[]){0xc0c1c2c3, 0xb0b1b2b3, 0xa0a1a2a3, 0x1c24}, + 4); + + assert_parse_bigint_be( + (const uint8_t[]){0xa0, 0xa1, 0xa2, 0xa3, 0xb0, 0xb1, 0xb2, 0xb3}, + 8, + (const DIGIT_T[]){0xb0b1b2b3, 0xa0a1a2a3}, + 2); + + assert_parse_bigint_be( + (const uint8_t[]){0xaa}, 1, (const DIGIT_T[]){0xaa}, 1); + + assert_parse_bigint_be( + (const uint8_t[]){0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, + 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}, + 40, + (const DIGIT_T[]){0x04030201, + 0x08070605, + 0x0c0b0a09, + 0x100f0e0d, + 0x14131211, + 0x18171615, + 0x1c1b1a19, + 0x201f1e1d, + 0x24232221, + 0x28272625}, + 10); + + printf("OK\n"); +} + +void assert_dump_bigint_be(const DIGIT_T n[], + const size_t n_digits, + const uint8_t exp[], + const size_t exp_size) { + uint8_t dest[MAX_BYTES]; + + memset(dest, 0xff, sizeof(dest)); + dump_bigint_be(dest, n, n_digits); + + for (int i = 0; i < sizeof(dest); i++) { + + assert(dest[i] == (i < exp_size ? exp[i] : 0xff)); + } +} + +void test_dump_bigint_be() { + printf("Testing dump_bigint_be... "); + + assert_dump_bigint_be( + (const DIGIT_T[]){0xc0c1c2c3, 0xb0b1b2b3, 0xa0a1a2a3, 0x1c24}, + 4, + (const uint8_t[]){0x0, + 0x0, + 0x1c, + 0x24, + 0xa0, + 0xa1, + 0xa2, + 0xa3, + 0xb0, + 0xb1, + 0xb2, + 0xb3, + 0xc0, + 0xc1, + 0xc2, + 0xc3}, + 16); + + assert_dump_bigint_be( + (const DIGIT_T[]){0xc0c1c2c3, 0xb0b1b2b3}, + 2, + (const uint8_t[]){0xb0, 0xb1, 0xb2, 0xb3, 0xc0, 0xc1, 0xc2, 0xc3}, + 8); + + assert_dump_bigint_be( + (const DIGIT_T[]){0xaa}, 1, (const uint8_t[]){0x0, 0x0, 0x0, 0xaa}, 4); + + assert_dump_bigint_be((const DIGIT_T[]){0x04030201, + 0x08070605, + 0x0c0b0a09, + 0x100f0e0d, + 0x14131211, + 0x18171615, + 0x1c1b1a19, + 0x201f1e1d, + 0x24232221, + 0x28272625}, + 10, + (const uint8_t[]){ + 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, + 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + 40); + + printf("OK\n"); +} + +int main() { + test_parse_bigint_be(); + test_dump_bigint_be(); + return 0; +} diff --git a/firmware/src/common/test/common.mk b/firmware/src/common/test/common.mk index 3a69b0e5..778f92f6 100644 --- a/firmware/src/common/test/common.mk +++ b/firmware/src/common/test/common.mk @@ -26,3 +26,5 @@ CFLAGS = -iquote $(SRCDIR) -iquote . include ../../../../coverage/coverage.mk CFLAGS += $(COVFLAGS) + +VPATH += $(SRCDIR) diff --git a/firmware/src/common/test/run-all.sh b/firmware/src/common/test/run-all.sh index bcf2cf68..0ac28ed5 100755 --- a/firmware/src/common/test/run-all.sh +++ b/firmware/src/common/test/run-all.sh @@ -1,6 +1,6 @@ #!/bin/bash BASEDIR=$(dirname $0) -TESTDIRS="ints memutil" +TESTDIRS="bigdigits_helper ints memutil" TESTDIRS=${1:-"$TESTDIRS"} for d in $TESTDIRS; do From a9b69432743bc4cae12bf440589b69395ba68a5f Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 22 Oct 2024 02:29:54 +1300 Subject: [PATCH 13/50] Unit testing bip32 derivation and hmac_sha512 (#210) - Added bip32 derivation tests on separate source file - Added hmac_sha512 tests using 3rd party test vectors - Added test helpers to common x86 test artifacts - Moved common.mk to common directory - Updated existing Makefile(s) to account for moved common.mk --- firmware/src/hal/x86/test/bip32/Makefile | 7 +- firmware/src/hal/x86/test/bip32/test_bip32.c | 10 +- .../x86/test/bip32/test_bip32_derivation.c | 393 + .../src/hal/x86/test/{ => common}/common.mk | 7 +- .../src/hal/x86/test/common/test_helpers.c | 157 + .../src/hal/x86/test/common/test_helpers.h | 81 + firmware/src/hal/x86/test/endian/Makefile | 2 +- .../src/hal/x86/test/hmac_sha256/Makefile | 2 +- .../src/hal/x86/test/hmac_sha512/HMAC.rsp | 11039 ++++++++++++++++ .../src/hal/x86/test/hmac_sha512/Makefile | 40 + .../x86/test/hmac_sha512/test_hmac_sha512.c | 183 + firmware/src/hal/x86/test/keccak256/Makefile | 2 +- firmware/src/hal/x86/test/run-all.sh | 2 +- 13 files changed, 11913 insertions(+), 12 deletions(-) create mode 100644 firmware/src/hal/x86/test/bip32/test_bip32_derivation.c rename firmware/src/hal/x86/test/{ => common}/common.mk (85%) create mode 100644 firmware/src/hal/x86/test/common/test_helpers.c create mode 100644 firmware/src/hal/x86/test/common/test_helpers.h create mode 100644 firmware/src/hal/x86/test/hmac_sha512/HMAC.rsp create mode 100644 firmware/src/hal/x86/test/hmac_sha512/Makefile create mode 100644 firmware/src/hal/x86/test/hmac_sha512/test_hmac_sha512.c diff --git a/firmware/src/hal/x86/test/bip32/Makefile b/firmware/src/hal/x86/test/bip32/Makefile index a0ffc42a..e91b58b0 100644 --- a/firmware/src/hal/x86/test/bip32/Makefile +++ b/firmware/src/hal/x86/test/bip32/Makefile @@ -20,16 +20,17 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -include ../common.mk +include ../common/common.mk ifneq ($(DEBUG),) CFLAGS += -DDEBUG_BIP32 endif +CFLAGS += -iquote ../common + PROG = test.out OBJS = bip32.o hmac_sha512.o endian.o bigdigits.o bigdigits_helper.o -OBJS += test_bip32.o log.o - +OBJS += ../common/test_helpers.o test_bip32.o test_bip32_derivation.o log.o all: $(PROG) diff --git a/firmware/src/hal/x86/test/bip32/test_bip32.c b/firmware/src/hal/x86/test/bip32/test_bip32.c index cae7a116..96e54554 100644 --- a/firmware/src/hal/x86/test/bip32/test_bip32.c +++ b/firmware/src/hal/x86/test/bip32/test_bip32.c @@ -32,7 +32,7 @@ void test_parses_correctly(const char* path, const uint32_t expected_parts[], const size_t expected_parts_count) { - printf("Testing path \"%s\" is parsed correctly... ", path); + printf("\tPath \"%s\" is parsed correctly... ", path); fflush(stdout); uint8_t binpath[5 * sizeof(uint32_t) + 1]; @@ -57,7 +57,7 @@ void test_parses_correctly(const char* path, void test_parsing_fails(const char* path) { uint8_t binpath[5 * sizeof(uint32_t) + 1]; - printf("Testing path \"%s\" parsing fails... ", path); + printf("\tPath \"%s\" parsing fails... ", path); fflush(stdout); assert(!bip32_parse_path(path, binpath)); @@ -65,7 +65,11 @@ void test_parsing_fails(const char* path) { printf("OK!\n"); } +// Implemented in test_bip32_derivation.c +void test_derivation(); + int main() { + printf("Testing BIP32 path parsing...\n"); test_parses_correctly("m/0/0/0/0/0", (const uint32_t[]){0, 0, 0, 0, 0}, 5); test_parses_correctly( "m/10/20/30/40/50", (const uint32_t[]){10, 20, 30, 40, 50}, 5); @@ -116,5 +120,7 @@ int main() { test_parsing_fails("m/2147483648'/0/0/0/0"); test_parsing_fails("m/01234567890/0/0/0/0"); + test_derivation(); + return 0; } \ No newline at end of file diff --git a/firmware/src/hal/x86/test/bip32/test_bip32_derivation.c b/firmware/src/hal/x86/test/bip32/test_bip32_derivation.c new file mode 100644 index 00000000..ab16b444 --- /dev/null +++ b/firmware/src/hal/x86/test/bip32/test_bip32_derivation.c @@ -0,0 +1,393 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Taken from https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include "bip32.h" +#include "test_helpers.h" + +/** Length of write canary (for testing writing beyond the end of an array), + * in bytes. */ +#define CANARY_LENGTH 100 +/** Length of serialised BIP32 extended private key, in bytes. */ +#define SERIALISED_BIP32_KEY_LENGTH 82 + +/** Characters for the base 58 representation of numbers. */ +static const char base58_char_list[58] = { + '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; + +/** Test vector for BIP32 key derivation. */ +struct BIP32TestVector { + /** Master seed. */ + uint8_t master[256]; + /** Length of master seed, in bytes. */ + unsigned int master_length; + /** Key derivation path. */ + uint32_t path[16]; + /** Number of steps in derivation path. */ + unsigned int path_length; + /** Expected private key, as a base58-encoded serialised extended private + * key as described in the BIP32 specification. */ + char base58_private[256]; +}; + +// Master seed for RootStock test cases +// 0x52a26d029f271256d6807e4cf6d9581a5912b8cccc447e5e64482928c9face80 +#define ROOTSTOCK_MS \ + { \ + 0x52, 0xa2, 0x6d, 0x02, 0x9f, 0x27, 0x12, 0x56, 0xd6, 0x80, 0x7e, \ + 0x4c, 0xf6, 0xd9, 0x58, 0x1a, 0x59, 0x12, 0xb8, 0xcc, 0xcc, 0x44, \ + 0x7e, 0x5e, 0x64, 0x48, 0x29, 0x28, 0xc9, 0xfa, 0xce, 0x80, \ + }, \ + 32 + +/** Test cases from BIP 32 specification. + * https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#user-content-Test_Vectors + */ + +#define TEST_VECTOR_1 \ + { \ + 0x00, \ + 0x01, \ + 0x02, \ + 0x03, \ + 0x04, \ + 0x05, \ + 0x06, \ + 0x07, \ + 0x08, \ + 0x09, \ + 0x0a, \ + 0x0b, \ + 0x0c, \ + 0x0d, \ + 0x0e, \ + 0x0f, \ + }, \ + 16 + +#define TEST_VECTOR_2 \ + { \ + 0xff, 0xfc, 0xf9, 0xf6, 0xf3, 0xf0, 0xed, 0xea, 0xe7, 0xe4, 0xe1, \ + 0xde, 0xdb, 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc9, 0xc6, 0xc3, 0xc0, \ + 0xbd, 0xba, 0xb7, 0xb4, 0xb1, 0xae, 0xab, 0xa8, 0xa5, 0xa2, 0x9f, \ + 0x9c, 0x99, 0x96, 0x93, 0x90, 0x8d, 0x8a, 0x87, 0x84, 0x81, 0x7e, \ + 0x7b, 0x78, 0x75, 0x72, 0x6f, 0x6c, 0x69, 0x66, 0x63, 0x60, 0x5d, \ + 0x5a, 0x57, 0x54, 0x51, 0x4e, 0x4b, 0x48, 0x45, 0x42, \ + }, \ + 64 + +const struct BIP32TestVector test_cases[] = { + + { + // Test vector 1, chain m + TEST_VECTOR_1, + {0}, // derivation path + 0, // steps in derivation path + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPG" + "JxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" // extended private key + }, + + { + // Test vector 1, chain m/0H + TEST_VECTOR_1, + {0x80000000}, // derivation path + 1, // steps in derivation path + "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6K" + "CesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7" // extended private key + }, + + { + // Test vector 1, chain m/0H/1 + TEST_VECTOR_1, + {0x80000000, 1}, // derivation path + 2, // steps in derivation path + "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYP" + "xLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs" // extended private key + }, + + { + // Test vector 1, chain m/0H/1/2H + TEST_VECTOR_1, + {0x80000000, 1, 0x80000002}, // derivation path + 3, // steps in derivation path + "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3r" + "yjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM" // extended private key + }, + + { + // Test vector 1, chain m/0H/1/2H/2 + TEST_VECTOR_1, + {0x80000000, 1, 0x80000002, 2}, // derivation path + 4, // steps in derivation path + "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f" + "7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334" // extended private key + }, + + { + // Test vector 1, chain m/0H/1/2H/2/1000000000 + TEST_VECTOR_1, + {0x80000000, 1, 0x80000002, 2, 1000000000}, // derivation path + 5, // steps in derivation path + "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4" + "WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76" // extended private key + }, + + { + // Test vector 2, chain m + TEST_VECTOR_2, + {0}, // derivation path + 0, // steps in derivation path + "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK" + "4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U" // extended private key + }, + + { + // Test vector 2, chain m/0 + TEST_VECTOR_2, + {0}, // derivation path + 1, // steps in derivation path + "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2y" + "JD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt" // extended private key + }, + + { + // Test vector 2, chain m/0/2147483647H + TEST_VECTOR_2, + {0, 0xffffffff}, // derivation path + 2, // steps in derivation path + "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwC" + "d6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9" // extended private key + }, + + { + // Test vector 2, chain m/0/2147483647H/1 + TEST_VECTOR_2, + {0, 0xffffffff, 1}, // derivation path + 3, // steps in derivation path + "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9" + "yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef" // extended private key + }, + + { + // Test vector 2, chain m/0/2147483647H/1/2147483646H + TEST_VECTOR_2, + {0, 0xffffffff, 1, 0xfffffffe}, // derivation path + 4, // steps in derivation path + "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39nj" + "GVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc" // extended private key + }, + + { + // Test vector 2, chain m/0/2147483647H/1/2147483646H/2 + TEST_VECTOR_2, + {0, 0xffffffff, 1, 0xfffffffe, 2}, // derivation path + 5, // steps in derivation path + "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq3" + "8EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j" // extended private key + }, + + // Test cases for powHSM derivation paths + {// BTC + ROOTSTOCK_MS, + {0x8000002c, 0x80000000, 0x80000000, 0, 0}, + 5, // m/44'/0'/0'/0/0 + "xprvA2UeNN7RNEZziKLXKBSefpya4kH15PWnvXByUVexASEiD3ugfgNDb1SkqPcz5Z3qFBy85" + "VbFHkuxEZLxRr38U2QJjCZACzG87StyGiZzSND"}, + + {// RSK + ROOTSTOCK_MS, + {0x8000002c, 0x80000089, 0x80000000, 0, 0}, + 5, // m/44'/137'/0'/0/0 + "xprvA3mkFU5ToBWn1BL63Ms2NLwX1wetEVveBGJXbvJyuA4r6VTYjzzyUgzggKtJhXdyVW6Rx" + "MaGFdNMGTYYEn74HaN1zVwQBN8ktd3kMupDD8c"}, + + {// MST + ROOTSTOCK_MS, + {0x8000002c, 0x80000089, 0x80000001, 0, 0}, + 5, // m/44'/137'/1'/0/0 + "xprvA3xqgq7Bq4w6JeD6fRQMojVYUeeHpVHq2uSSBzdpYrSFGGKPVdFeziEHxhA8BaBC9F9AT" + "NL6LhzSLSgJyxifCGdoQP4zrPsLLCdggmq34m1"}, + + {// tBTC + ROOTSTOCK_MS, + {0x8000002c, 0x80000001, 0x80000000, 0, 0}, + 5, // m/44'/1'/0'/0/0 + "xprvA3wQwmmVVpN9kFPhJanvESUgk7TaL3kzfxDzmur8Hmy7Q5fs77LbzYAeuDFXMqMTSFug3" + "gWn4Tqn9pzJ5iA3hvqNfVFJYonnQQQicdUmEgv"}, + + {// tRSK + ROOTSTOCK_MS, + {0x8000002c, 0x80000001, 0x80000001, 0, 0}, + 5, // m/44'/1'/1'/0/0 + "xprvA327ZZEydaEeVDtp8AoTiEaAWak4UwYm4E3FsrnW8fhrm6wKj8L8MzFL8e1vnAAq1QRiH" + "FcTDJ8LkAsuECPL51LBQDoHcC86dLTppTD9s1o"}, + + {// tMST + ROOTSTOCK_MS, + {0x8000002c, 0x80000001, 0x80000002, 0, 0}, + 5, // m/44'/1'/2'/0/0 + "xprvA2n1UrdXdG7D2kHi8i8wLS2auY8WJma8XfRKfTQ9xYfTGNg81p786NbUcZVCgP64Nqnk3" + "cAyKkJ8AzzUUd5u4iFVe4jU8UpQonvoYX6QSqh"}, + +}; + +static void reverse(uint8_t *arr, const unsigned int len) { + uint8_t tmp; + for (unsigned int i = 0; i < len / 2; i++) { + tmp = arr[i]; + arr[i] = arr[len - 1 - i]; + arr[len - 1 - i] = tmp; + } +} + +static void base58_decode_bip32_key(uint8_t *out, + const char *in, + const unsigned int len) { + unsigned int i; + unsigned int j; + unsigned int digit; + unsigned int carry; + unsigned int result; + + memset(out, 0, SERIALISED_BIP32_KEY_LENGTH); + for (i = 0; i < len; i++) { + digit = 0; + for (j = 0; j < 58; j++) { + if (in[i] == base58_char_list[j]) { + digit = j; + break; + } + } + // multiply by 58 + carry = 0; + for (j = 0; j < SERIALISED_BIP32_KEY_LENGTH; j++) { + result = (unsigned int)out[j] * 58 + carry; + out[j] = (uint8_t)result; + carry = result >> 8; + } + // add digit + carry = 0; + for (j = 0; j < SERIALISED_BIP32_KEY_LENGTH; j++) { + result = (unsigned int)out[j] + carry; + if (j == 0) { + result += digit; + } + out[j] = (uint8_t)result; + carry = result >> 8; + } + } + reverse(out, SERIALISED_BIP32_KEY_LENGTH); +} + +static void printf_hex(uint8_t *buf, size_t len) { + printf("0x"); + for (unsigned int i = 0; i < len; i++) { + printf("%02x", ((unsigned char *)buf)[i]); + } + printf("\n"); +} + +void test_derivation() { + uint8_t expected_bytes[SERIALISED_BIP32_KEY_LENGTH]; + uint8_t canary[CANARY_LENGTH]; + uint8_t out[32 + CANARY_LENGTH]; + unsigned int i; + + init_tests(__FILE__); + + for (i = 0; i < (sizeof(test_cases) / sizeof(struct BIP32TestVector)); + i++) { + fill_with_random(canary, sizeof(canary)); + memcpy(&(out[32]), canary, sizeof(canary)); + if (!bip32_derive_private(out, + test_cases[i].master, + test_cases[i].master_length, + test_cases[i].path, + test_cases[i].path_length)) { + printf("Test vector %u failed to derive\n", i); + report_failure(); + } else { + base58_decode_bip32_key(expected_bytes, + test_cases[i].base58_private, + strlen(test_cases[i].base58_private)); + if (memcmp(out, &expected_bytes[46], 32) != 0) { + printf("Test vector %u derivation mismatch\n", i); + printf("Derived: "); + printf_hex(out, 32); + printf("\n"); + printf("Expected: "); + printf_hex(&expected_bytes[46], 32); + printf("\n"); + report_failure(); + } else if (memcmp(&(out[32]), canary, sizeof(canary)) != 0) { + printf("Test vector %u caused write to canary\n", i); + report_failure(); + } else { + report_success(); + } + } + } + + finish_tests(); + assert(!tests_failed()); +} diff --git a/firmware/src/hal/x86/test/common.mk b/firmware/src/hal/x86/test/common/common.mk similarity index 85% rename from firmware/src/hal/x86/test/common.mk rename to firmware/src/hal/x86/test/common/common.mk index 3117b0c8..c4ddc348 100644 --- a/firmware/src/hal/x86/test/common.mk +++ b/firmware/src/hal/x86/test/common/common.mk @@ -21,14 +21,15 @@ # SOFTWARE. INCDIR = ../../../include +COMMONTESTDIR = ../common X86SRCDIR = ../../src COMMONSRCDIR = ../../../../common/src -SRCDIR = $(X86SRCDIR):$(COMMONSRCDIR) -CFLAGS = -iquote $(INCDIR) -iquote $(X86SRCDIR) -iquote $(COMMONSRCDIR) +SRCDIR = $(X86SRCDIR):$(COMMONSRCDIR):$(COMMONTESTDIR) +CFLAGS = -iquote $(INCDIR) -iquote $(COMMONTESTDIR) -iquote $(X86SRCDIR) -iquote $(COMMONSRCDIR) CFLAGS += -DHSM_PLATFORM_X86 include ../../../../../coverage/coverage.mk CFLAGS += $(COVFLAGS) -VPATH += $(SRCDIR):$(INCDIR) +VPATH += $(SRCDIR):$(INCDIR):$(COMMONTESTDIR) diff --git a/firmware/src/hal/x86/test/common/test_helpers.c b/firmware/src/hal/x86/test/common/test_helpers.c new file mode 100644 index 00000000..89475c57 --- /dev/null +++ b/firmware/src/hal/x86/test/common/test_helpers.c @@ -0,0 +1,157 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Taken from https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file test_helpers.c + * + * \brief Common helper functions for unit tests. + * + * If TEST is not defined, this file will appear as an empty translation + * unit to the compiler. Thus this file should not be compiled in non-test + * builds. + * + * This file is licensed as described by the file LICENCE. + */ + +#include +#include +#include +#include "test_helpers.h" + +/** Number of test cases which succeeded. */ +static int succeeded; +/** Number of test cases which failed. */ +static int failed; +/** Time when unit tests were started. */ +static time_t start_time; + +/** Skip whitespace in an open file, starting from the current position within + * the file and ending such that the file position points to the first + * non-whitespace character found. + * \param f The file to skip whitespace in. + */ +void skip_whitespace(FILE *f) { + int one_char; + do { + one_char = fgetc(f); + } while (((one_char == ' ') || (one_char == '\t') || (one_char == '\n') || + (one_char == '\r')) && + !feof(f)); + ungetc(one_char, f); +} + +/** Skip the contents of a line in an open file, starting from the current + * position within the file and ending such that the file position points to + * the first character of the next line. + * \param f The file to skip a line in. + */ +void skip_line(FILE *f) { + int one_char; + do { + one_char = fgetc(f); + } while ((one_char != '\n') && !feof(f)); +} + +/** Fill array with pseudo-random testing data. + * \param out Byte array to fill. + * \param len Number of bytes to write. + */ +void fill_with_random(uint8_t *out, unsigned int len) { + unsigned int i; + + for (i = 0; i < len; i++) { + out[i] = (uint8_t)rand(); + } +} + +/** Call this whenever a test case succeeds. */ +void report_success(void) { + succeeded++; +} + +/** Call this whenever a test case fails. */ +void report_failure(void) { + failed++; +} + +/** This must be called before running any unit tests. + * \param source_file_name The name of the file being unit tested. The use + * of the __FILE__ macro is probably a good idea. + */ +void init_tests(const char *source_file_name) { + succeeded = 0; + failed = 0; + srand(42); // make sure tests which rely on rand() are deterministic + printf("Running unit tests for file: %s\n", source_file_name); + time(&start_time); +} + +/** This must be called after running all unit tests for a file. It will + * report test statistics. + */ +void finish_tests(void) { + time_t finish_time; + + time(&finish_time); + printf("Tests required about %g seconds\n", + difftime(finish_time, start_time)); + printf("Tests which succeeded: %d\n", succeeded); + printf("Tests which failed: %d\n", failed); +} + +bool tests_failed() { + return failed > 0; +} diff --git a/firmware/src/hal/x86/test/common/test_helpers.h b/firmware/src/hal/x86/test/common/test_helpers.h new file mode 100644 index 00000000..57bd1670 --- /dev/null +++ b/firmware/src/hal/x86/test/common/test_helpers.h @@ -0,0 +1,81 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Taken from https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file test_helpers.h + * + * \brief Describes functions exported by test_helpers.c. + * + * This file is licensed as described by the file LICENCE. + */ + +#ifndef TEST_HELPERS_H_INCLUDED +#define TEST_HELPERS_H_INCLUDED + +#include +#include +#include + +void skip_whitespace(FILE *f); +void skip_line(FILE *f); +void fill_with_random(uint8_t *out, unsigned int len); +void report_success(void); +void report_failure(void); +void init_tests(const char *source_file_name); +void finish_tests(void); +bool tests_failed(); + +#endif // #ifndef TEST_HELPERS_H_INCLUDED diff --git a/firmware/src/hal/x86/test/endian/Makefile b/firmware/src/hal/x86/test/endian/Makefile index 6047e5ba..a188952d 100644 --- a/firmware/src/hal/x86/test/endian/Makefile +++ b/firmware/src/hal/x86/test/endian/Makefile @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -include ../common.mk +include ../common/common.mk PROG = test.out OBJS = test_endian.o endian.o diff --git a/firmware/src/hal/x86/test/hmac_sha256/Makefile b/firmware/src/hal/x86/test/hmac_sha256/Makefile index 08c87864..2a435211 100644 --- a/firmware/src/hal/x86/test/hmac_sha256/Makefile +++ b/firmware/src/hal/x86/test/hmac_sha256/Makefile @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -include ../common.mk +include ../common/common.mk PROG = test.out OBJS = sha256.o hmac_sha256.o test_hmac_sha256.o diff --git a/firmware/src/hal/x86/test/hmac_sha512/HMAC.rsp b/firmware/src/hal/x86/test/hmac_sha512/HMAC.rsp new file mode 100644 index 00000000..0e9a219c --- /dev/null +++ b/firmware/src/hal/x86/test/hmac_sha512/HMAC.rsp @@ -0,0 +1,11039 @@ +# CAVS 11.0 +# HMAC information +# Hash sizes tested: 20 28 32 48 64 +# Generated on Mon Feb 28 20:38:43 2011 + +[L=20] + +Count = 0 +Klen = 10 +Tlen = 10 +Key = 82f3b69a1bff4de15c33 +Msg = fcd6d98bef45ed6850806e96f255fa0c8114b72873abe8f43c10bea7c1df706f10458e6d4e1c9201f057b8492fa10fe4b541d0fc9d41ef839acff1bc76e3fdfebf2235b5bd0347a9a6303e83152f9f8db941b1b94a8a1ce5c273b55dc94d99a171377969234134e7dad1ab4c8e46d18df4dc016764cf95a11ac4b491a2646be1 +Mac = 1ba0e66cf72efc349207 + +Count = 1 +Klen = 10 +Tlen = 10 +Key = 4766e6fe5dffc98a5c50 +Msg = d68b828a153f5198c005ee36c0af2ff92e84907517f01d9b7c7993469df5c21078fa356a8c9715ece2414be94e10e547f32cbb8d0582523ed3bb0066046e51722094aa44533d2c876e82db402fbb00a6c2f2cc3487973dfc1674463e81e42a39d9402941f39b5e126bafe864ea1648c0a5be0a912697a87e4f8eabf79cbf130e +Mac = 007e4504041a12f9e345 + +Count = 2 +Klen = 10 +Tlen = 10 +Key = 0f942d98a5c406155967 +Msg = f84d0d813d2e9e779e8570bddbdf6fdc6baade5acb3c4cde1618c494d66d45d319e071fec88b89a8354699fbf325f05aea42d345aabc737d00ff1c69c746aeb9015f514927ae6548bd75b8992853fc79c40a78633285fd30ef191c832b0b9664d852142b019f18a05d9b3460246f7a83218a337b099ed43f0bec2daaa8c2e41d +Mac = c19d05a808054b8039f9 + +Count = 3 +Klen = 10 +Tlen = 10 +Key = 78cb194a958fc1b95e35 +Msg = d6eb23c5ea87fd67b943928be0521823dc508acb2ad5f0fdac49e0844ffa4533eb6b5fd66bf00b692d774588aca9eb275c32c383d55cc05834e38155be051bcdc7d818afd3e0c0b8fae197e791f2263206d3fe770c80fbb5f806c67c6b969da232d857386a81a2bce8289090d85652aba3dc438f1769287bc25bb5e19ed6541a +Mac = 539d5cbb60739e152196 + +Count = 4 +Klen = 10 +Tlen = 10 +Key = 2baa6731c367e0f818ab +Msg = a64ec0d93360976b75f50ea532c3d501464a392c00aba572c9bd6977065ebb294007fbf282a43c3203a2ffec054941c0fd4cb919f49e5ba72d88201008f909e2261d62cdce30440f90955d2f2822f3eea5bf277bca2f77e6b42d87d7bdbb2180a1b77ad0dfafb7e962f6afd561f7f37484ca0cb948050316a4d52735ed4d0ae9 +Mac = 2ddc8c4803e5a4c7871c + +Count = 5 +Klen = 10 +Tlen = 10 +Key = c1f4f1ac1adf93df6e58 +Msg = 5f458657da5aec73d8aa5e348bedc6af487341593a0a741256222362912fff02514fc09e222d74d9ab251792e0a9636579e3e975a29b6169f45c3fb5a4d2871bfa77e171056ff0a48eafe0fd4a653ea353940d62d9ff16aa15497fdb7f5a9fbf41051158ebe707dd6892e1ff31ebff70c0d0d3a648fe3adda3320c5b8c8ff1f7 +Mac = c1ebf896bd26a30cf668 + +Count = 6 +Klen = 10 +Tlen = 10 +Key = 5de237ba1edadf54d566 +Msg = 20100ed997ab74370607aeeb0bd2f64f6a56c7040d64fd8a498a380d638c8182531230f3c79f0c176bc2b52668903feb2a51201b677a4ce55ddc9eca5b1a7aaf8260b131cd52a4384f43adcfbca8ba332bcc3b291ac53f95b3a6d9494ef6c91b3661583ab0ae84c239f15d8d1002af4df42de1d72f2b1dc2d351b2314408b6ed +Mac = 8a3e105bffc04ba113cd + +Count = 7 +Klen = 10 +Tlen = 10 +Key = ed00f3c4c227d07cf2d1 +Msg = 3223744302f481dd32a9d4d1ceaf72229b45f413a1e82d3ce70f0dde7e19c574c0842c8ada5f62d28802b37520fcbea7d24dd67e2ed6a804e60d1e8bd6f58440414eea035e08c97613fee95400e18105bf72a16f6af5cd0e5ee2ea473fdd5ff93de8745695d8fdf15a053d1775460563eb1d1c8d5e2ee383d7f639bbc2b99dc7 +Mac = 4104ef3c144bcfaf8dd3 + +Count = 8 +Klen = 10 +Tlen = 10 +Key = 3b6af34ae3ea52d3962d +Msg = fb091ddd95b100dfcf892d78e5e770d3a37b8c3885df803c1d6f0935b55b68f136fb65a84862942ebb35d76d26be2413cd3c8988c87d6d2362af189dc07476c6c33417762eb77bc70cf38d814c226dd6af187250e4d47007f1553617d4af5b516a5d3b3191d93c10896a569ba13dd2840fb851781f0b115090086c8b3a34a1fc +Mac = 838ba0117e413095d056 + +Count = 9 +Klen = 10 +Tlen = 10 +Key = 6445f6d884fbd57a1eec +Msg = 97f2769dc081f1fd7138ad61bd30743cd81a4565cf22a41a761a3544a2d489fc99cf384fc716303eb3664c09318f29aed81c35acb636080c43c6f8a294dae791d14a600de99be36584237c403a6e9a2602e11f43ed9db46814a75f53ce45573027ab17608ed6b178ceb9658d409772af3eb02cb3da1f4f36d00393debadd80e3 +Mac = cdcff19dc81026983e6c + +Count = 10 +Klen = 10 +Tlen = 10 +Key = b9ec31346806acaa9221 +Msg = 76a69cdd9ff87ee6b07ffe6d496c54560de1e9f64c061acbe059386a5445d3b84cf7385d206d3876cbcf2b8a040335c0aa7cc84f65526a358b98b92c40eaacdae2451b48a41b829578a702ec337fa8b3eb68f205a46d8f632c3367a64487db3800394e84712de4ab81af89791d0736979a4d6f02517f11bb8dd14ac1a844e93c +Mac = f069430eb49866d7d39b + +Count = 11 +Klen = 10 +Tlen = 10 +Key = 518a96ff0a44f95d97ee +Msg = 3658212a14b65ac3bd9e3d9039c631a94bb43c4e493877852a3abf05e1b5ae53ea04c92b225dfb21db9b43883040a99396ba76bab4e5a45f75d294b25bc7ffd216862f3555d26f49dc30c05bd6ebcdb96d5a2113996598273546139e588d7030e267ba0f551f9c83e7e51cd1d5cf8662f91da5219fc13925951fa6908111eab7 +Mac = 0f4fae1d2b5960a54b82 + +Count = 12 +Klen = 10 +Tlen = 10 +Key = a79032a4f7f740f6d13e +Msg = fcd6d3ab67574d8f0bbf5ad14937966dbd4386a928e62a53ad0dd14a412b31405d20b7bdf55f1c67ae5039824cf31cb369c75b096deaa83dba81a639275afcd8b0d0a7ed6cef9486bfd96e72d068b5003d15100a0e19e432e8d2256c83676cbd5eaf4a42b24fdd73a423a0a9bee087dea0f74cb4f3bc03b99fc7f5ea3e9aab76 +Mac = 7d809c2533c47f832046 + +Count = 13 +Klen = 10 +Tlen = 10 +Key = ab6b1fd8231147512309 +Msg = c8f16efe636581b6ab7ab7f39426bd033ddccb8ec50d1b3160ef9f69aa7df3b33bbf91f17b4b4410b70cdfe875422e6305ca2de259a078dc17a203c8eb960b3e226f4c5975cc755f22c2d9a442db67ab565edc8f23d137a1c0bd6d53edb15f55a68909fdf8f0fcec14240eefa2fa50235721405dcaaa40c883c847d055d5d73f +Mac = 0c7799c513f4a3308de3 + +Count = 14 +Klen = 10 +Tlen = 10 +Key = d7f2be75aaebb90d87a8 +Msg = cad534c86629fc600b38138a7f3e1a701bc4bd1f865f96dac39a4eb46e31065e4280f53ddf3a52bfca5e74f0b667384802c4a3c78287c8458261ec0308cee9855a8dd0a4c053d2df8bc061f2569292aa8c19c6f72beb8943c7d8ba02d120ed8a19e40d2592db4665554621b8e926f13cc2ac6fd507f1a17c99e700da5090d915 +Mac = 00e416c156dc85d4d47d + +Count = 15 +Klen = 10 +Tlen = 12 +Key = 1379a7afcc0905a5fc81 +Msg = 96fa5619fac648843db788cb8e90dc6ffd6efe1332abf0815f0390ee73f56c7f916cd70cc09f3d23e436b350edaed29b4efec653b07ba20ae8f9f6e12733a406716def7a5157d518ca359fd3903db63f7940b8532e8dcb6d26133296d5c51e072043c6ed15b6b96ad9fb73dce1052f61657cfd9b12aa14b000986995e374818d +Mac = 42537b22520a085577587616 + +Count = 16 +Klen = 10 +Tlen = 12 +Key = 80a0db49d039b316ae12 +Msg = 91f8ec848d6f811431cbdeee150b93af6f678be99c903f81fc38295503d57c228da212a672e7a6015b7b4361d487fcdea28cdea356a8234f2215a89becf2a23ca1468c0bcc42646367c616caf02739d4c030f945996654767e908afac777ce8074eb42fbc2062201fcb53f719473b0597258c4178c533bbeb7b4b5bbbced6ab8 +Mac = ecae138322d2d4086aa2bec6 + +Count = 17 +Klen = 10 +Tlen = 12 +Key = 261812249e1338ac5a22 +Msg = 5a529114ba6bdab69bada5e8916fb6eb222c71256f919dd117d369f65846ac95772c712762cab34795c265ab3a9cb65894a692169dfe6c22eeed3b24e076c260f12f1530695059b23d0acbbe331a041b479d7bf24d264b82d90e36165c0bea348f048418152453615c2ede09c410289a03ba329fc830c2599ede63b4132dad79 +Mac = 2fe2bd1355a64e4661a6567a + +Count = 18 +Klen = 10 +Tlen = 12 +Key = 07a27c1b24094dd9a0b9 +Msg = f6d9565ef97ea11748689e263f52b4af880ff5c8ed1295226a34a1ec87b2edf4e5754f1016970abcb1228d04a61b5ea5d0bf516fc90cfded02837048132d22694fdc285e9cb3aaff82e897d181c9972aa8fd4296630d8f7a95238ff7e6115b115f944b1134da6827e04324547765498738523007621d33104a9a64c1a9668036 +Mac = 144d3a67685bf4ac70bb7fe6 + +Count = 19 +Klen = 10 +Tlen = 12 +Key = aeb526731e1d0ca809f6 +Msg = 68de2a68bd4215ac21bfe2b6f0d26ffd90d4ffc9f972dd47745e43dda24479bbc10041b32b0e734a1f41e50fc4b88d2b6b0fea3a15d29f5935376280b70c141340ee31b3b8bc6b5a064b92a71a5bb77631ca91b45408207222cb8f37d0045f9b6e11c2116c3445055c44b227f9a23506696fbde0bffca5b8c48294aaf714a27c +Mac = c3b94fdb9a6bc9b8e0b7ecb4 + +Count = 20 +Klen = 10 +Tlen = 12 +Key = bce413c5612019be937e +Msg = e1db8f7bcc0e5c22eea3e8dce39ac250c8681d3095f8c861adf0605cb435c4d4a1b1c99914542fbce958d4f40dca28409046e1cefc02f01ce60db35dc2d96c1efcf8f2294423a6a92980a990e9254c3687d8c8421f1830ce7762a3c6d6adc691193771f40383a933d5a2cf791eb31679d5a63b56a54570c08874996197b7ba77 +Mac = 2eca333903bf60931eb08ba7 + +Count = 21 +Klen = 10 +Tlen = 12 +Key = 10fd56ddc8f64b9fd800 +Msg = 285d7249ef30bf4b6e5f6bdc3cba5570c77f115de0d08aee7a63ecb2ae7cc11a03185a43ed6b7011938d0b7dd571a3308e1685501601799a0ceaa2b152b6a5b558a50e189ecdefad74c7c90205a8b0f09332ab70044c5ab09eb0db670fe4ed65b06b566e0a3c83489a736f13d147c6d95f3c4966b199745ab81d5e7cedeee251 +Mac = 04614d9e215e11546ef411dd + +Count = 22 +Klen = 10 +Tlen = 12 +Key = 8b09ea6af3ed29288222 +Msg = 2b7e03680c9ca6c759b6929383cadf567e4e38dd7216313cb477db12f4ad970eb87a27b209100b576b310a7213950f15558c36b95ce4273a1d0da3238d7b5c2c124c0a01382bbb45a6746ad75098d454eec487ddacbd3c1a230f667e88660bcd233cd3dc03b45f99f1c6db4aa29dd71a313d52d1cc6918e3adc44fac4b364cfa +Mac = f5ec42b8e5e3ef658223c8a1 + +Count = 23 +Klen = 10 +Tlen = 12 +Key = 71ab12ca4795505deadd +Msg = 5988c794c1f1e85d23d65be040c0129bb8a6bbccd86c3b1eb3a9588774adb571f2c3041885b37733198b77d6809f99970dcfcef05e08dae4790e07e51b781af64cfc860d37ece0bb3901930e3858d5b736bad96825204680fd76e9ea0da0a6428ebbb53a7ea50b3dacbf15520ff1ac425bef46fdd6bb693a686c665ef22d439f +Mac = a055bb1256afef8fac818a39 + +Count = 24 +Klen = 10 +Tlen = 12 +Key = 5f24aa8bbc1eca3eab79 +Msg = e8bfc5c09ec4807319d8f7369556e7654e981639e8c5dd3f0feae3085b4d2b2276fe514880ae10d6b2c4088042aebe428775e59a5e95dcf6cc0b7768e5af02a1ecc4831dbbce409b65a381d01bc5975c4cef1dfd10ee7e03c7b2b804fda55fd0923ce4a717cb17aa7a9deb90e644799ae52e48c9c879cc4e48082c426dd74997 +Mac = 449a3eaf1aaeedc860a7c522 + +Count = 25 +Klen = 10 +Tlen = 12 +Key = be881a061074ed05e5ba +Msg = 7d70cff8df77770eaf0ce671b7a15daf5bdd75482ae15812b3cf30dc9a8de052ebc6f321ad32d15bbb18391ccf11eb6ee00ea56aae9c51a09b677db9bcfd0b5b30d52a4db09085dc687eba7d05640db3107d5e337abe5847785eec709196fd4ff4a65dc51018f95a5f4850db82242a47933186edb7cfd4cef2bd644840df1ff6 +Mac = d991f360f28b18086fc552f6 + +Count = 26 +Klen = 10 +Tlen = 12 +Key = 67f385228039427df681 +Msg = f9598e9f4ece159beb897317f625a6a708e9aaeb8e9df706709c4c52f12bab53d709a4e9cb48d7c9025ab52d1d6f86cb4effb004bda2365f2a287f35d3e659ae984e3dec5dc3d585b0abbb37abc584d71cbcfd8be4fdb4399dc6ba3f8080a865854fe00fcbe715b83ba10e9b69cea6b3ba4b18e6cc56797e129f86d8bfa2a060 +Mac = 3f99eb6518dcdcfb45eda5e8 + +Count = 27 +Klen = 10 +Tlen = 12 +Key = ed01edde5f8bee443346 +Msg = 0f80ccfe5ade386b40e43f48136aedbe69849330274b761edee1c44a5bafcc1979f16d3b3a75cf8e169f524093b1c4351649d7a8f92cd214dd41865542e1840a554e8d3f08804a4968283df02ceff8d489fe8d094ec445052cf395bc55cc4d094a9d1350ed881062de85e9a004aaf1646aab9d9c4d9d38b873ffd7c7befa90dc +Mac = e4183c3f9245e63ac093e070 + +Count = 28 +Klen = 10 +Tlen = 12 +Key = ab692b9e0d9cc9632754 +Msg = 49867dfd015a50df8c676141eeef02fa2c347515bb25028d393d47555ba9d09b27a9e74e6338adde4def6a438c272240675e69e935dc776314957febde523d19590ccf66ae98c5ed1d8a7b6eee53a798abac2e888c383c8d3364932e9993236e4978db4eccc2c09464ff3ccbfdbab88b60e76dfaaa827693fc722a2675b3aa20 +Mac = 6a31ddbafa486d1a847e0b1a + +Count = 29 +Klen = 10 +Tlen = 12 +Key = 2541c892495452ed89dc +Msg = 204cdf0f384280e3d55f8dd010e88666080d2d722a1ce7cfaff5647f65be82fab3d86fc6d7110e48731b9dda483d941e4148d091b3cdf063e38d0086c9315505133bb7976d3dc6740048966738a89d24cbcecfddf78e07100b8ba9a328ef8532495fffa8812e6d0c84d0c19e69926823ae89727d7dc8f27e2dd6a8fe0c60dd2b +Mac = e2cfa49f38958405705dc320 + +Count = 30 +Klen = 10 +Tlen = 16 +Key = f5731a6e8925f74306fa +Msg = 44c7cc06ad290f3a54a970b640014cb5d1e6182352459901cdcd570c23ad4f995b9fe8c43b2528c9151228b2e44dc53398d299d2adf92a4a02fb6032e9b23dda7aa0c8762e334a7ea947bd54d6ed8228396b52198184779c5df93c22914fa2f549d35463addcdd1fb55019e43f69e95b5fb92b3ff66ceabf86ced124440de6b3 +Mac = 73b083d8be0d19ee7a697f9e5d76362f + +Count = 31 +Klen = 10 +Tlen = 16 +Key = 290566d777b0eee984fa +Msg = 787fdaa90a2de3937e7942e6711f165a89b9e077fe322cab597d749a7c8741b5e36a930e29e3836ace0627983730b602f63eec824cfcb077ece0f51702f9de0774222529687bbdb5061ab68b7ffd62c74e43b696be9cf249acff85a88e9b2a89b40f58a1ceddd999af1cb864506e61d11832045c5afb3a4a2040ebf527556f64 +Mac = d72b370a1d8290105173c83aeedb8358 + +Count = 32 +Klen = 10 +Tlen = 16 +Key = a7e54ce234b0d5c839b8 +Msg = f9a9c16e3a4beff0d36430c0e7e1d6bd68349498d240d8dc19755a2cdf3cf5cceb95b764d7fe340008981f5ae4851b5c3e94cee1152037bc7f3542fbe0f59a6d5f3abf619b7d58b199f7caff0205093f8bd1af75b42f4bc0b5c5fb98b56f3d543ee202efee8f040b6fca5a36a92b496d35345ede1535b9f2a36dac8bc872858b +Mac = 657db872e6e9aefcc3d69110c7591057 + +Count = 33 +Klen = 10 +Tlen = 16 +Key = 2918c7779c43fdf21748 +Msg = b949df3b02871bea0976873a9c76942ac934ce63ac2956d2856492970d8a231e0b1b178b22f6605ced2085494ec1986f026f68ae79aff750e5b92feb927cd08875e2ad04075518b754829b544e5de910686513076029ffdb5c0b179e39443ef22028086e5aab2a4465252f2147526d55229d3834099e55bc12e1b178ace953a3 +Mac = 7bc8883375527df5ac60fe47357e105e + +Count = 34 +Klen = 10 +Tlen = 16 +Key = 9e8c665ba53854f0fd27 +Msg = 850d673723789c780040620ad945ece61850a94f41efc64c8c81f45bd48d6b64af582eecdfb6918be920f9a00307e4433368297bb6a180b19f834465c0a87820cd0609aabfc5527c774ee578a4a589d8e6f87f6534780ae97b672ee68772b78827427dd98c4ee734f3f3aefc84c6e38d79293473821c6bdb68563746f1952f85 +Mac = 805a8f3cbb5ce17139cf8bb03db6b9b4 + +Count = 35 +Klen = 10 +Tlen = 16 +Key = 41164988752465a8f929 +Msg = b4c30b451325a9621e258a5d91de6dcb421cfe7957c1a7f5b667aa50bd466d23345814d07fbc550a185988983dc3fe55e662947cfad18822c2848b049eae1783f76102ed74f754fe71b256a7ad9feb0d42c023d5db690e9f21ebced07670f095e626fd255aa04b460f791912473adbfb3f7dd30d6053e173b9e49c3dad55a160 +Mac = b9b6e8e09db8509ac5a6609ad5e6390b + +Count = 36 +Klen = 10 +Tlen = 16 +Key = ea66bf3a628dd1a968c9 +Msg = 487ee933a49275727c8e36588e4c68c295a5516ab441c85b18aef8a9dab0625e22d821b792587291e216731ec7ff2bdc1a9ecbc836ed33cfa26bb885f06e2519e4bbff89d9540e12619118eb2c72f0322b34b027f422429869ae259c94c06d84d64e0c0f412d51dd4227ae26834dbeac0f8e86eeb889fc9fb6a0c556904e4387 +Mac = 571b3401f273a16d9d6011993c78bcfc + +Count = 37 +Klen = 10 +Tlen = 16 +Key = 14f43e5424ac9aeb97e7 +Msg = 9c3a8524f8d6d9ec907be803baefee0aa08b74ad4ff60f860a334a3ee4dee1f68eb230e56d4fea42ef3a0e642026172878727493f7f237b875f211dc33787ed9b5ca3dc0d43003c20ffb705122c64282dafcc9b6279b9b79733788aa3241d0ddba8994fd55028b3695c5f611e859d6e16c325c5f0577a191ac0997f00ac040c9 +Mac = 6c82c5f72dba335ff85181131dbeb990 + +Count = 38 +Klen = 10 +Tlen = 16 +Key = 6251c2a2976b8757adca +Msg = f1f9c895ab63fcdd69aed763d998a788e92ddb5294477313fc56b545ba5d22b9723da8f1aa3619cadcabdc5dc925e328119bdc6901f1accbacbe19443d52c63e8bf865f5ee78282052e078d38984eaa4e6446f0d070dcb11f2a34822649dab4365b1676a20311128f2d6148bc1bda6448faffa054ea5b72df68baaa7d645b70f +Mac = 9502475fa252e5bf4318e451c7f5fe41 + +Count = 39 +Klen = 10 +Tlen = 16 +Key = 036fc94fafab92ba5539 +Msg = 5b1a6754c3c30cc29d041779325922781454897c9c3f7cc69703521e3d49201863de8b96f15cda8e9507500eb9f5b87db37241233ca28cec2468046844876e17b307c0e43ddb37ef10c0a48fb96807984fd85ed9ee0fbfe967e8a524364188f0b55db0458f874a6c76f8bc0619fb3651504f89a79acd3d47ca4add58fdbf962b +Mac = 736c3332227a1b48acce71465f5726cb + +Count = 40 +Klen = 10 +Tlen = 16 +Key = c07d47559b6759f09651 +Msg = 434a42273f11fc06bc8eed402450f1915399d7e0a71c12205605b174053a929696e0d2794122872de62db204a17f6ff3a0626f3a31b3a8471fe84bd83f52f761469e2caddda202c7f8571b1b6321d6d99d57c59aeaff6246a4d9fd35d2a0f994fc8c380b3d1bd49c991110cf91bd8e0cf57fc248fa87a6e48cdfafd1e5ac00f9 +Mac = 66af7ccfa98bcb8d01ead88d046f1038 + +Count = 41 +Klen = 10 +Tlen = 16 +Key = a32e28d4b458ceb7cb13 +Msg = f753f3e9b4bd1895a259492ba160713f00ac8e24dbbfab0da7070e720b61b2b6f1dbf806debe99847eccdfa584c615d7b1313c68315affa32e98e93ca0d1d6ee623fa7628b743a53fb9c9af0340372816cd7c84ee02ee7bc6a4a9dba561ca75b72086ac464e8e4494053e1d35a1f728559249b9f8d434ca283a892b5d64b0f47 +Mac = 2993b746cb98445019cb1ed31ed34070 + +Count = 42 +Klen = 10 +Tlen = 16 +Key = 9fc05ef49579aaef45c0 +Msg = c5ff34dd398c10fc020277ab85050c51a1c4d238887e9b34cd46c386be031dfff3ba2e6927109922470adb0ac918389f3f52f5672c01c88f16618dd1dca53a9b4a3c156deb5325821e9be6b46c4c419a196abaf3f947ec47854932cb2eeda886f20c52b22c5d9a65b03c007017a90d87589488a39958eda544851b3c5ce24d08 +Mac = 287a4765a91fe81c21c4593f985a1253 + +Count = 43 +Klen = 10 +Tlen = 16 +Key = fe5df14e5888fad138ea +Msg = 5e09b42139c3e0c709527f4f86d73697aabcdbec1d518accf1b7f6f08ffefe8af18a81cb12bb72a8a3cd2fde00fc0e3362ec39ff5649bdec6eaaddfa36bcacc6699cdb0b6584cf69ddaaf665ce655cb2b49279affd364e30be65b081a562e3a82f076aeb1a671e921eb37eeed85a469a07744301fa61652049ad168ec437cab9 +Mac = a8483672c40305d7630f3e86b80fa4b0 + +Count = 44 +Klen = 10 +Tlen = 16 +Key = 6c56890c603bd3833d21 +Msg = 6ed7bb6653ef66ce21b7ba0ee616d07114c64d9228642b158ac3bc94b486ebdc97eec65a3af039d0a58b1c4cfd58715bf063e67a5439a2cd0a423d14295110da587ab0ef7c24b519945ec007e077bc8649c863f8fdd504015a9584830d0da4cd7b24810f60b26111b5daac25d89a395be7a0cbf36c5fdc18406399cba9e12d1d +Mac = a7df6225fc8a9bc8b91e4c39eef870eb + +Count = 45 +Klen = 10 +Tlen = 20 +Key = 59785928d72516e31272 +Msg = a3ce8899df1022e8d2d539b47bf0e309c66f84095e21438ec355bf119ce5fdcb4e73a619cdf36f25b369d8c38ff419997f0c59830108223606e31223483fd39edeaa4d3f0d21198862d239c9fd26074130ff6c86493f5227ab895c8f244bd42c7afce5d147a20a590798c68e708e964902d124dadecdbda9dbd0051ed710e9bf +Mac = 3c8162589aafaee024fc9a5ca50dd2336fe3eb28 + +Count = 46 +Klen = 10 +Tlen = 20 +Key = c52109c9d0da9258eb73 +Msg = 52b113614b80b970510f65a25d46edc023d9c7b8e7ca7c41923059c205366870ad669fb7572856dc4685ffe0833111a775c9455ab1590509132121950e99c5cd40b2a8d74a5f85d2de54cfb91a0da18a1413f4a8b67b147eccaf55665b7101c9341c9687ca2d2e9941033ff5c7e384b1273f3b6c9b3891eae2615bfe93c606ad +Mac = 2fecb466bc920f610e3eae9949e00f454a714ab5 + +Count = 47 +Klen = 10 +Tlen = 20 +Key = aa6197d4afd5eef5187a +Msg = 9f3360cf8f5465c7d24d7cbd7bef00315cd4f4ac29f245f6db714e8853baa14440d1056442e4bbb1502406f557d3eab2239e3314832eb925a8fae340cf5f6ac820f25f19d51570bf9ec867e744c2f3128dc1ab11611e502d2aa452a681a2965f063f77d78f0e0b5b86e2a77a8ce4a5ba62e264890aea91762918a5a1b0acaf70 +Mac = 3745829991354a1eb42277bb9aff04ab2abcaa47 + +Count = 48 +Klen = 10 +Tlen = 20 +Key = 9e0be94ed707458d5cec +Msg = f5a07e3741f03174c6efcb1f9f186d1f233b367073c56e814f4204db2e203b048db6a0a387853fe4a6bd161ef903cab46671993942de90d71f60fef1e5102807250d3edaa9c48ed1506ef89c19d9a2177d6ced710266a78d0d6682a8f730c43d64ae4125d03586036b0a58df27255d110f341861dae31b6cc05b774a8c08786d +Mac = e7c051682dfbbdecc828606868a8fe2eb85919ba + +Count = 49 +Klen = 10 +Tlen = 20 +Key = 65e06954b0350fb3db19 +Msg = da82641c0e59bfabc0618cd5cfcec107050ca4c1ed4b3b3fe93b04587f14e7a6f4da69e71cdf22a37089711061556e32ec1c20466f96f161bb1c5e556ab2f3d4734477d8fb3064416e059ac0cf8a53f54c035ad416af784d6f952f2c0581ab3e7e49f6b554546bcde35d6db0c07559974d47b8338aa0ba4b2e2fe0a6f789f82b +Mac = 60d775c440e378a5b3df018edb08c33c063bd8a5 + +Count = 50 +Klen = 10 +Tlen = 20 +Key = e89defd40777fe173167 +Msg = 1a40e896d0c0c13e7824c3ef86e02355feb629ea887ce4d2c71f1d02e7e889a875fe42c7742d7822ade5645c46867e5d96daf0f838e34aca5ed87765686af0aeb64b2f83baf167a1519872c553860b1268923db31ee71bc13906b2674b0a3c4484309710ca96f5830c43d472d468313c1ce5f864630fc07f00b1b551b551d533 +Mac = 3fdaec4c28dd5758d937efb8cd4ada0cd40a5d13 + +Count = 51 +Klen = 10 +Tlen = 20 +Key = 1501b98cd2b030d62660 +Msg = 5935a870229c7251fcd0c5c6956144f251ab2a39d74de951d0dc119cebd872b525de854947200828b013e99b546765f9053c7175f293593a6d02a7baf1ad46426371e7d29862a42d1878e32c21857e57ef6a21b63b8bf3e502807867870eb63c9b5596b61c4a8e88bc687d2003a3d637989e01a6bc1dfe7b17bd4c4cb7e309cb +Mac = c3b30827b4e2bba31b6fc0985fa597eb4896c7a2 + +Count = 52 +Klen = 10 +Tlen = 20 +Key = bc28be9d8fbb1d766360 +Msg = eb5de69eb1371bfce00ab629a1362f0d4885af7a71f9c90f4ec9655d3fa6fc49a3420bb1ef13c153fd55fbeaa64e739992d5348d4f1552dfa18fd7b7195e00b7e9bfaa97f7d0070c309895ef1f48519bbec028978c55ae75dfd212f97cbc527e65dbab96f2f554f123dd6b8035ad30d9734f71de4f424599b19afd6b8f495866 +Mac = d7264b214307520629ee5e76aa4a8dda4b556b3a + +Count = 53 +Klen = 10 +Tlen = 20 +Key = aff7d836880232f8132d +Msg = 10ca186baa79d9029eb618a2e5a636b9893b30e20b062258034c0ab1065bcfc9cc1e82fc92f0e398beae2791c210f8774239bea6798c1dbdd9c2be51f13953e2948fd50d387010049cac623cae8dc065ab67f99f88703feb91d2e3df50ff609fb0459b0862a2692e80d9520970c5956b0cee6b35ff5a90cb72a600c5e955fee8 +Mac = 42ddd9b92c2a45420a770b9727bf53dcffc84d20 + +Count = 54 +Klen = 10 +Tlen = 20 +Key = efe1c65a8a230e96cfa6 +Msg = 5369745bbccbba88780ed2e2cc2d57e2591d02b5aa0cd59d0ae79995981e8b349dab53d31c5135f2ab218bd88243737ad2f3c59e58ca4840313f2535f06d9b0eee17f53fe1e9b981b000237486add1892676c01f7e5e77ec7e67829f2a5422c3eeb343e7321baefc2fb380fe01f3dbd7fdafdb804451cc6998669a1b6f5c881c +Mac = b099c135065fb0c4c71a4fcb37a95b13cff95437 + +Count = 55 +Klen = 10 +Tlen = 20 +Key = 4fb2514d3d73b4770a69 +Msg = a413ed98dd6e0901b1074381e1a90d59fbb60e2282bd6706494f3a2f200f6d80b209ab83ae45aca3259bb79c34c8652fe2c2a71a4b490a47ffbf3a44a539c5f3e4d622838350f29eced085e43c07a099507a7e9abd1d1496cd249a7a0316462d00235b7ea3b7625b744fb743438c48fd0c859a8b1e620d5a7c2760bb84cd7797 +Mac = d8fdc66e0c97c0738f236f3dde60af8ac6c3d29a + +Count = 56 +Klen = 10 +Tlen = 20 +Key = 1b6c5146ea28dca9f6a4 +Msg = 25aee305cda093a71094bc5ca6f570fbd67fcb4239f3d724c00fad64f8bddd638d8b10370e5becfcef5b386fd43841b90d8f7c885ca56c64ff57c641ea54d4505589171b76dd30d1901f01de2c3c0fbfa6b62a15ec5151f88310d08dcb5fabdb83923fda8f8e27cdf9c65dd2376aa1b8acda1f1071614c875420117321482bab +Mac = be13212ac81902215c85a7697a2d1870ef74f9ac + +Count = 57 +Klen = 10 +Tlen = 20 +Key = 2d544e003b09cde4a4c7 +Msg = 9d31b168ce6ec3184d7c36243acb4e1404d81dfd82f73f603f4fc84f15267bd1fd5f3d882540c9914379a4ac2a62549d9a85cdd25d5c2c458f5ca7a43e32c4b0334ccae30e9b75559997eee05684fa825af472045e8ef3d9140dd649b78c63cfe60041bfb206312bf6dffd08e7b8aa8deb2ff5dcaf14fee4736c3e86a9bcbef6 +Mac = c87995813b3156fd712c511c328bace2d05cab41 + +Count = 58 +Klen = 10 +Tlen = 20 +Key = 1b5cddff531babb51b4c +Msg = a785aba75e6829f93f7a141c715763b64effeed00ce131899d394c0bd39c4fbfc8d1b5bd7de32e87c174a2f6555472744d53016cb95373ff85a1b4f99e85bc035617121a0a558f3f02736570987260d89df46b43f84f55d490e0d5fa6da2cca01afecba44de5d58bc91d667384d8b348058b343b11fd6070869fb8f7871b06fe +Mac = 57e9692b230b55a8a206ca48838d8d1f920202b6 + +Count = 59 +Klen = 10 +Tlen = 20 +Key = 8d8d15d8a9579adb2d62 +Msg = edb2ba099961d38fd0a0a6a235d61271cb4d493b64d9de135cbb1fe086c4a4a767be280da2079817b47f6a35e1a4307f6efc6d3e11b4a7aea686bd0223e07ba9ce426cd0aee7ef283fa98de96a1f8a17b308ba04b5ec9616cb008fca114ba3f98b072d5aa34a0149d9e5b8c6b68c49c10138da9536cad5d234f13d3f364d431f +Mac = 0c662e4793938cc37f3d51d2b40548ec55914f0d + +Count = 60 +Klen = 32 +Tlen = 10 +Key = 191a700f3dc560a589f9c2ca784e970cb1e552a0e6b3df54fc1ce3c56cc446d2 +Msg = 1948c7120a0618c544a39e5957408b89220ae398ec053039b00978adb70a6c2b6c9ce2846db58507deb5cba202a5284b0cbc829e3228e4c8040b76a3fcc3ad22566ebff021ad5a5497a99558aa54272adff2d6c25fd733c54c7285aa518a031b7dc8469e5176fd741786e3c176d6eeee44b2c94c9b9b85fa2f468c08dee8d6dc +Mac = 402493fac26c2454d0cb + +Count = 61 +Klen = 32 +Tlen = 10 +Key = dcb463a13ae337414151a31aa0c3e8bab3ee781b9f3aaa869dc5b1b196abcf2b +Msg = 44c9bf3ae8f14cc9d6935deda3c24de69c67f0885a87c89996c47c7b3e27850ac71c2bc8c6beb038ba55cb872c1d5871fb4a4d63f148f0dd9947471b55f7d0f4ab907302e016b503c8db2e7fdc453dac8dd1fa8ed8586c621b92fd3d27d82af1962e7f305f80c3f4a72c701ddac1665cfb06df51383fa6f0c2ab8429db51fbc8 +Mac = b96de3a219d76614aaa4 + +Count = 62 +Klen = 32 +Tlen = 10 +Key = 93e7402cb2b1b594670e656a6ca4ef247231ac09b7cce194d76e3919e4b072aa +Msg = cb2a072d74a5749481030ee46edce28c471ef412c8a4814ac40b87cbc3c188a3ef5e8a4a313862d59731326cf9d431fedca1aa3396a448a3b34d9045987baf2a66da766b216fa36012716212695b13f3273f4ecd3b5d24f9ebf4a8d17658af67f845d3788d73be9bb96aa5be089812d3f1a1e7c700f6a0b435a9d857a7800ec4 +Mac = 2eb0b56949f78f796b9b + +Count = 63 +Klen = 32 +Tlen = 10 +Key = ac286e206d88a3c00e6705df211b5ead6a693625445351874131790911037ec9 +Msg = c7f4612dc47f7ce6b499af0a51e4a3ecb2ef40251cb420351c65436dd268040c90a04ba8a4ee05cf71f7d1efc528fc7366f8b02fee6d68fed9e2a7a9dd07ea0b7a29db73d1b4c74ab9f652f610256afd4fa4796e6182df7db6449f6d93e458b3ac197858f4d9ac9fb41c9be8dae4d3d4947a03aa1efa6cf9d911927f9c06374a +Mac = 5cee7667d0a29278aea8 + +Count = 64 +Klen = 32 +Tlen = 10 +Key = d50ff2c5448b5c2b695f61dc55de55ee96f7bbe57067ae856a2d80e50d3ea0c5 +Msg = 4c259ed53a1faa09d9cf2a1454cc2e5acfb3ab8893bfc3ca6b9a473f4d737baa3d51196a6fa798acac28addff6dc13686f74889777db18da150d9d31982c87e27ed1d96e94a074c35f1f98b3bbc8a8a5c25c2d8bef7b1e1483725f222854877ed54ce6cbf131c7b8bb5bf27ae9b5757a8f14a44a43c75fde7f7093f9471203e5 +Mac = 476d8d8db76e87df0a3f + +Count = 65 +Klen = 32 +Tlen = 10 +Key = 607e645e1bd7fcefa0e34602d34471dd71173130ff1c59530017acd06b76f021 +Msg = 1b8747af6d82c61f98ccc3d79c7acebe18bd1fb5b0ba1f15b1952b58f8cf941610d3ea349acb7a58f2b8159f0fc21393abcc9857a44c1625a35a13fbfb072d90d4ef5b8d881275fa4ddff7f6159202acb2c0a3823e305893baedd060f599f3c2af042224fffec0eef269f1447592a1f175c1c99e440eed483f77eaf1ae30ee95 +Mac = 3bddf9f7384c84b3a66d + +Count = 66 +Klen = 32 +Tlen = 10 +Key = ba60ee3734a54ae42cfeb678233ecafd8d55c783ca742865577279cd466f6c7a +Msg = 4617b323bc286d7680df7eddc101aecfa46c6dcc394367a1ae4b5ae8c29524ce7d5e21191e33b369565922bdb36ba73a5f45c3280a21d53e2500ec1f514cda2417bb8a5cd97693d1087b0c0d983fa3ddb198e955a8dbf0142d4118cac69026f77cf796f5d3393338000ee4d557c6c941032f865bf9b9dfad2fd886ef08aa30cd +Mac = c4b0bc18c2784c858754 + +Count = 67 +Klen = 32 +Tlen = 10 +Key = 861ae84f596bd23cd37970454e8908686022111154b546e1da84faaefdbcabcb +Msg = a0cfcc6559f2bdc8d0efe0519e8d311d3af585bfbf666d90ef2b5d4678ca0ec9777f20423be804744b02194faa5415c2596aa7d21e855be98491bd702357c19f21f46294f98a8aa37b3532ee1541ca35509adbef9d83eb99528ba14ef0bd2998a718da861c3f16fe6971725565ba171d276b693ec5c9e6496102500867650e5a +Mac = e42a3482a658c651f55c + +Count = 68 +Klen = 32 +Tlen = 10 +Key = 304e23c570eb7887270d73abba9c3268d0ae42aafb9e62c09a5e8954fe0e2aa1 +Msg = 2fa33c03ada40c598f8800e017dc802a1c6a3ff0ff5ecb58e1a7637713a00815cef0d6b125af95c537ca8c4ca9a89580540d77e83a3f6f92bf68109e163c4efcf9dbd5759df99ff0e53cc5eed6e595584bb3e67ae904a84f563ebfffa66d12a6162ede57fdcb5161ffa754d084dda837682434adf5f69d160ef118a4ac7d7c9d +Mac = d623d5ce7f0e22c269af + +Count = 69 +Klen = 32 +Tlen = 10 +Key = cb3c6fb3fcd464d5d2dcebac4fa41cba7a60706d9c888ba1af7e586714725b05 +Msg = 0f546834a313fe3981ef450f3e3b16bc184e3d6bdad57e65006ed63c1c72024978114659fda567a45340f9ff4a87e15279c4124b25369a5464ace2c381523151a3ca73ceaa7e39135a350037bbe5b606bfc87aae26b2a4bc9fa205473097706bd7a578fa72477c6ddcf7e12159fc9fc03484fffca6f2a384fa79c630efeac57f +Mac = 6cc56c226b22110fb13d + +Count = 70 +Klen = 32 +Tlen = 10 +Key = d50df8aba7273e6427ea6bc0a4fdd4d5b0364f336cc696b906b1edae7f82050d +Msg = 6fb3ec66f9eb070a719bebbe708b93a65b201b78e2d26d8cccdf1c33f741904a9ade640fce000c334d04bb30795683dca09dbf3e7e32aea103d760e857a6d6211c47655df3665bbe4164e5d1334d301eff0bcffe6dd95dad97fa63a0ecaa7b197b55b6f86f073cd4d524324aa659e19501d2145fb8adc1d70eafec04bf36c959 +Mac = 51ae4aaf0de1921b08cb + +Count = 71 +Klen = 32 +Tlen = 10 +Key = 1daebe36007d26b988f8c4fcaa0b5a07658ef6ff528325927d98649673f4d7ec +Msg = 1d7f6833333d6f99cc4de86dcb1a668af36966074c31d4adc9acd0ae27aeb19318364a77a1426d73c1e8ae5953a369a535eb07b0aa087c27fd2714bc68ae701b33cdcb202055834707ced464bec4e6943b610a73fd41408fa881fe1def192cebb66c7396781eb7fde726e2f5d324e43f4df4f8b70c8328cd10e113398498eeeb +Mac = a03712aad2fc0e59732d + +Count = 72 +Klen = 32 +Tlen = 10 +Key = fdefd6dbd43cb817b132754633c0ce724be5572e4e732b7d4813ddef9489b20d +Msg = 3f5fe1a8a13c8357149f68bce47360bd6e73c98932ec4a7d2ac4c5495bbb864ea9f1c14befa93b394f4c4773c7b1f41a059b85b87d832123b898cca5ef059659d87212d8c0cd0a15da4a7186d7a89985b6b7a7f5de1743286a429400c4cc6b5575eabe973b3259b55ca1d03d3be2b8c429cd16887d2f1854e7c903a4019b6d0a +Mac = af6a6235395d057c6d2a + +Count = 73 +Klen = 32 +Tlen = 10 +Key = e32e6acc16d4f6ed9cc3e23ac65a259c65704a3f8437c598576687a76e97d079 +Msg = a04d563eec5c909dee3f6fa8133c70f862d46333b9f5cade59718273a4afa5b426a1ae3ed3f5de618f90df2ff438a8d34f90a025eb4a067b939890c152e352cc7dc0e2ebf320babfa4c6dd4d50ffbe52918d5dd61ce4b30444995039c017435bad943a6cd743ea5f34cbb12ab1f97a1c31b1e271d32b9924745c0a0476b13e0a +Mac = 190e04e5dfa9eab70cce + +Count = 74 +Klen = 32 +Tlen = 10 +Key = 128ffb7d52b710de97ee921cc9d2bc5e0750d3a2e10dfc49c80550d6c27332f3 +Msg = bec8d88f65e49567f23cc953d9ca9bad9a5ab34f38334c55edf98a251cd20ead87c8c9ecc26f0db4e8c7eaae8c63b79ef2cbefe87f203f546ffedc0ec6a61af1895d3b042d0f8445503897a6a705fc5638b60141c946c4da984e8e184c2762be2c4ed6e08f0d22a39358774412f6925cd2e19062fcee0471d0b0474b969a0f9f +Mac = 2394aef32f606989812a + +Count = 75 +Klen = 32 +Tlen = 12 +Key = a12794057de3b3ea426fbe0195ee17b4873ef7e6ba87b22bc6143c38da62ec98 +Msg = d199875bb7071c434ab236e6d10f8405978fca259f7c34939424eaa6ff3ae444bd7900a7af8a5161b328ba9ed382bcaabde18db3738a6acf44e62d41fbe022f8568f1758ba15b23d24c7083d638e6a2e858c82e88f03a04c71734e8638032a8e8622f5f53f6ee7de86d5454be8fa369ad6dad34f59af7d13011573fd1f6ba311 +Mac = 445aa92b032c6b65b28a6541 + +Count = 76 +Klen = 32 +Tlen = 12 +Key = 2a432b462ebb78835008b4aa8a92b40f6fe9dc53a963352ea507c06c8da90a36 +Msg = ac76a7db964e9fad2f98c18c06f929f23b6217ee35ef4525920f771764e653a39aef73cdbce6b9c0dce5e20fc9cd5e4085e75f8bf9cb31dfe881c92622e7a0cafa52c278f9782124d48e304d9cadad82357abe250906406ffdf35cb4a5d95be8b3e7bb63b6ce82e101dad2cde862bebf33635c43cc681bdcbbad574854832b06 +Mac = 2f8e18b75cb37402d6e87355 + +Count = 77 +Klen = 32 +Tlen = 12 +Key = 232eabc478501f246e73e76bf0227e0356a4161f97687540baa702fe8e442005 +Msg = bf465c887060c762cccd43e4a65c76e9fd685f44e7fdea03c83dc2f5c702676983c5803901bf7207ea4d31c7f399577d9c7773481d8da3a09db765dca6aaaaf7d6d72c93d792023e917371f59dfc06e6fd7de17a0b355493b0baad13d69b4f9d2043089fd8209e902905ab768ecdabac8a4254e29a3d2665680e42a1411d7fe4 +Mac = 9dc9ffa7894d69c67295c994 + +Count = 78 +Klen = 32 +Tlen = 12 +Key = aae20e01f6185d8073f40fd7648098fcfaf3dd8b6c7becb14a39ea480e8d4c43 +Msg = 635a508c6c44c1eb78e3dbf5961acab6ee7d9b92a8aa473609dcedcedfbd5f78207ce0f9ce202cb01d1cb9c8d8233db1013d70d0b81b13755da7310ef9e0a59bdae5dc627e4fdce4b3c4850ffbca17b535d8f53d7ab3a99946f82778d8f456bcdbbccc2e457ad9708006c834c8b661acd476b341b81b10880af4587243a27bc3 +Mac = a246956f07f6af8830fcd392 + +Count = 79 +Klen = 32 +Tlen = 12 +Key = 58d259d3651b6533f98cd0f7da9cc4f3a251bc02cd063bed116bbe8feecdef37 +Msg = 6349e3265d2630d1e14bea680d342ce9f76aefb789027f3d8f6630d50e584ce8d73351565d745918c47ada243a8a8f908a16b6fbee3f7c292598b6edc62dd14cd4c40cdf9262e4799911d00a27e12fc3ba2d7f7bde1fcf5243767794128706e081827c89a6f7ba3c889936e37c41f3caaf36b100ffab61010f89db919a6fd3eb +Mac = cbdb6ff2298283b4ddec7526 + +Count = 80 +Klen = 32 +Tlen = 12 +Key = e0421039b649a0d72d2b5dba7aa02ef7f1f83303bd0110bdd32b89af29ea5091 +Msg = 64f3d0ce82097d36385b6717fe155d0fc5ed85bf80a1fed9e3a1c37a6b08d3bb9ed18f839448639fb6bea814c681c9b3200ca5ef3f7a35ec82416fd8301c6a7ebb49c21841f53e6558f5b0fc0bb61de020771e549db586f18ae745f5f76c8dde41c2333892f857b3a7664778d69ba1bd4f97b897a23b391081fd0f7ac7e08303 +Mac = d7fa45de6ac34e2d3ddeeb97 + +Count = 81 +Klen = 32 +Tlen = 12 +Key = 59b818b12c95be441ff52d8bd19286300f8cb877e25ea4cfcb117fa74db07782 +Msg = 9c84d18b6ec339247482cc3ee52a1bbd6bd4ae918216912d211c103a9dfbbe8dca43bc5763d3379cacf233e7559b873ba217294cc9d2acef9c6707d067fd98631cd6691dad25b1e3ba209ec36c5751e2a1442bb5492347740f0447cc3d1e54d5d96660431460aee0e635953af2078198af813a33c9b269a3c51b5898e506f9ca +Mac = 7fed72bdb85fbd6fd73f9656 + +Count = 82 +Klen = 32 +Tlen = 12 +Key = 4def685532999b6352a6741ba47bd2aa393961e12ae4267ecfc558ad310c72ce +Msg = 8436228556a7569274bb14ad6271abfb82391e809363cb3877d84a63390898204e23753d1b8c0a4eb88bcffcf442aca099e25f11f11e1db988e07cef343b908153a2548f54574ca0792569efda522d06aed00f8ec6b321665ae8f0f20823acb61a19892308f064b03df3aa2d1e8b7654496af9a21a0a1f6574566f15bea734e7 +Mac = 1dd37b69db9cf4a7494697f1 + +Count = 83 +Klen = 32 +Tlen = 12 +Key = a3e983e3e959ad38b9bc4b4516589b263ad2c141884e5c84c2d65dee7c001951 +Msg = e01e4133819800b30445984a5f12d6e3e1e29e1bc6d428a209c569e37917cee70fb030767f4505800dd8d3bca27feb8f1f68532ff11a0408e6fd555f3e1db835062ba46ea1c5d232a8f6ac94f4010371f85a009b54f65d37a8c4d464a67cd81e6c978461109ed1917ca80b197c1f865315c28da819f09bf8f823ce3bd9bb9869 +Mac = 24a2f45f719e993e63adcf23 + +Count = 84 +Klen = 32 +Tlen = 12 +Key = b1b6d5e0b9b1efb608912da48d561f4489102abaa09f399631beb0fce340a202 +Msg = 99d4482daecfeeb8d44226a39f85b42f9513fdc2d798c698044c3eb55a803f1e1e76d1483e76f0d1361e8f6e30fadc256f55c6bced4ebc71432eb8ebcaf87d7100421d5a2d44bdc4462f9c8911c0526f8a14569f86bec35996175ce52ed5cdcd06df3449c160dffbcd1a57dc8afe9e77aef9b655e81062b8c3af318cce3eb79a +Mac = cd4057acd7ab2b1909ade91e + +Count = 85 +Klen = 32 +Tlen = 12 +Key = c913fe12cb76e574a23bf46c9032105848ce2c71f61e6d5880ff8cf20b917d76 +Msg = d83c04027297bacaa0ba8bedb834169fea05aef6c60e00fcfec5f6036e2ddc385906c27bf640216e2bb6c1cc9819d9fdd72a79e7022d2506769ac2bfd715b7f155a04cce2d1055e972bd158f0d7e5d5b03d5f405f6663b7befae11335af1f5bf52746aa21feda062fd3850de1f4be8e2f46ce8f9a9a28c82ef69ab06fea9dfc9 +Mac = 0695b866fc28c2a3390e8449 + +Count = 86 +Klen = 32 +Tlen = 12 +Key = d3dded60911343bca3af35d2dccbca9d2344b60c74b4819e27a0e62f75f37a12 +Msg = 0e9b073a31c8fd215af1d8d0ce54ac9ae109036e1794250988b7966a898adf8688cd913e387c888eefa46d074c767e7f1c9992077ec5571d468edf23a07d5b10f665266613f405648889ad7c4e458507ae65ae385ecf414eedead70e60b34f711e0ecb9a0959fc0aee47a0171fec489a5e145fe9fdd968054475871413544311 +Mac = 1b0dd1dec270305c1a669ca8 + +Count = 87 +Klen = 32 +Tlen = 12 +Key = 04d31106098fbda19af28e84339c736eec54e5859d9f288f4591ce64ade47ea3 +Msg = 86c7c82bba165b31ad74d92ba22a3bbff926807e5396f414f7b6b2c275e6680f89005aba41e8aaf26265d6c9092f82e78e49787bad90ed78e89506fd27a89a14a2353aa000546e91c09b425ad93601a59d3a4145e3371f6c650dcc1e670049e59a0e6ec73f7f31758fbf25c55b694162f0a4e3c23db2145938c60e0d7d16fce9 +Mac = 8e2916ef6b7bb91c15901210 + +Count = 88 +Klen = 32 +Tlen = 12 +Key = addde2c62bfa0722f73b99add65f2b3c9bfdc93c4b1839ec7ff380ca0a26a94a +Msg = a64ad96be224dceef6563f18c63fb7555ad926933f8e1cb02a4d9e2edfdc272e5170ed9c0b7b65a7cec509747cbe5913341320b2bf7ff8102be41035b59a2d61ed06ef42146f5669c90e84ffe564c5b4a3d1ccf90461406f71e9779fa25381ebc03668c4c6aab61e2d5a3821c8da0222ed3bb3d1d5ddfab4458559d46eaf29b6 +Mac = 1930cb1a51265b09b0aaba99 + +Count = 89 +Klen = 32 +Tlen = 12 +Key = ab40bb089199ccc0ea49c6f5216280f5dd3eff7c771f8f7bb1121217a51999f5 +Msg = 22eeed3b24e076c260f12f1530695059b23d0acbbe331a041b479d7bf24d264b82d90e36165c0bea348f048418152453615c2ede09c410289a03ba329fc830c2599ede63b4132dad791a53c6c5af6f29bab9d5a67434a6aa3f8fa5c107534559100607c9e74f0292985bc3e4217e5864271ea82ce8cd061371b5052f10398d99 +Mac = e1c43cb277d8c07146fbc6e1 + +Count = 90 +Klen = 32 +Tlen = 16 +Key = 58102423a4168fa60a5aa7f79092d52326c98e22ee5f3dffdb527d397dbb8c68 +Msg = 480be758a9b7ba9af001bf21db00c451cfd66f06c9d8d5d698ef47974a3d6f21e4049d5556c45b5fada447378b13226ed4af2427ab6692649ddb93831b0b40082e30fa9c66e60056148c403ab8ed6effbd1f541664ac69e7fff0a45e5fc292a68f57a734c362d2088b80532f4cd4d18df1eea7d9def280e925f62330fdab9085 +Mac = 4c41bea823ee6791e83636bf752c1240 + +Count = 91 +Klen = 32 +Tlen = 16 +Key = 816aa4c3ee066310ac1e6666cf830c375355c3c8ba18cfe1f50a48c988b46272 +Msg = 220248f5e6d7a49335b3f91374f18bb8b0ff5e8b9a5853f3cfb293855d78301d837a0a2eb9e4f056f06c08361bd07180ee802651e69726c28910d2baef379606815dcbab01d0dc7acb0ba8e65a2928130da0522f2b2b3d05260885cf1c64f14ca3145313c685b0274bf6a1cb38e4f99895c6a8cc72fbe0e52c01766fede78a1a +Mac = 17cb2e9e98b748b5ae0f7078ea5519e5 + +Count = 92 +Klen = 32 +Tlen = 16 +Key = edbc48ed948cccc421efc7a6475a2dc2479dd9996f5e2f10e0c600c3957aad9d +Msg = 6dcc3949424fefabd4b3b7b4cbd098a677878101640380ec2f3f34d699c8855ddac5926f3834ebafd776011ad30edbea8ca60aba4152deece119da481db266e5c28bc44d461045dca029bd695d043429f116decf4b5c4ef8ace7e6c7b89792ccce27b62b956964fad7d3d3ea933b0c2a4ddfe788a9a836da38b0409c920171da +Mac = 9005e6ded766f31ca4277bb116c483cc + +Count = 93 +Klen = 32 +Tlen = 16 +Key = 420e70ecc3cdaffb726a183c793845315f730fa4dac9fe46e4180397107a6a05 +Msg = f53ee3e2ce4467de8b3b30aece9404dc90aed0675b3f8454baf62465ef5f1c29e306d53563df85b088e54b1577027b344b2f377a50dc3f737292098df5d7151f66527ba9d12fc65e34c504df34761e4a0fd76673d2116f71cc88215d42ba0c566469fdc880fccfee762384966cba9525c2f085da48a8bc57af1f935d3ecfacd7 +Mac = 9a148fc9f2372f9c07c328e832b96430 + +Count = 94 +Klen = 32 +Tlen = 16 +Key = 78b8b8aa70fcb2b0cbe835941275a5405cef6d8013aae759f6f17c9d643f0cbc +Msg = 538e379b06f1d89a9ea978a8f17ecd6f8a22d1d15a1418e4aac5603b54fa6a68337108bed8c7785c7e99f06740ea7a968ac402f4ce22ade1780e6d5a2307d37b0da52442c880ae96334d5c88a94a89d878dd12bb9577afdb8ebf83a0bfedf1aec973b2af40e32452a40de5939367a13e3cb328ae17dbc4dbd420c99491736d08 +Mac = 85543d27b8a34ed9e222172ce308c672 + +Count = 95 +Klen = 32 +Tlen = 16 +Key = aa01f699da8d42261e3b04ba1389d2631e985fdba28a4c0a762e40cb96df3af3 +Msg = 426090153dd06665123aa375cb992e221cdd03068b827aa7d367cced8bded3da03ff11756f43f407474e588aed0b4e5f91fe1c3f52d68574a5424a49fb06f0bf9e4ec481dc421d1a68dae166fdf44a4644a4ea98f8cbed6748eb9f5e7d392e83dcf4b022cef667063e8944ef437bab41ff7576fac7883ce68309d316589f138e +Mac = d9f1dbeb901ac73bab9b5d40065c21e6 + +Count = 96 +Klen = 32 +Tlen = 16 +Key = 6733498582e94a58cef983b1f52f215da1612e8e48f605814aa9095d398b965f +Msg = 3c17d3274495dcc86f2722398db60237fc70fc0e63b30aa4a32c30b90b40556dccaa5103ac6647e4fece35e7d104c9cf688f7716ea49c8e95b78f573cb3bb45ecd2852972b330252d8d1754f265eaa5b39bc0819bc3eaa02d2c4faab5027814629d7fd6c2ac2b41ae77809f9f58d4de2593fd7a1415957f9f25867e902cb632e +Mac = adbffa3c88f82e0991fe2128ba2798a6 + +Count = 97 +Klen = 32 +Tlen = 16 +Key = 3a239ff156058ea4ff05e0f672b7ecb5d106fad5d31e9d6fb989430a84970a1a +Msg = 4ae231eafe77a158c2472143faf169db29bf2b53c3288d8b3c9added65778095f85e2cb471ab58362041f0a27d874c42bbb06385a0403ca193cba67cf70029cdb7e73c7e2267b856fa0b8dd4c706b45e7174659b0ee2891df911724324f7ca5daf07c912b9b2abff762e62a1817688757492975db7185c4695f3a90895634b8d +Mac = 9411d3cf30e359f33328f80a07b7ba6d + +Count = 98 +Klen = 32 +Tlen = 16 +Key = a3abb893aa5f82c4a8ef754460628af6b75af02168f45b72f8f09e45ed127c20 +Msg = 00bf40f1efb6484fb6f9fcff80510bc8817959cde43a98ca04d5189bdea1e0fec7f5fd995a481a3fb597516fe508411d9ecc61b52f49935eb679fd7c908d147814d7f9c381e6091834f3b0021f7c7d9f762e7ca3ab08c09f9dbe3f840d5be363512bdd764cd83d649dd3bfc117f5e8d47167529e3fbf4517216b86bb3b537445 +Mac = 79fffaa6767b3bacde8078aabcfbda9b + +Count = 99 +Klen = 32 +Tlen = 16 +Key = c3070d79ebe3c6a98ac13e50ae4710e602485a68a04329fb272c31d30d6fc253 +Msg = fb9cfb8a89761e4c02117be850006b26aede2a205f342d459f9cb6a4da27a5681cfd919ec943173f8e42726a97c54cf102c2d417943d1198ab6a76ea7412b6c35e37dadbcffb90f315bec6169f87771f6da5c57bc59649302827a71e84dd6585ab94fdc80466307180ce9e74d00d94b8d6cd25d359057c16fc1c70c9715159b7 +Mac = 8aef0e90bd29fd1ad4d80c37e070dbf7 + +Count = 100 +Klen = 32 +Tlen = 16 +Key = a9d599a9d003686e2a3b2a27407644b73bc4d7c7ef3ee75d193cbdb0e5c8893b +Msg = e7462835e38509f5bee74c3133482ad4d7fb7ddcfb18c754d2177682d79e66616998a852b887820ee51bb6df65030710a703faa1f647da40a0f7fe75580b4f1dd9610419cc0cb047ecf07fb1688cbc058816974694cd26c0f28ba9418e9912867fc8c5f4e7bd9c891a8d2e11038a519dc45cdd319d53b3bd0ffbfe4e41f1b986 +Mac = 11ddc4d89e463be1338373f0a1cb22f8 + +Count = 101 +Klen = 32 +Tlen = 16 +Key = 8ef73e17f2dc9e063230a3352fe5c549c1fd526c43f90f57539522b0d3b22f97 +Msg = 757d2b41484741e4f9a9fc4c30fc633d31be09c856362715bd5bed603ef31a42a0f8cb320c3f904bc15cc5500ac020ed6d24863f262b2397d442b97b71cb38ee877c90f2a101c34a00e93e8490bf69371b777d8abb0d96f59568094cc484f7f994d02288f1d5006a1f190ef2ab4367a4a17f95afff24a7b86a9583d920657eea +Mac = 7a5efb96b080064a05fd021e31f1dbc1 + +Count = 102 +Klen = 32 +Tlen = 16 +Key = a535c38a4f69ccbc134306f5f158019b7c79992625e462e9bcba4a2f34b4798a +Msg = 71db63e8b1392644e6fcf7c3d81a03a7518290f4d30048768a61d40580d7ad08109f2f389de0f0a784d74f004e3150102bb8a7859c3212f66f86ec24f02100805e989bed9c8fe5c629d9702352e11258a648f0bfabcfdcb8cf78e1eda1e81bdb4110cc8e150cadabbe4b82b44bf1f188ac799429699f4dc2947ddae9fcf4a921 +Mac = c070e020d56f7e294f10fd586bc3e063 + +Count = 103 +Klen = 32 +Tlen = 16 +Key = 2b3a5890de01a30f88d4f7eaaf702f6129a5e7718dfe8f9ce7a4bfe8b080ca2a +Msg = 179645a0885bf0f1deb9f6c105bdbf2bbdf728e6ed81786c3a3e955bd960781ba12ddec1650240338098068db186f8c42a07f58ae3fee7713437f652a3f0fcf0fb9839d99ed6498d1bcd52e2039f82a7f92fb988092c82313b4b48b767d3c7334a5fc0b0dadff147d7e14488a30f471c53f8dca9061332f67500f350cc12bf2c +Mac = 3d866bc71d43209d97bb596fa59460c4 + +Count = 104 +Klen = 32 +Tlen = 16 +Key = c05d6b83a27ef65cef5571222d24adbcc18958640548bc959a4baa2b00e7b0c6 +Msg = b20f96997b0603a0bb860070369885f3bb1908939f6195fd6b232124d2941c89e6d045bb8b79c2192ba170dfabea78619eeb2391b9d6efc78758e2c25ec11eea9265b6d7e842c0174ee3ab2cc984d3d5ae76538f15c51a5a8b1942c007da9d14209790f87ca924218c135a5f76adbfd7538241939b76413edd2ce928b426c091 +Mac = 15eec3c6d6f4e7f2b1426d01259ae8b6 + +Count = 105 +Klen = 32 +Tlen = 20 +Key = 895868f19695c1f5a26d8ae339c567e5ab43b0fcc8056050e9922ec53010f9ce +Msg = 883e6ca2b19ef54640bb8333f85a9380e17211f6ee3d1dc7dc8f0e7c5d67b73076c3eafc26b93bb248c406ceba5cb4a9bfc939f0a238e1559d0f4d84f87eb85975568050ec1fe13d3365033d405237ec92827dd8cd124b36a4fa89d4fb9de04f4d9f34864cf76f4ec8458168d265a5b02144e596b5f2e0d2b9f9cb54aeeeb67a +Mac = 374c88f4480f5e8aaa9f448b777557c50065e9ac + +Count = 106 +Klen = 32 +Tlen = 20 +Key = 950fb0cde30f34f597af5caa2b16fc86a5c3ef065d36ffdd06ec048eec915039 +Msg = e463626506144cece55dfb7aa22eb21ea3a4277d892c211762ea45cc205c2d9e4b3abbb8f2a1adb0e77171092cf43afca8c053771edeb467602bd333c0ffbc88c80d645c2b8a3a2dfa92008a1bc7d9d5f83ba34774908634235dcd91bad4f5b3c4a2045997171ded8787500759f0b633fbdcbef47289c2091348deeef62301a6 +Mac = 8c90480ea6414553df17e53cf96dcb166b94be35 + +Count = 107 +Klen = 32 +Tlen = 20 +Key = a31acd1af261a1e7f751140a580b91d476792a9f96e1dd013fba1645e2bf761b +Msg = 6cd70039a77e420d999b57caaeb53aceddbab11739447faac31adb3583fa22f3d796c9d00adc95ce287a0ea711a231b4cd0a650d1f38b0f25dfc2b697e3eb32975f9e2b7be883dcf3621af052f9f37acc484ddf76a3eea5ec8a95843c9d688d6ef0b3336ea0aa3d96996232d3034b47f6a2f011d41de95b7ad294c0b894a07c2 +Mac = 1b6a55344a48f62f8b351c69acb3a33b4c57c024 + +Count = 108 +Klen = 32 +Tlen = 20 +Key = 8ddf3be2ab49f11f12f392a09f5b72fcddec1e186dd3e49aab0e95a08ec589b1 +Msg = 8a2db96a4df188ec323ef6eaa7d58b56216b0097beb5013929c231e3be8d6f89eed358e2e5220c1d6b3335d0087946316cfa01880d5e3ce41245e40d70de42bb53b67d05bfcd611c77ef5e391e41d4d49c1b8e17c3158c92336505307a68ac6a807e33ba231b0d531e1b790f2f56bca97975ad2c270477ab52c89b33245234fe +Mac = 7652e4b24051283af4caf67079955373f6604c9a + +Count = 109 +Klen = 32 +Tlen = 20 +Key = 90aea6f7c6c3815718ba1959ececaf53128020b7039a51e766d0cf4bd9deb7a2 +Msg = 1e691365ad90646031e01e737cb3c65a665409621d05ad86bd47c9d721553121f8f235cb1b648bff1ec1890b24699707f8d4e5b85a8e59b5977fccc85d707597cccba584d0a2b5d1aff33d08de2b879a19e844c6b2037dbc2acecc03fe9acb18c37dcd587552cc1f0d00a33251007d5af0198e52ce6e01e39dbb314eaddc1bea +Mac = 8a536922cc905ed4c321180ebbf4f000e2a809fc + +Count = 110 +Klen = 32 +Tlen = 20 +Key = 5e6a489725810a85fe4505fab03d3b3c78771075e913b759f701ea084e0ade36 +Msg = 212a0448f4b39f0d22f9a0d5a42066167056368b9c668272c78a6bf8b58184f239e2d9cd58b030c8ab2e8e6005f5fd0c56438d2bcf96993b477a4b4bde9f62b3e02e3302ec5dee3855422336c8e485722f98edefd68ba26dcc9bd7dd8d6b7517ddb61bcff7e363c5e7da683d351785afc3fc5fbff86c256f1e951694090d4487 +Mac = 9e35e4bc678997c18bfb39568e1f77cc49ad153e + +Count = 111 +Klen = 32 +Tlen = 20 +Key = 618406f43dd79acd2cd384b3d12709e43d267d76febf63ed58afd60dd2f528ed +Msg = 2d9313691868161ff609b6f0b094317198dd94cb41fb2e62930744b41e200683afb2c23621f8587d76c0ee34276fe48ab7440a628ee111f9050740c9bea168ae36041a489d7517a0e5eb080e1917705af0a2de21a2b6677afabf53daac731735ea10846632e43dd16a136e472e95bb2a697e77d12282172d99b8e6ad939efa60 +Mac = 46d9d7c519e520029320b48451faed81f9112f44 + +Count = 112 +Klen = 32 +Tlen = 20 +Key = ad445da48d46abfef103f9c6c5473444ffbbae90275cc4a8162bbec0fe26f6d9 +Msg = 81c94be426eaf01864e813a03e4674491b61516bc95d8a77c15f03d0adfc4adc27f27a5ac4165ff6518eda1a5c408708f78a9e26b834179804a312148d4f75f21a77d78387139da40c0a6293c2a59d0162437d68504f189ed970c5abb9ffc6d8e1be2b0877c7f24b1dc273b1765bfc5ce6f4b8d99a96d5b1c92ee53a39f685b3 +Mac = 91bc355fb0221825307af876d11404b473222d5a + +Count = 113 +Klen = 32 +Tlen = 20 +Key = 05905a6ecb1679364090c9510f06fb3c0e09321b21fe0aad5cb9d980674e3561 +Msg = b34e5b0832128d3a8794c2ab447132857ac0a83475f6d96ea607f470e1ce7a8bc9af50e0887b1368c393ab37cc5123011aa3b7ddf7f92f4979626c6eb3f141a62c66843c910a6473a6dbfcc982e9297cfc00994e6187258568a8613767b271c4c6bb1ea4b48929631ab3dee9cd03edff081f760f1968632b5a23fa5163d7b2ee +Mac = f76d200078fb5b3d3aacc3d90efd4edc5612a777 + +Count = 114 +Klen = 32 +Tlen = 20 +Key = 3e9eebe9add8e8315892c6b3bbeb77abf60dcdae1961e2839fffb73538691b66 +Msg = f184d3809b13c417e06c7ed51d89e79c026fbfbbf1022662a61d5e5a1de2d3f2b04f583d8112b47a179f5dd44c7f834c66eb50f384996f5c3cd6cb5182d599c5cb47980a732b97445ce8391ed999f5bbcaa860f0089eafb0033977c7a9c0b8cb8a931a503a06765cf76f981b8c7e44d375cd761944b8ee46446fec255b4939ee +Mac = 99fbfd85069f25da97f9621fff93ea599f61d0c2 + +Count = 115 +Klen = 32 +Tlen = 20 +Key = c116c698b12c153b57c9d57d4eeb97f7dd8eff14cc2a2dbd767e7c35208c6f41 +Msg = bc74041ea20c9b7489dce3ba9e279c00c124b6bf94b90cbfd2864f37e3254037adb02343ac8470404545cb955723368a145b86f30f00131395fbb4bb4151ebb2cba45c5921fd848fb9c8a7d325200aa8e84d633e888b8e4ee40d8146c84282a6bf5798aa28fd3f298c6c5fbd2fa87f24e50336e627e3e33866c59e219f826fdb +Mac = 8da25f1b52990f59dad1405161c54eb148f002fb + +Count = 116 +Klen = 32 +Tlen = 20 +Key = ff73004a8aa629ca5c72414ea652a6533fd282e847a492650af12c5926ed80c4 +Msg = 2f42a2ad39f842c355d46670455817e689ddd9e7e8d8e12b4d5b8302d4dfea3a25400b430109db911af2c04228a7460139cb142a483d1e2e129a1c3a25033a133a201145c464d67cc993d132f182118add1f5f7cb9b0703315605fb3f0f75abf16e99bfaad92994c0ac08087c972df4b1cdfa12763ba3f00fdb534b75e44b006 +Mac = ed84ee8c4d99c5dbe7a253be436ac0c4e4b5e0bc + +Count = 117 +Klen = 32 +Tlen = 20 +Key = bedb392f8a77a470858a9c366b7255f3b25c9a5d10b76d793de9eef8fa407ec7 +Msg = eeb955b959c48f359e05da6fe4992c907c1c0134671c007818cedb547a00772c354f4da12e9a10ad4cb78fef8264de430a80b096ee7b08f9cd0b11f3dc20491c2b1be5e72a3a72c06b57b857a9d3e33b0acde5aaa19716a8376a1d4e4b5814655783e733558dfd95824f1b4e62ce859f046a6618875971addd54c90ccf901e2e +Mac = 7ab9416ae1d32bbbd13277aeda805d66b006461e + +Count = 118 +Klen = 32 +Tlen = 20 +Key = 863bbe40cb6694f736b532b95e38fbabe0e49c15f7dc42c54def09ae1161b7d5 +Msg = 1552df9bae4fc97985bcf7d5fa01799332423bff194a2a61a7c298d263a7e24d26fb500922ba3c06220f77e613c8e8ffc40876aeea3b29ee674f8b29cc22554e1c364723d3ac58dd26700fee8db1311e7f949cdd7c2973d7519e7bca98b2c5947e6d8e91c90e6323194689926da39b17ea4f7533d8fa5145ee15305ccf417c4a +Mac = ccf2155306cf89a73f55a0560d32337e266432af + +Count = 119 +Klen = 32 +Tlen = 20 +Key = b476d28aeb5fac74fcf4cdb1ab00a38571231db06624b4586588ac436a649749 +Msg = 4d4481936f523035b921005101ba206b85f55e272ea49016160e32d0479f5043c6dda74ad09e07826378fb59007aac67b0190302456d0e0ce29ea510bd994d8d24075c92be7f5e8b14fab85b4f888bab4342db81ad80f114b94cfddfc81600f46fa9e993c35dfefbd48e7e80774e85de49572fcdf04300d5a4008464ef7e321e +Mac = 65437f28501640304b1ff95db6a6437cac37d10a + +Count = 120 +Klen = 64 +Tlen = 10 +Key = 268b0e1f110052aaa2eee327e34ab349029806daf702306867a7a03bc8351d8ac7ba50eee6b783166a77a8bd749e9dd96e05ae15a8c55c8243925c894f4be325 +Msg = 7c881de00388a00f8ceea887b8e87ef7ceb23ea05dad950623b0caeb2ea2fb7d4149aacf795d788630e12fd522b306abce61212a203e585c4cb53921fdde506caf4fa6af5935879450a388ee6829c9ef5ca9789b7066967c545efe984cdaa3a08e43196aeb3757a1b2dcbbbcd2744e2c3e324ada964cd9d00352203663be7c81 +Mac = e06c086d3434d79595d3 + +Count = 121 +Klen = 64 +Tlen = 10 +Key = 77c192472253685d52a6fc393bb7a9d5bd73f5af2b6e742050d7eae9b4acb00f1b2a59ea4f8894781fe454f7a87e2fb2d324041b1fede11aa12a24a5499ae091 +Msg = 837dc190bf0a96d9c7879d8d998c5c21a263475180bc9c700ca28cfc98ae9b75757b496fb959f2e73e46f3d3ee1a0efc3e011010f92eb0f33fcebb57cd3b6e8c7f73239912c8318b2fd90d0da5c0b539f78d4eae16f40be36f4252bb28951a59a74d983555be1a6fa127336447e81880d2ef4a535f7475e6a5e6984f32256783 +Mac = 2d0f6c935a06d9d48e10 + +Count = 122 +Klen = 64 +Tlen = 10 +Key = 79a557102517e406b26557d026cf06429a5be840ecc0f0c9b38399357860c3ba23ebbd35b377a3273237eafee8a33997d01d7a0048d532820cea0ddf65d2bed8 +Msg = d60812433098c44623159153de7cd2721b349f685c43388a74c2a3d04a8e972ada4199177c61657369d78f907ba26a8934cc29d3029d4415c1101e3a8283e4c48bb2b8639fe60fc67f6a57b1b03fde507f10efcb43683e1ae223851b962370e1f144b74f1f9189e66cb831dc05bbf46e03e93877a50dec40dde5239a0fd5022a +Mac = 6cdbed1cff27b79ac20b + +Count = 123 +Klen = 64 +Tlen = 10 +Key = 3a4182af8c3914d1df57b6321fa5dec68748ad746e0369bb64fc2d9b7dc3dfb3ed9063a7d5cc0ec45dd35ee703f9e89a33cb9181179701f5b02e55ee26e81426 +Msg = a16b3fdcaa7eb6a2135159aa6948c6a8dce747519f9f54cb92e759621f8fb97c615112cf8caac3d189e8ab70e0833404dbb09082e93443f24076e223c6d91a9d3248f3d76e1356aa40f9ce062a868be48f9fac7b165bbeb754147fe7a5bee8b65a786b5c1a617a1582ad48d20ff8d32f3ed922a6f1bbcb0215e8b91682e72cae +Mac = bb7654e63c2ef4313c63 + +Count = 124 +Klen = 64 +Tlen = 10 +Key = 3510c8f6da91371b5c81468b714d05284becdad01d5a2476dc481f784312082c19f181bcb6723635c426c1da439bcbbecf8c74922655f5bbe5a984a892877962 +Msg = 04e4798b90beaee2ecca6a4c1463ad9c1f9661e0718332e731059f00fe955105dd6bac9876e7a5ad8130d3497b1bc8889d4ea1e50ea5dcb658d46af6194e0547fb66c437e5b4edc373bb0a1aa4c83fa3d31dda40e94f2cd5d0ed98042b62e93b441de8f145ef2f2cacb43847f935b9f2a94d347a684bc94b839850b39c9aa4e8 +Mac = df4a9f32c2b911138a7d + +Count = 125 +Klen = 64 +Tlen = 10 +Key = 23904039640d48e163676d16198884a825604ba86329a1cdc0f0f6164d5100b19282af1c2493648a7af35e88fc3774e05d170abe2bb93e11a4336234cc4bafce +Msg = 2d201194f73a9ca6e44834d8a44aa948287d1536062c647020c9140d813c3a5e877bc622475b07f92da6721ce36d9f4a749f9406b2db46ffd5835dd0641238e959af31cd8002227f20462836dd9fa658ddae8da62a63dbb45713629d67cbcbf4eae3dafe69d6f41e0451de905a89c75aa9d28980366e2c78f0a2abdd500ffb68 +Mac = 9238de28fd468cc27d76 + +Count = 126 +Klen = 64 +Tlen = 10 +Key = d4471c7f6186e8c0ed3dfa2b0ef2cd184d6041c0921ea5fddc7c155135ae062ae62c1f64e7584b1099610c74b76812528ae20c6e5d3ebe4a31c75334b2cbf582 +Msg = 1b3b012e5a3147207350e981c05f20f268b4792078f986a23630d325b2f51bc69d03bcbf5efa694663601fb2b5e55ae0d0eb88d5b145bea4303faa9290dfc979556bd96a552b92961270916f47d6950ac1c5edc8703e3135bed431301ff82b4dea7a4177674d29da298b27009eb83839e44b9041de6a471d88f6504687c7aa09 +Mac = 65d6db01f95625fcb481 + +Count = 127 +Klen = 64 +Tlen = 10 +Key = de6cc5a186dc79b9e21b0578b5ac6e2440a115e713162d7522fe72ee1b221806f7660263d04e3547f2c28c6e340ead3a892d3b0dd2474ef6f678209135d30928 +Msg = f80c55de4b5ad74e4f8dc14b6a45c019e1826654ed66d9d5123dcddaacbaaf60cb8323d440f1b1ebf810bbcf89eeb37b0b128b68294a6c6977aaaad307d1f8e2376ed858cc03566745e9f6d16995eb4e2319892e8fedfd3f55f03cf136aa39b8e4d45bb2171a2e8add1f599c31c2d05ad0a04aee48d9f6215218697b61cddbab +Mac = c4953ddadc2acf38e677 + +Count = 128 +Klen = 64 +Tlen = 10 +Key = 8989b2299f9db5a5df0253a97b775c94e8e9195ad698e1cd6576e71b96cf5698ff2fa0bec4811272c274ad890d23318b9df47ab744c00f47e335f9f5de79d1bd +Msg = 9f65a426106db99dcb2130be14839241d4a92c8becc108d2c9521b8238c5c0df7c2365ec9f20848c0559d6e847dac3103ee31ce55dec0c3644e64c2993c497ddfc3a5e4d9dc4bc788cebacbfb3c47a8edeb9773e128bf13a219862617b5ae8ac4731f511b26248a7875f1c0a01499f01ddb3a55eb2a99e2685f0c5f298909b95 +Mac = 616a0dfee4c59643e047 + +Count = 129 +Klen = 64 +Tlen = 10 +Key = 8f55e53e046e6d6d64c4468d44aa49a4e07742dd04d8f4812c6b5e22ea893d1a8863d234ee50e5a8c7650a4de047230ad03d268dde8921401ff97b79dfb97cf2 +Msg = 5f172973852b947ad8406fe004de6e94127c7fe2e9f3658c1433a21dc5359b7a1a31f7baa01048371624ede5731737e32a21ca50ac7e46602e2027afada1ead5307b723a4e7ba92cef736a2e57309f9360aba64c0683faff29ab0f598f607da4295f619c9754007eed95ae63b810efcc3c83db7e00ebc7908d3e21c2725c9c10 +Mac = 145ce9119643c0c9c23a + +Count = 130 +Klen = 64 +Tlen = 10 +Key = d5bbd2a2a536e6204259cbc2aa7e88452ffc2a5270485cb8876038fa84695d091b964252994dcafb1c85186a0473a408a5658e443eee33da2f43ff5566e582d2 +Msg = e84dc3e5a3e9c59b8d4c80fee20b43f388c935d5fd5ce9b98f2b32f7cbda39e6372acce6441af9a47e53dc9906c2b5d442873dfad30e3b8bc77b5266104c1d9035397e31485f32df189ea91fa7401529dfdbc2ec8078a5525df437c5c8a784f24b447ecd990098d5c3f79099afcb8c7bc78e69b4eee25098b85e8a1bda349595 +Mac = 0f6585d0203aedecad76 + +Count = 131 +Klen = 64 +Tlen = 10 +Key = 4c34132786865ebba9bd1aa5d2d3675637744f7e5e619e8a8e16f36b84ab189a66f88f59fdfc6d3b1e806ce669f73b1837a918e8cd10a14fd682e7e61011c5f1 +Msg = aaa05c3e8c3337306abc752b9b044dd7349c9604da693749d461dfea648ff6ff585dd3d3dc122f8b929ad908e586ac0e9a53bfa5a7efdbbf4979321c51484d6bbe3047b2910039efdd4ff5001e79f7c0cbe498732f88856474ae70cc01f705f606a120a154063da6736530daeee51636f2d78b35173c1d7e7e8701c31ca405e9 +Mac = fd4032c4adf2a19e69e5 + +Count = 132 +Klen = 64 +Tlen = 10 +Key = d7931174ea188b2c8a1f045978346592014283a1d20f992c0e06f5959e39f11ec9a6255104b9db9f0b13c347308ae979f371e3bbd4194f8d65977d48a3c8684c +Msg = c8dc1345a06e53e6d7b7eef4519d82a43f1977cde9e8e242ac84a95e3e52e9e03a1d94f9d8c35fa4fb2edb367286e13677a5346e7ccc62422894eb419c27a5fafaaf5f11280fc592d1d28484ad60aec203785f066cdaa147d9448d45d7a0b362127cbcb318ba4e57608930078b94afefe97940bc3f7c66f7c87dd6917927dabf +Mac = 8e99a60f575dff478d99 + +Count = 133 +Klen = 64 +Tlen = 10 +Key = 454262ab05cca57ff00f12d653f08a5e2e441e324493c6b86e1b56c93418af139e4332bc48997b48b55d4bbde560c5052a80de93376f0f4a7ab64c9aacf93aec +Msg = 77c192472253685d52a6fc393bb7a9d5bd73f5af2b6e742050d7eae9b4acb00f1b2a59ea4f8894781fe454f7a87e2fb2d324041b1fede11aa12a24a5499ae09166dd82a76c2bb4fbf546817907adbac195139935480fa54f7f15d53994a5f89761c254a702a68e8dddb4cae8e0ae12a90a28fc252d3d8769f28047cd1d35c2cc +Mac = d52b5f1b01dc36d76d8e + +Count = 134 +Klen = 64 +Tlen = 10 +Key = 66ecea6ce6274578ae5283c8de9576f5865a38c321b9ca3d5f33fb0828a48bf1dd7391c8e10c1a71589013382eca69655b666e10665d7f3728b4e40ed366f796 +Msg = 2272579ca6eb22dc3f558314c47c2ef8ab4d678a7d8017e0877a1f28d371ece956d14b8c6bde7f1a809b92470febe8b0d1f71a612ecf019af75410d35755e7fd07f8260bc25c7fb1f97c106bc757efc2274e06cb65cd21f0d22d45f2bcd9442f9db08e2193ab4a2810c0a589d3066ab61719d4d00ac0a06a80cd6590e9452807 +Mac = 6ece755234adba6cd01a + +Count = 135 +Klen = 64 +Tlen = 12 +Key = b244d305bfd534de7b05b66cda0b7bd3c2414956b5364611b0feffea53cdafc541c5bff7ca0b89fdc820616fc66fd62f682235e6073a4fb19bdf7c17def4e03f +Msg = f54c5e14a29abb699fea3504f4b9a077bd40a4dd72a61cb56c75bdf0a54bf848c0d221d449f1d0d93d4488e4cdca96155fde3cbed6690f2d13559ec5bb4554543b83a0a00a3952432ee549b902074bb8361c34bf17d053f211701125729ed337704822a16edb0a4e7bb3bfae1cd787064be3d30abf45afad6eac5d3851be3d99 +Mac = e685c26a4ef766a1ac244bf7 + +Count = 136 +Klen = 64 +Tlen = 12 +Key = f3cb2cbaafe6281ebb546af88c052e6658a58407cd7ba30502918052ae159f3198ff29f94ef440151a6a8f50320e25502f62835fc0abf372a00a1c63c5e9d482 +Msg = 8f636070d8c5c1f979734ae36acfe63f0c0817531a3f8de1dde9f7ada0751939642e1ed3d56230d17cc4471c350f3eebe4ec2cd16416f1fac0bc0fb2a627bc26189c356f658454cc58ca652faf8536fcced76d0db5141ef930279d964d3291bc13754a4c71715571754d4d26bf78f3f93490810ef7833c6695f449617fe0c182 +Mac = 3bf0f6f4ac757afb9deafdb3 + +Count = 137 +Klen = 64 +Tlen = 12 +Key = 5ed96404ce1f0ae00c32ada5f605c10253d5de41135f211bd84fd0d1b6fb3c783751ec94a30ef7e97e32b28e51b08b43ae6935046e5b06df3d169d025970c718 +Msg = a89bbaa86a339951ddcd37799e21b5d1688e4abedbc72daf7cc9b5adfe10be34c00a504196cc7baccc0485b8682e48e9b00bd515ec4f5dbe6d9a529fceaac9857acf23606e9fec9a41ea03a761f1fbde9fd2c287ee4780356790c25691aed808e0d27b2e7b15b4c34269f96f10d098583dcc593b68165ebb73924ff9ce83b464 +Mac = a8028cb31b89d1e668eb4196 + +Count = 138 +Klen = 64 +Tlen = 12 +Key = c92660b2f009f47d3589c74e22daca9f60d0147fcea28e7cd0eff0c5eafeec908d4aa8ba303e72ada33db087a0e51579a4951b6cfc2cadeb2314233d4b8074d1 +Msg = 46252e54907ec102948e8233e7254a6ad0fe414250aa00025fcaf272798100ed59296db80545fe920ab75f8c0934c21b72f4c96c90aea6f7c6c3815718ba1959ececaf53128020b7039a51e766d0cf4bd9deb7a2ed9ad495722a0892f674edd788d6bbcdc2176d98069e1fec07e2bb228b22d48b7056d204ed6550ca1b98c290 +Mac = 515a7febe556a317919eb3dc + +Count = 139 +Klen = 64 +Tlen = 12 +Key = 2ab04d9a3af659171d80653a1f7ab9bc64863e6ccf0f882523d913fd68ddcdc09155d59d5b13831e7816a85eed5f1776b9016438b778eb20c53b14872695d61a +Msg = 8d5044a308c18e305d0a13bda0c69555bdfa93c9549bc053c751b37a917be035d973c75346136b1a1678062f6a05fbb6e4ab0cb97468cdce6f0e58f4e24643bf25d4cfb5b31d62f738e63824ec5e557a205fbe3e16f1e85e16107156beaf0e509afcc58ff5e65c0deedc1163ced88bea989d1120e23dfa4de4dd6466cfbc2931 +Mac = a3bc85d2694d7868120934ce + +Count = 140 +Klen = 64 +Tlen = 12 +Key = 2c66bc60707a1da0c194e5422ba022acd049a0058a0fb2e9d2992e61e14cba12141c46b495a2dac6386f9280a3a1e70ab2b42feb1a9a67c44c0d313e9c241941 +Msg = f39dcfd65ab7d025bbea7aa405f6d64a22aec28f7c64937fc0a2ff0de21b3ba961e06015ccd71374856a65a4c57cf8cde0a1643aca8ed868dace055dcfb7373b119dc5153945ac01d29c776f61a962b9a4c1befb18fa9724bde2954d1d70204a8b3ac77fa9e9e3f52dea77aee4675b35f7769a786d9018daf1447885d52c3cfd +Mac = 03368545751957bda8ff9db3 + +Count = 141 +Klen = 64 +Tlen = 12 +Key = 67856f8f84dba19cb38a23b0efad6eed229c536f45753f81c8fbbe1134a43e620fed160100f1c6fa333a804bffd7e899c6ae19221d14e8f32d9b6c5b592bbe9f +Msg = a18a27748ef39b49be984e8d18520110008bc8a1d5aeb424bedcaee5a7e1a62c8666ee12e367e09297e8c7e3d4e4fd056587509b379daaf81949f27cc0fa2d210e9be951940adbfb55ccc7e5ccffa044318ff18af9ad7b7f9c7d1f939a0fff72c091e1daa7c3d4a97fab153b0a8933f2eb0d721621c86de0cfe100d13e096548 +Mac = e2ac4a0e354277a62cc82573 + +Count = 142 +Klen = 64 +Tlen = 12 +Key = cde363485e01d4d36242665f35a6e910b991fd9041211c05adbfdb40d6f46c372c7e68b69da4cb51b9c6419d1438a0a0ec51b5850cbe4394f01c49622ac78445 +Msg = 9eeb079c552e421f703085b9b275d5b05c0c922efe14f2e78c7faefbb416fb1e6fbdbcf6d7f9f6c438af8447692f0cde5d7031ecf59d0a8018d1d3360620e358e9d6de49ae032c241237aaa0008a9f371adff187966a99f84b70549f0b4e9b6234bdd65d8254cd85274f5f8b1e8e7604bce13ac6888285954ce397ff6caa0c84 +Mac = 31a0920da97a3e94b151bfc8 + +Count = 143 +Klen = 64 +Tlen = 12 +Key = 74c6bd81ed71bebacf5f7263cad715951c690afe4cd127e41b1e5468b813540833cde26834a60052ed5a8cfb4d68148876bbebd0728a7c64217ddfcd7611aa14 +Msg = b8ec3714f0f54c83d7e1e5e187b110d0abbaddf1ec4a71a9ac8e5625f7b3159bb64c07d326f468e78934ad471ca717ff485b893d1c7b970dfb2bdf6892b49c6d0de178ee8ba9a22ecf0d21e938446895f3162ae86f866f9a11b3e86c2a007f692673336c065b23e21036e8d1c4d1281a13b168fbccb222d757ee183aa5e0e718 +Mac = ea5be261fbfdf4e083358099 + +Count = 144 +Klen = 64 +Tlen = 12 +Key = 18f10073e71422a3d223c1a95fdfa6f3d5c27172f0e4ec9ed91f99bb55718d5b3da381252e2827d48148ba837e7ed927cc1e955d2c3ac96668c7aa6f85fc9e16 +Msg = bdff024f5c8c625bf0e557c138e02f1fa7329bf70b846d616ccaa1fc37d09a2a9c15af7d34dde66ce782ff4b0d0bb57ad3ff40dce07c1e8a398313c962966f3ac7858f515a85a6087c82bed521b6f9d92f7b1d5a285d4f7309741f0a72f1c50306f6aab315ab2b98798e9947bd0a84a5854c395a29528983a444cca7ad0826ed +Mac = 96f596dc5ce8952cb2b0f914 + +Count = 145 +Klen = 64 +Tlen = 12 +Key = fd4e7dfc0c21461f69fb237fa283378413f1e5d25db7e613146798f6b8d19977e76b9562d0f75c12eb5f387fe8e47d78e577612ce3670eef7b3df63bcde567f5 +Msg = 8d8094c0736564175a29e567309809ea14e090745e8e2904dfb9da996a7da14792ac5c89b6bfe6d93b13837e19527ea6992e10b45d5684dba0a299ecbf91286cf8f606ea72ee2c8f7e1515f71dfa683fc2d0d760596647bb875931f53488480447c85c8ab0d97e62ac996579447810e0172cad1f5aa6bacb1d446a5bd0484a37 +Mac = ab8810c9a05afb0169fd36df + +Count = 146 +Klen = 64 +Tlen = 12 +Key = 0293926e81c051a6c0945d2594644b824c100c368a85634751869c245ead7cd0bcac744393d9190e41ead93dabfce681d5db778fb17d30c335cfde09b0b568fd +Msg = 69969242b77bb69e8d7d63bb08d63ebe8be96a460778f4447a176f0db6e1dbad6469cc7e48f4c8fac7e5f0cea678e22f14b3df71eb9a29d633a3afa4e869ec7afca40de3a059522cc04eb673ccc1d201be59ffda595dbb91ae244e61e5cdad7a3a309e9946131ddb80a2fed30319d5da92c413a6d929711ff584926d3773e356 +Mac = 078437f1a1089c5724eebf2e + +Count = 147 +Klen = 64 +Tlen = 12 +Key = 75dfc0b734046aa2ef9d82f7596269e100793e5223f853a2c3a5e179fc00faee9683c0f0d828d5e59c2c1292a9127c3b3cec730be8d62db6a0c3635c137c4ab1 +Msg = e68ccc21d4d7e9155773e9d612813f99baf6d72c3336562cf6e5a478b6f9a8e543145234ae12df41aedd587c42895c9d989d20942eaeb4bf3733886040942e4e138461ebdc9147558af9f3e178c02ec54dff7714217f48f0e1869bfbf4f1ad0e1e83022ea57da9bbb36fc1ebfc4d3c77a0c5e39453d09a25bb88e62f1939ac8d +Mac = a1147bb0ba909865a46b4720 + +Count = 148 +Klen = 64 +Tlen = 12 +Key = 8af2e72ed2ad3be1e81a21e6fcbddff62d45385bf061ed60b6d58306c9cd47f8777190c173b9443d78839d4d2fe32dcf53ba20ce138ac2f5b888414a87f3b319 +Msg = 657fcef962db04bd269ae5fef2cbd5e6558d072946d235e8706394d4cd250796769a926fbaaa121b6da42cfc82808474dd672f9362756af252bd8cded78d39b9ddf4d99e24824844934fcf25d03e54df0d83cdda2563fb2be73b54b8b1c4419d429589cfc9ea0dff41a3b7c20190adee8febca47b6264e5bd8e8d4aa8552850a +Mac = 6eb55c6365a8957cf579ca2f + +Count = 149 +Klen = 64 +Tlen = 12 +Key = 81b7e464796841368cda2cf7048055643e8d38dea614abb3e36db39f4eda9c93a96a49b40e1ec8a7254b290c9a3f9148ce278a88cd319d0381ed237f25f95816 +Msg = 422e4cbdbcb7128f1966ef7432049d13a407cb27c8b4b7cbe686fff4a5d3b53fc6adb1ed12072b2b91188997fd05750176ba336e771831630956e06037a1c3aac106c64d1592d0627ab89b8e8ff2c4cbf4ab1e6b475d4c5a52f78fa38281dc359b0232e8aba22abb3d0cd05fce16b1fa85a435251ec92f362830b3c570bb2869 +Mac = 9609b20113e61797397a428f + +Count = 150 +Klen = 64 +Tlen = 16 +Key = 8eccd467d875839cb4b0a0170a976f6056876859fb242f69d99dc6da2132028068f33b9cfbca48ff73bbaa73896b08562bdfdc88cf876b88077bfad955043fab +Msg = a67b1dc3633d30c4ef2bf3185fd44865d2af5e72015cdf8c182e6b28c5e746c98ec24d2467b72f8284fad9676cc532714f570982993d4b22c7d07a1e79ff5a75c94eee75dc1fa222b630cad753664b30f3c99826b5cfe17c67dd875b9d0bd2390028e6ffe9fef36a2fd6adb13d3ffc69670cf4a67e9c0764a15e7925579315db +Mac = f35a4323cab7ade7168c8b9f7276744e + +Count = 151 +Klen = 64 +Tlen = 16 +Key = b488332a10f2bc7d9042a1933da85dcc892504be3ea8d57bb5780f1648d1076309d276ffb5971790e3a2724e817ff2c381a73eced0a6c6ee88799cbd663a86bb +Msg = a9174a67603a4d5fbaa8cfb562f07393abadbc80d1b57231829347a29c38ba6639ed3c3ce98c91e23ef07a2e8eaa915af4f574a098ed250630fbb17cc7941024bd234df11043e773d93276f11a8291b9b612f0b4c13dce3dfa5191339643ad4d40a1c6ae5dc715ba94560c278ee23d57faeb78e5d50f337ee87d2ff292ad598a +Mac = 59a116a249eacaffc54498957787f8f4 + +Count = 152 +Klen = 64 +Tlen = 16 +Key = 9dcb2ac482979d2b4f69b86154a66286c10a73dd5e8f0ecf7d9031332e2e8accb1f38d1331b5c337afbd65633c29293f6b8f5cb906e33105009b59e2ab10d320 +Msg = 5c97f13331db20f6351f9aef4e0b7c9c92a2cabf476903a80ecbf8b65bbcdd1c289da1e1eb5f7b2bc5ecc6bcfcc20ebdabe16bbab8e80def077b19c2ede7b490e8095cac8d6c7fa5c1b146c82c34b2e6ebeceb588593d53f2107e310f6f1305102a4cc9dff4853ee9337c51cc7a791a0ba8af39e97b28023c43900ab5c207be6 +Mac = 86d4b3a747285f26530e364b659a3c15 + +Count = 153 +Klen = 64 +Tlen = 16 +Key = 5f360b2be1b1d9473ec74ffe0bca455c7150cfb2d33e0645b1250c43cdd24afb8c20fc4c9e11f05ee11d8a9183ca0cb3687d1476cb90672127a4ec855839fc33 +Msg = 179645a0885bf0f1deb9f6c105bdbf2bbdf728e6ed81786c3a3e955bd960781ba12ddec1650240338098068db186f8c42a07f58ae3fee7713437f652a3f0fcf0fb9839d99ed6498d1bcd52e2039f82a7f92fb988092c82313b4b48b767d3c7334a5fc0b0dadff147d7e14488a30f471c53f8dca9061332f67500f350cc12bf2c +Mac = 924243335c2eebd348ea23efcb442cc3 + +Count = 154 +Klen = 64 +Tlen = 16 +Key = c05d6b83a27ef65cef5571222d24adbcc18958640548bc959a4baa2b00e7b0c66361926fb8b1f87e098565ba0d8968c3fce616ada108b7eeb1a5c07a5bfb022c +Msg = a782b87323a0ec6abd8f27e50e976184847e166a04a001f1d442289cb923184e5c5472b9f24aa6181c32ff210c84e035eadb4ddb7604ac6cee54cd10323f29e82627678d587225bae3dff445931aa454498ec3cda17a600ed34714dfd71944a4cda4a0d89b41efb6d8400f39e9803747693e8029cf2ba43f4ac105f2f0d6f1e9 +Mac = c05fea12c1594631fa9a5b7e35cc74e0 + +Count = 155 +Klen = 64 +Tlen = 16 +Key = 2af1053d2cca20406b7814ab9013677feeaeb773ade5fb2d27b50bb892916333e0b123c6e3ae5bdbb54c868a579654549831ad1538eaf2344e91861de70a8df1 +Msg = f7a519f3b5ae6fd988eae92a9bdfbecf81e7b405d73ee50e2559c32606795ab98981d5d3d60444d815a39c758b96ffd606883e1a7ca89d04effdd6f393f960143352f0d6d10d419e8ddc11bdc8a96c9f88732c441e59c1f407f42e2f11ea54e4bec073e3edf0ee93b73c4ee898418a90cf4f866d0778d94836e7d3c4c674bf90 +Mac = 34515b41c4af316223ae43e6869a38c1 + +Count = 156 +Klen = 64 +Tlen = 16 +Key = 9c9445d7df7eab77c9a5c7afbd2f38707d26efb89d1d415938173afce1a43565dc4da9f98f32467d33f24120cfcbecbc67038959708660f388d00f7d640d2225 +Msg = 2fb3b04e1f5e7fade5abfb52efe19edd2ebc80181a657b85f7a18d3957497fede1fac453500da4a6bfca9a8523d8fa0119f8d6f5e2f42396abd1184a124cd7bee7854f322ff561186fa541de27a220089cac0881da2e0733fa738fd5a1161d04c9ba1996c4fcfd2b7da6ba04022558193f3edc650cfc6e856bedbb810a8e99ea +Mac = 8bbe93e9a0e39128595251c7a0504f10 + +Count = 157 +Klen = 64 +Tlen = 16 +Key = 64169fd4b7ba1e5a62412b8719a2b622d5031aa777cee7f5ae06e4471adc5465b27d791c632f57ebf99cbaff436d7a62721bfe6fc302ff895eb88e0c7d9c5984 +Msg = 7f7577736313f725fb872d0703a3759c422a55db25e34ae0a7ebc8e2734f7c654ddad4b1ae2cc182ae0cbc01270007f3181a35314714ec582ba0eac108f946b45cbef8d87a009cee759a73bf3fc0ab5312dbe0640f94e212262fb9d9351be6bf74c7ecd210b70fd116d65c2a930ee924fa165e5ec58bb4785f433d1042dee5f0 +Mac = b3d266e44d21fea613913002229b7994 + +Count = 158 +Klen = 64 +Tlen = 16 +Key = c49505be68196bf7b874b25353de09d677a847856a1477d5186a9464fd4891e7453a9c63328aa4a1bf5a19dc83eff3bcd750f5883b103397f668d207fd890fb2 +Msg = cad04d5a15ec41e28c9944fd13bafcc52f54aa86c5420d17252a846b46af726353e8e6e667117c3496817e772cdc4f9c398a0a604d6866ae80bddd28b56f0d0420775e190692e539c43988c213d463708a2b6b75651d51cc8494aacab7b84cf63863fb1a79d5459a20aaaa05500900ea2b1d16ed95c998193a973278d2f2f8e1 +Mac = 45d9e3d8155dd1d7aac1faa36827402d + +Count = 159 +Klen = 64 +Tlen = 16 +Key = 5a905c63f9660429ac7b7be84766c71ba5a443458fea9fe3e0ba289fe73549c60d3052fcb889792f6fbb1fc93eb1542a5cd89c550b78f3e9c04410548430e743 +Msg = 55ceb7328ec045967807a80790b5f55b2a66aa1f6d2edc2c9fd0927ba3316c3bbf0c8820a3e6a5fda7458995551da1af278be86891c509cd4252c8a9a8769e9cb2f1a36dd9e9b2a16124c74ddc7aab28f18ad4e45bad86bf34283f5574a652b8b5e5d2c239afb1aa2d0c29d62fb65bf00fcd373cd2cc9b29fdbcbf2610a7d0b6 +Mac = f5d0c72599bd5f8323a599ca7d2d54f1 + +Count = 160 +Klen = 64 +Tlen = 16 +Key = c9b74b2ba807d65ae62728882a32c4c0a0b2d9019fb50ced8a2477c5f451f29507cf91ac26866e4fd106a8afc91cab1875a3b26a859d8bcdd5839aa194d921b4 +Msg = de66e519983ba074220640d09848cf606f6f959c4e588de61f11156e67e3e953d290520b13d99b04ea43c58b861b7cee0eb849dd7b000816a82e9d42acd2e3196718e5cd5b4e51a6bda129e9cc27bcff6223d5d3c984327ccfae371c1d7de408c487052919a2a8a2c3a7d4b2127578dc9338a246e1ebf160bd1b4dc561eed566 +Mac = 2c77d71152e343414dab1c83fc5f6429 + +Count = 161 +Klen = 64 +Tlen = 16 +Key = 3af349f3647218e4be26fa863ac71381b64fccaa7e66761e121e308e2ae00ad9f8a76ae0ad6baf963ee115566861d87af2279d2932bf0d70d2bbc394d4a768a7 +Msg = aca7f7f326453435b2ec9e17f0c8823f3cdab1cb8d4783429df61cca4b59ee9c3d8b7fb6c99c6dcf1629af907e2f1d01372033423337127b4409c715845ed02bf43edc3b634fd322925e1647953b08167ccacdb0335752e0a72a8d522a5b06ff19e896ecbc056e146db35ca2fd944a6453fe087d564e4b5a0e7ff5e705fb9602 +Mac = ddc60e14dc64399f48c2629cd9ef9551 + +Count = 162 +Klen = 64 +Tlen = 16 +Key = 23d992873b968a5106f95b3693e230420ae819d993a80ba8735d29db78b2419098d49a8cd5caed2d6409b1a00d439b54d58166afdb71d0ff8001e5b3ca2c7fcb +Msg = 13475d77c30210f6beedff5c38b926803e950da0a54f55a540bc90a8565b56b6523595d0bd0728366aa3abe6f0948e5f5d0169aa29d48f9b691ae65545adf60cac113f0f479dd005abdb1576d231f18eccc00c1eb28c6fe4dcdd4e0c53e624f689a5063a480a30eae95be517c6d77696f29aa00327c01a07ffcd6fd7674d0afd +Mac = 2c47a1dfc80df9195ccac2b006904088 + +Count = 163 +Klen = 64 +Tlen = 16 +Key = 2e4a7b49eb4ff970dc932c156e9a1a7be9616217009c6ff2a742f14f244b8e8e69b9d450a1d573dc09bba9c10118fdbd633330de132a71e7d77ed0f569d2f562 +Msg = 3c5a85e4d4ccc1b8ff94c7c7af3031136b58e1c7452994790c83baacc2b086995046412f794ee3580da5e47e5fa3504ef8fb1abb8de2b2462f74d97dc253b5c2b091204edfd04676e0a76f2c694819c805604a090a3f2456cb39ba4a104c2270c303cc4bec99119ae0620fd9b467b50bf8501ab7a2881331499b041a94e3f62a +Mac = f253721edace08cccce596b231bdef4b + +Count = 164 +Klen = 64 +Tlen = 16 +Key = bbfc60ad853142be6f602fd1eef95f882f478915aaad0ea0fa2f75e8ec33172ed6891b4f2aaaa5304a3d4b5e9ee0c9f6e524f5c3c8d9f5a7b58daf3cea4f81ba +Msg = 0e16a3bf115933403b178eb58a604ee203393afc54a61060b80882851ba97e2f7f96b2e69ead50a7d0f60ed930377282fac24cbb389284629e96150eb24d5a48309389f8acbb7d1d79ddb8c1ca71a82d171d2959c2cc4ca6fb0056cfe1690c1de9b62edb84ab420afc7492569f39784820f2d9bc3a7df09696ed4db1ef261d18 +Mac = 32e3a37e8ca379cd7b604840059480d6 + +Count = 165 +Klen = 64 +Tlen = 20 +Key = b9575f4d5ecc0f4f62e4a0556bb89464ba97d4570e55acd4c5e5177e452a3d6c9a0b3adb60c6211fe48640e08637a6826299e3e52f930f4f66cb0ea6a77311e3 +Msg = 8c8387f4ae2ca1a6dd13d29e93580b1cdf6268da66cf589ca8b1ff0884f7d8b8fe299f8e41596e47e0562653612210e4fca6c446a0a54a6e37ef80d52bd7bb8729e6b17625d197159ea98622235223c316367fd5b03a3c8145f2f210c910d00094238757627e63379e75bbb3e0d08ce1b47961309d7876fc59211c60678c5f4c +Mac = 15af23331648171499b58042dbe7b2d5df72d152 + +Count = 166 +Klen = 64 +Tlen = 20 +Key = d291adbf05b06596c2f36f41a8cd8070370c42f687b8a6cc3a3e7b59afcd40f07801369b0fbfba17c460d21ffa1106ee937971ffa99d17177f017985b71067a8 +Msg = 50bcdf31389eadac5bb8197ee949f2864ede284c07d039a0b40eed7e6f1c43355d5cabc8828d7595da918a34a5735aa202a8159fbf951e547052bd39beae14360273540913eb30e75ba29266316e8d9a63ad947e11cee996c21357d3b19424b7688842b990c0c5eb08749ada344275b698740bb3a58282aed2d72514efd85d00 +Mac = 5f7a57d42e3ebbcb85b08565304dab941d6234f3 + +Count = 167 +Klen = 64 +Tlen = 20 +Key = 902c2af0d13fb353f14a93eaba7e8a8f768eccacb264ef954114071b840e105ee9978ce2b27a6ce5f8fa34f0ef0c5bad6bc3f0f8a30c8438359b43f06b256491 +Msg = 65bf93633e3a4cf878ddb21a5aa2672fbec644fc6bcc4ec59ec6e5b5ead03f8042dd154655b69cbb1a3fb785abfc6be556d5939af116d5026fbad483b1e9a7299ebf8b90764fd40563e82ae85297f15400ec09035801b86bfcb9e42d224686b0a1ee5b094b0edd1f7e5f710cf678e2c6e5940efe4696df486e4a7d7de4eec25d +Mac = 5921643e2713d10428843447df91f482f3922aeb + +Count = 168 +Klen = 64 +Tlen = 20 +Key = b9f4ccde4dbc27f1e6bb0fc9e854aa084249029cf32eaadacd1ea5d178ac83d8bb1ccd6af7d4a334f40da46be0ce0e63951b265e1b6adba26e56a6ce8197b46d +Msg = cf7210d4240cbba95a8635c1c37ef8bc4bbef2dbfdb32e16c922b0688416a16e301dac307eb3a73f91ff760005bd2c47307c7427a7093009042b5ffce790444c3b08c556bbf1119ab4f285120cedd1c3832e569139e9d35771e34137946ffb2f799c22ede3ad40e54bc92ba0e0f42d57cd3e61c0ba3a602895b21dc292990e3f +Mac = 3f74a3b2a77c173b8b6e20c2ededffd43103e4f6 + +Count = 169 +Klen = 64 +Tlen = 20 +Key = a1aa034687ddffdd659326c6d11f58f1451f8524c4996da8c04aaa433c3af1662e9495a627b54c70358336f909001b75551ff58978d6ae025d742ac7a035880c +Msg = 5d118ebeeb1a9774901045f4af19392c0a3f641b351618934b9e653ddf6aa2dd35024ad7b2870af39295175dd96dc5f08c5456b320360fa4338f92b57a8c6715fb6ddcb07c2d0ff93b6549e7df6e8d3dafc5710f02b42d82f62ff2d365fd7d9b1518eb512f55cf10f347829aa961ba9edb5c5e36c1d899b4fd462e9e89050bf7 +Mac = 3b0ce0fd9eed9287527edb23c0ceaaee4026b570 + +Count = 170 +Klen = 64 +Tlen = 20 +Key = 8fc7e719ff492846f151bdc5f6f6ed15a6452442ef42e806ac2a0f3479fb2f56c63657952be4fcdafbd736331c322d78162ccd2e6910c2ab2488a07bb31c6103 +Msg = 155f60ad0a95bddede2a10f0c8447acd23a541f37b768062e8431db99a48fc9cb6eb72586189fdca1975327d4c3ef6122331f1e59f1f40ede8616ae4e21896a800b9fbe25dca97e509e624d9a007481822050cd8fe598f0b7027fc830d7cb95a9dd4e19128dff5f75484ce4cee27d6a7c6277815c0abd583289fb9de46f9cd78 +Mac = c6c30cc650546dee441ad83d2c01b0bb50319da0 + +Count = 171 +Klen = 64 +Tlen = 20 +Key = cd7fd6beaf8ecdada5a4dfb800617e9b5b83bf23215a0340507cd65c7cb917eb16515a43ee658aaef7acd3be4a67bee16e979e35d76d2c9eac026e15ce48dd43 +Msg = a5bddb41035156670818c030d2893f7eca39a429795de6a19e8aced57dc0f35379a7e9b0e518b62a18df858cbfc09f5278b8960e9c84c30a5b68f32f0f295e25ca5bd9bc31e34c8b8eb465d720dc8eb6b6c41d737cb3cb35149568dce8fbcd2cbf62112d8fb800d1921cc8d89ce6f6f1ace7a122c1f2e569ef9a94a4b13e27ae +Mac = 3e87e626a2014346f4d3b545f0c47043a657c82f + +Count = 172 +Klen = 64 +Tlen = 20 +Key = 5657c22933cb8f8ee35b3ab821ab6b01ef8554252b1ee4a3639b3d66ead369a52b5748083eb0cd0cb9e76aa8c94bc931816ebd7b717178417b81fec6e2a2dabd +Msg = 3280224a9c75f01da9fd8bef8b925a1b7e901604ac8cd0064ee836ad15a41225c87713f22e1fd0e12ef50a3f35c43148d8db2ae2bb61508cb1e9b9912446ba81b8a1ade12bc9f12280c933d05cc0ec0cb0ed2b3c980a950183dbaa6a95064a67492577805b1a5cc6e5a28e0ac82e934e4deea1790c2ea74f0de5929f2e8bc9be +Mac = 46251e1b289f217c0b1f0f7dfd988aa62425efc6 + +Count = 173 +Klen = 64 +Tlen = 20 +Key = 589e1c67214c34f4380e1bfa3629ce139b297b3fb8318bd9cc90e0ca6d945bfc29a3a2126e872056a70a4df2a8c32f644c2f212c5c04d3c7b3c192e1a08ac9c7 +Msg = 012870169ad72eb37a51b676597a2a8c0104464fb33fe6bdc632c82891ea922e8b1217ecb1c4d66f289fc36b241a4b30081792d9cfbcffc7aa7efa4eea7ef4ad2119a84484baa10194f3fd1cfecd7004bf5c8c998b963f9b70659d62b7fadfd00b65ac85dd6298510676ebefae3ba3f06df8bcf5b175ae21600e38cebe055c7f +Mac = 79cd6dd6ad3d3aaf11617b0a9303ed3645ab71b2 + +Count = 174 +Klen = 64 +Tlen = 20 +Key = 95ece1c8ae5e94d16ec9983b1089a37395ad5b1d660916c13c87e4c13dbecf8f68c6611c324a679471def5487a93aaec86c935025b4518962884ac2cb04e66f7 +Msg = 4432f43f1b00d306dfab2c2a2409d049e1c30e897450d42ce62418657124766a3f5e1bcb75f7e1027064bb4b4edd54b6b10ff37abf12a28c6e9a8f70fe71b250c725b04b34fe000f10324caa005c1a9d512bab32f4572310c7daeb0d175c544362ef7d6661fc7655457da5ee426d69274a7dfe5a1b09a1e17b4af4e3c2cda36d +Mac = cdae582296f2c18e05c47a2c3885b24e4976fd00 + +Count = 175 +Klen = 64 +Tlen = 20 +Key = 91650ed89aaa63a8fd43907daaf3985c6404ee02c23b92777a0b7de6de093faca7a0e7aff20623f1886ea8656280d4016d0692148ae87fdad95a4b4d3754613f +Msg = 7ac33ace5b4a6a3292b72d0dd4bdf853509d9bdf87a5bc155ef684c6718b9853ab774b16146e12fde9873878f240d29610c3f66b166828b4d97a15be8b3e848344318916e292fb421320296eb025c9c44db331930e2ecaf1bc0ac1a417d6ff436e7a5c986ebd0f49380a69b7b673c4272ef6b62017ff8a132c2ff042c05cf3da +Mac = d985cf29d85533af9b58113d7153732678830390 + +Count = 176 +Klen = 64 +Tlen = 20 +Key = caa2f077c0bde9e98c2f54a98caba4a9f95de80e742bfe92e23b03267ab50ddb1cca1d02e5f54f92008054cbbf4b2219eac9ea3b574b4ba4ba81c522bf3d70bd +Msg = f4d7a8f73898fe68c398588dfe2e019231131e194517908cce121bb2491ec781a1038634f9f3189da5782cbb79aac88f47a5ea2ca33a700ee9e535ac82ff7d5062359327d539b0947cb71fca928b9f9a74310989617d32267e8c139b1dfa27813e5515f956d28ff8503f7ae2d2394f5bc19fc15a0747a07e94effda6a2768fbc +Mac = 790315ef7d9441b0ea3382471dd217dde2143788 + +Count = 177 +Klen = 64 +Tlen = 20 +Key = ac049e1a39d6039ce480416f058e06995b54a23c4d26696b76cc583c6130fc1f915a906ec59e66457a148893b0499e71f13412b3906c73bd2f98179983260546 +Msg = 504ccaaaf09c8e8a0c567ab7f1a1eca78ebfedced9e3b7126e43757e796f493ad7e193bb78d57137085b825cceaaf041d4b7ad9d4806fc3722c0349d0707c0196d866be1014cdb8e45da5acf7e7add5fcdd33e349cbbcdfa3b4c07bfcb3aa5f05c63d98452a8d4770dfc8b7ac9babbe9c23c2afd9ca93143030e774c8fb1ffa6 +Mac = 2258ded89a07b87e3397aa8a033f151e3c1a23a3 + +Count = 178 +Klen = 64 +Tlen = 20 +Key = 82c16c68eca59a92986938366de60c16f60c98bd66d43e10d975a826dcdb67593055da9dcb8e521120be73d4a021de1a81a90d7fbef07d9b5f7013d6faf6b97d +Msg = 7416ef51d9ee9710b83b2f0bba9345aa7cb4f4ab8f7308bac4f66242a6239f824758f4e3405d5c89f397f628137ea819675109adca087ec1778aa3928320ecd3ab298cfd501095e7c07c6196b7c6325626b0150932540cc0805a6b88b06e838727f17e4712ef8a51a7523afeae55288a413be06ad040f9df68d085cc34f7acc5 +Mac = 43673696e3003a2a06ab0f4bf07870fca1b51415 + +Count = 179 +Klen = 64 +Tlen = 20 +Key = e262a7385aa3282c5d4298376acd1b7b6c978b029a0c75ac9c41656cefd064b48ae2be2ec28d09ad6b616263403dfa548567d20aeadcc28bb3e5c08816eb5fd7 +Msg = 0c6908b5053e858bd901c18bfe5f85e73328301465a5b6c2d42de91172f3f7028b22342bab2c1ab0bd5e8e6e70b96579dffd27c970061330fc5b638f3105d14a359d59f98ca941613c2957a22f6c7ab1d8285b091aca859e650b9b1322c4e12c5103fe86705e01869f87a18f0321c97868d2543d2a9a15f455631a030bd93191 +Mac = 449121a13d619ca26cfd574204fc9643df12cc8b + +Count = 180 +Klen = 70 +Tlen = 10 +Key = 150d3aa309a3669af99a70f2cec52d3da16b1c137ff7466269f268059f2f54981f45958b68425276839e75ac446e0b13cedaee3355d1a28c28fc7e2deef00c822fa7b26e1731 +Msg = 07355ac818ce6b46d34163aeec45ab172d4b850b0dbb42e68381b67f1cc8e90a4c050f3d0138bab27e6f4f8d678bb65e184656493b7541649a8bab60315fa16c882ff85640e483f3eb9789c2215575ccd01fd0ced3356d9ac695e3bb19be405864b9fc5bfa5a2cd1c1c4f894412b4f28fadedae4fb842e52b0a545d8fc6d2f97 +Mac = c73d3cf2bd6c5c9dcb91 + +Count = 181 +Klen = 70 +Tlen = 10 +Key = c9c8b891b82567757dbf1a15b317628d98c486dbbe5ed4e6049a35bfc5b604264f182050973240e72ba8875367b55938eccb6c3f4e79221a0d9216c2c78cf403ab268f3b314d +Msg = 17925952af30959b1a5a136ff11b3de10db6e4cee19f31080dcbdeb43129a5f1ff71f9bb951cf50e09b3924e454d1ce61554e7307e873e9552459cf501081f48b23039869202a9c56cf0a9a17b1a69e17c16bd5806ec12081e65a78e0786faba5757807d50e998086c96c2323a8b0c1a6984ce0e22d797ac9cb46747eaab1f8d +Mac = 3b89bc8d9f3fbedb86a8 + +Count = 182 +Klen = 70 +Tlen = 10 +Key = f3ca2dbf8a94697d351f5f18320749aeae13e6d57e15cd980f1201bda0a3c54aae9bb247b0ea06c405c23f1e2bf8e97f31acb4a46f2cc9e374165e6c40bd88cfb4ce51be4634 +Msg = 00bd47d752532988758406e3cf718baf9bb9ed1be09a80fe9f59866351e4444591b75c9715fc5688e2f68004c09ff87eec9007ed0e22b0146ad389075aebcaebfc5fa4fd28f5d4d6a5a977ed9c4f205d4c7b28e8009e453c3e715e7642979ee5ab7ec8107386cafa246594a449ca2ad42340f8159e5567ff83fcadb8ef31e9bb +Mac = d6d0b96cfd9fcbacd20a + +Count = 183 +Klen = 70 +Tlen = 10 +Key = e552f4fff6f6bbd14ec50aee19491452ac917aa36a835a1fe87488d34ff61b0d02f12c1581f6da188ecf91658e5b8ddc319999a255021d1a281c57118d4ce939c2eb94d93f9d +Msg = ca7e275113faea9fa709a4ff193bb035ae1985a5c9c3d316a6d8cfb74b96ca5fbc4309196fcbd1e0ffaac1a7240c659de33307ae021ac84dbf58f071c24683dd4f6415a5c0f9deee33fa11f5802d6a536e8e067f26f27894e7ea1954fcea9f6debabf2fcf0cd3b50a9c13df013e6e8dfb5f22b1e1b940b738658f269e2ca4998 +Mac = 4fa9b60a5cde90c2c0a5 + +Count = 184 +Klen = 70 +Tlen = 10 +Key = 9d4219ed569eb35a9f5513eb1b938842371a995856da49b82bc299eb65d74f339283f67c3d2f268f5a140589e54d0e8bc53111b4f6e17b4ce71dd842215c96d92a1b0c9ea975 +Msg = f211cbcbf3f7a9c489ebe8f76922fad5cd3d0fa66b6e9fd0a4dd4256ff4ac89fd5f386794eb8ee5d8c7d63f525d04bdbd7cb65a4773c5c1d2b049dd4d9bd66dadfa020c805a5ef00afeb8735585b412e3b896ec653daeb3886ecf6991e323fa678df42c00006d5355dfffdc1e80c0655633cd316e89072a91f5df3aeb4f17b8a +Mac = b621d1fa15d9345096b2 + +Count = 185 +Klen = 70 +Tlen = 10 +Key = 4e1acb25c41216f48b66627320abc5f5e0dd1a7427f548cbbab9c82562d861b6da3636a9eb850359d615a4c3f2edd73c961a425f3947b84ad88eb80a998e3653adbe9e747a00 +Msg = dc59a9d3b6d846f0c7b2ce52eba31d3bf192915e4c7260e70b662fbc0c28e0026cababe441ff708f8c764b8169056a0489ec1bf5e29929caa5ca69d471f390c0c6df4764bc9982b9f58d0d23d0eb67f9df4cd4419c98aebb5727fc22732646aed23da7dd8e6e2373ea413bbf881ebf21dcfae4c9e03696c109c30f2e7a8ba9d3 +Mac = 5686971a145ca79e0b63 + +Count = 186 +Klen = 70 +Tlen = 10 +Key = 4f047d37c653ac9434b9ac3e79628864179aee4f448ee0443d57adacdc3420726d17f7adbe64967f75f5fd3ca661f8cfa57e955a1924db1d5234b999ddd93df5550e07a07b61 +Msg = 62e2a73bc77ac85b1aa812463dce29a097cf3c6973d98b76a28226226817f74196300255f388ec05e00cbaca3c32dcec868c6aad419dadc39debe10c5355397ed1a7245d976ccfb0e104ebf586f6b014208722926d8b9307f57b69d2edc8210b5c6f94b97cce794563b52c2fe2c1ae00aee5ec80bd4a4428f35945dafe16b6d0 +Mac = 8ca1bbe34502616b975d + +Count = 187 +Klen = 70 +Tlen = 10 +Key = 22329812517b7a7a31d3cbbe04c3004e07e65a36a34abca4e71abaa4367af22f3db39f6428906b1516088585ca1cf470a3032b4cce85ddcfbaa512b1cc827bb3557f02e0c1a2 +Msg = 34576ce2cbe2173bf40de23050851aed2fe7341f5678b34f00154d6e226d49b1f36d2b9facfc93688ce963782021204cc1269b845ebcd03a7ce60e937a1058931a8e0c363d45c2bceea87744a2e7eb9cbe6247585a640321450e0750499110bcb0a156cf06266ce0213467bc5f3d42862f8581c2d3d715ac647780ce165739d1 +Mac = 970c9b7981a9b706806d + +Count = 188 +Klen = 70 +Tlen = 10 +Key = 09e5e326d7c2b5b17381094933ea11a5030c36d9b8390d7ba15187045f44687af7d2fa4c2695027ef542f3058c2c62754b09bad917f931e2f2c4fa45cf63bc5ea4c34419c0c5 +Msg = c8ce9813cc18ff5ac309ea9e2a79e5091387a258d2814ae1fa0511d488660dc15d51485af2b1147b47cf9e671cbec65564f62e2bf73f918987d15709d5b966c5247e3a1aee0538acd7b23faadfd08154db3391ba261bbcc6945c9d7ca7bcec81069d97da2adc14f75bf8f5f0db77bd0e6185f28dc8df73a009ef0cb6673848fc +Mac = fb8e0cd4a7656f1aa4da + +Count = 189 +Klen = 70 +Tlen = 10 +Key = 25ff10f4312ecc23b4af653fef943c7272f9847031d1f959dae5cfe16619e9aeeff14c02c155d399b39124d5b8a0e218b1aa257185cb277c74164083a8da14e90d230bc96384 +Msg = c4c45cc235592317741f8ee232cffc52e9cdd87d6f66c9bacc56284b498eb740c93490975cea5ba81253c4c10dd32d0dda979fba02d6075adb569f8aa431aad2d1d964cda45a398afddf35317378bceaa31a7bfac8e89e2f8db0437f1fb92fec85bcc0ab34302384decac77c8c4512b2ec5f5287ec24f601876efe72dfadb054 +Mac = dc82b94bb291d36a94a6 + +Count = 190 +Klen = 70 +Tlen = 10 +Key = 81168b80d79f8ddecbd9e411cc41a22eb02b63b304be3bb5a140ed3b80945ee5d00049d1453433beb288a272da868a5a84a80871cd625262c263eff12e192397b173ae6c12ea +Msg = 2c869831696381346890bd7be46d798e15dd5c8879fa6b6dd4072abe76a5044bbc4aed49d9f046a4d60a0197d8bc0579a24bd4da5ad36bce90386a897c5e742c879dd9df0e6f7220626ccd5a13798aba6e3c053e44d3360fedc5d5108d38c1b79665a21c8e4acd4f139e69ef1c0ad0f8819638ddbe6293d7f496b47c309bb293 +Mac = e61320faa6b1a7b6796d + +Count = 191 +Klen = 70 +Tlen = 10 +Key = c6c9fd575759c0f6010ecb932fb29559b5dc24c36e09d35423ee5289af0dee0c6187132aa2310f87d8e918108a2b9132c4df8949bd75855cb7347f0727cf2eb8163a881fc7bb +Msg = 008cfd9f494b35d937ef3e1d8dbf95015f1284bdd206ff822375cd0deb25e87ba13f255f60031712eab9314aeeeb2cee86d1a829040d16beee99d59b47fd9bb010c517010f32d5facf306103e888af558057ba0c12bf6c7d6fdcbec902f920b357041baedf40353aed3a157105fee7dd568a028d8583c868ac27cec1a3833e2b +Mac = 490d70fc32e3c5f6c17b + +Count = 192 +Klen = 70 +Tlen = 10 +Key = 560d76c1bdde2e56ff54567df6713e4e243c1a42f7fe62fd4bb1786a31b68c0defc6bd95482b80b1fd30462593d6591d57c807c1a0910309540d08d3ad1dbf333d9fe30a309e +Msg = 07128bc2e31dcb22aa5b9f3ed1b852041d36f022168f59cab91c95b26df56760385a25a43351c6663b913da1ea9f06b0c537fec9b7ed77c7bf148c2ce5dfb26672c69051602b11fe103eb7b33b1e32322b41313e2b15785c3ce732d7090589061d1f75d154f3d1728f2ab479ac7cfe13b61b318b584f8311985d31bbc2ae15c9 +Mac = e271addca04e8f983680 + +Count = 193 +Klen = 70 +Tlen = 10 +Key = a193b558891e947e0ee76f912ad51c607cdb59ffe033052143e790c9b696b022c07555aaf994e096d4638f73bd743c096482488458b3d2d6d71a2c57e5808fae9b640df5c240 +Msg = 58dbed97e835ff418e9b06c0943d43e2e3727edf23504b8b24798cd07d37375c73cc59971c035bd8c40b84d88f85c06760dca05dfad5a1d46567b19494ccefcf44d8b30f278ace6c42e1130293f016a2f83533c84c27d2cdd30eea5ed817c42d94a802e652f1df65d1c4b826eaa6ccfd72264007626d66e035173e1692413dde +Mac = e2280710a35f000d2ca5 + +Count = 194 +Klen = 70 +Tlen = 10 +Key = dc986d3d92368e2a19f49b6e537aaf845acbce31716c79c43ac8809d29d318ec38ee2dbbdc0bfa2f3811d60a91825175035b7ffd723b94dbc3c8b1784b4efe3087aaf9560e67 +Msg = 10ae29e78abbd1c4ba1a24bc417b6122f5e9b87628fdb0382e51c6fa193856b9c7acbf6d1f88c3df97f82cbbf92db5e6685527119ecac38f7789e063b3e7d59ef77f19e8166fa95c8fc4aa9957325015d809feb53964af9be0a39440351cfec2a90e7f7ff8d64ce2aa66e67de0f2fa584dec858983333b0570882ab628419bce +Mac = 2a7d988c3a8ed31c16e5 + +Count = 195 +Klen = 70 +Tlen = 12 +Key = 086d40b5bbe75dfa5905545f83bcd52d712f092fce2c0f5cc9faacb569523e7120abf258a4bb376dfa3a73cfd3e9f4e11cd329a9d1d212761256f5c678625366a9d71adb2af5 +Msg = 33fcb8eff417866344632d0f9e8198c4dbee1c139edafebdef37356b2610729f0b1c5eeb3b932261ce402d4a36d8311b6a8a6fa445d7358b28a4a5f9e78db793e37d82ac737bb7b889c76e04922625a59d7a05afc09568a7b74f993acfd6da2e0346ac9a647a4a52be2177a67814794cbce7669ad8bd9ef8e4619996a593e35a +Mac = 14ad915c8190567f889160f9 + +Count = 196 +Klen = 70 +Tlen = 12 +Key = 5744618fe8e5c1e4cad95cf43505cc032df1cfe50434ed13202d5bfefef420a377907660426b7306bb03e82fe2e18ad2a7cf4f1465461b61ac269cbc43a972536d9a94576cc2 +Msg = 90a02bc5f26d2ccc030b1503c6c712b8e6ef4b41ec33b887b45137c122f2dc8211ce88f68c17bd684115b008320ea0ecae68675480114f32661f26eac5b495569a25ad0db45bc3e521797eb6e6be2e61f3ae5f11556cafc1ae6bdcffe24521ef14ebc392d1ffe7488a7ea69448a263209b075c01d30c803b737c8188e36e2955 +Mac = 43bf1001ad1f5c5adf0f59c2 + +Count = 197 +Klen = 70 +Tlen = 12 +Key = 6154b5d6d233c4e630b4b2094155954ee63f80cbf4ccfa3d4047afeef9f366dc3b4e3317e096ee6b9a8de33f3f7acbbd6370fc332cd2dcb962179b15c6cb22dba5d646d9ac01 +Msg = ae3897b902c499faa6e54fcf8864ae65eff6e24903b5ef7e8fd198cd0683805cc4438f82973b97da7efb3796b06e0016e00dd7bac0529af4c47007a12841d99934803384bf3842f0f27c1fa14e59f228f0095db814691834d9aed88c4453764a86554d6882a3e4658ad0cd98690cccc3a7523ceb08e3af6756f2d53860a19f98 +Mac = 72ad19cc01c8933dc6a37cc5 + +Count = 198 +Klen = 70 +Tlen = 12 +Key = 1e8602e3f3a12b3f9ab21c3a7add7fa9a5381eff4f74f51385c08c231cea8418e7c76f0b2dd6e5095920d413f4621769d16e4a0987cfdd7224ac68ad20ef3e8e90a545389ca8 +Msg = 7ac33ace5b4a6a3292b72d0dd4bdf853509d9bdf87a5bc155ef684c6718b9853ab774b16146e12fde9873878f240d29610c3f66b166828b4d97a15be8b3e848344318916e292fb421320296eb025c9c44db331930e2ecaf1bc0ac1a417d6ff436e7a5c986ebd0f49380a69b7b673c4272ef6b62017ff8a132c2ff042c05cf3da +Mac = 639410b3e778003a9d66c317 + +Count = 199 +Klen = 70 +Tlen = 12 +Key = caa2f077c0bde9e98c2f54a98caba4a9f95de80e742bfe92e23b03267ab50ddb1cca1d02e5f54f92008054cbbf4b2219eac9ea3b574b4ba4ba81c522bf3d70bd567beee24e9f +Msg = 820037b251f283a52f6c19177dda02fe2416060fd593158e96dbe6647a3bde72afbc3325be56514a0f617d24ac4cb8bc4691e6797de82ff05cbca6fd23db28134a7187d0c237e8d57ee86ad432f509ea5b79c1307f6ff68db62313ce69e672f85a067cdce4fd11ed85e92a4f993cbc3068b5e05b638f320aabf876fcd3c482c8 +Mac = ac6f7955adb9610c7a30a046 + +Count = 200 +Klen = 70 +Tlen = 12 +Key = 12145ff87225dabfb7c8dc370ec61b16e6219c14a4fb10f298b464bb3053944a6c27c00c92ae810723b57d1b0dc1398822ae2fb1c9962120f4f4acc952092093c57f8f14164d +Msg = 097abbed69ebf2e5e87e4ed54fe38d10f32f4073962ed25088fac6ab11cc40a91413c745ecc349459af05f6c229bd3f232cc603105e1b8a18725cc06baa447e8583e5b44bafbc181f89efba5527dddc9ce8f4bcb23c74442d6a020b7a3fa15121e2400529a3a62814ab1a9e7a630b27f10a18ba7b8897d1bbd944a249575b30d +Mac = abee151bbe2d515b07c63a23 + +Count = 201 +Klen = 70 +Tlen = 12 +Key = 495539a68141fc099393ad40555a70ebb45e3d37f9573fb14b5c7a5c759eb100ea5687c606fce40297ba9a509c2049e24d1980185b1e245178a916021aed10057cc4d033e6e9 +Msg = 3f61d4e1b7b2014510544a12ed367d378f6204bcebc8a4a8003d6b2367c3e3d82c0b8c9ddc388956dfe69a16086b4a886b5c6a8e6f54bd2724f0f596d61edec1e298dad7c8ab8d35823dd98b140e0d3a653e59014d1086d9efede31d49ac83ee0910a5d6a29274aba061f1b738a82d15240fbb5eae8465860a3b1e00e8f33829 +Mac = 21b96662150e4f742128dfa3 + +Count = 202 +Klen = 70 +Tlen = 12 +Key = 387ca57d6cea7ece2adf507ee497bbc1cd043b32e3c04d6b2d45d4d34160bab80ae3da9ec89b1ed65881e452b634a7b7c0a7dbb43d1718931d417b0d02d14a63001dd6aaa113 +Msg = 0f31992894b41db6dd3e8c807caca260b2ca46b5320e6bb5288734057a105b874ec9d373ccc8aca9250b3845d4b16c74246a8887f22dfb46b4298087bafd8effb42bef5775caae82f67c374f9ea0ba3ac0c9d088666e61934de3c5623087297c494035fe1624ecec5979d3c562e0555a90cd66df163a6743fb9d49bd6517f6a8 +Mac = aaf4e6bc966753260f912e95 + +Count = 203 +Klen = 70 +Tlen = 12 +Key = bf1512506858d2b38e387a1e65aa813bc1c1f6e6d96a6a864b59099e61430a9f934e4a014dc63391f211e30d20e58aee36b8148513780949217db17093bc7bbcea3d9f98becf +Msg = 8eeabcffbbe968425ff795fabaa1a9c77a2ce9a931338fc205921c5eaa83ef308d0717de528866c181bcc6e67cccd058b5b69ba11df0d28ee04e0a334f25522f1db10b31cfb4fabb6e609b267f77b8e735b13b10e45e411ab94c6fe1a9eb89f0a7af40ff1ab64cba8eabbbc4a9ea89fc61e470ff6dc501eef955f4719e1cbdfb +Mac = 6ea8c31c4035c2084be1743a + +Count = 204 +Klen = 70 +Tlen = 12 +Key = 332c022cd7cdbb71fcc3eaf48635a8bb6e03e73f5c08a9cd799c702d7e5df58212301c7152822885b1d42bd20276c1d9d392feacfd6da55379ea9b6d75509b1aa74c2a19e23a +Msg = 07e23ba57979f53aad3bcd9341e6de6fc64ff3770c9cf019a0b36e9394f3a64e7e21906ec3a54ca716f6c0523b5383c011b4f9cecf00c0b98e804b340894cdb89fa4591ca15a4765ca0ed9df0a821f6d89d0171de9a019ffcb9e7238942c50527153ded69800af1dd16d606335dd791d368c958ce0e6c3935ff72bc6c023f5c3 +Mac = 07c6d34628e28c8ba39a619a + +Count = 205 +Klen = 70 +Tlen = 12 +Key = ae1ba736e20691bcc3495be8e438d9cd5aa469de20ac7c5dbad753161960074cbfd1ccf423d3762157453dc0e88bbd8506294125e49040c6623728b3eaee5b559770775f9d37 +Msg = 8c79f911b301a8718cc4b19a81d5f0cb6312d87c5b4b079e23a61d247541cfc2c41a37f52b2c6e43a3db5dc47892d0e1feabcc5c808f2391791e45fb065159f99c1d8dd2f69baaf75267eb89dd460f1b6c0badb96cbbc8291cefa370fa7ad6997a4ca2b1fe968216032f02f29837d40215fa219c09161df074e1de8e37056e28 +Mac = ff39e0b4fd5cd0c40be32024 + +Count = 206 +Klen = 70 +Tlen = 12 +Key = 25117774deaf7c068cbd4ce82a595a584ecc9dfd541ad81eb9d71f12c53b97f76d797da7774d6ae8dfd4d5e37aa1d9d8d90d380f70cea112f7cc2e19113031c62cbd3012a863 +Msg = 08dd4f5c7afbdb4363a7df60d247776d6c7c122eb155d44981c23858de4bfa3df30134b555b5c7318a69fce1c8046b11fe4a1cb8190aed4e809933dfe080a45e2f72753beb81bf37a3912778b90cbed866d72683fe85f7c176cb601023341276c4165915c3c58c00b806a84d2fc7386cab0d78b7eb2db9496b3f07142ed00a2e +Mac = a52411b649601f629bb75f5c + +Count = 207 +Klen = 70 +Tlen = 12 +Key = aac2322ffd2efaebccf8389eabb3411ab55f21087d90322c48cceeeb7934020a4c66a3b8c7a325cfee2dca5737f3d84c3d70eea0b8d19784ad5620e4e2faa730955675626dc3 +Msg = 7261818aa26ad3861426af03ae6ddcba10f19213d473def6143747de2db5b230c39183cc06cd05e1333e0c055d3cd9856d9e3df968e6021cf0b886db0e91a9ac2eb5e9216b69ccbd0d637f06507fbcdb68b3f008c1459e188b3bfe6b7614eb88bab5fcb35ba6f0c3ab7e4f2e109c4e660718f36869f97b91eea9f9b4efa63f6b +Mac = 2785abca097ad771fcaeed6e + +Count = 208 +Klen = 70 +Tlen = 12 +Key = 100bd00e9c4c9f2becaec6145640e57d1363a9e8e8dc95610627026c300e643c1b7bd0251a8bbb54fbe305be2b47365621690783fafe24d1611730e7b2af09b95f804efe921c +Msg = 725400784625df22bbb897e7df2bdc801f8e8c1f724788f5d4b5c3f7f61498e234a1617cc7fe451d3cd7516f24c6ca720e74c2c3b202ea1d6fa7a720f89a68514a323663e14b8db52bed6a1b3d28a5e1c542810d3f1582e56cb27eb1004af7c29b4fa8b3fbd65eef70400973901913d62b40f0868248f754b31f703378edee3c +Mac = 86d5e21fca7caf63426a9a4f + +Count = 209 +Klen = 70 +Tlen = 12 +Key = e01b54dfcebf64fdc61bc0d9a46f3850db32f7350958b6abcfd130d1df52d6a55657c3224d69f2acaa9cafae3c5d4b82086a1491dd2284bb2fffb9f922612540e48d87a940f5 +Msg = abc9ccdfbd92b6919a5d6c6b5a765a39662ed90080d3549204dfaa5f6d70d48e1af8c84d53369d658765ef11d7b38510d9f431f99598f8cfd4da73d59b3b75a3f22fef7ae91610d5dd6db040f846ee6df7f51885300dccbcd38b5d28705078d3b9d5080f8a1a560926df75a1c417dd794a9a564c581a188288583001f4972545 +Mac = 0aa1a8368477289bdcd2bb2f + +Count = 210 +Klen = 70 +Tlen = 16 +Key = 4a25e3a88eae864851b4c6d01c6b98b799a70f0ca49f1860a4f167df1ce7b1c07df91ce03f93f4a92f189f390b26d3c04c1c062a43d926ff67c78b87ee192a319a500b35d604 +Msg = 7272eff0b28964a1aabfa08f37527a8607043fedf31ba6ee8fad05d8ff1ac4c10cda126f7779d8798cdfeba9fbd586a5e4c5f7ce31c1986928c701fd40447cfb34d6baa45756c4282716330b2467a4cde35f67ca5ed9775f8ebcaf4e3c813a6414ef4c59fb290ff7a2ebe17e5b11bc482c59f5a922692a19e814769598d9e642 +Mac = 76122c5582fea3b4f59181cb1d83a5ee + +Count = 211 +Klen = 70 +Tlen = 16 +Key = 13e8b6568b1d83ee06235223caf6be6e76897ffc950a9a0f7468d5a231136e4c15030c6623fbf670f10f83b1b764d21ea637ba7d7b2004ca5398d8dac1ba763e1e46276a20eb +Msg = c2c1ad604e21c2c869193d6797ae657ee740649c7805eeb83cb6237dfc88b7e59d5e5009a13d2f38f1001346d94d5a2654c76abb8a854fec97c4a5f78ed8b907bd69eb0833db57ba800eb404bc487b8ccb6f4c84de7c8fc73d2c572445f88bf9ac4847040de48077a0abe74a488710d5d4a0d49e7ed0f470b858fead29d175e4 +Mac = 87ae0952132a3b0583317997e5907ae4 + +Count = 212 +Klen = 70 +Tlen = 16 +Key = 583e7b26715647c6c50482866f84c9a097ef1f1bf4b18ee48e3e1120c901b2c19f95f0572d386329717da38552416554e0dfe7f1dea88f3c7e8dcfea6b1f4b1f0cba3e3e08fc +Msg = a20f4cfde1c12ac3aa4d11b13dc4590ad9395f0ed28032d8e4368f87c701109c0319a0a30608321674aeb37ebe873cdbf6318d46e228b7d54fd518bfa7c78cc0c640e2bf0af38dafa90c9cb34871ed85c9479d1864b9c27cf9f45d03a4768aa29389fa99140aa356f26fb6970209d2d0f98577cc80b9bd968b9e469ae6987108 +Mac = 702a4317f0e27c16ad95ec8217917285 + +Count = 213 +Klen = 70 +Tlen = 16 +Key = 381dfe5c3405f0c67216a34475d453af05f8ae8fd47b92d561f119cd1d18d34ecdb152342f8eec0fe0edbc1d7d04ea7608dd2c878e648dc107bf6e927eddca957252be067b62 +Msg = 3b8bcf1cdcd4b5673d298f8df1e226c1a7ff4a2552bd15f588677402286fe26340bd77672e4722ce05e2333832571cdd5fba787f97f74c9dabae8dead541e3fd9c2bad4af7934551b52085151c108ad0d184b7e5f81efd169bce5af750e9a0a2167c78ad81dfa659178d8f0cf932f802c606103fbc5ab1c82070e312e090a2bb +Mac = dfc632da93cb1a878ae38c0cdf5db11a + +Count = 214 +Klen = 70 +Tlen = 16 +Key = 772619f048d8cfa9cb846e1ac8deb0ab56b0029eff70d0441f1802718d32c72d7d3291aca50961819ff7440e8fa11d3f0563a67825e7b2cb05f7b56f568f856d4737629da68f +Msg = 5a84d46560d7ec2d1ab663c984022cb24393463581c5361af733b4844bc2a5189de249615d10b6735f9f85cf31b9cb87aca14ba3c93ae9c2b6cd620529073b28f541f7f2db058dd0a2cd19bd690dd2643d743c89e76f9fa507f0b7d0676dade4892b46e082bc5b8a0bc78959d60729911e9682b0826c3e0913221bafacfce394 +Mac = 490c969829f9413c70287001488b0f18 + +Count = 215 +Klen = 70 +Tlen = 16 +Key = f39adca21ff0939639ff8d6da236d519572de92a742364e7f7aada9ec7a10438f5631d10413e8b06e027c2cf7cab668f7d29afa9873f12d543821e746372a421e0ad1a898662 +Msg = 9ead422c9e22b885a422c37ea49c271f9d65f28d297fae76519bdbafa5dc9d1c8ddeb1d1daf7a576a0bd49f048c8613ee1b99ca0b77acaff27c84989b1efc09c4fd510e5053a88c9ba3e59034624498fcc55abc74aa88ecd6ee03528ac77c7b28d9a48b14a74c84499afda01c73848dc0743054a0a9063a7cfec86d5bdfa1927 +Mac = a7549bb8be315b3a8fd3e62c8d960758 + +Count = 216 +Klen = 70 +Tlen = 16 +Key = cf20eaca221a646675f696c2c9ffab2cca83cdfa0135f4154ad0fbb489fdf96a9977ce63856dfcebfb28b92ffded4248da2571755dbb92a844c67345f368ba266af57be27558 +Msg = 0f7251cc8687e3e02c363af2ed4551233cf2bfbb10e5ddbe2c622bc0a4c3f0f99d26219c54638465624115713ee9a953039ad164739f015a3c7ef21d7b7344d67f1c6848cf76bd636e08f9165d5ecb6662b9bfbd08056184e70ba5f325e886283dbeee77ffa9d602d9f5ae89548eff83e1b74f6dd6ff4562b4710decab0cfe1a +Mac = 9d0b8ca2dfa14e8aea28a65698796da2 + +Count = 217 +Klen = 70 +Tlen = 16 +Key = 8c26d9e739fef007ecf426612f7408daa6a8e41aaa918b3e335755cdfbdd66eee09930d88aa339894f0b1ebb5370d914f4ce3f9d6598cc759807a3c762b1d1f9da5dd2260216 +Msg = e437f8b6ecad318267ddf85d7ee05b35382e3d6b40564129e9f3eaf66fdb0087809935d8fa1e087cf7b3ea3207329fb8bc76e8e46c105ff0323ba2163613b35c2e019fb2257a5e3a7be9fbe72ee9f54957b8e4a7f8e85f4ff4581e2a5f635c93f8577f69f429fb63fe6774a47b6d239012dc7add6c480bed3831a65b7335c1d4 +Mac = 0d5aed6fd871560f8123439d476e19bd + +Count = 218 +Klen = 70 +Tlen = 16 +Key = f1e95a2ac2982a63584af1b7aab0ee739bacccaac5058187755e77e1f669e910135891ffd794808397b24deb33a371d9982af25089933f0da0a35b1b8fcb3ea2aca07900ad90 +Msg = 5ad21401118c89f381a8343b12fd5a96d95d587dbc26e758d7149eef1f59b92145f018d8de2e8b3cc09a4c27affecdd939beb4eede69248d748e3fe1cad1e9cd8c3dcedb66dca6766c85b85abaf69c48572346fe60cd40666255370e07d3b9d8f5633df3f3bf64094d137eba7a0c504afd3215968979c24d68128e5c1e87b2aa +Mac = f137933e9b264f559dfd0fc262a69c0f + +Count = 219 +Klen = 70 +Tlen = 16 +Key = 4c1624a9407697dd3feb1bddd4a9ad07f99039e12df356fdc69d30208916c5a278225518eb8b1331e22021de9afebbb65e0eb398a0cf1d9248564b014c93fcfa81d5d0e9b190 +Msg = e3a90651f7652c0c7dea981f8167c7e3879f81cdc249b1ef86b773c200b76f2225b7669ae82c0ae2b03413a609798f899959796a57458ee6f7675c1ea8889cba0230c12e3a0fd13b999b74b92cfb4b95bc2482160042a9641259bf4a202c903b645e429356d72a202069e4e152b3a20dd746c4572807a971bfd5c5cfcf6bf4ad +Mac = b4276d71392026f683012521bda55952 + +Count = 220 +Klen = 70 +Tlen = 16 +Key = 0531b92d1b218c08cd8630dd4861f7c80aced6f75d7e0db81e670ad6c3ba8b269d16045d59fb4024cd814a6ff24a8e0a2cb53c74d254edf1eaa189db34ec68396b98b793c787 +Msg = b9b8f4c824377a6cd1a31b1f3a21b551dfc16baf8bb002f4d8b08b02f5c64331a732b7e78ea42c69aaad3df01e74c60033aa01f59fc0efdf0857fa8fc4f8d8f2e305b29e6fef86abf2aacac4395e527d586073e7ee606963aae4f6b30ef54c5773172d164e7f51dbb18108c21548207356c909affff93728c83ec8965d246707 +Mac = 6369914b2350ed960f0e8128c02f04c9 + +Count = 221 +Klen = 70 +Tlen = 16 +Key = ecd29cbb1a39d7fdbc5c92a096c0cef1d4b2363e9e895537ec2b079a9cd32d10c211a5523f127a8f95215712f96e4220aa0e861f8244f1fecaff40d053a3d8bac20cb7102cd1 +Msg = 84c514e4714119a9e4e47fccb9e82404dd5a785060d631decc92402cb69d036d9269bc2ecc88423914b3f6b9f910f9a0b9b59c4657681852efa880de47f2f3d6a63d16a1e9c7c104d313f943a5321f89ee436689a5368b6675d5c0d05804e97167470a87f18600d2ca0d70b0e5d7fe87250cbf6371c8f0e0071ee84b125d4b04 +Mac = d598d7af92d2d65d418a116484cdad9a + +Count = 222 +Klen = 70 +Tlen = 16 +Key = f54e514eb70f39579c9f175afd7cbdf1de2fdf102b8276e042ee63cab25355d142ecec2636811ff6cddedb870e85ec83c4a02194c839ab307eadc7b7a25e9dbb45a9679e1218 +Msg = 3d31cf76288ba777d0da29e9ce21d69dc6419c153e7a4d2eb02f5001dde9970c659fd08d9535e02f80428de851167a22dffc591982bc5c842664ec779d489e883a4863319b51ff75c627bcc678615f27b9b55b8eb475458cc65a882fd5815a28e3b3ee29e2e9eb91ca0f1e4bea096bf37bf40a3b7baef08eb9988af32c9ab133 +Mac = 0dfdb14b000d0420880f83192888bdea + +Count = 223 +Klen = 70 +Tlen = 16 +Key = e88006364955d8110c553fdfd59db9baaa310ae50f9081026f8b7e85be5631685de0a4213e60fcd14830fcbefddfca035a82f686fe4ab82b8f5c79475adc9558394b60f3ba14 +Msg = 4bbb7596f19aa5ded4017a81cac28e7d6a685253c01a5e0c45c2057a0d6e2dc043f65d15d3df18c4667f6a779362c0b653edfdabb641c928d5622ceb08995d205916d42738daa69870d41284594a57fe4f7bc9da648324b5527e2036b4f04692756501568854f861d9499b2f8443fc5e465be16a30a717bca35e09e3783d9121 +Mac = dba4d87dc72e6187afd8381a490b0d0d + +Count = 224 +Klen = 70 +Tlen = 16 +Key = deca6cc2bec006c19ae4b3b2246fd63608aca28b225ae80bee522df5406a007035988bcd695b670d6a56b5a36d3e6a7b40f7ea3a80fad9c80cfa2d0cb9c788f64872c6c395b2 +Msg = f4a65ebf30900ab9860490c7bd7c0ce4f46cb5bb38830f10522e625ce25f6ab7b28c50fb44fad927ad3bde01a6f6fc00e1e68c689925d5b76dab81406e114e16779b062bbd76b1b9a63e09e1dfc42e93a90d9bad739e5967aef672eedd5da94febdc6897c28dfa381915faaf8d6e0c64f4eacbd2ee7402e7bc191eae56c8e32b +Mac = 97f6e4631174e11964193a37a916f257 + +Count = 225 +Klen = 70 +Tlen = 20 +Key = f0dae6d8753076b1895c01262ca9b57633eb28b3f963a7c752e2cbb4c0314c20eab11a10493faaf4255a8ee4c0884929d1f561ff335eb699df2d116618e60093e5c1e2d1c499 +Msg = 61cb9e1f1e4b3a3b3bdff8cd5f24566b987f75c8a05377855f772b49b0e7ec1368b9c6cf9553db2803dc059e05f0bdd871983c3bed79dfbb694bd0f1ed8de36e9577be50da313d13124215a93a4bb7ccf4f57793cc28ed43bf7e9b68fef7d125efeecec9754b28a271fb6e16899d0bef287e6df7c5c867c569f6d4d66b8b7ee0 +Mac = 62ac956ada19f04be50c23f2328a32477cd58fb9 + +Count = 226 +Klen = 70 +Tlen = 20 +Key = 65af1f17cd7fdaa523b9b7a9829d497cac7303d450c59e9888cbbaf3a627c8a830d327a529578dda923fa94b31cc076491ea338d4a6221ff8251ccd6b4d91e67b11610d3e453 +Msg = 9ab4667b2df7eb4be8863aa53e9bf9af8bae0fc09de94f7373dc56fa4472b6b5c4235403a26c0e59557ca1911831ca843342acda7dbe72211fb5351d9a34205f0c77d219af5b0331a2126b94ec1adfcdbe70bed6f8018b2eef61db2b6dbf7292fa19a9655aac13fc57af5f57c14080b3b29f0c5b169ae2c16b4810cdc6faf475 +Mac = a279d055e2d73306a8187344fc32cb0b5b80cd35 + +Count = 227 +Klen = 70 +Tlen = 20 +Key = 538b4a4753183ce5607fa03636db2fdc84722aeb9d98a6ed70d0282aba3571267a189b6aa6eb65871c5dcc59dbc7db8973c7c355ba2a2e94c110d1f4064a4087eb07077e67b0 +Msg = a1c7f3c9a79b071b49301aac754a2e89d971fd90a7a2dfc99544effa295d6975330657359b1d6d295c3931d0d1e35f0630038b1e54980830bfac09b4df880650902461efe3e14a131d7ae06c033898a95566e38e99050b4719c15efc2f238fa5c00759200751658094dc6ea994b3a31a52844d09fe51b1b5ae6938f8a297cd1b +Mac = 05598da96093f17687d9cca772ef61ea2af8ee40 + +Count = 228 +Klen = 70 +Tlen = 20 +Key = 1e7982d0975b36da4144041fac9a7f70b4d5180bed489f11453e073be4496ac957d74cbcee06244562ba197dbbec09567145cfd2d2ebc673a39b89f20af8fd34ac229279128b +Msg = 8c5337d74388cbbfe0f400f403879687887b6b2f5cddefeb8f49d8e9abf517a745f00a58d1acf389bbbba904b3d68df44823c04bb8b89361065b3fdd4e8bd7d956c57a416500cd7c587aa84ff2b610fe74c566b46dc6dd24d4a932715438974be757f05ca68a41e2e0b9679d693007eb34eac532240fb67e20bb176b66013f46 +Mac = f174bb064880c9b111d71be221ceedd9add971ee + +Count = 229 +Klen = 70 +Tlen = 20 +Key = ff5f9fb03fc15b2143ef638bbaac07557d3efda920bb9bd5c68349f13a0e37c23ce84bdf19f95e127f0aa7018e85770e327c277bb1ed4fd2804539845b2296d0945d6fe6ac48 +Msg = b9b50774715edeb6947842ae807d18bed911c4c9ce3491fd9ebb53f05b014befefda4a935cc81994487219e2b85127f21cadc2568cc8709151595d29a73b46fec16795d90e20ce48bb6d29aa79cc818680256c21d3fdac4fc6ecc689be51f040394430710eccc37af552bc2c4956ed210d610a4f2e3b0cde075dd4372aa9115e +Mac = 2f5e0b070c0e268578ac6e868b364b144abf84ad + +Count = 230 +Klen = 70 +Tlen = 20 +Key = 06ec0e5bc833caaf766f8a531b09621c0c93e859280196ac5f166f18711ce55af8d8fb7da9bda7a9d7607a3c382c821bec57704bbb14f6bb9f0b73648206d29448edaf8710f4 +Msg = 15b186bce73456813d85a50e68c4e2a5fa4ec9a3288fe5f7731753d888efcab8642dd873bbc66ecd9ba49f1b4df8a5407cd225db98efb4bf7dd199a45015d41caa0260c8f95eb6cb2385927f6cbcf96799c27b6555a8b62dd5e31bfab8a0f5803157a62167a334631c5105a28db6e7029a4654a82763f32ac2736143863532cc +Mac = 4bbcf1bf06f47a720078e2a886d70c8e90ced8da + +Count = 231 +Klen = 70 +Tlen = 20 +Key = a52069d08c729eec3f803df6adcfc53c7eb6456549bf29fa084f5425c98a6fb8a6718070f64dbe7cc551a439827b4440f8bbdea28057b172748e1184e67cba75923d64eb1255 +Msg = 5967ebc2c80785c87cda84a888f4bab97312ff49e981819ab13b5c2adf546b374b945d8341660b557af008c04b847a271d3729011dcfd6da35e3ce9a3a3dbf0a6783c9940a17d84b7d3b322b58794ca1e542e24ed4d546083062f921926f78ec957c587e89e295b26c012870169ad72eb37a51b676597a2a8c0104464fb33fe6 +Mac = 2835d14142e4b662578b4c0879c1831bb7245a5c + +Count = 232 +Klen = 70 +Tlen = 20 +Key = 5a04585891a5ddc97a7ce83bab92eba55133905c7ff4aa34c5f56be80564d7bc824278603a6a541876cf1c1a9f05a63753039dbeb827789e107aa8ca8e3616e26885cc0f2e8c +Msg = ecc714bd81aac0002a987a81d35d328872a23a2e8f63ec6e03a4937f0060896151c39cb7e399b6d48505be18ec76b97dfad7356d4006e7d7c1889381f87b2ca01dcb3da6a5a9875b0839eb2fc68b8bceaccd2df653bfe085eb67e1d73605bf4ed749be32cdc479bc3b9dcc6d6a85f1a410ece970d3751ea309a84628c2e88a96 +Mac = b8ffe657b108b8367502a28c0fa1d595ffa853b6 + +Count = 233 +Klen = 70 +Tlen = 20 +Key = d5ed1cdaae3edacf80ee9487eb317df46ba293b07ddbdd350443f150ea28bad30a0e788b4e46087114c26624d72770970b24ed074803cd31ab7db2c17ad3b00d061a5103d6d6 +Msg = f753f3e9b4bd1895a259492ba160713f00ac8e24dbbfab0da7070e720b61b2b6f1dbf806debe99847eccdfa584c615d7b1313c68315affa32e98e93ca0d1d6ee623fa7628b743a53fb9c9af0340372816cd7c84ee02ee7bc6a4a9dba561ca75b72086ac464e8e4494053e1d35a1f728559249b9f8d434ca283a892b5d64b0f47 +Mac = 7056292af9371cf9ad3e1b9c2743cbc1f52b4e16 + +Count = 234 +Klen = 70 +Tlen = 20 +Key = 9fc05ef49579aaef45c00586c8a35dc0960513483e8951715bb29e77c348af0801fd80020650a47f1bb2da0f1ae7e044deb08c74f8a718baa36abe3efbfb84b669675a2d62a6 +Msg = 4e7c667a38bee08ac51afde3f22f2e38736a7f7d3f7b32f94e05a79ba19a809184e60217102abd8df3ed6fcd74ee26bbb15ca51e2b4909ae855dac6d89c74a3b6c7962a55395dfff1522f8b2430455d6662b7304870a4965f54b2c0f42c1f0928f9e50cd09e68f07b423603b685b04b2193fb2d75ba53b482438ee29d46eb9bd +Mac = 4dcd504d883e2b9d5d1e1ee15c0ff396f4d1c42b + +Count = 235 +Klen = 70 +Tlen = 20 +Key = 3e3b577a9cc800d2dc69362837878d4f7ec0fbf3fe3ae08aa63745886cea61d2ec8a627652a46a997bb5d7b157f8c7f4927ddb0f737b3c1c04e7dcce7345ffefb8bff90d7874 +Msg = 7a000b03fce176de620f0df2d9d3886bee54014da45ea65bc361b13874bd9acc0b3c8ae924e0142ef1e0202cd2ed27c826b9a6e062bacc32602c7679f9555ed8d50c8f7c827c1d7ec42612062c25abb6ecb6c546eaf7926b13ef90fef2cfbc5a817703063f3cf99482e9cdc80f037dfde85246c5659c5fd086b4e60f88b41b18 +Mac = 49d70fcedd5029673d8027f34a4282968237cfef + +Count = 236 +Klen = 70 +Tlen = 20 +Key = 98fdfe9b591008fa03fcc480809410a53a2a4175de480de360a1a95f3f462eab0a1d41ea2390f3fac382e6033e87b2508854865ef87413334d3da5f1ef0393ab778bda7770c2 +Msg = 9eeb079c552e421f703085b9b275d5b05c0c922efe14f2e78c7faefbb416fb1e6fbdbcf6d7f9f6c438af8447692f0cde5d7031ecf59d0a8018d1d3360620e358e9d6de49ae032c241237aaa0008a9f371adff187966a99f84b70549f0b4e9b6234bdd65d8254cd85274f5f8b1e8e7604bce13ac6888285954ce397ff6caa0c84 +Mac = e887df3367b67f8c9e7386d13d1a07a08de9ec68 + +Count = 237 +Klen = 70 +Tlen = 20 +Key = 74c6bd81ed71bebacf5f7263cad715951c690afe4cd127e41b1e5468b813540833cde26834a60052ed5a8cfb4d68148876bbebd0728a7c64217ddfcd7611aa14e33d0a881256 +Msg = 3af349f3647218e4be26fa863ac71381b64fccaa7e66761e121e308e2ae00ad9f8a76ae0ad6baf963ee115566861d87af2279d2932bf0d70d2bbc394d4a768a7d43f1c5a8ddf18129f3a923e904fe1e71099e28881869a21b62b1d87fb36aefe562427090db49c81689b3be5b87976f1980c657273a3655847d6060da8752405 +Mac = 97284bd4e44b2e7a034a2f2795d70250ed5c84da + +Count = 238 +Klen = 70 +Tlen = 20 +Key = cea65320f0ca8dc160c5ff83100e523a16b7651d5e4d9cca9c007b8b850373d83f36fb1d1603e3bd7085e55603f07e47452dfc6f24c4d738f8ff44d4b64d08c766e48aa6d7aa +Msg = 13aaeb074c23597bf5557b221300ad3df211aedc75b198feaa8116f8a124d11b7fff2b91ce3c30881715c993b34f334cde04b03f0da67d03824103aa1d00515c75f3ca3e270f1b986e777138f4fae811e8dc462851d9e9b1a267fe748e3cf4761d1030d600a403f52203d9d97f07b3d43920d760e851c54e327b6e209ddea1b3 +Mac = 0819f3d43c19965373a3fc72c446508c969d154e + +Count = 239 +Klen = 70 +Tlen = 20 +Key = 314743435cf8e0a1e1c4a321433bafec55ec262de77aebc5a4f3ad3f3b5e2106bd938ed546508f70e0881592a4feab262313feb904dc9c30ee78fcb6a8a1bff97e803596e7c6 +Msg = 0136ea476e2e823f8e00bbcc7f9fc7272e951bc4caa67e1d78b060b248d66e4e67dd638b97d62198ddfe003a79e266111bc7981d5448cf814b418f86b1ec34e2f74ace3bbec52ee78f1341f6cc5d9d72e6a15ae5d155231cb54d8c2be7dea6b11744d25dcb41d2b10c0726065e5895d1f6ec0a242813a1781f9b02a9d0f4ee42 +Mac = ad4892f36828b64ff5c3fc2dfd780dee39ea30d6 + +Count = 240 +Klen = 80 +Tlen = 10 +Key = 13fb1ed6389f32d1de3139cb04bcdd53525c9889b85379d3535a25d290351c95938a3d0cdaf38dbf1d5234bf7965c8ddce9ace1b66247e60d74ec7702a0f931a3cdf4cb465ca9fc458c380004a3a6e79 +Msg = 0c36ca43e7c113ed9fb71670b3ea73bfd6928c839f36db1a82d08ae0ff2c3dae199133a10aa38d1d3588ed115c4a437c137ce4307421ddd615c9863237fd5aa840dd05ff6c08bf66bfbcd9b43e3f95f45e7d3b21bdf2692e10caab495c474b616a646be675b850d0259c01e2c1901130a0dbb9dfe0722a2c5b1b20afd7d2bbe1 +Mac = 7653dc1ca2b70f058614 + +Count = 241 +Klen = 80 +Tlen = 10 +Key = 5cf59e34f1ae4ed732a95cee65eb494c1f7e89e1a2727cde68229f1a00b904b519f4fffbdd29238b80886cb818a1be2faf268eda96f2df05fd4b71c0c16435848526031904308fb6a51d9a6b510565bc +Msg = ab5da4a64fbbf3c60f5ab1f7776ed6a55751e39a5ec81967ea88e9061ff9adbd373995451864e42c2c135c786d22f68dbfb7d751837f808d693b4597857c002ea6aa06a5e34b5a44768221ebced656f8df35bf6bbd39204869aaae3dea43c685a0b9df0cd6f9bed496b1e997c1135dae5fd68331337d616092db0d4176d7688b +Mac = 8db94baaaf03a51acc87 + +Count = 242 +Klen = 80 +Tlen = 10 +Key = 909d3891b6a5ef3c812128cc630711861b6e73dce4f289efec5a12520778a511a55145f2027e35fa9cd20d33ea3d0ead4bf0b3c33dc2889fcfd33f01596f013b6a3502810278585f01e50d8be06673dd +Msg = b7b3580daf783c070fa8fd143f5a65a18115ed1a26388c670299cdb71d6d247cab6882b63f2527753bc7b8998be191dd93935c1465f6e2b238ba228d160ea0e5d4c000a247a6d3deb53cb1a38a8e88f64c593314d16d4ffbb0554a2cf53abcb01905fb5931c4ea4a654f11b9a42bf3f496ae9ba2d264794c52b26c1c23b920e4 +Mac = 670c4e2d2661928b8262 + +Count = 243 +Klen = 80 +Tlen = 10 +Key = b51ec038eaf03b3acecf407f43e2f0f4961516850f5e5d87c645c153b9a344341caae284f025c611d701bec6270ded873dfec05c14b623d216c6f49e3131b7842e738c773ec15f02d6935fe6bd60b105 +Msg = 2ab533078b3314949c1f34c68bfdd76750f75105902c11e8c14ade47905f61bb7fece4f3d33c59aaadf39ed677eaff22813afd9fec974db6c8e0246279f3b29c5fc6ec16b6b48f2bba1462160f10bb6361b544a44846ff656ed68862f3159bf7106bd5d7fb43bf010baa08f01d181212368db17c6ae02fdcfc5493afc66d22b4 +Mac = e7007d2f4a194a8b8144 + +Count = 244 +Klen = 80 +Tlen = 10 +Key = d4c892aca8c9574a48b761f33f44aa867bf0c61a4929734280b77290fb5795574da61ab5b14137d1402bf662676f43719706435f3efae829f7ccc3ebfd1419a3e66738388e7d0bbb5193edec7d0fbb00 +Msg = d1a31b1f3a21b551dfc16baf8bb002f4d8b08b02f5c64331a732b7e78ea42c69aaad3df01e74c60033aa01f59fc0efdf0857fa8fc4f8d8f2e305b29e6fef86abf2aacac4395e527d586073e7ee606963aae4f6b30ef54c5773172d164e7f51dbb18108c21548207356c909affff93728c83ec8965d24670761527076b3bc54a0 +Mac = b58e9dfdb9d88df4c71a + +Count = 245 +Klen = 80 +Tlen = 10 +Key = b6294d160b6df30fa4546b63ae64effcbcf74415694984f13ecf21ccd6ca27123f1dc1cfa45bff662925d68717b3695b39b08601864b743eff8bec70dbe265c4e20695a917fc3485997503a6cb5e0d7b +Msg = 4c76c4e416be43ac382abf32f44d9632a75c333740d8285ff66d7d5e3b1b48c5eb937e85cae409ae2d561b7df796c196c714bb8e70aa8bacaa7eccf10729c55528193e54303392a979bd065a867c59f439199d1846ca4536e82e7e99d378c3a469cfab5b30f50625842729cf894586d5643380ddab7f7d8519443c5e874e6938 +Mac = 97eb7dab4c4d89026158 + +Count = 246 +Klen = 80 +Tlen = 10 +Key = 3b1cbf6f4212f6bfb9bc106dfb5568395643de58bffa2774c31e67f5c1e7017f57caadbb1a56cc5b8a5cf9584552e17e7af9542ba13e9c54695e0dc8f24eddb93d5a3678e10c8a80ff4f27b677d40bef +Msg = 34f6d2877d880c45408f53a1d8ff956146ec6b488e579f8e5e48ec8df11d04bd3321d8e22660138484bae7a0a6370d9da49a0781be39a965fa0bd7270f03905e829c2c930fb6e1ae4aa08cae8676ae9df6adb5c312ec7e1b3c1d1703a4c5c9376990560001317fa9da68c9334164814a844cfe77531926966ca6348b780ab831 +Mac = d56a5de69805f8a9906c + +Count = 247 +Klen = 80 +Tlen = 10 +Key = 09c8f4a892b2efd209af0a8135c15756c528213c86cac5edd9d8c3b965af158309fcc00c1424a874b9e3a8fdbd33e213736f5489eab8ad2665985e600be5f367e0e8a465f4bf2704db00c9325c9fbd21 +Msg = cf3fd262068f490c203d8ba57809e693ee284f4a3744536e77c55137114fe71abd8baaa6dc2b1aac0928d5a2f14e0a4964fb318eac24f9ae1d98829eed89cdaa4648715c9a508f9f378607241bbfec05098336a9dc11b7e71ca2516ecff2656491fd8e4de706902fd1de8bf39e63750f0447c6627013755f9b6b246e5e93988f +Mac = 583bc1ca3c68ecebd811 + +Count = 248 +Klen = 80 +Tlen = 10 +Key = ae69e1f10bcc8ea9e47a1795c916a3132b9d4ba7104970fa0bb551236c43dc26b4bbc5ba4c34d650763886508323cca647cc357dca67354a40aaba0d3b2f07d4201ac080d7fb41cbc7f6348a02216330 +Msg = f570273a4e5dbab38410e4af672995eb088408461e0e4730a8d7f15fd4693bc3205935bdbf1b4f8c3e1a1b08670854926673204b2a9a92840e7e7376b93c4233429979dd98df121622e84ab7a278a5c55fd032a1837f107ec27c31183c725ea4a55b7b02a3500d3a779ff926e01f8e6c3cc0c6b0f166c9070bf8b3ae27b397fc +Mac = d4225a4949faca02f3ef + +Count = 249 +Klen = 80 +Tlen = 10 +Key = 7f0568cca4ff79dcf1e5a306b419d25d47dd4cdd42bb86f3ef243c40fe57c09a7a849353fc3132be1fde32f033e48fc436a3422200dc1180bd5caba8a0dbf4bcd6239e78b975f9b847280c3ad293e4a4 +Msg = 2512718e7c139acdcd324303db3adb70348d09b058baf0e91d52b24952f832b0a3b81fa9bc9a2e9fb276a64e9e0922778b4992d892f6845b4372a28e47d27b53443586d9015463cacb5b65c617f84e1168b15988737a7eda8187f1f4165fecbdd032ae04916cc4b6e18a87558d2ce6a5946c65a9446f66cda139a76506c60d56 +Mac = 85a83e94fd8b941124e7 + +Count = 250 +Klen = 80 +Tlen = 10 +Key = 0daf68d47caecbcb7373b693bbfa4b98a39d88ad3e7e1b99cb2478d2756928883d9364e534c1e294ed89ef8032dfbedef638006d8bf0b4fc15e9412e3f76c27a2c77a175b1c56754c1d0d2ac2886297d +Msg = b3fa42c51aabb708a64e4056402fc97bd8964820c09c4541523c99e2d9ad76feafefa7c1a2a519f79c229bc384c6e2945f8bd055bbdbf6e44da557c6d9af6e19522e73c94394db076da91ef7b1ddbca931dc824bb364099d465381a52705aca3e5dc2d47c42003225f0a515b921b60a397b2e66a6fde895384719fe68c563886 +Mac = 9d835f06dd733eeca888 + +Count = 251 +Klen = 80 +Tlen = 10 +Key = 01663b65d9d258268b1f8c770f713cbc857c1870d399e7ce901887d121d82f5f2116f8c107839c5702997d8a282ee901d04a9c183c36868e7cd5cf7d8e371990ca6c05707e96f87fd5421fc9fdf9b038 +Msg = 64971ce186ec2dbe037ca714f212f62fc863d080799e72dbe0442de3613a22c2cd1d4a1d85d5b946e36d23b4d5219fb1cbb9ab53d41670ad030b4846186e7ecb5c6e5500cd264bfc7b739e963203101b59afe7421a0b3961c43b66e06d08e6eedb334574a5086b47953721a251e0d1d33aed8d3495a4535de97c9098a730e296 +Mac = be05ae222904afc2c266 + +Count = 252 +Klen = 80 +Tlen = 10 +Key = ab6832846f39aa9be6dedcdce2f0d5ad7d331129b8b340d16212497e3c20909b5aac7590cc9a1d817e3674395dc87261bb699ef6f514d1fa53003d692f2dad6e5a3d0ed7bb862fc73965c5aadcd5b26e +Msg = 33d8e9e9c066e53f1b7d689f82f33fb1ccd9872aa7ad15a125d1159f773cf0f5f87074526dac2f148a621b5fb9eb816c187a1724c04f6bee4d2d85c59b0dc88dcd141aa794c345c3ae6e9cf5acefe10cf99b661f187573682da2e855bf1d23ddbcac2411bd13eff38c87328ae46528367724bd423589f3b8cc1984796bd4c98c +Mac = a5095b5f7a26ab55a37d + +Count = 253 +Klen = 80 +Tlen = 10 +Key = d14474fe023c284a27f7be751ced9ae210a4fe5ee681889bdbdefce06a5d44fe6d7bb58684689439ba16d9c0668f329e508d4b6215444d21cd83a523eafb06dd63deb11f13adf48f5c4bf0560f55a019 +Msg = 6af0473b68f389d5b6f20efc60dddc2f3551e62170b0d5699877077ba4ccd8d7635721801b53ffb071e5d6ca88ac95906d993b96b3019af65af05a46f6c142c70cebb3dfc01e75caad8fb78c1590502a3a634b190b50a3f703f54b794fde71a52f5504419e7b748b3598b92a4db0966564571f93c2c579d25b2de1fcf84befd7 +Mac = 51d76d949452cbf42262 + +Count = 254 +Klen = 80 +Tlen = 10 +Key = 1f9284000341a262e7b61f949523b7744277e99013d5a03be04413e137a8ea97a4f1a2f62f92322a2734ef461eacadda352b27c89ab5a1534ed5cb792c8ee983279431dad3bd741c27b2016f81eac716 +Msg = 8e7aae5ed6832b58cf200019101822d0d54c4278fea6f5685b4c112626195a7dd14d5ecf03839dacdde4eda2819b1d57d588d9d68439cd2746160e2262dbb584714ccd4364246f1fc84e2b7a4957aa697524920bc3e0aa1ad4393fbff8ccc6abf4ddc263034ce8db1ac481477036112e3e8636c0c384d2698c1d6ca6f2d3d418 +Mac = 7832413077e6bc1ee994 + +Count = 255 +Klen = 80 +Tlen = 12 +Key = 24d8938c1644cbb080c4505539e44c8a61567ca74443363b80dfaa466b4068a9af7022da37c1b3dc4f60616f062d5f84d7ca96f389f2a670540d27bc45013418e44a2aff134dad1439e9ec5aa05026a3 +Msg = c0b184c7b9e4cb8dd19af377306516c563b3b878baa250c1ee1605b90708b5527d213b8e9e87f2ef2ff7752e5614a930b8fefe35de27f153dd62d623363dd4bafb9131da3357cf6a80bdf724ff7a568e705e452b972d4ef2e1adebff4bfe9089802aec1441fd6de70a1702c1f33f24c8d4fa17c2ac5c6d87441fcdb60ff2f2a8 +Mac = 1d1d12f4ff4e0debb715b9cb + +Count = 256 +Klen = 80 +Tlen = 12 +Key = 4bdc4b8862956899373d3df4da7281c0ea2bdd57634059efb82d157a221339cb37ff2ef9be6f0f08c2125ac6e5d0ecf4f70a2ca6c72386ed393f1bb2994ab6e52f3d02d8149cfbe54443a357f363f688 +Msg = 28aab2e4a0e55c11d5503c4dcab584545c4923a61b313c2c5a44d61d8213d523ac2629ba6e8945d9f488d2d553b6a5821b34ef9b2b2fb464caab7f8df37f535aefa1e4012aa407543f7f689f55907bd4aee1b5e57da9fb72f8165ba4af49fa591ca34d817b3f8cc7dcbf6475764ced913ed8db4cb8a6f89e0d0dd22a5f79b067 +Mac = b3ebb567bef1fea5d4f954bb + +Count = 257 +Klen = 80 +Tlen = 12 +Key = 732957d1867047f2904817b4f559649059870d38b2bce77ea2e8b27205464ccbc6e02589f655f3d81fdaa736d57f9fd88fb41d4ab50bf857fa3f9128ec7609b0c9c3b14795efc29469794fb10edb778a +Msg = fbdbc0f366d4678654544804b8d6fd6f171668f2832e4623cdff0785f7d2de51e83f1476634fa1de3addfdf3bf4234627c31391e24df7ca9c967be8f4e6e243320028bcd21c81cb4e55720d921df1594600e01a4f83406713da53793f45faa980becce02878aff90bd8a58bfc5f6c98f2c76698ae9740d03927f199cd0ed960b +Mac = 243785864b714d4132b916a3 + +Count = 258 +Klen = 80 +Tlen = 12 +Key = 0541279805ec5e82ddea16897848b0dd584fe59f2dc1ff44a65f493b87aec4cffcfb1b4e2c9dd96b127adae188cdff59a526268e49b25aaff6bc4605e274f0d54aefa48808702d0968e64c6f38b562dc +Msg = 39b971d28692e9a0b5781c9d4090e839a7ea7021b5b4791004ad14e8c3dd7e01b78444c18050aa6d1ed24e3eb33309b88a231637591376cbc3a49245215f239282a64f48f0ea147ff61feae25f6da4063f2998fa3803ff1ff6819f39fcaca7c7a309da905fcaef7f454638b0caa783cbcee23e91d9eddeb4a42c81ecdb2cd147 +Mac = 3528e08689fac23da65b7024 + +Count = 259 +Klen = 80 +Tlen = 12 +Key = 68ed9fb90aa9c95ff1add2476ed9a8f9f894a3bfc514b70797daef0ad97b16abeaa6b7a2b96349d99299a31637d3b6db33437a8b6b0829cdf6acac352ef1522207cdc8e2a0b3461d18140670a326fa58 +Msg = 224e8d76f92822915a2fd36a510c398460090421d118ec654b17ebb9a452a96ef64a38a2f5b501687fc5fe2375ad2a33ca6236d4d99e7e42fc2b3b225a5efa1d00e24dce34b6c0de05790e6d27e695b4fe9b08e9f91e6463212125fff205b9c2699e35c05e36473c14d46b100fbe6250253ce12ad89f8610e3820f1a1350cea5 +Mac = 3f172df211dc9da262936060 + +Count = 260 +Klen = 80 +Tlen = 12 +Key = 772326bc0d10921a489a82e3651daf798b2e2a39f72fa1ad5620de0272b890bc11b54ea81a70d912fab4a13946d08b00a2ebf2e6e198ec386eabce86ea4af2531647b710f4adca4c2998a425a64a5402 +Msg = f5c05a093ad994096deba25858e5c50168cff2f361b0280651b00039c37a863d34e44738cbd2abc3445785342e1ee92356093e27831793e1638b373cc64b83f20a86fb53d69996420c345980f8b82a2dcee4e48b53b1a706da7a72717260f3935eed9de2c5f8fc8eabc845c1207c3226b7a90ca83a46097c9cc5d9612f837c26 +Mac = 46a5b300d160deae52b0dc0a + +Count = 261 +Klen = 80 +Tlen = 12 +Key = ab7b932494ccb9a4792cafbf75988ff49535f837903761f5b201ad521a8dffb5250fcf862ad53e366872a6803c1b76ef98513da1b0c1044af668e17b49fac9256985a659af51a951fb0ce2b4ed230e16 +Msg = 231b4a2a2e6a517a55f10aa8047cdf05941091df707f7eb077392096a265d703e730e8b65d65c5eaa03f8fcd777bd933b4b0af8c5ce3d613085656498ba236a2d505877e18fda45a2916b74828007f9c63e451e978f85d2cba523346d6fa86b0b7422f6aa65a7434b61f8b015f345aa9695481de0be69a6155d2bf75cb944d95 +Mac = d012486da17a6c96d6ec6a85 + +Count = 262 +Klen = 80 +Tlen = 12 +Key = 1f8509c8553d0d77593d261fc9fcff90bf77b24c4bd3de472144faeb8e2de85fb189cd09e7892152877e02a9d0faceca1f32f04065a7fa28d906f539ea4cf401782df07143b7cf9ca433c6bc7b4ce176 +Msg = ee59b47d837ce466a5c6361ac4f64365ce5007de53372d17e8fe8d16c9fcf409c2de23354f411a300281965025cbd863a17aa8a01ea09ade6ce29004218a80c184d7777daa97de8fdff8fdb0489cbdafc6ebb2671cad58ef55d89d1060a6a0fcfeebb93cdea6b9eb05d67322748f7bb3054c2d1a9787f1b06a87be22cc7add22 +Mac = f5eddca9a528054bc587c7a0 + +Count = 263 +Klen = 80 +Tlen = 12 +Key = 24b2d6332eba8fd719b4b37463b456e44b9140d9909adc287c85516821a8eebce36ccbed36feadbca9472b76241f0fc86dbdffd5f1725d86c2986b21dcc5b31eac44a636d3c583bc27537a30fa871212 +Msg = 1dc026b6adffd69b6005aba5e5d179ec42620f8c75cc04565b8ab4c6d21685351ab76f50829abbc940250a4da0889ab56195c5805bd1ca8166cbd0d578ac28180d10d3d8cc14444a67b0663cc348e14b597d9a56dc4978331b4b6ea02a5fb67cbc725a37d495f9879d4fc85c9538d717f1c396f63e5c97d344b3950f2f57b6c9 +Mac = 109f370cfa011ede8627fe4a + +Count = 264 +Klen = 80 +Tlen = 12 +Key = b712f94e606e293683b2968806ff6a1485504a3eebb8895c3feb9b60c100cdb7367534718074e3a171546107e1635becfee3954ee452263d6eefe5854b791f8d543a8b7f1c447fa9c9fb632423d367b3 +Msg = 8a7fdf734fe3e03017ce96e9a154d7e6a2a52578ba333b3aa713e697b9a6168c857835afde68b771010af3a010493130c251043a58acda45d3aad1c56407cce124c8c77905666768082ed506b1e8cdf1b9b7f20e024065cad00e95a6353559f2cd363cd8ac23179d9504e6246c78d4b4eea098faa03804520507db42147ae447 +Mac = 3072ddb57d76181c164e08b8 + +Count = 265 +Klen = 80 +Tlen = 12 +Key = e199ddb8612936d2e46b4e301a1e772b0312d5a903e713f9381754fe0b376d900579511fe576cc99ef2a758e8640de93fd900de4abe7304d3d068c4a50edb76d405907003a8b4aec994bb7d96f2d2597 +Msg = 0e0e09152ca3b8f9e77d4f0781a0500ba7d8e5d202fd188e0976467b19fcd1c3c7a016a075109fc0231699ed886188ed618839a70a4cf8884b1e042574e14022acf02b528663121fd58e852dc2cb073a1b7a0949ee451aff57a9584d96b12a4f6405317488247be0a5eefa0e566535ba7cb43efed771e4bbd41f293aa6f7f713 +Mac = 5b3a0278b3e71a3a93951b84 + +Count = 266 +Klen = 80 +Tlen = 12 +Key = 483d3190b2bfaf492e9688e61db2b9ff0b7dd864d76b555314d201eeb0fdccebd37cd38e0abd9ad4a5e195f25ec8eefd3b6e82ebb57b2dba191547ef2ff96e421aca86987fa8ff31e90556236cb4df07 +Msg = 35a2b369b9e1d7999354b2a6d3a2e301355f3d833ed2775588fc250d5bd5e7197cd9e1614ac36b280699093373e89d2e9f51db4b0044fe2cc20cb903600c71f87248a9cbc627bebab177d4a5a7b110700a7e08a9407b776a083936810e8967cfbdf6f3ee549238173cf6fb429984a48e1fefaae426fe4cd7018c82cf8cd43367 +Mac = 994e9838eaa0bb1d6515c12a + +Count = 267 +Klen = 80 +Tlen = 12 +Key = 2aa3cc87deb165b2c4114d1e5038b882732338786de33223e3588f16313db3710164b34d1d43c25b81b0edc7b5e9096359d7e9010194d420442a35cc109e95bf402dc7cc71d5627e111775fcb8fc752f +Msg = 189aed1c0cf7700829333e5751bfd718a4450879e8836a3a2e5a2d61b222132e0441bf5165fc305b748d89730a75134a621384517d768229c470635af0eb374927800864674660a028e80c253dfb2047fc8e3bb99e020cfde91c151f0c58afa3ca804fbcda7e07bf8e6f50d6b4f806f9baddb41a15cf12a0e286cc17ce108526 +Mac = 5a745e9ceda09b0332cb4cfe + +Count = 268 +Klen = 80 +Tlen = 12 +Key = 4de1ed235e4247d73df86fc57e56360f0ca78c6c137d8e1d1d46c0237b2096afe6ef3ada66ac899673005ee45a111448e39c467a3144d95fe9293d3797bdef184dd3439b8df960d568088c89e8f9aa9b +Msg = f08dac1d4d6a7ac4672b447a46cbeb3162f247ea09c6b4290004cda66d4f7746f4c8224921de4bc50668455325f13a0890526da74e87c11401bb7f0cc6a554145d1799af8ad4d7d4baa38b9feaa12647c5db58500c1c8e023b04ba196a5a52be71a39bb64ff427dacd049cc75e85b8d64ab5924f0b3023d9f70804352017792c +Mac = 7f25062caa0a514034f793a6 + +Count = 269 +Klen = 80 +Tlen = 12 +Key = e48825a5503a6afe0bf9a240c67f27acd4a8f6993834645e03c80c72dd370cd2e10071a3ae18ef19bae9d697ea9a4118609190cd95361907a7fa1b58f499f3f5e79b935f12212f437dde399e3e649024 +Msg = 8c84810e4c90bf6e1e88c8b944398b35c422d48c6a7070680c2d913f11b474713468409086a532feb2f7f7be858a5984aee21e0ec2cc2db78395f34a61790514415e073d7ec3cc582df3be38a67e810540e9d3905ba5b7e4a43ed21e94d5157e3ad09cbd3bd0d6a117e3e7d0adfc4ae202a0bbb93ee15415f790f663b2afead6 +Mac = cf0b256cb91aeb1bf3877d4c + +Count = 270 +Klen = 80 +Tlen = 16 +Key = b5438e3845f39afe7deb0fcfb86e2dbe4fbc489f55f01c0f842961b576e89fc719b944cf5d16f4af2f8820e2ab0fda068dc4e797e9bd16fe1d31d1ca03dcf23d6ba5d80ac87fb95d298d391c6b893c6c +Msg = 8ecdcd8176d8a164f6259733bc77ef783b48d40cffc547353d195912afee9d399e31dd9e41160cb7455d7cddadd351f6dc1b3651f0ae4ed152216d4e8ba789385ad66b7d03aeaaade9d7da5d5f2a01c9bc734abdad75feb5d02faf437e5eb7b1e843e1e765a665900a1b1a797c84e73902d77a17de223d28decc86b82e1d0feb +Mac = a95cf7bb2f67983469d4fc489e3192d3 + +Count = 271 +Klen = 80 +Tlen = 16 +Key = 95f2c1509dff6d162edd5de32ded423866dfda682bc7b7503e734142f2fcfe428c9c1175efbf01d6795dbc2b2886dc38013f2832b28c5e7676ce307b394f8c05fd1c209c7c131e3d0e3c3c4fce5d00d8 +Msg = 1c4396f7b7f9228e832a13692002ba2aff439dcb7fddbfd456c022d133ee8903a2d482562fdaa493ce3916d77a0c51441dab26f6b0340238a36a71f87fc3e179cabca9482b704971ce69f3f20ab64b70413d6c2908532b2a888a9fc224cae1365da410b6f2e298904b63b4a41726321835a4774dd063c211cfc8b5166c2d11a2 +Mac = 0a060735b4799eeb204c5203e617a776 + +Count = 272 +Klen = 80 +Tlen = 16 +Key = 9da0c114682f82c1d1e9b54430580b9c569489ca16b92ee10498d55d7cad5db5e652063439311e04beffde8c17688ffc7f45f0255315dc8fd2ab28c52124cbf4911c41b4252231264f684d3ffbbf7963 +Msg = 7c287ca52d40f53f92b00432984595cd20e644494ac7c3a4f3e07cad7c9e785bcdd880629a048208e5ab3635c51a00ca655b19344f63ea41eb8db83242478611080b3745da92f463c444cd4706f2a36418c74558eb7cd9c372cc7e5a61282f3735abea73745012f73663138fe4354441401411dca57a59d39085154c60a73b75 +Mac = d2f6e9f1ea2cbb0519df68fde357979c + +Count = 273 +Klen = 80 +Tlen = 16 +Key = acc3e67746033c73958992fd94f457d6d12c29367050f66372f06181387d67ac42fd42443d038d883ddfaa67471261921205c9d60efa6ca9a642a603c2b04e6f914f986185503aca9f46ceeaec967865 +Msg = dd3e68b757ffe06068e52005889bfbc1b43bf0a11164f35cd38d713e5d998e66a9abb131eb3b42f6716ab2f4ce92bc883722eba42da95d7c5d30c682c4cdb795167521756112157bedd5cd8768cef0393fba12644f1c7abfbd8f29de225a1861ec45c06c01abdf57a5d17aa69d761e3b94ab6ccabfe5d58ebd51a13ac1673633 +Mac = 104ac1da3bc023eb3a94c45f7c42be51 + +Count = 274 +Klen = 80 +Tlen = 16 +Key = 545514c74c932e3ed856e93d878ad42cedf8e04434bd09a1d4fa38989ece684aff8108798302a19b9894b92d95c4f74afa9e887cf920c0d236ef0533cc49e9f1903b96a199146f2b0019f41de47ae645 +Msg = 0a20bb48b5a3e4f47b2fe7312c223cec1271936281eb0a88afc2a2aac647f45238f5206b53b107a61550ba1d415a3137b20d41cbf0a5c88801db2b9482ac0273f65b112b5db97ba509a43257adceb220b7c0ef73df1e8bb8002c4def2791cf97ea5b76cefc44a7b9fe33382697062570c68f85a377dcbce155bcf105e07ec385 +Mac = f72b19e31efa84db9775dcdab258b91a + +Count = 275 +Klen = 80 +Tlen = 16 +Key = e79461f00c4c05e2e01808de1926f41aa8f45ea5ebb5baf124f674902a813c3b5e81a118e1e8e13d040eff70009a1730e8a6effadb1ecec57e6991cfa94cfb9b610b4d3a07d116cbce514d3e73ae9d5d +Msg = 166cdbea93469428e66efe853b6c4df9fb13db05f4126deab4c5b81a355124ecc0efcf930b88d551a583cfe893db99523c7459b182afbc89323c832d9e2f3f77885658bc42ca54ff14c55665deb3e5e9fe8cef5174600e614434094e1c0c9e7637497f4d81359a9bfcdd9de5621fba280c03a8ce124feadab4555366f910ca4f +Mac = 04d599b40b7623ca25c8ea694aec3afd + +Count = 276 +Klen = 80 +Tlen = 16 +Key = 48eff7d489f9b25c0c65cb3a37d4efba3a84f79be7cf62b5c3f403e05d1af712de92dac7e25d3aa686ee4c61c230deddfacb8d93cfa438363ba2b595ddb8c2c491203e7644e499ae07a389976192feaf +Msg = c2412a6d1d52d12c0a54b8f5701ea58adaa11a767ad57a9e6ff46c1943e78441b8fd210ac4e39193dad17cfb6b017f76ad6517a09b99c1113d175f3129aade4d4a2516ebe054f15bc833d08ffe5e2a2d60c976e1b4b14cf8edd2c72baadb2db8001fd2b8798d39ac5ce27d592f1defd67b3301e3cf05637c078f6baece62baaa +Mac = 7bf44b98d95c3a57d83f8e8bf82a1cb3 + +Count = 277 +Klen = 80 +Tlen = 16 +Key = 6ad25e9dabd163d092e124fa0ad1867fbb3e020389074a7c5e01308c2aecc40f28a6bdf0629f1b40778d0a899c61085fe1794a39b6175c7fad1209e481cb7af65863a2f3452bd9df115cc6d33b098398 +Msg = 77517dbfda50493a04445d72430ea3f6fd54bb31fc81f2920a0d72eabefeb61595af41dc44d0901a4dae4d1ed1b4c551a5329c18a85ebffc53999b0991f38d73d1f099805a8d5ea1df7e49e254ba0a85003944ead2fc89b3f84f8525ae4b79d0549eec72c48f9d19e23cbb88752658dc35f01c6f246436fd22b79805bc0e6472 +Mac = 69211fd5573b030e379f7661ae6e6d57 + +Count = 278 +Klen = 80 +Tlen = 16 +Key = 58812ce4018d2cb65571271492fef87c06d703d4d52819b8f7959c138071e3ec2431df83fa20ff9d8054521ce0e0ecd2714b8a97814179995289b3f462374c83ef230cf5bb995e230d5268a0f8a37c92 +Msg = e88b88545af54f3559594239f0e4f0854770d576d3f02c2aca0f0543da1497e71a09d70b411c4af2164517f027296074be3fd24611317b0cb985dc13657c404cd03a4c95f028d63a7197fbbc61a66bd12d6508abcc3ab07d3a84563c287f58a3f2680c79d1e19c16529615240621baa37b2b9e2f6cd4728635559b4589e488f2 +Mac = 85c9afe1502539c3140777de9b5afe35 + +Count = 279 +Klen = 80 +Tlen = 16 +Key = 20c0db0aab2f9be21d2bf0421a16c6390a0bdd57c9c11cb4a0b22933757c36083e871e78bce8b0e065854af9a27aab5a3abc023f0efc4a8808cfda054e0b38f0bb742fbb8f98210d65f79e07666734cb +Msg = 02140f7b50f2600961ced8b36dd48b8e3f70c2108c55ef2d83c4e6c0a50b492dd74c4444b57f7b692aba41f23db00bd12e792473c291a2e8db2298434b868d44ea072d34e7ea3f115badd7eb248ccd8ef04a6d61982d708eb04b2c635c0407f964d031138b3b93481d2d0265c86fb90dac6b06a2b533436929c508e87d8e9f93 +Mac = 66aacb93fac3b3ab7f9a61ea907f863b + +Count = 280 +Klen = 80 +Tlen = 16 +Key = 282d222b848ce96372409931abe8e1db709914b2d6dd213d62fbc593d579ff0949e0c50d7dbff5526ef28e2e27242040d99381552e13c28cdb5661b9756ac0088583d6e3defb25152e97ec2fd40c9d2a +Msg = 7b7ba2a854840b24fd75ae12ebc2c6144bb2065c95abd31164b0b0f58528fa464ee1d5e2315466ae912b4337d300279ab968eba2eb30b131d7e663e1bb9b5cea00e86447ca2fe214cd234d3b628be44fda439fb81283651147637fce2c9f4d223a983720489ce7205b67b564bfea63fb574b0be6312c557a5d30ed0500bb35b4 +Mac = 5e671f68bee18089e4fb7fb8ce85e66d + +Count = 281 +Klen = 80 +Tlen = 16 +Key = 82a19090190ef59e77a26cde0e1799ec5b0a796bc64e5af8ca862b5d55f3f607728aabbb254a1f8496cc54f0721cfb7b8fc7374ccf35a41f463998839fe7a945bba66f2c9c868be682d3e74353ea40a1 +Msg = c1e969ae81507ce3dd94ef0a21da24935129daceca79f3a4270d7a856203e4a13b2a965bde13a8fac06be9a2ca872384b941a051c503ecf48021dd80026cd167430437eec86d51dd82e5377bf3f520b99247ddae71b7a6431dac1930c5a980279f1f534e8886fef3ebabe37ce34ca39ca4e299cd17bea8fac457377bf5e37947 +Mac = b1fbf176cb48f5a90db4af7a555a0c65 + +Count = 282 +Klen = 80 +Tlen = 16 +Key = 76280c24849f0c384d6e5b512a9fb1dd2131da0307b2ffdce71027e0a8acfd9ee9b0d4b130a3e8ef443ae7e3d771b07e68db5a096836785e9c439b58c2d5198877270d2958729f5668bf867bb2facb0a +Msg = 09caedbd5568cc3ad0590b7d409fbc26547a2a20d9d0b22630d2d58500dd8b23289ed9c0f87aa57ca02dca99e8b1688322617d0d5d5ebafedc328fccc7b389a71f2addb9f7b545ade2ea0a6ea8bd62313da4fdb5f3f9dbc9ee9f6010d8e8aa01d7b62231bce151d57ed9f682e68d55388b8bd19f0168bd904e6270d79d449738 +Mac = d65dfc5a7d8477da3f29a4ea7809f265 + +Count = 283 +Klen = 80 +Tlen = 16 +Key = 72ce9cfd27b714419bde4dcd9b377dc840bdc3adaf5a734c0307af128834378b2a6a81252d2f0d371e2af3410987be76ec9d7c776cce1662c7afde0b0a696789846099f57a12046e1c417560b854c706 +Msg = 08df48713db1b8ab2b51e05cde25dc3dfbce1b12045bc181d8bc492479796fdd12a44d6a390cc43971b31d7df382f081ae3c453c8cb1fa27f734654b9c4e399e6eb4ae8fee77dce0aa7b68b4042a63e935696fa792cb24390d05b21cfea3c75624f9b309e65bca48df9109299a85fd1c9a3fe17b9e130762231979c029dedfae +Mac = cb314cbfe1f935b03adb10e5a8b88c96 + +Count = 284 +Klen = 80 +Tlen = 16 +Key = 34991e9f5b19fc2b847a87be72ff49c99ecf19d837ee3e23686cd760d9dd7adc78091bca79e42fdb9bc0120faec1a6ca52913e2a0156ba9850e1f39d712859f7fdf7daedf0e206dff67e7121e5d1590a +Msg = a204be1fc04372eed3c9e5ccd1435a02b357317e78960b6e6cac2f0eaada2dbee0a7c15852d2f9c0228a9abdcee1c107fa7fc6a170936568651020edfe15df8012acda8d32b8b82ce629f8f33a72910e793dd592395d9b0f97049d65c4361fd8c17dd26666dff757a90dc7171ddd1341b9fa28fcdbdaf58a8cf1701e062535ee +Mac = 548cba2de5c3944be4d48ec1a2a34d9e + +Count = 285 +Klen = 80 +Tlen = 20 +Key = 4ddd00d0ab6aab2100ce9754c3b3987c06f7e58656011d26e3518711e15b9e6d2d96cd8534d077c211c43ad7f5ee753bcc9e07dc1d4c5a12322ba1d17a005d242b3526d62b29a87231cbec6f2867d9a4 +Msg = 28be0d9e62dc89e2a913064c0d3dbfb35a0c7766f756741b0eafcc28ed3ddff6adc825b211112a45b065d6875771f2afa958e80f0803cafeb9b9961542efb99e1761d1497661b721906fbdbfe90b34bd01c7326e34a092ccdf8e3bb2c45aa64cb0b09acb5b753a5d8f5a425c8cb28ec5ac81dced43d5d26fc95943693b27aee8 +Mac = 393238d3afdb7d970b966d374fe097ec8797a870 + +Count = 286 +Klen = 80 +Tlen = 20 +Key = 7a31553b05e96a8da0a4d5b81a857d192afb6aabb1f127d740456a8eda7cf696fbb4c121d8d952a4e91c6ee6a5a1f3588d7804a46bcf6688dc662ae50c438d13c1a61c789b3f1c599a9f28efe0ed1cbe +Msg = fb091ddd95b100dfcf892d78e5e770d3a37b8c3885df803c1d6f0935b55b68f136fb65a84862942ebb35d76d26be2413cd3c8988c87d6d2362af189dc07476c6c33417762eb77bc70cf38d814c226dd6af187250e4d47007f1553617d4af5b516a5d3b3191d93c10896a569ba13dd2840fb851781f0b115090086c8b3a34a1fc +Mac = 0fdd3f836dd7e5c506ab21adde9ae5dc09cb359d + +Count = 287 +Klen = 80 +Tlen = 20 +Key = 6445f6d884fbd57a1eec0716f893aa9f4728aaa07d2038da62f3782e66217abe35776c508d8e0ef34c9666e4ce51b4b27562a8a189c8d34c43a65c8f2445f4a48b5b0b8c878e44b1ea3427c99f5d17fd +Msg = 9f63b0edfaf83bafce6c4e680bc075c7b3baf15733e5aea7f3d975a82cbc6356fa099a9ab290366f75bf8345051f6da2d821370f6b1b7032d98e2338acaa4f76f314964f95e63958e4f844ba755e06d83031c432a393af899bed1245f67bd013b30b0ed24b012db0449ffb9003832ab0e2710188825351f5637eab96b137d076 +Mac = 090cedb3f2833a3f260b0937baae56267a6cd935 + +Count = 288 +Klen = 80 +Tlen = 20 +Key = 2967fa4c626d18a77aee781aa5200c227ffe703ca0901e4a706ce1393c7d8ce18a03eb2caadbfa7b8e015545dc53f0014097084707c05932ea6d920827b3061dd71ca4f47bef29a8d8b2948a05eeda0c +Msg = b02dcae915a6a6be9d3c9bf3fc61a99ec3f181b4e3b0321f6cf304119b9da497144d82716cd67821eaf0ac428f2db71b532e0774b21681a8673f6bfc782c8a2f72bf8753f6ac98db742e5cf437f90619a26fbde1b916431ce34ad51fed2f535c53eaa136bb114d13c35f72b2fcaddcbf361d6ca4ff99bea3667c0a21058e4845 +Mac = ccbecd82cf4b29b535a9d57137b853076de78ddd + +Count = 289 +Klen = 80 +Tlen = 20 +Key = 58fcc3895930c2fcf0d7c934a4ec3625633509e3c776466f98e49bd091dc436667d52a7c0794521c1f9f7527e1f3eca504f9cf590bb75e98c9439f5c257e49951bfee1bf034c23b91650a3d52e09b42c +Msg = ee880b8150bc9b86607012a9a3e737e2407598d659897ffc9beb22fe14411a6245d8166979a1d137557a4135afaf12b4a4c152d3e4666ea251d05d87c9321be13f8159ec117873e595dea26ef50b73333ea977ceb3b83ce867d47da10bbb9632040a3ad1c14768d64b249b1b1d0242a837b56f906e87d316067fea1482e3739e +Mac = d8013127f8491c97f1d5d275cabeb1ba3b71a2a4 + +Count = 290 +Klen = 80 +Tlen = 20 +Key = f6fb322a18bac34c75998040511cf04877344e7d2b6324135f201cde2a7d121575076d57f8eeb0eb65664c4ce24cb9e5bd0dc4195bc42b8672a2678b7893c9075c1ec864738d9ad5b54f01db299a680e +Msg = c280f5b782a0ba40a15699d680129b7207aa89c8ea94511c2b59aa57e146fb5a37657992b7ac90ccc973854b762c5918724ef09a5a9273663a62f258528e4ee31a4256a58335303f8022fb63c57cb22fce5e53b924c141ebdcf1e79160429fb072fed2196da3603fce4b4246f46c6e5c24c1fa4cd088855019eed32792c8b768 +Mac = 75cb23746c04f583b8ac78998537d98022ef2440 + +Count = 291 +Klen = 80 +Tlen = 20 +Key = e03e23e502700421f0018449c0fc9164ea488c1d00849fc69936519e8f25574f6a03adbb1b4fe6f8ee7ac199ba49fc305a7a6d1161aa4e580a76d92d6ee11546faf5efae1fae8cc54b13de8919a67513 +Msg = b949df3b02871bea0976873a9c76942ac934ce63ac2956d2856492970d8a231e0b1b178b22f6605ced2085494ec1986f026f68ae79aff750e5b92feb927cd08875e2ad04075518b754829b544e5de910686513076029ffdb5c0b179e39443ef22028086e5aab2a4465252f2147526d55229d3834099e55bc12e1b178ace953a3 +Mac = d78807f2a69d8e348cbd2c2d745f342397e20a41 + +Count = 292 +Klen = 80 +Tlen = 20 +Key = 9e8c665ba53854f0fd27ec45eccfd03d58d1360a3a94f5f24f2ddf52118352e3e5b00a3c96aa39980222dada13ac42cef121f8b27641c6f5e39d103ed1b565b06a5d546dd8658158fe78f8206645c07a +Msg = d1d94bc59465657e9cf4020239e6164e00c707f8c4764d70c2873b871ce51c2d89bc827f4a96db0160c44527fcffa41b374ff1ba032cd5df61e376e5d53c9167175ac94a0ce23efef4606200e5e608a478f6be11c2a15d8d86f1defba8856fa1e57bc62fc293b6fdc2900095dce26b712c831706e91f0e0197771cd07e07e164 +Mac = 9602a3a1fd2dc3c55df5815ac0517001f8c6593b + +Count = 293 +Klen = 80 +Tlen = 20 +Key = 05b0363fc500dccbe78ca18ac7d3521d539dee9e10e9c4325e27d5ddfca77f9bce525dacde98692fa2a963f27de87789879c1a9d91e935876400851d4a9241ccd08afee8c9fbd13f9657b3f4a5e3298b +Msg = a60c0e1ca329b27be58968171049a625d76154731e341b9e6066df854fee8afdbb6c0cc7b5bca0bff4cb505578a9bb416ce0167351057149598c3b0511e0097e43b493161b93ffeb88bf6352e5388581d91be58b7c2dfd92bbb8c737fd968056078bacf11cd85a69690ca9f4a11e8b4be5b9c9a3e6d747df4d918a045b3577ed +Mac = b95df20e4e63936b74af4ceb7ad94d4e4b56ea8d + +Count = 294 +Klen = 80 +Tlen = 20 +Key = 5efb39ea8bbf4bdc7bd985dabab07db427bca4a85550c8d832b7ddfbe683fc52fe22acddcab261d003164241b14a2f234cf30377223b16c1f8db07b9f479b844bb3599a2d67f2ae95a2bbbb2c8c77612 +Msg = 4996ec69eb2522599ccb47ed1dd6bb0f79b585be8b68f419c03585b91f9d0844868eff3f36da472491e8fab523aa938fe0ce5302ac39e42021b13d148cd9c5b63863bb5cf081d5f2bf9c274dfa4947bc8079afe041ef62befdf8d3134e5602e7e97de865210215eaad50985caa9d1fbde41c5f005174b61bde720f5d6efa0702 +Mac = 5f009c918e2f8d7c9f9087b78af44f54518e1c5a + +Count = 295 +Klen = 80 +Tlen = 20 +Key = 3724e4bed1e72985fd1f879394543ac9448cfb8b3363c771e55ee13f607d1a188e0f50eee2ca353d3e1b51f915bb4bc5cd83646567814476614bf95cdb933d7dfafcf7ad8a2c05e8e72339471dcba12d +Msg = 01069a2a048aac5791e0e922efcd5292d7af1e19c0b3156d60483a936fd4ac3caea5ce55282aa6dab76383ebcb96e321674493226c5b18731aad4e8ed4a14f3523289605fef3654e49e463229bc28aac443040c38fe0c4bf4404cc8c71056dfd6a783a620f4eb05c4d4ad2f0e8b910db775d6d25b0aae1f9e535fcb4cf69cd3c +Mac = f92f9c4b8d423b14ac7ad924f183a1cc27de6afd + +Count = 296 +Klen = 80 +Tlen = 20 +Key = 4718ad423439cc9d3b1f691718e34a30df9b3c4dee7ea9011f496d8a42e1e69fca394a69c6763ecf1351a4f6d0bdb40813ca4e35daca8ef845b2a29c02c3d8fe0869fb948863e0ae20243cfc5379b851 +Msg = 6ef99052e93de72a0928886350c3a86b3e1b75c81beffc65f0ad4a29d79dd1ce745b0ef1c48a696515c75dcd56dcd86a9136e531b69a88219a13e9d33f2fb553566ac22e02ebf2ccdf6e59004382a2dec4f4aecdfa8b7fdd86f5555a520216a11b10f3322dc749076e06c5249e1ccc70dd3c1ac36e2ba940ba3cd4e5987ebc60 +Mac = f476bd42bae22e645cedf601511b1ab8f2852b2c + +Count = 297 +Klen = 80 +Tlen = 20 +Key = 7fc4aa492a3d12da5d2de0cf9a61c0fbf9e4a2571920554a5c45582754efedf878036e7a1cd9e468a0a1d6fce7ff5fb40af983524e13c32654b8ef8f90dc3cc0fce097c00eb638b4e7457961cd0fe9ed +Msg = e36b3b02b86b02996c1cc21fcb70b5b30327afada1f0afdebcd1b41970c8d2f18fb384c5926d44fad63a59880565f1b8d1276f2ce9cb061f251087ee04cf77d759dd650141337abd584c520c2dcf0a61f36e9ba8790e66865c2810e37b6f8fa6abb385bfac05cd6b5c1c54b32bf72b36cfc4da293901f69cc7e1f6ffbbf142e4 +Mac = 48d48ceb4c1f3e6b1e9c0fb8515f1121b846c19b + +Count = 298 +Klen = 80 +Tlen = 20 +Key = b6ec7ce6448428c34fc6819d50507a2d74ae4175fd2ac53ee5e576c5c5274bb2f6f40a49f6e0c4e40d249ea130f0d858250307d0e87aa5324ee5ccbde8a03fbc2a61aab5cc0d2be471d010e7876ce3bb +Msg = dde1c090446d11f936517eac73d6776695c1ff3051850e32fab734cc46c280e355dca079ef3949810e7edaf19c783c187d0e0c32d074fc3a72a276ffc405837aaf74ec5fe5659ff26961531c51b56fbecb6b28455e78ea7f7237faad131659d9f290eb69ac5bd8f54fe233561bf5daff85bf9d9182f9a2a9015e07fcb95fcaa7 +Mac = 9e51be58cf2d5c8e85556b8f3d484109fb49553a + +Count = 299 +Klen = 80 +Tlen = 20 +Key = ceb9aedf8d6efcf0ae52bea0fa99a9e26ae81bacea0cff4d5eecf201e3bca3c3577480621b818fd717ba99d6ff958ea3d59b2527b019c343bb199e648090225867d994607962f5866aa62930d75b58f6 +Msg = 99958aa459604657c7bf6e4cdfcc8785f0abf06ffe636b5b64ecd931bd8a456305592421fc28dbcccb8a82acea2be8e54161d7a78e0399a6067ebaca3f2510274dc9f92f2c8ae4265eec13d7d42e9f8612d7bc258f913ecb5a3a5c610339b49fb90e9037b02d684fc60da835657cb24eab352750c8b463b1a8494660d36c3ab2 +Mac = 4ac41ab89f625c60125ed65ffa958c6b490ea670 + +[L=28] + +Count = 0 +Klen = 50 +Tlen = 14 +Key = 3714707839daf79122c782416351385e88a81d31c9f641d8dce538e90e63c95892a2ea9b1962ed0ba372f48e9474aa730ae2 +Msg = 411843a21387846f3b9ed5fc545acadfa5b70386f62da4d9a27b041beea3aa1199367567b4d11a4fb4e8d46bc6c256ed62c505fd23f4645bd6b6cf45d1d96d9b86d6604157573ec5acf6c5414348ca83c81a736ca6faa6961cfac13993b08c502f816cf7a420d9184b51114675f30ee9ff3db69c264853d39dcd42c1dd31ef79 +Mac = 33f17ac8a5c6b525db8b8644b6ab + +Count = 1 +Klen = 50 +Tlen = 14 +Key = ce4c926c0922ba36269a20d60dcf08d43a1cea120f266af76f1c8acd883d1f68f09b8209f41f87822dceb39a544aa9b2569c +Msg = 410ac8703f312fe426f0d1a62d362d4478252f11dfc70b78f0fc6c9137b7cef2bd6a28c8cebfcf26ff89979c70fa3b0c4f16ffb99d6793a135f33b0d0a6b2d66b0a53a4a1e4cb1dfb2d7816775b79d15a1d5a51f603bc215d711d27163ccc56f22a2461fb6419eb845c0d62fc4d61c08764a696dafaa607dde4078e6ca425db6 +Mac = 900842bb916fb0dff7abe37ed8f6 + +Count = 2 +Klen = 50 +Tlen = 14 +Key = 543a1e5dc93844c8362eec72943e7fae3e66d48b5554ae4c637c86183e678bf3304ee8ed54e74599437f90c1f049fd58d1f6 +Msg = a5e1aa463703f68b32fe85a0ee169892da4e39117089cebd68f0efa12c9375fd8d53d349b4ffaa765bbd97773dac5000cac7ef8e200d8da737df13635ba94d2be0c440c1119bbe80690d37e60613d24f5aa3bc0324d4c0739e4219c0f8b4847d06fc99b6361f5a31c4b60df331944706f1a94a7a642690aa07e2a8c1ecfd417c +Mac = 7333e365fcc3ab2e5110144e62ab + +Count = 3 +Klen = 50 +Tlen = 14 +Key = dc57afb918742728863dd8363ac39d220cd225ab48d1491ba7ea9c847e6b444a366c09e1fcb3acd8b9d47a17459c2065d8b0 +Msg = f791be39f3b74208b327202b5756827084246045fb19ac1f71eecd1c9b4f4fe788dfd9dc337d5f6c59c698c388dab3a9796346a69fd4876a00efbe6b448afad00b92038e845091d13cebbb9d332fb2b5358cafbc67622a9a217c4d21fbdaa8f12bb326980eba40fe04a1700181dbe95c61a785cd7c4aff777b9b6285eac5c110 +Mac = 03d7967659bc07f287f2e47d8e30 + +Count = 4 +Klen = 50 +Tlen = 14 +Key = 06e7210def086f58b210a7010668e0d25c52a4421c1f4f4832a3b871c9e61331561c1676d9d75b83607c06fcccf3a73dd7a3 +Msg = ce7be970d6627256e245fc65ecc0fc50ab417b0b1578bcdc23081fb5d48345c17495753d1e7f3e8980c75e7fde2ee30359e390db72f682c2ca0f14b72b60ff9bccd8c6fbd19a512b12add7941df5024e7e624ef23e67b3a9a9ae8389540a95225fada353f89bf163205e2f4cb2fba15aa1267df581b295bb494b35d357674f7d +Mac = c5004135b9bb6d8364305503f703 + +Count = 5 +Klen = 50 +Tlen = 14 +Key = c220547bac570e70a718f581606fb2475ade8f72d7af7ebafb895d192f427837c4f45026d8539b4f7e3d8bac199353380948 +Msg = 781c463af91dfa350251b15aedbb2bfd106c0ebce30c2ab260b601edb0098721037b269dc0f1057fde8d8a2491c71ee32ac030fb38d27cc9f46c8d3fdc1d80919dee0c3136f5bffe5b278ab9176e80b8b6fcdbdee2de40ca0cd4444f0e602e240e1dfedda552af1a40c7baffc7d7dbe47dc7174d2856fe1c71952e058df91843 +Mac = ef69cf16a9809b0175d98af7ccd6 + +Count = 6 +Klen = 50 +Tlen = 14 +Key = 188e6c04d6053a4456fa301ddc7abb965c749fb7d5bdeaa5e157260e89f3d3c75db415b4c536a9e992cf1d0ed815410800a0 +Msg = 1944dac431dabd6e8144ba06429f093e72c99f81e023e9d68395c0060fd39a01cadffd7e9cd03ae266d15763956c4d6df7097444cdb13bec21181c465adbcf7b0d06be9d16d9ba8ce8ccec1721d00e6462d8db925d98c39c2f8ce481f13d36a289c0056bc67fa535ad3c616b0d52b4ec5a3ebcb1b75febb055fa0000fc81353d +Mac = b210e966616558e005ee616bf4fa + +Count = 7 +Klen = 50 +Tlen = 14 +Key = 7d8ebe7625883eed19dee539b5cb17fe9ac18ae55c4fa0a07b48f42895223249d99c2d61bfa32b65f67783249e0a6bd0b8a9 +Msg = d8ae0dbef561157c710616ea139d1daf75a5c0d9fc3cb2220d8794717e540da44bfe1c8d8b91ad3aa22f6b7ab7b3d69c6993957abd0b0db75b783244fb029d291a7de082f19116c7a719be51c6cac91aec15f1c5c34e4dde320d2262d5d5fd82abf3fea40fa977abea8cb678262b1eb066f17dc0f44d991ffa0f0cd3f6165237 +Mac = 4c55c164cf85019bb8639dbc4f05 + +Count = 8 +Klen = 50 +Tlen = 14 +Key = 7a1179690bff07f9f8a8fe7f62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd07086d5e89de1 +Msg = 4ca422ce459adc04b35fa4a6215e099633c1587d4289627846de7f0ef9a3d366394ed0b6aef7fcffaeaef5f85d12b24719200bf715487c2743c626ff782f16e9cb4acafd3e22f1bca0597302b1bfb13688230ec4326aaecd9cde7e1db2c8745dc94018893a4443a5500826ac658d8fca477568cae11680d217cd8f4ef194742a +Mac = 3962ed25ae676be974aedfdcf9f9 + +Count = 9 +Klen = 50 +Tlen = 14 +Key = b20315814413cddce84df335c154697174489fd08d9b15681e201bd2a865dc233f439a1deab33ba749e3057b7a8aa61f3c78 +Msg = 8c354859fd7704e07622012c055ddc38499756912a6ea75ec7d0159db060c4af561bd017c03b997f7f5b5efbe3dd0e926f895afb8b760fa4792ea3f98a0d0de292eada8d99fa7e6fd3f0e885d36959e0fb88756037dd9bc0eb8c72d229abc40c28eb9044f17b5ab85c29c6513bcb6529d5ddcf4a966bf2b90432a9b3f5029136 +Mac = 6db64a98037ba9bf581f29d151c4 + +Count = 10 +Klen = 50 +Tlen = 14 +Key = 2bf8a0edec2ddce639dc48783ed6809ea07d6f6baf281d93e3c9c72d86cd35b7ae43485b6e41d3704d83ab44f756021933b4 +Msg = ab6e120c5ed984e0a6f3a284005474724e6490757d70e16065fea7fff05ebf4e7f8225e98910b7c485b43b1c0bbba4ad36de91264c5b17daa14bc0b8b82fd37dacccd628ce3952ae9036d6f0a2bf3eea5ae1352d59cdf98f6c2b5f21b0b01661faf32fb1757cdd088d1e7ae80c88cb9083168572eced10e78d468a22200a0f62 +Mac = 8634481efbd4a9ba5763ac7f2048 + +Count = 11 +Klen = 50 +Tlen = 14 +Key = fb899aea64e30f436fc4a805bd58b1e095db431287b00c224fad52d1fcba364e519a36a96b08f68aa4064023b872496326da +Msg = f5cce107d368ac05ffafb9771b49606acae0ee0370d691cf3a3774545fec2aeca53250d3264b6e7e54731f2e3b1672c606408fd9c5559e086d02e48b20732f0dafc775bd5ec1b8a2e7c02c2ec1f19c17a1c30a62429b96c162caa11e0dbc31781d7197ee02315019bf7c2a9f3541a705a450a6c56f1040a11f75f136ab2df8d4 +Mac = 06abfe43b10b8e68fd6e8c964eb0 + +Count = 12 +Klen = 50 +Tlen = 14 +Key = e232571aefff52446023c68cdafca7e615b18e5790190cfc84d93f4d16cda2a3d0aa29f852e18eee45c6e51391f17764d0e4 +Msg = 76586322763282f98f4e42c1638e8a113ce8082d5c69262d8e7a3a5c0163fddf560d3f97f80cd948acdce2fa696b269f69d8d3f7807b76b1ad2526d3efa9ff5b599bd32669571b1296453460285cc85c4ce58a3f68822654ac6e775aea06fb2aa7898599721c32a074119eba4968588e0e9693cebb861e5fb3de96ba9a83da92 +Mac = dee506aa1b37726b5d856da66bae + +Count = 13 +Klen = 50 +Tlen = 14 +Key = 9408161e23ac784fc94a28dd7c54e367f3f4370d5af2dd774ad94819f8557eb5ade02721769de34a1c84e17956c0aed53e55 +Msg = cd0246ffb98719a0c8c9477c3c92bfd919644d612b6bbebd4ab14466dd911cb89d6e6d499ca5747885bfde4925ec75702aadffab2bd06355e9a10e39d55f95a4d2ed9cbe3bcaf61928430e8bede78539e43c1cf56db0d5ca32d255d4b0c28d55f3e69906a0dfe8ab39bc9eea9d6d365dce7a6ce6f7f55a43aeade1e276a44af6 +Mac = 69347adc61cbfbc1cc336be083f6 + +Count = 14 +Klen = 50 +Tlen = 14 +Key = 94772ba56aae967118acc7a474fce946b312718b89df5f0590a3c019ee0378b0335b3e2e8055e8a8eebbe9522d8918366c47 +Msg = db1aea4487bb5c2f406421dc86e8d448f6bd223cc2a2db175f8448cd7da3c0303cf1766e9dba95db368a8ff12b4cb19559affc9cd4ce308e940f29aa6b4b6e2a3a3008c865e4908084eb8c985c4bfcde0dee2f318c47db4254396d9c59349ee23ea14758c78076a5914fc1d8012edaa87a426400d35705bb08c9bdac2fa476e1 +Mac = 01f51752f7013f8fef2619827854 + +Count = 15 +Klen = 50 +Tlen = 16 +Key = 495539a68141fc099393ad40555a70ebb45e3d37f9573fb14b5c7a5c759eb100ea5687c606fce40297ba9a509c2049e24d19 +Msg = f2c298f62ccd8e102645352fd264af761784c22a77319467ef83b2111eaa570caacbecb0e00bcb779ae948f966d0f21be4ec1683703e854f01eb970651da70ce3f7d82e071ef533a3d408193ca0d03947253b1456b8407c6a7db263ff8ed1b197882646f28a2b0bfd7f3e7e646426a4b895f9c5ab02ea134a7fb66a45b0ee156 +Mac = 0440b3fcd0ddf507717eae86be2b0a69 + +Count = 16 +Klen = 50 +Tlen = 16 +Key = 60cba4ffa639da15809f0c930742ba0a5d50a647eb183525ed7917a6319b2a421bde9c7fed1051c245e38465e89eb009bd12 +Msg = 1ac2649dc5458f439f94495db84e48199aa87cf5dab24624ecdce5333bb831ec79018b7b34dd14cfab5f1d43df50df7eed2f6c979a76e67d301fef97896760a769d23ef4116feaa8105d97775d8e0181a3cb5d7adcf88b08219a936cc0964f65903b6551818379967796a040599017ec648435e4c6c19e8b6854bafc0bce65ee +Mac = 489b50ad20002fdc2765ada1134badda + +Count = 17 +Klen = 50 +Tlen = 16 +Key = 0d414c67d20fcb7066860ee97432c6d2c93fbae21331b1d6e9d6920a0c78ca46ed56eeda6f56a1ededf4b9127f7e9d1c7983 +Msg = f792b853901b60d0f59c16470837038969e4ccf7ffb9c4ebd56a6053280ceb9fbe1e7ade79c923232b676a2eac43fc482a9fa06fc1fc6ab34b9531e07a2d445d240a5954dd42c613cb35f4b3b65b10f75f40037613cca5fd7fc82d2fc69eed6ed1603cffe70cb3687d0f9c1d4f07a75cafcddf561db3dd8f190a3b8735e84c9a +Mac = 59775c5e5f70ccaea59b9598e4563568 + +Count = 18 +Klen = 50 +Tlen = 16 +Key = 6998867ccdf0348c8932451111995a38acd9a579c0544e6f509015e7c3e93837e78397d135831617577f4371e732399d7a75 +Msg = 2ba96d172503c131d73695b0a7183540e9c322efbbeb122a2d6f37e8a62dc425831bae920094af8b5cef91493856a95941d5a24c0eb27cb14bfdd34018676558ac58cfac3e3b9739251d6f7b3e76b8e08e46467d286463ff511316e5e3d7a5edef8758cca6a280227ae6b8ad801f6bbd193e96e8d1aacffe87db8740cf248ccc +Mac = 9e9f62bbf8e8d7d76209498cf2025325 + +Count = 19 +Klen = 50 +Tlen = 16 +Key = a3db09b1150358aca50e47eff034ff8b0e40eccc71e7c4231058c564c5143e31f40050b66eb8f69895274327c055ebdbe17f +Msg = 8e4b575a094374381475258a32272e536327b280f954a383a75f7d3fdbd334244d536a9bd823e6a48aeb42bdf7b7e307d2412fa4be73f9636128409fba331a64b5a2ebd4fd44dac9126886bc9be8f4e6fd66cda42cd6c620c23c5f2e4eb7d074eebf40ce20ab39f1d576594ec7c24a390d1df44aec84f003f12540b43c693e9c +Mac = d77e5de1693e16dab3520d4223593738 + +Count = 20 +Klen = 50 +Tlen = 16 +Key = 09c6006f7c3d71e40dfa282b2cfe3adca438e608cdee6bc2035f1dde58a7b8f986e2f4ba28945a562949555a7c788ca50dad +Msg = e2b3d327be3161a8015d411ab36ce7f20812443092e998e1b61788e95d2c70ffeb49faf97587f04a2f964ec923a59cb429827af413037da228a439cbd4719f709d278ad1599694ec9e492e407b69f0d665df2d8274b9cb67d0cf51b966a642c7df94aa38d225f69438be080721808b62a66f84631fd42a3696e0f83b7b91000a +Mac = c45bc2dde21e13acabb15c908aa50529 + +Count = 21 +Klen = 50 +Tlen = 16 +Key = 00ed97f4bcf7ff6f72a3d88e5f43ff45f29feac6e98ce9afb8c1ac822ae706574aeff0cd84a8d1460891fd546fec7b6ea113 +Msg = 8790988b3b7fed636a0b37f79bf643ae277d675635801568e9e3af8ed9349d62c18e9e7977bd5ba021a24265a5d991da619ab1951dddc6fb3dc284bf3b2f44a555bb578c83cb9aabacfa4a1b19bf1a952a4a837e48ae5c201a45aa3bfc50b9bcaddf6ccc47f1d10c75dbf81fe0ee066aea5485179f3bfe60e836ca0a02df252f +Mac = c8de4bf4c82080c892d230bd702ccd27 + +Count = 22 +Klen = 50 +Tlen = 16 +Key = a03af59fc7c980945bf19cc58194b6b249d27b25e171a9bb09821ea0c641369a5b3e534975babdada654ade814e5a44573a8 +Msg = c1daf562109509908770f59849d507df3fd699a6af72437711134fc31e5a6dc9291fa8b9b2b4991a396adb695057bf03f45640451d4e39f194b8d5d3055b47a5555abc3135718eb5f87cbb8ba1399509414ebba7808e475f7978495acb0075c8ec931810c15551296cad7d476603f3bbcdc8f214ffb7d78b675b939e97d25dfa +Mac = 28404a6dbb1d24176ee3792b423194e4 + +Count = 23 +Klen = 50 +Tlen = 16 +Key = dd4edc03c8ba52b3bd091b7660a01874c68e30c92c6ca388e9879b00a142053ebcb59ed3169a51d7f86ac02d48c32109fc0d +Msg = b57e6073c038e709c70ee3d36386d91e43e110dc224430e8f6150f926ba8c7578f1b0cf0cf7ebc8f2237b86584a5f367a604c852e49191ec77ee758decc781dfd4b6fae2be64f23362f21a8d1f97d790a88a98c1fa2266d3913bbd25dbdd9a8bed18d5517532b17def05b2551ca2ae21b03a27324b3fd823abc68e5f203039e3 +Mac = 25a26798ee0e3eff658ce1499e137358 + +Count = 24 +Klen = 50 +Tlen = 16 +Key = 7997d6fec9d1efa159f73eb5588d0508a9f8e34c89949ac87302154d40bfa96c93fb9be674a8e2643bd12f68b02d2b8470f4 +Msg = 38afe9cf13559044a9e90f5fd72a3188ef6b1043f5f4e6b40ea51f6235dcb33b3099b2d8c2e02103235f0476ad51bce6d8a2934068549633e521a3ee4c62c22b042fb86c13c8da849233205a5e277aea1129678c31f5c379a71fe08b72fad9449cb923126dd465d1e0ae8a925374149b8248b3afb69f168f3ae701c00f6ea08f +Mac = bdde4069457ceec3f2dd999c0f53061e + +Count = 25 +Klen = 50 +Tlen = 16 +Key = d668ad9e7ef2cf3cd79421e2560257fe042f683f24644c4b169004b17bdfdc1e9a8dedd303fde55671050b68f58c7d385158 +Msg = 01296930383b4c7abbc6ad920a5baba5e7c4b202b7e0fe892aae5a5f1ea72ee7c151b8eef6119a26fb4095d6488294cfba53eca2f0e3e210f6246ec220213e3b3991fe0addacd744243d353181f9ce46e90fe0533700b9fecfb17d7081bf244eb112c2ebb5b50bbc7fe4160c7c6761f0bb1f167e52df8c3afe7d11d10928e70a +Mac = 99a18437759048aaf9c4fc117fd0c017 + +Count = 26 +Klen = 50 +Tlen = 16 +Key = 64014b00565fd2c24d0a6b6d2439faaaf27f5a349708963a95205c0522f4aeda7b9ddb227a5aaec86b1de5e31c4ae49533bb +Msg = 51d6db811d95785bbc6a202d2ab4c6ec18afc853e2987c29c1110cc642c685d4f6512a536b5b0edf5c04e23625850bf57914f8a25709b2ef3a3eb43d91bbfe606e9365a282092d0a49f7d9de82714266e2a5e7f309058420b5a9e65836eefd982264337649e7fc63eb0bae2d29be94c8ba283d4ddfd61a439918491e19a7ab05 +Mac = ca7ea1ae13717ca42f1f8b64367172e3 + +Count = 27 +Klen = 50 +Tlen = 16 +Key = bb8e4540db93426362738726a831dac254e9ba4a8061a4dd18e08f208343b9eb864da543653f64894ba815f0eb7fa835686f +Msg = 3926922592cdcb3381f0cd2dd577ede69c87d23adb5fcc07828067799e11418bd18118caff6e275c4bc6b342422ce1da559dcaa88d53d1557ae935f86dc1e295e7a38de350a6ff53ec54b14d0c099abd819c45ce564126f5bfae2e324c7d9d9362d218f9ec3dfb1e4ee2f0d79ad7c19707cd6a359ff373ef37177caea40e1a8c +Mac = cb0f6c2baff858b7fa81e5792264fcc9 + +Count = 28 +Klen = 50 +Tlen = 16 +Key = a35e79f21ffca49fc833afb32c6541c9cb227b0a7bf87fa10b8d336e27ec42ff7b1d64bc1cf8e061233a4fb29bd9a26a9d95 +Msg = 47e470d7f06a9b5f7ba1b41b74705350d873fb8bd8a9f9ecda6d8fc5c1a852646e44d12c86e477eb76d2b367b538553a49943ce08d662e0f312b0746828f16a9ecdfc40cbdbd764e2b17b5e8995a8dc516e2325527b6eaddc6722611aa84f2e4c99b909f1c5d6030a25904c5a73cc09a4647270f2d00f4fea028364bc1eeb0bd +Mac = 91cdea1d856f5a56ac8f7053d6b75318 + +Count = 29 +Klen = 50 +Tlen = 16 +Key = 59fbc96fbccca335af62d218f30cb50c7e759d30c3d52ea3336809990420a8ae3197887ac2478e654dfda4bcbd8ba30552bd +Msg = 0a6079cb30654bf60ee7ab6946d94f4e606a3ce8aa863a3142a086c271afc8f43a764445330954fd948d16118e3f6247deb8ff9ba16f16e16a7fe6ad92aaba70cf9e18e308783ca96887c530b252add8d4dc7e57be26c35c74f6bd7262d75827f1615d6e57bae943b35d1e8d591a18486a5e23e3a9b52be7898d74da8b3d8b63 +Mac = 52d45a3e4169cf8d268af429431848bd + +Count = 30 +Klen = 50 +Tlen = 20 +Key = 76cc58378782bbc0178f9b4f1f9c4afc23a625c500af74dee4b391489edd4da518fb8f4b21303e9770e86183e611857b1489 +Msg = baa0acc08814f2453a816ecee2f7f8a831bcd3d7a3aa83a1f7d2de51e265663504d5d6e91b37fbd777ecc5ffae809ef490d2fa275d753068365788aad2a0950772ddc504175e3615f2dccb641c6080ce875ffa2e352a63dfa786747c9996d3eaec02a099e4524a06939ba885955e453dfeadfb74918fc30d33a6cb4e9f0fc9e7 +Mac = f255c7065a6ad7ac49aa6831e5e0fa8b128a5ff7 + +Count = 31 +Klen = 50 +Tlen = 20 +Key = 4918629058bb50847e7ab996a8277c3551d6a74a91d997cb57ef618cf2b87159d76c71439ecd6d374d5a34d5d9c6017eeaa8 +Msg = 387bac63cf865f06e96a5a6232b73ba8e843cf80df1f369fc9c9419cb4a31fffd4a4399c834e5a1f86e013e792cc5e180e6b81eb1bf03549d29b0899cc2f00d6e8a581e4482270249d279946a5074e5ef29f513aec41f5f319f17fc39cd4d216fce54ce427eaeb3db7a7b426735155a3194509155bfabcc6273470c32b7bdfea +Mac = b1756c196dc4407521f3c21de553ecc21c5076f5 + +Count = 32 +Klen = 50 +Tlen = 20 +Key = 9561d6d7e4018c397d3ffca92595481626fd14e65ab439de853eb942e7aaf83d12172982fa7706344b93c404ff5046992f30 +Msg = c7b59cc3e72134ab6256e3eee90e11a349b60252f8ba0758ed02f18cb5bdcb22c45dc9d009e27b30c55c46669cab1502ed8a4c285fccfeeebce45f0503ab7c9cb85e29817fe63b89e95df8338ecdcc885c3b3e452ee4213ca0c60ff8226213a04cc1a61d72b5dd7f7761e09de6fb9efc3ed1bff38e8ada0c42afe9ac3d6afaf7 +Mac = 5aa8464bd002b49a6ab293cdf84910a0ffcc9b67 + +Count = 33 +Klen = 50 +Tlen = 20 +Key = 12846e9f31395808c16a67385d50bd56e16fa5138723d5df507cf05ea64b4f153f7d016a44a810cbb3e4062d02dcb0b80525 +Msg = 5169b92e115a96c8eff26e9e95cdc13f2311663abbec2933433eb9356692c24adc535649ec3d91f02f117d32968d33d2ae9b433123c9566584f9128a45593e5d0a962707234d423652c31272d5d54cafa0323a1eebc75d49ec7b565fe61d07cc629af50dbc74f0c3e26ff706598e56fb813d11a919d08508052c4d5b4fc463c0 +Mac = 2db3d781acfcf3df4e09d542dcfa6a8b41fcd876 + +Count = 34 +Klen = 50 +Tlen = 20 +Key = 801c6b08c64067238beda9baeaa541f2825ce2ffc97cdc44a42c4abb35d28d98f4d6f92902aacd01ba0769558879bba6fe1d +Msg = de86c1ea91250309c902170950152742b403521f3d43466b217f11cbfb3d348c7abef99f562607e289de34a2bb379a5dfe50edccbb390c20ec58d58d8c0c3e054c91a1468824581679678acdac064415b39bccee1acf32f59dc227e597ae125ebec761e50e651d2d0364c2940bcb4df13bad968d414de06f9a85afdd0569da1f +Mac = 6df229b8e175e0ba5f2f01582dbcc2fe1895214c + +Count = 35 +Klen = 50 +Tlen = 20 +Key = 6bfdc8539fe6bf99892c1c36d521f7b17c224ee3837755fee57a0dcecefb183e09e4cc1dbc19862253a2412eba0c67d2cf0c +Msg = 8c43c86b59bcf845cf911a47d39fdd723afa5c868c9afd5f08519984e800defee60bf266fe0a594276c219921c531ca5cfb2d531405a27a3fa3f82b4a0044f3d766d8e4c2317bd77b667fc70e6c070da9ef9e55bb90eb7f30a15f28c9f74b8d24652e344514bec8b97680c0bbb4ea0b9b1b5d22c7d1c76f63ebb32346cbae264 +Mac = 61b8fee079ffaf55d9ed37c25bce5e19ace036bf + +Count = 36 +Klen = 50 +Tlen = 20 +Key = 7e1cb6baa2bee33c47925a3b5a620fee0f2178022621ee7a6c8657b984fb02dde7a3d24f2a529f9880fed9777f706e30273f +Msg = 139b77bbdb68e6289f3281b13cfb908ae0bf6db45aa9e9d19487eb375d7c5a436cf43defa2dd21a79015bb59391ecfcc1919513266f2c90095d8fcfd20f0c899874a508195145970e40df448a33d5e6197e4242160b08acdfe322e9e9393e9186a83f6973973562ba30472a501bf03f262062fa8d04af4dfd67fca423fcd8466 +Mac = abf321036ecd543f90284ddd0d76a1095c05eb9e + +Count = 37 +Klen = 50 +Tlen = 20 +Key = e986a1ece466d517548568cb2a62ee22b26e25acc36ecefb3920bb65a4212a05420e51032be93a15ccbfd14696883cf7f74f +Msg = a00f91cf355006032231ad6d0563c367a22dc392e360866d1d8daf27957546b243c1a319d6f48e13f89da4d8d2d1fd33d3d80bd9ad27c5f9a18e0514fdb32f0fe3bf14874b5716644bce8cb1979968ab44031717d122a8d9670931c3603f6eab0770acc09e63e51ea62c2d9f5aa34cf47d14adf555387736f864f9dbc6014bad +Mac = cb4dd9fe9824a6624891709daedab72028ba0c59 + +Count = 38 +Klen = 50 +Tlen = 20 +Key = 5f44865db5082dd25275545431efe1f79ee1a328eaa59fa563a4a4cd83be261a68ec49ec84233b88967cc760d99327957b2c +Msg = bc67830c46c7a610306dcb9fd0e59bc6d0c1b1ca328db6bd9205ca50ab8526e81dc000f46eb5af7d4edf10fe1fac2877b4310bbd591cfc1414ead5ff2b5aaa57e621a99b96df4487d65293e811c9f3ae45dcf443065b721bc584018d52798fe1a0f144aac92dad56512e1a03af254494092b330440325ffb2c3b169f29ca1dad +Mac = 0e4c352668f4cda821487c33b717d168b427a6eb + +Count = 39 +Klen = 50 +Tlen = 20 +Key = cd82c9f2ea550a3c288eccee63227fcc26049788299b32d71873fbca96334e5c82cf9d4879fe121d9cef759393375120d20f +Msg = 833dfc27e2ab4e9f7544d07131b5cad8392b0a7e5cc28392de403a1b7b03638ca938c6981e4e684792aa684ac69d278cc593ab09698d46e322d172b2f3df001cbda872a7c0fba5ca5f40b34a236817c403241285e3554ea25ac4c246b814d54648f5c6fbd29a4b50646c781a5200e3a87c46069bcf04e4f80f83f07cd3892a30 +Mac = f423f25eae07c8a97b31fe28b07ca32ba5cb0597 + +Count = 40 +Klen = 50 +Tlen = 20 +Key = 48ae39510f364b5979ad08031e1ddc58ec8b4e15be34310c30161fc8b2b22370dc11b6ed0205ed4f07b1f06d764baeccce21 +Msg = 38adefb575f2727d687419432549b16f09aaa490f153cee8a9298d2aa81f1782fa5a11d67d945d4c50be330c89e9734726663978472cb2e99a7b2f7916bf789eecb763a6bad6a54202eae744dcfb1da8e77613d1858b481648d3007da73695c6f60c0eac9582f267673f5f758548569a34215926153638769c7928bdc34b1505 +Mac = 7a53b31775a39503203f051c82fa8442c6abf6c1 + +Count = 41 +Klen = 50 +Tlen = 20 +Key = f4b7cc253fae9bd41c9c81544661aab0ec7f6296572cd608cca51f55b4c47c48fad5df9fb5a6acbe07ddbda5448ea920570d +Msg = 24b9b0d5babe86e31a3d6f3732f875c201832cd659f99483e3ed402063a3b8283d801d4839c00bb58367c3c3f67a8ab4996e4ccd6ae185b05b8862e59b6923ba164ac34d3f69dbe70d6dc48b439dfbcff550caeb48a425107973d3fb2183cec9b7fdeb0d5621bd20c037b7b8a4c992bc1c0fee577aab3c4c4497db897d5b81fe +Mac = 5b9436bf4568a92da332136edea80d4304ecaaee + +Count = 42 +Klen = 50 +Tlen = 20 +Key = 9125504e453bbb46f0c0d827eb3a6ab2bf9de1aee906373bdaab1863421245f28e823a87afb80fec1eda9ca31db1e0c13f12 +Msg = a2e1ef13b1e4916b30182c3d10b3e6a64dd43ac8d1cff8bf95c58dd6097985fbb65e4e7121f53fc5f355d803580b4c29a5253cdc3d8ac65ab58dbeb036c13b2d230e5616fc042e9b8370300a1d2d95437a3d2b6c781859e645445d7fc426d9e933188e6b0abc67d6268fb9bb26c1c9db16448fdf4b23b9498d15f3ab7c526616 +Mac = 34a1b3b9a8c73cf5a0c361bcb7ee00dc29887bd6 + +Count = 43 +Klen = 50 +Tlen = 20 +Key = 468abbde3ff2c828512c09da1b6ab5df2e0c7fb06f7119c7bd0df757d3bc553a6f567b2ab4844035ccd2cd6bd305a3daf0ae +Msg = d37f463f582eb6b4ebe588996d08618b5a382969646fc7085b4c2b2850ab92a7fa7905f559c723c8981c211138100f2e6b165d61be9a9d81fb4c8aef4ebb4acca625f0695e8d45ff1d0fc8a1fb71f36ee5fac00b42876c51d6db7b42e737fc429f2a0e84b2aba3c241658431fd5296b48f8b5b4f385fbbdfb4a2050965473171 +Mac = 247e99ba472199b7911e830c99c9e581aa26e562 + +Count = 44 +Klen = 50 +Tlen = 20 +Key = 45802dfa44c7cff300dde8d60ae69b8eb2bcef5264ecc8ca38021673c4074c44354714929e5840318f5704dcea7563d6f2b2 +Msg = a9fa5be91a29868050d6d0ed64c7b9446cc9a6e39f462aa4ba1a8357a2a3686f4a1702fbd71b38d802912f25beb111f81b5b0e4f6baba14aa3cf15970415472dfa48ad3d443d976555a9b528fa35da9b3ed5ff608b558bd81135d2956bb6db0e80356697a8b82d9011c76bdc607d9b959bde82fd466b6fb8ccf4c23921aeab7b +Mac = efe95049d3fe3959027baaeef8218e49e3dd901a + +Count = 45 +Klen = 50 +Tlen = 24 +Key = ff91e9e748c94fd081842c50fc5efc03b9e566062d4e1c5243670348a1cd948c2c5f8217cef29c887747f6bb613a439d993b +Msg = 9ce66be0e16f03baae3567aeb7ae8400fe601499999c7b5ab668efb0dcbddc6974f387c68779f1d1c9c9fef0d79bd6bbbd598c0bbbd4fe534935fc345836ac4bdb922c4e86b97a57d5c9917f51bad5af0fd8b1b379777f9050e2a818f2940cbbd9aba4a0659965f5db1d6883ad724985fcc6cdba5bedc7b9d6573c85333fc561 +Mac = 77ee7367647fa410a09e9659b688cbb92a51b479fda895c6 + +Count = 46 +Klen = 50 +Tlen = 24 +Key = 3c17d3274495dcc86f2722398db60237fc70fc0e63b30aa4a32c30b90b40556dccaa5103ac6647e4fece35e7d104c9cf688f +Msg = 1bd96db96e741d637e5c63d697f81a4d99f84496ac385a1530e7e00cf3e83b1aa778c701931225ac888fd2701792fe9201239b09ef9ab48663bf00b2ef2fb7b6a502a401ceaa7c45df1e6ec3a839fbc9cf5c08797d5b31cb579761d6b0679f4bfcbd2b428806ca3969515e59b3b4b9fcebebb36dbe437aeef2b72a009e589ede +Mac = cdf367a1b573713f1fb0eab4fa6dbc134e1d3b9014ece510 + +Count = 47 +Klen = 50 +Tlen = 24 +Key = ccc5808a28ce4ea682f0902288b7f7fe044f4af1a53c50b9024bf0afdcc9979ea3f2dad53cac5d7b0276f3230b9b06a0acab +Msg = ee36e5784fcb43427be072aaa968ea52bf3b73f55d0b45fb1d996d4a1928725eae32399c805b26e3bea38465a8df27b54e6a4f209a18d041906b70d0d50a91bb6e6e1078cbdf6c99049f2ba162657916210c13d7748d63b0ca2bec2c50ede9aab75131b3373f5e8bd43c2e06e0e02a9dc18a85c1f4524670523faa0592bbc354 +Mac = 6f8adf6dc6a03e187e400b6bec7f26921373192491ceb09b + +Count = 48 +Klen = 50 +Tlen = 24 +Key = 900d473876b96e868bc3b3cdb392b3c616bb7cdbc71a4ddda4229ef57d7160dd78a7864fb379c4be2c019745de5885dd2d67 +Msg = 633974ba735a5e57d1e804bcdd4d72d4a9e9df0fb9bf8db2076ef1714a64143f784e39658ad2c0d17f814ab1a3071e4111a5cce177e2106b197df8c319a549b0f56c20ea517ad574f7fe242b1ceb8fa0e560fe232967a92079e337af5dc42766e17d707150b864e54048da52ce5f8c982b01befb58b821792d8af65aa028760a +Mac = dca4bbe04b6c4a0ca0517ca5cc1efc57288f7f97099b8c2f + +Count = 49 +Klen = 50 +Tlen = 24 +Key = 25cdcc9cb014784dbbdbb13f56ffaa63fa234c916f02367dec0303e8810fcb13b29fec7965190abdfe5c54e2c89909ba9766 +Msg = f406fefb05d8b6887f42341cdd1ff50ea239af114b69e17282ffaf9a9463edda25fd7a682353cfa4f871d7a0048e02e04aec955e690044d1cfd3022f29a818711ddf74963c1944ea329dc48840fb541eedefcef0f88716209088f32cc70f1db84574978e39733ee3968ea3dc7bad1650f20803d0de4682e42fe6299858df2437 +Mac = 67937819c005ba41dfa38d4deb33f7ea2fbcb216f5db23a7 + +Count = 50 +Klen = 50 +Tlen = 24 +Key = ce6b7b04ec97a0dcd1e116b9bdd9423b5ec06b624535ca509b11e051108f0d1815b05d4c4bdda5433bcecf0d47ac72b4e072 +Msg = 73d924fbbf462c3d2da264ec5e9b1931a2cec0bdbe7fdc15ed8e222d24a6db399ab88bc088a8d0f22d468c3b167f46189cd5ce2aae0c2089d1268b5a649213a429a1135f013927cef7cd480f808c39f101d9230592fc7cf802172c1f1b5bf354277b0501b361f87a9221e090252bb963dac40577f3b7b50a89474da5d06944f2 +Mac = f82dc33c6c812f8ea9d887d438e7b604f6d52a235cd72bdd + +Count = 51 +Klen = 50 +Tlen = 24 +Key = 61e79383c6f8e253633c0079ac6d90a1f1a21eb2ce21a746c2745c5d1ebfa35221505f0e6178717b6c997f3bb081f39b98f6 +Msg = 49cc22efcd59725f9ebff30573293208669e3233a5ddbcf96a8cf6b62d92373818c21a7ebbb9d1bf0109bcaf62973afd5b41c0201bc4285380dd4bde41afd1986d6548aa1418749543f3e6773695d08acab618ed310eaba7e97214e9ef414d9330fed5fa403e02e84ec599e558ec9cb59b4663224e82eefc8f937a5d9e0f5231 +Mac = 3094fac9d2340cdbfc23c643c4dad9279876430a8276aa52 + +Count = 52 +Klen = 50 +Tlen = 24 +Key = 4731af72a11f3825e192858d026c82346e3d0dd3130aab2aba4e7930943f666c1652a0a307014cb3d8cc7abf337e588cd6b1 +Msg = 1713d55f7d62a4ffbb948efdc98c7eedff169aa8e370bdee400927507888734d1a10cabcb7c2576af284fa03d70141366ef194148f9bafb9f798562f9cd9438f3eec64693f7a4366b415c62cbc301882116fe7b5dc22d03ace0c17946c689c79aa2e0a30bc92523d29cd58402121eb1b1017fb53730c06b9ebebd4498f3c6452 +Mac = 940c3470413d47b81b45ba37e7065091b75fdab0750590ac + +Count = 53 +Klen = 50 +Tlen = 24 +Key = 94023596340b9e0a093563355ff044a322c3b8c295343ce947eceb9844174f02880a77c8b928490815061a96a9cd7c89c3e0 +Msg = b05d1a07804a7ca6995c6d9e8c321d341ad87e60eca29bd0855b2b30749f66a9ce8617a7db83f3e0108b29923d793a0b08b10b6f9a0339b698d3acf455776fdd46e1be88b67e6173ba5d39c8689419de44e0d703fb8ba279549395be63088d1000b6383177046f68811cc6c8734c61b4b6ac09a377027e219fe20f17061a694b +Mac = abc34075236a458c36e5157face3066a5e4deac1d9198d2e + +Count = 54 +Klen = 50 +Tlen = 24 +Key = 5c1580ec4c3492a498303d0c6cd81f157f52d9b28cbd1d97061409400855b3368be3058edb29cbb24c810a64285493ffed82 +Msg = b69a56dd4392d07f6936e19f56d12d9df3731c9401ac8b3d6794c111ca0ea4ae5f4e2c7cfd991990774ce1d12820ed59cfac041e9e2c08d18d80e006f478b596594e614186742498df90991bf3c6e99e51353ff19dc47cbfe31e2bb72afbb7ea4da2db7406ab5b5f4c0af2c4df498b332115b45527fc4fd010758a6b95211273 +Mac = 0787b50eec48efc7506a80bc0afabb2f58ea82990d298185 + +Count = 55 +Klen = 50 +Tlen = 24 +Key = ecc615c35c57015fa46370a0795f4ed1c8109cfc40fe1702102614eaf2efaf7a685f2404458f7d83705c6ee7e5607dacfc21 +Msg = ed0b7bc25ab6e77983957a6ede187820fd572615639b3a799620900976191e2fccf52a6e26e1ba01e38e4dbf8a34c84260d7b34839c9a5598e70fdabd049d342fc2d2f5b70d3780bfd972f243d79dd58266949a1e0c2efe0d414aec40626c1eda43bf051df9507dff93888639ff09daa7a9550e6018efe539194091bbfb8ce78 +Mac = 686fc4801f1f93cf39876e4a135c985fd9055a91331d3b17 + +Count = 56 +Klen = 50 +Tlen = 24 +Key = f37072ec2bdb37cc41b59530d8e563e796499d4a7ab359667031fd5d2392b00913250ee3e7c4202304118b295e00071c8e96 +Msg = 1e8aef31cccc86955e11008d8f7e01f4557962175b563c76b23343c9c420564289845412fdbc302ed1044853609bf247e6225863ec45874e079ec20bc2d61c36d90e468aa87da5a7e25aa71286fc587e0f40304aec2b2f4a2fd02dca89746bd076f16da2b5580c88fbdac7d3e8e95a1e3a9a92d4414e5ff393912b0f00426a99 +Mac = 713571c88ae662e434bb1f01186397edfc0e44472064db63 + +Count = 57 +Klen = 50 +Tlen = 24 +Key = 49394442d99454f26a36a494081137b55b3b944ccb890fefe75f494708c6fac231bfee873ad84eaf2efc21b2f18f121f26bb +Msg = 82a383ca2f83738c73574e3418dab6667cf9b49f7f2ab4239fffd13762fb5391f5a4760d12d96ea12666a793b4d651e9f4891c22c1064023b291c1748601f1acc5cc362aa4640d0629c64f47914fb457efd295b415e9f6e7b788c3baced85aa63b424a8badc95aa4c49eceb977eee596b3ffa6bd447bdc58f90c607103289665 +Mac = fc03b6b8513d77bb245911ec9b33a021d3ce3b91f9f03984 + +Count = 58 +Klen = 50 +Tlen = 24 +Key = 8bbab7942dc30f731f7c74d19a8c022db10b810183e63848b584013c20a9a364c69b5bce0b84bc9a2218bab8c57701f12955 +Msg = a2f15d7f9bb063e5407b12e93f9b9fbb9b554970a012ea4b1cbdcc3bcc6dbda415446662f497d80c384e6875ef8ebd791e9627f6b5e73218c1a87cdae448c3c90265420b3eed3ea12583dce928243567500aacc42dd0801710d89d647aeab862d31d9a825ffbbc2c6fe0154cd4a3300d997881e4f215f9d16f14d8e27599c3f8 +Mac = 47aaf0ec1eddfb7dbae89bee4793746fdb3ec20c1872b415 + +Count = 59 +Klen = 50 +Tlen = 24 +Key = 109fafbb9012be9720361585c158dfd01ec646cfc230426a8954aedb54dba1b2017dfb1c9b6c3e64cdf0a0ba9d4e5e3457ef +Msg = f2a1c204bbd1cc55c30972bcc2b5bc3397c13726d30b98837b18a3110a064b02b6c11bcbf47ad4333e5558aa1462c6dd41cfe7875f5cc98a9d0ea93ec028160968575430952dffec69d0f0c130f4650b9d065bda56aa3fffb468c667c3a21aa891ca36daa5d293a8cde304a61d51dee634cf5dc6c1df430b468dc2341c5d9c08 +Mac = abfb36e5d772309adf0608367269582067a30f8db710d3b2 + +Count = 60 +Klen = 50 +Tlen = 28 +Key = cf127579d6b2b0b3a607a6314bf8733061c32a043593195527544f8753c65c7a70d05874f718275b88d0fa288bd3199813f0 +Msg = fa7e18cc5443981f22c0a5aba2117915f89c7781c34f61f9f429cb13e0fcd0ce947103be684ca869d7f125f08d27b3f2c21d59adc7ab1b66ded96f0b4fa5f018b80156b7a51ca62b60e2a66e0bc69419ebbf178507907630f24d0862e51bec101037f900323af82e689b116f427584541c8a9a51ac89da1ed78c7f5ec9e52a7f +Mac = 354f87e98d276446836ea0430ce4529272a017c290039a9dfea4349b + +Count = 61 +Klen = 50 +Tlen = 28 +Key = 82a289b0911f55c532e2571866fa354d973948ec7b899d573b833f00d53eb8d8bf65d50bcd8daaea54c5d628906e084a434d +Msg = d06d296cad7d428b56b25c53fdfcf558b5bc4211ed31cfe63732678a4f23338b582225286881986247793056741c08c9698c0c05206ba3e4d692922a0f061d17da276e3d562b3b9075cba4bc003c5abbdc6106a68b3fe9cbf5b1bf01695dea38dfe6cc548064753c68117e2daa44345594a4fa9d3595e8c61df7b8b76410e315 +Mac = 5507c4c7c127046c04d161fdc75ec2f5122ed44e86679c39c69c5ae8 + +Count = 62 +Klen = 50 +Tlen = 28 +Key = 5ed770cab9aa8cf1107dcb4fed42a48832e6a30d5b83c8f003d62af7a9f3dfefb5372042b67fa9ccee975feb10f635d548a8 +Msg = 5c42ded57c112cfd1365227f99e993790bb7fef88e6e57b056840af1c6de3ed6d89e56c0c03dbe02ccd9e4de8fd084b13e8d296a5aa2f1408f1790a5dd029775f558f774e603c0f7f8352fe1d8fbe8d1f615809a2c053ef4a0662371eb7f27b27b18c6da358cbb435f200c70be934643fbf70a704cbfc8325018cb3d3a7d76f3 +Mac = 3613be648e6da86b363598f8d3c622239c70374b154e9758be6ac9da + +Count = 63 +Klen = 50 +Tlen = 28 +Key = e8ed22a9cea119cb930ddca9c2675ac8dafd3b7fea7616585e5be5b819d6b6c3c4b9a37a65c10326331de2faa92aaff4d981 +Msg = 3d2edc42edc46ae84ef03cb26b60d56bfbc0c4af36391e96e7372b93c370609bf9228d890a9b58c1dbffea130946e8e37c84a5873f6d96f18e18068e31030a6d0958b8a4e96e94f0a7934b9b7209a4a3654eb3185da050c608c1c7143ff8d12c9658c35c314406bcd933c7124eb1eff2dfa7562a39db335d7dbad8ed95569c1e +Mac = 9d0e55b33e5b72be9f073e5f4ef4bd8a46d8c18a128ec33a09a536f1 + +Count = 64 +Klen = 50 +Tlen = 28 +Key = faa2e1ec2658570a8d1b60376f7f5241ed72781cbe1c61e1230a7e171d8ced32dd5b8f597c7f606cec7008462f7cad3fc668 +Msg = db0b6f188d114902a58112a506c653f52099b0955cd56d49ba8731aeb8450a2977c2b21d199f11616d8302f1ce6d5ae34849279dfdc23546c758d77a1fb2e3423e35ff4381d51b35122b3f97c5c887a140ca6c7b5fad44acd7630cd519a6669f798ddef28f5d7168dda25001b37fe118504307954a3ca36530d05b276dc99a28 +Mac = 14e6f0b573b44c2899b9fbb916b3f0c3b44fced9088fede4add62cbf + +Count = 65 +Klen = 50 +Tlen = 28 +Key = 167b50360501077b3b91f9f612716bad0d661c2d0f191d17cabfe3db79f99bc4d2f9bd3536e7e4322c83dd210d0bfdd2015f +Msg = 07c15fd37f8f92a60640f55a8819868d81bc37f41eb137959f467236ff995b15d7f3e9d98057dfc9775b513c06376450211c55df8fc7bdaf4a5513e9275972cdb92c9ca3738440f50e4878fb2aa396573858200397551987fd8a826f19fb21fc7714811aa33d3a9291af72813c86a4098e17a1468083d483828dc9ae1da8f10a +Mac = 1f7e48a7c46fd9fc87160d68914a52cb4032e671fba07dcc8f684d84 + +Count = 66 +Klen = 50 +Tlen = 28 +Key = e2325dfa77eef21da5e3da5282190b85da82bfd6dcdeca9c12dc2baa9782e1d284ce00a8ab9e038888cd64db749f6a951c5f +Msg = 8fe5d697455aef245a22bc8cf420a764e42939df21b0309374a3d2807490824eb50c91d63d5556e43736813bec2bacdaeec6337e96514668b1b53c60779b2afabdd0b5186bee24b02f39bad073c742df8de4eb2536b4568e3e1aeeaa7ed978f90df9ea66b76d8111aaf20e51733a91fa294a08dbe821898b819a8f66709392d2 +Mac = a160c89b4ecbf32f7e640cc47566dc0ce662d5b1ff225374a889b059 + +Count = 67 +Klen = 50 +Tlen = 28 +Key = 60b93c7a1e0aead32ec730cb277a80dc2a0e2aeb17342bcd0106460ae0ea57e186bae38cd522f3c52e4923882cb3f61b9366 +Msg = 17a4c6b2e4a0e55637270fddd3ffc065ae5a2dda4fadce6d7bbf1a4210019269311d0010a3d101f777fec124eafc06d7893170c099e2ff70b548d50eb9e73d4bdf1bed9728f48896fe4367cd17f599a29ca028838b5c9e655ad4c870dd9dbaf869c613b03ab0831a121f8a42239282ac2fd0df8beec4b633b08a7cd143ca115a +Mac = c0c210b676a3aa61db1f80b9052e5bc0b7eceb2ea3c311dd9ec11332 + +Count = 68 +Klen = 50 +Tlen = 28 +Key = 7b9a8460b00a50f164fc8f2ff2ae9cddab86572d80f675ca02a21a1b8dc5a9c7bfd0db742f550ed55c24e0e3e4b4fd6af7c4 +Msg = de6dbfbb243f97802390fc94678def3d2561819a17b6454186790526a9deb4bf2da5a465159bf9fec4635ed95876f6d93a6995d6f36f3140421e93056b7652b5d11f02e5c7f2a9d1a4bb7245153da6bdb877d7cbe6265fb9d08b096fcd6e0d98f2634201e44c8f41ea1fa29f46eae530c614ae4096e5b7f35848cd2c76d0ccae +Mac = 44b8e1bca512b936422d090cd308dc5adc1b3fa32d0f3aea64243fb7 + +Count = 69 +Klen = 50 +Tlen = 28 +Key = 24a262e7bcff1c84c390b9028baf3831393f00b175922cfc668a26a6ddff77e4d061dd4c0b9f9edb22471d3caaeeab47a8d2 +Msg = c369a1eed6a0f0667fb4c4fbd7ad168bd0038ff16c0455882d7525ebcc7ca2ff2ebeec3493c4750711a310cc41dc4baa3881ffe7b8992565a8c6eb6dc22508ac8c764c7b897d7b64b0a75be11df10c66070698a2f2a7cb03255045785f19cd7ac6dae84d2092aa83450acdc3d4b500c826db81ac80f6ee678d5d59930b1f9a72 +Mac = 66872373d4f20e0121fa4e846ea3661c4d4f3a2854a581c521998efb + +Count = 70 +Klen = 50 +Tlen = 28 +Key = 34764f9a27685c085a94c34e5772f1b68fba84f041c255079d07b6942a09f832655d3131abfd3b8f58e2002331d5f51cff82 +Msg = 980e6c01682e99159995b50d0979ae72313dee4ffdf0d5dbda17665810ac403b5266d08d933bc6911c24c5a7dc205f70ff7b4033c250a980854d211321b667fa7dacaafb5cb0fc30796305f4d68ff403516bbbdc781b7c6a9e773ee42f0de5f2406961116a942538d9dadbbca0d056714f96c812c85a35e24e1d2794dfbaa468 +Mac = a31d29e30af3ac60bc5df465883c916342b450ebf754bdf93d37ce19 + +Count = 71 +Klen = 50 +Tlen = 28 +Key = 6c2539f4d0453efbbacc137794930413aeb392e029e0724715f9d943d6dcf7cdcc7fc197333df4fc476d5737ac3940d40eae +Msg = 1f207b3fa6c905529c9f9f7894b8941b616974df2c0cc482c400f50734f293139b5bbf97384adfafc56494ca0629ed0ca179daf03056e33295eb19ec8dcd4dff898281b4b9409ca369f662d49091a225a678b1ebb75818dcb6278a2d136319f78f9ba9df5031a4f6305eefde5b761d2f196ee318e89bcc4acebc2e11ed3b5dc4 +Mac = 4a7d9d13705b0faba0db75356c8ee0635afff1544911c69c2fbb1ab2 + +Count = 72 +Klen = 50 +Tlen = 28 +Key = f724a2c66f6b014e2c6f82616a8ce16153582fab203217c9821e66e840d0cb8c2106da820c1b57176ed9b287dc90ceb8fa64 +Msg = 32613f9240efab504376aad184a683521fbdc633c1422f4eb1f6cc870d0862a457880e60301e28ba62fc6c9324115c789a7fe0bd9c5030cbb864f3ba7aaea923eaa1462f57e41ff4534d0a02ff0dc138892888ddf22910ec15139aaee59a5f8ef693302a3faa5aa61e53cc459c037c3af39f06bb4d359658cfea098bd6334f90 +Mac = 6749760f89b00032e1c5b7c0bf45d15f2524fb560bbaeb5ee1df155b + +Count = 73 +Klen = 50 +Tlen = 28 +Key = 75ad7c5fb3eb16ccf6c8cef6c0cdd7d288a40673602990c6d5c3147f17f5dc535a3060687bec0b0ae7f7429fb90ca3dd22a7 +Msg = 56cdb738696e86f5f2d29e2636b810a480d50dee1ec907c0ac5213e795bf9253d6a8106e05dd6cac929c39634e0765de29d418ad4047df3e175d0ab2224b53e98b26c0df2fe4ca3cea83be261488645a4babdf7b73d1d4a9fc3ace5663fce155fcb08e34ee6be7cc7ff0f316922354416dc12701c04f2c29e350277c60bb86c0 +Mac = a3b64a7ee8ffe8db725a5fb38547756ed47d84ecd27685ca2877f502 + +Count = 74 +Klen = 50 +Tlen = 28 +Key = a290c3292804994e06c778796d17367707c8e468898c001d8871ecc58dab9fc96b949bf4d0f11ed71b779d6c6d8e6ef90354 +Msg = b4646a046330bc33ab1cf1e9ca3869573ee1a1549341ab007915dba719b3c4e8a94b62163e6d99dee2cbde2ae74135467b125b417c7544978d50c80c694399db77e878109f59a8335df3a326135a0d50a4bde6fc3e5c03fb7747bf919c68ee8f45c312bc2dfdd279411ba7a5f78dd9bfe16baa4a82fed076608229fc5a2aab4a +Mac = a1ccc00a167b36a9354b8a7a891448787131d4933a02a542784abf79 + +Count = 75 +Klen = 55 +Tlen = 14 +Key = b2ff282d913a3126aa231ac406b1cbde6e98f8ead01ea371e42be3c00ea0e3e187ea2dc9b8d729d3e6a8e06d14670611257b3878427982 +Msg = bc687c26e42bc5d771e3c1ba81c61cdfb5811d7d362ece89f6805d873941c2a153ffa2f6b30273342081e26943157116666d65867b44df5d6090497461fcf3e4ff99fe61efd07aca669ccbfd94f651f06e9048feb1c5ec7e24d0e19a1d3dd35f469e5a10a17f20c0ca9c451f7d51029557518d8de19b3d14caaaefa274eca837 +Mac = e501ec9c4f64a8bd0045ec1f5d1a + +Count = 76 +Klen = 55 +Tlen = 14 +Key = ac37e26cdf421613638a0051f8207c607cbb774d5f5a01b4572ba4cb55acf4a1b71068a8bfe4687244f2a7b8a766b3a0092fcb3fbba8f0 +Msg = 31f71073707b064cf9e9e579527f7fd7f5a03b80a3d80beffc1b9e654d4dd68ca9087c5a3b993339da4baa65dee91695327ee0ddab5f9ad3986b38f19b927d3ab794b320a90b9fa67cacb4c258ca87059b1b837d2abfdedb0a7ecbd12a52f2be83251d8d63db34da06936b57672aba6f55018e29c901be4e77dcc0cea3951d60 +Mac = 98195b2059de0457a53c81c48786 + +Count = 77 +Klen = 55 +Tlen = 14 +Key = bf180584a31f0f4210236755c86b826c8c42cf4be1ab991e14512e0d7cbd4110ffcb8d05d75fbb00965486e268b51d2d9930c81657c7cf +Msg = 012389a8499b7336fbb2e7e9edf70ce0159333b7f2225dfa27c1fddf6a68ff349c7b0896399b00e4f3c2cef39a8f62833fdef972999c9c30a8daea73971f182ce70336b9caf9b45ccd6d24ecba0f41cabd6e3117c5c807242d208c2a9c923f3c2ae49a79c45d9786d1da733c151eb29dd66a630d3e4da5bf01be6a6d40687b4c +Mac = edb8b43775befcf89f6602851f7c + +Count = 78 +Klen = 55 +Tlen = 14 +Key = dd03967cdbbb93551ec24b01dd834f60c01628654411df8260a1c36169d966d53349e91079d379167eba1a72f5fca3271ee20ae933d5e2 +Msg = 51367cbcf2dd242bb5a9c4824a58af16c67bc2a9f57d4f8bf1e15a04f3cb08f76ac254bf4ab4045da73adbd5821e11d5e31b009828e3200a9c67352d4b52c7bb15d6d30d02acc03bd5569485e4a868f126861a368eef41d9973b669621a071017bfb616dc1cd400d6884565917fd9eb3b846764bd0a89a400be553081cbeec11 +Mac = 72e2804186cbfcedef233857918a + +Count = 79 +Klen = 55 +Tlen = 14 +Key = 91d710b394861e8089cf07b55d3e3cce2ad3cf66ada586fcfaca2ef86e7b31e9e6746b112e9a3a23bde0d44b9f6bde6fb2f53ab5156f20 +Msg = bb3e126b156927aeffcdd45e11738e649e2f6dce8c2499746286ffdba3a448595b250b7af79141a35914faf52c7f4f74759098696b73df0589889446e167811fb32201d33eca6da2d634d8a737fcfc0119cb733105d62bc366a71431e3201b04ecbd5c3c931993f29eb4d43cdaf37d51b26868edff5465f7226ae76251d6fd51 +Mac = 966bbe140919c02819f20a00ae24 + +Count = 80 +Klen = 55 +Tlen = 14 +Key = b7c1d33f84cf90932456016a657e023caea7c28f3d9f24c8b4186541d459009b8833ce562537729ef026f468e1a9acbea6426257eb83b3 +Msg = 2cb3f51b99401a8de2c5a2ef117eecf2a14281ce7baba58724772c6e342e8fec0a053f7bbe0339f55762db113e38f62af3572443ff715c492a80c397ed64c5c02ace65881b5ed13389083a033ebce2fcbc4677ea2f739fa5a175d4946d887270f6d60e4a98980ad0df7f66ccf752d9ed64d821caf3f89724f11f066b9ae2bd84 +Mac = 4336ceb8bdcca6637e85b97da15a + +Count = 81 +Klen = 55 +Tlen = 14 +Key = b85d40d54d6ce99422f865fd881c33288bc853a2d3134d62c8d274fffa696c20bfe1ea331e3bbb62eb0408c2342ad8cedc0ed61586da55 +Msg = c07b542160a01c6114675c248330026c3b9c3c82ebf24682d4c181197ac7c48e9f12f6ff7165ddee03dd31fcfad4f5f38906070a9ff2f5655e8412dcd0f0c9fdd5e1325460d3e3eae3bd090b08f4b74ca24c7dcde3803dbccfd43a1af0f872c24c302ea794b2d75d9e4f0bdb1556f07f70b6c8522062c68e0efa205d44a766e4 +Mac = 0a2b64301d7c04b7f0deff28dd71 + +Count = 82 +Klen = 55 +Tlen = 14 +Key = e669f73b1837a918e8cd10a14fd682e7e61011c5f145b0709d7d974e8672e80c7c4492eb876e755a28f9c8cae2efb8bef91352217acfa3 +Msg = a34d116c98cdb45d765ad3ec4b9d079b98e0ffafa81576491f1a62d3d63b6e9de6f9abc8030982640ca0eed5dfeee87b72e82292204bf75640dea26bfcf7af7d6140b024b2bb310a0204ee4f01d7432c17d1e3d7af7bcda7d6847c79044e5e5239ad88464ceba898800f3b22595e00f7ae23ac48feacdf84089557c395496465 +Mac = fa7320d526a197c51122a19b5046 + +Count = 83 +Klen = 55 +Tlen = 14 +Key = e967b95400f1f070a93e73e97b58b3ba8ec9a45c8d5e6ea20c2b66e21ccf3c551dfa75c0d42c1c54bebfb5d3a32773f56d79ab0a3b2a87 +Msg = eeda318a52aef3ca4501b1a89d668372c1b0bdb75508b9fd1a3cd7b20f5ac165dd7ef43671e87c8beb51fe05b77ffcb3f91855852fb40b031235493ebc5ba5071093a26057107930271d193b89b26c505a45dcc4f2e21620047e0d17c58942bb51c244f04a4f7220c20d08305b255ab3ace05a5ee7bc60bcb9bf2b23720b23e7 +Mac = 03ebf2d8b7d0e3cb54669a0d73b6 + +Count = 84 +Klen = 55 +Tlen = 14 +Key = 3746baaa6734aae1e59055e7fe0112c46ee023c126ef98c14c486fd48293000a6b7c99856b6565d2af57927a6e3fb2d36e57621cc9e22a +Msg = 994751e831994a6aa68eb2a0faeebc3f1fb20fa50dc778be130edb246aa7708a106f2b5ad3c77c9dac98391c4f94d9c400bee24fa82ca421280b2870ede564a8c51fb00ef1c67ea37b8b454bca0bbe2e7354535f52a5d5bcda766d15a9b8d5905f5ec74bb11cb644b96fbd7690ddd5451f7e4a1c32bb7055ce569259c5ab2b08 +Mac = 57a30d8aa83d5d3ce8b8fd75c093 + +Count = 85 +Klen = 55 +Tlen = 14 +Key = 7d8eb8959d999e14d41ed1730dadb35fd6ef5966118ae2ffec4507cb146df41a267756b167e6b6cbb470055dbc5c789e6c2e96c7ab868f +Msg = a8912cc46f08a01c8c7e16768c9e9a80ec3eb961d042dbb1f7bdd4c9ef5ab53e85fbe8a8809f7ca88f89bd297f9f08e5b110dd2bcc3936e0afca17c5aa2467f7ed06febc4069ff7cf5a8680e1be4e736f5a7f06babc70cdd3e8e74b6c117dea0c7fb9788182ed2a2a82340aec937e0799f4c19a6d4b406ae8e5211269efbc341 +Mac = 4292bc2dc31e4d67481def0579a8 + +Count = 86 +Klen = 55 +Tlen = 14 +Key = fec6206d29fc9fd68277d76952b173fca6ce137c47c4e432ecbe7345afc3c380be929d5653d12723e667b8b5a127eb0b14aef25c2a8e2d +Msg = 4d63634acbd875021fa7e16e08a7f634e4c8aef819ee31cfb3009bf64f3bffc437cdacddce9fafa92f729904112d8237ee754d27647f2ecddb226ae668315eecf107c344926330b94077e029ac3bb67e6a077ee05361762a28140d9a7882eaccc33a30e9dfcd011c9bde4145a3799cf2a3a6ca8baf3d11cce3fb0c7846d6ac4c +Mac = 0eb6c85cab837db46db26102945c + +Count = 87 +Klen = 55 +Tlen = 14 +Key = f8e0f10eb9e25dbd16cdd2f3ee14cdce3addadc0f056b78827485d617beec079b30773a4a12a82524a5ab3bf47da0b696b4294c7a6d35e +Msg = 85cea8adce08f416f3beaab4198bbe3b74e99cfb67ba6b0fed218ed8379671aa973a82c49c677d867f8ceddebd38f00406743a6756565ce762d3464435d50bd61b8de57fbe0b79df8f0c5cc66713d5ef6ebbe5eb3d4b845b3f8b2e625dd69e5ada71dac67b1b6f88ece5fe555f44f7657665a56f63c06bd44ef04d1bf6c2b19d +Mac = 8d1e02443afaf9ca59ecc8a8f7f1 + +Count = 88 +Klen = 55 +Tlen = 14 +Key = eca152831231e34e7ec8c9da550ed843980ccde090f6d4bb70474e443613d046d2996f198a193b1a9de5095826b97690444f285c782f57 +Msg = b5438e3845f39afe7deb0fcfb86e2dbe4fbc489f55f01c0f842961b576e89fc719b944cf5d16f4af2f8820e2ab0fda068dc4e797e9bd16fe1d31d1ca03dcf23d6ba5d80ac87fb95d298d391c6b893c6cad66f9780534516e71455ec9118e4ed6934f7271eef792105342840460a4fcfb98eaa6c8101f72676aac303b07c45c9b +Mac = 8bb18d7e600e26f5d6282d80cbf5 + +Count = 89 +Klen = 55 +Tlen = 14 +Key = c7312c82dd27e8b93f327a2aaeddd0658bd57413eea84cdaf3cd838154e5c7553d40b5cb5ba3916637483bdbc2275e743074ebb20a69c6 +Msg = 568a057ad937a1046265f999143ee1c811ec29353c527cec44fa89f4de4f6128510d204238f5d03983c58acdc067de5f996976079dadf5e1436225a72b325285a8bdf1287c478619e2adc449d29ef5ed80079c8b26cf595503c50eb7a3d7402c6284c0552c948a4c8606ed36d24aec17ceb0e5eb5f2170f28d0d8a4bcea4f3c4 +Mac = 69ba74f8dd40487e613f356d2b38 + +Count = 90 +Klen = 55 +Tlen = 16 +Key = 21b7026df9d8e435966d299ef1d4c2a4a9885527b1fd8fed46cbbae7250f92b5fa0e546b1b1c199676bd627ac909f49e1155e68b440ff8 +Msg = 6fd5c7321727293f9ecccdd78355ce3f4945752d2022fc7dc1cc97259a0db56b2b708256b057b16200487a77b588de1c8deb32e910eadb3a73f6572bbd0c7dc0288a0563ca414a9474cb4fdcdb1e0002f562bb82a6000f3b9cfcc46878841bd12ec95643ae0d7b3dc4fd56ec3c42bd594b5318e22a8d20e70485e6c5129d1708 +Mac = b7df20fb02dc063c8250c10f2e0f0a91 + +Count = 91 +Klen = 55 +Tlen = 16 +Key = 75dec697bcf30b7b345d97bc027fcd80c54a6fd16ebc114352a7cdd67db4391d49a796a030e54a80df3391598bc06f6c8866e9fe182d74 +Msg = 7fc3aa4f04ea5339d7f8d6ee4164db434f520525caba80dd69c7d992467d13108f9ff7c87ed0ab178bf886cbe0e923e30d43b496fd94999728c432980bb1f10dd516b33264b1504f6fa5703a051da11e3632a77c100f136fcd5218344ab699e9bbef86959ed66969edc63c4698467e7f32e886dfea7116eebe393370ebd5342f +Mac = 122a00cca991da9c55a5e03315613460 + +Count = 92 +Klen = 55 +Tlen = 16 +Key = f722a9acd107e287ebfa8c46b9ac61496e97c3f81c9100fd1da2d4b1b3132fd3ebc73980c7cf935f9b38e01db82785194829ac6079c48f +Msg = 7bdb43e42accb7f3f7b452670c65af3ff97f00b2a990a5739480fe34372d7d69c152ff4e10ad5c2bdb613cd631992d7a226ef398bc0b1f4b390ee4d076322545a72bd2b14ad27545598208e2c4c20adb1e24d2fb966d22ca2af5ff0c1751c08b94306616bf832bcad8e15e90ad296de7556944e421fed576d0fdf8ef02d276c0 +Mac = d71baca24c4e14a63742654e3cb74675 + +Count = 93 +Klen = 55 +Tlen = 16 +Key = 9eb8c92a37b1cf8136e7db9d6800c388ff76ee9d37a5173f3a224fcb414f41cafd2cba6c35706932b0d9e3ea55c0e9e091f0ee53f9b8d4 +Msg = 3d1d74bd66947aa6fc1760eb8a989b3dc87e48546255143efbc45af772bf8c3964fdd495f2adfbc3c46589374d5b2ef451d760a5a5e846ea3757d5f04ed93944128876e94e944fa8753667a7e3e6a63d66cede05fd7eae31dfe1a721bf70ae354fa5a1df03b33efc17744064d3a3cabf0e4b099bf17f16bcfd4c19b34fecb4b3 +Mac = 044df32332420077f055601e9bf73765 + +Count = 94 +Klen = 55 +Tlen = 16 +Key = 265bbe01a65c7dc3a5cf117c53783fb4abb2092fed0fc7b74f3f791cef335c780d81bbb7770b085744dc2b6dc5521ae9b982aa1ac0d8a5 +Msg = b55a974e1475e7bee2e83429f016e4aaf89dad7277dc056dbab3da233c8984dc2f94f80759543edc21612541ea6735ea9f6fe5c58f600e957cc5a0dceed094ffcd9f21a52fbf33606fef198f7f267d837fd79ae08e73a946e0309c3110090f1eb8057cf040bdae91f31878dc585aa6bbbf5d348c1a1dbeca0e7b38e94a3adf81 +Mac = d176b43f284bde3ecb18f378ad257a94 + +Count = 95 +Klen = 55 +Tlen = 16 +Key = bf78a6bf7967bb1109610baae80e6b973a0fc8a1f5906b8044217b4b2ec1c433733cb671b6b8b17de18a8081c64e230d0236d10c27a23d +Msg = 3e0a0d4293c00b239ed46d62f6d597a142199395f0a7600e2a538c31052b0508fc122c3e9eab2b23837988f68444fb642bbe7d4c6966a2c587ad28625f57d0b5cc256c115fb13a9454997065c4df183b1c901e1fcda4a8724526a5311f95a9789689f8454099e17ff97d4d371c70972dfad89e968429191c4b072b27abab385b +Mac = 3e460bf893897ba23da09b433ec10efd + +Count = 96 +Klen = 55 +Tlen = 16 +Key = 3fd7caf1ed54f8ad1fcbae81034222da20b2be85de73c7c549f440a312af0c86d65c5403a36528f6b99b69d28d27e63514c3c5c03d2a25 +Msg = 6541098aabcf7a235a8c23c3e4f2285596e66688713df177357fc188beeba89493bb8749bda9c2cdd5b1f1a46119d9d461af9a472452297060b30132825d16fd43f30b3a7cb9a4e93b567e8816d9fe37bff9871bd9a1f0000aac354252ed6ced9b72fb23910909beb3043237aa3a7fc7da4e95cb38342c6d5bf0c381d5a192ad +Mac = 09d6054b7a9cdb2b4ccda991500a3c98 + +Count = 97 +Klen = 55 +Tlen = 16 +Key = cd70616c632619fad6b6ef27825a459ef3c21c2c55b829802c002a2f46827afbedabe3546110b41f855414b7d84c9631a7620ee58137a2 +Msg = aae214e17e07fd59b8b4239d0c9dfc9abec40e0ab73faa51d83cd6a58e428b72a7ba21fd64ad0747cfcfb7344ebde9ec798307822961e2d4d1cfa3b212be04428921c0a2ecac47d055dbb7c7dd3708eb6dd586a7d11f85550ed6505ef65862a2f91fd91a3e8b27bbf3e10b9ee193c05f43c274c3d801fb9d375cc5f263990d5b +Mac = e7490a4f54aeecd9fc7388ae79b3cfb0 + +Count = 98 +Klen = 55 +Tlen = 16 +Key = 5bdca2e50cb78228d1f7553e248075e755ade9dbc7ab38555c1f7fd22e0fc21680ff8071f45a8a40fe1415b6988e0ddd37baacd7fe7f4c +Msg = 7ce7c4013b6c2e1644b855c027ace60996becc436cf1509cef0585f252eae3e87f7b32391369aa4ca97558095be3c3ec862bd057cef1e32d6237479c81d2d03a3e1abe5480e6e5824cb80b7f4734923876d7572349e5d9d2d8a39ec86cc7d28b412d32fb8acb28e1b6e737cbf2879a18ef2a284fe5b57bb5d8b0511e1ab23203 +Mac = 186fdd989417893a90ce17219f9fc141 + +Count = 99 +Klen = 55 +Tlen = 16 +Key = 24837f2f6179d7b75d09d8e584c26268d96cb0e08a488a43c899bc80d562c8635f72d8b90c9ef6b4564e7f91993bd5776a7655a32bad89 +Msg = a08c1ba8c9bbd8d840823bc47b130241ca0ca106ddefe3bc87d4d354c15add9df2e331166e0168013c2b6ab81cb58f44c8ff042c7bec718bb095d8652c3fc13b3e8b94dd46ed4680745f3710d2575bc885f699ff508270455916e0ae3098886e0dec0ca65967b97e70876c74a6e1aff4885a2628649a2a110bbeb3d7d54d7b5d +Mac = 11090ad63d392e01ccb3964e98a59504 + +Count = 100 +Klen = 55 +Tlen = 16 +Key = 1de2fba2444d58f7487679f94f7e51e66cb638c26857d5a6c274425bf42c6b28f824b7e70b35eb5eb1614bcdf90c02c40268c337be32b1 +Msg = a1ecbce979b0c506b38bd43842b807b5ce47fd2ba16fe0b1c425a2fe65ed86d87cf1e3d0af50252d72b8142672375954344e3d66f948b517e6c99c5d61aa3fe3be041eba1b8bf14c881eea916c9c3a8524f8d6d9ec907be803baefee0aa08b74ad4ff60f860a334a3ee4dee1f68eb230e56d4fea42ef3a0e6420261728787274 +Mac = d7e5dbd2138f1ae96315a2a812d2b48e + +Count = 101 +Klen = 55 +Tlen = 16 +Key = a46513a1df6060459698e380db285ae87df033037e3ca106c7a1efe31b2815834aaf8950a78b57f7bb72746c3b994f2e3819aacc9697a8 +Msg = 5bcb347ffc99f10e3b5e64b29a9bd71a5e9b3c01a802715de2a9c2d95ca9b08637b6f0cd83afb7a9a4723513faf55fbdc193f20235a3b51dfa4ffe9abca4770b13e522fca9259b299e149eee2b1ac8fe86a2a25806b9db7788d7d5c911fc6463b5ffd2f3b72326f6f1eca52b76319a47777153ea636b6cd252e8504fa4dcfcf6 +Mac = f81ef68004449d4b8e58c401aa532425 + +Count = 102 +Klen = 55 +Tlen = 16 +Key = 1cf756562c964468a26e4ed8ec0470fd130b28b493e2e402695db6fb6dc84fe2e2292b914cc6091b81e79eb103dd8ac28d438b66ec84f1 +Msg = eaa297508c137d2e7ce1707877ab27580b91ce96f13bfebd9c1dec7912f9e144fba5ea41f70ed068357d4ae4421972b91eae76aa95ac905acc7338b11bcd98811abc406aff771bfb27afa119f2164fa5d4225459a90e8ef34923b4965d35d56d717001914a55462d79ffdee030aba6625577d26bd56adfd03bb5caef8138804e +Mac = b80a5093b40d8038e8474830eed44cb4 + +Count = 103 +Klen = 55 +Tlen = 16 +Key = 9421184d9091e3d76fbc445366dc1b6c81960893807fdea1e5de54be4bb4fe82f9f97c5bb729f22fe1ffb842b9805259013ca220cad15c +Msg = 7dee5fb1fad0eabc121d898dd66e0028488d843b6f357201ab1841664726b66c4d0d56cd9efc21e241ad7dc3fca271b021af13b0abb8447789bc9a8d3a129ead9af3386cfc39671b786635ed87e8eb5dcd9c81ca35905864430d2c4ca6d544f70da9ebd43c0e242e5f519a539ec9d6f6f15cb4d2364418908113ddebb3f50e12 +Mac = 53397808976be10aebc16de638699d08 + +Count = 104 +Klen = 55 +Tlen = 16 +Key = 92a5cd61ee1a0b090ac648d46aacc607086bfa569b71edb4196be26a7bff3966c0be93d6345437f6f202b526a84fc9409afa8128ea32a2 +Msg = f3eb0991837ecc12dd1b3650ebd4a190f3a7a3596c00871c1180fd1b35fd108356ca59dbf43872a2a35cae34601307ee21445892b065cdedb84197b720f8e4ba99470e3773091285b5fe45fb6ccc4210434327c154e501333ea6849a78f00059e5ea906ba8fa95013989626cb806393e822d77ac03890b37cb372c8ce3ee4ca8 +Mac = 580e9f36962a4e39993da6053af12e13 + +Count = 105 +Klen = 55 +Tlen = 20 +Key = b908269810b354c1ba7ed9c82bdde5673f0c555cce53e3ca81899adce4d78eabbcbec9629a5b88a0b0eaa81de48a5b91233f1fd1f83df1 +Msg = eb391d7804741bb2fce4067e2ec63a98fd414c11c5929e94126630ee1087b9cd43bbf7c878ea43a0fc7e68c60b0fb51d8b405100fbe4cf87a66602061c6713d7e2a8d05a692b47393d9594f17fd7f78e950d2ab520a6f1e82ec6f206b2e8c71131c85234bd80500527f131077164287382717e381d212b40144fa7f5b954fe04 +Mac = af9d53a76afb2504b76b9659d4041124cca9056d + +Count = 106 +Klen = 55 +Tlen = 20 +Key = c5f1b3cbdd471b97a9945f90b7c30c18b061cc44265345338cc43e9e866203b164ca0b19e840d95f50a4207490a12a8de0287a30761db1 +Msg = 4f245909bf3d0f29dbb58377322fdf465c2daad232799ac83fc5a909718e6aab14469e4101b1035d13906c53db7d163f95163a495a5ddf27975ff2e4bd1498e03a87c319a93604a845bca08fa4ade5b1a2c2be229b3686a1dd6f1a635ce13213a830f1161d94ba13598246b3f489f3a56b7a5fe65ccb363ff93d480fb7bddf4a +Mac = 6b30312413757c67a1a17ec15835e1b7e6586577 + +Count = 107 +Klen = 55 +Tlen = 20 +Key = 0f348c5dcf7c5a46602879b7df6ca4927d4b1e1a3a509a4df17e5974958992f8ba47167757613417ca4eda1a1c82feb387e23c18357cc1 +Msg = 8d8d15d8a9579adb2d62f3a2a5dc256d5bb1f8377154a9992cbce0ec93ade1ae3938062657856d4b1dd0eee34ab250e8fba2bc2fc0bb714cf5c0bab0505d1d14b6afd61b53078432e9eb21bb685e376cc06251f1f3bab0d96ef440af99a7cb67adfa6bfdc665455839bc7474276944c052f8a1c530dacf093e625b339714516f +Mac = 66d3b56c9336521247f4ab0a6a9be830de480e7b + +Count = 108 +Klen = 55 +Tlen = 20 +Key = ad919d4518a98923d2bfbf57f9447e70ebf323a713579f7a038e2996c34c30fa6923945aea0115c130fa0c7b6d475932ae8f9c57b366a8 +Msg = 5c8589b3845970145e12b34713455eb6b5ceb132242024e42fd9a886fc9a30d3aa15703b3467e4dc99a915ae3ac118fd837e571dcde5945983c52a2c849296b4c96f3763488d52f818b459add51f6db2468d21db3d958196bf3a531f65bf9cf702bd66928672c14f235c08aeae0665be472397d43cd9f3822b5fa9c767ca4984 +Mac = 1fb663f5ba7d78998e51dcde11040cb9f52f9466 + +Count = 109 +Klen = 55 +Tlen = 20 +Key = c57dbdb6ccf6e2d020520502fbb44b2cc9a3afac820df782368ce7b2eae7b4eaa2dcbc65bf1d730f8b98a1ea13fbcbb03578eebaf9c674 +Msg = c7c317f5bb7788377605e7440f32ae3e7548d7c70f219fb89f818a166ca9a742a028156feff5c65979bb8335f27430e30039526be458cea75da8f33dc919bbd18e8f4e78b8f1c86fe47c3c0d5c5ef9f683800c9274a306bde6aeffc05346da8059a0cbf6609317df7df21bb5961890ddc7c40d220528cd62013cb3874f588bb9 +Mac = 8b0e3e54b5966bc97171420ed7c553aec4e15878 + +Count = 110 +Klen = 55 +Tlen = 20 +Key = 31c7c05605d73064fcc914cec2ad0b419eba3fd59ae5a23ee4b37746744b157befcfe724cbecb87ab5b02d152f9c93a57efbdbe2c372e3 +Msg = 2e7dbf9b92ba0be65b9cebf6612d90420bc8372712d0083a87a13ddd18c786108f6fac8a9b1a7509d399c9e6f83512ec7a2ee96a3e67ee879f5ff7d6b3636e2acf02f4ac4dc24a2a8c1172b2397e1160cd2918745778a3a77c0c22c0bcf4b662f720de282f1852f48fee2f83ac7055450ca30d6ce56df043269204c2bbe2275f +Mac = 8c3a38cfcb2cf517614a2f2dc317073fbb3429bb + +Count = 111 +Klen = 55 +Tlen = 20 +Key = 10c08a87af4ee0cd4d67f79fd3231b690deba0840081d15b7e4029cdf7a6c6d3920f1a637cc3e49480335e02d980b874443dc6bc5976f6 +Msg = 986d1322a012271c525e6347783c1684fa497cf30c358f71a66b215f34f428a6909859f72d47f85895b8eedc15501cb1b645ef60700334519bcf2e8ea6aae6c80b78c39f82615a1e76788785b59abd4c6b999a64519abfc022bcde144ffb14ddf3537aa10928f778dde558cbc0e4a25c008ea68617c3d7c7237c597b96ae5aea +Mac = b09b90b015cd538d9202c0a688f3d5f043de90d1 + +Count = 112 +Klen = 55 +Tlen = 20 +Key = 6d707f7bbd43fe595913e2ed16b0cd27b52b9b44123b364d9ddfb2e10e45963555eb7759d004ccbdc11dfdf3ff00bdb6ecd99a2ca697d2 +Msg = a60a1ae28eb4348de8d486c1068689abb67219406659c1738bed39ab43e62d7438524074c82c51a26431fdb236ef65d3071f319d5f34d545ee3412142ac7c0173a8ecc1713b57dcbe1ccfb4da8d211cb2b93327f0d35bae1360d771b78b768bd7265c4b2b5773e73264c887aa45816faea7724cdb681faad2b1f6fa873ddacce +Mac = dceacce827876a6fe4a53e6b39e198d362cc7881 + +Count = 113 +Klen = 55 +Tlen = 20 +Key = 85b0b93089f82d378aecabec1c6204ed3505875e354b228225a8cb8c3c021eb2a86448848bf6237c432da2d6ee3f70a12ddad4172915d8 +Msg = 0f734becfe994306e776262d4528ed8577218e3cc5201f1d9e5f3f62230eb2caea014becfba60fcb1f3997aa5b3bb622b7205c714348ba155c30a79a2cea43b070cada807e630b4086b129051898e1d9e68d1d0ecc9429d20d6a1403e0035a442b37bf508eb87e8ea347a3e68427b6d48ed299ba65ecb37b38754f4547423eae +Mac = e03fc9727b73b25d59c064ffb6a3d9cb5bb1bc8a + +Count = 114 +Klen = 55 +Tlen = 20 +Key = d744de9e24ee707727785291e1761a344a883625ded28ec358ac654fbe9a808c9d7e8b88960cb8b9197fa94b718a90b90192959bcd1a78 +Msg = 5bdc9c0484c9e24f8c3641797b63114891dcb85c7ce67ab5ce1c9375ad5a83e7ccdaaac19b9d14a6bb0d96efb5e01aabeb3f37e4cf28052552112f38a0ce49340ab464b843ffe071d07182e2ba3cc6648622776b66db7c0cb1b7f5bc9184875bfcb2f371e5b5eeb7b3ab2dd9f23fbf7a48cd9f78abc78a72d2570e88e945e462 +Mac = d417e29a8322a2823235517b68190558429c9978 + +Count = 115 +Klen = 55 +Tlen = 20 +Key = 71380a0fc4cbf5ab1890991cede0870170fd806693df2da06337107797aebb8b646d40f099e3e81ce7c22803804bd080e5cc86f7f86773 +Msg = a2113f311c8967522c37fee7a0855b3ba4ba3773dac26170ad2eb4f6e27b470d6f97e3a791a1ba8419f055530658cf1a59a841d725777d68e621ffa8130c20dbf7308d4cbcd6f834c99f0dde4ec9a8091cae458ebb8db842b68d1e1e3aff139ddfe42566c6af892be44c0dd19d604ed195d32bdec38c79c8c77bf8a07ddd861d +Mac = a904e5ca71d9b1cef347e535b91c615f56190f3c + +Count = 116 +Klen = 55 +Tlen = 20 +Key = 18bbc9ed05e1d39dd12f1590098b2efae9d9c4fcd76e24be30c828be477c5e68ab6f66e6a9499c391227f8893f9132b951ab293fbdaf85 +Msg = 767a322d8591637c32fffb50251dfe6ca26b00e4033039dd6661dc94a3c4a5a28155b17e29e99343da11a4b3df419a7cbe325dbbb38416bf5ca8880fb6fda3ae4839569d9e0ba6a2f9fffd4845a1c4274be5336528c6687dfe2eb73fe916421935eec994ce3fc321f78fad163f85a2f4b14d2ceb4c3e5aa0b3ba122d2556a969 +Mac = 1d216bc1b87a899e26d79f25c07f828da8a7c5a0 + +Count = 117 +Klen = 55 +Tlen = 20 +Key = 1e599f193bd5f10ddbbd2301a5aea8a75401c83a03fefe59a74c9e15ddacba49e6e8472aef057c1e96c07bd2ab39338633e985acb3d9a5 +Msg = 4b8b1f99fe072f1d9322931192d3b6494eb124296b6237ba9e57f2fdb4b62d80d698f22e0b75286bfedc6e6102684a9453ef83bd9efccbd5c480a170dcc4764c77a20f2a27f52adc424e64a0e3e95aac32df0f0ae59c8ea60794d0a6f832dff9b6113c335a6f7e98e6df3d763d3d2eb973e78fb9472ac656eefb454713e8b0af +Mac = 4e7a96d75ec1d4e705add0d6d83b620f81c2d823 + +Count = 118 +Klen = 55 +Tlen = 20 +Key = f9eb79122c1eb519225cdf32587a8480f25c0c9faf164ae51d5052e709ef8b3f3af2058d5f990cbc45cdfd874dbc583b1ec417be97923e +Msg = 73bc357d7a35655ec3d0652460715fe364eaaa208c11948825155fe229128942ace2517f763776e8f2e642334786c7b6c43a69da81cb9ccc43faef75a1144aad65c673ab3533d7c073448846613f82d3899c32b25c14399319fa6d81f0ce20156810a6e9fe5211500e913f44f7c517a07bb70f906413f1456dbee0ed5f6996e2 +Mac = 942051a44e59aa7fe1af9da22b2d0950ff0f2348 + +Count = 119 +Klen = 55 +Tlen = 20 +Key = a9c911ac37745172987713087c13a84edab4dbb7e1197e9430b549954955e58c43044375c02b32b41ffd319df3128139b3527f47b31531 +Msg = fc69b738e30a0bd58308bd075d6df55f8c76550f4d0095fdbe3d6a16e6abade5f647b964cefe1512c3645345a0a837c2eac81c8b690194f8e38a4f092b813efb5b26f7195d475cd5b0fb77176893a9d577ce04e42c4cf50ef9452664797ba2d5b16d3b0097ce2947d035f325be1693c1baf1d5c39ec9006687d8b8ced981239d +Mac = 2e6e8f164a2fb4c4107a70e2d7529b13d707ee02 + +Count = 120 +Klen = 55 +Tlen = 24 +Key = 0df40cc547aced4a85ca485740357ca5dd0745cb2736d505fc732733465290252eac97158c420675a1a241ec084fd79bea1c57a472d965 +Msg = 959bb5d84ad05a55caadef57c7ead8fcf933a2ef6e2cf38c22b1c145cf62c344065f25517f5080f7aea909e2962c098ce2af8d19321f5e7fb3c533e9f2c8265ef2f3659d7cb92a4cb676ed52f7f8d882da3e7b79917fc1c97c6f2257fabd1b0180e0db84e813409d0b9e016f91582d25086ad4d8345503b3a637f655904a8a76 +Mac = 3b47b78b7dd5e4c009a821679e8f7d84d204074041bda9e4 + +Count = 121 +Klen = 55 +Tlen = 24 +Key = 5ad50155c46526a9bed20daccca0f729df0dff6379a2584f1109d700b91eb163fe48852c100a9d1023d5713514216ce750bcf38cf261a4 +Msg = c33d3d1f442776d546f4d5a25b7d23402a5fd65e6ef3333a4281b5729bb0b21816413c04f4fd466e62ec07bcfec8a49898b10946352217345a2405d387c200a601bc1599d48051931955274e75da1167e2af7ab1b272dccfd1ed26024a8d603f0c169185ef96e16df298fb03c699b5d491c0f348ecc9c8322d43dfa6ecfb1a0b +Mac = c605a84b7f4d7571c4f3bcee283d45e27a5813d800fa9dc9 + +Count = 122 +Klen = 55 +Tlen = 24 +Key = b62854fc6d0ad44863de7548fd836ee3d736d86265a86d25da538f94480d8c5909de20cd5f0f3baf5783051cf34b1fbb87742c39642391 +Msg = 113a2132e19eb77263988dde8c14745ac0b70861a36928a52c11aaf6fb9f4c65ec50eda9ec2dfdc20bd632dcd37d7c75d8353cc2916db14f66b7b2e70acfa3b30bd8a2a5a8e80118e2c7f9b0d6f49c8849e90c8c85a0eb2364561212aa8f869d975aa7eebdd6abbb10f54b243c80bcda3b5ce186260bbf694b75313f81e9dd6a +Mac = 398e8bb8fe9014c10adc53f8a73bc8df00b2a945fba8c507 + +Count = 123 +Klen = 55 +Tlen = 24 +Key = c4573a6e291e4184a7a7dc529de8f7a5f430766449bb76c44e84d5ba6d5af4b6af36bb8eddccdeb8e5605fbd7edb55ea0f1eeb49cd96ab +Msg = 527ecf0fa414a7fad205a6c16ab477f90172f2a7d596e4f9b1d00e3411ba70ee87b0c77d5de254af7ca7dfbc8c15fc785dce8dcd861c88694c41fab4c5084c053da0c515d8aa51b4799181bae31ad2411e3c32111d31c05c9dcdd4ac500f3f193bf6d4bf5c95276f916a94a5b5ec83ba0c63eb5be1fc153a6d1da303fbf6d092 +Mac = bb5e583a166a487249112110a327a867da1f41b87b784dff + +Count = 124 +Klen = 55 +Tlen = 24 +Key = 0c85fd19adeb2ea2015ec9374aa8be1d8c4bd9fe9373e684372a1a26dfcbae4144b9cd6a7850b003261c080c1b499c3c055b33507b20b4 +Msg = 23de79f58cd345ce85982ac3ff664eeef6592c7154c6946b12cef324a033d58b876ba8e34df3c3b998e6a71997ce84019ebaff161091329682a5f48e1d8b5b4d442b80187713821f7811ceb0ac009dabc3e2be369c2f95b1626d64edfc01c998a44588fcd5da8bea6b4027f006a3a1d2aff8f138be49c5a5fa4dc9a8033c2656 +Mac = b7b504997f3e004d32151a788dccd669d44cbacb54183332 + +Count = 125 +Klen = 55 +Tlen = 24 +Key = b2f1adfbbde4dd9a9674166ee08c2f4341072475b9b80b1032ad4a3658b408c1aa1fe12ad1c5deaa3149a49ebf9feb3012cb3234bcecb1 +Msg = 5d40e4c1b85a4e944bbb21838e0b2da97b65f4143b686a78fe8af9242bb0c836b9fc3d0bdce6c1fae58fc3426351ff408f9b00e6e7fce368187d5f3821340235b616bd20e20da34ff14beea58ddd43c12783377699bf117b092cd164101172d11b366de612f67efb3896aa9453d581930cc4a1ac98d87b1a983e5a903e6ea173 +Mac = 92bdd2de24135e38452069355b2064d820946c7820e18846 + +Count = 126 +Klen = 55 +Tlen = 24 +Key = 5f15353970b6168bdc8b8c8afb1b511af18d44ae30180b613ebafc43b92d3ef098172b68b381f91a868a9a42315ce075c460e57abaaeaa +Msg = bcc43013e0481650a6c282bd8dc883bfb30cd2bb3d315987f9ddf31f4210739a25b4e75cc2751e8cf4d267c934749c18babf5f21e6a8a49cdfc670067aabdf985d746c79649f6d33431ddd646da85eb635577e1033703a0eea7dc1afa7a27a4eac2d47d48e6f0c2bdccb6bf6010cd27f6cfbb8f0ee3223c7632b6e84949c49a4 +Mac = b01a9f4f04a781b3e4b9dc39b66f58ec25464600cf45d0df + +Count = 127 +Klen = 55 +Tlen = 24 +Key = 09fb37fa381d014988b9c9622853cd1de68ff64c98fe5e36ba380f47582b0e052fb298460f6aaba083c1c822b44ff8418b6a0d1516f42a +Msg = 4205dc2840b315ecdd5be372bf97c7421e524dc8837fefa8d00a3656810f22e1314bcc0f60d04aaf73fcd32bfcab235d3cac21a3e772c036260c23b7e258040b40735669687329b18b59cf0024413d817edcb3867620a0d7823ec049f2d587937665c25ee1067c9b2c5a1e19bec0db57eaca4b97baf25633eb88543438ef7221 +Mac = 04ee15575117be2c7bb363a344ad2faaea3f133868066de9 + +Count = 128 +Klen = 55 +Tlen = 24 +Key = 7767d1933bab95d2197c1d8c39775e6ee0d77ba4dc47434d23f4fa2cb7e55ca0cc8fdfd62da4393ddc2d223af8d85b1ee493ef55a659b9 +Msg = 19699d047c01db80a7df61cc67ef7ecca3cd6e9d8f2b2c1d237487adccae783561a5b36958467c4b3a49bcf154135489b0dab19a430aa08d68e7646b8d7407e82c94eda1fe70afa26b18262b446dc5b4b43e2c2e74b1fb8c3fe5e48286d5058c64807433d4471b8c2296c6019fc67a53994209e08ae9e32290b42f791d991a2a +Mac = 1b37dd45ebdabc24ca1060ead25b8c1360636f8d24e4f725 + +Count = 129 +Klen = 55 +Tlen = 24 +Key = f2c0a5bc165710222a9053d9c9a193fcf69487f7be553a3c190a0c3712a2fa8327b1205ef37b7c5a0a4ef55625169cad7f2b31ad7e6de9 +Msg = 7ae510baf298eb8e7b28fb613e6ad04d7af1c4157a318d65c4e0125b94a27e4588e493ad9d0842935ac378f94bc43aa5b197f42278c80e08694bc17da11b29fc42229b55685938f55f30c2681330af1cc7df7c680ae444cce76b917b5dcb72160f66cebb3bd1f73ef03682b67cf6573c249204ef19cb573ca7082b5caef9821d +Mac = cc1210863083977df631900617f31e714bd28b331d8bcd8c + +Count = 130 +Klen = 55 +Tlen = 24 +Key = 6ff1b7b637e6317d8269c1be2781a4d7de97ed99022b6e9e96c6dbdc87302d7b30e245e423bed21b27fe744e7d6b22ae68cfc97decac35 +Msg = e688e0d3fbab8ebe93140584fedfbd4f0ab4921427540fc9c971ecd20ec3d5bca1586e2dde2c931b37f9e43dd65081bf83e9123ac9380be354402e039eac51a7cb1c6198d1bda78ddb1c4aa0f03c15ffcfe67be41e40d8c7c4a1fad294a4e0952b7bc1fb1b86517c49243f9593ca0275b652d5fa6f9500dbe13b5a2737d20cee +Mac = c376dbe430701a561f96a131638c7d3381f6d044ff51a465 + +Count = 131 +Klen = 55 +Tlen = 24 +Key = 4dfedca1a4530eb6a7c96e8d7c80ef5e4b8ba20945ecd6aae5bf836e75b5e9a6d5c4741a781de3a0af5fa9ed2a0a93aabb36accb5e855e +Msg = 2072a24e82699ef5fbfa34963439fcf43912fc8ed92529164fd42b262299612f499d25b2938751b24692016906e39b3af9190de7292556042a5c48abfcca8c7232cae69a54d4ba898395d07a5b4554741e3521780ea73fff1ae3a9a4bd87541d241f6e6f8ff5e362f92b2633fb062e8aee8dbfab5053eaf06891d7772d77c218 +Mac = 3e4daf5d8fcf135c06dd02fe4935c0bd118221e51b4ec089 + +Count = 132 +Klen = 55 +Tlen = 24 +Key = 7fa8b4e5829069c335d1d8234e1887c59fc1f96deb522588f9482713e61736b9bf6cd63b50b54e1536e35d5f3c6e29f1e49a78ca43fa22 +Msg = 38efa75867c539a6b76bc7b596e35f3293d21d96ce2941f0ad0484e5d1d3adf549b75f00052f35088df31138f320b02505968255c89eb9fe22d1a00fd7352f74b7a8dc961582b3227a76a90c9bb92ed38966010628224807e2fce00f9c96f272e98ac7257e07dd7de7bb3a3978f600c3850c42b3d6fb1695554debec0a401d77 +Mac = 1c1a5ead689fcb69e21cbcfaa3d175e99f1494e9a55240a1 + +Count = 133 +Klen = 55 +Tlen = 24 +Key = 7cf7326d24380090541b3b6c5693a01ee43fdbec3c34422877fcc35616de1b91de60492ae60b4393ee6ee77bf266343bff9cba71464e4f +Msg = faf30ddc8ae590873136091ab81e1eb889ec314ab6fa84163de0a1948be8f97c3ec2cb242f794709b0a6f4ab12e44f9f6b83b5df958182647ab57bf78f4e69449f7c0730ca6d1e6ccd7bef4a84a4d1d0ad3a1b0ceedb44a61aa449bcb0a24fe9a4898aa762a95dd8111dc39f1446ed74d7782d78c8f21205a314d58af3ccf396 +Mac = b6e9534247ac56d793a94c67b2d0857a2d634cd4c6586f81 + +Count = 134 +Klen = 55 +Tlen = 24 +Key = 25afe3fff3f2524896c9c63d00f354b3801068738858ac91b38d2cf9062eb74b77ee88e9ab65264e040488a1db4e7d890a454b44ae2396 +Msg = 19a9626d585f23bbf9222de8cfc610150c06ab6fb42545fa51d6d98ee95ab01f2de83541f35106eae6e4477a7c8f3bfa294815a1d3ab0b9d85e5ad1067d07558ee5f9f93503d3a623bb180eec6c56329a8a76857a74fb8cc546275f7f6574a9fc4d8466d576beaab5e51804b94aeaf2befeb4d971a5974102617d84b7d35577d +Mac = 39991958efedfdd8b12ed73952e71d205860fde54ca06ea6 + +Count = 135 +Klen = 55 +Tlen = 28 +Key = b34a6eba59e632e3c334df582fd0b03aca7f641c6914920a79943dca3998a86127f36bdab795c7424baf37f76018472305f0a983928386 +Msg = d03dd94e43d96ca459928aa96d2b81c35ed54566e33e66351fca406b7620727a9ee991f2f9d41da322deb306c6d085d9b509080a387decd6a6fe513232bb386a07063708975a72f72f9cc6e8cfa147f53af1ed8449ca8a6f8468ff62f384b084321b3559c47053e7a9542a1733a5af5f15155d9ebd2c2847e491b3c26385c20f +Mac = 1c4944843c3ee7f98ab52987e0d2d4494aa72548bfdc3602db45b5f4 + +Count = 136 +Klen = 55 +Tlen = 28 +Key = 2fd5863ab5ac0109cd1cc8a6598e75d85811a84d0df14cd55e8b1cce7a5f65dfbe670deadaa8d43b2f06da067c5c6210baccd5ac44540a +Msg = 85c02d7cfab29f8adf0fa55ef36722a04757c8865053d2af3ba2f64e80aa958aba6e3625b655325cca2db00f686fd422f2c53423d0c98c2dc110b20c6e67cca1455cc0888401ecf994ec18ec9982a8814776169ef78ca0dafaa33e9a2df2d779cd92b4ee8d3c3529e655c33daf270584ed72573fec23787e8f638240e4d320da +Mac = eabba9f35ba39cfb9283390d5425687cdd70d4cb1fea433925647c79 + +Count = 137 +Klen = 55 +Tlen = 28 +Key = b67787d13434effcc68528109442b9418df025de59e5788e8fad1fda29adfceb3506ba95cdbc5e9548181f17b24a787c7a537b596b2268 +Msg = 59282658eba93c8d2997b78c201d29700adac276c58668bc83d90a49c2a8324e7f52daaba65a81b5ce557e37230793b7a3c9c5fa8e2d6bca17e586f660e1509ba5b818a2b8494c8aada2d867d621ae2bf2d8a625a13689c71be468ac22ee33da3523874407bec6932f466d2521b2a2565dd10dffe6e9e93df69f5b74f0160293 +Mac = 9d2df0d7aebb6b08e816bef8df1bcf7d907622c617449346113dd317 + +Count = 138 +Klen = 55 +Tlen = 28 +Key = 112bb3c6f8d2e4f85235a7325d2cbb457336f9b9d3263619a4196b9237ab14bd8d6bd5b8198c637bc6dda2693cfb0b265fc451a9191044 +Msg = db2a58b070862fa950c80788b5cf8d5d443e31e492e5cda2e67c87314197f8d99bd68e60705c2e227b831e64c2ce23e5d220e6b64c2b9c4ca02ae6d419d3f6c61a87f4bda7cda08626fe387667429c01e3bab08941ff02741fccad810ef77d5cdea653701dbfcbfcdaa01d69ae1141dbfe7657067a4a4543e9c8a2e229ebd3c2 +Mac = 7d3cf647380947283bbc71d6a6f0f2aaeb1bd74a2cb0ec7b9a02c962 + +Count = 139 +Klen = 55 +Tlen = 28 +Key = 9dae3b463c86d64ce598ba9a567ca83783265e402d20c642b5176ee7339938d5c31d53d31f44692d735e1a5a6c30aadd92f5f669d9a2ad +Msg = a7052e9a8f361a959f3f988e98e722a95c9e38f60a11a5a36bfb03708d3e8162ad32e4bc5a3dcc2bd8a43941c3a04d24f4b55488a93f01dadf4efabe03b398bcca5be7365edcf59eba4e49e6575cb137089a41e5221a98a3e13a65f307bf2ae1c62840f1e03c1c560de6d0649d42d4485ef807f7c0c9f16437674bf6e18ac139 +Mac = b942bae8786a0addc6c61e27a776429b2a110fa913711b835aca58e4 + +Count = 140 +Klen = 55 +Tlen = 28 +Key = 9c3a8524f8d6d9ec907be803baefee0aa08b74ad4ff60f860a334a3ee4dee1f68eb230e56d4fea42ef3a0e642026172878727493f7f237 +Msg = 389f7483a19b1ef154c514edff2514d4dd19d01bdaec3687f8aaf4a0f1333c631e8fc437978112229c5ff63d3320586513b73334c1a0e22ff9b89b414f51396916863eaf81cc185c08caa36a0d6bf03ac031458540cc649503eb10b57752cee6e92ce9d3a7a3b80761af235ed52b64b9ac2e0bf69e984520ddeb5de2b15d8342 +Mac = 18cd8351bee9a65fce63e4fe4ede777a926be229605abbe6b403b5fb + +Count = 141 +Klen = 55 +Tlen = 28 +Key = 8fa70b480660c4b14a55e58c3e29953461b167be00572f82aabc13d6e5a2e51d1f08b001e79690fc5d3cc71de7170e092694294029d7be +Msg = caa0f65c2259cb224bba5e8edbcb2491149d7c5c708ae6c67ebf70eeedf87222e68b7b00a0a88bdb2edf83619be2d97a388d90733523685b6fdb52ad899b26303e03981cf5ad697e96b3dadd9d72661e6d8eb0a5e637bbbd39aa593afbfae65d791035f74cf0cbd12d3f4b4c0a02324559a9c43bac4c47b485346edc6c9d1870 +Mac = 4f0fc6a3a014aedb76dca61469fa00bea0b68d7de36171447d3ffde5 + +Count = 142 +Klen = 55 +Tlen = 28 +Key = 75b069b367c4b38234f3a7687b7175658f54ad591da601bd0fb84d91b1bad4951289ccbcaec81ede493267ad1e2e42ea39a4c9d9221059 +Msg = 40cdf73a9d9a24385797f1c128209d2cda6ec9a3c20e22328b913f1f3586cc7a5ca5e9f4be4dcdf5f831afe8904ee6da38204f435115ef23af42d9519c5452101fca34e47e6290a401d197cff9b7bb2301d2116c8472fa9b7f2d021788d3085810a5a0b1e5c1b56dfae1731e6b456332bceed8c7620d8bc184bb821902ea3677 +Mac = 3d36839608bc95e59c85b95f5850742caf5fe6a839df67c8fc4e77a9 + +Count = 143 +Klen = 55 +Tlen = 28 +Key = 48ca2fb5b7e4f471a20911af6a66158e45aef700ec0262ce941350dc208adaaf95a84e2cce2983a2716f690b21dce48ff580db4a29f48c +Msg = 86d92acbdfa96b3940c2ad0e34d2f5061129688c2b1b153847a516965354d7295463b5af9f23cba74ca00811e88285756a311626683d20c88bfcaa104175b6cbb17cd122f41fe91c82415f64ea855d4dc76e6a13efc43b64ed39cc1eb24cb05b876ea6ab46636ca0caecd890a4a324960f268ada2777101255a3a6490ea26edf +Mac = dbed958bad74760b01386a77326716a72d0b1f9c9d17c5739170af21 + +Count = 144 +Klen = 55 +Tlen = 28 +Key = e2d4aff9b71bc43ca85918536b383fd44da600b381d55166b8858446f285bb399377a18eb9d55c28cd31bddf58c1ba23181a1fe2543c80 +Msg = 4d616a302d74563bde32eb5357c6761bff084245154e1a034f8409bec17f640b018e0adb8952ebf15cd0c79aedc538983c39f35f42574b848f7cf772328e145fd98f6e7e3972fb76b02da814290f583c41542a26a8f7fbc7c9c72d8cadbda64e1c8d1b83067b8eb122701529d54ddef1557f70020ed433b3458c3376fbb421c2 +Mac = 0b86fe83d00d27ac4fc5ae186235c173513a38ddf8bb9b682b87eea8 + +Count = 145 +Klen = 55 +Tlen = 28 +Key = 152f10957a9e29555bd53365de742180222da717221e4145dd5d7805b4d461a3134f667053d348badf3265fb96dc375171f81e2e66b35f +Msg = 9dad4126c47577262a58ce5ffe9a0cd647f78fbf78e584e2441a5a44b34e7604764229837801dfc7b56599224fde9d0ede6f6b5c08f9f48e53bc0781361b0c4f769ff473b03f702e31df612a0e16905e7234a031328441e2a7cea627bc20381446ce8c3f94b8922247cb10c064cb4f8ca84f15861c0dd2a7e9571e7f6ce6631d +Mac = bdb5d4e59a293da549b7c21c94b26ec2197bc12c09db16439881996f + +Count = 146 +Klen = 55 +Tlen = 28 +Key = fa443acbee73c903d551b3fd01bcea2f2566ea78afd8a74b57b6c310f84405c79f2907efe2732ea674dcdf11f64bf0fe0f9e5dc8bea73d +Msg = 859f4bca79d99c1df353ba60927d66203ef2da8316a35b8aaa320e936b9c0c22601bb8e01a4b51e4e98bc33250a6c381b7b31a42603941dd9c972f3e3fa36f905192754806183266f0cfe6f774dd36df7bd27ed569cf68af53edbee06ddc7c3fc1cb2a0a2788682a71e9cbb8e66ae7c1f217ad461badf88737fc6282dc8f5cb6 +Mac = 50b99043849ab22417f6ec93ba0589f3b9323e906ad326643e3e0b4c + +Count = 147 +Klen = 55 +Tlen = 28 +Key = d6d6c80c2890d096e581c98d9ccaddc4de8d360b4eb0b70df8deea79e4cf3a60eaca63dfc76826fd719a41d6a8ed9eface0dcb10f888aa +Msg = 37b4cf3789e40a62aebde9cd9cab34eb846dc10d057644e39f94693f6acf201d089438e1d81330df6ce54a203ef2e0639e92fb63eff2225813ba70c024ecea5f650f0f85788eb08fd15b01b06ad7f1f2b8f6b777df9ead05225162c29d0cea3b366f79abd11d317bc366370589240c9dbbe21bd23b448ef1b2a366cb3df7cbb8 +Mac = 35a0adc7292a081c55cc4f935d6a648062ab9ca98fbe7cf8e6ab44d7 + +Count = 148 +Klen = 55 +Tlen = 28 +Key = 7a60ac3fd22921ad5b4eb147f97671959c21faa3b74378bcf431fe7626c11def7eadb455033909ac3c1619cb2f852da890c0aed632953a +Msg = 93b8e929e470fd73ab648adb8eb3fca8010b1b11b17a90af2381a431986b4c5235dc630860ad36fe6df745457a6e484797f171fc2b5ff16093abbd240b3392a3d24d36198923020fdcc29d1a656d0ac5cd37e5cc35d1e98bd4a0b6b5e112d149b333edc2277b698f42ea19c21758490ceb06ffe9987881182f87174ee1b2122b +Mac = ef7aeb37c728672913d996e3ed749dd65d101094368a2a802f3fef7b + +Count = 149 +Klen = 55 +Tlen = 28 +Key = d861cd2244ac78b50b15467885a2efcbdfdbae91c1db00e42da6aa07abbdf99ba3f04d160a74d9724035a422396dd34adc762b2fa8ddd2 +Msg = f659d94c509e50542d632e7ac0df585a4040dc203aa8dfa92b75d7e54ec5fa80b339f5c191fae2b2ddfa74811b7d752675d773460a77b65788247506fd8749d5eaeae1099a3ff8c3b164846d08a53057b8830da275b3845e1e6a90ef91d82ab5c4f204ec127579d0d228c4052e61713733ca12fe2465330414ce9069b3c18566 +Mac = 9e0c784393655ba9f9a4a8c55efb349f33bcfa7a294e084ff6b8631c + +Count = 150 +Klen = 64 +Tlen = 14 +Key = f429ce003a8a56aca928f88bf9ad4e22b24e43fa4295ca8d4c64d06744376e8539a96401f13ac3f13b4fe98c817ab28e9dfceddeed880d6eaa4a216375280777 +Msg = 7195bef6e63a04c5d4a565ff52e0d3991719d3d6ea488e0a591225a4aeed466b1f86fd084560ccc5d0bdfd9478c1375337d5504eb54a6206043e21318dc46b014a3f21a9360f361e0270051a0a9ee867873e065a06f96c9e196a60324c3af1b55a89d3e2a1906a57d485259af0bf0d5d711b9e01c59ed55a015c8ab2d3980010 +Mac = f5e7c57d68eb37626c4d14e914c7 + +Count = 151 +Klen = 64 +Tlen = 14 +Key = 99e9a3e771c61c89a904f0a1e20ef08f92d65083b3bdff87b8b734c0c5aa4af01f18cd40e2fed53df2fc922033b52952fd79be2fca22d20b323bd0721a68e2b4 +Msg = ea753386d44844fcbdec773fa17d5055ba5b78d1a4c50603beaafe6cd3bb1774fac5c260ba3e677e721ef2a2f8f08ed68128b04ec1b7589a53dd941f5a3e45c8693925f9a07509c518bc6460820d0dd70aec42fe82fdecaabcd124213700f7cffe78663bce14b1397771d66084fd54be1e5034cb2ec04a9cc22fb959b228b5f1 +Mac = 12510295bb3534369bf5d830b1ad + +Count = 152 +Klen = 64 +Tlen = 14 +Key = 90dff02fcecb7506564ee21f2e9ea4014f278914102ed164e3b489a23f9d146cdd110bcd27234708eeb03b915b8a875d28d6cb5b0fb3b943831d6f8e9f1003c5 +Msg = f85d81cdafe811caf3a86a2fb2e48c907cfc1f82e644fc0b2c12ef561a16bbab2cea5f9ff4ea9888bc46a7346d5654dbaf2d335152702680ed692316c457387bef08cc06b9aa277047df35897a0f862915029a6a23ae5c14934dec5926b3a1c38bdf4f6ac8d0c56adb9a9a94a1b82a64f8a4db3320a5a5ae68e8d18706d3006b +Mac = 3ffe0abc7ec63095bcaf19463bc7 + +Count = 153 +Klen = 64 +Tlen = 14 +Key = f7c20871fbbf36b8f1bbe8f19908781ec0cbc9a209ac2d9bedd28672010eacb177560f14e8769ee25102e77d5b8f7f38df22a46aa9e921c17c2972d85778290b +Msg = 45dddb01de473e3377319ff4c7c98287950711436f906b949fdb3e425b9298f63c3bfafaf217af40354a5ba6fe3dd778f8413c3631753e9816e9bcd09e03940fc522bc4a3c828f3e5f6064b2675e65fce1289fc65f5855126d979a7cc6051fbfc8dc497b26508636ddb9e2a069f3d51b38055f7a5f0257098c2d01ce3b60de0f +Mac = 1656ed6ac09c9f2242920b3d9978 + +Count = 154 +Klen = 64 +Tlen = 14 +Key = 9f62b0f2d5a67c0e48374387b1c2900f09285425e480d83a005bf6131e4b896e10a622e81487fd1e60163313fe0930d2da6b68541a9c46a3ad9a6540277e03c2 +Msg = ca739f537b6bd2a215458ddf56d714cb4c098995ba9e6a4dbd515b9baf2426b14cf5007e13520e25ef8e27ad1714dcfa33fcb5fcc0dcbe26b5e14222671ed7c3aa239a3b39d2bc8e586e3e46b7f5f8699ab0e0a8370889d95f9beaa7618f61882c26f8f0b393e6c5960d5912fe2172ffc84c9101e7c9d44e03a8da946620cdea +Mac = 88e0ea6c3aa81d7a4c1d27223f3a + +Count = 155 +Klen = 64 +Tlen = 14 +Key = f32dc12f9ba452dcb148f0a3b56b340b2761b891993ccf9108da736a6c227fde8e8a1fb71adc84b0f53bdc92d061819efe2a702b8256fe906d8ac6446799e644 +Msg = 09834fb1ec058cf37d8d839e09840b003450024fec77e1ee9b0893eca13788ce0147058e5aadbee31a72a6c3eed906267d42cc0e554e26c4254450642eb3ab9bf4590eb0394460c12b376750dd4fdbfef4e6bf95a3b8f14cd944ff47b8763c5e4a82131f6f139c161aa56d4cbd2fb30d020681eebcfe670f1dd2479e29c6649c +Mac = 2cbe6f2d0ebd1c10635cdfea4702 + +Count = 156 +Klen = 64 +Tlen = 14 +Key = b0af4010823cd4e97eec0d9d86b16ac49b12a340e921d5d103ade0e46fb80dac652bf574d4c99e34a662e6624549250a5e080e21e551d617593899ab49a0f903 +Msg = 8f249b0121b9375fad6588a85cf638ad4d6276b245ab4971a2052461913bba37814f13add861e083e4d10cc414a8934b6834978526f3b179cfb3850551f6996a7e9b670bbdbbb071ffd21493f51fe054814d274e6a5214ce53987e1fee5abd0c6d52bca039915030e7aec89c6822c6d17ff34d9278901a7918fc3838d02fcf25 +Mac = 8127fbd9b54057af347b4562e438 + +Count = 157 +Klen = 64 +Tlen = 14 +Key = 2d8e2c01a1d89c01f235dc83ea122e0e02dbe3013178cf320218fad6e92d98a1d7b73c2e0cc648a02d3aa88a96cec00cf155a23f074385d3d76e73f7e5164179 +Msg = 1521955dcc9a936acd5c3af0124d699c9f2d6fd35b1c7f511e5d5e100b595f6b20e791830bca37e23f7b785e482a58405bffe7a632a5b826170995b43e5f71c657679eb664ee4167c897022ba1db08e4584f246a77254c2dbaf64c1c68bfb8c5e32925bd7e0d984290373f1fc76a5fd0bea58ee7d1a522ae30abe90e327f1baf +Mac = eb78628f2d2b7ce510b48934a509 + +Count = 158 +Klen = 64 +Tlen = 14 +Key = 7d3e8ba05e5e2338b63832711e0dcb9fe4073d6a68129536c5ee64e3b482c2b7ae74929851f6087f05e36929df0a1210c6cabc99d4dffe8ffe7b13d0f898de46 +Msg = a08193aa302cc1dbaebe24a5b8af67d869fca4f6ceca7af39e4c603925e838ef8295287b1288a5452c0fd0be0fbd06a218c7b27a39ae6664a61e2b16d1171521994a1a73bec6232099d364620a1ee9deb11772286198818ad1c7b101953d49894d68119a1d2d65f35dd28796911c3a149bb48c0a2fcff3ec880e9b0159a3ffaf +Mac = 84e695c5b8b2b2a3efe05ae8ac42 + +Count = 159 +Klen = 64 +Tlen = 14 +Key = 73cda3e38953f6795a6956b1e957fdaf5bfd57faabb95b809f8b1cdbfb779bd2f42be023e7e249804b8821d7e51f74d63a6122af4aa733187b096a96d4c71dfc +Msg = 750195a2cb52ecfed80e504bc30f41dc2ace6688158324f2298e6f0e1f16e0e074f0088761c2057b0d6852130296e44addbf72c24a36140930940f1c2959ef2935d6d799af4a164e804bfa299267e9d0880cadaeaca5103b2806a97d7a0af5cf227aaae19d314700977ef0975dca79f6917bc1532118410e79ade43af8711958 +Mac = 7c47218ee725b6a04a7df42c1532 + +Count = 160 +Klen = 64 +Tlen = 14 +Key = fe68736c692971f585ee166a3ad0a74b19f15459ecba6bfb9267cce10ac69de7cd3b3e3c61087fc32bcb11b985483b991069ce3c4b835b4565dba3bc50694ff9 +Msg = b34c68ce1c9d0f4c8bdee0553aae150a59d16d01bc1a7f42d18e4e96d4c61d024695858e9bebc44a33f958938b96cd93b5e2d307052993450e0a437dccd8f83f2340bc3d882ce153ffe895c44583b6c74e79e742f28ee3d5e3fd111ae2d2592b329537654d280d6cd7f2be6fd03e78ae0dddd139e91316fa38b1dff57c7ee7cf +Mac = c8487409dc74d47e1b49ecc005aa + +Count = 161 +Klen = 64 +Tlen = 14 +Key = 10ce05b983a434586115fbf5f948b8043a7d74f917e869bc30bfc157ae92a1f26edb660263d62fbd35929bd12e48d45557edcc00de03c699bbb419ae93213089 +Msg = fe26c1a8ff444aa57cb67bbd72545c26539a0dd25aa9b6931c8ec08361c746a33103c6c2322a1da1319db254febff1eb7db4fb52fa699b76bdd47da9de7d9a485b3df79b68458ffc06638d3cd781bf42316f48f571e2955d92bc9204fe8d1da3a35abbfa4a9e8900248f763ca6a2b07397515c83681c8a8fc3ce685c6601b5fb +Mac = fdbf8d54d5347ba5301e40912529 + +Count = 162 +Klen = 64 +Tlen = 14 +Key = 014752cdf65d7380e0d897946067015561d797209d8988756324314e988742affd021c7fafc57e96f498611734cd20004673dcffeecd1f88a303bf249516060c +Msg = dfd5f4c0574f1ebd2ca8cad1e7d372a06abd9f9b318051d4d7d9a110dcdca51ea5e69468c4d42ac87a724e9d7a36f31df02f3cedc238e3ef1671db5b14f03411edb3402d1cd9f4dcec12906f3a5583ae7cd1886f022516677cd3f73fbdf236eabe243f37e6c842a28871d870ae96e9fb158bcd4a78afb1e411e83de65e4c7454 +Mac = 5f86b8f90715e580896af852e363 + +Count = 163 +Klen = 64 +Tlen = 14 +Key = d84e6c821f1969ac78c77295f3fa3484c7d8c783e957dfc0ddb74633cd508a81d88df321ac39b7bd57f971db5a1ad0bcff8d8c84ed309f9cfa50b155406bd4ce +Msg = ce678eb6136c44860d823267a837c1f1ad7e274a395383ed6e9d29aa68583aee73f379457bf7591dc4ea5bcddb7396d6ccbf976895226c28db02fc30dcf19a57a519d9b384dda15dc1bd8274897a49652b7bd16987701c4fc235a27b3ff9e92fcb9f5609186443cd6dc352659b960026337d7d55f683bbea8dffc4937bb952fc +Mac = 326dcd7fd960907823a7538f036f + +Count = 164 +Klen = 64 +Tlen = 14 +Key = 939072ad06d11f98b0ce74f4cc26a6f06117096370e6df5872816dca026455acd6b91f2df3c31939217c61439d7d40420f1fb9f9bbe0627cfb0873f0ed8c1d92 +Msg = fbfd9bbf851189bc82852a1ecaa13908053cc1a7c17fd514c2eb8277999d027279d132bd45a6470ded21bc3bfb738ea2697facc9b697a9423986b5d1b4d4cbd12c452cd4f8a30b8a19bd8ae4c9b0e5785665ed28315bb9fe42a7985b7f394951bd606f4dc6913ff9ab647c605cdfa55475f76d0c5b546b128855135d2354e5b9 +Mac = 91dbf6cb70f75cd9541e7b71671b + +Count = 165 +Klen = 64 +Tlen = 16 +Key = f00f2344b9ffa8ef49dbb623d01cac563a1369760f3757db97bea97a416ae05b45a6944d89d171d8c2da8073db0da7f79a2c745481c21682f2b4acbb9719c3e8 +Msg = 882d041c2a6f0505efe2a66c17925952af30959b1a5a136ff11b3de10db6e4cee19f31080dcbdeb43129a5f1ff71f9bb951cf50e09b3924e454d1ce61554e7307e873e9552459cf501081f48b23039869202a9c56cf0a9a17b1a69e17c16bd5806ec12081e65a78e0786faba5757807d50e998086c96c2323a8b0c1a6984ce0e +Mac = ab150058480efe9b9243bf6d59b1ea0f + +Count = 166 +Klen = 64 +Tlen = 16 +Key = 41c90aecc46fc8e193380e6e147f1be22a2c858bb62cdbcf5e1e88788d4ffa50bae904eeee6781cf804c3ba923150bfb246c41e9ec9e4547cc4f7ff4fa6d7569 +Msg = 922450541fe8fca66a8bcd46913c86fa150b447c99a061cee72d99ce34a16b0aa51fc2d512aed59b09324c71169ba4f0415cd444d91e318070b68f342755a9422cffc3ed803f8d33fe184b5d993e33d4e5871636d99c43a9d3f4a970dc033bbc2dae99c4f303ec1750271131a28ffb4d0773527b218060f216ce2ea7db11ea1f +Mac = f84d323859670d9005e283065a76aefc + +Count = 167 +Klen = 64 +Tlen = 16 +Key = a4660dc15771c06c51d8cfbb320af64ab81f02833377e366399e03869a73d654968ab3a04ecee25d796bf6a558eb5cfdec9e35d966406163dfd6dc7849d94ef3 +Msg = a89fa7f6435ff4a8a12c1bccb2c2371b18d08ed6e7a97412a93c6c54a646915d62c6344766b2c7d143e8f9f8d56723c7c5bfe36f51c6069a508dacfd7092a62cc33723b37a738c62f0c8ace8ea7514a41decbeb7f086f05e8476637ff1fca581d3dbbc61060c0c02adb47bc57954d25a283f66d64b52f9054ddfdb01b1ea5403 +Mac = 2986412f95c26d0800cd6474f7b73c1a + +Count = 168 +Klen = 64 +Tlen = 16 +Key = 1e0a7224fd9a7732bed784ffb60dc1e76219ac3d5986b19080f5fa2d7dc288e56ee48311da15ced3e734df9ecee7cef88d84ab7edc321529614b08d12705f7ef +Msg = 89e8536a4f93a2d3530bec1d411c6007ec24767e9a18ddc2a2c7b5c53a63ffd48a3d527805d0cf9ff80157f763a5fb9b0944b3f1c31c53d21969bcec13e44f654d8aa8c14a9e88060af1121edf613b7c7ca07c034f37c92311cac7459b9d3a69fb57bc0dc706b551b164875a5c5909f46ec0377be76e28fbb17040967795a626 +Mac = ff3ea53d7a42c3f6a4201f1184fa7a55 + +Count = 169 +Klen = 64 +Tlen = 16 +Key = c9048ac659bb73214c18f9fab82df3a4367cec49db17bd2c6a056230c7e8069eafdd6023a7a4421832016f064761ae6a02c11cb59accc6979343777d35a2cf59 +Msg = dff4d77d8d83a4e90cfaa00e95c264b120ff523acc651d20824c8ca2d5077ab82d72224925cb999e31c39c1784d48c1c31d4b75790cbd920e302e339395cfabc93e9c35146b9dea4a0eeb017ce1566b4fdb73665c02ae867b2ad96fc5cb5b060598142ffb7f47ae5a1a465763b2ff95fcece58cc252c53dc37782d5106b8a28d +Mac = cab0ae54a9bab734a5cf637c9678f01e + +Count = 170 +Klen = 64 +Tlen = 16 +Key = 25b0dd1990567010d83ebd58b2d3d5cc65d1d4268cf9c45d1709be3194eb5203ad2d2aebf1b1e905d7a6590bffb6c629bc81a50cd04b7a3d76f1f8ada6226991 +Msg = 7cc9d583f55b6738dae656f929822cbb58dab6a63b83080e278cc1a6585691f090a5f8f801f850426d160d018cea4489ae906a07a1b05f70d50baab7be5307437a401fa0b4e09675c82f4ab627e7da1afe9966d012fd966eee87de2a413a004c82c1d2e3d5bc41b732589680c422f8558f1d32675611b7efbc27e365a9b384f3 +Mac = 47e454e84068af7a19d431eb975a650c + +Count = 171 +Klen = 64 +Tlen = 16 +Key = ff01f88e07dccd198b26b6514be99e43b4336f051076e03ffb2f8fea16c64f58ffb5c37580ed2c4c06757fcd5555bbcd7bb2794e023ac4016ac32c09d72e1602 +Msg = b262bc9da24a1a84264bab4f8915b63ae6e6caa5eb45a56adcf3556ddb1f9d7566d99a3a21c9a6bfd6217de1bad09f30f2f9f5ff55a3b6b774b28c71d716f3c38a42e2d9d9dfaec857c22b20251c14c070f1adef3ccca6a860b04334d251baff2584dda450f5f84ab118fd335262de926ab83b9d27283de4aad7c2e1543abad0 +Mac = 591fb4a3c8a9fac8aed786c23ef3b768 + +Count = 172 +Klen = 64 +Tlen = 16 +Key = 8169aba951a245496ba96f4b1ea38b1f6d945715b678b816918fb692fbf8c7b9b48150eee5be69780658e17bffa881278d849530e859a97ea37a9125d3b8ac97 +Msg = 3fc5626b6525086bcdf2d2b9227ae8aced70422a0b8fbe6d5d806f07c1fe382441389a108b77cbf9a10008f5d23c2b47e91680dea4a5d51e680bd0e3329d86c3d14448945322c02ebd793e72ffc94c8c26398874d438b3bbed64058494abc3d156b01400a470119587251b398f6b71030da101f781927fcc5654b5f3cd711ad4 +Mac = 9f3a6c7855d72d29ff6e5049ad3bca0c + +Count = 173 +Klen = 64 +Tlen = 16 +Key = 9186eaa3b8e785dd2a747297bdbdd4f5532a47b7008c21686ff7f8d881d464cd383205f6d45dc8203bb267ac9eb12f415a5406be1c9fac73497941909dba08dd +Msg = dd1f8be083683b6d471f54ad29cd88961939d15072df1044c49ef476d6b11d14ebe0814f45f70f69e878930fa08ddaea454016713eee830144f94b2f68bea85d58c7488bde41f570a9b075c950e1aff2942010b3e6ac2d5c2968aa14b8d35a6eab3aa73d562d35aa132fc28342b151d68d4287bf7100557ef952d7cccdd97c70 +Mac = 3b30abdc7e3b6fcac25cbae206469af1 + +Count = 174 +Klen = 64 +Tlen = 16 +Key = 37e22c20b9c1a3bb28f2ce40cabca74e10d2e55307287efcef046bf02858abbd564f8a12bd262330ed3d249ba46ed115f09d4ccc949013d3ad01cacf95f23bf3 +Msg = 52023970271f5213b06afac0fdc75598fa824f6794e3e1d61d0390e2f2dd368c5ba804d2b265c8dfc8b46c7f84ebbfd5cd697950aa2879dba89250547d960340eafa0dbde6f3a4b7f8f33d5fe5c252d98bd063350dca3ba1306b74dd05953defc9a05b1709f26e0509cf764a6773950dfc5e17ff03f0af917d350364d4026b00 +Mac = cf3b54ab112159ddb821b49527c891f0 + +Count = 175 +Klen = 64 +Tlen = 16 +Key = 82032ae68cbabf34b156064ee09b032fee97df74ddd445255ed20bd394b415e31b3a762949efd9b9b4a420f9f41c4afbaa099a0ac137f583f3088de78f20bc2d +Msg = 889e0ddd87e6a1163af9278819fd7caa8f3e0a4c0122ef290d5f5cbb0f6b3a53ea3514680512312f93fa006d18f4ba8a28cf42e672135070fe37ce74b31482b41c9aeebb6cc2746ebfc3bee4a2895d77d663b01b51fc08ef868c0912e64f54b8a737637dc4deb3f945be2994c0a4af9b20621e94a5c460cf2cc6d63eb104f786 +Mac = f657a0cb3e47fe3a6ca54ada6f95d631 + +Count = 176 +Klen = 64 +Tlen = 16 +Key = 2187b7301623af26de0d6cb90a20b2ae177389fbf3cfe3ddbd668025ccc10fd2f4fb96e5042d1371932964f2fd6b64dfa84c57838c798808f2a430d57b799a1a +Msg = ae88c3a96652d3764a00f8b2d0027adc8a709b77fb9311b3a9a7ba4973df8ca725aacb4d4a357e77423123fc94d6a276852880a3e979550b392f80e3e6c71932ed1a2732acdf13f9f3725d585fd48e04e3f26ef3a82a7609170b88f4345cde552d60412032597b45884b0e90d90226cdcf56cd31e1ae5ef56cc33c4405a7c357 +Mac = 2498d552d78ae3fe9aa7379bd54b371f + +Count = 177 +Klen = 64 +Tlen = 16 +Key = 2d0228f6391876a1bf364ad64e3e5398ae6a31182082da83e6533d1f065c26964cca62928ea72389334ea6dbf622121ae87fa4a8b4f1098827a40b6ef01c7018 +Msg = 068780d21ac0c389b9d103ace6c4f7a7ae85aaec093a7ce702d26a3317e1900ee3abec0afa7e650615460c5d6f5ba15d6e9d59fb86c3dec45bf0981725872b92594141ca867d893f7cd7008fb4fb6fe9ecbc34c5126046d2633e7430d48cede0b17205798462361c38ac65a97e4d67337008c4b274b9bbf864e586e7ec95dfe0 +Mac = f94e37efd3372c418140d2ccf2a360e7 + +Count = 178 +Klen = 64 +Tlen = 16 +Key = 36fc6d3c189a094a88be7c8d2dc4cac84e29870f4235eb8727dd296dd7e7fd5a184f84c513ea51c90849bd283fe07e9142677c1e4981e021f69c6d204218131e +Msg = c3593383ecd41eec6f51dd4ea8c65d7683827f499cc163fca57ee68709886956ced8d542c022dbc1ccaa8159aa59da5bbf1014cd413cb9a89cab2e44149e8010ac1f5f8647946b5e0e95af0211fb6b433139174a3df0a4d15bbd0593aa56ee0025d5dc36cb53552dfdb9713127d39996a2a68fa7d904aedfab5d745c11d83d90 +Mac = b08970375bd745dee747cb09fddc8c79 + +Count = 179 +Klen = 64 +Tlen = 16 +Key = d07c9eb81f37b4deabd556c4d501130cc70e833908387f134d2d914c93ccaa636a2c13c994e0a643ce793e8fee4d6c4a2e776c11c81f57e7c3fc99d60c16a6d9 +Msg = 85cf9ce7e47e7204f0738c0a234edbb595d9d72e2096c43ac29a34b2449ece3319544d1689f7cca30f264081fff246716b361f3d4827f8eacd2b6f351cef543e24b3ac7ec6e9fcfe36ffc4cba57949a51d4297f7ac44c70cc4367e7fe2b5b6f36e97c105e27c8a7f2fa51fce5d0a6cb771a649459316b80670626777de1b7dbc +Mac = 5d3f772961dab87c422c1bfde1a894c8 + +Count = 180 +Klen = 64 +Tlen = 20 +Key = 0ad08872ef79c940188935699564f18e5cb746e78daeff1ffa681265e6a883c00dcd86a2e504e4c124bc9f22825ad976c02ef2aae9a6f1bad8c225c6fac80c67 +Msg = cadfc1a687a6b436e1bd3f6febbf197841a6ebaee049bd443b24ae2c8b58e93b66f2d48893708b151d828cb1a60db41cfe756a6df41c1ab16c26e5d5b28096c60e20d8d6998ea7624ea305b16490ee20dc238d7c5646b0b028c97aa0b1615754ebf035594006f2649fa81039ce51b0cb0237bea5adcf69889793d6563003152e +Mac = 1f60fca9694f8254778f18cab6c286a04f89b371 + +Count = 181 +Klen = 64 +Tlen = 20 +Key = 5988c794c1f1e85d23d65be040c0129bb8a6bbccd86c3b1eb3a9588774adb571f2c3041885b37733198b77d6809f99970dcfcef05e08dae4790e07e51b781af6 +Msg = 40ae14834214df6bf11010a32133c6637b9b79d3d7c3807aed9fd6f92de91df9ebb6e362bf4c25cd2c37113d7f9a1009fac4041d3203ce63b6bd147bf1bc41b252cacd32aa7ebe76d5556f019c049050da0d6e0dde9174851165f25cd8681e7fbc13595bc951b34d3391b059401a4d1e619f3e09a2147aca45c0f904aa92bc49 +Mac = 25c4de6c4e7053ec00c29d0e95b51ccc78c1f110 + +Count = 182 +Klen = 64 +Tlen = 20 +Key = 67d59c84c2161c77d170c1b2de4e55ac14846f6beeed8c4aef5261f9948e70c587f0da1a15e17446e2c71c7fdb294e286d13f250f4bc787c776627a69286b285 +Msg = e4e7ccc6881ff706c3c24f7a35428fbe9cb4843c48791ef4cf1dc779017ff33c1e32f90d472421df337dfecc23cafe59185b3ffa43e9a4d9bd7d29d3788c73c37667ac0438d38d317af3bc2f1d6f596e65cfd36b6428017ab6fb6ec26f5af489524c8cb24473648300ec32ac0b77c985ebd8e998947d5c5f23603e4fce2f9d15 +Mac = d9da4971a753bf0d6098915a5db51d6ebe719487 + +Count = 183 +Klen = 64 +Tlen = 20 +Key = 24e41a8aafd3e3ad12886774fc48e7f4c26778b752689f046a661d6107b30c571fbe2b75923a77985f7cfb691325e8268802e8a6cb30b0975e84d40ba029e033 +Msg = d8cafc4115201dba55a30ad0b7c9f34609f73945df452443e282d8296b7885b45170df1bfff9cef3c9e666508096192e43782b0f99cd67e5bdb0113139541b6db68e9ba813937d70b40275f41d25386abf74ecaf115add2de33c7102f0b85e5fb22a1a2d7a7594f7bf002104b6feb9c324f3636d7173eee5fd2de2e3b729b651 +Mac = 1f8307f4fb9117e10d1a9cb3e46209abe34f36cb + +Count = 184 +Klen = 64 +Tlen = 20 +Key = 5e89370f90e49004ee4c0ea30765da4261edc2446ae7d453b1f82ce956110a15c04e287c8d1e4a9ecfa5165a755e26b407055cd797b47556f44ce1b72016d232 +Msg = e939624b5903f7f174c9a23af665a4f5c635b095d672f2294bbd508fdffbf0e48363fa3e48d59f9e7f6e5a201f59757568e8d093c6e3deabf820f05c7153b626ff280221aa8fd0efdf5784efceff72b310c9a3b58d0fd6459ddac6c66db1ab1aa5af035b47d992ccdaaea80fc9ffa2980600b361f2a0e5df81165a3699bcd8a9 +Mac = bcb1ae27f88ea645eabb0831ecf79a33e96c7747 + +Count = 185 +Klen = 64 +Tlen = 20 +Key = f9589585b06af7d3a9147cfc4445258e22293e398afce03b0c21b91b646e0f9aa1cb03e786fb131230b9e3c3f9073d2c9dc3563c9b7b5315de820bc19d430f20 +Msg = 6af240550657a89df868051711bd5c481b1152d37451ec35fcf39ab23189748f9996c38261a0c3674386a734ad14de2f1fd5955fd4287d40a696cebb2c638c54256309a6190fab0c3dd8efa298bcae6c64169fd4b7ba1e5a62412b8719a2b622d5031aa777cee7f5ae06e4471adc5465b27d791c632f57ebf99cbaff436d7a62 +Mac = 2da98cbce434bd18dbed164a287db33a557a226c + +Count = 186 +Klen = 64 +Tlen = 20 +Key = 72a2392e953e9aaf621e5e741f068b7d9a190a19b24951ff18123f99576847a312eed1f58d68dd9d7073ea31c77416644cce86d6e9580831790ef771cf066083 +Msg = 3d6f9ac66786d1eae1a7ffea8417e7cd49b96e355fd44f3f7a150fab6dd8343dfba3b262eaf3a6175a3c4607552b18f3a72e6357f036e44bf7bcc1a74102c36ae39bbf5d942d55f30676dd74778d9f5a836a42fc3ca988697c8b38977a3e5bbd9c5eaafd8cbb48468e5dad7911c5e2ca8376f46a6ab4a363b18c5ac33f1464fc +Mac = 811abf01fc132bad8298368714a4ee061b082af3 + +Count = 187 +Klen = 64 +Tlen = 20 +Key = 35c488554f2e59f57cc580fa3d4fbbfb60b365b9315e49a5efe5b4a27decce0b5a4629f8d35e9bbd77d549b4cc6c053d4025da0262a5e48052dd65c376e91670 +Msg = 6a832bc8e4a7481b2f3b713273133a210584b48795ca4013a9a7a0474a4d547cfc7e2327f4f2f85a86f9ef8edd61b09fee9afc18ae1885b183f90316f9e884eab741030cb1753d199fb1c032adba45ff741c3ff32983b4d214694c7144f1a8be8213f4ff83fac05f62aa0ba64de6a1487e51a8a16cd3757f433ea4e1923267fe +Mac = addf167d11cec391fdae6081447a2fe99f1d9234 + +Count = 188 +Klen = 64 +Tlen = 20 +Key = 9efa7be8c7e8b472c653802b8a7af2646e5ed356191ca213a279d9bdf8bf72f682c8aa97025805a5bfb09281e35f705e225c91f89c52be84053bdbe203306d1a +Msg = 4fa7ca50a4e49c7b78a5e05b14623ccc707d9bdfed267fd9467c987fc4f49591b2ff3a9511e7b3d58dfa28abafeb91fc5375cc035d41ec50a80ad5103fff068ed069b5fa5d8d216a35d4241e23290708e5a39b8bdf64858411c1da8747a3ec6b8f2c6308f09e8f3f5979fc3bd8e447f70c4e3100dd55f27d6ae7d06c43a7ef2e +Mac = 8bd092638a865fba788945cb89117da17f9d1c9e + +Count = 189 +Klen = 64 +Tlen = 20 +Key = b59c4ff10649aee731e0e29b61af936d82c5257954b27876be8ed2dd663d194e7ef04631e1ef16995e97026d539e72c97e9f2ea211d215a9041a1172af464ad6 +Msg = 60aeb57c867bd2d79c0318ac6316e573c8fe2edb080fc204187fd3ef4478b233166cdaf179a930091e2d898e1fbb6d78e32e1b99410eccd3e8613c87fec3675007b990f20943888dedb02d1729b631089cc21d57b98d95a6e8f0ddba29f99c2dfb3ee0677c7163cad1350d2dc830b98cbc623cfdbab5a3e6e1d5bd6e0f41da31 +Mac = 51ba90ab36be007d0d03d9e0669e55ff5989a2e6 + +Count = 190 +Klen = 64 +Tlen = 20 +Key = 1a3560983831aa42e660abd0c27c88ec9ca52dda79567b08de98a9e74b76e4fa05b0392d18b4b5679dc9cb62398ef5bbe6a39e45f6a640a35561ca160e414493 +Msg = 70cfe1caa198af2199f8f46abdd4ccdcb443c46310a09d4e30dd4d47641947895375fc4d9a24a285b6c234cd24e7ba9fc6fbcac6894c4f15455d8958e582558bc7a9af4a667b758936a46d85cf6e8afa4e956b97f85725af21ca42314d720ada941301a94bc4b094e045a8790692c55712b8b0bea5e8a7848cca81bae413ecde +Mac = a1db2d5f0dc35abd2ecacf4bc905b3ee8f184c7c + +Count = 191 +Klen = 64 +Tlen = 20 +Key = 370208f2b2ab074fd0eea5798289fe305566a2d6f5133880f072674dbdb2f6f7fd7d31a700738f0e8bd893b1d989f084df35f0bbd5c916ddf12c031a762d96de +Msg = a34f04a6ae42324c730fb54254602316b9cf3ae260f1cf74f59308ade343cb276913761af099d1819c3a417821a93ee9d8aa0667121c935aac36cb5de311f8e46a667722ba9ab42aaaf756543f3db6e2c55996e31e7410585b2fcc96892d76ebcdd36f84b44bc38ec4cf5c9c57247549a964511e2f012cb62a07721f7da12f84 +Mac = 360622720de4a8a37d5e1784504eb69e4289a935 + +Count = 192 +Klen = 64 +Tlen = 20 +Key = 963a14a34f36f0e54a3a40224d490a1aa1d50b670ce14bbeff63f5720fec6639a98a843302ee51284ecac012327dc7db7bf2b56710c5c6d525a8f402b206114f +Msg = 55b3bbe88477bb46911f9777f54d3c3eb6046de74301c4379f4ff39fc21650b43db491e41c0ed3611028e262cef4b48bb26836a9a8d34ca34c7112ae503d69bf1e06af46bfc5cd19fc2e77aec385af8eccb38b067b99392009a440d2dfa2087442d49d773544b0559b58dfc49da8362f4b0df56686fa93951d10047336ec38bb +Mac = 645d55d02c4ac7c848358006217750cec5fb07d2 + +Count = 193 +Klen = 64 +Tlen = 20 +Key = 0f169ddf896b9367f6577af0e143ea433e68097d09e152bf290595289af53f00cb71dc3645f0da0d8eef90124d897f51ae48d7c8083b3d1cbe48cb8b63c45822 +Msg = 48ad403771d32d92383812e76c3d5b3f06cae163ba931a40cc9a8c9025f588b7a6d214ebbcb8299835101f0352e3652d1de575fafcb30792875985089717c03a9f65e1f84034a2681777bea8dae2a5b6a3f1758d8b2d26917bab042d3fd563bbdc6c8ea424ce00c88775d7202cc185a141f7c9648f89de055198f24946b7d903 +Mac = 17a5027efdc13efa2a72faf80ceb4856d09f00f4 + +Count = 194 +Klen = 64 +Tlen = 20 +Key = 663c1d41ac51602c10f835907653c1533c13853e15f6d5a7158d8b4d0843fc83089b2b914fb93d5749242d33edcac1254e45bd316d5c560552cde9dc5b4aeda2 +Msg = 3117f325f1540abae5a5d177b3693b57fe052982dd8882148c8b8620625c5ff5035bf99fd7a314b1bbed9842f6b228366e90f9bf1cefe522bde4bbbfca56da4cab5ffe6128f4593920c9e6b77d6ffaa767bf1c47b87c1605b0344c8beb674df98feca871ca8f01d97cff63dc30e8d832515c37229b773e45cf43e08cabd9e084 +Mac = 9776dfff1526fdd68a5b44db0abc1ebdaea1afdb + +Count = 195 +Klen = 64 +Tlen = 24 +Key = c7341fb618ef2448c11c6761119ed19756564c78f6e97b72bbc4a8f06f5efec6a9bdf8cfe63c19d4db8bdeb00af7f1b294ec9f434eb88cc91691a5cb68da5755 +Msg = e2df37f750aadc393a1d30722f9cda3dafb6fdc390faba2fa10cf7628ef85fe703c5aa29144e1fe3dd4d57d965b943c6c9527195967a8ad3764620650fd5a67628e0c0b40d93bebc359b62d22381ead68a364a73b4efba9a2432702f7b31af02985800000322c0ab8c30dac72f9cd6563b8b13c7b401506bf5fa712899b68071 +Mac = 0a94e061e965f1098102966f5ef8f031076b13d8b5b362d0 + +Count = 196 +Klen = 64 +Tlen = 24 +Key = 7d4085bafcc14200f7ad298cd0ed4cb8c9c8a91c6cb3ac022a6af61a423f5d70e4b2349a9643cc36d8843a9403725baf77051662f506e1d84a2187452e3b28d3 +Msg = 192adf7a2791331e995ca976a8365021fe666149b6f6d0e0831422292fb87e7b4887064216f86846cfb5af300e44604a82e6c286e3bf7dc22b38664a02a29a9e7a1cca76fcb6d50483d69c7907db12ca3d0192b47d8476fe0309e5fe5b39ec5e17afd020c314a3e01b8816597b448e2b967e7adc6b8de31c754e444d22c69d42 +Mac = 0d47d7808c1fc2d40a5fb67f75b0d554929e4094fc45ee88 + +Count = 197 +Klen = 64 +Tlen = 24 +Key = 54817791035e6770974be3765cb8ab2f3e2e35098133015bb26e27a5dd0b321a0061305bc0d20a865bf3126fdeeddb2d98244dd9ce16f892b085a9c48cd83baa +Msg = 739f460034249e805aff665d6248a594250695835aa24cfa5d9c9b962f7d374abd0d163f65c51cdeb687f72b778d4854eba00389548a180fb6cd5390dd9580b6a1ecd4f8692d88b3eebbc77c42f2cab5105e425e252bf62e2fddade2c5424ed6a8a446d249422a268b029df9c96075de1baa19a8d56f2d8051357234ef6ae7d2 +Mac = 28447efb984969993844f511cf43095029cec9817466300f + +Count = 198 +Klen = 64 +Tlen = 24 +Key = 30be326c2ffff6d031affdab0a27d5a8cbfc4ba9dec626ad522615f77307e56d9e23f73e53c9f2c78cdeb5b84d2390727db5b3b4f4dae677d5fa7b161eec81b2 +Msg = 811b71ee28dc485b4978b39e38c5c0d99c9b764cc5dbc47840b0b884a815f2dfbe985727bc5d0a4ae76598eb641072074ce1a1d80382b5f9c508fecc8177ff19eb8920f7cdaba3f09d49d960554b961e7fe0e25e8f7af1d6761a562074cd73602e76342600cffd9694abe0c6b47e14675c1ea2a814cb62577c6e2649291e35fd +Mac = 4b98864cfa1e3e9f0a20ff8d55046dd39f9c7d2b529231c1 + +Count = 199 +Klen = 64 +Tlen = 24 +Key = 5bdd951e212c0016ceac37942d439161769d240e80869280329825ad3b171fa002194bc3e0ead85d8eae675ad948634b9d7b91adf04fe86e9eb7a2add67093c2 +Msg = 8918a388ba3778bb4f2abec7d2eed59c430a732aa40a4773bb2fdce41365c1e54475e7af747c4a5d1e9cd34612f17d8bbdc7b8ecab0a0be04afdfce4f12f341320acdff70a70529f5021f0f110fd4e421e11952491ab287f821387e41076741da723540983fad7a76f20db70d3f88eeaed4fd37a5fd7e879ead7458b7920c72c +Mac = 5e4d02a29c7a943cb82152f12c8f3bcca1d6485a67169fe5 + +Count = 200 +Klen = 64 +Tlen = 24 +Key = e5ffcefccfb2a4ede3ff600ec5cce30b81c4b8901e9f4ab177a4548a466c9a2282e8d796eba6f673e34f84637f75660cde8bc735b935552a3cc3ad6214f71360 +Msg = 36896b611dbe4e72fb3205557a792657885aa5ab57cbf802a71e785c47750b1dd97b0063d7563a97d3d7914203f47522fc79d47ebefa3eb6f10c481e6eb52e0c0120bc306d956e24b1a9d6448ab23ec0397e8ff0864571e705dbb44a982aef6335e06671ea6531421e109b04199ac959c7d39ca9b893d7bc6cf48588cebe9547 +Mac = c0d0df073b13a42978688b607f939a0a7425d5d53ed489d5 + +Count = 201 +Klen = 64 +Tlen = 24 +Key = 63baebe7ba9dcde12c626b840ea04f42d878646970ca5bf7aba94eaf110da36ce0c834b654bcac93264a349f520e505f1ec903d3589e3a4adf82687a65ee6dd0 +Msg = ae3990d3a028b8c2e85a45ea39442e7dd4b64efc0756074af34d2a0493401b15fa823084dc885b91509d0901d4d649b692493182e27a7d3d0f167a155ee423264cf8894b182a783381c657b7d185506a1abcb172c0d4929737fab99a0e17bac82d0362ce5bf656cf033ff8b437388ac4f5799674a94c8d80f461ae3aacc32922 +Mac = 6fa4f1c4f2bf6ac311d62dd501bf9f3d256218d742de26c4 + +Count = 202 +Klen = 64 +Tlen = 24 +Key = 097abbed69ebf2e5e87e4ed54fe38d10f32f4073962ed25088fac6ab11cc40a91413c745ecc349459af05f6c229bd3f232cc603105e1b8a18725cc06baa447e8 +Msg = 6b6ae4c62332005311e3b900c1eb99c0adee7f7d5e5dea54d44a7401287b9d9870bdca77e37a8e783e8e276b66574cc34e0b268f1b4f9cac8605d3398265f54c1f4f32e3afdf051e2743b9abc8c92b81fe3cd1d18871fb39d91d593cbee9beef42c923f4cf89efac95a976a92f6abf6284298a2becec9164953b0ff024317fe9 +Mac = 783eb2c3d5a12d68cd2e458b577fa597caea3de72ea832c7 + +Count = 203 +Klen = 64 +Tlen = 24 +Key = 3f83b0add6ee237b3e852d2cff01b8d07e885d7129183399f529e5150a8e08f9bc9dabe4be8f2f85922a595e449da5c858abdd38010bebc0940fecd93b85855f +Msg = d31db2ca6d718cf6f5f202ee44a15ce68c7cf4df98ae9b7b55033810929eb2fb04ee10378ddedf2ebd4cd4ce9abdb3e09c4f6f95fcef93622fcbe00ead0a380af6bbbb00d70c2faee9bda5f55cd4592df291dbbc4ea46ce76f9eabe878a67140b26df94ed3644421812cbb8b124d1776962c7e7b1737eeb11f63dfc37bd82446 +Mac = 521f5512d38760fdd4a8fd913404f81010561cba59259e9a + +Count = 204 +Klen = 64 +Tlen = 24 +Key = 21387e7ac80af39836a7a52bca4403b19ce80b01b3cd1ad3790903826b6d5f1115ae256d3ec27bf1608dcb2f5bbd18ee69f3936f552369f5e83de083a50da2e8 +Msg = 73d82ae122e20e76ec2d6dd0acbb9819bd0d540abadfc449881290f697ea40806479e9be435b0c3b5ba4bbd1f217fd79eb9974618ce53d3f858018e62ef0c9161129be99a848f18b688310fafe60dcafd826cf4ae7910195a3ca4c125096aed680cef09ada0f851019b2b57358fffb628c9dabee524dd7f2ebd974a38446b967 +Mac = 579e9e98b12c934b8429e620213b6c4e5bdd385353d6f431 + +Count = 205 +Klen = 64 +Tlen = 24 +Key = d6bbd3a880e3277fbc24c0e15081a38e856a8d2020e2874c94e1b96576f783213133caa0fb4390aa08dcc839fd5d6837a7afbf88ed6f094b034f415de1b9361f +Msg = fbca586edfa57645037b6b3cd70fc341e4d4ec97af4b3dcbe18b36e9a6210aef531b5a824b6044e023439c16045779735184f43c8a5a2ca171a68ef06b4353092833491286eed76cb3fa3be592bc172f618e2c91981265dc14c517a174d787a1c43aad8559f937cffbcbd1114ae8a45c5a1b1cfca118ef6213115b628b84af9f +Mac = 0033050120c3f75ba7f8cc1aec9e7bded311ea8192733204 + +Count = 206 +Klen = 64 +Tlen = 24 +Key = afff73e06db8ad3f67c7cb45776d99d9fc5d8dee2cc3b6a7ac85efbe5ec958267ab707efe080fa6bac9f508f0b5fb99b4e9d2cfe3dcfd873ae455c7156af3ac2 +Msg = 949807776398fa06bfa89edd2dc94027f8a62e0e77ca188a9211bc76835cc3e9da89e5c3c4a354868c55586862a536a65cdf571abacea6106e323a56dc6f3592de83ecd80b3a487c39a56c2540c8972301934c03a714b1602dea36fc21fd760fa76c62dec0c79c90cc7f213d4e9a2b49f0ab56f0c7020121d720f790da6e4f07 +Mac = 2e015ab68310e33ce7e8c72d7c220f2c4b3b4c6b25a11c8d + +Count = 207 +Klen = 64 +Tlen = 24 +Key = 9f63b0edfaf83bafce6c4e680bc075c7b3baf15733e5aea7f3d975a82cbc6356fa099a9ab290366f75bf8345051f6da2d821370f6b1b7032d98e2338acaa4f76 +Msg = 2562a463423db58230d8f6cb72f826cfea46562b4cf7fb53d3ac428e3397a342cee0b9722a475185a30ac1495d097b377d28e1f999f55b296c8ba75ccfb6715fe55724c0950aff903d076b68a4468caa31e716095bd0624c6198c14e3ba4104ad08f8c5569cfe82c66969d3030f782af6e4a9c657cd13743189c356f5fa9a78b +Mac = a6287e00b8ce0177baf1058c9ed4c8b1c67bde350701f49e + +Count = 208 +Klen = 64 +Tlen = 24 +Key = 2ae58425f6d7ea7b983e06711bcf4bfda7dd4eb09a1e7a98d9b20566696122cc3925792942e8d468d28e1b252536821236bd019ad48405c4f8746559563f9749 +Msg = 350fcedc3d2d18531b0c4f70bf6c840f662b6e1d19b90dab77cc8c40b5556c74e3b2dfba7125727ef185ef701e33821f1e501ac9042d1271990311335ce52fd5c7f2599ed4cff66bc055caff0f861b9bd0c613ce2248668ff7c63589187531b66a38032f6f13ec430fe3a8c6994d99ab05f521d67cf0502b1a7bbfebf2edbb40 +Mac = 6b1f938b50c3957dc200fc700358431046376d6514d0e753 + +Count = 209 +Klen = 64 +Tlen = 24 +Key = af369d9f65607b33657058b3d6832d4c09357697ff15d7b22b56059578c7e4a38e05ed8051eed323ab5a662c8c06b7772fd17df19e2bb7aa78ca932cf29e8f0c +Msg = c782597141b52135e34d240df67b9bdc274f2d41e6866e0f0da3a6fec241d3a09ea7f1960f9d7803fa7e2741a58f00d3d58f949b338f804df4043824b91b03d4b44c47bf0d32076b849aaa3457dafe3e66647cae959ace1a72e48e3d180051f0539ae456041dd556c7c8354ed4049d0523f56fe2d44f5e5ccd6b31b2a59ac3dc +Mac = aa2456458ce5f0bf5944f36f997aba3aa3121faaeff8426d + +Count = 210 +Klen = 64 +Tlen = 28 +Key = f3aa51ee90aa06e98e2388df7a3af2cd697f2a528f2a14140da405600b4a7b10076d0bb26c9d9ae66727d008f6dcca0f42140fb52ef3c6d930eb262160822de3 +Msg = 2c070e5eb0a7efbfc40b234314c055fc436ce1e2300539b3784287fd3c4f947824c5e89aa3d933667dd4eb8587c33797ae6f0ccb3b8f95ad563dd940c8a7984d050775fa69d55b9ec23a19d40fc94fcf876a8eeddd96bb8ec3cab426ad353691d7b4ffa789012f119a28f45b333a6649d544b06f9d8271fcc7d162d7726338ed +Mac = 695c328dc858a46be7ac8b8debf58dd9a9bd72d7a408a43e6bbc69a3 + +Count = 211 +Klen = 64 +Tlen = 28 +Key = a27f5ba4a0d5a80cb4ef9bb18d4ffc4ad487680cb5a8f6c69cfe1b293cfacb67d670e101b803c1d904dd3c8fb2a3b40ad8a78055296091adbc1856d810e5deb8 +Msg = 802ed28873c2160562fb9162246b60d75e2ffb8cecc5bb08831e9aec94f43be1735e2acfb8a26450e64a1a644a7ab26626800f3e0fad12d9946360d620706682229a9b076a7b05e0d690ff902f8c39944ef2009683e2c0e33733c71fcfc34b38d40baf9851f7029f7df4c9509a4afe4a1dac58fa0f0dcd10b3b6562f6996f2e9 +Mac = ee63e86aac85f36961d697451288cf780041eafe462ca6557035d92a + +Count = 212 +Klen = 64 +Tlen = 28 +Key = 489bd8b1eaa33c50e65f35208b752111d3896607e6b010e9e027bcf4d445b45611ae5bf8a4cacc9b1e75be2697f8ab3ef2383118632eb88b2f97556ab3edee10 +Msg = 4b2b843db0ae2327dea304821a4d31bd65b55b52a34222f9fc89911d8366e88c154c9f7284d9a788f5aef389877d37e63663f0bafe79a40043a66b0470b7ae17dfb12f87f96549ce9e467a0ac7781ead69297d769d2408a0ffa3e059536598756f013c64557a92619f139fed20656d7cc8ae0c6ec86cd740f72bf804749b2f0e +Mac = 5b25f50fd3ba3f628058d49d28cd6ba02fdda45d842d935ff9a8ead6 + +Count = 213 +Klen = 64 +Tlen = 28 +Key = 21556df80e1bba77a079a3f3c86ebcffdbcc209ee53c62604182c7ce6602b20804835fad5034d4fb9bec15382ab69850428df8bf8264edb1766a7c68688b6bdf +Msg = 908049137194295e174f2a0565dd5737dc8a5e3fb283416224e14f060de3531ab67b0bb1f00ddbf06073c32b1b448f4b73564d73108104e342a6a31c95f03844a65a62cd367209527d5c4cc1c019bbbf260ac748c8af769607b55c452230c6b4082538ae6a4b1a4a1512ae0f7fe5455c9facb307029600451c1560cadc2a6531 +Mac = d6c24c2c68c3c879b141677702852fac78c88a39701de6bb8a466fee + +Count = 214 +Klen = 64 +Tlen = 28 +Key = f86fe94d5c6ac0accbb652d7eda9aa7559cf380f098ddbcf0a043f87783869f4aa729045aae32fd7e88958432f574b9ad79047ef3d74a016701e12ac2dad5557 +Msg = 8cc53f92c6522670b1408bf15ef09e97131b7e12920ba1119e0b7558bc1c471237e9656966fd7f55313453b1d26f8a94d98cdcde73967b11eb38af637178bd111ba20ef529818d5b8dd55111ab027cbd5d0663733aadef87180843a0cf1b9e0e40d6835e9647182bcc0dcd3770103dbaa66f59f96fbac31b2b6278385d6db2b4 +Mac = 929a3b33729126cea761fb2d23baf40757e77e0b3c5536dcceb68433 + +Count = 215 +Klen = 64 +Tlen = 28 +Key = ef6436a16eca9ce86c952e93853e9579c2fe353dc83203d34f04963fd64880a095a4de6eb4f42e00baec615148ff31030780b5a4df0833316a1735d8a8fedf02 +Msg = 981fd487f05d8a56eb6d92d5ea41e8a0647f6aabd0d3de33c68a37f4615d149de78a8a81ac2a238f33be2684970b195f292885155bd5f987dd0e51b105e03824747cecb6f78a4278abbfe9e865b2f26850eb90efd83d1dffc7575ed7ae9508e9871c838e9825edf99b9962691bdf7ba321f114a010b65383ce8ce6ce24238bd4 +Mac = 12c4af7d38c5918b7bafb2200405284cececdc950c96d518ce719149 + +Count = 216 +Klen = 64 +Tlen = 28 +Key = 1e37c92da48870b1f34c55ad3b01d0ac2aada00410722d0941630f80bb96d457087afe93666b4c8926843b5152b5cb78921586f55079bf5e1b45185c4982475d +Msg = a0a26f7c2915247056bafbdd707cbebaad906079bdb53377a0ba5b96ba41832829c4cf1056d51123caaa3fd544d82511085f576879e76a6eea496361b251700c7ec3d6ebec9b2b905599c545e9fd72f302906943b2e381029edba1ca106d78df47a76e5712f0da7e9d9075788a730f28432980518f32e2fb6479fd19fd1e0368 +Mac = ccd42b2d55948e4db6d5890d4de2d81ac07eda4bdd9af5fbd2a58728 + +Count = 217 +Klen = 64 +Tlen = 28 +Key = 28cf7424ea0c7a23fbebe213ee05f9e18d4df2c1cb397e73fa239dc43eeeb35742ecdea529ff8743c8ff3764125cac9ed3052df1a2881a05107ac7b326198ac7 +Msg = e1b8c070bdaf7b9f4af22f4d210b4ef462e52679ee31b5b1d609be2413d31c11776957b2e37775c0bb24123a97f4b3633bec580acaf8500d368b5120fb85c8cb0d596eb20e6f1c19c5c7e0a7cce0506a88d81e1c5ed4eda524a263e0d69d80a28bd12ef9a76019b15125c01d2896cd1431efa139148d347f89971ced0de4eb9f +Mac = b69bedd9579b153abf6ac39cc57ea8c3dadcee5beb2cc1edc1273c27 + +Count = 218 +Klen = 64 +Tlen = 28 +Key = 5ac29fb59fd217a02b843ac93af83de2c70b1856a11e372bc11a732ddbb0424933e62a37b2cf7c5c39993eee35ce695974d355e137b5718988243734cdc05f0b +Msg = bf9495439926c34fedfeff918c3a402ece61400dd799dea0191bc0021ae53c4378ae79002a1fd13608407a578e31669edd1a67a0026497257b2af735f7ea56765e8175b5115668c273d53f81a81fe63e9dff4a414821bda2317e9c5f311b2fac79f3d08ad731509b35a39635636c89b516f93116303618c24101f7a74edf8e8e +Mac = 1ad405970be21fc9fa8c33fe9314afe360a0661ecf003c91f40866af + +Count = 219 +Klen = 64 +Tlen = 28 +Key = 4c853f110f6756d8d30ece69746f17857d7fa5dea6a4962c9b6a957dff78feccb1c242d64e008e29f75ea77e54751948d87a908d47b586f576351e2153c3503d +Msg = 991be73817322fff280eaf82d5a06656b43d2593c4f197d09917804eb926427345cea57adc44d76abcdab2442ad23e81157477bbf65e50abfa1cf75363f85b7c2b13ec63ebb5a1b0fce240a7dc2edaa2d3d294bfd6feaed6ab71bdae4e483b709413425b0e2e95ba304fe013b25b41a2377e06052d7ab939f43f5ac542bdeb35 +Mac = 0851e4d1258b19c3c5477318c3d8855f06391569479005d0e655250c + +Count = 220 +Klen = 64 +Tlen = 28 +Key = 62453baad88ab1ba96d0a3d2c13214fc101c0e248e008c6f9b4a98cf3495b1d5751f6fc65c7a6af0d085573ee29b740b520a273455c7e171956049e57a3197f3 +Msg = 67837675e67783d472152c943ecdedd43cdbe7bc41d427b6647f2bdaa7e7a2a9d9ae74ffbaa402436198afe1db6f9ffa1573bf5afbed05aae2f5f9e62389741209dda729eef26057a06a89670a9bf17f10e2500bba3985f7950c21215649290ec1b718dcc9882477f931c21012796ccbf6d0a2b8c4e32f05456dad7287504b04 +Mac = fba3581bdb141fd22d202d4ebb776023105e97b9144e3a167a1b6be4 + +Count = 221 +Klen = 64 +Tlen = 28 +Key = 0a43912d724324f1ead5c066f0cdf99ee65758cac3ddb045092aafd4f7cfb42cffc5e0b47a55708d9b354ad0a1f4d51651970e3ea485d96abda0944b1db5f29f +Msg = b87f15c1e4ba6af00a693352f2c90b23b61c7bd8c69f1eb22ebb02941c7f52129c4e32caa7d5ebf75c4048438dae40dd7de2d4cce83b3b8344e63db54752dd6aa9e43a532bedb75ad8d95a7e8ba972deb1a37d13504748c349865873da2f899d66aaf50379e81742079a31aaf4a1ea4dd9c63c5606ac8d9dc3021c78dcfd9fd3 +Mac = 41396e958a823fa5ef3919fda45faf13206c8af057fc828cc7573027 + +Count = 222 +Klen = 64 +Tlen = 28 +Key = c87c7209ca26a717de784a9f30fa9979924d7d77d60310e07bb45c208d4d66bdc6ac6b8df96a6927b1f8e19715eedb560e9f2c79acf1f428c66c6a52e190dc9f +Msg = 18b13b090ab6da6880e0f48df80814aa6c89349fccead3c1abbd47da39c655727160ff4d931d9d35d5ad2ffa5501f2b653af31559d995e554aca61cbaba030a77f30a03866e67bf3996cd270d7cd94b5a3db60b7acce981e8d2db749b6f2e492aae9c7d36c599b2933e684f765b6232ec3d368cce1d0a8a3dab0f05c410398bb +Mac = db02339896b4e308e8bd49f40bdabf48987219626bf18dc94312b894 + +Count = 223 +Klen = 64 +Tlen = 28 +Key = d5c0bff07e61417706b9ae14be200a90df3d6e6a7c2aa31cb4d3f0a02c9f2f33bd53265969331521946a8caa70ab7fe6ba199c9ea464dcb6123559b308cd5f7a +Msg = 67d6969e607a3a3f12e5b8ce8f2ed5c5f944db1ef28ea41653cef431214b0c7ebd2f7b1c5a2e38fdb468eeea009197c71e4f4c1916e35bc5c20c9b1ac828fc12cc9d62d5e377b47f4a532f23587b0110b1521353bdf3267d581521a6cb32a9b1fbe8f3d2e19fd64e3a6c258280353b271816d7d4cd042bc47db02fda12ae3be2 +Mac = fcfc80af1c6fb95e28f77a96cdded3b208b69c38a7e04bca2b6ecc8d + +Count = 224 +Klen = 64 +Tlen = 28 +Key = df75538a5cb4b34dad341b9b6d32a4bd135f0813ce35a906b48ad53d1c6648144812f24a4871fbf91a9305cc1688b16c8a72643ba1de4b4589559c74d42d1f03 +Msg = 2a0466dd515d2f48fec5e78e22bb22c606b09e8184691c5177a46e8c70fed24dab147ebc41e97c8f9e88b8d136ea58e274194bc0f3962584f1f82a3001d7a8a7ffe88bfd49692bf12cc068b89d5ff9fd2aea0125309ce3d74de758bc185abf8310c8b429d3a7e37791b61eccbfe3ae1c106be739a143005173b721b81f51bce8 +Mac = a0b41e6eb6a6181b3ce60cb88fdd5cc3ae1277bcb9fd7e6ceebf3be2 + +Count = 225 +Klen = 66 +Tlen = 14 +Key = 411a36dc28fc025e3753b7525d1de759c6a63ebaae09fd0478f4aaf5faab069b1c5040b9a161686c4482260e077dac5bc887e9d215c5005e410ef836b7f3b5028ffc +Msg = f6b8806d8883de5ce52cdbb32fa2c16c084c6ac449ec9a3ff7c992ec730de1eaf06c7e2b2a061478568f9db554ad32672ca12173b82a41289ea68280827bc8a379b5faadc0f155b1ae7907fee7b0f9a1d3b1ec2b4e33c7b4a1b02f1fb1c659a077dd1c7cb00a4b10d63341154e74bd22e3c2f17273ced5e8e82cc1506ab53be8 +Mac = b35f3ac18e9605064284a8019bec + +Count = 226 +Klen = 66 +Tlen = 14 +Key = b18c6b2ac59c93ed10463467c206ad12c72cded9a7302f14aa45d3ba3f304ed29e5b342bad25344d207d56afe5af812bbf7d40ae3172c5349d732ff4ad9708d7f239 +Msg = b223f1533efd31708f49ca6e7921c052b9dc5c537b86ceec208e172f3dbf265ce77141b22e01a785e77e7491afa5c48e2c101b0596aa05617666f949ae31832dba25a31f35ff70e59fd3004c5dfe8cbf015dd017ccbcb1b5719122ce1ceb4807b3a5dc425cdfd2b73fae38468d13600bc12a413426a41b0f99775a6790d4bd11 +Mac = 12ea64d90d298c967125490cd629 + +Count = 227 +Klen = 66 +Tlen = 14 +Key = b198f222847d698a283f5767df682d33d3ce771b05bb6d4a864ac56ae914cc68f80cb578a6a8315a454240dbf9bd469e6d6b611cc42efaead3de9a3b8debffa5be44 +Msg = 94f4bb6460b54a7ef5875fdf39cba708f531e34d7fcda488966e520e8d2b73e2ac3e2a29d316fede60a7ddc7530561a8b03152b625326b4eed6861e7f41e21463c5e59f17f093be516277e8b197ba5e9c85a831529befff0f3971510ab611dfe0dfb50a2adb788fbdeae4714d356fb3304568053d398e7d470a07672fa1def74 +Mac = 9fe0f50386eb5ada4784b0d7a888 + +Count = 228 +Klen = 66 +Tlen = 14 +Key = 9dce1df8bd5edabad153a598b76763b88c8b4b4266d03d67468756a248a7c13d1d70d018bb4e4ba65300083884f9bb7ece07104a4932f79897e73fcc1756673a5b18 +Msg = d65a384d328a1c8908a53151d8fb1e029c6fc44958c2728bf314588445a73f2e71e777e475a710c7ffae4d61837255888a232c854debe27682750af176ac6eea5cc501d7e47f151110a9ce7e44e5d76d9cad53c1819317527fcd169051f01c6a3efcc06ea9999431e3a09ef143dd0c79791423451f4179e7912464a9fffdb274 +Mac = ce724494043888b3aff08e9e5ce4 + +Count = 229 +Klen = 66 +Tlen = 14 +Key = 0b2b3d65c6435b17c833ea8b476874b7afb05ef3454cb5b10a462a68e2055ad1f51e5356566d54c8e365d5506ca4c7a817ca1d8a028c8b692b048e608d4bac688c4a +Msg = eaa297508c137d2e7ce1707877ab27580b91ce96f13bfebd9c1dec7912f9e144fba5ea41f70ed068357d4ae4421972b91eae76aa95ac905acc7338b11bcd98811abc406aff771bfb27afa119f2164fa5d4225459a90e8ef34923b4965d35d56d717001914a55462d79ffdee030aba6625577d26bd56adfd03bb5caef8138804e +Mac = f01a16bd2e77bb0f5f0097cc2b35 + +Count = 230 +Klen = 66 +Tlen = 14 +Key = 9421184d9091e3d76fbc445366dc1b6c81960893807fdea1e5de54be4bb4fe82f9f97c5bb729f22fe1ffb842b9805259013ca220cad15cc987b0bbf6652472d9df90 +Msg = 34537f8e18097b85b6e30abf95e27d5a29378d3999fb4258c620145c88a8516f3a14be4a7a2081932aad3e6abaff813faa285ce64ac451edc5e7712d5d54c69ff8f0ef71dc760a59b76bd72ae25519a5e62840914001460e6116d726f9edb4a575cd592ac673de7f65051b26944c0f34e61d83630118ea62a3968c6fe3dce328 +Mac = 239941052aeefbbe0f54696c2308 + +Count = 231 +Klen = 66 +Tlen = 14 +Key = d2e6c7fc4269fa692a6efc77050dce3183c73f3c8c780f658187557cc5601e657c24576c929eedd9ff7a32c44ab1832b4c482842373a7b0ad7b34c25177e85e9c6c1 +Msg = 2cc949eff99b6625f8fd620806e7a86a84c541415b71f5423c5eb4b12d16357741e6dd75a6d7e218e5e1b02d665c8cf733b7777ffd6c552c64334e93737775906a06a796c10cb6436942c7385563f92739e0482d92d4b063e63a95b04d5e62e1309171fb51212bcf0b8870d0dce4392220a77bf31f904f0e4ada51adc2b3458f +Mac = e7eaed3423c3075ea71a26eeb7be + +Count = 232 +Klen = 66 +Tlen = 14 +Key = bf52e3802f419d00e3c665e4c4bef60a090af98545882939a442b5a571e6e5ffdc770186fb416f140e121bf207a71cf14a6594b6b14ad756d322d02386fea1c5a2e2 +Msg = 29d60fd3aa6f36c9c95016e09dc812003f1cabbace7ca0d8b6365939322a85dc107e033ab593fed960375d1eb31c5a636f8870497f4f7b4f38ff1ba4df5a593a6b098d1c8d8e7f01ee7bcc21b8e18b47570c3128816db2f373d8e9297ef03aafc3df76223b4afe6afa832c92b401eed6800eb4fedcc08debf12a8c7019d37163 +Mac = 886fe94185a671d8190f7be64b1b + +Count = 233 +Klen = 66 +Tlen = 14 +Key = bb9ac6581285782735ac94611c76f5449cba230c9327247266e39573ad72f9522cda50e00604ecfb2d6680551ddf7a77cae29205d6d7a34308bebad8fa166dd211fd +Msg = c1756db9e911a2430f9282b7bdae0009a69a8cb8db6fe85342d2373c45d457acc71770f75c33cd11b957eb516934d076c2169ee81854684030eb4409f766a2c87401dc3bfc0d0edfa59627b4fd444044fb7f2de235d6523054a2b8e4c5e661cbb27ad80e31690bb4bb975d68dfa7f87c371b602f9cbd4e2b963ebb52161e3bba +Mac = 1adc9a43267e2508c9fa91c4fa6b + +Count = 234 +Klen = 66 +Tlen = 14 +Key = aed9f67852ceaccc33dcb65bc1bea9f1ebbb85253f36f2895280c92362f0d6213a36ddc856ecdaae486e8d295aec360775bd9e7f41f656688e3c43a9f3d65bf1b406 +Msg = f03f736124a37ed746fa88cd61ee20eb91f96621182ac08caf26cf991a6da26cffde2983f87eec96e775fcc28a592ae74faf784f69afcd902348edb37464a795d46d518e4f107151d841bd13df7f46f02659f08ad03125f3bb40cacd0fda72af17f3d2cb50e376cec066b20889e7dacdbefeb51b7537307c1e15502e13566a82 +Mac = 434a6721dcedbf570f009f72a3e7 + +Count = 235 +Klen = 66 +Tlen = 14 +Key = 3149367d716d5e8fde7985774cfdcc6676db6160a05645f07a6c531948667e8f40ad5a2833dfde8d70226835e6b9019488d5e28ff6ad383459d025a88eba076088a6 +Msg = 61e4a04f8b30a5c3e152134349ad8e702721464dc6df78aefa7c37ee03456ce1b5d31c09d6dfe90dc857dc6667b0615c357f9331b543ba9c148512790e24cfbe10ea5db19a62ec58e8ee2c31d1145524ef196bb600d1c07f8cb5badec936d6ebbb51edad9f64b78e8a408d0b4e7f73b09d18554471309141aa33b687f9248b50 +Mac = dfc0c5e27b734c3d9b17486b0699 + +Count = 236 +Klen = 66 +Tlen = 14 +Key = 2b0b018d11c1ebeecc2a1b5bd17e3be5b87f577987ac3eb733b82b00643aa4d179a6a350cc7cf42537bfde8bd7a905a70f9d8f18d05d86cf187d7d21b918771a5cc1 +Msg = 683ade55ba5e6525579ea3b9fcd4d6dd8e5fb5070075694677bad975ac122ab492b486193a811da2f3936a6eb518b82dc061e4d680366498b46d8812cfbb00c69ec99fcb2c8a5fc3e3cda40df30ec53cf892c8c7d7b36d01e8786f4c5b68068ad4a0b0d5592431706e73d8fd7e5e05f07d19e843cc938b6c5d03138c17c343e9 +Mac = a97731c6a843d7632597e2cd2871 + +Count = 237 +Klen = 66 +Tlen = 14 +Key = 0318b6f7d48edf20ad491f49b9d6a37b26bea2a38657e2fb76e07dc67ecde540396026d5b6796b911dafc4d8969f26576684b43a5b093c9f6b5b054b9881c89c17f0 +Msg = ca72a059551913018f1082fffcd93014a277ec636b3894e1cad3dc07a1b24cca639188cc7648d4d4dbe5d77c10fe9f293546e6406f5d94978aed852ae2f28b108359b7ad8fcdd428e0ce351fef03b19af4d1eb3e4f2cd7c427ad79a951e5f02673f2b462694f1ce7e7f12352608f6b4f274182c5d54c654eea3c42eab73482f4 +Mac = 8da045f02dd42b27ec1efc55fc2a + +Count = 238 +Klen = 66 +Tlen = 14 +Key = 386b3df7e5ba8d8cd80774b603d081939ac2c0d70fdc441341d20338f1afe75775bf21aab0acc1d841e78375fb49ecc895fb96d2a393c98bc57f4a6f1fa77839094e +Msg = a7c570103bc6723491bce038d92ef4ffb7372ca231db4a66cb9b9eecf04787a89414389418efb8266e102c7f7dd159e5c7c1657349f4dd0fa29efd9d78e02b7218e2c40c5c221b00d20cbf331acafd4d905da66b2ced1315a65d656fdd2311b379579ddecf09a4aa06d820bd78c0e9205b3478f2a16df15e1c0161cae6b74351 +Mac = 4ffe79c080088883d4cd92b7eb49 + +Count = 239 +Klen = 66 +Tlen = 14 +Key = 18de98f33a9273c0fa15d9002519870df8ee59e5cd9b0cdafb2d498bf74fdf12bf1b517f7830908655050974bc7de267a4bb81bf42374fd0e411bbd91da6813a2262 +Msg = 1b8e2151f987bd2c9a557f9b6bbeed9bcfaf0ab37918d86f18fd1a103acb5e826ae83b8e9c8dd851ccd8adede11d8e7ed77ee5501dbb3f4f3c4b0abebaab9c2c3ef678a4f4b6cd2533f940515ea8eb690815a6795bd385d0bacaa2b3a58a1c53dde05ffcc9a7a68e19e1bf31a9070e45a89dd598f908b3dcd9a46a58c312e5dd +Mac = 5b82a41defbfbb03f18492c09709 + +Count = 240 +Klen = 66 +Tlen = 16 +Key = d282396db948b2e4f3057fb12ac64774cf4b9e00bc16cc0c17c2cf2c7996a3004f5ac0ab8169e5875208141888f6dd3ecc45e0ae53678ea2be8c2fd03f2c2999fedf +Msg = 86db23e57d0d89018137a329e6b2761ff7e9d43e2fbb2d04ac21a8cde01172e18aa256b1e4708f5e1e42da7b0ceacf141c6d70ef8a640311d7a21d8477170058caf426e84d101e5f128b977a6db1bb8ff121bece9a2eb6c74c85ad2c7c10f4d82d1bbb111fb6df0a435a03ac71cfe2965d4ce363c8e1ef2bf3127f4c59c5f96a +Mac = 391cb64eed7e29d506da77c480e577f0 + +Count = 241 +Klen = 66 +Tlen = 16 +Key = d7187acf9275f6e6eeb86339654627e9a4e47e92e0c16c756db7f6d78dce91a48602db58f746891f6bc8a03b2f77e9a761c39efa4aa36a8deedd91e0e0826a3a5bb7 +Msg = eef81a2810d019cf6a139caaf272d9223bc3a1d53cb143e953b2aea08a3ad52d182f58c72b9c60fbe4a9ca46a3cb89e3863845e22c9e487abf149ba031516cd8c51bb34cd203161bc45009f3633939e258572b69ec5920d314fa3dc4ab30e815fea675df8d6d02d610ef9fd9b924b3c7b9089b93054c939b5a4bda357e41118b +Mac = 547c66e6191858e7373c21c77c9248f4 + +Count = 242 +Klen = 66 +Tlen = 16 +Key = 36896b611dbe4e72fb3205557a792657885aa5ab57cbf802a71e785c47750b1dd97b0063d7563a97d3d7914203f47522fc79d47ebefa3eb6f10c481e6eb52e0c0120 +Msg = eda14ca38a4242743908b515acf174a5d33a9c614531161ae14561e7b55f92171f759969315cc5805add8b91430c835ff8d5b36948d810616e7742e1f12ca85ac8209c4dc2faf8bd25f5d8e49536a225385c44421858bdcfc97fdfe64bdd531d31cdddb503c7e114e27827756a18dbdfddf8d8537d5a264a3986c05f8c1a9b48 +Mac = f86f5d51c669f9a7000d504557ad1c15 + +Count = 243 +Klen = 66 +Tlen = 16 +Key = 8cf87c04e4cf980deb8a360ca865b0bf70b122a3597a7bb8f168d4882fe30166a97a66f408860ce8b90af50fe6deac92a50d1f786f7bb16cd3cb8cc06b7f34b31061 +Msg = 96cbff162d869064820dac3caf9fe8f38b486d1b2d599f9cab17fc0727b046260d73e4d8963f861b913c086b62ca994b4bb71c21eab5ce46030b295e808a09e5b6c30e0bea7741c2144ffa15e2cd01bb0083f3ec9783e773141652052ab128d11a24445832150a7f93ad4be23891686c3414bb253bab324a64a13da32d0beb11 +Mac = a36cd08dc282d01842800342438fe776 + +Count = 244 +Klen = 66 +Tlen = 16 +Key = 2e58fc5b4794edd5350145303ddd1bb4dac3680b62c8c5f3e7c376365beca8dcf8a9f79fdfa4339f00216457398f0bd0c25cab14c80e88e65890afb07fc936bdb073 +Msg = 74e4acff328284993931702ac701cfe35a4d1f9b7e3f6f72e39617b4b2a7a60021a21ca946175a5c28b9d6031c6193ea4f5651209fcb0121afa97bb13a8f730ba717a93bde5c61c95bb9139780d3630c30d95372990ab89d5178ebcea50cc0d72ecbbc7fa5578227f7b98fae9c5d2793255e8f5915057d30f28ccdd19c2775aa +Mac = d29fdf23dbd05bd102ca11789ac48618 + +Count = 245 +Klen = 66 +Tlen = 16 +Key = 830db2e9fff61890bde5128c4a01bae1a6163e529d94d88254db005923b5e0a9a2240812075f6323af1769c1fafe97cd5c8a1c01b1f6d61bd18b7c3e651d1d95f9d8 +Msg = a1162c7ff5b4c2a9f096e13ab426dd8654fc7b8ae6a4a8d3daa16b9c8ab119371153c8ae618705a990d5ca927390aaf86e5c4f318aee2644c8135906b6f4fe823f988e9ec7aa98fc787db61fd64dc1cf9ac841bebdcc276bd373bf479a4de017d3ec669950a6e16a4f968f2706e488d27f463978a6c71311a1c884a85f4427bc +Mac = 1e4899298be41692e1685a1fb6d5d4f3 + +Count = 246 +Klen = 66 +Tlen = 16 +Key = d5ad5870d1df92942eabc76c845aebaa026a56dd59e1c458d5e1a06fcd7d82ea3ecbf6b3b33a7fd26826db9baeaa892691b68900b96163208e806a1da077429e454f +Msg = c5cee3c5a8957b7380ae9a209b35b304a14c375c2f265c17c25f1dd2d78f8206501e21801a5ae5120dc60e8913b579de8d1822b1f295e7f2b9d98fe27a2e0a3a5050faa9817c738461cbffba73bee606d21aac68cff6dad5dc12022ea96afd6f8c0b77292626ae324463769a037781e238f9dd690e71be27f1b37e9dab6be20c +Mac = 99251175ab1d5b0963078ae0c4f232b7 + +Count = 247 +Klen = 66 +Tlen = 16 +Key = a63871e55bf4ebada47e6250e5777d282797aa386baa13583ed9ce938e2b53cdbc4c34a8f28c08a9b72aa897c1d39f240a66dbd026faa909d322e097d2705b37f537 +Msg = e2d5a913557fe304e9ce0f6e1d19bfed32666c66857569321c01167e7f4256f1c9b64390fe2120df9fd38e497c2903c2ca5679ab756363f6b875e58aea4f44e99b179c10df5dd19fea59c739dd74d62ee00b7857716f4542fb30228fab9bb59a7f811c5ba03ade8af1ea2106e8031e779d0bd33220a0f75e10b93355692e8f4d +Mac = 1efc8077b441618d2c4de26eb723c499 + +Count = 248 +Klen = 66 +Tlen = 16 +Key = a2409634e9c91e73e8e1d9767f764fb815e0c86be014b355601a48dd2dc16d66f391d6dbbb01718b6cea0138913c086a5cf0eb09eb3d512bcb0fcc2bbbb5bbfbb2d9 +Msg = 763c6dbece85dae266f13915174550dbe3c55f432e9cf66c2a7d0948948b46a09e76a6582ce743f5421f695cbddbefdc427ac86f7561d53d6b9ffd6261cd80f1ae388839f6430247a106abac8b3b6e80fd5beda6dd045e52219e98c9893e6d688eca3be8965fbee069ef288be82f74ccfdb0f76fce4b38b236c3010475a6b60c +Mac = 65943ffcfd5ba5ed576ac9bf9940ff7e + +Count = 249 +Klen = 66 +Tlen = 16 +Key = 6a131c212593cad22599e731248898e10937ab88b2a27b26f1df14a5d45498b12a28e2c942f76896f6ca667ce84639700c23080967e0aad916b5c4fd91ca32f331a6 +Msg = 04c690eed39c88ddc7b9804abf5757eca5837dc28ad9a8faf88fc81283b53e3da2ba4808bd33c03d87d807078ecf3c58112eb18811bb9f3faaf61894a4593e7646deb34b6ac250d8d7881a61ca427111d60c8b9ceed92122c172685746bb43e19738b70102d19f765dd2a19e9b3660df9d25f3454abb976ce20ba0a18f64b644 +Mac = d6905d3d0289bc6a50da79b5257ff157 + +Count = 250 +Klen = 66 +Tlen = 16 +Key = f06fc37f8f4854be42195a78f1bf9581e8df63cc221d2a3cc78ef6b8f36f637eb917beb9682a67550c10791238a5add703327c4a519d849d54dc2daa52af8c43a88f +Msg = 2ce5397319596e63dc9a56efaa127d011918b9ac3d7a68631158f9681939ae8646589f031a3f03d10c97ab042e3fcf890d9b0d14d92faf5ac66c2d81b1c9f2d4071663bce30d1eeb762b7fdbacbe69770c3e4318e1e040b29769e4506740c4bd37c88d84bbec471be1fcdb5c6cb7d334dea9629f9cb7a4d44df826bc83c6a9a9 +Mac = f3da21042ca05a7eb384482ce36f3a3a + +Count = 251 +Klen = 66 +Tlen = 16 +Key = bea9eff7816fb0c147f6d3702ac0604576b531ff0224ecfcc10535a2948121fd62b4eda96bb1f0f3d9c6ce3b9802ef9d68f52fd031b7d74d962ccdb4cc85076cad0a +Msg = 5e675b4371a86ecfc11b2c89f59a9ea972c7698f2c964562bc0cb1f7b446e6f42fbc0935acc7a46e1c615712392ccb741ab7e82d04fc48bd842deb75bab02c94f868f3b08c362d57d9bf79f7ad7024fbcec05837d6b5908641aa4fb1c54f1293e2f1837bb9fcefd221befafef86d9285b76c217649ca07051e0c47757b2c803b +Mac = f2256c3ae3784bcc6dbd82652dca048b + +Count = 252 +Klen = 66 +Tlen = 16 +Key = 29b82636ec4d10c4a43e2cde47bcbd50c409c69ce7d316ec7dc0824ab84a7213d5cd9fa9fbde1a6967df91ddc6d0ce32e26880ec81653ed88a20c9426a649169b680 +Msg = 1c124cc0aff12edf45954ba3df50c57cc39c346d714a3e57dadc697acd2f2c39b25d4c1d7ae1661dd6fcc71da75884b4b6ecc832a61f68e22730bd8c6cd5b23ede221c4c12ad4a96f8f0dd0956eeda69751afe4d1b74526bb8f5ff15e42d6204092b63555d9d03d114383571d35aef2167ee80c5b791247af7f2d61e1f7f6512 +Mac = 0f84b0279a6701bec3d5e569d040ef2f + +Count = 253 +Klen = 66 +Tlen = 16 +Key = c9778ca154972ef9d9a470326a789616fc4acdadc680b1b1eac41242575af8dbeeb1e485e438594a67729bed844db7d848b0c3562553670298d39d800906b46af38c +Msg = 42313ff1f77e4f1e9c50dcab95c59e446f88a38dd0f5e762ae7e2463c04debb0322af4f19da0b39a365b2b6d46d50740da32e700bb68f8f6a0a2c749a3e757c4f2f671dac7753be79a4b0cb9954b7f4f4812c6e09e3241200f904fbe180a6531e85d5db45d46108f2ee826996a6e2dfb21f1e936609ceb68630e65cb07ff3d7e +Mac = f4aa8479b61c2131ab468ab1c628faf7 + +Count = 254 +Klen = 66 +Tlen = 16 +Key = 62c6b8b7a7bcc01d360b1e6099a35408037cc4fd90d01855cd88e16b7bf47e3190be40c77f21cc4cb956c0f4744f995aaba8d41866db53963bb3031f1503bc3a3497 +Msg = deb9043c3791167f480cd6ea43a89c08d56b272f4e77dfb302df5c59efb92c0fa074d1da516c0a0f53bc54c6b253af8c164ba558e77689c1b439fd6dd69db6cd50a38407fad88c34df2ad8cce3fa135ea9728d85b3198617cba4a89fa210d50eb8ed23ad7bfd2556b3fd6de41dc34ee85689e79efb895c1f0fca67d79d39103a +Mac = 0d51b3c52c951c401d0d0c4cdff55037 + +Count = 255 +Klen = 66 +Tlen = 20 +Key = ab0d78b7eb2db9496b3f07142ed00a2ebbd72a6c66eaf632d0b2c789b19da072d5d2597b656afd8f68dd701289ba552e1b9c2e675a59c576f47ccc54c8f6c095ed10 +Msg = 7b5fad44acd7630cd519a6669f798ddef28f5d7168dda25001b37fe118504307954a3ca36530d05b276dc99a286ff1d79209df1be01610bd95603a702ec0dc8155861a59571ac849d8e4c587c66a8a738bb8021f87059d0fbd93a03dccd7bf6022daed6e6cdf736050463f355fb07f3945646f8743f26fcde016594fdbde112f +Mac = 18a14d19d9614f11475d666eb6ef27844ab87235 + +Count = 256 +Klen = 66 +Tlen = 20 +Key = ce6888d0b1cf634d4ff729825a18410a933f93fd3df39bb9d219bbe2f615d6a7a9321a47c0441dd4968c2c38ffdbe0757dfaf131b74a4f7126a86fa51293e3e5bd91 +Msg = cc46f7b76f11bd31de6bf7eab80ad36c32decf4c5c481efea6874deda27326cb0b6dd5260796493da93fdd11baa138bfb9ce710c20e87742e991b13b51a2e1bbdc204e03996c22a2a7b9118ff8c33b7555bf544ea28d02336435867280919fe24547ab73adfb1009e0c2da8bfad9a6360e97be386ba0857a1e5c16bdb8a728e8 +Mac = 814c77d4a1a0b88aa695dd78a383ae4c26382e90 + +Count = 257 +Klen = 66 +Tlen = 20 +Key = 22943268c52744116c87652ed6476a919a73c03fbbd0a6d17c66991a753c100ae7636ad24d35254933df508f4b1d43f0be458d0bc0872e3367730715bdbb8e9b143b +Msg = 49d6b0d2c8846b94ef0e140885ad4d58e2eec291b0620df6ef97d79a3b48402e52d18117d1e5d0c43e83853e4b267a00593db70a3cda4f313eae85b966353325fa2e6d4e424e61b38f3581107ca1e53274e2ea09748e20ff12756388bfd747fa49d5baa0a426e409e90b52a69f8554953ac5a3b7e1e4470874d4b830ce974455 +Mac = 587982432a26c3708215bf7d33c3ccd6c3457d2b + +Count = 258 +Klen = 66 +Tlen = 20 +Key = f8aeaebc13764a4697c41412fb8258071876d8b0de221f4046e812d38772c8f68d519b6aa7e47f25807c939a50bdf63a5348dc3b7b97e19862279d5982dd7814a8a3 +Msg = 9b5d5a0ab57619e9fe21c1387e9baabc75713a1591e7b643639b57681466a1cf5483f02e94f35428751f9e1680c0bb0717fc4105abd1489b30b77b94ce816f04da85338d04fc28dbd2ac12714dc470a8fa0709f40b2cc86ad785c97f88e0b41313ab4aae6e5b3d09fd0e45d04d6e70a604d9ba6a18c0ddb8404d6ab3a8491902 +Mac = 95154f6885ddf90b4d8d7f822914893a4e94b479 + +Count = 259 +Klen = 66 +Tlen = 20 +Key = 9d2fb8530bb8e5b086d235272fede844758614192ff05228e855b78379f80631debc23d442eacb895c2f8310fee4ce2deb92a34deab61e6d18c1763882632f6ff309 +Msg = b617e6965eec432dcc4684bb749ed016df232b884600a52c5fddd19b77a879c8c1959029ee636818fde2267855b2729b114d73639b47faa87cd5fdda728d48e8c36c6f60d21d07d7f078158b744ac7470e54628758967cddaecd6b93403afd9265a56a8233a286334c133b3cfaee37e27f40e23ba67293939ecb030e0837028f +Mac = c529f8618c32183dbaee7f92c372c6d7177ef4a2 + +Count = 260 +Klen = 66 +Tlen = 20 +Key = 16785c02ca39caecb9a70cbfafb1697b43e544c807d8ee7f01c8be6c5f806453667c7a30ac4e5cc387403a4cc53b6b949de7042ce614aaf98759a4f12ffa341f460f +Msg = 8ab416fe0bc37195928c36209da96a27e5fc35bc85432dae5decd8ffb92a6b982e48d83cc53e08bb5c82656848209ccc3f0da19c76b8f3e906e3219794b18d10310070397ff81ea615e48c0a25410ff15c1566b10a83fb9d839b667dc577333b5b83e5df811c3abd885db1ed7c354afc05bd8de18bc9cd339dbeae9994a3e581 +Mac = 5ffbfeadd6b3711ae7ddb3ba1ac431e778417e2c + +Count = 261 +Klen = 66 +Tlen = 20 +Key = badf712a65733a808cc33bea4ace8af19af511aac8a49c7f25343031ff109f1ed01759c0b642857723875088d6fd85650a405f2fed179b795354d04facfc037633a8 +Msg = 1aeec86d57bd0ad4d85437b5347f3a64414c3588d7c26871d7d054ac6c8420d4917e3baad4a3436859162653216487908cfe63381dedf4af7ec1d531c4ca68adf38b75d7c56c1379a7afcc0905a5fc81c7227a6b1c2e7a3b76fdb2e2d622bca049ffbc1ab28042accb09720067ac62e0faa0c3485aeec4c0c76e33e82af2e555 +Mac = e2353a4351e93402308af2e55e2cbbefd940ebf7 + +Count = 262 +Klen = 66 +Tlen = 20 +Key = 8a933a2d12da0e00eb915fe7e4dd1345a0687938965874295b7edca224d0215f871a31a781f09cddbde7f65213057e5d5075fcae357ff0dfc2b8e84cb47632254c87 +Msg = 9c97322b9357482c07cf9f2178d2d50383d6969e5a9ab250720c730e7b692da795a6164dc10f5851952e652e35ee8bc97e00c8f7847edf403fceabe381cab4192b1d009ea1f02c6e7bc7bbcc7ea5ad89ca77538354af636c973048cd876abb4ac7c697271b44e90b206247043b4164cccf03e14bb377655ce3f8efd475926bc1 +Mac = 373f095142161182dd4252e416f555bdfd779521 + +Count = 263 +Klen = 66 +Tlen = 20 +Key = 84e7efb0907d3bde111561e5cbb3609dcc7fd1059e26c0cfc17eba1e5869278e23fbdb75addfe768c7f6b501344254e0a60310f0ea1f46eb5fc77621ac589a75b27f +Msg = 1ce6e8f01d78b34e0cd55c4b631fd2311cf87cda74391c0aefe7f9029c633d519ae09ceedb1a36842846bf0d6544dda2171cd19123a85ab1d88ed6f23072ab385369e56a5db021c5619ea977aed7e06951c3e15cdb3e63376491e09fcfa1f6c950670d8c2ca03abbc0c663b1c53ea42dd2d3f2612263fe4598d85c31005ae5ab +Mac = 9b039c1219e1127ee78389f49ed4b5bf33d8b8fa + +Count = 264 +Klen = 66 +Tlen = 20 +Key = cd2322d1b2717c3470c51fb5f45f17ba5ef809e41a5677424c1f40c472eb66f2459c14dddff2e056235a4d5f5a0794df1a44a49a6c09675f2dcc4783b599f18fb765 +Msg = 5011f28eed69a1a67d7291ee9d6bdca9d5c8f413c0cbe5986d54da4404fae37bad5af5eaadaf33bdd2a46b121266e4ae6ffc57ef1edb3b02e7b54556cf933051f523ba41ba53ef95241ea94d85a658af5784ff3c6b5c7fe243b41873bc062d56ef13477d5a7b5d963b8b53863d56c0135607f4e0f0753a9f47f85a82127c62f2 +Mac = d25e6f1aa655c39481770137cbaf31a1751fd04d + +Count = 265 +Klen = 66 +Tlen = 20 +Key = 067a059a6bbc2d9e2a5809371a9d3fc32b8573a84138baf243d2513e6e668fd6f043181db276542e75901fc020a9c24d58a4227352b5389ae521c1d7e4453710aada +Msg = 782daebf804deb7654298e22ce83652b43ad8917b6ef34094c29d28800b95b82989fdf91d8df637cf527eb014db2d8d2546c74ddd257ccd04c2dbeddbf4752bb95bd4eedd1cf04468d846fada6907e1eb67bb0f14200e15f35b464428de8511c55cf205bd3e477db028641ad43e500174f2264db70b21cbcf104ec3fd26300af +Mac = 7e6eff161b22df17750a50d4df090c4acb490e72 + +Count = 266 +Klen = 66 +Tlen = 20 +Key = 9bba08114ff78829757578563b7d92b558bc5c069c8b590dcb748037abf1ed815c76d796e8b2c2371b13f5e095882fa91d8a966a385df022fa93159a1dd3a44550d8 +Msg = 19f79b29812520a81a53ea95b4a3da5addff8c39a4c23897a3b4d69b3c3c86f822d12e071bb2651905d7900b17274a1b6aeb0af9b883ff2263573f69b91121d6760ae7b48a01a1e61d134e7ad1e74381472ad11de43b22dbd527644350d729ae1d880e58567c9bb66bef6b0a684d8d347ba229cbb152676c000a8c528af66727 +Mac = 556eee5f3d290ce2b919a5ae6edaf175aaf68d1c + +Count = 267 +Klen = 66 +Tlen = 20 +Key = 305016ff8660f67524c25501c35f4fe2f19e7dddb47abbeb70d72f2f0a16872a4ee781328e5eb1208c4a7f4a9bc26fb10000a57b9e73a8a3d30f66ef9de8782201ff +Msg = ef51d40149378ddfd9485bb0f396db32aafb4e2ff0aee1afff15336cf8da1186ca41847856b90d4bd1b12f0a69ac2e752b9817f9245b00e0c6b091c68e31c34ce4b4e81043dbecdc99e7da1df1cda1974f8c1958dbbd41ea426ccbcd5a26da2405530aaf57c7b1f9fb9364d3d221bd00de805c325ffc2c363bf2e76ba3e2dd78 +Mac = 1fa170ef53ff379ac5a3985286f9e3791378464c + +Count = 268 +Klen = 66 +Tlen = 20 +Key = 6741bed7ce51fe0b9de8734273365a590921d1841499df416d25b58a6fc2334fa0eeae239400f1360fba81836a21264a388ca6c129fcd4072eabc959dde872881821 +Msg = a9c81892991032aa57021cedcb322835f4f36f04dd7867c8cc39b75dbc9849d40dc5a1737bdf6efc4d5c5f33ceaa389a0116257f91ee4e3807e2abae3fb01a181d01af097c8d4bad6786704f8c34531feddd3333d9e7eacb1b40c2d971fe89c14043e85d8564f0440f4af64cec18a14d210d41289ead6208701ba2e839cabf56 +Mac = bb540a499aa732435e5d38700beea7af6dd06d6c + +Count = 269 +Klen = 66 +Tlen = 20 +Key = ca5f4499b874a5d24182c3e1124fd96c4e4635d5de79315e09e6659144f91bdf4b53038770ca29b933b123fb14598fcda5d7bd88e308a88cc6d32b9a17ae717f8264 +Msg = 8ad3ff96ee38563b3dd32c034cb3a48f09a1b60bba528d078ae12d82417c5948535db47f1cfb267c6a8281db3c8165cec9e361b5c4215aefdfb631f08ed2a0940d5265b3a4f0a3f62ab785e9c8bb2451ff06abbfecd5b965cb050629bbc84af8c09c5a5d0e7e9452855a7e5678c7aabfb2f1dd52bbd66f1157b6f55450c41e1b +Mac = 0ce354c2cdfb436bfb1fa0936f6066f5bae98e65 + +Count = 270 +Klen = 66 +Tlen = 24 +Key = 42125d3a9cf80a5136c9fb8e8ed9c77c0fb553bce6ab45aa118cbb3db8b03c2fc13bef5e9f9f0a736a628ec1352232709cd69cda9c56d735a81e0273f84e456625f6 +Msg = cb0a257cf3cd7026944722e60df2270c3eb907108ff40a25339a9f10aeb2fe3b940b0d05942d805db68f458fe10b1f5da08e91522514fd538fd40d7768b75219720f2b2ba386e9cc6e54301d44b6a0515b9bb504aea0ecce453e2817b642532dec7e489327bff19d44ffac393fdbf410f6473dce2f801fbddd42b7999f3c4ba0 +Mac = d6bee9052ecfb1dc1d219bb53aaf45bbd9a9d485fe468e0a + +Count = 271 +Klen = 66 +Tlen = 24 +Key = c2441da1591a0ebb8c3ea52cd3dfa7bca522f2db8217a93537ec91885e60bbb2247b640f4f7c19017f141fd0b3d111b510ddcb31dee887a3d463461a95ef72687a15 +Msg = f791be39f3b74208b327202b5756827084246045fb19ac1f71eecd1c9b4f4fe788dfd9dc337d5f6c59c698c388dab3a9796346a69fd4876a00efbe6b448afad00b92038e845091d13cebbb9d332fb2b5358cafbc67622a9a217c4d21fbdaa8f12bb326980eba40fe04a1700181dbe95c61a785cd7c4aff777b9b6285eac5c110 +Mac = 0f4342d0346049efcd70526727c7ab92de50bbd976cd0b83 + +Count = 272 +Klen = 66 +Tlen = 24 +Key = 06e7210def086f58b210a7010668e0d25c52a4421c1f4f4832a3b871c9e61331561c1676d9d75b83607c06fcccf3a73dd7a362f0569e4ddfbc181906e01ef5ed0085 +Msg = 2716190fdb5d5b4393787fb8cd3e0ea671494c1104570d4b1ef0caba1e49f4db1c6988871f8ae47690c2d901efe2012cc59f53e3daeff484a7b6509e0ea26af9495370d621c0937760d616e28862a4e3c530e65021745590f76a4d5eaa3a63cb961ef98247c61050e9fc5de400849ed35a462edf41afd778f554e88359d8885b +Mac = 4f6b0b2387f882bafbf59c6dc44fc5f7e4da8c33ef1e9d40 + +Count = 273 +Klen = 66 +Tlen = 24 +Key = 89f7cd96483cb5ffedeffb54c13fe259c247e82500e44b8f47c4cde4fec0b4db4f6c16ca89ec5319c209e3f7c084524d1aa988f09a284e1be6210e1c5f7eda4d4a85 +Msg = 9dbdb092ae40499f3bbbb40b2e81c5eb94789f674728766ecb1199a97742afadd52740744ba3780efa5e2894e6610e5e57e056758056604b5fd8c4aae4a294eb55f7e168f1288034d4f20d091a0c318147012189e73c67137161e50c71e4178ee6d49856e9f7e878901c6c5112adb6be2c84078bc3ff122fca5703b6662dc0fe +Mac = 5e516a70c8903e0f1b9ea74da052f8c12443433e7455d8e4 + +Count = 274 +Klen = 66 +Tlen = 24 +Key = dd4161cb1ab5bdc92f902101937a6091438ef986646be1942a87820bf8c70306c94dcae5ce923ffe58b4d390f91142f8e6141428a04f6a54d4caf7ee7f9b4dd555b7 +Msg = 00cbc20826a97e1389320a39f595274ac84ac290f701185f51d81eed08d020646d82a836fb0ea1b19755bcd31668135f003f0d3093af81ce0b961e3f21590a20d290c9f461ff61bb9fc9bbc76ae04dcb74c0f635465d29bd84594e3e727b65c5b75dede86164045a2af5cfbcf9e61cb5ac33464415f35955428a7793021f7b7e +Mac = 3bb45ce54efaf5b6c77f2696d36321fba9cf71d8e6e52fc3 + +Count = 275 +Klen = 66 +Tlen = 24 +Key = 6261300e813759d1be2dab7e0d7c4d32693fb80fbccebd31ff47c9e3a26d68132eb60804299f00433a43d0dc8d2caacd796932bb60e083e4d7e67255070d165d533d +Msg = d3f8e9aa9b5cce0b8a964763773382ba97a7f4449de19a942622850c550e9598ba04859c79ab272aa8cdf179f869b9929803bd4d563fe67c08ae4e662ae8ff77c8dbfe359f6288767f1a9bd0f371b85224ffe871fb1afd4586a41af69d287571c5255c5f54aa7657d6234c52b073076003437b9ad399655869acf1a4f5f780ee +Mac = a80ec7690bfa0be634ac16f2de65ca1fec8d6fe7024e9b77 + +Count = 276 +Klen = 66 +Tlen = 24 +Key = 1a4e62c8a51715ca8cd3c745ac05bff02a48fe5f9fe37d32799eb58d9ed464c852ca8f675a3fc34c6144a12b9c4e9a3faa8af63bbe701b84ff9b0c9d2fd830e28b7d +Msg = 67353dbf985ec847caae6507fef13ed7c15069c201d25eac1f23af374593f3e8fa610386f43a6ac32dfd161f39c15408d619fb46c597e696d88ea8954d1c7ce05a687b7a0929126e4668b2b53686c959cb80f2db967268d3dc5ac1d6eb1fd99caed20c628033a88e3e77a192a0488712c90eb6491c6dcda9520e61c1c9a3f264 +Mac = 1ddf68ce1cdd0ec4595b7c41639d5bd76e11244ca5db1d28 + +Count = 277 +Klen = 66 +Tlen = 24 +Key = 82f4afba9311ac081773f717607982dd18736dcd7708d758b9d5f4b4d0575fdc560bb2d8c5d3553eea9c93f9973ef34999a3c50be92cfb3b27503ab7438731457e66 +Msg = 8e76c10a23aa8fa392f528a75675853dce9c9c92412983712157d9158c54623b18f4f17bd0a78bd77aa9c9951c787e4abe8b9a3870414ed98f1871bc451f23904faeb07f0354b7bd91118b6089c5d9729de98b44a97ded06f0410e95a8286a94ba0ac5bec3995a7a5e9635b0a545dedcf51e3761f2c5a71fcb3c7847c0587e6e +Mac = c1f28ee98d97c9ae610b3ef4d660972c175ae0fdc13c50d3 + +Count = 278 +Klen = 66 +Tlen = 24 +Key = 6bdcec81a6fc5c05e23045fe1c54a0d0378e9260948b9c7ae30c127039a2ce0462b5258878cb1a44b407d21885f04863df754223d62d845d6be343bfa651dc84e52c +Msg = 354e9346198b618e6d4f1c8c27431658cf64acf03eb32688a62ede21d200a55daff562920c30fc1d9e207af947b0699097be7ed094cf7d82b60159d736419d4489bd0a90279c822c90ed25c291deb910c32f4ff756e623cf0c43c5fe88f676c9c990d56af238bb624c9f63108d36ce835b9e658d0c5fe118b0de68bd5189f893 +Mac = f5492b259ce2d7f8a955104bb0314f26f9f14c4f00473e88 + +Count = 279 +Klen = 66 +Tlen = 24 +Key = e774851939b461eebf513c86ba5782ef0df13f544b2fd6d91506f7c7a399cbe9a0b671363ba4aeaf7b1ce08bd2953492f6c519c7ec64f5496533167b4e3deb63a35c +Msg = b1868ba2d6fbbaa850326fbfa5a20e4df6fb5f8ee2728e86a758763a8af21e1f7a8584d3f0b09a0b19fe8fcd37bc4fdf45084d7fd92b80544f29aba52496e2c9a0aa4adeb89820be321cfd2f0a53585a15d04c7fe4ec9be6eb5df419e20b71506c1f642df75c53a9e3b2414fe6102fa8af7be3f6c95de824c31fd6fe8ef9d49e +Mac = d0f82ab5a9a185f5dbb93a39c7c9ed2e13d2f8c92624dab0 + +Count = 280 +Klen = 66 +Tlen = 24 +Key = 056d8a62bdb898b39cdf10c24d7787e0a8853b647a37f7fe84d23748c6ec8d9efddb43306a6d4255d5da3223d2f6e33c43abecea1ea7926f7052eb96a203438efb73 +Msg = ea9222041a580bdb27be76069fa60aa4f93f8e6ed6344e908623c1b8ce506a6ce89bfca0ccafc188ae7d3cabc8e90e3959c2169eeef8dc57e00930041ebd0ebf2c13c5ad6c7b58d29d45252aa15ac4f5832a3252b8e52f0fa5eee4c0628dc90ebee4c65283249963fb0077abb262f6817e5d2ab3bd640e61deb9261223276301 +Mac = e9bc98284c402d5e72d48253f643a27321172f8e70a726ea + +Count = 281 +Klen = 66 +Tlen = 24 +Key = a6c95c5e14f2cd8a551cc38aedcf7649677970ba3dbe91caf80f5593987e5ad236d01c9be8d4034be5f4a1bfea0a34c3dc7573cdae6b87ec859057fb1ac8081a604a +Msg = 54b6ae1cbf3ff8d5130983ad580d3d708185454d4b43f3ce6846180edd8f8726a931d4e8a7a85bd0b56b843716c546ca15e0ea3beb231236e3bdf997bc82fcda4ff75ad272a8389e1bc2e8dac9dd6a121f1a337cd26e2ee6c63d01ed742b91708f2fc844e7e996298d3535fd3800b230e75aa978c8cd50c659edb678cd314dd0 +Mac = 45506238e53eefe7894a4591b63db2496f7a18c5ce3f33ab + +Count = 282 +Klen = 66 +Tlen = 24 +Key = e210812e59b2d0e878b2f838704ecfebeb5d66219e8d3bab1df0b0b8f4b7bcb1f33de161c9475e59d58aa593386d0f552f11cf58a08e252af280d4d122c3d5b1137a +Msg = 050262294ee1d4e811dc554e6a70034c99a845fe572cbcd36b7b76ef787565cd191c10292f9b891d7a889f8a676654b9296e92420b8f192d05b3bc588d44cd18afeed62360a789ae10edfad27e4f0c34d02f29e5e3c63787e069c7b2100a8f96f1011ae1890dbee3fa95cfef57341205b67574af86dbfc292325ffc4a8cf938c +Mac = 484fb98b95239c8327aaa67f68395990ad563de3492ca3e7 + +Count = 283 +Klen = 66 +Tlen = 24 +Key = 22d4f1f11997ec7379091d849500983c3edacd939406010e1bc6ff9e12320ac5008117fa8f84394f9d735d5191ec372feb397c1f20d252fea4220536488efbe5c6b4 +Msg = c915f82c68da043be3b0ea87411290712d8f9823fabf8524e47b1f29994d182ff826efc6184f15b08ca24faae5fa5b8a79e8d68a63a85de4cb53f39f6855a2a842226524bd254605d3f9c4dba1dc77ed2561f7894665f9981443bb75524ca300327123ee5f43df63401e12c27ca02dc4b960c2c7aadda16948b541565f18615e +Mac = 5c5a5575b8bc3676786aa91404dd0d7f40be345007bbd611 + +Count = 284 +Klen = 66 +Tlen = 24 +Key = 6d925b47dc7f208e8644c506297b09c0a351f4f9508cc53e92cc2dd4b110ba56e67d96a0b25b71ec7461bc3b3b3218f7d9270ed6394f0001f2b45f761be01faa62a0 +Msg = afd6fc648f18cf636c31b55fb6e044215b697c40eb2f0550fb85b857c7c261801b93c3147396dda561246c8d2f6eb197c5cb74fbce50499017a2123d3708c5b075c47053e6a47a7cd6d42be569f66e5b8274d6bae415e01898cf78418eddbe648711090b316a2c5094e9f94eaea104d75a0eaa6577a7515245b6f04b1268d302 +Mac = 5ba740f453b0b1033a06aa75438fd28d8cb04945169d4db1 + +Count = 285 +Klen = 66 +Tlen = 28 +Key = 5f448c3d3df6ceab97356819da0d459662b2d5a7366a5d46f2a6912a047264491b101f9cdde0b022d9844527bc401ac6c7a78fad80747e20a8b6cb416e303d8ee2ff +Msg = d52fce9d1822001f8a252e34b4adc81831f9da370fec929d791cfdae93271117a646f0047d246b940ff0c5895eb0ba459ed9c0f29a1d8d005485d9d4ebbf65bec2b93c2cdf6f391e9101c9da5608f2e1fb2a952105ecf06c50c86629f680834a72b13b7e06ab72a75a80c28e655b78d59013df2e1900c2cbb60e2c167c0f72a1 +Mac = 1b3459ef88671f031be60252701231fec17132a0baa75d13938fbc9a + +Count = 286 +Klen = 66 +Tlen = 28 +Key = 08e13bab5326369a2706c2b3e7e8f9b71cbe5646bd371aadae35efff8681cc6795be18bc269b1256014d7020343d46ef13fd2a127e81962b628c8e3d8268820578da +Msg = 9ee9136240b9c431747ba363a9b2b8363b1d57fb453898bcb7060821a80e9e94eda3f1a4ea69a7a7a81531a42874b670f7af4c1603cd6e7cad79ab441f069bf1e0b0174ba525a9046b44429bc2242b816c583e7b26715647c6c50482866f84c9a097ef1f1bf4b18ee48e3e1120c901b2c19f95f0572d386329717da385524165 +Mac = f6f742b70c95ce5f69fa8ab727004ef546d6de9d8f05ad9f84a0210a + +Count = 287 +Klen = 66 +Tlen = 28 +Key = db90d973356fb4bd0a1b7185f3d7154cc33baa866a884093193932f0a7daaaaf341d67240c2bbee2cd38dfe6cd5a5a11b69be2dc734d5047509deb125c6be6301259 +Msg = 37847f191e40347bb29e17220cdabf552d87c462fb84db32872c422091cd5f0b4e5ba4aa6966b520474acdd18fa65e73ea0ff76807056b4be32530c947a105b292eed74fb8bce6f78b2b24dd393cdd2c16859d569c2a4fa8b008a2232733b18789a3e2b0152a0e2505a9e3ef138487a73b537ed3c3dbce73793c61d63c6baab2 +Mac = 46dd7d3806c2f3d125cdc76fb6c57bbad30b823094889306b079b4d0 + +Count = 288 +Klen = 66 +Tlen = 28 +Key = 8ae4661c7667477d8fac08ca2d7bdebc3be232678e36975e7554fe1e922c2daae8816d7234ea8379811de2b7f76c1fbdf490a5975ea6aaf63777628f71fc72be0422 +Msg = d86d541a028e4f53230e6878a2046feceb7d48d31f663f1909ac9cb655a17731fca2ce6303f7d57e65fa8d4e4e7b98be89644c9d3c9906a2d322c1ae3a8ce7524f8c669197e607e72f8dfc8a060cb7ef4a24039020b74ded98e542d0e074a0d6b875452b25248d956a11dab4347d7488150794333388bb00423b48a5af214ac5 +Mac = 240360c4f6eb08cd84f19ae1a8bf2fb9e9186010236b8bfa6ef88bb9 + +Count = 289 +Klen = 66 +Tlen = 28 +Key = 2c0328f05f6a3541456b54b7a83c375057fcce496fe8b0f0d9d1bcb414ce007e352eda442cb05cdb48f7f50cfe384eebe6367364067033175398c9667548bccbcbf1 +Msg = 29442b41530e3624d63dbe8be39098c6197a7985f8c90b9b98853f019b1be41e60ba794579fe3f8060cc938c657d7b24eb3e7f83d4b6ba243aea30cc605e62cae87d207d463b9f1874f9cba2e7a9de41c33232b74b16532d9b525930998675f92955c9f1a00f7d747c8d0fd5525deaa307203b2b432f003e238561352ed94431 +Mac = 9f46ad82f553d16e5bf0cb802fdcc836b3954a120a5cc76ff4bc2860 + +Count = 290 +Klen = 66 +Tlen = 28 +Key = 163a9793132d4052ed9a4a84a1d8bce9843ea3273143aa0ec6e4eb2050460551839d6f0baf4c0c75ef4efff5a4d4c0f4212f6fe1a8f16978964f1a44daca1262ab0f +Msg = 8c8387f4ae2ca1a6dd13d29e93580b1cdf6268da66cf589ca8b1ff0884f7d8b8fe299f8e41596e47e0562653612210e4fca6c446a0a54a6e37ef80d52bd7bb8729e6b17625d197159ea98622235223c316367fd5b03a3c8145f2f210c910d00094238757627e63379e75bbb3e0d08ce1b47961309d7876fc59211c60678c5f4c +Mac = 629595a3b333c7deff011138dfd899e071799fb0d11a055031e7e2d3 + +Count = 291 +Klen = 66 +Tlen = 28 +Key = d291adbf05b06596c2f36f41a8cd8070370c42f687b8a6cc3a3e7b59afcd40f07801369b0fbfba17c460d21ffa1106ee937971ffa99d17177f017985b71067a8c5be +Msg = 121fe6f60ab4f1bc488cf456d129b67f48329824b32079bb823bd8d6cdc538f8dd75c9a7ee2744c233d117151bb9c22bd3e581630cd32b46fe6b5a18ac32ccad6ac0097f9d7446fdc3668a25b39d0f542583eb5d7495efd9a35fd0bf9fa88435c3eaefa5a105bf12003395ad213f65a347f21f3a75cf8f1c7a0082f22b8f2a35 +Mac = 13769cbf39507ca00e3f35476492707d6343c6219ef736f8ae0cea6c + +Count = 292 +Klen = 66 +Tlen = 28 +Key = 7b8e034879171a2d91c381f57e6a815b63b5ee6a6d2ff435b49f14c963966960194430d78f8f87627a67757fb3532b289550894da6dce4817a4e07f4d56877a1102f +Msg = 8125ffd2230741919ac7d4a24a48db2a19eb07aad0601675c4bc9968b7cbfbd5f9a7bfc0d289094e25e0607a4da0b20a4bdd98c12398dcd783d939a6a6fe61a67852459bfbe1900de98b74f99b58aac6290bb47ad3fa662e9f1ca4c044646dc7474d19cc64b7deb72ff19987fb17cb46fb9ee23ca72dbb6461ae641c59a62620 +Mac = abd14b96feb5500dc17da9b8702cf20945e50bc2ab988e88ac99ebe9 + +Count = 293 +Klen = 66 +Tlen = 28 +Key = b1e432c40fe047b008fb1df81465775fbf07ec31f1b6491c73ad3140af3a0689b7b70d3d89bcccd19293b70170ec0c20fcd2fcac88de0b2565abb91fa98962972e76 +Msg = 6ea76a49e84b90e62497e86455455bdcbde050e71e71c264725b9575db842acbddb53124cb44be117ff09ffd4e0cee6b3ce0e27f6b4ceac0daaefd1c4c062b2d855879babc52eb814e2fe233b0dba8c1a7584ad6bb60a6a4e94cc4e498346a18ce58ea14a4be3fbcf71d580f61fab46567112ff4f4f61c9907fc93d6a8560c17 +Mac = 286600f6c7cdfb95dd049833b2c95aea7ce5d413ca9a72d57b4b6af6 + +Count = 294 +Klen = 66 +Tlen = 28 +Key = 874259f08aca519d041a66850dfb15ca92b3550efa1f642a0902c523059d8a5a1880cf02f69f87d7bfa87b0d27948f87d47d474a08af8b317f01a7e29b669600bebf +Msg = aa72ff5a3704df376a5285d614f5f5bcfea6d48c895327c392725ea598959178213e09ef59f502e9fd99af5c77f47f8b4b919f80b1d2c0b6833d1a165a17b124f534d77bda0df2773f137f312a4357b0d8fb315d5c0c69b88810004a10fee3daedfb70e400733647f869fc3e750b05916d8a930dd028aa316793162a0271b002 +Mac = 647dfc6443e7b41e975aacadf853b1ea5b4281565c515b29d13dbe32 + +Count = 295 +Klen = 66 +Tlen = 28 +Key = 506dac5c717492f8f81266b6518ba7289724dbd113932e37ffb45d398f7dd2a33234110015df52afe8fd6f39e67301e20fc9c67eb89647864639b76b37ca1d2a6251 +Msg = 43f81c1d3d20a4c2d7fd4d412ad1a501d25eb2ffab9dd81fd8b3fcc00a21ea92fe3bf4ac48dbdcd95056f5339aaf84f44a0b6c88e7650be75f835f214b296d3a758ce3399709fc7c6617a44ecf7bddbc81bb61a4abd4880e072f6dbf17d24c0cafd42fedb313ca522229a3ba539b76017f54d7798052193dd8a06fc2f58451af +Mac = 318898bd97bc0e07a414cc256761d2854661ac876cd34ac76f7fc578 + +Count = 296 +Klen = 66 +Tlen = 28 +Key = abadd77b15e50d7a720063bf0e2c21030d0b3016520524d0a0e27a4bff981d4f62612f0e861107121da776732c224f4db29626718a7e575b92544b650d5ff63a46cd +Msg = a3dff5ffee2eb403696d2a4105d581d6be8231e37dc90b873dcb7c0a6d4a105b96bc35bd3e9e42bd0c0bb7672d8dc6b9f5331358cae4b9823ef28d447bf2a6ede4cc1dc2f90e11f37b86eeced10fef33ababe248e5d22c6dae0a0c73e9b82408d3363576e7252a8eff0558debb03042b2611251b973c6c31d63a82fe80439196 +Mac = 6d30fd7d9ffcee4525374592ccf5983a62e1603561bd531bbb74de9b + +Count = 297 +Klen = 66 +Tlen = 28 +Key = 3cb152647fac57b4b6d4b93c4faf7a487d72836d8b0f97b4716f86fba5fca3973363773e1098b725ab1a7465c67892a384147bf0c32714eeab05f13487a3c5f4d456 +Msg = 16a5c0cc8104031e789c05f885df407d931b9a8d534ee639df3bac7a9ebd2d22675ca212e91ec5ae4a9f928e0e644f763b6dca89ba09e2b901ef4882ef8987d8f793425e81e5bdd88d8da0e39a21f7e4c6547c3e36c619c8b821a97ea761ff76107329161202f5858b8eb55ff1be40ad7df739148f2d944c4ef955d48eec9be4 +Mac = 2fda3604f3b8f9b8d984a4ef4e80ba6e7d43026a31385324a9e16107 + +Count = 298 +Klen = 66 +Tlen = 28 +Key = f53262ca97513119b80223745950e85949dd67a5497904bf6df31e13c52fdcc23d792a97c219fe3ea628e0b046a2a9f2eabc8bffec7751031d75e8c9640b1f77a899 +Msg = a5deb712fc3bb9fbaf1398698b5696600fcd61ac68489f26a0f8ca32121a3e8c21d5904529662208b67af4a2f4dbbdc1674f3bfcdcbec714a0922c7aef63b911afd495345fb853fb4a7ac6ba00bb17cb063c148ecdffcbade1a958a5632bfb82b9a16ee9847a755cd2dab6ba963ccb05555c96682154d479cb05f5bb55b82c67 +Mac = d4ca2eec3b99d35d81821f3733bc58a5babb3ff87150d3e271aa5e57 + +Count = 299 +Klen = 66 +Tlen = 28 +Key = 085ecb69492deaa704e25aeeabb7b7795fdcc807b3255f2fb30081f425a9c7990ea104b7785c288c733965965ab8906057e8c99d291e5e7325eced197b51c9a4bb2e +Msg = dbda25dbaa5c14f4ee2154c01e1142fe8e84e4699da8c2393022f7ec60f8874670aef39702af0b3c8aef046802cfca25e0419795452cc57e7712e10591f000ba796556d5131704bfb45332d5daf35e681a85f30859a91e023fbbdd27e9b259cfde48751e455ca7865594078d0c46a5d12499204943e774cd726614d9d008398e +Mac = fce506c3a10a6aa3ffa75c04b9a7a53cd429ebaa70c23f9834c17092 + +Count = 300 +Klen = 65 +Tlen = 14 +Key = 0177a2eb61014968ddf7693ef03876eab8bd93cba77cf1267c8c586d718903c1b63ab1b51f71f9551a33de67e319a3f0fbf6e1fad6bad695d397001c7262eab9c2 +Msg = 20ffa073888de31c6f6ebd5e82ed588273431b2aeebb3591cf147a1492276ff20acaa05056f33a801221d582caf792cbb42a66469e9eb59925cc23a92867a7607c3fe1aee165adcd3590f8cae8bfd241b020c5687e31654eb02529658889793fdd270895102b648d4284cc3cc48d416acfeddf9676bc6e3ad8e735519ad50e15 +Mac = df78fdfd0444ccd0c61a4fe6dd42 + +Count = 301 +Klen = 65 +Tlen = 14 +Key = 8c5723251cb32615a453e346172818d138bdaf4668bf364ebcbc8f8f532be9d0e7adef5ea1923eae329f1d431f0e68d25cd7cea51d2e3d3de94d993bf073b4819e +Msg = 8bda936626ad7208c7784b0a53595a0ff69e3d8572d1f1ccb7f2fd9ab503ed9e6eca02634fd22878c0b328cefa931f6118ed2f1a719174f426ec3a5ff78a6de25bd95003cf30726b6e0fdf46c2a993e9da9f34b79c0f00455dcd04bcaff08e7f7a91e60e4fcf392bf816d63b54a29dee623eb3229b527b05851cc27a853e3abf +Mac = a8e445eb09f8a4a01bde6a023c28 + +Count = 302 +Klen = 65 +Tlen = 14 +Key = 933a5f5051062b9f8d13fb841803bccdd92c3d9db7eb3360ba3b80046c86b56786bbd50bc8a05c11296a7f65308bb636a2cb78a95d9a45ce84a4ead3dca7017776 +Msg = 8736d7d854d71bd931e1594b98b7f9484ae2ec4be759e395bcffbfd0dc6e49f372f3246555d90065ddeb0fa9f634bd4572099ccfa44a9dc12ae4861e0a9aa0590106b07217da2962776ca0b97e7280861209ff7735fd5141d9441b42f6cb2a65db766547c2620098a66df3c359f8abd1d1ebff8ac2fa65de73276684ca884fe1 +Mac = 59e80de8523a97fcb00c87046243 + +Count = 303 +Klen = 65 +Tlen = 14 +Key = b8a0f193dda4ce85b2650a8bab966204fbb0375bb48ad7373029fef1b1d99d4b447cd95feb2357d5fadbb759c2ca5e4c6d7a79ba29743e8d89117500278d38568f +Msg = 292835ddab618e0daee0b6df97475f90c057d09bcafbdad935880eed2d432ddfa724e007add9a92df60e1aeebaec4561c4df73fbc99d19b0f864075bd282e3603c1bd690d327854d7fba43ee4b88846574a8951ebf988b2b10827a9f39bde73710977f40c45209b4716c99a7f12406e1f6399fcd55f51a92a56acd7f09fc21ac +Mac = 10b78da020239ae95fed1b7f93da + +Count = 304 +Klen = 65 +Tlen = 14 +Key = 7ce4d1cdffa5f187c1ce688ac4ebe5d8cb3df4de64b02104260d60833871ac7613feef3588d022de0432b534131231ad23b31cc68ba21d9acbeb60b3158c3c200d +Msg = 27e4cfd8d255669455e3b7f28c8c19f835a2e3b4f6c38ccea20c1164b88a97112cf1524f6a91a50099858b471c2e359c5fe0f520d0da5a2d2b7c9d32fbb43bbe5ebae4da08fd949c8a5d00f9d49a33dbf90c797333957cd127d5adb26a9ce59943a54c21b3817b91b2d1ddb1bcb85bdc8c90385728dc39e11d7e0a8b0c2bddca +Mac = bbb63805037813d010b81782ec8b + +Count = 305 +Klen = 65 +Tlen = 14 +Key = 3e2aeff414980f918a90596057bf53214b7e80982a57d732bac474ec1b398e715765a9823ab60c9b641b76d49c0d0d0567d0972dd9f6ec15ac26ab308f1b2dc6c0 +Msg = 4c38ff755fb2b9126c1dfdf7e674e9a0e8b593966b43e5eebb89ab122ce1eac408b4735fcde2b9609564e026d63016f64b5c264232874a2bb8754144b2f9a2998d1870f0886bee4e20c5b5bdcc16034deb8f5659fb073a0b0b9e5f2273a0eef3c2ac1daef81502e3f688a44532ef58adaf964b622d8c5b979d4d2b35d79d76db +Mac = 95a851b40550d0a7b7ff96503f3f + +Count = 306 +Klen = 65 +Tlen = 14 +Key = 16756fae16602d367b7d334ef50dcce83c359de24a5b7c88c7d3865bc5bb6b11ad230ddc79724aef2404153f5f18cc8686eac58ed21c2bacd05a088a123ea22a24 +Msg = cc91431ee4fe1d68c272db25e344001ffd27092f8f68a0a5bd7012e95b90036348fe6199fd1a969765f60294f016a8d2e37427c6f2c7ed791005a72e8627fb45422c7a5f7260d0c352de3e0142544bd51c06b64dc416ae2e010245958b6e23da652477b96c5934b4313279b3048650ee51e69c0c30da4d8c376ed66592ede1e9 +Mac = 4c334162265eb10be0dde4bcb851 + +Count = 307 +Klen = 65 +Tlen = 14 +Key = 902f1d240d06efe2733480211d3f8bc0410fa411baa61e2d0a0b2c8a9f8746cf5514cfe63d13f4539d3dd7c537dcedebce3ba489e75b4acbcde72ad9d76af8abed +Msg = 8f1427bb8aac066bd10d83562af33642917e9858db3ec4d8998c7a0a3f21697886e1ae5a0ef898524828ae599361f3f9a59368be2dc0d3e7b655bf60cfbac4f5692808c080bb06e3fec88e7ddc700dd68a750fdd914d02d577753d4be208414b01903ed3281cd988ba932ca84c470e4007cd959f4e0dda0aa195fcb1c23368e2 +Mac = 67c5512170160e68c0a5da0f3715 + +Count = 308 +Klen = 65 +Tlen = 14 +Key = 160754416dc12ddb6e908ba3ae45462262d7ce171f0f12c6e584a0925cca0dce5de797d1b40609482570dfd1adb7abc50934b7547db4ecd8ce6ff263903a999aa8 +Msg = 726ff5dcefd28739e3159f932c7415b678b23509a015b8b638b3f40b64ec4f21ec38f9bb9323db70a595ca0dd057013534d3ce4abd1b8b91b12dd0908576e7bbf59480505460a680202cf2cfd949ffbd13cd1da6cb924ae7f7825e4260128584b40df264d793d2af7b617fa2f053f7973d268ce56f83dd01313904e99dcb11c2 +Mac = bc92da1504cfca63bfca80e3a78d + +Count = 309 +Klen = 65 +Tlen = 14 +Key = 7a711aa5e147b2c8f2e6a2d4825c0f629333a77dd6eb40b56ea8bb6ff7272f7fc7f644f973e5dc4395b8f96fcd1edbc806e768abfb71d199f9637389e69efb8382 +Msg = 1eadbf3cdb2b681802c2b91c500d754fbbfd59cd031d4f268a1ae5016582fd05b3ccc6f92d99eb29ff390a0cd77167253b7be2271f4f265cb72124478a2bc089c8acc901dd312f37461370fba34154490e3fda70ac6f727381906cb08984b1bf0456b19d117b9c0a7e58d52fdf05a484dd512bf1d1069b34926ea7828a153971 +Mac = 93524deca48aa93a37ae0f2eadfc + +Count = 310 +Klen = 65 +Tlen = 14 +Key = 508c8933450b36ec19d8320eb05a1a523326fa22b218124e0ea3da02166543f5f0ff40e2bb23853c72ef8e1e1379e48101ab9cb1a75120025f7032be92d92d6320 +Msg = 1b58f0aca0420effdd22e848be88da41a7988ebdaa68ce30fea99670ac8a6ebd8cd9f600706bc3509fbf69ba85ded942a885ee25de864261be6c4677545e92701946791e2132e1a497fa513967234c283a03de1ba726749aa7f1f1cf4a85fd8ca9e6a08f1c5d1104ad1ac84bcc1edafc445886286d0e0be2a37fbdfef8c75819 +Mac = 975b87084cc8ec2740b27298adf6 + +Count = 311 +Klen = 65 +Tlen = 14 +Key = 5a736de0d9a8fcebc9de8701a33af2841052cbdaade12cc20bc0e3e8fb11d1b708bd906e44225976480524f376ce109981f406c030b699bb5e0c316646dd69fffd +Msg = b221fe1f0235f4e10d5edd371660bf21ee5b83ee73459f545796f2c02345efeb7bf4feaea3681f17423bd1bc66d5324fc9986773535b3ecedf1a126042ebf0138934f793831c055f803f902157a6d13baef628a275e7bcefb4f862b38762c00b664ab275aa3aece24dd2e10df2bbe40a25dd8d22e3d25fde5d9aa762f990a7fc +Mac = 4467db8060232e0c7e822017496e + +Count = 312 +Klen = 65 +Tlen = 14 +Key = dd9e0fd3b4362c09a6e4d81f515c488a26d91b77700f845e9160aada8f524fb8d041b04d2251ad0dffa72a5a0ed9b59aeca2698c2ddb12dc9ea692f5cded8316cc +Msg = 6466d2a97de4380ec5e8de4fb16001818cbc67236b0bf25e6460748cfb7bc5f8dda513e4d1dc7ad1eb30d4fa026dd32265fa4d8fca01d65787d094da05804f9071d4c805b4634c21a6fa88ad7e3c9f138e8b7a652d2c60a1f4a5c6342d6a68bc88b9981210c3d6885e0ca26f0c148edd6d3797ad7bd2b5c611a7b1a15b833705 +Mac = 9438b86bcfb839cd01e8003bae86 + +Count = 313 +Klen = 65 +Tlen = 14 +Key = ee3dbf1adbcf3b4f7c6a2e6e78ac0930752c5ef32669fd5584015d025b243dca09478af7821d84dd98c31db27a3ba1a07a1b9c191386f96b2a5c679494ae0157d9 +Msg = a2d181ada2c60050997f3bb087ce48d956c18dedb22731c71a4fd0dd3713736b6d15bfceb1496c2d9ab4f95fba739e092efe830774ae2f0e7d7d438f030e68de1ded86931117373169bd7b054945ad51ff92b5aadc85809f42c3ad9bffb9890dd9de3ec56a3847a12f22276adb4c5bf9f1038d9e91b30ac292aa76cad21ebf3f +Mac = e75a82a8147582de87e490215006 + +Count = 314 +Klen = 65 +Tlen = 14 +Key = 5e99a57a7ab0627effb0f54f374c9357ae6ed2ed3a29c6df39f06a4d1a0542be1f333f6d60c0e3e4149ea5cc0ce19704807646f00e11e21400679fe1ce9e5acee3 +Msg = 68eca59a92986938366de60c16f60c98bd66d43e10d975a826dcdb67593055da9dcb8e521120be73d4a021de1a81a90d7fbef07d9b5f7013d6faf6b97d7a5448161f56aaf1c6f840006bd681e8ece4e4580f5f009ac704f268b37f0000e8267c7bf0e7ea5a127f6562d4ed3eaabf27e7f2620b0f369a980f83105e850a02333e +Mac = bfec482b52a9cf862e7600178930 + +Count = 315 +Klen = 65 +Tlen = 16 +Key = 36f787d4a10a902c83eaa21f6743c765b827d64532b28d5896eedf8fa2f48f774054febcfeb742edbec3777eae3f5a137b7814fcc2e353fbc8039f4e6a8dece957 +Msg = 1c1926623bf525eb461f0767ae94e459798e206b3aa9f7b2414458320f2af7a50d729e787da3c317b01c606a79b3ff9fe39d142b1f8e900bc020b3502b7922da482839647e51a2c1df0a27649f04c426cb6e014437167fa7b9d2d069941e8b943706a02d2847ea713bb1035e07cf5c759aca8dbf6c8be90e9220568534615c5a +Mac = 84f45010a01931c316ea556836051929 + +Count = 316 +Klen = 65 +Tlen = 16 +Key = 863bbe40cb6694f736b532b95e38fbabe0e49c15f7dc42c54def09ae1161b7d54aeeaa6e6b0c0f412771555386d5e1c339f904f22be82ae6587c54f1e225c88d61 +Msg = 681bfc9d5fd82158f117c29bf5e800142e8b6537152bc78dd9c96f4fa5767b3321c581863b80757b279acdc3a465e25d82059ab0612544d7bbe8c33c2522ef68d1c9381958a68d95b6507c3f965b9a68d1cd256731d1e8ec7ab05f91abfc1cb2810f697f3db42f4fa72316385333eedc23cb4e850d997a751e078a77bf6bc9ba +Mac = 3a396d83983e2ab8c51822013b2985a9 + +Count = 317 +Klen = 65 +Tlen = 16 +Key = 222324c6e0c10727dcafd04c2dbee39af5931a0f88430c77d1208fe3f2d27b572ba9b1c3fd315c348f07774c50ec90f0de18cb4027d029ccce3b0a04d072f1f167 +Msg = f6ccdb274b7a0b2cbaefa5b1732bfccb060fbd842511d32eab3487f7de38ecbdf10d7a23ce8ef9e4126ca16758687f94bac61ae795fe57c28db49a08d1ea2ee7a075e7f50dad057fff695c1d7b2bb28a269769b3052a5e0e8828102dc7d605930bea69c69040f9a689ce1ffc65da5e56516af113fefdafbaa478329047633869 +Mac = f31dc5d73ed29edc7ee64a43c2c45203 + +Count = 318 +Klen = 65 +Tlen = 16 +Key = 3698e0b369260224cb21f5e6f8805f53f01b49a1226ed2c2ca9924887daca80d0222765264ab1026452f4f4a750f9dd2c4ae65ce1430c82ab28192d3e6996c1bc8 +Msg = 186f894c7a7ff577f0734fffd58ee5cdfda14fe6ea7348ed4365bde881562447ecc50f22c63501c2c6d68063c8616b38c2448eb0faff74f876ce7cc1b4882f439cc7d181b34936cf9196d89295e32648d7371ec85ecc1dca94b8f6a9f6cc426810bdf8f4a9813ea83bfc7e16a6dcbb0524c226b680a2ec6c836c532ab0ec05bf +Mac = d9eb00cfeec6d000479fbf845d8f9339 + +Count = 319 +Klen = 65 +Tlen = 16 +Key = cc962a865b8e9786c746b593a9c60382922ab9f99feafed44e5f5cc79083714520f9e7a1124da674af7c473e80b7cc50a9648fe97966799f3e9e74005eb1237aa3 +Msg = 97a343c8fa57d6490e92fa99267229de2260f8e9dbe599b0c1bfa5ffc235186a6ea79e8659690d59c1d2320e718fd0ede53de68baf38313e1aadf2d40cf7f1853128c22555e5479f1278769eac205c8d39ab62c20547d0f634968ff9a90033a3274d390eb6738c0249ac4eb19dccd6a564d2f5f6a3bd7ec059a105d461f9e6ae +Mac = a75e3612e5802a07c66f1e8e5fc38e5b + +Count = 320 +Klen = 65 +Tlen = 16 +Key = e5804b099ee4b351843adb9c9e3c231773256e6a2070d697a9e29e258dca677f9d88a7970d4c58cecc20ed1811298a5b37297419ca49c74fe216679dafc938a656 +Msg = 80c2b135678734729683dfd38f835b2a69929973c6196812054b475bb9c07757596055c53983e760b857b560bb81da435b075acddb6db64edd1ebe23d50ea77fbd9e5d6c0bc01a0ce05b382582f144dc0c7f53c164a4990c6e0637267ff2556c1542712fc584f6ff74581129ca1ac07ee4c12c56490738d520cb5a6da0b3aaa4 +Mac = 6da8ec51c49a7b17470604c89316779d + +Count = 321 +Klen = 65 +Tlen = 16 +Key = 0e2afe79d45061100fd958b3cde9894101fb8ebc30cb494f6c73779086d488028037afde413435138cd4128b33f2beb088e7452f15669afb8da42d9602bcbf8c57 +Msg = d34b09cd3ab14416b09cdd7d23934f63fda285d89e00ec6009efccf7dde4d85488e8046bb73e9635104680b324a1ed319f961ac8c2b4672614b9ae9254b3d32ab1659c6f3eecc304a0a34ab309430fb16b4fa023e5af50e0829a8b7922ba6677b88b7ae3b605f30cc67ae484bbc1de6cc794c0f1ee37d017ba5a0bb63141bac1 +Mac = fac4fa165de196c31dbb45bd214dae5b + +Count = 322 +Klen = 65 +Tlen = 16 +Key = dc83196932db429204bddb545e11f30b77470fbe91a6290921e1f85a30ec7261010d90c1f436510caa9201ee6a5ebba8c3fa2dc073409bf78814267cc53c4f5f47 +Msg = 6abe03e3e8da35ffbd1e5afbc7484a20bd7bae42aee2128daa963b82bfc2ba3c2705c1f8bf1736d4bbb006d798a5bc32535452c5d94346e5be04f15d315c15b230a4b5acf86e2911c06c71b4a68ecaaeea6b7fec5ae202ea0d013bbd54252057ee6386077b27363f331b449ad84b9c1de986debe19076c220055c1ab0f6704b2 +Mac = 51f4c684bd5d2767bc29b50a33f88f62 + +Count = 323 +Klen = 65 +Tlen = 16 +Key = 1945d4decf3edb36c2b9b122f47f895758890b33e4c401a1e711533e9d9035ba001e9f80e21cfd99397329cdbad4960ca945ce0defd91e356dbe8fba907d190825 +Msg = 4d3e9b2bf9c3b617b44c26e33b391d08eff3ae5d1e2131e7841fe8f212abe360eee22042ba6cf7a519f3b5ae6fd988eae92a9bdfbecf81e7b405d73ee50e2559c32606795ab98981d5d3d60444d815a39c758b96ffd606883e1a7ca89d04effdd6f393f960143352f0d6d10d419e8ddc11bdc8a96c9f88732c441e59c1f407f4 +Mac = 2f9242f5538759c071fefabf6b14ca7b + +Count = 324 +Klen = 65 +Tlen = 16 +Key = d417cb62f6e212d8f01d28807e205983f67a4415882b3c4cc414ee325cab44192cf38a2e77acd05174c68f24091c8f62d65f07737550073d0033133cd48010d595 +Msg = bf436f34bd872aad8ea36a73ecb9d956f7b8b85e2a81790c8e488ae32d3d6f27ca6c13e5cfe2603387120db98d77b770857a34aa09952453e6b9c87689ed1802b4390fcf76c24adc5936d1dbdd6a35ef2542dbb4f1d29780ccc27ce887f7f386e56f0bfa986d102f6cd75fe0c3dc785a41d95583c87efb1ba72d4e420ea2293a +Mac = 564b7e4bee1dfc9d0dc87b13737411f6 + +Count = 325 +Klen = 65 +Tlen = 16 +Key = 71e7e400e82b5c08b93504fe4d5f1f299854f8b7e6c6c90bd864da58a906ed6fb62bdad53ea677196694ba64809122528c2c5200ff980067c4a40de881ecf5271b +Msg = 42d491ea5dfee0de25fc258dd7e2b64b8c3d819cc551449847a5fc9429c29ffe2b370d8949e0448a9068d4a2310d949ed4a3929b2edc506ed6c62d43549521837ba3adfcfab5123c2d80c23d396c144857973b13701d792deb97909bc3e17ac4dc21598a9704b1baa44bd5a617879f10be20644ab29c279c2d1e0de69b2d1186 +Mac = 1dde990057e9e5fc1597d40a96ef0b43 + +Count = 326 +Klen = 65 +Tlen = 16 +Key = 40308baaaeaa0c96d2c0824cac84878853bb9b5edd34232c8359b1cc0104860e3c945665273f4be0e7aa4c5c36b67ef9059d0bca653f23d1a7b6412ac230b086f6 +Msg = 4f33ce5a0ca5c3dbaba37308b0361842c4ee4ec8fe1c748862405536a7c5079c3eec14318f07d8ec86e72a5a4e973fef5c4bca9ab093689b57d43c9935f9d6ef01665a48912dde6b588513582d7828934ddbebc0a483327048b6793b47e0cc0fa287e8c799819dff29657627d43f9cd7a088f862625598ae3cce544365e2b1a1 +Mac = 6cb4676715ea1e8d2e80917aed2b9c9b + +Count = 327 +Klen = 65 +Tlen = 16 +Key = f2440f1d9962bc3b08f5a6d85cb5709cefa4e4b67da23718853c8ee4f2c6c021fba95eb348fdf18a565b82191cec600aefc61d30a379dabdf3e4c4b5224edfa2e3 +Msg = 033c85fd093f7f44d62fe4b8d464fc8f36d3368b7d84ca1741469e922ea167eb4d0c106e84605fdd618dd6c3138bd705b9940cbae091063c46d2247fe401b7a22c5963c49013c9194321623d431faec897878f22d524ef99e8c9a9b01042a7ba2a8b48a832400420065552cf6d07c9ff5712866c6725cf53ae93f5cdba4b7f5b +Mac = 4e1617b4f3c7a60673b53ac9759eb9ea + +Count = 328 +Klen = 65 +Tlen = 16 +Key = e88d816ef8596dfc9ace3855a2c4719e2d314129d79144f62e8b977a67d133a05048790e86690da9e8e7e85b4b91a914707b2c0e33585e56042b50889b1f8ad9e8 +Msg = e3fb267a7068e4771dba2459d3c8afd54408752f73032d5076063c197a1bd8f709376db788b53f9c040352af2e9c8757a3360729713ce401d77efe524d2824bac4f07cda2f94256442841a757adb5a265d94465e03fb4aead561bfcf951410de9f8f1c8a6eeddcf761a44653bf6f7169fa8cf9733028a530f71847375ac9e48b +Mac = c3dcc373089ae07ae14ce87e6c6ea1a6 + +Count = 329 +Klen = 65 +Tlen = 16 +Key = 61b8436081a6cb0ced5239b0759900c3444ebe39139414029d8ab4d3532ebb28507b428a8fd52f0d5ca7511e084bad7be12a12836124f4b0a63277622249c9de94 +Msg = 574367744a82a21c896365d984254bea473063320094d547bbb1c9c7713784eb4152d45efd1eaf4fe86117c5be794032f593f54c431e3818608029470d0729c655223e9113d1b9c8b45a17043e3e26eb916b6902eeb3bcc3b57d3bf073ba61261b1b6db594810aaf74b62e3f0c5a433ca42085fe073aab714311c967aa3a7533 +Mac = edaa89fdf65337e298f6e93a09b49283 + +Count = 330 +Klen = 65 +Tlen = 20 +Key = 10d2f20d367dd00e9f40d366b4eb5597402d1be0d464dab36ab4fa69485699352733d35695b2419198cebfdf946b73636eea0b9ef2fb45e672b2b514b0dec37eff +Msg = a5b15449447080caf01e9e30b527bf5ebe970be71bd2a76cc285dc25d3dc75bd20f66863ec96b91ef31b9c60abb2dadfcaca75a008c88f5426fc88e82fd46758fe507bc400b642c53b8789018fb1d5fd3c060233a5ed2a655458c8303df61de447a9d393083ae168d04cae3aea8e79611e35f8c97aaa3f45537fe42586a8610a +Mac = db6cfc1e40588096c8fc8a32ad0dd3e3f06d6fa0 + +Count = 331 +Klen = 65 +Tlen = 20 +Key = f57cae320c3e91519c0907af848a150c1426a1887c99866584dde40f7e4db959790ab60ab89e4b9863df05337b161905136141b9be56c63a44e9debd999039010f +Msg = f7d570f1a841e69ac9c9cf9ad3ce96039d9ee22f2cf50c60ccc4d6a35f305afaf6de40b99e6e34317d45978c1d9075f80785b80894ec9b5600df616ec0ce46e715c6b6d3e2f2bd5abb62bfa13e0b69f1a60fe7159d3f570352de7ebfcca8ba7d7e1338061bd5675caba6ada1df475835a1c3d71ff0f52aaeeb4a975f2bc99f02 +Mac = 152aa2a9ca84d9a119cde11ab2786ec1a72738ad + +Count = 332 +Klen = 65 +Tlen = 20 +Key = 9800f1cf94d7458985e6b1b7e35511d705ab19dae6893c7a2898cdce59c0651c769b84eead297b6867c589d88657448febcc3af03cc3d9c6e4898cdb5b4827c6a7 +Msg = 905a86d4266e0a4cf1b4833f418de2aaac858e23027bff1b84038860500874e520b655c6349699878dfb5e9d5c9e882fba85101d99299e42fbd75bf6625700d787cc34ca4edb143cfa0f13ae9d7c0470d3a375acb0963fa7f75d5b448d97f7ca2d64c9e65c83a4f4a0b8497aed717ff560a866d9300b08d3e15b3151ba128144 +Mac = c1d64f881f209aca1e71d652ceb4fb2c044f523c + +Count = 333 +Klen = 65 +Tlen = 20 +Key = 3b6706f63011b61d5803e0e27e72324d5cbbe7bca755eb7a4c043f93fa50a0e7e036637eb81da41b040c9f1497195e60582595f243c6ca45b085b839d84af61d95 +Msg = ad9f1777ecffddafe66dc3ad1f691a0b1785f81c2abe38dab50cc1207a380c1a46eee0f9d11360ebe558484ac2107413c23fa29b39f3787d9fd7c9d7f10514b6541c4dcefc92e06f4c4cf4b43e6cecfe066b34a0f2673adc95beba0f24db3f282050e75e3525662363704d535b268db22c3136951ec385dfdee91e2fdc639658 +Mac = 140f4c4d0276a65f818e470ff5c2e5edaaba20ff + +Count = 334 +Klen = 65 +Tlen = 20 +Key = 4c8639308778b5ff8e4ebaa3cc52b3e6b9ae745f5be0d88b0d68a8207fc3bf9dfe9d6c26f543188fb45729b771c726178cff1b9a185e3faf96e7d49d033a4f1816 +Msg = 0c067a267c1d3d06a29844c52318fe297fab8fd89544726a6a6863c126297c9d5f589e6b9af7125e0fed70c1adfdc08c5ef9e0358c3326c8e435453a5ab275fb6dbccecaac36f5cd798dfbe10da3822fbc0c22007a7d0bd29f81ebaae76e12adbd98d4eab9c42e7b67e0adcc4af18c3a204c1ce0680969ad22b51bbad6479adb +Mac = 2f5cfd5dfd814a621e61b32069cb6cc31633078c + +Count = 335 +Klen = 65 +Tlen = 20 +Key = 22b022ebe5e54c4f4f2359157a723f282ec538aa9dd918f25160ded1625f891aecd52d61c09d45025a954b66140086819929249f9b4a8861c9abe502fb0e0cdfb0 +Msg = 4809f31e93423cabf44cddcad23da7d7aee734d311fc7babc276a1bd3d35139861ead10369350d421d0af4944959cc006fee3f51b996f66031836a9134f1f7a0240a339e5e077d366c99d9357b87fb4a0f98a109f5b326367a455441dae37b0dfb31bff55b02b61147c033b54f0f5c3bf6ad0303ae9c33b7038408d41653c466 +Mac = 3ac5cb202059cd7b0b063c5e4685fd82cef6c1b8 + +Count = 336 +Klen = 65 +Tlen = 20 +Key = 4c54f5d9075f6129957906a333bd22d641d93c80981115af1f87dc2699b9a102c14b0c9e99074fb3ff2259c481c04cb972bb32ca3da0ec9efafb6ab43fd5220339 +Msg = 84b79f9225d965f614f58f3b3be1eb077599d45a9534571ea91694ff8066667c69c3463e3e326ca9a15b38b286f6d1f0f2800cf501328fde2e333629cf0db5c7df5e7f7200d0e741c04a857a1c68dca7432939ec9ce8de97098e60f96e054e756df013d674991ee5fa2a403c05215555f0fe26e66b3e8e71c38ddc16643879ad +Mac = 541ab01cb0acab20a07c5865cd9206a607822f89 + +Count = 337 +Klen = 65 +Tlen = 20 +Key = 2e1d1e60bc725f17625e47a14189a7175dfc3dd1feeb35d857d1ef9e66c303ed1bfd831ebcc2808b8863cf479b9d0c0c1127e0746e8c806c3e3776e6f8cca4cf28 +Msg = e3acf3a5aa3ec9c2bb1471913c0a64768d4f28b37ec622e6c0acacd39a7c6764dd0fd2ee1a081cb6126f37b46e9c2e97b157b8096a3d0d33ae66f884c5442eae24cedef29bde899ed0d814d4ec8d1c8c945f89dc1ba56678f651f07570d0ec529f313e38968ab881dc9730781da5d55f20aec3b7f9c6d4bb80b5b92e01e64a56 +Mac = abfd5b066726397af51e7848ead93946c248f285 + +Count = 338 +Klen = 65 +Tlen = 20 +Key = 3d30d557b07a4750159a3daf763e3a3b8a12cd94893f0bce3e313c5f5e9ed53b18c4a73dedf255c9c2490bb034c46d532b76ce0cb213a3c906b237faecd1a0ae48 +Msg = ed3ebe140121faef029f394fd1aaeee71fbefb2575cfd3c27780db97699517b2f2ab02a92026bd2ead6c6ce48151de7177d16cd5640523fa5650258b19da4c0a003f111de188ac29625a7d22736daba21c400b38790b430203f62f7e1088839d9e62b2194c2d0f09a9d132b3b1e79ea19572a1f7bbc97b0306d8c21657880492 +Mac = bc1575e3d988d0c648f3b062d4021fe21c19cc45 + +Count = 339 +Klen = 65 +Tlen = 20 +Key = b283986e9b347d19cd47828842e10d1c2b7a8629da305feede6151cb7078e8ae0e0741cf6517139d74bcecf7efecbda0e19099ed96dcbac1b8dcc5bbb8504eae6f +Msg = bd5ea9709471f063a8af04faa7a39731703e289b1ac928f6381e5c035b188295d94837e7cde918325f16287f463b72ba8bcaef098f2fa95c4f052144e78aee085550a8f6803604f77997406600c1c2224aa9fce201dd92c98db9bf3b92def5eeb9e0c344b43ffcd87c991656dd1dd091354317cf79ba2b6778a2fe8f64fcdd6f +Mac = d783d8ffc7dbe9157820c888f98a11da828239f6 + +Count = 340 +Klen = 65 +Tlen = 20 +Key = bab01a2698338360d0195f5b6bdc967429cf80b1c2524a9a71489c4ab3cb78c54d1e668c8ce2ce6fd08da5a34c194b1407f9b4fc2651c7b56e6603cc0554685678 +Msg = 4c36065bc14e9a4a2ba707dc3594688802f527e367a3cd22570e18da9e244f0bd275d25d8795f5a9c3c20ebbb2c7cd579a20cc79105f67e16dcfcecf7c56580c75a01b292f79b90b917b7ca84aeaa60bc1dc029e4f9dbfa8ad517e15a8dbaa761cfe08481fc28f797d1a792865c39aad616ff1d98b237d7effde51328c7beb51 +Mac = 6a76b2611700fe0131acb8942726ff8f6cc8044e + +Count = 341 +Klen = 65 +Tlen = 20 +Key = 1290f597ef1a2ea5d86389387ab23d76ed113f55e5ae13152c81e30e502fceab992f82b73d2b0dd7d7a9f05816ea752bb212432ea58a30ae97a356299a7c695817 +Msg = dd71b1e9855a93b02caff3ab234bd4269a74f6316e5d4a4542efa82ad1c9c41782865f1c3e3ebabd7e4f50e0a85dc4e99b971923883c2162055e38e65ce7328329d991ff24dafbbc3befec96e488a90fb1bd75aa24d70694c6123a8973a107f6f8f3b05be0353ff48a182f987fd469e1036d728dea34e224ad9218dbbd012cb9 +Mac = c45398f08016897cb5f708661c11d4e6a3c68308 + +Count = 342 +Klen = 65 +Tlen = 20 +Key = 2f637d79583464f88205488a5823527f7703339c2628701b4147fdf477aa0e5bb6d22a8ae26081c0cd367f8a64d9a141261988d4dbf54cc782b9127c8b69e1b246 +Msg = ce7be970d6627256e245fc65ecc0fc50ab417b0b1578bcdc23081fb5d48345c17495753d1e7f3e8980c75e7fde2ee30359e390db72f682c2ca0f14b72b60ff9bccd8c6fbd19a512b12add7941df5024e7e624ef23e67b3a9a9ae8389540a95225fada353f89bf163205e2f4cb2fba15aa1267df581b295bb494b35d357674f7d +Mac = 19dead34aecb0ff62d8a49d929dafe0603542595 + +Count = 343 +Klen = 65 +Tlen = 20 +Key = c220547bac570e70a718f581606fb2475ade8f72d7af7ebafb895d192f427837c4f45026d8539b4f7e3d8bac199353380948e8a48ab7044cd83a716998f8848873 +Msg = 0fb4096a9ead69a90063f445b8dde49e70acd4f33c20263323bca20fdce85f54d5e6e7787a079672b31f43cfae362303e080e9fd469032fef1c821aac114466071d8c5c7d326b4a95d35c405e50e245fa989a25b9278148aba22f6842bf35437ea71eb7e34728bf6078cbf0de4ceb05bd4ad4736a941928086b269c4a1ed5181 +Mac = 32a6c0bf8ccfad8ca05f61d7150952a26ac3036e + +Count = 344 +Klen = 65 +Tlen = 20 +Key = 4b2d7771eb7560b6618ef1b97d0e32ef303734b7ab835191c581b68b9de01ffd81c9e2760f732ff69af1965ed04ec92499dba44b42c86a93daf252eddcfc42310f +Msg = 5a4223a8d0a0073c8b4abe3c6188fdd6d4ab627c9f4eab468fdc2a91945274ed18465a368f291a0050c9d638a31944091b35a8fd26a1ff65e2d17dfa32ef3ac412d8293b276849ad9af71fdf272363f771d0fa99996e24510e7bf731a7480cbbefff7801c0e5fd0a13dd8278162ec1687f85409a203e82d2bcdf7e7d1ae55098 +Mac = 1e1af030e41c9e2f3c566618672c761e6de10d3b + +Count = 345 +Klen = 65 +Tlen = 24 +Key = a4a4d811966ceadf62a5a5bbe900077a3c97d3a453d1e4770385c22f2a6273852d8e9476a48da8455365afc35dfffbceb4d13f18d4bae92ab12db1a8ed9272d64f +Msg = c1568521069cbd9d644b8dd40da4c5a182f50b68a56088fa16dde1b8bc8269fca20395b40575b050ab57cfdf76d208743840dfcfc9ec0139571835b0fe458f4498aee6c1d716898e91c32ed55acb2be4588ee9d4538495680c391837d0954a0e4c616290a307b21fbe999100e41598b98ae811be6cb0ac4ddc4674975afc0220 +Mac = db81a748dbbaefdf4b68befad4fb22482589a76bbaa7c07f + +Count = 346 +Klen = 65 +Tlen = 24 +Key = 27a60a681b49ddfa89d6f5b77eb36c6776fb4312212f495e66283e18a95039104912472a6d8f55b2019350f0fbc78afce32860d492b71aac3a721285a6841901c3 +Msg = f03d7a4786405f0f048592b2af0da0d3ac38fa6f1489a9c04baa3d618db006b4c99f8781b33128df15d32b5865f1e1489d731e864788ea46d7a2793e3ec25e08bcf5fbc8f61e3c0e48f785fe5c53e8aefca69ccf24c6aa905cf3eabf44162e317146bd657790036447f886ebbcbb1ccc70d75c92d4cd526480a6772cc734dff8 +Mac = 74d2ae245ece88f9c8ccfe9cd58a910ac1323bf9f8bc25a7 + +Count = 347 +Klen = 65 +Tlen = 24 +Key = c7520854d6114b4de62e526366aa2747d0693196dc93055ef53b7fdfe93e128ee46e5c609ff0fd44d5e3aaf1f7427de3200c8fa04ba2c940c470f72cdccf1e26e1 +Msg = cef77f0f5458c63d03e0a86659ad1eb1b2311e4b562bbfffb6d59d08f35f7f23a09d37e8c9fdca5934bbd1bce6581fa6e948a4594deb914f6dbebd1774d348601f7e7e54c452fe27934b1bef1c4d82b611cd1dcd4dce38641610e3589f84974cd1021cfb4b3ea9cca8f94ea800748f08b12a52525fbefb653933d5727e5bb40f +Mac = a72c58000af7d23d977685ae3efa6eb76b09bfce75d927f2 + +Count = 348 +Klen = 65 +Tlen = 24 +Key = 3c03786d819eaef79b65583b492dc7d8feada94e888ed1b5efc13bafa0154a9bca09550b09de627842f13135ce487da2da6b7ea20d75b24f6c6addec7bcb4f1aa5 +Msg = 3a90bb64db51cf5f87bd7ec05f818dc301d22b6eae0432c5a859aa3ede178f74cbddd31f9c36a744916ff7a9a5a6338c712455944eed2008ba94a53ffd540c580c5d912bad6ccd7edc9e377d6d86ea64f47da97fe2392054f0a26c1fc1e0de7ec2b9fc6e561ac97630f34722ff4839b351862d15b113ba11132807c473e38c50 +Mac = 5f243d6f888e29bc447407a4e7ef3b85407db622bd47ad30 + +Count = 349 +Klen = 65 +Tlen = 24 +Key = 54f866bad7657d9fe8363d0023a5d0ebb43e5b85787e3b435fa08f5d15b4f680e1f19ac4cd4c6ddd074ab2958712c07af2c602d3be1343d9980728240223fe6441 +Msg = f29ecfd0800a8fc6411f85855ff4bb02cc405fc1cbca69ebb3207ea2ef8c14914a44d8c76ae14cc59912b5d5cc92349edd5733f61c0d02f706c2c25554e383ee3867a9a3e34a94674a3d80952a9ca98749a0b36400d64a39f6cf064c2e1991ad446f0b0df32dadd3db07ad6d81f962e49881a9b47f0d87da0aaf102e851887f3 +Mac = 484886256aef5b2bc23f658baeed04dbf0ba51c5545fbd79 + +Count = 350 +Klen = 65 +Tlen = 24 +Key = 65309b249cb1e909c3f432375b0d8a889fd4b9ad52952a7eba09048fed8596044b72f8a64cfdef367c0f1201c3802bb4ea88e0725b76932428a486104faa43ae3d +Msg = 285d724315837eecf49476bc95b83a277110ae8f2f35605a6de26b47bced9b02ec7cd1f68b75a962a8365bafdc87df018ccc550c6880a32937de60a8d7e1f1687f6ff1a648d1d713ec67d229cd9af8be3911a0daec280cc6d69e4c651f8d5ec769a09afc55804e26488fa5d26fd9cd89004858a1c317e359d288f6269dda2c47 +Mac = 4eedc0eeed8ae4bbf0f75e4b2747f570becd75e8fb82e5b8 + +Count = 351 +Klen = 65 +Tlen = 24 +Key = a49757f96079b41b8f6c978074bcebf8f5c66be1410a64e2b582bcdd0133331e8601e9d903c721d371a7445f2b9f298c525d939d7055fbb95b1090e45dc77d2e91 +Msg = 8457f876c7a2194ed6f7d72173209e3e03fcaa85368ac61bea435a634dada42a422d4622071c0192141ec04b46afd8de3cff8e0c0200da7eecbd6ab7c5edea4629c883403019a1ed4d95fac2756bcc8f831c65fadb8de92c4d5b50ca3d6eae2701d1b7b88bc082c848038d6c477b02ba9efb38360a597d8dd5c41386fd577835 +Mac = b4087789c69997e3e63e2b78d76210bd1512d9032e7560e1 + +Count = 352 +Klen = 65 +Tlen = 24 +Key = 5c29dba60f2bc0756df2070aaf605b757c152d7268e15686bb7ffe4b7380bd088c8501857eb1b01e085e0e152c0fe02d7ba6d27492d81660e5dd4e1dbb6cac267a +Msg = fda29c20ac76bc2a8f01b99a4de2042c7aec76655dd638dff734e0e240a6dc33b45014310e8acb1d54d8c6ba131cb116ec0abea74fdd8f9987485667f7b03ba9a398fe2df25ddd48b223b86e5c0f730199b79c6706d64d5f34455495f4269274d162a13bdd57ba53b1cad5e0af2311968ad957cd092b3ad807112293bf72aa3c +Mac = 29b42fec8b65d8a034c569b3639e35ed45fe668baf65b6d3 + +Count = 353 +Klen = 65 +Tlen = 24 +Key = 3841cd6169b790e99cfc67b49062acc2140d4277cba77bf12c563999cceb54f8e05d3ccdfd75e05c23cace08faf09b245bed850712ec575ee3368dc7cb5db99b87 +Msg = a5ef1f98836baa3d01ec74316b1dd08e420fdc083c2ba87d8b6c9bce62cb12eeb6fa493842547f06cd15557fafc678b092fc7fdf7642171bf8545d18d38e8b3aa7a3d7f0f99298437bd6abaf8edd153106bce9a12d216d420a897898e3b31e7900548f67b20c3d1d94993d68114bf03826b7e2f769b0f2194b73b4f59a2213d3 +Mac = 7c84e28943ff37d99f3784d4e0e283895b0861dc0e229bb1 + +Count = 354 +Klen = 65 +Tlen = 24 +Key = 5ca4724b67ce55ba0859a82ac24f981ed97332815a2f833d5bcefe0984eb1e82cf294c7e8b25029da7a931212d23e0ff0d5516351c4dfb5f5c983a857eb3a938a5 +Msg = f397ef4e6b17f7e0fbd5b5fce7923786517d4244b7a6f3f0bdb5a28c2ddc0bf63c0ab0bc0f6279317deb9ec11789c681652c710a734793888c84810e46b6112dbf0efdc4259389197ccc66299bbfd53d782010bea6c2e54a1c51a40738433b38040ca00eb7916fc07fe0d5de7d1eace211c0e70859ff315ff485d1200c6dd13f +Mac = 1140dd50027a89b3e1b9781c0e21868dd95b12bb16a7c688 + +Count = 355 +Klen = 65 +Tlen = 24 +Key = c5a37910b4801faa8863a2e3d1e541d2df68eb7b35b651953be6409133802ed76ee11353c0e07a3031b1d7e3f50a1b6c9f8586d89146bc0bb7dd1cbc756d4dc1dd +Msg = 204bdf1413f0c1424f2a82efb6eaa2af5e7c8f40dab71163bc77e5ea574da913ca74f8143a07d5f75e724da84127584d439201d5614ec6d4b799428e43050951ec71d409c338de0e88a88d4070b6555625efda730fb254fad29d38a4184515d0902abb1a37eaa32ed6b48bdfcb0061730d7d62416b4b837f146b10555c749335 +Mac = 923824589ffc23ca14be095bf4237fa564c5164c2166985a + +Count = 356 +Klen = 65 +Tlen = 24 +Key = beace32bbd37ec50cae0c0a78d816277413709640a651b9489fc5911aefa576ece3130aef64a77617e097110e1d381dbcc6de36174069de02d78b39d39cb9b87dd +Msg = aebb0ddb94ac86c60ecacb596cb2534170a8a107588c689c1809f235e810c258fe8579379d38f63e4e16c1e86ea1aad6e89dad22440c19f1e15df2477ee19320ff7e97bc6ea7fa3a418b7c68db8d46da55f5d0397de502de1f8e9a9f84a3cde9390e311011e3dae26d92c382bb6070743d18d2f40cfd6b8c5c04b3e50140b9de +Mac = 6ba183e7610508e8aef191c3c208bb0684b350b59c6691ae + +Count = 357 +Klen = 65 +Tlen = 24 +Key = e6dbfff69b0104cab9199c9ea93f8af771af24a828736195ac3f34bd979918786e3cecfc1cbf02269f7273780289b55e8b7c6fb535ad8b8d604c8d2ec877245ab4 +Msg = 5c66a7fb28d32b47f88bd22a0c5987ed56fb616139d5822b92e73f60f5fd815239256aa936663cb5cdaf7702290e422d45220cf7aed373988b406556daf98555fc6fd0b174a980caec3830df786c42df1fc87e7b98b4fb8051724364b653b21eaf2b1f3b6a02bf2f5c0c45e982dc4eaaedd4fd167de0e28ced6421b30f72d055 +Mac = ca2cade091327cf3fb9f83d543fbc4ca4296d871f225ab20 + +Count = 358 +Klen = 65 +Tlen = 24 +Key = 74265ebcc2b96a8ac99e16b7ea7bfebfc93503545fb6fa464beea1a66917d72ba63e0cd413fff6cf3890859aaa011a68e0c1f4c64265ea7e83a560bc31a7746f8a +Msg = 1ac16a8327e1717b5e1f5242076ec700b5e71042d6112e58886052fbaefb953443c2e979ef905018d8bd4cd9bbe896de3bf312cf794e0334e4797c2253c4171a515ae82eb77db46581135f61da62a43f791809bf308e11a5c24db35ff6d20be7e98e50eba831062cfe2874248b6459eb165edb5b2558c073cae5e0f9bfabda63 +Mac = 68372639ac68a2aed91e6f38056a3ad414e47cbfe98e68e9 + +Count = 359 +Klen = 65 +Tlen = 24 +Key = 8b5c106d1b31400cede8d17985c77fd392909190c307521edcaec5ca09d395e272cc4b160f82c324be2ce1b5935d80816f41abbad42310a8f733b1911787dddb0e +Msg = 5ae1884d8246fc46d6cb2face902774aebb099a5d72d9785ed0ec9b063022ff958fa0679098d991d479a5a61292f315afea914fa851dd89061f7478ec7e1728f7ae74998f9d8689ef6ef34490bb227f8a91b680551f69f4a068a07e4027bc536a8ef7831baf011d3cc12e5eef855002bd44cbc4ea17f93bcc50f323a7c98cef7 +Mac = 5682f8cda124027ad605396f1c245fee952dfe626350461d + +Count = 360 +Klen = 65 +Tlen = 28 +Key = 4b0f8fda08017b10b647fcd6cd04f7870c92b2687574f238998c6008158e314d5db50634b8b511358cf07aebdcec01230f05e433f35f038d011f4293e3db2fad33 +Msg = 2917cd5724319dcb5c08d917b67f25628d15543ff717d18249153d51dd92597e12ff271495eb4c2fdf74b911ff018a739a332e193018c9a9a0a2d6bdef581137454c94d5384d40054d5d5efabc6686ff7428c00b5f76ea96e7a25aacb936c440c9e45dc296c040f4afad11f97615e1ae24de523e0d99fcf126fc0f45c4923940 +Mac = 453b2373ce46595855f6030d243d1646293889416f05373e78126f59 + +Count = 361 +Klen = 65 +Tlen = 28 +Key = 289e2aece1048674bd571a4dac53043351a78964bda6fdf67e3fe36dd82f568d5275a86d750648cdd0c3e9a93fa8e00f6d46ce2d987380ae94401347132b5c8c23 +Msg = b453fc9e54122b181483005c4153cb8b47cef47a7499e307fe9f1eae484db1576102d372cdc1c646892aff8649a8872604eba16cb299ad4a55404ceb3690c58c71c7a88db36cb1c84340ee213f72245e2912703aa2c82ab474c60eadd6fb9eb2ec89c2178e7ab2454aae1554ac186bddbc2ba809c98e21ee6517ac1cb1f70372 +Mac = 01dafb716c50b09457ecc8778141ca84b645a232a4a39ed0230c7349 + +Count = 362 +Klen = 65 +Tlen = 28 +Key = 4713c6d4e3fc1120bc809a8aac602c84f42a29b52d61203e81d8a2411a5f52a4dba13c124e4d6843de74ae7e4733cb5c4a91b5cea5aa2c61420e92c1af64fc7cce +Msg = b7f3179604e8e4691d2bb56aff13934c267cfa6e006ee7a4a2f9323aba631e36c4862fde81733b7aa55bc45bd0b0851cc0874b28c541067c756a20afa0e10d2f873924cd4860ad7c9d7e3b55c6203cdfc496ce8ec899d489eb3249b01fd7d5de66d69e6b42f761f66c5cc161c8addf1c99722aa7f2c079526d1857481e8c9dcb +Mac = 530fb3af22bbcead4242be2a723098024c330c9b29fca7d8d65c9c27 + +Count = 363 +Klen = 65 +Tlen = 28 +Key = 5ab1382f18a2265fd9ac5d02593003b494c99cfacd3b2ed4d5a6a2918a006ee79ec171439ae01e5e22ffdd117ae3ae6a492610ff9d30218230630696ea968de1a6 +Msg = 019978d7f84fcac4c56837935ae64de5e212bc019a08c276e275e60294a0e9b394a7fa4ca80b29ea8a6f1ee73c9d0bff9ccadfb1381bbde86368acdb893f9032bf2c596a9e377a7a52af9cb7ee2694f502bd93ef70a29de97bd63d9321347631abaffcf982dba5bc44af1ac91789d20f3e724181eaa34cbf524901f2058685f7 +Mac = 5c5930eb8c4610658291dcbcbbbf038b7e4a2992592d7453f68d4ed0 + +Count = 364 +Klen = 65 +Tlen = 28 +Key = be8a0d3f26e96bf4e16ff35223d48a7c16e2e12e18d94a442313cb7c8ce4717cf1c4e7176db047cc0dcd308f884f19cd2a99e5aa12a5b78d9da707de22edf60ee0 +Msg = 0c89ea6c61c4ca583f88a1a9054b5bb092fb80e450f0587b721f52377990a683fd123abeaa2dc3d789582c1a806c3b491d5972ef8f1733f1f5e02866dc9de2a8029ec0ab608d138e68a57f708c1fa585ffedfe69bfab0ab4d3d3abced130cb05a49545dc8cce03a666d764542e4ce08cc221eefbe99325eb935ea2186331abbf +Mac = f905f3cfb0a221b8a14c57c746415c966e6ae18e0b710ec5e7f2b8d3 + +Count = 365 +Klen = 65 +Tlen = 28 +Key = e85e2a6b2b18b5dcde245dc6c3d37d21bb0bb130d13ff2117a9e03931b8b0d47cc4e86da5c0956a195ed3d76c1ad6fc36d3382dc6c938a921f3d8305f476efb92d +Msg = 83cded802398cf566ba24670e22b28983ddd007f799abfa52678ae78060aa7c0d6e2853a6c53d983027cdf38d281b05ce31cb8fa22556b0bb48d34998bc1ae25370d1747ff6f029431ce4bc4b63b5015e9765eeaaab46ab8ad9f0222189f83634e588bed0574b14f9fa2745cb7de728afaf4db98383f2474bab7005bd72b8c42 +Mac = cb6fa9b5c2d8b4cd957411a897194c3dbbfc614098c78ecdb7aa69ea + +Count = 366 +Klen = 65 +Tlen = 28 +Key = d83efe16354e973367648ce9c3127b6f7957b7da1914ed3456bf08cf095b51d879a8db2fd9971e761200e269c3975f6d861da26b76d332deee34f42b93e34c3294 +Msg = 0df219910ce5b0bb03e05b21dd747a7413866d661ff4a66d347c02c42cd959b4c22e541101a87e07fc5f9e17c07e455c87a4a3132e8a9e5ae9e52638368ec2de0fe06f2c6461ab77c8a5cd8a6b7097ea481b0e5f9f3989afa67a09ad7ccfc8725ece15eb1d595e94cf7a8f82c5929ba7beb357525a4a8ff5d201542be5e393f9 +Mac = 0ae2eceff877842b3d77b4210d391f42151b696006c6974722f0bf46 + +Count = 367 +Klen = 65 +Tlen = 28 +Key = b74637baa33d5a7443304b85aa7260f48c788b01008d397184c67926423961f2926aadadbf06aa850ed45396fce8b9bbc81aa8a331b68727817580dacaace1e270 +Msg = 0c671581ca7648fc5717d4559b9e83b568a757af5d64872b0b35c4a25779c0911fa5f12721939341181cec9927e8d33a7b8573382db74d9d650f7ca6c5bf3d3005adae6ddac6d6db1d95e6772914be2e85c2b394c3f590d8a772daf88c3b593104a8d3babfb91bb1aeab4b5667c94d77cc85a02be7c758c3198567fe74941c7c +Mac = 69269527fe9a121b9098c2472e1250577c66e1ef48a432059488f3ea + +Count = 368 +Klen = 65 +Tlen = 28 +Key = 411356543a5c2819773ff2a93fb94894f575bf6eea4b5d7675084d74466dd7e8f77a9060e4ecce2a3d045f2b598a7b0f4d12f6a3be7eba7ef3c475e72ef18ff33d +Msg = d1287e9a5a8f7f32ff9bb5c9d0a461acb7815474b8b358da78e1cbccfc858dc0b4e41d48b843fee651586022bbfffcdb292e40db0a2bacae8bfc7cb35d208773b87c6732a098dac4670b68a27334463d412b7b92aaf741ff6502ae55ceca932ee5d8a5819af6da73489d16707fad077b06604dc22081df760fd9aad9d7eb7b99 +Mac = 818bdeb99de0067263ad93afcc03b7bb91e076d16d1cb2f2762636d9 + +Count = 369 +Klen = 65 +Tlen = 28 +Key = f105508d6a45d37a80a7f963f6f927a9f5cf7594f3d2b248d95ba8f56441a04fcbef293ea3b916d60070c689de33a89bbf89fdd795ade081e129848b1da6be0b58 +Msg = eeabda87856e3ba98a57d619be748ff5508a2cbf50b66818665042cac4149b0c598400024788c584985853202c9bc262f6d1ab5269ee373f2c477cbb15b20ae755e9c0f1f030e5da7138747ddb42b6cde287165e5bd83227f2822e861b744d844ba4c25b67aec3357dbee037b2b193be7b7718e810bc7e571ec7ff31bca28d6b +Mac = 55b681a0747e9f2db56762ff44129ae29c94f5ffb933156197dbc655 + +Count = 370 +Klen = 65 +Tlen = 28 +Key = 67f86b8af7c8bc9bfb568522f9dcadbf23990354e5197566bab882c64362f2709a9cc4b3e4c8689225a42e6b5915ffd6c0234bd07944421952dd47dadf06a18bc9 +Msg = 9f552fdb9eb3464a75fe354c3c7e748dc257eb63d1b958a5b358f0c0f41c49076a19774b73c176ac7e58c8aecda95e9079f8bcd9b6375933587d447c96b30d1b0e91e3900ac9fa4f028130cf6207efde8cc05537216292567d63928b80b2dd4e94a4bbd2eb319bdd0960b5d68300ef200699fda69aa2cdb728f422153a7f7f48 +Mac = ef9157092c101ffe29e2770231cdb0721d3b90d2d0c08344eef32d70 + +Count = 371 +Klen = 65 +Tlen = 28 +Key = f67ab51d4988b3e9d55f05b379acb03c84d498a42993982d2de3d243e31f44b95a689d56d5484e907b95e39750989495646f17344bb0b962cc4fad51ddc2a4c1d0 +Msg = 69d557b16e874038598b25f616afeb4f4a900be7dd0d38b5b6fb4259c51a3aaf4748d7a445f518485ed72b25c7df8ed0906b74bd29bd6a5724ac3a503c990f3697a5db484821f68718470810862728a80ce34599a41fc5bd8bb46dd845a4812ae1532c457ef4211d0e41835e5a6f030247614822571c930c727ba397e723d6b3 +Mac = 39eeb4ce5ac153717476531a8b0c1659bb77fb6bfea052c9b90e86e9 + +Count = 372 +Klen = 65 +Tlen = 28 +Key = a629f7b9614bd8800a9a53196555fbd55174389105dea58b9adcb674cace9ec6f71d70576e70842fee231c9664f54772f90006d04eefaec1066b8d6786d6d04ff8 +Msg = 8ed85b5f96565939cca9c21728f9ef816229019b59af6d9fb5a3b98acb158016c2a4bce9f44c450c9780949e9d79cdcad8cdfdf662439f3d3ce66620355836780e6973afdbe87f30acba7e1c6d285d3f0b7d1242d9d1252231206fe15e9f227bb94f091b13d2118f537e09f960b0a6c84262cae784000534dc785d340e914a05 +Mac = e51184d7cae852dd4464bf04cf3dc35b201d286a995d8c045ffb025c + +Count = 373 +Klen = 65 +Tlen = 28 +Key = fb396dfb0055d6c7cba8ff2275b9e569fa6189e38ed2eaed35d730548e5e2a03ef33fadeb70e0fede0d054bdd40aa70382bf8d83b06b2430934359959dbf5a7396 +Msg = 73db1e155da94a056e175a070f7b994a888e2c6fc220f4e1510ab565b16377f2d0f72cc2cdf494a900e75ea63ae790b84e1028f2d03403d21cccffcf9a355d31411969255a2b5c118717812503b897332b8c77c03e66f65b61630d2de61f37d2cd291b678bb46be40b8f0cacf357776328eb5f009420942327b627a81b8bcf7c +Mac = e9169a8bed8cac987699ee1e93910c43f6285d5ededf37b4ea99fbda + +Count = 374 +Klen = 65 +Tlen = 28 +Key = 409cacfdbae5ee2a9f3834dc416c8c354859fd7704e07622012c055ddc38499756912a6ea75ec7d0159db060c4af561bd017c03b997f7f5b5efbe3dd0e926f895a +Msg = 6b3b8dc256f249335639de72e3faa5433bc8ef85580b996f205ee01add35773fecc3d743b91bd770eb957c86db7312724bc47b5d5589c8e8a11706b6dbbc5a2c64a5517448ff71c8715d14ed1a5a76fd867f0c6af1671740c7207aaa14d5c8b83baaa25fece840c2505a4daf86f7f86d53c048b515ecaffef943e3fe6ec8e96d +Mac = a73e3d29d57b71298c9b3c6e9e52737683285bf7353d5a7b9c14ad6d + +[L=32] + +Count = 0 +Klen = 40 +Tlen = 16 +Key = 6f35628d65813435534b5d67fbdb54cb33403d04e843103e6399f806cb5df95febbdd61236f33245 +Msg = 752cff52e4b90768558e5369e75d97c69643509a5e5904e0a386cbe4d0970ef73f918f675945a9aefe26daea27587e8dc909dd56fd0468805f834039b345f855cfe19c44b55af241fff3ffcd8045cd5c288e6c4e284c3720570b58e4d47b8feeedc52fd1401f698a209fccfa3b4c0d9a797b046a2759f82a54c41ccd7b5f592b +Mac = 05d1243e6465ed9620c9aec1c351a186 + +Count = 1 +Klen = 40 +Tlen = 16 +Key = 17b52858e3e135be4440d7df0ca996f41ccb78b7d8cc1924d830fe81e0fd279c131ce3546303e95a +Msg = e0eff00f3c46e96c8d5bd181283e4605348e3fa10b47945de3dcc159ae86e7bd3fdb13f2ada2c313fce6a69efa49a470689b1ef05aab778ae15dd35fe6fd1e3a59d351c68cf8f0ffd968d7e78b57377afcc9dce3fa5db1f06f6985c4414c0fcc780030f49fef791a6c08edc2a311080c373f00e4b2044a79d82860f0871bc259 +Mac = c4061427764f979468ac422891dea9ca + +Count = 2 +Klen = 40 +Tlen = 16 +Key = 7c67410e0a9e3d7ae4f3d04eff1c2716891e821c6ec1dc822142ce8d9949b1449a1a033a350f0ba8 +Msg = bfd166793abdcffbbd56df769150d1466c18a67af452c7e67f86ed741d163ebbd874b9d33a91d3671099620b6eddbbd0f31117164eb73ca201db59f1650131cbef5c7b1bb14089fd24da2919241fc9303c02def424ea861d88636bb90b13ebc38cf177f8a8b139e68082fa46bcfc428bd054c1bb7dd3ed7e9b86ed751736b6cc +Mac = 1a0d427e79a7bdca7b11579339d0ff77 + +Count = 3 +Klen = 40 +Tlen = 16 +Key = b2c450128d0744421c3f31fab37bbcdfb5a2ff2fb706d1f7e23c4886992c7d215c648ff8edb2eb59 +Msg = f6989ebb07aadaeef970f0b5ceb806ecffe77cc20f3c221a6659a9315dff5881961900e68efc320075edafd83de320c6f18f0892489af6d97a2effb252b76b9284ebaf6d42089c1e0a5cd509c20b86ff060d5362c1768f89fafaaf65f1b0fe656b1692984a567e1260c7499085b79f5fe7684779a25855f291c5a192637177c4 +Mac = f0d7c63677033ada0b502a4e95b20e43 + +Count = 4 +Klen = 40 +Tlen = 16 +Key = a7744321d73938b8eea13754909029881bbd727439fe2731b1c67b7083eb7b5d33adfcca65f5d189 +Msg = 71299ca3daff2331082db370bdf8ceec227b71bdc49c3b14dc3fd213d3ba83e2058828ffc6414fd5a2c99891e9c85f316c5b9bdd810a067b4df97f7e4262acfee642e30ed6534b4a0b3b3eaf5d03f2b045ca5985e7bb45c7503cd03afc68fbea9bc09579141d5fb7cbea6d73208fcf913830715dff98401f6d708ef009b5b8cb +Mac = f6302c5fd7c8495e233b5d6129f361da + +Count = 5 +Klen = 40 +Tlen = 16 +Key = 795a0ba9b02984cfce5e7395fb94d98fcf12ae5db8a06e239c9ad439bf42e523e65a31c3bdf356cd +Msg = 8b4aa20de6c1f051d11ad50ba2e4fc4ff1ec478455f9b5b96fb9893d2afca969402044c101ccb73c50e2b2dfeeae9690fb64222ab9c94fcd943078785fa8bed9e174ab6390bb16a29c8146cb2fd65a98f44de752d6b0e42f0af2c3df4f65e162742d201c1bf5d22bbee1daf8efc30d0ce491df2632173b8ad9e9b29b819cd8ac +Mac = fbecae19c2ce766d286c8ce70133b669 + +Count = 6 +Klen = 40 +Tlen = 16 +Key = aa41b5222efdea882cbebd11d343000ec2ff6b2f7bbfa746158ea54f32d534ae31c7d3b7a5fcc373 +Msg = 3274a0326682ba59d6c47db4164e3e9937bfad4199c6507101e5305aeb75d2bf22eb68558d59496f4c389fda04645f0676687f6757fc631b5bcc98cd947bc4d9fae8ddb14bb09a7f15f4270c105c1de0b25bb1abfeb52ce39d3f9baf2fe6c704e3f3670d458e95d158807f10e53d5f6d1221add336fa9211ecc7a1c767bfc286 +Mac = cec1ed7aa0f1cbd6b7f667a079a88577 + +Count = 7 +Klen = 40 +Tlen = 16 +Key = aaa449923f0cd3e6a7e74d9c56a7eb6a3b4c3dea97e6a8400e5517fcff54ee4211b640280eee415f +Msg = 0486d2647e2cdf7bba36c8f3ff9e2941001c706eb1a44cbd582f638ee7be4482899c9ce07be4ac381d44fa4649004718e33ac273b1707b746d461a731986d12c93658f216908773aee4690af8eb0be275ecef122f7ac9c94859569d21b1f2bb24a6813eef19e28ca56c5f1f776b474b69a6165412b5f9766c7a5b6759491385c +Mac = ae73b3740a7a8a07223635faaef0ba71 + +Count = 8 +Klen = 40 +Tlen = 16 +Key = 6c13d74ed004ee92adb44b755be92e8440434704a1c22790b788f50406e0629aea80de53730b0d99 +Msg = fd5cf72ee0779aab7daa27d5c8a8d31f4082ba47741e7e73c6e631806fbd7597c337e101b609a73ca0be744e3dac9859f827677069f4dfa91c008b739452a62a8f3f84e98cdd2ea08bba4d6614cd49107aacb1026100de457e36d3da9e78684eeadca88f69db77fec60478c554f12d6b4f7b60a6652ac27074efd35c9616012b +Mac = 4304f9864598f801c6aa1a692aabb8be + +Count = 9 +Klen = 40 +Tlen = 16 +Key = 12541d81c6958221c44a958ecd7f48c08a89a8687d306c2f3814c93ecd498e0485456c33d5fc950c +Msg = 31f51d395a06885efc34032349bc635cd4b1004ceafcb1c426a2f88b4045790226eeb1084e09e41c4ab157c19d2ec027cdbcfb07b98efecf2d130fffb47835d3ad6eec22a12d1c86d4b94cbd1a64134fec94d071bbc69b2a84d37cb4a572da25efff364ffc7b19e4c3d34ade6965451d5bc0e95299ab711d556aa572bc3c5141 +Mac = edad94e7c30813be7c5ac58df418d8a8 + +Count = 10 +Klen = 40 +Tlen = 16 +Key = a1e8cf95c6d729507661fcc687156922c8975645e5f36eba8a3069eccb298e96c498767c7c741259 +Msg = 48bdae9d81f1beaccfd00374f522f90cfedd8e3dd93be13947104a89f75b9a48ee1ba48f2d64fc308eb1fea7f07c124d930c2fcfc58f9edfbf680129caca9389a686b17b2b219ad3312a73aeaeca8ea81e9deb4f28c0ffd87e2cb5110542b39736a6de49c45120fc7ee269717835f3846537cba548f98d8c4c036e29efea80da +Mac = d78d7d266cf83add4355e7395b63adfd + +Count = 11 +Klen = 40 +Tlen = 16 +Key = c7e5ede152c50a935e76b59979e08638a09cfffd01ac7008056a18ab8ebf8d347e955e06788ff6ef +Msg = 1e1bdaa984ca68730faf61c697d5fb15955b28992d69bae86c68cbc9ce735c4703083c04f2042cd0ffce407a89d288e6b731f06075b66530b90d396f0b2fc91944215d6396de4f4ecc92707cd308a7427a66db00761813ada90adcb6a41aec096acd046c76401b140062b8737d61a0516562b11e38750e87c3c87c47a01b0c40 +Mac = b7de3be2fae6ab41aa6386b8460223c6 + +Count = 12 +Klen = 40 +Tlen = 16 +Key = 6ab37be64f4b1e032c5a43dc03e4afb65c6ab1329fbca9c4c10fc766224f158eb6b7b85d649e7319 +Msg = 490700ea587a001c7162f0946f7ca6a5e3655c6e09ba4c13fa7e7d4e22bcdc27f56d8effde9b85d378c751bf018939c10c768bc0754630cd9a3783a8c8ac6486f41a8711ac2412b14d05680a752f3fc6bb31f9949ede3170bcac9426455af211aed69429aa5dd13d56e4dc7cb3b7e03a5a604ff16bca7786c7a656ce7f0eaf51 +Mac = 380eaf65a9be83322508498748504b50 + +Count = 13 +Klen = 40 +Tlen = 16 +Key = 785a1189381824a8131e885ba4b23c2e94e3dfdc03652cc32a9cc1963ff72452997f077315b0cb67 +Msg = 5bc93a655f35d346f9e96e96e9bb560178dad04ea46259917d2d30a2cfed14cd01774fcb3d62f3f1d2d164a8d68d161d0f57983a147cd2d4afa98b2686012e7efa6dcd36503366e60ecb65d8a8ee6bbc5cef4e9d5b4e6114298bf5bc46381fe50e52bc8dded1b38c787e7a0ea905dc46294bf961c2018eb9b47a764c59b9716c +Mac = b452d180b9cacc10cb012f48dd19e4cd + +Count = 14 +Klen = 40 +Tlen = 16 +Key = 394575dded531000e776ae4adc64c4affb5b220ac5a96ebf1f72d19fa6aef00c42711e5dfe6fcf84 +Msg = b733d51a7eaa4b6bb0e378a218caa6ae7475a3f32909184d34d7165264cbf2d8c60753b861cb89d12498204f1d95b52dec3109f8760a54d6de0edcc8b1dfc52c607c2b86f41f6e7ffd61cd2ecba43797e1b25d71a7a20c2d5ffcba335a1d5f6f6cdc860c9d6da37f2186a7c88bc1d2f43d42c8e72399e858a1e9d91dc94a65a9 +Mac = 3f6417a99d7186bc36e6d0d61467360d + +Count = 15 +Klen = 40 +Tlen = 24 +Key = 14d45ca2a3d4977dab2b7d442c6f9e57ce348e0a6a808bb3cc7f6002b87789912afd98bce26ad8b3 +Msg = 0c294a318b7c1e884649fe54e4a87285e42f868e3d0a8519414e05f9c78b236089a11052cbd4cd593e22327b23d33569b35369f9bf3dc5d694b8a7762106184d5c5a5241e1ea805ddc46c4c92ae87efabb0ccc263bc24dfbf1412b90e77e589c4bfd17e615e7bffcea5ebb28400dd6a0c403b6fdf8c1a5ee2191982e601a69b3 +Mac = 28f1b663213043c4d4fb312bd36d85fbe62c8008ce82aabc + +Count = 16 +Klen = 40 +Tlen = 24 +Key = 2a0466dd515d2f48fec5e78e22bb22c606b09e8184691c5177a46e8c70fed24dab147ebc41e97c8f +Msg = d60812433098c44623159153de7cd2721b349f685c43388a74c2a3d04a8e972ada4199177c61657369d78f907ba26a8934cc29d3029d4415c1101e3a8283e4c48bb2b8639fe60fc67f6a57b1b03fde507f10efcb43683e1ae223851b962370e1f144b74f1f9189e66cb831dc05bbf46e03e93877a50dec40dde5239a0fd5022a +Mac = 7c2e5f1fdbda3c153536ec7136091eba0ba525b950bfc84f + +Count = 17 +Klen = 40 +Tlen = 24 +Key = 3a4182af8c3914d1df57b6321fa5dec68748ad746e0369bb64fc2d9b7dc3dfb3ed9063a7d5cc0ec4 +Msg = 3db052695a599813309fae5cf5b19690d3e1e63b3caac1487ef10766978bc9b04a00008c728e7ed397712433bf6256d2865eac3471a8ea5f8011333d02777941ad8c384deed864d47e02a03c364bb086245b3130de40875a16b418296f9eb8698fdc63767640325c0ed8883d03738cf3d460ddf72b7981816a611ef186096c6e +Mac = dd3334fabe8d0d51084c1e99a2a7fa8548c4cbbeec854fb4 + +Count = 18 +Klen = 40 +Tlen = 24 +Key = 56e8ada1ebc8706b94f99bf2290365222f6619a7fc3161151cd0c566f4266faaa5dc31fa34f8c9ae +Msg = 9ae4b799989bc132e5a50c4fce6d6e44e2940c6ba7dbb8248b447d191d7477c77d5ce83a111889177a171ee0c77d4d74e8c5b0d565ab292e504976157880050ddf99094f6e2ccdcae84148681db6f39360e1d7f83a75ea8a60aa9bcae398ac46a7e44060169f3551156bb36e37e005a9312ea85a8f03a240a5af15c2c786147b +Mac = bddd77019ee3e2a16e65713089b23f0ef13e5f3ae6da5052 + +Count = 19 +Klen = 40 +Tlen = 24 +Key = 1e6d00b386bbbfb7f44001c5915448a516954d7a2ae8f4e9eaba807dc98c034a9aae19d1eb4ad624 +Msg = 009f5e399430038250721be1796535ff21a609fdf9f0f61266e3af75d704317d5506f8065c487218e99eb4c3d4546c4d607016901138739dbdf437a5e6f5021a47d69211ad0237eb08768734c2c952cb4f69d94306273a8a2ff62fc85deff88afe99962030683a43d683fdfcebcad1c11718b8e080c53421e370fea6e3fbfa17 +Mac = 7794f8fe7ace77512eb98a5459aaebe28ae1e8c62832b5d2 + +Count = 20 +Klen = 40 +Tlen = 24 +Key = e2127a48f615eeafb927ee53222f5004d11dd2d3a22e5377826b43f08174586a297b82630e932210 +Msg = 1dd28756d292e5a4f3537e88777933335a64f79a4d50257aac791799b083f450e61ac946dfd6dc7e29613d947fdb9d433d7d632b177dfdd1093274e8917944cf1d576a5abfe0bed528578346d4963df382b0c224e7d6942aa3776ea074ab1df1aad2911bdb7834b2d77d7b27de72ba4a11453c0e2721938c61902d4bc0e328bf +Mac = d0119cf3ad1dd9e917ab325c0b85927819ed606084542944 + +Count = 21 +Klen = 40 +Tlen = 24 +Key = ee0a81a8bd52c9b1422083522d37f8071896ba625ffa22ad32a4fdd1e85c837796b6896ce194f74a +Msg = 0c245de3b250c33282ea1a02d007f03b34ed427631283eb614db4d521f555136e7e42b4cfbee8134c63dbe3bb79b5a8b9f9f5b9f5ac61cfab1c54d197f1e3ba613f251eed616df952d691b88a16466343ef2d0f63882ddd2d55b8a6786308b2257f5d7b38af166bd7f1339d2d8899c9eda8fa86215850ba547450c267eb3c914 +Mac = 335ee9a4c96bfcfc38c76f7ace6c84adfd0a57a94efc23b2 + +Count = 22 +Klen = 40 +Tlen = 24 +Key = d4254694ca38676404cc2cd6a444f61e230c188a9f92d4ad769287bc1397203808bfd6cd5dbe1b7b +Msg = d106a9aec442fed61629e77566f789b28c2c2c3ec628878a12f73d37da6ea7ced677d4b12fa9ce51e01c1fa2627b94cc885a4124a8cac55afb2bd0f34642e2faba8c55f319d19d111bfbcfa9102960e5c6002fbdad41c62339a1dd7e88d5205a45ec335ecce1f27e8f71fd72b82a746610c5fff31fb5124e95006fbfe84eec55 +Mac = 5adf1391c94a60602cefe1bcc610060de90a4b7b8822db1b + +Count = 23 +Klen = 40 +Tlen = 24 +Key = 61b83d7ff9b82b32a89225eacd7c9c25807c8dbac8cf56610e88c875d2797df99d566bda3718ba73 +Msg = 96560a07f7e398fc739648ce9a924350fbf9b45239ae7c7f626026867dc41d7862211c71cf12e77bb78839afdd0efd9ea251c0ef1bdf6749672f1d7340e290b9cf485d92c526c881a7b6b13969f0c4043f08ef65b03819fcecbf11ab5f2ac4f786d2b4b102a6a5d5eb2a99b266c0ff4b7a2728fe1f41fa639819e877032422fa +Mac = 312cd3f6c27e3ece5ed08f1020c815277f7e98bc3bcd0248 + +Count = 24 +Klen = 40 +Tlen = 24 +Key = adf13d80eef135f3cbfe63ac19e8679b98c01dfd263d72db335e76d47551b31ddd94bec6c95a0b3f +Msg = 81b8de7e17cc5ffdce4f2213b561d67d244ea591aab5c37f47e946d7db97384bdfa9eab7536b8c5ef7ecfb76bea8dae88063e451ef58804ccc9396f35b9ca2a3145507009b25a539f256ad8eeebcb40fe79807a6b4bb3f57d6ef15c7f49277fb8884db63d744d3172655e1602be78d7ac2b3b698e1272629cec3695a8fc3dedc +Mac = a80b1a06ed13f5579a785f7965ab180908a07f152ea81e2e + +Count = 25 +Klen = 40 +Tlen = 24 +Key = f870e26dd47b20d386f63d12458c46d795fe0790bdc81d2e7c025329f8842bc5f74dba955126b93d +Msg = f4d6aedd9a34e0a1822362714d4e81794b53b266417678c16a97887bbb612cc96bc5e532b3a654e5d3d65a5155427ff09569906381138cc49e3fc2384c5d33c34abd3d617c487b52ec6ee7b5105f41584b7eb5cfb512b8c31f3f338d5236e30398a8ff927e801c8ed7d14fc5040d915a737967d166ddc266f68023a357530431 +Mac = 68934f2d0de64c4e4eede0b1d867630da790c111371458d5 + +Count = 26 +Klen = 40 +Tlen = 24 +Key = cd4f85a044eaf7c5a9850d0d708f0905049dc27718679a8f3713af3ca3b756d95c19c50d7fb90ff0 +Msg = bbf96d794a6a062fed76429a8b395e5664c6b1b0a26bdf083137507ad1bae0bd6a0cd84a9f111ec1a5faa889560f36b781ac4132858a2e141e40c8537e0aeda0a0c8878fd94abff9b0ca6d9fefbad20ffac189cc6000bba9b09993768e72f1de053663901f9d519db3ee77217fc29826760a71c55b53ed8e8f49972b287a543f +Mac = de9a7e21d30725d253fc4d09a3fd21530d788795d672c057 + +Count = 27 +Klen = 40 +Tlen = 24 +Key = e6e97a286f575855cec8a0f4d06327929d41f81d3fdaf9f65ebdcc474d85f4974b08399c02d14d50 +Msg = 99140d978b2e37f32684f3bf075c4678fe4b3a95fc93df7532af9096772b7707eab95420d9827970e2ba19f75877c395e9c32ac37def2781602b018fa454ebe0c10dce4c7f11498516c8f74c9318f0e57d7d92c8b95c8199ab94ec5a9e5712e0663805834384ae1a09d612277ee6d34e04a2fa0c7880f3a55912d95e2ddbf5ed +Mac = 61a0693f740c3b121238cc904e98c671563d506780960a00 + +Count = 28 +Klen = 40 +Tlen = 24 +Key = d763c6360763561ed2bf47749080549b6e2db87514e1ee1c85a0bbd346eb6e3cc29267cbedcad67a +Msg = 41677677d9b19e249d4488c3eb18153d5b705002ea6aae4258d59560ce421aa4c45e0f30227f3d35a57cee6685c2afad55a4531d2af33b29ffcfd51358bc63a726f9fe28eb0dda8b1ea2cbe3d196081d915030ed8e508a08fc0a9194b8f5b0dc2fdf4a497c83fd8ed05d282217bdaaf3d81bed595daa2448152fd0cb361489ad +Mac = 014d599f9490a22b69824f8cce92f30c0542cea92b621a10 + +Count = 29 +Klen = 40 +Tlen = 24 +Key = a4b540971d9bdb20b47e8282cac841a86fd94fff27b4eecfeef893cb7b1347e7c2b24d69bc7b0543 +Msg = 50ee2389b8b70182548ccd7e82de8496c6b3602bc99efc7ca2efba77552762d099af0b51dfc93f718fc65a27957a33001cedfe70995371650c3e26228313414bdfba523cda9a7d9f49c5d83e9f6f1415b3a560acc33c8aa4b807678fab4d7605a979c0f4b314023709f10e6aa9a76ffd12444c884d408f5e2eb04565d8bc4825 +Mac = 431d287099550ba9e523dd1308b0514cdc5faddb04ebc4c1 + +Count = 30 +Klen = 40 +Tlen = 32 +Key = 9779d9120642797f1747025d5b22b7ac607cab08e1758f2f3a46c8be1e25c53b8c6a8f58ffefa176 +Msg = b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e +Mac = 769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b + +Count = 31 +Klen = 40 +Tlen = 32 +Key = 09675f2dcc4783b599f18fb765583668a0fd8ae4096f6fcdc60d4f35b4130fbefcd542ffe7459d2a +Msg = 0cf2198c31376f5c8915660137725f2bbc180a986e5a7bda27fa81593a4a339bab92cbc39fb2b8581108ee48c794812d845a72ce8008c9e915d9e330bbb90e9136aa53ba0e6693dd4046d6b03362dfb9edfa04c887153cc5de677aab8c7839d517035879679c29727e96c5426324a2575fbe678d6cc7fef5eb6cebd595cfddef +Mac = 6b142d4dfe217f1881aa0e6483b271dd5d43f70b85605953a0fef272ddde46ca + +Count = 32 +Klen = 40 +Tlen = 32 +Key = cfd4a44910c9e567507abb6cede4fe601a7a2765c9755aa2cf6ba4814223811a26a8a1ef499cebd9 +Msg = 3fb301cb4092f9623aa5ffd690d22d65d56e5a1c330b9c4a0d910c34e391c90a76d5401a2d3caa44b8c5d5aef3e928b90d2ee233e9f9a2cec4a32cd019d06a0dc1fcb1125f5746a4fbd32169ed7bf0e4fd065fa7c8ac97c366380484495f5c5b6850dd1c9d8cd6694cf8686e46308ed0ed1f5bdf98cd831339771db63de5a7de +Mac = 20153bf8ea2953c48251ebcc4161f8b6e28499e5c76c24014cff4a9e2f62d25c + +Count = 33 +Klen = 40 +Tlen = 32 +Key = 5448998f9d8f98534addf0c8ba631c496bf8a8006cbb46ad15fa1fa2f55367120c19348c3afa90c3 +Msg = 1c4396f7b7f9228e832a13692002ba2aff439dcb7fddbfd456c022d133ee8903a2d482562fdaa493ce3916d77a0c51441dab26f6b0340238a36a71f87fc3e179cabca9482b704971ce69f3f20ab64b70413d6c2908532b2a888a9fc224cae1365da410b6f2e298904b63b4a41726321835a4774dd063c211cfc8b5166c2d11a2 +Mac = 7e8cba9dd9f06ebdd7f92e0f1a67c7f4df52693c212bdd84f67370b351533c6c + +Count = 34 +Klen = 40 +Tlen = 32 +Key = 9da0c114682f82c1d1e9b54430580b9c569489ca16b92ee10498d55d7cad5db5e652063439311e04 +Msg = 4953408be3ddde42521eb625a37af0d2cf9ed184f5b627e5e7e0e824e8e11648b418e5c4c1b0204bc519c9e578b800439bdd254f39f641082d03a28de44ac677644c7b6c8df743f29f1dfd80fd25c2db31010ea02f60201cde24a364d4168da261d848aed01c10dee9149c1ebb29004398f0d29c605a8bca032b31d241ad3371 +Mac = cdeacfcebf46cc9d7e4d4175e5d8d267c23a64cde83e867e5001ecf26fbd30d2 + +Count = 35 +Klen = 40 +Tlen = 32 +Key = aaafd08fd89bebe239ab65bb190b86d49c5d39faa50b1109f7dc8b179bc693f0810449c36a68041a +Msg = 44131187c07a8e3979254b0c1d1cfa8081f0beb8890633744932af3f6987c7eace6e153876f639dba46b1e9f3e2a7fe673b3a954a00082cb7516ca9a54d9a1f1f924499960192ee1e3b623dca4a9efc92a6608d34f769efb5912db5267f06a6b0f5d3610458c74347e2ee32916425213ef2f649d5c1090ea3d4f6bcf6b752a3f +Mac = 0c19ab5d4ee7b64396eff7b2ca9efa5ca7369c1a1ed14952445d2fb5ece9473a + +Count = 36 +Klen = 40 +Tlen = 32 +Key = b06f7ca7a5dd8baf2ca940811edad87a33da666dc427bcf4d54a8e03520dd5c399e9729d39be1494 +Msg = 32b45fbcbaf262bbe347360bd6076c43dc26ba9573fcabaea14595de886ccc793b09157dd0a85d74b6ccab9c49335446a45c6e7cb64786e6997c96ef1e4e3123ad6101db4c6a731dfd36b1be4deed1c92a994b25f5e2b171d81b9a335a83e03230c40b2056c00c7c5f8d2fb70abe4b9615e53bd756569217072d8bf362923f6e +Mac = a9c9d3993fe7ec4c2033ccf3b73b3407cd999d67455b43a75d6ba97efda3be63 + +Count = 37 +Klen = 40 +Tlen = 32 +Key = 2dff35c2fe5039123d4c5d9feb7d5167e3e959b31841abec1e5b18b0ece2ef25e04d1f8d030d9b1b +Msg = 14890f3b2ee63746c8249909013571a403eb54273760090db5959b06ff59acfaee6d0c4aece58b5964d10b4b771dd90cf1b63d947bee4f6a12220d67b79aabbd68b02a3850352cc33b10072d4c28182df2855aa418b236239c659dad036155be6b9c908bc09dc38c3329b538e81ed710ef9fd3de7671673f3da5745f4a785204 +Mac = 468d8498d46afe74a0ffb541b847bac724faeabd48c41322bf534b284c4e9fe0 + +Count = 38 +Klen = 40 +Tlen = 32 +Key = 9794cf76aeef22963fa40a09a86bf0e2ba9f54f30f43bff09d44f9d28cfd7b7a45002797cc1437c9 +Msg = 3e8a9030eae1bb6084cffdb577623c4cf94b7aee3d3ca994ea94c12acd3e1194cad6d2ef190e0219af517073f9a613e5d0d69f23aad15a2f0d4e2c204ab2f621673325bc5d3d875984145d014bbcb1682c16ea2bdf4b9d56ce6da629ca5c781cfce7b1201e34f228eb62ede8d36cbfdcf451818d46721910153b56cfb5053d8c +Mac = 29973999c4ec891154b83ebe5b0201cf29205d68e7be2c1d59bbc81658d6668e + +Count = 39 +Klen = 40 +Tlen = 32 +Key = c1d60814376aae39c4111246353485958f95558fa38ffc14e4a0981d76249b9f8763c4b3e2ce4ef5 +Msg = 97d29ac5ede94c0a5071e0095e6102123d1726132f9dc102672ab87b1cec18abdb04096c21d3fdb129742d250389460fe63b5f79c77c2f912a8f7d4f39cbd758139c872366cac35a40fe248322825adf57481d92832e66057f80e08964be993de6a0fe31e45806cb3c17ad6ae4d2a44a374647a88c3acf260d04c970c74ec720 +Mac = 50db0ecb5b31524a6914264930abccae0da07f01a2bbb9408207156f8e8a340c + +Count = 40 +Klen = 40 +Tlen = 32 +Key = ca5f3eb9308604f9fcc2af1c6a3175cd8a75045593b473bd7ae37933c345ddb0982e2dd7180db31f +Msg = 8734e49e3e629deb352c77f58ff4dcce2af3b1182e7d896ae68619f6cf66ed69efd95913684ab1484d51bc06b47a67d70d48b7f9b27901bdbf8c5d2d238158f1f7e0e9740ffca742cf7938b5400c0dd063824c6bc6040e905499cb2671ec12cc47507e085a01e5a163acd2495b32367fd6aa5ab492a518ad50b54b28e23084c2 +Mac = a5772a3da86365b46638f1e97037fc0d8351d2e19ed929f85448ebf4e8379a8e + +Count = 41 +Klen = 40 +Tlen = 32 +Key = 808d7aa9aba6a40d1bc43e9b932ec8e9273b892ffc0a769e4f7255f3b83c224bb090b23952ae9616 +Msg = 61c5be972faa61f67bcb332542c0b8a7c74ef67cdb95d6f65c8acec8fca8bd6043e31677d8de41e6fc5d3ebb57fd8c8cf723490b96329adb1b014da2648cbd6043e9f6ffc67e1a2bbc72046374612a50c854c8565af03b6a1eedaa2319caec1368bfa65783f4b46dc3f0cb4622545c9c43c9bb86b237804a6c382e72a2cc1222 +Mac = 5f1b8de0e3b07da6f9ce1a494be5712e54ac16080bb4f6d5373620d86d5ea5c7 + +Count = 42 +Klen = 40 +Tlen = 32 +Key = d8b994bb8df02d7803ca2e09d601b918d6b5bde90b611bebf70e078d1ac7b152bc4c2528e60b70f6 +Msg = b31d11cb4f5c572ccf3405c65cbd218ee8abdc08b6c82e5d1da2baaf8980f7a9c29b915a718b0d43e000adae01b29342b29b28d53f63bf81281c76fa252f5d1e6896dbce224c4dfd4802ef0697140043d6bb21db5b84ffdbd001318937be64f52c76b5d06a875e8191a4957627cab1b8dc758fc3121334949cb9b303c6155153 +Mac = 8e44d685fa79395b4761cab89688e37509e69ad007a2794c8c0b4152b67036ea + +Count = 43 +Klen = 40 +Tlen = 32 +Key = a89bbaa86a339951ddcd37799e21b5d1688e4abedbc72daf7cc9b5adfe10be34c00a504196cc7bac +Msg = 3ad17308cd259688d5b52c32d01a3b868bfaa4758bdaa5ceac34a1f908ca24e71a39224924d17f00cda4d4d50fdd716b50549e71cf5f271c42ea17d5becac32fd64e0a1b0717dc5f542af9442d44fb8f956e97b384d020458aca4cb0b6413b2ab637b5e73f9fb48cb06f22e6f2f6e3dca27016a272d89830ccfdcaf3b9d895c2 +Mac = 905d55da5d290d023f6940fcb904c50e70181c95000eb1e6a33aa01077692736 + +Count = 44 +Klen = 40 +Tlen = 32 +Key = a9560fd61746d7f986b691f070c920256a535c21a64ab5a2bd771aeeab7119681bcc4761e68ee230 +Msg = 46eb5059055d3345c1ea84a4ebd2d7cc53361707eccd70e7cfd86bda83585bfe7c7ef937e1634b7e93f9ca7c6a42c357c2bffecc362c9e7eab6a488d91bd876b65376feb7a74819bfa88cf542736610fe763d6fa80c94ecca0f08855a05a485909fefc9e58f99e44fe7fdc55ab17779dcc08e9bc530e4a79b65274593a996671 +Mac = 9045dd3fa6e8f2ef7c57b03932d244186caa1bc1d4b694c47e1f2901d9eba193 + +Count = 45 +Klen = 45 +Tlen = 16 +Key = f987eb83a3fd6d94ebf3626b7d34fec23ee06c63dfb4078cb38bcc97bd250fda0e286ecd4e64046a985bdfda8b +Msg = 390a9dc2ea20221c5993c581892eb4b04364294fad919c451e83376531398a4c18ea808c334a910ae1083aa4979baa172f3ebf20823930e238630c88dfe5632b3b4042f6dd92e588f71529996fe840e13212a835cbc45ef434de4fa1ecb50fd14913cd481080875f43c07aa93a9dddd5f5e7ced6b1b88d42b9fce8f87f31f606 +Mac = 0b3b220ee7a4fdcb0d17a5c8b595b981 + +Count = 46 +Klen = 45 +Tlen = 16 +Key = ef257132b7be124ea0886d587765e8e70357959cf39ebf621420c3f3c70e219fb3c5d349b7f2deb222fa26fa27 +Msg = f90768954cdcbd5705f9d318fca6591787af840a921fbd06f24b979ef612034f3f64c71cd2012c756c83f75d169f9bccf8a8ad52725498fe69c3927edfbdcf87c73cf478172ace3a1e6b446a181e8aba00209894a5d2db01001d2acac5b3fbdd3897d7f142df0b6dc4b9a1862bac8ea845202d185321ecd75f6046c9cf7af116 +Mac = a17d0e0f021184a3937222de81be627c + +Count = 47 +Klen = 45 +Tlen = 16 +Key = 2cb8e269726b75e3a6258541251f6e3c5184c5e6878decea51eae315dc656115acc224818ee9851ace474f51ab +Msg = c1d80128fa208ba18bbb13424012ea651ee75e73f796e94c3b9aa9e911521040a605dd67c5254bfda9d088c60f9c68958f945b6f2b7e9ded2960ace21e42ff3e4c34f5322d930c955089538764d3225493c7089b119505aff4cdf93d46215d2f586d31d15af4353229ec5cce683e7e69d2874d3ece628a5944e97942b07992db +Mac = da4571749322008e73dd436a13c5f11d + +Count = 48 +Klen = 45 +Tlen = 16 +Key = 1eea906ca11432655750a4e1af21eb1e03465c6d6f3b0fd8e20391077525d965fcf57d7edb1426ab1c3a42f2be +Msg = f57ea84caaa2af18dd7efdca356b9625f9e70d3a803a9d31e95976460c0a5512af49570cfeea0f4f3581d69ea07f62a5c59d9b81e07ea9838f8f5231cf33838e271d2c9c23fc511e045e5fa2b6cebcbf0240a19c05b02cb1e105b1d2b23b5269c4c1cf0303209f0eb2de3fe060a2cafc1898ca91d9174d4445823c2f9d6ce92a +Mac = 20cccc1ea0a8a89b3bc5fe3d5a9c2b24 + +Count = 49 +Klen = 45 +Tlen = 16 +Key = b2f1adfbbde4dd9a9674166ee08c2f4341072475b9b80b1032ad4a3658b408c1aa1fe12ad1c5deaa3149a49ebf +Msg = 33ca6eb7ec1091b406cf64495ccfa2169f47b3b590477d4073537c14c05015d51ba527b3869ae4ebd603df906323658b04cb11e13bc29b34ac69f18dd49f8958f7e3f5b05ab8b8ddb34e581bde5eb49dd15698d2d2b68fe7e8baf88d8f395cfcafcdff38cf34b59386f6f77333483655ee316f12bfeb00610d8cba9e59e637ca +Mac = 5eeec5bd9583ce715d613d4c04a702f9 + +Count = 50 +Klen = 45 +Tlen = 16 +Key = a2617206e2b382078fddb0af3743a69a5a7484eecfff6cd96288443bc21ab79f9bbf7d70ff4edd6a0a85704ec6 +Msg = 74c4ca4db1aa812b4d75852c6717146351e83299448ff84d52262ff99d991d97c74f9f64a90d78e44817e926049882491343373f2e3bb6d18a30f8e30acb16fab34d5ffb6073a736b79ce1a25b2df16a6335bba90c4d8072aac36a14e5f7659c2104319b3ea3b529824d9729d3a009cf2a04e660448efd399b25ad1394e3b285 +Mac = 64d5ad7697a29529ca3ca4ff65e7d735 + +Count = 51 +Klen = 45 +Tlen = 16 +Key = 7af197b78a27038b0cec128001ce6bb7dc02c0258956f62ead678676301423f4f9329d48f881054e6adf12f358 +Msg = 68bb5b6289907589f8d91e46d44417ea80bf6be10245f52ba9f82211f371f810ad54571a5c277ffedc64d32447ccdd7d19ff91ba914ad6bc5ac0424c6a8c250d2b85caaed803f9642af1c098352474dd8cebf224ace82a33981edf53c04aa84927773b88c5cdeaa52baa6e0b65f4e4f024ad15881dc7fa78ac3a808dbd5588ae +Mac = c4fdcba979357f639cc6d89e7970943a + +Count = 52 +Klen = 45 +Tlen = 16 +Key = 96ab1d64acad8cf69651c13e4eb42d7382e38019f3a927771ba6134c12a1bdbeb2206793fa35a4a3b09a1a8d4a +Msg = 900e4152131d8c4dcc38a9e8647234dffc7ce88ecbbb65a8089d302c0a2efc95aee62852f9c58875fea368af02c1ce7cdfa3009ba62246c188bdf18ef7309cc00848b2a71cf531d9bfa1ad26d0c097cee3a8bff2e3a31849fc43bb14b7f62f5467dae83ac5d30ddfd7da7f351698163ecf332e7bca6862a82ada97a694a93db9 +Mac = ea411f749902bb0d2fa36e07e694da8c + +Count = 53 +Klen = 45 +Tlen = 16 +Key = 582c13a6c4d497e4edf69bde35beaababa1b068ed168af20b04cc2f06adf0478210ebfb27640cddb453af27790 +Msg = 7159ecc145a3f919044c851a4eca428279626e68cd8fa4c5f4a7f932acbc44f3bfc0bd3535edca94c86415e09815e22120dea0d869f7bd887d8dbf751fad91acb9641a43962514e2516a1c838e9e0575e73b72a72a30a423c18590d97141359e488c2c74d011810c89a6c189962f5487b7bf0d5c7701009da7d794e50a40d9d1 +Mac = 7a699c1ce4e323fe1b9ff6dea2038aa8 + +Count = 54 +Klen = 45 +Tlen = 16 +Key = baf1d8aa12f5ea6264d122938593a8d677c82a37ebed7b43042680625e334c674f9f8a666c3a1bc54fca019698 +Msg = 939bfaab9f60369542928b1490894259c22706747f0c48215b08e1e59ed6f95a460728c74f3cdcf43198fb3dab75c9e4bf560bacfe1d6da3057f213f48b4c9ac0e739765bd1db2025839dc50462053a755f9f478fee8a626eb83f617b686ff0af4c78dab726c8264be5b7877e9f2a74a8cf9090109d4bd5213fdaa9571b2641b +Mac = e2a380effe8de7d29948c5d9d7bb39a9 + +Count = 55 +Klen = 45 +Tlen = 16 +Key = 735d943cc93f783050c7ccb09acc5a6f60af4efbc8919793e7c39038857ee00621d59fc535e7babcbc5998c5f0 +Msg = 29ba205089b12e8be5b422faf99c3d69aaca324eeb732db8e13c148245070dcc0b0c40ab412bde2039806247ea3917d194a4dab4a38c2121d6c63cb7a007dbf6cff9d1f66b8d1759e192147e60871bf784ad363e326122a3c3a99a89640dd9d2bca85a98d07ee21e2410c006232e53c4c10dce525f993825ef0cb76158c00d49 +Mac = 54e871ae687626fee5669ce20cc48041 + +Count = 56 +Klen = 45 +Tlen = 16 +Key = c782597141b52135e34d240df67b9bdc274f2d41e6866e0f0da3a6fec241d3a09ea7f1960f9d7803fa7e2741a5 +Msg = f7321718bbd3b401fb5d72f2e8931a5ebb18d2a1ecd4f189a59912157607687c4aad51719a702da6e031708f4faaf668c1999779f121fc99ea6db0f1bf967a027dc7ebea5e9f33e23fd6390c5424ea6c1b5ed0338ee3e7449d36adf1dbec790578c90d086f266ebe0095f4f161c89d70b1afa6582de15d92a63d319d33d10b8e +Mac = eb5b96d2f51d56464b95da4927ec5a64 + +Count = 57 +Klen = 45 +Tlen = 16 +Key = 498584e364f632184bf26a253d0e81e146730963b785eac1d5c2b51dceec34e3f16a464c1dece9277a4e99d868 +Msg = cf25d619fb46bfbc39557914dda02d767ac511120d173b787743b35b3134cb943b33b36955534810720c2d6f6a261d26efd87fcfc2323b8426b8cda2965098cdb35e7c35802daa17d191b78601caf06be4aceecbfcfd6a48f01f52eb39ee1b201fec5a02e49c8ed93f2b40e10c554f4e4187858c24416dcbbbbf69bb84d8ff94 +Mac = 020d5aca34d8c7066ef5d8c9b3429669 + +Count = 58 +Klen = 45 +Tlen = 16 +Key = e4298464a0457dcf98ef09cc00d92238d06d9a7574b46769c5773ec939a4639756f2bfe96dc833ed845c2c2a94 +Msg = e2a26ca137027066af856453d2a4adc4d5d0c9d5bf068f8acaa4b74d0c7b9c9e562541065d98924c17fcedec68bae1c5fed636127a7e2d9bd0e3082df047cd47a6574816bebc4fa36ded4a4cec47f271665f586f149729d2a7ef31c6e61e1fcf98e288baa4942ed477ff8159a672662fd41438d4d7780c9616713a023528199e +Mac = 0d700ca9ffc418b29fc8e316acbc1abb + +Count = 59 +Klen = 45 +Tlen = 16 +Key = 28ae9e327911b76898af1fa0de56069e0d8b67bd2813828f87b88dc42a49a74d4ee30dc13e6f90ff6c6c4715c0 +Msg = 3b9a4948d67dc894d70c9ec37104a7147e22bcccb98983c22d648b21edcc986a06ec3bb8b263a648cee9bf388e36738f70204d7e6e0347e67865e01921da6ee59926b6cfdba2ba9c27e1d216b392fe0c9ea87b9b25b994ac19a4bbbe9077d8e6dc90e113b902ab97ca3a00e347e2f192f0056daa4574131ef8694597a36b7e73 +Mac = 6696e3812da4807f05b84a29ad9143ae + +Count = 60 +Klen = 45 +Tlen = 24 +Key = 9117cf3ce9f5c6e19752bf0b1cf86a78ce3adbba87dae1399a2a937b0b722ba3ff92183871e84e282774e10de4 +Msg = 935a3c27249dcf92aedac8dc76d22ff7742e5cee57711778c92afdcdf36e26b8448504ee6ee48e9eb25b9e495e9098d494ac4ddc4c541f499cdb652638b611b0353090ac125ff1fef8564a78419c57f038dd65951fe06e8377b986947b407579eec1a60a16f540db0931921027deb472e8296bc2d8fb4e4ddf2c27c0c6f49c3e +Mac = 4cd095ce641f217f8b5f355152eed00b1d9fd721a08dc5a0 + +Count = 61 +Klen = 45 +Tlen = 24 +Key = 363b32accfa593e454cc3ec83b9d775a0dd027b017ca2ff863c1fcb9e6215b5cfb2e8fea10eba2179f3bf88061 +Msg = 548564e5b7370426d575bbe8175b48c244dedcef3daf7252ec625fb777d02a5cb9ba9db0f2af1c5abd2f367d43107a3aaf218c77e20e78df6783452aa994ce9f635dcdd759e539c34649d2f11516fa0a53f6c6a0e58f5526f6a86040348d133e3cb51be252a3016a560ab6caf3346f3a1aa4b2f0affbb12f8218d8808083a240 +Mac = 646abbd426255d2e369b7ac9eb3c3af19c7185ecd28bd82c + +Count = 62 +Klen = 45 +Tlen = 24 +Key = 134a50abffc94d8540d7ec939b7a28b10916e505ad90843d08b4b51770d48c27beb2d8d548a1b0a50fe64ebb39 +Msg = dd802635f714060381d2ee1dfb50f2daacc637598965fa7158ead3eb15723bef95904dbd699dc99e054f5e19228d29696082792f30f1d565f1c8409359f7bb4517820cbcb6d5bee4c5596986354433bf02b597b1160065786a460a5f6e4a1254ab7feb9aa666ecbe081695ccfd1c19c2da861945023bb3930a8ebbb91b124806 +Mac = 3d731839c004ecef8ab60fafd811d0bbe6e306f7cc802bdd + +Count = 63 +Klen = 45 +Tlen = 24 +Key = c83ead9a131a1d7d126b88642221ece7d3a6ddd6016ecc6f40d089d47e1407bce3cd6068fc6918d91906a640f3 +Msg = e80a112713b2e0aafddfdb71c091141719e1501c1ce55ee526d4a804146a08bab28eddba76335d306f7c2d0278232f56b11b9b543074512df3806d5c19341c2c52d0af7a95c3eebc11c8af426556a7bc13377ffd32762afe647f77260882e2c8b118b0eed6293b55cb0d8ab8eff12451287d269e8cb49461611bedea481d0298 +Mac = 0a4f17a280f9017f1435cb8a11738fda4f14e3f222f06b86 + +Count = 64 +Klen = 45 +Tlen = 24 +Key = 430a7dbd62b3b3cb6a4b2024bd796048ea60990d8222f94228a26093e88f59acca9e4fa2a616fe8e3992277b79 +Msg = 7e5d6e5e9491a965968a08adcbfbbdb19949f00903f7618270624e74aeae975036002079b2ed7755bc33b7a3e9a7ac0f066f3703a171f4c1cc0b1baf1d05a4f1f9c4af3d12c022eb2f38944c2c246a3d416b3ffc87568a3ab7447a7135a025774e11e254bef0f35176ff68519c583f64d2a3d09abb8c6915bb753562ff67620a +Mac = 5007afb09312d144091f2b35618c26714bab8784d8be35b8 + +Count = 65 +Klen = 45 +Tlen = 24 +Key = 4953408be3ddde42521eb625a37af0d2cf9ed184f5b627e5e7e0e824e8e11648b418e5c4c1b0204bc519c9e578 +Msg = fc0624c9d2fb237707df2c7bd9090b031329835432d99304c575f8691a2df35116584cf3650b9726d4ebb6d1fa3f9fa31e4a600455d7604beb15e73104a5e08583f2de222bc15e1f04094c450104c8c6df86292b508e428f591ae50bf940a6710b7be13d6d43ffc862e0f4bf357f0cd42086e8b36b25c338d82dfbdf3f26cc7c +Mac = 08c4699d15dcaef9e99556ece73793e006c86d25c8be3fc7 + +Count = 66 +Klen = 45 +Tlen = 24 +Key = da6d09682610d23a666ab7f63147a1f05db8b3cfc2c12de3415290b9067803ec09d5f53ddb4e04e69f031d2c56 +Msg = e35dc1d0e414ae0e586ebec9a44c1918d795db378a89177d0b521c8ebadcf6d2b2e73826ac5bf9d121db1db9af9cd6d7be7869e8633e3665854df3b63e6138a383ac400b0829eed85e2d0e325e3fdef3cb29cc5b334f82061640201a4b8bc8c59ed460e7be26930b578b199c7bda395646d18cfac263034608532b24a802b022 +Mac = 66a57a169d8d0ba263dd954b342919f4622592eed20c1981 + +Count = 67 +Klen = 45 +Tlen = 24 +Key = 22f6c7ddb0e46ecf627aebd9ffad6f36682ef5c98791d25e82af8d333449f0b7ddee5f91181e69e40eaf9dd1ea +Msg = dc4354ff557dfa58b17a0e38f63a61c20e0fd1eb6cac102cf37fa77913413a7735cb0dea592bc76cfdf7766541e1d4374a8cc9b9e49e30e76b17ded8ebe1e0f086a7055616eb9da814537feeb94451cd62b203fe39379dfe12623b069351553d9882442dd5e60273be3732bba38c60ec202b89a0b49eded7b009c5ec53ba21c8 +Mac = 7959e5367720f3af55ae91843397134032ee73de6a8db8ac + +Count = 68 +Klen = 45 +Tlen = 24 +Key = 2e2b999290c9b4a3760c4bf767ae44b28a8d12461552cd39095088291dafdf0df7c9cfbda2d4cbb53dc20b15f0 +Msg = 36581b498cc8b9ea79de28ca91a9cd0a87e30bcefe73b9e59c37d3a860016f2436dff37bc9a086879993c4c14d92b6614a3f01c7848e5d1a9484492f0c3efeac0734a16d04bfbc26f4d9ef4a9124e32cf22f80655cf460755ca583ad12a8444cd0e08be8e42e450fb137112f05683cb3a638f06f2eada83e1922e7e91d472a4b +Mac = d39eefe024ce0b545d77ce327f0731c5581095ca734c21fb + +Count = 69 +Klen = 45 +Tlen = 24 +Key = 089aa37f72b2962c18fa4e9858ebac2fc1655ff41ba30715a76d9ac3a88f0740218b1a3ae18ba057bd99cb111d +Msg = 45ae84fe11078713bc87c465e8d88f0b23e2804a6a3e19afebeeaa5a0f4c729db84107c6c8b7f838e251b0c174599d27f5fa92046baf6ad431fbef4df75bfaef0a79dbdbd6a2fae8a97abff4b9eeb078696bd95fc84d71195a9bbaeb1cf12989c2bdc7e643aed74b976ab9a7bf800e26079d1d04880276a4f035d4dc86f74893 +Mac = 3accf0eec5b26ea6c936323b42636e5899f4bfe7e7cbdf3a + +Count = 70 +Klen = 45 +Tlen = 24 +Key = 4e1ad1054c00b6cdd0267739c8c92994a4af4bf373ba066c48bcb483e38da0e58d5b0c59444279f3181c228ad5 +Msg = f6f83ff6ddf386bdf3af9409ef5cef16acb376182322f57b9729f76f0f04dba4098a2a526d55287dc023a9779a7c26a65a951087187564f3db5680a20c4e35ed2b2e1dd8c1ab2f4f96bb90b02342ac8a4aee86a5455f4c42dd8c2fa3dc6272cec4aec08fc13cc2bcdd40f1bc73f6a94ae6867f77922ad5ee0392ac7c6588b9d0 +Mac = 55adbc7d757e6904448ebdbae5a8773a1781f952f5bdeec0 + +Count = 71 +Klen = 45 +Tlen = 24 +Key = 36e8128355a3dc7ab3fcb28fe93c8e695066334f6610b398737233626cbdf28717ae88cd70626c5d4c6cb9773c +Msg = 25c04b857a224389e8a2a304e1bb8ee1b352e4cf5c3cb6e99f01fd9557df8bac0c1241dcc453834b1b9fe97d9639377835f2902647a8e6fa820db5d653a9f12d73233d65bbbc5d7f391ceef9835154f34b15f592344fa5a2e4dd607f5b913f358379a5e60864b96c69a11a40500ace9a1f427bdacb3ad927edfa6756169e5d0d +Mac = 22950977bf0f3fb8f4fc53ad2ea2c91d936aa98d06ce067e + +Count = 72 +Klen = 45 +Tlen = 24 +Key = ff469d80d2dbef999d7d4815d123cf50ee9c2c23fa2e9aab2c7e3d4ce8afb7f5f0cef6a5d86e4f2eba8fd1392c +Msg = 6c15d1686e680c5aee2941900dc9af9d2503b3b6a5623f5c1c04873c939dfd5320be8055b858d050457c468cf864c2b7e1b7e43ebd097ffe0fa14a1c7280d9312d9fccab087747705ec6a2c47491616c096566132ee365ee587c999cb478b550ba3d1e3105ce57016292bcfd27577405c696a1fda1f8d973201ada82018d79f6 +Mac = 646031963fc8bf827a30924763dca11b589358e7029daf1b + +Count = 73 +Klen = 45 +Tlen = 24 +Key = 93fd8e208a1d6052388611beb9f047fe91e33afd4bcd74ae6152d5fe5ce3d9073c921e861a24208f0c68477f49 +Msg = b99a110bee03f440f15145e28d32c340297fb810efcc36a82e3da171fc9b6d981fa629062eadbd93f35df07614d72d00f205868bd22df9ad3bc6f2b19e8b12473dcf2f7a45109ce33dceaa1ca49d6e78d67ac5f1305b9662740a57f76f32d3e1d9ba2a4e7c531998994d7bbc87af100f9d867e2c527d9531a3aed72bb5b838ce +Mac = 00aafb9109999ccf61f6689b7405ad2fa54129c3bc4e67b8 + +Count = 74 +Klen = 45 +Tlen = 24 +Key = f189baeeec507e945f0c4d628a0d0548eedfd254b11faf25458e29a3456466ed9fe76793f83b8a064c7c534cd5 +Msg = c821be1cce09579ea899899d24f8329994c2c839cf0084e27857c688837fb5c4f4f72527eaf7bfcfdda75b37248eb153ba4d31dd418d2fea473643c0c9e1f0ebf591838e349d3ef868f1b67772777a71f8cff5b0654696fe31062ef2628a99095355a0f8b4e41e41d2e162051899d519d6b0dc5c42130047bd2f4dc55761f745 +Mac = 1c8b29577349cf99f80ca11477f401f61e0b1a4d6974fc61 + +Count = 75 +Klen = 45 +Tlen = 32 +Key = b763263dc4fc62b227cd3f6b4e9e358c21ca036ce396ab9259c1bedd2f5cd90297dc703c336eca3e358a4d6dc5 +Msg = 53cb09d0a788e4466d01588df6945d8728d9363f76cd012a10308dad562b6be093364892e8397a8d86f1d81a2096cfc8a1bbb26a1a75525ffebfcf16911dadd09e802aa8686acfd1e4524620254a6bca18dfa56e71417756e5a452fa9ae5aec5dc71591c11630e9defec49a4ecf85a14f60eb854657899972ea5bf6159cb9547 +Mac = 737301dea93db6bcbadd7bf796693961317ca680b380416f12f466f06526b36b + +Count = 76 +Klen = 45 +Tlen = 32 +Key = 9fe42dfac92a4a136fa7c9f6e331b5d3a61aa73035b53a8d2517be43721b31b215a96b9bd43798cb5e8febfa97 +Msg = f9660fb784c14b5fbec280526a69c2294fba12aea163789bbe9f52a51b5aebb97d964f866c0d5e3be41820924fcf580db0725c7f210823cf7f45a0f964b14e5555070d1c3ddb2c281a80c7fbf72953031a4e771d7e521d578462cafae5a02ac8eb81f082e173ddadc8c41d964bbfda94f5180c8da28a8ebb33be77b0866fa798 +Mac = 7786c155d10c741b63ec650b7b1aa3bfd71ac71881ad06ae98fb082f17e0caa0 + +Count = 77 +Klen = 45 +Tlen = 32 +Key = 98fff7b5f77326c24471bb9c317490be1febad28e2e825afc41c3b97cc03c963405ce3ec68dcb7b19523b76e62 +Msg = 64a78a4d6fb8ff3813df8dc022faaf4415e4df2949e16467683c6c47242e5a6b2c02610e5877528d2766b2266ca41000442a956c4b73dd6b10260570c6f506673cc541f50f0f5b021e864a753efab03e2f7c689acfc35f928ecea6c522cbc5687c38518bfa48c19ede887d33ffc23806be21803a3c9793e5ca7c75cfa1783f77 +Mac = c02c6022ee0de099e3027850be95a29ce800118ed3a97757dd8ab9e60f69a005 + +Count = 78 +Klen = 45 +Tlen = 32 +Key = 8d649e5ccbb8bb0032cdddbbe44ed0b5bbbde78a30c0f8437bbca985fca5ea08da15c34bea9b5086d2550ae16e +Msg = a7734a0739d51af0ac2c4039dfafa86f36fc06c2355d0f654d4ae938f52fe0a5fd6f5ac71fa80dd2d8396faf76016ee6716a62c1fea640afe23910e684b8a14c47d07b98168915b441cc48668724043074c14275edc239dc09b4d5fa2255652b2c9e94c046019a608ff0b3a83b9ed015e6098d24273864b769c120bbf68f9408 +Mac = 13e0834e4dd72a2ef7872249bf895da4432329c6e8ade8665d702ba33bb677b0 + +Count = 79 +Klen = 45 +Tlen = 32 +Key = 57958d7e4c73fa606ef405d77ea4977ac96b8813fc1210483a037e7b6c502ceed8f7b22bf6655aa37e38d495c6 +Msg = 0b9a58cd96351a135c559d17e82ede3434a0caf0befef5dfdf138ec5586793fb2ebe4114b9e2cfbff7a25bef261b253a9136fb7faa72f4cc59e4617f947c01ab308974bdf67ff25ffaf83d9c28fad44520786a94441b96100e42ccb0a8478c43b604d90f7695edb90c602b651753551d886dff77b4804472a835b7a2bc509c8d +Mac = cd251e66c421bad1b37cfebfa3c04ef30b8be4e5526b10fc48fd5bc5d6f04bb4 + +Count = 80 +Klen = 45 +Tlen = 32 +Key = 6d32ba0c063774bf8d0621b208d72095f684faa33ca6f3dc62fbdf95ff0c3733720c6c34d3027b6f2a2bc29cde +Msg = e5804b099ee4b351843adb9c9e3c231773256e6a2070d697a9e29e258dca677f9d88a7970d4c58cecc20ed1811298a5b37297419ca49c74fe216679dafc938a656cb92bafb78efb31f24e71c2d5b5f994f6dfd82862adfd2faeb8c408fd22aabb852f2bb90f1e2c6274cb1f0195c089766f9efee7d9c86e79a69f557526da555 +Mac = 9d283d8e8e473a16162d186e96355b1885370e83954dbd08622dbe64f0aac695 + +Count = 81 +Klen = 45 +Tlen = 32 +Key = 6b97478fdafd3a85d0d9b339971a70c2fd24d542abd3e20eb2bd630f67b86668719df258204bf66201ee80acaf +Msg = 8b1d4523b6e457f856e5f09875d389eb6587223e53477ba01f49878c6c731ec9f365f28f1cb9c4ebcf89d8648732a6dfa958d2c0152b5e52fae81f69eea26d463e421fba82cdb78f75e5d92304930256a54376a6ea107a995642c45c6f1530a914bdb4ed11a696abf100dc1b147b0518014ff639fc80373ddc605fac1755cdbb +Mac = 6ab8f69868b4c87fdec9a031045b34b66660212f687a83d561bc4f9caad59fff + +Count = 82 +Klen = 45 +Tlen = 32 +Key = 89c77d79de98df18f0cf29a9316d6dc46b61eb7af7f1e2de2f5ca6c525bef3c996338194193fd85b9c6e66a811 +Msg = ff8662e9af3a38d3efc0143138fa619a57d569f61e29b3895ae08f2d055befdebc11787c7379d9cd672b5cc25442bafbe804348c78c5df02f30840a114e818f0dbb681783de43ac81b2140bc71c69effd07185cf0eef9f003c60a144d89520a944bda563774103ccf3ece8a9f64fb3aff564854646719b8c1d2fdb9db92cac12 +Mac = 4746e6f151caf29b3534b2f493f7cc1308fa119116d251481572a1b53a8a1b3a + +Count = 83 +Klen = 45 +Tlen = 32 +Key = 08cce7d7f3ccea0212cf0299f27f3d3f393a97d3dd71caf1954e67bc8d9a26db5edd7ac23dc7693372ce9b040d +Msg = 33ab861f089bac0e5c886f66adc568ae7ba331655a371de7475e269138ff2725f7904c702fdcc62ac703c31d70c29d8a7af451c8ec59342ed397e133da7e76d41b90003635c1338d9f7b5f3c3ce59f3e2f6554c4f064d11f9f5158e199e8463f4ab48aba42d25bff8af92b0b38b7d69241fd20a28fde5e84539473e39dc4fe2f +Mac = 2c723282159ceabc5b367b95cd807f249f1dff7f9ebf5ba179a43081454e1b05 + +Count = 84 +Klen = 45 +Tlen = 32 +Key = 1a2e86f6ab2db235e5d7f00cf438680fe5b442dcb1f8c3ae7730b92f097a1a8eaa9be8d216f2576ec3aa321567 +Msg = 5a2240f64fc704ce9f8ed33d019e4155cb46747a659e3421fe6b42d67f44eb84bdf3dcf1f31e38886f27e85b8b503368df238e1bb511b515bd59fa2c032bddb31d0ddefba97f8f19f7daedea027ef055a52c61d00bb1ec2668c57677e632b180e339ed1c5931310b9d718af34d70a3a4832b96a04fc702db65785ebf12a18c73 +Mac = 22de07c3055a8935b52bb2c85a9a6b7ffd4038b5db4069c07e9e86ee1b171d25 + +Count = 85 +Klen = 45 +Tlen = 32 +Key = 3270b4e48d575f0312659a6202adbc4e877d69298de4090ed47278b4433fff95802e844fbd73fd4ad5532b9b97 +Msg = f407f815a33cd450c0b72a378f00762788f91bc44f09f93de67a41d2222088935b3c1b6a689f935bca13a90b28f64b7ffc28ef278b28271b1a7975a45f4b61fe3657ca5c950b7a2dc2e7fd9ec327b26017a222aba3f29183efd5d33a92d36136eb21acf412c6b14d0efccef849d9d451412e5d587fb060fdcd55029ba401afc2 +Mac = dd1a8105ab753d83d90ab39adbc748940fefda05bedea7eeebdbdf54b02d9ae1 + +Count = 86 +Klen = 45 +Tlen = 32 +Key = c704d5793539ef3909bdaa7c29e9c0a0c441814c37bcd062325f6e2e16107be4a2aa3949cf4d14b0f8f8df283e +Msg = dbb84fef130f929805b0876cb4646a046330bc33ab1cf1e9ca3869573ee1a1549341ab007915dba719b3c4e8a94b62163e6d99dee2cbde2ae74135467b125b417c7544978d50c80c694399db77e878109f59a8335df3a326135a0d50a4bde6fc3e5c03fb7747bf919c68ee8f45c312bc2dfdd279411ba7a5f78dd9bfe16baa4a +Mac = 441c7fdaa40e50bf1eba073509769b1c0942f3a16e1e183435819d3b5f8538cd + +Count = 87 +Klen = 45 +Tlen = 32 +Key = 5b2cced47045bca47512fe226c1f415ef127a209bf885b8a76f5a24f9c6bce61e166bc3ca75471ddc14a001c7b +Msg = 1de00288a6e93930070183de9d9ed0ce86f6cc0f64b7bedb5df8af24676fd06fc2e516e5c5e827a7dec07963d5a4b825502d696f9c0ace8baaf6092058e78304f2888f51f9ea4bbb2376c720a2276a61a9f691712d9578abe95f5e69a490e4d2b6b1b7f3c9576e12dd0db63e8f8fac2b9a398a3d9ebe86e3201df726d2d1ba82 +Mac = 15c62ce7a3bfd5b3b3856d6f47cb19bb7030dc469e35a27807511f81ea83091c + +Count = 88 +Klen = 45 +Tlen = 32 +Key = 0d4dd35f90f0a10d7d8030e9919446f3d5e2532472bcef0cc5db84bab65c48dc46086f2768d89ef912b8a23d93 +Msg = 2937aa2ff7c942bf7dcfa670154e988c28177391969db4995804ba1a647acacfd0ca56f63b2e7fbc6965d8f62d066d118c14044c1fd2a224b9d951104a67216f03fa6dbfbb1e5f0f9283b6b7d452c74620c1c2bcc9e637fa7cc8d97623bc81330aef76f1403feba1414fc91bd1daaf132b4737495b7e7c01e9fbd9b3b720f303 +Mac = d5596bcc39af2782df1cd9fc8c37a8f96789275422f511280971d8429a8cb661 + +Count = 89 +Klen = 45 +Tlen = 32 +Key = 5ef946b64ff80e4df8ee98a357f07c825c3acc434d0f994069c0b88ccc0ac5e192a469d93f19d9615fd49f6b69 +Msg = dfa3b06eb1e30b47ad9f0bf0f441fcd94856ca8b1f4cb88cf6795582e860ad9c7f30bc2eca8e289bb0942f78831addeed934836097fb664e4e91b47acb5fbc49e9a15d6baa25bfbe864f42700361b46586f9c7d869dcc2444df17685b291743ac5fe7d6f78303a79d8d82d209c9fe804f9ae7d39be7435359ca385ecc57c3d39 +Mac = 223dfaf583140a769c805c33f1f30bfb2f0926b088f55439dfeb4f5a9ceeedf1 + +Count = 90 +Klen = 64 +Tlen = 16 +Key = 79f87734c46c5a11d86aedead22ed3ea01577ad4ecdf42969650e12000350676f0cf3c04f10a11339baf783914db6d35d7b0d77bb44ab22c18f56d0b8f9d918b +Msg = 509a0a45a1512b5072474b297f9c1a8c24890016144468504e245fe94d065d437fef6232f9f34500695549b44ceff29361d417e85d353701e081117aa8d06ebe058242ca8c23f3341092f96cce63a743e88148a915186ebb96b287fd6ca0b1e3c89bd097c3abddf64f4881db6dbfe2a1a1d8bde3a3b6b58658feeafa003ccebc +Mac = b5b0c43028e81628dce82517fa36aa29 + +Count = 91 +Klen = 64 +Tlen = 16 +Key = eae255d9e083268f896429ce36645502aff9dbeaca7159f93c7d51fdaeefdbfe14c396693a5ce46e9f1157a687e866f94ca165bff5f7b425092236d2a6a004cb +Msg = c28f6a09ce076ef270458967fe19d46e6f6b2cbeb6362bdc4fd55684177e984a600cf0814501665c3bcb4353e94681c83a8381ebb0c8fcdbfbd73c0eca738cf2e121edd46b2c0a0292eb6e2c4e46f5107a7780572d0eedb9473847684a4039ac6c56c9caea90432b9e2e72bad422168e5ad093c9d612e7c05c7fde5c40ed89c0 +Mac = b84003c417a472fd2935341962744330 + +Count = 92 +Klen = 64 +Tlen = 16 +Key = 42521bc3f168b2b3434cb4e44d92f526b41c5f10bfe0a0e6b0eb20c055a636e9da599b86e1ed1f78d4f69a837af126afc9c98beefca1fb00e5cd00948321b2b0 +Msg = 5a600c468ec22e42af5ba93eb79452864ebe469a86f83632c85201800f3288b553f7bec649ddfe704920a27a8f65d13aa755985a238b3cdc8fb0cf5ca7e40295c7603a27a25ae69837290f9801aa30896ee2493e93e52f031ef626de8cefb1159ce4a9f003038dc061be1920742d1a7b8bad80cf3eceb5b05d6c2d8f261b3f3c +Mac = e1c3c6d90820511c8d685c73bb757ee2 + +Count = 93 +Klen = 64 +Tlen = 16 +Key = 81b5f12a64f3c347902549a1fabd39ea1d9efeabed3851880df40dc541d23f0926507d62218f7a8a95b1d76959853bda6966a5b2db6001ff1595fa8d3edf10af +Msg = 04369f9592b00626d15b0a4b0ee2f92ba0d086c16d016ce7b05654b4f9adf90875118a656f2d50011707901982ebb387f3a4a49759f37a17183957ad0c778f6ecb780dab2b4df30e05fa81e6386f38c0f0ba3f37287a050d6d97287ae53096c391d5f20fcff73977239ca55c3657d1fd1f781f48e28057f136d890c28cc25432 +Mac = 5f840796e0d35c807b3d715727432e68 + +Count = 94 +Klen = 64 +Tlen = 16 +Key = 34f5d28d58364da4b95a48c07e01b0a99c5ace173ff2c9216bc96df8e3ab2ad54abd60308857da336f11986e9f21d1cca6e438c66cba7fd6cf17192f8ad745ab +Msg = 59a6b0317f130f6248e746e396cc684b32b9a0eabf15c50bec1f2f76ee8dc9392e7368a83e675ba312e344176deb26c799efbe4d5bf2175b26ec59478f6de1c7018497f9b2df7ca6d53383c712dfa24833cc280d209751330df21898f2474c9d3b9fe62ac1c39af3faa0acfa6cf0055568178632f44b9c1809f81570ff633243 +Mac = 5a33b8f7cdba999ed61fab3869b8f1e9 + +Count = 95 +Klen = 64 +Tlen = 16 +Key = cec8280c87170f1d4836cdd77abb2a34410b8d5351d96d1a03e90920a71a59ca1ca344b49f9d1352e1c226d75c74e555e601fa268725be8c88d0f094cc2aad40 +Msg = 952e93853e9579c2fe353dc83203d34f04963fd64880a095a4de6eb4f42e00baec615148ff31030780b5a4df0833316a1735d8a8fedf02f4fc7f9136a766665b8df727021cfd3f78bf4226e74a5de2ca98cbcea472419af2b341935eaaec2435c0179d1b5ba034fe02024a48c128ef59cf7fa7346e4f6e78134bfb93c7674232 +Mac = aedb7ea80734d1a65723da4f3ba18f86 + +Count = 96 +Klen = 64 +Tlen = 16 +Key = 9f65a426106db99dcb2130be14839241d4a92c8becc108d2c9521b8238c5c0df7c2365ec9f20848c0559d6e847dac3103ee31ce55dec0c3644e64c2993c497dd +Msg = 7d3d9286c1fa057175c33c556d2c4b87fe46d1b764727d6b6172d1ac27c626fe7835f1960caa44c8334198bfbba2c970148e62d0b2b71b45b3d5a05bc2f694b93b15d6538fef03e1eb123c8f143729f696d13d4b1de63cd6231efba6cb1a68840d06c925147249a4e45db02f40937200cb3aeb8e6da7e905f8766bf40cd9a846 +Mac = 9f19ab5e517e884cc1b1d3124ec9ca50 + +Count = 97 +Klen = 64 +Tlen = 16 +Key = 2edc66bcca9f99ee1366992fd0f0f954d3d4c5ca2115c2d053f6f8e33c0f6e7acca135f43427a7cf4b2df11a3165cf2d32f89797ed1a7958b5e105513757edf8 +Msg = 188a7fb0222c9d8e19d057ab22d71e0356c4f8d1184179aea663eefcef2edb85a55ca860925a97152f94f90073f2a2fbe9a29a370519156bb854a5314264afac48291c6f265e509a86d5604632047f2426c1ba60ea4ae6cc1e88d63a5695d129297b42a5853fb268451ef44506169fc736a8c2156dddd2180187e7e0d5c92844 +Mac = 03243d10c48609e8f4182638c23516a2 + +Count = 98 +Klen = 64 +Tlen = 16 +Key = f987eb83a3fd6d94ebf3626b7d34fec23ee06c63dfb4078cb38bcc97bd250fda0e286ecd4e64046a985bdfda8b01b34d9dc0cf2ab3bf5168ef64963bc918f5f4 +Msg = e105ff11481159c52baef5de550898214e1d9a90da2d9083c36b29fad8f956323613ae76c68b103807758a600e2379e4cb54f2998da86149c857700517232bbc7d8b610df0424d5a18df751e54d6d380fea73328f055dc51461a721f66591b333ed4e17ecd1f5852e55580bf2f09ec1c6f7f24e4091c49c4c51cf7f1cf836fbf +Mac = 03364863690c439b306a2967daa2418c + +Count = 99 +Klen = 64 +Tlen = 16 +Key = 5a35a2909aadd278b810b101ed44e1548ddaf9ba8c882bb142d9243f6b23348672baaf99ef63938e6e0b6ad472b972c7b9c2fc82c23c12f48db45c37a224451c +Msg = ba527305604ef5581850b222fd192e6260c3f20eb30d8f04a5f4e1438f83915b0febdd22f2d69ca958f97c6e12e88fd34f2f06cf789e3ce458e4f6518060e988ea337ce2dc9ad0920f7bfdd8113d9f77e8dd9268f83ef9d027c185303e16f4db9252d7aee54199fb87fdbdc6c0bf673473f61e40fb96d0b059b31647914eba3d +Mac = d360c381d230d21cf828782ae5e389f1 + +Count = 100 +Klen = 64 +Tlen = 16 +Key = 96da746779ee441651fb9ccd2da621eff4091111f8fb795cce92a8335ee7e31636195ac724955bab0394c672d5e5c1fb12ecac7140eb58bbc4807313f86f47f4 +Msg = 198b79d09a3dfdb5d41043e679baba6592f3c751cd7cbb0d1860029f6e7a9c56f137d2b03a9d217aed8c7b399044afc99d282544d5c2ce26d8065baef3dbad8739d78da7d54a9e789e7f8f35ec3e9597aa9519b2add9ae1944e7454911afa44517f4147d134d5af41070e9a236af5618e3c30c62fdc94131868a293a70ff69d9 +Mac = 3df86c710d782309023d65fccdb91db4 + +Count = 101 +Klen = 64 +Tlen = 16 +Key = 43aae2621459a8d5b5cc919445f3dabc0165d136ba01e58187d5ffb2b73f15b90951fce5207a7dab3163aca3ff1875d309687830018e17628111ccc8fae8c0bc +Msg = bac0889281fe55dae17c45079bc44f8976508f5a92953c26f940daae77bfb16eac037d7d5f8467b615863415e29bbd63806a9f169eae33737a82c1f5b2dbf0f25856817c44343d86aea22c47fc3e08e4d8d8f14986756257749a644513c70240e641fc55d914c091d35995678eb51a51a722efbaf1f2b21c0f112d66428acda0 +Mac = 83467cdf51f59916b492c5aba554c606 + +Count = 102 +Klen = 64 +Tlen = 16 +Key = fa235ef9f48a666e2e55dbc448ef934de0d22ef5c0ecedc75548c8b364eaba8ef8fb605a9f26c2c8d54171fbc130d28f1f06b9da7e6e3971ab4abbee6d994ef1 +Msg = da32314c22dde556d886ce2dde1291f1a4c1ba14aaa95b694063f57e91049c2cdf4e576c1028c66c6a4c07e39b40d9a1fc87026a1618ef04660f9b8f5da3b215ab58f562bd75e01684b98af8794ace8ddeeea8ea467de1c65797efd3cf92174fc5b6d4d532ad7c7aaf3521158018b5ded25e723b41c179d69d61baf3eeb91301 +Mac = 0d88a7f3a8369888b4c3223499412256 + +Count = 103 +Klen = 64 +Tlen = 16 +Key = bf248c7c6101e6e0281c8955e5cc028d98e5688d3f36d754f05620bd26a1bfa6597d0e52d1e2b80cbb196f0d7dc3e2a0471ee984ea840392ee34039fde5506a4 +Msg = 557f845dc8962ae11561f63ff9f7a9fd73ad5da479f1d1c3e9760236c292fba894e4ed5735398217b6b06f9a951d49ee34ac99478ac732ff1939c2db2093a89011ce0586453316dbef78c1ab4f2c6d8f285517637357a24d55176ffa4f612e2bb587f471614b8d34a8ff13fa8debbfe635ef007f9b6acab4855a311cb7c43682 +Mac = 84ac389ad6e42798a97784941bb76fa4 + +Count = 104 +Klen = 64 +Tlen = 16 +Key = 8b4c9c2783240e19128fcc2754c47d68d6acb3365999cd85d3351c74b7b94422765fe5c346197bf3228383491216e030ac9f7cf2dbf03216dfd6ecec954b0866 +Msg = dac416df793ee5fbca992682974a0c2cca63eb49805df0a75e1410b628133eea8f12e1614bbd85c66ab7d075e8dfb8df7fd2f430c0b1b03063248567dc9ea8852fe3620104c8c0fffe3a8b7749827a9472c7a75a7cd5408c301d7fcdb4fcdc055f408106cce8fe702d2b3ed1e2bcb9114b4dec0eda5206836c07e52ed9b44032 +Mac = fc38c3bddbc320bf7373834f3c83ac67 + +Count = 105 +Klen = 64 +Tlen = 24 +Key = a5fd99ca57c1fec8159a798792426d296fa1b17d539241de3dea335819b7ed0d92c596d72867ca2f8273924e058f9391a5ab8522fbcfe7d59817f1509afccb6f +Msg = 5cf3a5202df8706f6bff5bf2590de37c902c7ffd4e6c8ea611288e4e658a8e15fa51e647f9d22583983d4b1ced2239bfff346556234cd22d86b140530696a04446e4cac4013a720e9e32582e05e7c0acb2b4226a073e22cfe7b4c2258055d7406833ba61ec373f5aa566ebf24c62618ace341e01a34866d65cb97e8c7cd01c53 +Mac = 2c2bc8c87017f204c958abd9aab2beb6ac67781d8d9d804c + +Count = 106 +Klen = 64 +Tlen = 24 +Key = 30bc3e321a8978e235fa1b550064b82eaa0c107525eacc827cad6f1d66ff88e31b092cec663aa3aafc4462140c68390417f4cede020a4a736aa2522537d2394b +Msg = c1263be423e7888eaceccfef26f0b5aaefe03f3ce732dde98c78a7f66435e6199cefd62eee85aa2bc8c3d156aa3478b6cf3750c71155917207d23f3b7082acbdd4de3e536857721933eb21136ff502ab324971614d806ebe7491e989a0a23d3eb21dfabc5905e73e358b478c3ddc5c735e3e2a72645b7db61edc2d49bd3aa186 +Mac = d722b57c48128b37ba38770cbf4660697757bab95c00c484 + +Count = 107 +Klen = 64 +Tlen = 24 +Key = c189ce5334f670ed2815607ba9549f07682e11f70259dee3854019a431b3a0ad7bdd439f58772817b73c6dca4f9d10d59cb50c4e247fc51fff47a614965e0932 +Msg = a5deb712fc3bb9fbaf1398698b5696600fcd61ac68489f26a0f8ca32121a3e8c21d5904529662208b67af4a2f4dbbdc1674f3bfcdcbec714a0922c7aef63b911afd495345fb853fb4a7ac6ba00bb17cb063c148ecdffcbade1a958a5632bfb82b9a16ee9847a755cd2dab6ba963ccb05555c96682154d479cb05f5bb55b82c67 +Mac = 3d6305ad9dcb3a50105b92f331009a3cb03ca7ec36882fcc + +Count = 108 +Klen = 64 +Tlen = 24 +Key = 085ecb69492deaa704e25aeeabb7b7795fdcc807b3255f2fb30081f425a9c7990ea104b7785c288c733965965ab8906057e8c99d291e5e7325eced197b51c9a4 +Msg = 2dac1599844d82a79c7cd1669a1c6976267f655167872f8b2e0c5059717e8651fccc1770638466613b3bc4fc892f880e7b2b625856abecdab0418251df3754feb176b9a95ea6c7e6ba972097afe00eb2ebc6d344d65f3ab6c7f7724f77b21cfbb673a34b5cfdccbc83588e3cf37723eade175f1eceea41a9dbf5c85e213607d1 +Mac = 35fa859b3e4a793b2329652cc61f9f68816fed67fa402e1b + +Count = 109 +Klen = 64 +Tlen = 24 +Key = f5a07e3741f03174c6efcb1f9f186d1f233b367073c56e814f4204db2e203b048db6a0a387853fe4a6bd161ef903cab46671993942de90d71f60fef1e5102807 +Msg = 067ef2ee1e95ca546882e2a9d441dc563235198efeb52be97dc7894f092b8718a89c8571e4526602d7cb44ce86cb615a70a2611166adb7e79c1f5e3d0101c904cc781c2657479c21319464f56fef5b41429062a9cfe0d27a3a3c259104f5f379989b21d3207b55fb9d66ace837b4b054d189841de15762ec7fa44814bc0eedbd +Mac = aaed7dbe184423f0b4c9ff72dcf4557ec123b49682fc24c3 + +Count = 110 +Klen = 64 +Tlen = 24 +Key = 887c37f1f09920ba51885934af50a4b065e9e2160e971ed8a676cd26ed5554610cc7cbd17b78019a22bec0ecbf70527b87fb432f10b2691c6e6622b49d37dd3b +Msg = d6fc8b4b72b7eea80b1c6f53c11a52510f920527feb8f95598bdb120a0ab1994809018ca83de68674412a6656794a51686de08656ee110608ca4b2f3a22fedf6bea75a6b6dba05002c3e7bdc1f1424970653d38a6ca29c4a21e6e66feb1ec09a798a79b698136a7daae7173e536477de75378f1e5fc5461b41ca741be33f3c86 +Mac = 51ac4d2b5923a5df8ec48c14ec514a0629f8e385a9ea4985 + +Count = 111 +Klen = 64 +Tlen = 24 +Key = e9061ef9b298e47af4bfe35903d22e2ea4cedb85c53e5ae16b5e0501eb7ff7615dad22044e909c71b5903afc283c604650ed17079ba6600b303fc97b28c33d5e +Msg = 5e873df5f280723dadd718875684592a7b2c56916646bd874d7c99b1c9546f5c890f867a48d286e6fc0345f051f6dd1555c9020e758c920da8a56e43ea7389a5ec323ef00a1fe7ea7ddcabebd215979d9a64f0006472c8b1e860d06b85656dceeeb80e5f20b0bcd19729f383c12bb049b3c6cb6f1b4087fb757368338270445f +Mac = 20dc2be5c7f0b2fa8eaf026c152a09cadbdb82e52538b393 + +Count = 112 +Klen = 64 +Tlen = 24 +Key = 78bab2c40d60d0770c5d2bafc455265942b0d932174afe255b6c0ed4f1fca7750df031dff408c1e403bd3de2f375c2955bf8422f762772ab27ece35e3a6d6ecf +Msg = c2925d3d09cfab81f32f769d61dad5a03aec0423be785a7417cd7bf331f7cfbbcc893385d09aeecae00ee628311714079dfa357cf317c26e922423f736b9200c111198611e0f7587b27fdf57549fb094cedd28cc84e3e37f05d10784e0c9c2a7b9b1f4979b342800900ac9f46f7a938ff61d47db18e4a3f1985c9161d7319fd4 +Mac = da713e318a9e5b4b4f1dfe0a2af0837d70fde54442f264ff + +Count = 113 +Klen = 64 +Tlen = 24 +Key = a2f1635f239f03be853b26aee7b8035a5f267bf0ebd7a8ebabc0b8984d21fcd3c8693c124d544ea67a56e63dd23cb0aa6a119ce9e43e7a5da1f6c65d33d1c5ef +Msg = 5c32698a0a56b9aabd41270ec1e475c5f965bdd07366a7843f8adf2f8235c7fec694691e94deaf2245d9d6a5159f203079a2c95eb3ee3d3da3ae88f8e0f20eb307af7cb75307fecf6ecbb3f1873f5e21a51d5e933bdce010fc31539af0d71c53c88c8b9b6f5c0e79e121a53c404b966225dd62b834b8f7c3f31c275fdc6c59a6 +Mac = 5ebf7b7d25b0ff498322e4264bda56f7512e9d4ce3c9d51e + +Count = 114 +Klen = 64 +Tlen = 24 +Key = 69f533836771a3cc0087fc2fce7c42318f24c76acbf8f139b8693db65a7484e8ee777e3989438426fd729a3bfcfbac3f800318ac69f66d6268d7729b1dd46b22 +Msg = 70901c61c43a67e647b5274e55fd3a934b0b8790eba58470027afc67476e0fa087337a76ff1918e60a27a944fc6ad32e4d8d66bffaaae404286041b40a26e71b06defd5813aee9c8660b13c24d16ec855b2c306ec5b8686f0c4cb2bcdcf1c4c735bb2f6fc8a0e174a489ee2f11aa9080bc0f6c0715781697f667d8e78577af8b +Mac = 4f0a78dbbe767218eaeac0400656c4b4b23f908a9e7f4708 + +Count = 115 +Klen = 64 +Tlen = 24 +Key = 2daf08cdc015bf361f66be9cfcdd6aa7f1003db66fc95e23f70475c88cf8bdc268495b74ee1deecfe07e67d1d2001b4cdea316e99afab26c478d693a4b7de818 +Msg = a85ee973c99d8da60d745894990b24b9cad7e450be0e4369175e883bfbdebdbb5f45106e865a797bc4ab9d048882f3b69a15259fa0fdb940e7e9f0e46094ee30e9f41cfaceb5cb5f90e51a0fe5f119ecffd02ed4117eb8ba10acf3fcb7b61cf0cdd5d5c0aa96ca79f88a955eb73fdf828370c8961a7989ff190d582c062b8d26 +Mac = e6e7baded94fd4042c2d3ccb586d8ca983e8033e4ccffc68 + +Count = 116 +Klen = 64 +Tlen = 24 +Key = 65e35c88ebfc4c425d0362c5cd125ba40a0aa76516347840da281a2419ee82fba364292fcbdf1b6d1a154aa9453b29625d6a76274647575a6ae3a934aee09509 +Msg = 7ba8ff928460a47c78aa938519d33978d7172ba2975c0d2bb421b2a643b184e69c9c2713166759fe11831db23a7c184c0a733b0c90cea2ab712ebcef2da1ad7ea31af0f0d81e4127f4bfbae38dce3c91284d1064fd23cea7fb137e520ceffedb9a09a44e52eb23a02848b3419b326cf03a8cf3d367c359c75bb940f56a0240a6 +Mac = d9eafa06a75b5b671be1b1f1e6296f17f71ff467417b7837 + +Count = 117 +Klen = 64 +Tlen = 24 +Key = 84d5824f5b0deb22f4476578e8d0dd192bdb87f93019236a54897e9079923b15f14fd31f9f2adb7f58ac862c8f936aef3225875fcfc58510fbc43d08f4797b72 +Msg = 20dfbdc107b5e0af83b2d16021039d0269de2d27b40bbe6c3ea492597c19e589b076230bbae95807317fe8a5b22e802a78184c652d0e6b490053a0dbf8a34a4f8874966d637cf33a9173c6d5c31a5f9fe47c2c9ef0742d24096fa8abc8731e04d1617db1aa77978fcd18d3b8fbd023a7d493369da545ee448180149293914bf1 +Mac = e7928a55a3e4274394d81988a08196e07d5a5df047140690 + +Count = 118 +Klen = 64 +Tlen = 24 +Key = 833b09f3a7e41110f35ae33acef5c9a76ea93119548154fb154815ac60892c1b3dbb839493b5e0d9ed68c5757dcc954d621bf778263e7f508b848cc9879a6c02 +Msg = 62d432e97b1214a94ab922b6bfc7f0a32f0e9973a737b0b67f067af532e05a506d8a8c66653316756eb5fcc2ca18b43cbe57d95ceb67244fdc769757dc71fb6f0ac88d2eaf75f5edce3b772cfd2b6d32746df5f4643de7388a340afa03c9870f62179d0800e1975993d3fbbb020a05ce78d75303b8c0e2b9b0c839a650f1e479 +Mac = b4c5612cb1c1dc4333450daae500cdbcfe3ee1e3ef7a0d61 + +Count = 119 +Klen = 64 +Tlen = 24 +Key = 5efd2d24a034c9cb778e6730c3739a2e48abdfdb0e2c2203073083d5f38b59db813c7730b742afed93b195e4f3048591b2b5e84d140bb2c564342fabdb9300ab +Msg = b08f5e5926b68f1c18652c7f7fc593fb3c3f5370fed6331965bb77be681b5e2bf43cefe2d5c8f50dda6949b634954f3a20acc3fbc640b65660b3d3d59e08e7a549f3a14a28329691202087c69e88e7283ab7989a94d5f69b827516786e6a4fc0f9dcfaf9e49c779131b57118854462acd18959b4313dfbd11526c7119eea9f66 +Mac = 3d0a38dfe4a8801ab9f9dc1446c535d792393ea8d763db4d + +Count = 120 +Klen = 64 +Tlen = 32 +Key = 992868504d2564c4fb47bcbd4ae482d8fb0e8e56d7b81864e61986a0e25682daeb5b50177c095edc9e971da95c3210c376e723365ac33d1b4f391817f4c35124 +Msg = ed4f269a8851eb3154771516b27228155200778049b2dc1963f3ac32ba46ea1387cfbb9c39151a2cc406cdc13c3c9860a27eb0b7fe8a7201ad11552afd041e33f70e53d97c62f17194b66117028fa9071cc0e04bd92de4972cd54f719010a694e414d4977abed7ca6b90ba612df6c3d467cded85032598a48546804f9cf2ecfe +Mac = 2f8321f416b9bb249f113b13fc12d70e1668dc332839c10daa5717896cb70ddf + +Count = 121 +Klen = 64 +Tlen = 32 +Key = ceab398e4107483ede64ce107c9270e6022778b61f6a258d3b7045d4ad8506d32ece0a738d2cb948a562dbce8d7b66f30e6694d65ae439cffaa454af09abe449 +Msg = 6dde9ae867e2feb367008a975d7853ed8f89690f3c87a1107f2e98aa7736f477a527ed64956f0d64c1b23361b261de78688ea865fcff113c84817e5b377e829cd2d25bcf3adbc06762cfda736f5390d01a49079d56e969f03313e6c703e3f942bb87ed0f9c4d9f25120085b5dc75ef5d6d618da0926d3293568dd7d8238de3d0 +Mac = 2d3a760595f3fb19293cc6d23651222a9f5a4f02284457a9c1ed4c43ac993ca5 + +Count = 122 +Klen = 64 +Tlen = 32 +Key = 6a6155dc4d59c6bf46caa3de09666326da308c51a23e6ec342bd12b227376e8a1f11da906b58c8c515bdaf0d84dd48904dc6fd614cb79f5ef4285757e30adf72 +Msg = 107bdfb55c601e74f6505015a5cb87bc0eb0b2e7cb04594fbeef8e0fa5072007eed21183cc854a188a128ecf2062ad8604dffa924236fea9cf5b6e001acd5bb0e51ba95e53a7c21b42aa8b89da78983f66069c6f63a923c6d7208394e5d50f2d9d608f8f194ded45c51f318bfe94afb2df2b7fc657e42e6f7f47b3152ba7a547 +Mac = 6dc2b05619ad5458ee3de70b0c1649b3788e1a5312e8924b5486905506970881 + +Count = 123 +Klen = 64 +Tlen = 32 +Key = ce97ded47e101a6d0aa1041138093586046524f54345ec9e860550c9415bfc002d2c0d7beaa4d4dce985d71d89bf19c680429c637d1023350c963c28b93c7e05 +Msg = f62796faaa333dddae596f98cd4de3931ed90710287446604a158b575b4901fd8d841e8697b4df85131c555c246060f75ddcbbbade3a38b7c0444d25b4f6d00de6d8ff47288bc3a54ca1366ed1b2620ec3ab4c0bdc6a313bef880f3587766705cbcc4124a4dd72a7228f1ab61c6a704017eec2ed692ab7549f8ad86f1bf14e4b +Mac = 837ecd647e03fe8df9a92c32dcbc87d0734851ffbc17376e03218cce9cbe974f + +Count = 124 +Klen = 64 +Tlen = 32 +Key = 554e344537a09659920c19b40f2850b07235c3c7209993a6de905c82db1e5faff148e16f2883ce087c6da219e0bb892d8272c591515b5163bdb0c4ecbd1c7730 +Msg = 44e9a1f1437791963c1a3e0aaaae24affc3b405844d16a5233b6e5a145c4358b390c305bc4bf585f864f68333dd12d4139a69789105a109e92cc0cf1ff8fe2527891dab4b4fa8731f457574e39f8687fb4969dee7e3af27889590cf8d74415c9e9c0c6867bf0c5146e7c32e306ec7c7055557a0ff738b7e700a70d3e33a975f7 +Mac = 9cd24a0efa26c107738f5335526b57d8c93e54fef8c1babbbbb2d42f3a1d03c6 + +Count = 125 +Klen = 64 +Tlen = 32 +Key = 76d8e0342011d2bca953b26ee200e56685b721d50ed4dda7cd3a05633a50f153884998e67da901528004fb7df4090e1ec4c0b11f3f10bd4727842215044fd9ef +Msg = 0ebaefd2153de2c70537ceb27e5ee70105ae85bd4da38462b4abebed11dbcd36ade16d808f3aa54ffda5897a3fd74780a670521fcd2ebf231f60ef7d999e6e94d1b81be038ec89b49c5ca65bf1bf9a675056f2464021fe16355477ba5605652e8327401797bb569fea456c7f1b7da85d0c48af592de60ae3fe6dcecfcf767cab +Mac = 1cbd4f923d683ca38aca6cd0ad81151062fd642b155b2a950eb551ca8216b0ca + +Count = 126 +Klen = 64 +Tlen = 32 +Key = 731ec9f365f28f1cb9c4ebcf89d8648732a6dfa958d2c0152b5e52fae81f69eea26d463e421fba82cdb78f75e5d92304930256a54376a6ea107a995642c45c6f +Msg = d98557504a21fc3a434c780c328ec239cf8d7c26f58d6ad7b23329c79a8e1e176058aceba778aa1215cc14e5a92600714f94d4d8b2e5b7f45268453ed6f787eea3342264ad13cec78d990aecd5e30f79a069024a6d846d132d2ef0479a093439cba4218205f951a2d53ac4ea5bcdd599e9956c45cd73767c6a0c92ac8ecd0d40 +Mac = 4f2501d2a88cb13046a6549f90e4ea924773408bb684025b5126a8fc21f48670 + +Count = 127 +Klen = 64 +Tlen = 32 +Key = cc38826523a9097e0f7d075a3a039a70ca1e2b5590a6443e820ba1c16c3b89dbe2c65f37794074ad37e81f0a4786100ff19ae1bccab2eece281c6786d9bda3ac +Msg = 6e09febed308baa41a8b6e0f7fab61808c9c8471ea32eef178a4888e9a910a77d44026e2972c02ac5ac0ec3fed5f4ab90aa7cf4b2ef7f5dea62ea7fdedb63def35c2ae2344d301d2818105df4f78420299c12f25ae43a60e5089943f07c5f51abc15004982069e5db75721b54cff33a261700cc8151ee9c89c3bb91c92c51942 +Mac = 83b1403389173568588e5b6b8cf9da180408c79f91d054ac5cd99de0b728ff66 + +Count = 128 +Klen = 64 +Tlen = 32 +Key = 62c1d149567f05a0b76c4fd32d1f365d170cb165cfb38f922f1716225472eb36a127327007f8f5c08479ca7beac4b0aee26f3bb130bbf1ff390ef344c2a4e0b8 +Msg = 7af390cc4edde0f3d496137d0cacd0876b54c909dc5ce36705619742cb42989418d4b6fcdbd80256512a338f843b48b711c06f582dac2607ea5ca038b7126a5726a54e14f37778fe41a6d7532687c6166a50ec638c14600006f51134d29566dc2dcd21bb9ba289122b74c870fc7992cc006a07d1007cdb79e192b4dd25b1d34c +Mac = 2f1a4c2bde7c8bdd7d8a9b6315b19ac654266120c652fc24ab19e00ac11c5461 + +Count = 129 +Klen = 64 +Tlen = 32 +Key = af81e327525f3a9104b7282959a0f6600fad7efae7709bb8b33cde34b12f830c1770a342efb6abe3250a0ce7dfcd34590cfcbeb840b3e59cbff03f9cd89aa870 +Msg = 75ed3ae9085bbf2d034b864d7f87057c2d0b12c7395feb0375237903b3ebd60e724e0c8fbe3a200f518a4f61fedb971c509b794f6e62fe6f4186f894d9ea8ae50d16ea51628d66812f5aa50afeed30e634253025f5ae7ae0428dc86f64f949db8e6d5d96befb996ae4e312b04664d8c223d2c0b396e9673dbe6173fa1cc21cd7 +Mac = 579d35cef5b6f8468c8285829861e93587c8dee5791208406a7f4bfafb70abfd + +Count = 130 +Klen = 64 +Tlen = 32 +Key = 17a5baecf916634433dcf133ddc2dcdfcf4a680e088928985138c01d1d09eef3b437cc6290614f14079814c72bb75c45eff255968bb29b7421a1feffa00086b2 +Msg = 7809e59ad48aeb2c6f03de775b1371b7f86926ae0b87098e10c69e19d29b18073818cba862b6e4caf45158ddb2741a554ed791507d2649795004e92cc25065db8ea774b0432a457399816daf062025108dc8b210d75124d284a8434ec314c7af20bdc7f99e6e74ef069a07347e9df8b05d4571353e91026354b896c9fd6da64c +Mac = 810d7bda3421589a7dd60597447edf2b987f1e7283f3c65890248712c80969c1 + +Count = 131 +Klen = 64 +Tlen = 32 +Key = e09ad7d2ff8d559a26e0454bcbfff844e8d2415b07872bc59c93e73698f308483bb8f3212ac29050c1cc46f9aaa92732afcc67accc0e139689acffbe878f01fa +Msg = 4745100cec0406cffa146350ee12213330d192123af4a1bafdbc5c98801eaf6ecb19724a0346a7b9d6b1fc381ae798ebb0501392afbfc6b8be48462dc2522bb7baec1605e665f2e42f1679b6c383fa1f00a35a01937b5aabe1f2174da6e0d7afdb680223de886fb9cdeee1b1320dd236e6716f492f4fe3fb2c61d8df73f03bbf +Mac = 055ee0ade716231bcaa0a7d18161004127a37e7aa12773433a376073474d3d58 + +Count = 132 +Klen = 64 +Tlen = 32 +Key = fd013d615c6ca959030a520e148808a07e27d38a215634d53486ae8be43a856f3e5dc6eb4fd9874a8a6570276a9e7b25585af7e1ce39d325bd7d195f2c1bb951 +Msg = 91ea78334108ce6261ddee5d98045bb307a6e8f3d0ee65c1d9bc7d28cd9edf3264fc9cb6e592d072e9238559616cd42eda584d5200729adb619f5ee5740d632dda67f5dce34b89a054fda301685df6f31416cca78f19a8a7124a2a22dd7834847a934b4a451940152cd20ffdb4bd07273c4a2b9a86c9d94e7323a9860ec89860 +Mac = eb5aaa4ee702ff7b5324bc72c98fe87df6d9cc342b053ebce6cbf27fdea0eabf + +Count = 133 +Klen = 64 +Tlen = 32 +Key = 62e3a735edcd87fca0dd1d2797cc0e574160da9ac23f60e39501a5b77688d1287f947a0791922556f5b50afc434818bc83433968931cd752c9df9f04d8818531 +Msg = ec638734d336b8da6dfaf3da9e18c7131494fcc0709cd3a9a6618e9ba62533153c958e44345a7531c3eb503a22a5d8bf7c1d1e1d0ab5cfe07d6db7349cfc859d2e20cee81a325462cdfd8747dcd04c7dead2fe82cd96b2a4ecefc070eb067f6c8ba94f09cbe6ddd354d9a2eb13c2adb7285aa3d8ff68045cbc8faf35dd6aa9ea +Mac = 26db47a48a10b9b0b697b793f5c0231aa35fe192c9d063d7b03a55e3c302850a + +Count = 134 +Klen = 64 +Tlen = 32 +Key = abc9ccdfbd92b6919a5d6c6b5a765a39662ed90080d3549204dfaa5f6d70d48e1af8c84d53369d658765ef11d7b38510d9f431f99598f8cfd4da73d59b3b75a3 +Msg = ac4756b851fc8866b9adfac2d02599148e0db7757a62b1e06d26cf8c99556b79c91a5649ea437752cbf3b5f121961821ce1a2a4c635da461e3e14626cac707d04dfb6ed1e4ac40f106ff5ba03304e28a38e99a6daf6d9427c5980d1440a99296c05168f5441e2a6af13ab4760f55407855e0cf7f667ccb5d9bb2eafd03e455f6 +Mac = 0e445d77789a6947da70848dc4da5dc9c125869bb6945b04304bde93829a75d9 + +Count = 135 +Klen = 70 +Tlen = 16 +Key = 07c358ed1df3b06d47b5ec763afa07a6677ca3a722524e6103c1056d8c56f6cd0d318adbc5a4a3804afd23a62b9fadf0d358afa8b0eea0f995fb865e5dfbbc5ad2a4f26acd76 +Msg = 2aa1d94ec83ce7c3c75c6bc847759b085234fd44b407d8f80ddfe93c243556e87e4be8fb30b4743ef1169a24732fb2f5f416042b10c3371dd9d20dda29844d58370700ce69f7df5e69240df77b96027a0ecec71b904f690b875da854de05ef047c5d898d1c0d116c580e2a0906b271dec8e5b0dcdfb2550a40092270eabf2533 +Mac = b3a189a17e8d9e986cd31bbe01b49fb3 + +Count = 136 +Klen = 70 +Tlen = 16 +Key = ab8dfba4414e6986513a9767af5eaed9720811c4b38040b991f3fd8278b0adfea497002ce0cdd48594b5578ffe1c6cafc0b4513e9bc47ee07a1dd011b250e601881ecca2f430 +Msg = d1a7086d134c11a8a3204e019f52843e89f2d01a02a88a94d4a66e8d36dbfe924c6922f7ee5a1225aa8e75340cf8cbbd1c0b08e9296e81cec5f70cfc11d763523b12ca174433f246073d1c2877e4812828fdf2e41134bc8090fdce3faecd1e54a58948f59f3f78b2c1148b05687d712ab2b2d630416001513b9efc7f9523f53f +Mac = 7aea0e2d93e9a6a3004117ad4a4a72a3 + +Count = 137 +Klen = 70 +Tlen = 16 +Key = fc68be1e46a7ed0d4293c6ebab8d7546a7b6e95d495f7d315ac1d8df59ee112cc008176289b1515bf1c281db7c40ee23398cc2c247d9b1af98e3db95f5dff46e42ada2530455 +Msg = eefa0d62254597bd67c87e00fb35f69c5cb2dc09f58d9d14292b547b964232b79b482319172cae1874431deae585df51ebf92ab81e6ee57e2a6cc492186ab540cf417b4adae1983b6b4371f8a09fad9806dede755c52638399a58de1300f00ae92cc5c1ef4ce1dcd53afc053b6e92818b4493f6a35a1e0cc7dbef5916699dcaa +Mac = 04c8f6ebcbf13fdd2ab1e5c5c25bc7ec + +Count = 138 +Klen = 70 +Tlen = 16 +Key = 6e9ce34b4fbc78ea92d3d14592e1c0725bd053d70f4c599b89d4215a3f11851d6d67278970cbfb566fd40603411465c88ba890cd290ee099d0374fcdf1dd8012e017ff50352b +Msg = 56dc2b84da28f94847f598980ebc2d5892274e1639d0b7ecc24c3ea8d968092be8b2fe0f313c7b8d1a9c479dc737c95eeec078b9e7fb934103c7125e1f5bdcab79d03a9cc2e08c6474ed3b166544ee0a9da4018264fa338da06f9e2c5ea4edb4af3cc973b59c9496fdee5a4a0f6c042244dbcfb9d855fd98404ccb5abecca20e +Mac = c7e82b7b2478c319194fed944fb7c772 + +Count = 139 +Klen = 70 +Tlen = 16 +Key = 91e87e19a4a4af9b2068f842e624da9a21e57c40cc4d4df57541ebf140e144792ebdfbb49f450dbb1682b4ef3d048b8f291cf38ade4bb69116f9eb713e6a1aa0c2efa0158a59 +Msg = 3a51f6fbfef38724347ab1a4f7aafb7a999aee9b890a19e87af6585dc16c568bff9a5148012b1da5e4d46c207d294c1bf8b6f18dbe4bb5f89d975d9b23f89ee84a92e0385b9f41be0c05ddb9eb2e4dee00146d56ae9b6214db24dca9515f996b63602b34d3f6fa57f3388cd80b6004dcfbdde95e21a329247dc65ef113474ffd +Mac = 589afd7086a58d77f046c59a419504a1 + +Count = 140 +Klen = 70 +Tlen = 16 +Key = 1abf71698a7d52b41caa5c26558d46e8cf27a490d270168c23e4c0c4213efa7b0d844876aa438c61061c7a6e977f4d3f89b7b806572720eb99d308ae1d22cd8d38e293685e8c +Msg = aa02f0b377f161ee60b0fbd6c56a537c0358cb8da62b63d5daaad203239cd6ac4ee8c892a8fb73256d6a264a83d8085c681bac706a9ae5de16f9dcfdf2f95f2d6f997c1b19824f4011a118abbd169001be4d7ec2226a85cddbeb4027708891f8f35e35d6334d9c46329ff880daea9573eb3768093863eaac13c6270906131114 +Mac = 8cbd8f921c55d36e5b7db27f7891def1 + +Count = 141 +Klen = 70 +Tlen = 16 +Key = f8dff7f41b7e3ef6d558dcd83d344db5551d410eecb5a0bcc2cccb29ee3125c07dc8d2a25cddbe9b78b8e1542372c2caba073afe84ab7befde6250c595cba74f943c4cafbf14 +Msg = 72d18951da90b1f6d908253e55da1b5b476d6a936cd6e4433efce72422f92fcde3c3ee795f0b1f0b8065174f6eaa5d83039abb1680c695af7eae7a712726f97ea5feb6b9dbe1bdd1537e157b78e699fe063503f5be754a505ebf2e9dd0a31086a2cb089ab6da32503b9a4848db5776d5368669b990abaa2fc6792a2f873a1eed +Mac = 1c649a21afe336c72c4593cb3d3c9462 + +Count = 142 +Klen = 70 +Tlen = 16 +Key = 9fb4d6fcd697d4522dc7e386ab41dd9f8a637906e0fe123b7facabc719643172a84bffb50ccda872f6edf0e306d91bd130c26b0664eae4046eff52f71ba78de99d5cfc35307a +Msg = eb6b60d0858d6f87f5b9ba7fc75acba8751784ef886061700047fde7f692d868800e5751d5260c7cb1b338b9fb168e7ba6853ad1d5a2229842526cf0e0cc40ecbff0cf8e30db94f22bb8d9c9edd87e09e506f6e3d11492f625ba02c2aca1195f71bad06ee0d48e51296ea697e5c921bafc42bf0dc6df38f07028c746a238e929 +Mac = 9ca6f24c476e59b5b068c37b0383ff4b + +Count = 143 +Klen = 70 +Tlen = 16 +Key = ce3a2bec5ca00b544e8d392ed309e9ee5d48d185eddd8b33902a3b9d291b711f721451633e27f133018b028b9149b3f32e39d20bc12d3468616c589e1b62479ef395be4326db +Msg = 36b5cf31af37c90334f2f4adf6a918a22eff5e3e54dc1a4f9212e8d47841fa05f1f8b093761c6930818e9a5245081d349c48cb1e41714ce73fae2eb8a91835128cdaf213229297f548fb0ad732ca38c05ed5ace1c67a601a5a3fd3c0adb65b9eefa4bd391b61fb5971826dc427b6134d5cee2a0d4dc1fdf1cb0efe75ede315ae +Mac = 48fc1d0123e5c7f686d74f5903323f9b + +Count = 144 +Klen = 70 +Tlen = 16 +Key = b127e4819e172ca09868c28636dfa63b2eefd1ead22dd3f0db04bb3366aa37b53c52fc6956a46845a16a6698fe8c939e8d3e9f512b78f58339a69e2aa0a262fb11df313a92e7 +Msg = f1ab8fda839d00f0477d1ab6f3badd421834fa89a4ab8075ab77b738677a4cdf7d54af2a81d5ba9bbdb893cd2e8ed307d0f8e8111c19b846ce4b86ebeb111abf034e1cd3b3b4c29c6f7eab477e620a4c46c10646ca22610271de58d6091ccb340b009e7e21205f1ce53829cdec1ec83a03f81dd1b8acc4d01d98f5a0c884a865 +Mac = 41fe6d923bfb13fcec839d3c272383a6 + +Count = 145 +Klen = 70 +Tlen = 16 +Key = a04b6205d7e712aff28a8d520a79547e41e42800001970b383f8dc9998a7482aa387e3ece6669044fff68c8cb27d5165e9cfbb4ff97a6a77274067cf6bca0a64749a1bedeb42 +Msg = 6bfdc8539fe6bf99892c1c36d521f7b17c224ee3837755fee57a0dcecefb183e09e4cc1dbc19862253a2412eba0c67d2cf0ce61117668767af0d7c0a868c376fcaa48310a037cd6d1865c25060f4205638f5c5aba5a40d15ea915a34b4fdf408958714b3b3083b80c2bbc8252fa1ca459e23133997fa8e107c4cd2d4bf17f60f +Mac = b6aa4e0beccfdd37588699435e2d40de + +Count = 146 +Klen = 70 +Tlen = 16 +Key = beeba7959995358a1c238dc2f457f3c0aa6f47372f5f3471b85fabf1cba590589a74b385915501002ba5fc99094f684c45db476804a808f14a75fc42132609f69fc5a2090dc8 +Msg = b551096a194aee8992991325de92c9597c4d1c156c57b47036a7f93f2dd47be6f585906e43283fd8e4e75cb101d7f5e7a173eddb6f4ae7b7bef46502ca4a317240d7fd010189464223ac7ef6391969dbd5abc8c44bf335eeb72d4e92417215b79f2f974adcd5cc7058d2bf1b11c1eedc20ddf4f887bc65bd293afa161ab3ee5e +Mac = 98323e25ea0635d6abe384e8960f373c + +Count = 147 +Klen = 70 +Tlen = 16 +Key = e7747f39b1c6c0157a9128c012391e5148200ed5006a193986040a6a22e48cbaed929b86e2e73915381462c4f0e74160aa4aa4d4bc0dae0485e5cbf8ffb4e93d940ae68833ec +Msg = 868bf010b6e26e4c1f91f0614ff42bc1403087c33b7e229af6c718880072024f5e7abce977c36c782daebf804deb7654298e22ce83652b43ad8917b6ef34094c29d28800b95b82989fdf91d8df637cf527eb014db2d8d2546c74ddd257ccd04c2dbeddbf4752bb95bd4eedd1cf04468d846fada6907e1eb67bb0f14200e15f35 +Mac = 591d11b2bd18f982bccb6b3a44f760a3 + +Count = 148 +Klen = 70 +Tlen = 16 +Key = 2f95c1d1d94db8ce7bdafc8af1b7e48fefd96b7ae8f733f72f29caed5db42df6f2248a123f9c4a9c836b4f7d54df7a9f405e71a5b5b29fd91ea57c654fce0ec723aab07f63ef +Msg = 852f420342b4bead2e714424eb0f287f077602047f40553d816d6e4e76588f8540e94d33c00d37ba9c63b8e83f393f8321b69c254858ae4a0fa23ba8260e1fbfda49a9b0969f4252aab44f834c7659bcdc4f6be96d9fbc7780698eae124d5641dab61d23cc54269de1cdd19e1aafbf52c3aa37f5f5fcc9ea5e2c310744fb7e34 +Mac = 3d4a25554afa0abd26f72377c7180e19 + +Count = 149 +Klen = 70 +Tlen = 16 +Key = addfd600416f8511f3f07b03df2248b6bcec047003f49317546c26a4172f05d45f0c8d20136174f04fec550c08df6853ef3290af983d9c48dc86c6f87cd88000069571f9fd4c +Msg = 01c6d5c0272b631c3f9d1c0687f7c1496e77e1479bb9fc8f31e6e8b252297453e2624c7e8d1f1c3b0bc8f862a219fcb0edd52f1bddb9ad63fdaf06eafa45e1c5625de513ac26d98d794b095f196aec3751c7059b5b42077f2f863c17018427ea0b2069288c29e13d118f17a6f3d0db0321b4296e1f3a500c4fd253e170cc90e9 +Mac = 2d2ac1291e545de46a42ce6c435518f8 + +Count = 150 +Klen = 70 +Tlen = 24 +Key = 058f604e53051a0f8550de16b7245fdad3da639a6cc3c84eeabcc5dde8027390da488cc7f30772eb461673a32b7a4b4be47feaa2800878c200239756b9e0e807f964d037ed39 +Msg = a74100cf30cd26416e9878739dfdb3c1fa569d6427ca8ee9d06630e18f6f83db0df7248f6bafce5ce0fc21f5a34da2570bab04fef492a65866ff5c7a71ca72125b36ee9cfec716d96b53327dd35c9328a89dd498ffe3601d391e344de2b8e7f8d925e75fb1bc05a058c53475f6d38d1e1854979c0e66c62091ec41c3aae1e877 +Mac = 08e3a1718c6d1cdef2c0c67660f7c1e8a45963e5ffed54a7 + +Count = 151 +Klen = 70 +Tlen = 24 +Key = 986e0d3c3e7645e493d35962291d979ddf09e8a610d5a73d0ae7b397c2b1c35ec6d7fafa7294bc0f675abf4639b8655168814929922b179ae675a202dc4c305623f01865db53 +Msg = 72c21be6f0c4df7cc8a53f9226f36146f9ec5bea9c94f3b7b604a8bf5f05f72484ddd7888c6986c43b6c87ddd727ec348a2ad1fc086929f17192bd47799e71e1c6a7c9c49af9adcbb16b699c6df0f8da3069829d09bd231f942ceeb81be0320c01c5fb83619bdcf9f24aecb72e750fa2b35177b3e9b86aa7e57945f88df3c10b +Mac = b579eaf7706976152b1622c17fc47c5db3802aa3f46f6a3e + +Count = 152 +Klen = 70 +Tlen = 24 +Key = 7a41ca8776a3dde0f5c7d029f28a9bcd3c4daad2ccf9d604563f95501e256d6e0dbeafc304386185701d7c201fd258d8526464b013831a8bc8cf3292095316d5af4f97352d3b +Msg = c7627c9a6d1e7c41c18657b598ac29b28c4d0ef047008af7feb329353b58624ee0dcc1b369594676718c085d77891d35e3adbe6844d5a7d2dccdbdd15e0cf39bf69e6ed58a61e8614074527740edbdf7bbca7afd2c2b80b6ddbe0f73ad7a93fc1290cb275a9e2aa936267e2b7840cfa11c8b8ad78569df4c0a6c6744b10b0a19 +Mac = 53f3436a128fd497c5cd1a534558d6a6bdb5f086efabc6fc + +Count = 153 +Klen = 70 +Tlen = 24 +Key = ee36e5784fcb43427be072aaa968ea52bf3b73f55d0b45fb1d996d4a1928725eae32399c805b26e3bea38465a8df27b54e6a4f209a18d041906b70d0d50a91bb6e6e1078cbdf +Msg = 8419330710968fb40ae915e66548f1ac445509e361f583abaf5f87173e7346295f4e3bfd0a1bb0447c2b85f424492d3ec047f9c1c4dd99fdfbb4e00a70bdc7898fc7b5dc8851fd92f49ca825bb0576e835921f3b8fcbde0171cb3054dd96da775bad290b53e07d86ba6409e2f025d492e95d03ba8c665b9f58cd025d4da785d8 +Mac = 5a841e55fb2250c431fa397f1d0ec858b2c4a08e40dc897c + +Count = 154 +Klen = 70 +Tlen = 24 +Key = 27e1dca4978d2a05d3f9cabc29cb18c76a210b4eee825d37d915ecf59d1061a0c0740f4be0f81e92f442e872d45da35efc68418e8c8b949b9430b6498f6fa8a32dc9394e561a +Msg = 57d73f3bdcaadf51fd61aa65a01dc75638546dccdd899a1da25a086d23c05d1a5d93a157c34cf6168e0f832c54e9b2afdc569ba33106c0d6f5e0fa09f848b350099d56bc0c0604364d6f89ae14ce8e767aab0fe87adf104f4b9c8c05edadafd803ff45b2e061717ae488a2350956c371b95cb2e3e39df44f4d94a7a82c79b779 +Mac = dbeefbe2f550671d7fcd3d5bd66d19ce9faf5e6b29308ef8 + +Count = 155 +Klen = 70 +Tlen = 24 +Key = b415314e151701a503b62a5c8b5dba5ac357235a533fe2f634b85f04b85f1426cbfef29d7803005eaf3046684593e9543cb9972e451f258383e977bb92d6a1a9c8744b61ba90 +Msg = 0c8404fe10870fdac0e8d21c99c73d04a78b6d4c8fd3cfb8d3ae87ee520e13880e7a2b683204ec4b547b36a1f7e1539d541fd9885af8d15af33c188b893e0627c9874e21a6cc25e9a11ea7404861764cfdffa4e7f9ded33d918f9a96b7c82b70c31433d174c902db313aeca1952fef392b929613766b1c88350fd5b6e493ca8c +Mac = 95beb7fcb2b8d049adef7e0f33a7792c8d71e10b71ad3efa + +Count = 156 +Klen = 70 +Tlen = 24 +Key = e04e9731742a767445247fba9701ae17fc9acc451b8c4ff3af307c5fd3cece277c0d9b5d47aef5d9757acfd3337960b11f65cd1d095e025bf6dfe0d96bf19e08e89f696bb2a9 +Msg = fe1c33cadec693cfa53250d906d35d1e2db8df4300be8f2aa505600b44a063c60e91e7777ef4e44bde7a9a930e197517810234ad88d44a0ad30f84d734cbed08a7aaef69900bba794380ea7cc98363cce264807046866eef30cbd2661d4db2d9d14f92c79c73dd01db2d87bcc177f1e458c60db3c23dc283c52192e0878e7ae2 +Mac = 2f8d11fe7f6c07bdd0d33dfcb3fc7dec51fe2048d1e8db44 + +Count = 157 +Klen = 70 +Tlen = 24 +Key = bc3732e901768fc9b98303d599110be8236c5151780022796d1b22c6e0f43fbe4debe3709c126e0f3dede3e17776e157fd64d67ec3ad6f960f4a53ffd33a105d3ac955f48112 +Msg = 023004dff89f0820892be15fb91dc4c498936bfab92320eee6c117d412e3006c8fe3dd8382a411bc9378ba90e941419455d730facdaa435b1da9c1b4d9620cae966a772259ff59dc50ec609fc0ad276a3fd40afa23ab39903a1b0bf4bccc95ba7d8e7cc467f80708284e789328a89dcebe51a201a36e2915a7e09c9ea26bc219 +Mac = f51032cef423d7846270d8bb43f7d8426e392fd92b753a57 + +Count = 158 +Klen = 70 +Tlen = 24 +Key = d2229832e4000614fac6db5c0a235e49217fa4a9a831f9aae7f282eec79120dddce9963fa211ef0a07d21a782a5ed85d633ed8b8838d1f885d64aee185955f3e579c11193bd2 +Msg = 0d612e1953e7cfde5242fae7d51c8152d2a4a7e44de128fb7a467ac4228653ae47aa6b1f0b608365ce96a6ef9747afbdb5950b15a619c0783777aed4ed3515fba4cd5854760001d0de6e04201d644826ddf563a9154ca64c2c4059c16129473a6af27e205b705008caf29de3311a557493eb38086322e061a1ca02f3460bf153 +Mac = a87d01c705415dea8cb9f0e2b6663b629f88a5ce793ea8a3 + +Count = 159 +Klen = 70 +Tlen = 24 +Key = 043899af301424ed13d00066c0c37a448591f27371a284b314d2e7ec866a94c1ab502b67b47a13b8e9a86183a653fc27a4e0fe607a1a5d6064dfca224219d9fbe4f16372843f +Msg = 62908131c688711835177348434fdd1016941788765b50752430716e6dfe4f3dfe8b2588fa4241b14a35fdfa3562f1ed303567fbf74f0f63dc86f5555f2daf570095dbe951d3c9644fc47428f24fb7f603eabd9b2e60bacf58d1d85c33fa75830fb68b9bf3c56ffbeccdbf1aa59e95f538ba01b14415b782401904cb0eed0787 +Mac = 97f3b4e61b5885dc4c7f69f79a07d7a40c2d1d2e3936b91b + +Count = 160 +Klen = 70 +Tlen = 24 +Key = b5fee466f106d7a526d468468a16981251815a022073a402c4d7c5f6244af9fb747b3befacd85a3339674faff2f1ce174d661b6dd37d1fc8d19bbb5351f65c9848fad0ff11ec +Msg = 4745100cec0406cffa146350ee12213330d192123af4a1bafdbc5c98801eaf6ecb19724a0346a7b9d6b1fc381ae798ebb0501392afbfc6b8be48462dc2522bb7baec1605e665f2e42f1679b6c383fa1f00a35a01937b5aabe1f2174da6e0d7afdb680223de886fb9cdeee1b1320dd236e6716f492f4fe3fb2c61d8df73f03bbf +Mac = 1fc68ed1bad0898d691970b530b54cef7c2733a7f1ffd276 + +Count = 161 +Klen = 70 +Tlen = 24 +Key = fd013d615c6ca959030a520e148808a07e27d38a215634d53486ae8be43a856f3e5dc6eb4fd9874a8a6570276a9e7b25585af7e1ce39d325bd7d195f2c1bb95122118809c7fb +Msg = fc0723c3f84de1178d14375c3307f0babdbb2086813f6970b8f477fe289ecd3900bcc4a60315d077e89406030155db741c002fbfa7568ada1709a5298ad12c39aabcc2b0d5c646847ca9546cc9f60f9485651e953869f5a49208560909ea17d4c4b025cbb887c9a611fc2a7fd3121484c191f7ef7ea23338f2999288ef121672 +Mac = 10ab06d732cdf46a1711dfab98e136c4e6ed856ea0678efd + +Count = 162 +Klen = 70 +Tlen = 24 +Key = 05915a68f16938d7c6c5d4326904e0f3b89acf4d7063e01a4e38581575bf0e4910872dc9385436a218b7440e4fe294ea95bb446aa22f5b0c4cc90acaef83329411dc25fd462a +Msg = 5a40298e323ce97549d4c820b0a77cbdefeaf6ca9bad947a2b60985a0795d934e208b8334adc56497d2704ce7fb1fb6a69f94e3404791c1b962b0a86fc4cf037f960d375ce76146a0bade6caa4f705b5471da6dfed04a9eeb02e1623dc83c73d4852629ae7938ba09a6f575b48020367315fe6117fd4a4b91e70a57bcec3c50e +Mac = aaf4fc8d00177a99d1c895d72b3a63e7ce15f1bc3946f338 + +Count = 163 +Klen = 70 +Tlen = 24 +Key = b05f0e3bbb12b9351c465ad5eff31e65e55956c5f4e4ca684d53509f8f199d1a3a035aab661c7b4eb5cecc678649cc4a6b29bf00de52ff492f1f93ddc1bd02f776d169146861 +Msg = 99958aa459604657c7bf6e4cdfcc8785f0abf06ffe636b5b64ecd931bd8a456305592421fc28dbcccb8a82acea2be8e54161d7a78e0399a6067ebaca3f2510274dc9f92f2c8ae4265eec13d7d42e9f8612d7bc258f913ecb5a3a5c610339b49fb90e9037b02d684fc60da835657cb24eab352750c8b463b1a8494660d36c3ab2 +Mac = edfc7a2815d6779681590f3855e668f2c2d44e64c773e711 + +Count = 164 +Klen = 70 +Tlen = 24 +Key = 3714707839daf79122c782416351385e88a81d31c9f641d8dce538e90e63c95892a2ea9b1962ed0ba372f48e9474aa730ae2359d6e4e66e449ee33b859576807e58999614d2c +Msg = aac4256339f6377a4fe225d50e74424c80e0f96d85d162c410c3135a93ad397bb8e4e7bc523cad3d93706d2c7fc46a8aa0e8a232fc205e1744a207cd4e3f3b4bc54620ef20a6f8c2d052f6febeea50cdf49796549a3742f025ba90bfcbcb90633ab37902897b40916f516953b32e1e9ce3b57edb495d37d71bd25739f2995f4b +Mac = ac38d22527983468cc48efbf64cbe1307022327207fb7f94 + +Count = 165 +Klen = 70 +Tlen = 32 +Key = c09e29071c405d5e820d345a46dbbf1e0f8202e92de3ed3e2d298e43aa4f846866e3b748990946d488c2c1ae5a6e99d32790d47d53d205481a497c936bf9ba29fa9c2821919f +Msg = ea7240529980076d3b028a083ebc4e24efdaa06c9c84d76bf5b2d9fdb842e1038e487f5b30a5e010cddb4fcdb01ffc981eb0fcbc7d689207bc90ad36eef9b1ae38487a6dee929f3ff929f3357cb55253b7869a892b28f7e5fe386406a2776ed4b21d3b6e1c70cc6485947f27e9a5d8bd820380b9eced8e6b865206541be39fdc +Mac = 49ae1c4a7a570fde47f7517ab18898b1b991d03cfcf8c45bb3615b5f755da682 + +Count = 166 +Klen = 70 +Tlen = 32 +Key = bce50cdfff843885d4f364d69f93bf58a2322c707b82e878eec96d11e5db97bbb54606a3a3ccc3bba716261070a6f759a70ed3cb785fd1354fe56648df11863669b70c803b7a +Msg = 93b7ef0e470ddfac6aef93c0dcd37b8f1c4baf5eadd978e3bf0512fa0baeb099ff9ec1061b6172479b5674db5606ffa7e6b5173309370e1647054aafd5904816bad5e1523032cccd4d786505e241ac83a484911189666f287553d6a8164e8dcb0c85d75c4e29f624c97ceea64a2c8b0c9ddfa560f70fa3ff91183e4b968f88a1 +Mac = 37f9f32918308210849dfebf8dd456804babd6845af07218f9d9be9df9743d55 + +Count = 167 +Klen = 70 +Tlen = 32 +Key = 0cb35a02ddc8c7fb7c93aeab77b9318118b0fd449524209d879a1cd69d5439e192741f9c5c64a353a774e28681c58ced576783ba20bea51ed82ae50e30e6a147843130900dac +Msg = 21063443bf02ffe9f813dc6688920d036041a2a3a63a9956fc254a2c05ae03472537ef3489c93c7c68517c7588094c5e033434ab4b0ecf9e6c032c17911f73adcac6ccfd0ca57c427ae85127e2ad41d98bb94e5f2e6aad2e42ed26f87cb1bec6971c9446517c0966b6402321a06834997f3ab66756377a2f064d0277cf4e2bb9 +Mac = 5c258ba6241f65c2ee5356bb47332236baea227857e29506165861a4c7379c51 + +Count = 168 +Klen = 70 +Tlen = 32 +Key = cddf76f985d6797c9fe3830c210567c5094fb979343fd5a1804c239a2ebe9a0e8ac283b0cdbe802c42e2cc5da800c4c1d89da72ba7489ab80e2aef0488dfa69ebc8434b95c11 +Msg = 9724c0d5c989e5adafcd7527fee269ea14c0aec3ddb62596f3fdee9b0993e6c689466e877c0f6fb4aba29bc40343f53d3edb936fc04ba263bf00ac0fa7c816cbbde4ed09025ee2405a9d9229ed360b2ece058c20db7d8d28e43cff000fe2d5627a24c3c1231c463805e3e4c08462b5a50b65223bf4f1edcda8d872d6078a2c73 +Mac = 3c5a9ac2a0fa2f58825233ff676bedf93d8845a409a42a05a9ae5218cea14680 + +Count = 169 +Klen = 70 +Tlen = 32 +Key = 731bdc9fb219f3667c9a135ecf34c7f52cf638c39c554f1ef1691ae84e5a71ace915d9e91043a8ae6a7b6a6780b684f77b0417072f7e279d597cfdf02508c97bf4928c505be5 +Msg = 12353bca6b0f3d545ec4b470c69272f72bb5589793e6ca769a226018c5acde83145567a1d6fbede5c150ec3142dc58f81246d4a00acf242a381fe51432447b7eaaf84c8d43222c0da3a0175aca442680a21cbca1d7f70097e82491db7f7d75a5fea552555a8de0122c3d9eb105d1c4d802c17963a1664706d3bacc345360b240 +Mac = f15a210fca2cefc4d92bf14ff572d021463bcc28f60d034e87222dc6076eaffe + +Count = 170 +Klen = 70 +Tlen = 32 +Key = 85806ff2a642f729d28ded0734aef4f6a3f0bb32771e77729b4391cae4b49bd0a15089fe74071e576099a44d22a0e0e3c5d1450f717f68628460b4eae3945f5893e39c5e8347 +Msg = df073817d8687293257d7ed1816803afe292d779f34e14b0c5ba6e0ac1e6c3b9e239f4f02110f4a430a71e906a3dcc7b0b7325bd9cf63600b25d4544d8556126cafb3e61e4894095d935d647a8560929ccc9559cb393b77472c707fbb7ab8838ff16be71091c7fee8aed4d0022fbe3428f5b0e1f216ebe946dc05d3746305f79 +Mac = 6c63bed6c6082bfb085cf2426ef3d0dea97acd717a57ff0aa624d0b803f2ea14 + +Count = 171 +Klen = 70 +Tlen = 32 +Key = f13794e5ea5e27507a7bad638f8eb8b86ca5ad73b5a17424c63c74ef494bbfea084189c6fff5dfb2b6a5967cce3a81f9d9cde7a86f6b33927e15ee74e10beb20344bc121e754 +Msg = cd3f17355a1e254b9821276141a850f0b71cb3cf4824a803b01c71d8dfc31d31fd33ad1cac1776a98d18c6fd0598caa241a3af21772208d36f5270f4437570f963c8a323dbb41755d948f72369e7672b843eb0a849799d448ab7252e8abb496d05e44074715fd2f6849b02fbf6fdef3488d6fc8b45922fff0832d7af3efc7234 +Mac = d08563dad7c32c02b305b87fad504918fd566c433e98a1367a3dbbadb26e9b64 + +Count = 172 +Klen = 70 +Tlen = 32 +Key = e3d0c3abdef069e6e4fa35015797bd8a9d64bc9b75f20b028b12cca04a4fe80ff1bbbd88e9ef1003564d499fec88df4503671188eec5d7d089dd18b812c41db43a3746f77b97 +Msg = 934dc1ef76993aa82061cf67aaac7714f12e25aa8f6f54840a2ae3d84af32481511d300126db7dc612a5b2ac0fdeb9c47eb316541846781e270c8ee5f6731c2e86c94e4482594c7e75d70ec43bfe7250b6778cb2c2fd3d176abf07ca5c051ffb9a17c4c0735bd059b2bd8db81553c94100412dce73dbcaf63a0af58f63f15571 +Mac = 5717fc337916d66b4e292e69d507b1c81663d8140536670f3e70e33b04c83ac3 + +Count = 173 +Klen = 70 +Tlen = 32 +Key = 51bbdf37124cee0cd5830e9d8f4b0ecfa44c8b1bb86a6433c18f6ee961ab694d74f93316e5833c44c5e83a039e5d1ed104f246e36e17f4c5445eff423982c883dba9707b68e6 +Msg = c84394086457d8fa900a57f18ea50a93be16f06fc28b5532de40541da5959bb6d2646ebe7491ef644ee39cb87d1219625b213094a4ed163dd707ef80dfbf9564f38195cdbb657babb4015071d58260c973fb418562fc10d95d67fec8a77f0bddf342121b82f906368b0d7b04df1c682ecd4c2b2b43dfcd6f370888df45fd8689 +Mac = 3e0212e7982f43fc303d5e8457d2ab630aa257302ac489c74976cc5678823931 + +Count = 174 +Klen = 70 +Tlen = 32 +Key = e95751c99e14bed0dd9ba102f48e5e440519c53208e03ab7133613dad99042db7239347f5a47f9a8bbcda428ef52f5d7408235e4f3246268864c8c4135d27f1dc302a2d57695 +Msg = 36bda8d33b3bc10f367caf71c5ed387fe5f1493c1d3bd2aaf97ad78cba3cc5704c0c02ed78dec72a5bae329f17639720c8f91817badf7511d99e257c68bca5aef6e0102a8e36f01f2f1553327be0227db32aafd8e31d8d575a1ca4145da7842e1d7ffa11e60be1f898fb3bb15b2b81a08fca370702bbc285663b7edc02c50cf7 +Mac = d965907e6d0f926a7ea719464b1034a5879c865a00d4df0342b2d4f4bde0976c + +Count = 175 +Klen = 70 +Tlen = 32 +Key = 9dd10a4c713776700f7e7e0a710a014b923bf228234daf5e807c8eb3e26cb97fd6c93d6cee2a5d7ab63c2c46e91c5b8be5044fe95d2a76e54ee5dc323412f92f7db6ceb03ee5 +Msg = 3722eaa433830abdbcaa9177e373bab05fcb8fd82fc3afa581e34f08d3c07f5f58d0aeec9d7e71866c7a808ef15301251b470a9c455a612c16a586e8a5f1f3efe184a2e6313bd0a657d901319a9f44eb241db807a9474f3f49cbd2c8b8a225859ce5cd7b36e3af8545701a482780086a42f4a1ffa2b30144e3fd3b9052fc9e87 +Mac = 9c22961d48d0651bd592fd369129e44822ee22d35c142dcb6b60a725bf177c85 + +Count = 176 +Klen = 70 +Tlen = 32 +Key = 36bbb59925c6432139c7cd1bbc2b1b05c4010e09645f797e230131b2ad3468e7c9f2369b8b4f790dcb14dffcd6a941b262383341c80fd90d6d46fc8a81a25c47edba482c8658 +Msg = 03074e714d5eefdf5b714381d80e694ef37c2647b374d8a38a6dac2a2e1d11dfa43c6de19d8b0e93061563fbdbb46c683cd86f58c284ed981399d4adb457f6731f21ba04168011db366bac3acfc66dc8f3281b7fcde159c5343cd9d98001cd719d3e9ea25e47e1ff13fc87055d4a53b741f592857c94067216dd23763a227e21 +Mac = a6109ba372c4564f4ed8c875619ff5bb64d503225197ee9259dd50264eb1f4ea + +Count = 177 +Klen = 70 +Tlen = 32 +Key = ffa63ebba8239b6896bbec6af1c7b87b9c69257a0d146c0d5c4e8b8a99b43a18633f1f11b6c745ab05c5cbd8895dd96ad89cd87bb9fee30c373378ecf42274dcc02f3ef06ab9 +Msg = 739f460034249e805aff665d6248a594250695835aa24cfa5d9c9b962f7d374abd0d163f65c51cdeb687f72b778d4854eba00389548a180fb6cd5390dd9580b6a1ecd4f8692d88b3eebbc77c42f2cab5105e425e252bf62e2fddade2c5424ed6a8a446d249422a268b029df9c96075de1baa19a8d56f2d8051357234ef6ae7d2 +Mac = c580c8e0f6a1f36403322f7b0ae3d06dd2dfd16ebc6dddd205704e97dc2998e2 + +Count = 178 +Klen = 70 +Tlen = 32 +Key = 30be326c2ffff6d031affdab0a27d5a8cbfc4ba9dec626ad522615f77307e56d9e23f73e53c9f2c78cdeb5b84d2390727db5b3b4f4dae677d5fa7b161eec81b27d743bd56609 +Msg = 082e7b4cde8914bf07c288441be643e408f6cb5ca932f67e9b975bd54ca706885468708009afaecd4d9ee846ab6c0d70a364c5a24131a766f558ad219e06e4f7e80c68e9d8289040a586662fca865ab459c037bf92465596b4281178133e7a806b214dcd747b24e0b681ea459fbd9276d31108fcc3f968d781106f20d3d62fed +Mac = a51f5988a8f0f3992f549ea7f8c370a06d5ae8d65880067997536385d632b206 + +Count = 179 +Klen = 70 +Tlen = 32 +Key = 19fb88775a517bfedeb2cde7c9455ca58d40d150b0a47ffbd0288e42e4725822c48d130eec98b13e7cbb044b846026f97f9f18531df9a9fe464a99c75bf9ff7ebf72e80796d6 +Msg = 892525a0f02aae7f2264cb024632f11e8adbdbecb7d0c7080832e2373c94014cea02914c1542d1d000593fab43524fcd1f3a63670f6ff8509f1b1da881fb2abbde65ae27ea89a942bbf7fcb65b611d6e1ca20fb62b00929d68ae979e7595f6800d55637b98869f9cfc43eb6bb5e9c2ca281cc720340bfdb70bf5366340edce65 +Mac = 974752b18d0dcbf29cc6104295e041259622cb7733cff63dbcf6808b15a5ad45 + +Count = 180 +Klen = 74 +Tlen = 16 +Key = 815c2a911aaf0f8498706110a95e6f9c26c3ef52a3b13781448cb03fd2c887520df4a55144f8e206249b7517ce48afe52c11eab584f4bc0e4d5d706142edb6f0b67a99e82757b2d015d5 +Msg = 8b7fdf792a90218f91998b084756f32ff81488466bcd66ceb4956702ab343ca59c15bdfd405f7e20ec61a36e0933f55fc49a357f062db0b6a7b613cddfdb812efdfee3eb5b617f02918ecde0e9f6852313d8fda41a64b2b5972124a7258ce8901402f84a62df4dbfe6e8b064cfe6cd044d9489bf8ebb9552ec9c4399658e9952 +Mac = 7966440df79b13e95c41346eb792f3ec + +Count = 181 +Klen = 74 +Tlen = 16 +Key = 4809f31e93423cabf44cddcad23da7d7aee734d311fc7babc276a1bd3d35139861ead10369350d421d0af4944959cc006fee3f51b996f66031836a9134f1f7a0240a339e5e077d366c99 +Msg = 6e4abd414dca21a6ad433146986273e2da952ef613cd1f9a0a836ca644f9de19d6c24abc77845002d9fd48333a447ac936518d1bdfc043380fd26316fdb5f6ec0f05b5dcef92c3d5e16498b854fc3db9b6ddbf098d4bdeb2c45305c2420b7fabc21be7eade7ce0e76c80071c0e13267a0540ab0846f758ced00d3bf13c84e11f +Mac = d7baa0117d008af786c2bacb38b9d386 + +Count = 182 +Klen = 74 +Tlen = 16 +Key = 1ce3f5bce2b176bf89eb7015005ed1ff5177a4746cf8ed7226efd49381e906e02e6359e95081af1683031c381d744b63b4a41d00e059941e4142f009c42c171e23783addabcdb640420a +Msg = b6acbe5df01480614143c94790974c82d046352124f56a0246861042293152f7ddd65d22b491afdfa39092dfea21e318f70f18bb882f82671136ce9c5dcdd27277e8878bcb535146898d87354ada2fd2f694096de5c2d06944ecbca8bb2d4b444c8941807f81edfebce5af32f8eab716947c0f1f81d5dc70a94fe14f8a7644d5 +Mac = 7588b290c3adf86198354e3eee4fc06f + +Count = 183 +Klen = 74 +Tlen = 16 +Key = c8fcf6fcfbf498b33d3ecf12588a596d9fecc79ed43384fa4976138446ef9861ab0c9a8cd6c407cbc72878e2823ab706b5017f949bdd82032019b01846bfb758c7b0c6c3fcf397bffd4e +Msg = dc058f909e7170bee56c4dfde862b4314f68314a9717ccbbb79bd42d0407db7552eb02c45c29771e66043b0e207a2997ced4346da67bf066790d542b96b0be33eca737f26e23f84dbc5b2e52ffdefb261428bd3eee7492d235d21c8f3379818df15eb6809d06fe322f98ad314d3632c46b8d542436abbce93311b4c3a30a2e6a +Mac = 99066156163139a8735711534c022937 + +Count = 184 +Klen = 74 +Tlen = 16 +Key = 8985c5dbc6725a4e1ca26f5667d6da4938a8d542cab69a6938023075ee99846f5d73bbb8f49bc74d4b8f384aa1ea55ad88406c5ddf4a666b01439e973c91f41685a81d92692c3d734755 +Msg = 48ca2fb5b7e4f471a20911af6a66158e45aef700ec0262ce941350dc208adaaf95a84e2cce2983a2716f690b21dce48ff580db4a29f48c4f148522ed5a958931633f81ab0c3af1759c007e72f92f5dd41c2f65e1c21569f664c7c4cc6a6135fa9cd8eebbd9dee7f20b05786b5a262764a004bf4c1d2da2ca6d215f01b6b68713 +Mac = 0bfa572019e6d0f987f79b03ad67ad09 + +Count = 185 +Klen = 74 +Tlen = 16 +Key = e243c480ff1de35ff7bbb71963e145b20dc43b31afc1d4f4fe4ffc46e733b53419f3b99cc38c60869f67c5b72f8a2484470c87e5cbcba2caba61fbb26b534e79178c2f71980af1b570d8 +Msg = 7e8bcb42e9c0015e96f4f802520a15cccf3fb280540e7108b251cfb97aa8fcd86d1eea5d340aa3f65234e14f5639d89155315729978e0fca914732b513374138c3c01f74cab36964cd740a1b1f59094d3554a6115ad2a6e5a3e2ebf3269a479367b692101383faaff1fc9bed1532500957f1c8c203a0dc62d2691ffb199ab7f1 +Mac = ec8356beca9d87dce7d010de113b9fd5 + +Count = 186 +Klen = 74 +Tlen = 16 +Key = 2293336d9fd48570e6515a4d7c4985daf0e1230d6b6bd06589e71b8567ca3723fefff320af2cebf81e36005d4407071fc08fbe4f6e0804a43b7f491d389043e8ed71e283ef328721b542 +Msg = 7d70d5d8676518e8f4ccfb3660bfc14e20aea6c775a616b342d21d3a1b421f819eebc9d106ef47f5fd1fb7e3b2bede9f2c881a5ddef398e67bb5c73c0b860d813f27b81501a337ff50d58a8e4b2af73f8ba9ffe2b63090f951007c61d67b2a34072d8ced810a50cd94f65b7e528b73f7e6163b9f28e265b56eba23efa4a9de61 +Mac = b7a1d83414cbbde7a7738c7e77cbfe3b + +Count = 187 +Klen = 74 +Tlen = 16 +Key = d30c4a44e6429bb5a319252763da22b8593b7884c4ca9124698f677441edde996fca574374f08230a6b273f2dfd2f9f172a22bb3636a435bd70ab070c9e066e0ffec79453c32ea66b860 +Msg = 20a0f85250a95615b7a40f25132af070aa388d86df777bfb03c0bf0d6ddf8787cd9718e6bde708b9998cad4e91c7d58afc60b719efeb2ac80f4a152ea3732792ee74c809bbb44fdf397b753809b409f796f2e6dfa5b223f82de08935689c4a532a3def047296934d3e794f2da47af57f1ff501212753cc5604880369e3e05894 +Mac = 495f4ccb0530c7b1f03f3285faaae818 + +Count = 188 +Klen = 74 +Tlen = 16 +Key = cff586fb91a1e9d43c36a76a4dceb9e123df15670324d1c75fdb8c3b58310a8281fb1e33e6a6cd514d71b01fbbd99a363a557bd4da448477f6248cabb804b320df3c45ffc05be17e8b61 +Msg = e37e9da1ddfe11a2ff6a95025d1970fa1c2997bb7974d0010cc017ec4e36410c5a16dfbaf0a865afbf768ccfe4b8f446ae100ed6a477396fc9772b011e9c938e6925fc8335fef5481af36f163e1e66091ca1c476849b827ee35410e3c5bbf71b9813bda3b3e908969749077e74310e6aef46804122c6f255e4be8d3b4b7db4db +Mac = 836034775fc41e033c56ecf21d1874aa + +Count = 189 +Klen = 74 +Tlen = 16 +Key = ece40441a168c83e0e356e687788081f07f4b299726c5f8fd89fd836ed84017157355e455700d78dacbbb8efb459fc0ed5bbcb011bc8410522c0716e37cdaae4badcf9cbc6aaee031522 +Msg = 4b7ab71376d83edc4149b74ab10b7c1b1b6fa9ce977f2d63b2e321626306591e4174393bf287ca6ee7420d84467d90a628423edb05787bce6cbe71d2f89aa4237fd3cd6e8c1be59410f180ac54c65c47325f3af7857aec12deb4b0b379aabc026f5f1ab52cdeb6d72420b6c8c22f0986a18c432affcea8b66f8d860dcd7ec943 +Mac = 43385c80a077720fbb417848e4fa0138 + +Count = 190 +Klen = 74 +Tlen = 16 +Key = a3a9c55995ea04d6ac3a93ee579f6e7c966ab5edaf1801472377f86ae00a1f97b8adf02e127c2dbcdff27334d04e127dc63b1c2d8bafbc95bf14c9fd15a69b30bf1c1e3c268a2473df86 +Msg = 806e9111c731be67707d49b9e4248e82039608dfc6fa1645227eff6f30eb349b8c7cd6f6fbf0785550de26259049a6a55474fd536ff736a3d1135ef7ab43d3ccd413bf316c35df7ebfd289426b1eed7dc62f9b107a0f45717210c6a3fa5f646621dc52ab6229794a840179f7bfccea732070e7ff2f69cd16ce1c405b64686fd1 +Mac = 9014a5bb17057eb39ab9fe59436e6c9f + +Count = 191 +Klen = 74 +Tlen = 16 +Key = ccf7c4e2a8e7a27c7bc54422214c880e7c2582d0680b1395f02dbda8c2d3b539e0453a5e99e92657b8abc316fba1dfffc6ef23ec19e9a074c078ab6dc9bfebaf3bfeb01b05b686dc350e +Msg = 85a438185205f773b7b39db2a71ee86aee341f9b2285a2edd7a5c53913d2de4b02d79de7ea309c09606f3771bddf9e5fcc66289cc5b0ebb97f89899be18b4c389afa769b11ecd22e9fad8f38fd614ea5f8eb7a066c0ed8d86fd25f09cd2a49b8b5d36a3db17fc169db334d0e4fee21c2dc8bbbe1ffe892d11148ee8abff6fc55 +Mac = e4c09bb7f5ee13351baf8f4fe7386711 + +Count = 192 +Klen = 74 +Tlen = 16 +Key = 8a81d2ad65585e1e1383783faa17f460c39560ab730f95657d8c8c71c5ae731608920002cbf8068e91a446435104879d2712e9104a7c76493e02fab64b2014482dee8e780d44ea88b021 +Msg = 18915f3811cc77d3d9e41d543f3bbdc827f5781cddff193da94f4b7da46d0a39c93258b84fcf31573712c0e321e5d34763188d675c605a4b069f2880cb65d5bb9ab7e3c039107382dda6718cf8ee0c9f5262699d5b8298a5c019c7803cc1b53cb1a96a167796269ef32897156c5f4e1a1b5d7486816eb994fe458e459e899402 +Mac = a43a35e87ddb24ac3420c60c99090ba8 + +Count = 193 +Klen = 74 +Tlen = 16 +Key = 8281addf9835f1308be680dfae2dde6c52a58b698c9ee3d3391643a240e56d9f17372e76893f3e0cb62a67125b52e9db53b51e6a5ea55ad022c115b56f234c34c7db24ec1e9cd153deb6 +Msg = 48dd9054dc7703793557e492fc0fd0d45db0de0ec48683f1e402b3affef849c9600ba9212c65a4575aab9c52002fe81dd16879f5e4a0bea0b8edc6007462a5e77386182dff056c005da69b7c0b7db97b45628eafcda285eeecf4c5ccb4ae9d6f8938259fe0c1221d45322b36a3600a97c086656307f29e838afef73e4742fa09 +Mac = d02c59ac11fc434a37eded33245701bb + +Count = 194 +Klen = 74 +Tlen = 16 +Key = 183b4cda5c0282dab62aa4e48a19d3a5a00aab5524046e45f1085eb70f8f6af379340d9724ad742f3effdf05b3f2493bf6c34b16fe1a3e9d8f3ba063ba80b8a1a7077d8792a8b5d4142a +Msg = 3978b24f0bd0829e22c0596627d9d6d858f1c69b8c19486771cf30d01975aa5fb50220e7a0f85d169f96f24b674ed8a75f795867a84a28715b00d72c11606a95a9634890452c537b963c58095ae9a94e220c081659fbc77b82b72eb7c1661d369d03f2f00454adf58f1c5349089390f32a139f51a7146fae705afe16306d0969 +Mac = c6d5ed018b85568d03fce635a1332e1b + +Count = 195 +Klen = 74 +Tlen = 24 +Key = fee603258582e3a3e8feb886599d4ac405a1634c320e85ea8ab0dc6bb65f72012f82a2e951d2cf4ab2615661b1dac0db520a3d82499f4e1c5430c190ce7ee24b82faf0e2bd87cef9a780 +Msg = 67541f77f4e40d143035462505de14a02124b992ec1d0064bd15185d4d30a2696c510919f23b12eaf9f6b4ca497529d81475456ce4a80757d1136e6cf7b48d3f2769e22cdd0de49b72e4db839339f42df245953b3b53eee84a22d1919b8bc375026353b99ca3aaaf05c66457cb739e26235c5007db66dea0900ae9d621fb6b93 +Mac = f914c842b78c3b91fe6626272c04f6bfa39c586d4823ce0e + +Count = 196 +Klen = 74 +Tlen = 24 +Key = 832f87d596449aeca656e0e0b4ae92dcd16a66889020a9d2bbc48eee45ccc69b809150a990f993b82053aa425382ffdcfd5e1bb81457bc6f615c28fd7bfbc20df6c9db78d804ca084c77 +Msg = 782ac16bcd744ec016ffb6b014e0c8983dfde231fa72c31212349a7766f46240e047723da60350a893ecc7f3e79039c53d6f363fbe5f4c83952f2177a28bc0c6731f312870004ce45547ce93e6ffad26de41a92a289d244b51bc33173e44f5051afc24b69331e97a4658f51677f4cdc506ba657c9ef3f1723023f8e0a0e8aa05 +Mac = c68f215b059881c9f97117b3c6d9d6deea2e0945e3e1972d + +Count = 197 +Klen = 74 +Tlen = 24 +Key = 92a0e01315efb0b347666581560b44bc582ab63e8f8ea651ecf72bc3d3c9673d1e02afd0646eebd17b1e40e73b16ed62854673ce84bcf9c83317ee11203ff0e16f53ed7e21e3880c9760 +Msg = 7b2f5c2741338d25d8f9d4bb0fa718499ba960c65eeb399fe94b59c23f4e81f5db11a86df583559c02d24d4a7a236ee7dd86db20f82959b065ccf9795174f8d38164e3249749feb192b5e7b395ce77aee948e9fe44903eb24c4adf9e57fe85ac750e5673b0ec510b9289eb1fe811fa43c6d5d388cb89af4ea6af545ad953f129 +Mac = 3d516a213a6b8c7e3434138238ca5e339fc21038fb7bfd21 + +Count = 198 +Klen = 74 +Tlen = 24 +Key = ce4c926c0922ba36269a20d60dcf08d43a1cea120f266af76f1c8acd883d1f68f09b8209f41f87822dceb39a544aa9b2569ce6a9ab30aefee421463484b8647b112fe48c6bbabcd55cc8 +Msg = 8917aa6e1cd35af30eb5c7ac200e54835d4a0777a06a2fa756b44aac85a8252c0e3745ac2f3086a64bfb02dcee8934eb0c8b5e2389e22796fe57896fbb8dea8608338931b17e1c5cc1d7b8dc8dd1f000f45d4169e641ae1c23c6a7d645b12fa001753ea2aaa7643cf6b2b05305ccd0e99f2979f1be6e0a614c686c882dfe3ca2 +Mac = 94c47b509bd0c9b7aa95289a00a8a54efd425481307e9ebc + +Count = 199 +Klen = 74 +Tlen = 24 +Key = 0649b582dbc59816a8042cac30cee6772a0ed8cbe8e07bd538ecab8a88f3f3dd4da70b35a5c09f1e3a4c523e6a46038ca66b4fbc184957fd8999c3e781ce07afb0eee49e8ca132c13c88 +Msg = 1c685e17890ee079ee85cef5ed709356f4199e657aaac0bc85a1d5d5707ea666ebbe0ef1430d5c96e4b8f92d1c614b9121f6d83e56e4af1fca8704a101e51a0cf89d6613631af1aa390cfe177219ed4c10cf5f745cde9bcc728430b4ff48dc064aebada6719c665af56b24dc7900412ec78d792e14014b6a857fa235f20eb5fb +Mac = 9bd70f0386405c04d1bfcaa538b4099abea343c5c4379482 + +Count = 200 +Klen = 74 +Tlen = 24 +Key = 3d7094e005eaf0b1231cf60536f768e62f79dae86374660bde91a2e2fa94cff531e2536530406ace2cdd187179936293596abd20125ec7944362351b77a40cf7fb131523ed1f8a3696bf +Msg = 9706d7370b66bfa78abb8b25a9d6143a9aadcaa4f60c9baab98717ac8fb3d2fe4e960af7c35b8a44b14ace8217f8680db2bba312c36165ec12225aad33d24efa085cdb1d876b4555bd6aa27013af3e9cd1f33d7be0068275d4c0d0522a3b2f08cd3f92d1dffeb681b7024d1726635c92ff3de206d661baee074bc2c4fb553dcf +Mac = 59526ab645c2c0f464a48e411d111abe9aea19edced55383 + +Count = 201 +Klen = 74 +Tlen = 24 +Key = 74d72be7fc8f4fd566f863ef53bdb361137cb6d96b79efdd95941161897866997b16710ca552d3ea46fb6b9feb01c1a8ede2a5a53b6613b0598c5aeea9c47d63ea5eda0bfe430926f0e3 +Msg = ff8468cf11d6190cae4a1e16871ae0817214fd441a889bbdf564fdf5779e542686d2d77a2d2d151694898a5730d9715b37c8dac4579dfcb8a762cc2cde45cf63c33e2cb1e4f205858bd807a7ee9a40bda6be31146285259ddd13c1360dd1db2b9e1090fd9eef90627a7ebd8c2923f5aea73d2bbda508bd747fc1019a6e0a2187 +Mac = 8ce0b5dde0328c9de6d4acf84ff61b3f7d01f9e9e8e36b91 + +Count = 202 +Klen = 74 +Tlen = 24 +Key = 94869ff7b6164a24e89ab734f20322421bd31581548139c6b41f6d46243a15a05c02b41e0eaabe376012a759a0a440e6337c437dcfcb2c7aeb7d4bc0731918b6bfe9c68fc65c1bcf8fa8 +Msg = 32e5a9f3c3f9576a21dbfed017b961f118cd23f3808f2c2b1d294e35ee2b28432a804bb584a19ceaae08fa561ce820d50a1bcc3fc05b213d15b6495b323c605e98fb8dd7652d72f8d2afc7a701b541d1f6bdb901e3c18a31a8b13be09a205e64833eb782eb06a13c96b8aeea4e8a8e8ce39a325f6f2830aede026aebae3febfe +Mac = 549afd1666a491b7ee9ccf6db2a33b2e3c2a21cfa69a1b17 + +Count = 203 +Klen = 74 +Tlen = 24 +Key = fbca586edfa57645037b6b3cd70fc341e4d4ec97af4b3dcbe18b36e9a6210aef531b5a824b6044e023439c16045779735184f43c8a5a2ca171a68ef06b4353092833491286eed76cb3fa +Msg = 4bf841ec0a4211b05f9a45a127bbbbf6434e8642910e8ab11b2a468e8feaf009f096c7388a94a55b2bd0d364906122b71e69372ed33c27607bc544232726364fdb9f4dc587b115b038832b0b908450647452bcdf04dbb47dd0c25f9e4804d6c575db7a9ce7e28a38ef7af59d0e6d6c85acd2bc5d0d315b9182e74009dccbf8f4 +Mac = 0cbfe6e817d297b69d5bd7740bb0e5172d86cf870a9c4da4 + +Count = 204 +Klen = 74 +Tlen = 24 +Key = 624248769dc2742a13e6b69b5e7212ca459b36bf86be5dd8d35273601a1c7a6309a12cc1d2e1e2822b42b46999cbe2ccef9273a311781bdefe1362fc0eec03d978eb92c7160f62e16d62 +Msg = 633974ba735a5e57d1e804bcdd4d72d4a9e9df0fb9bf8db2076ef1714a64143f784e39658ad2c0d17f814ab1a3071e4111a5cce177e2106b197df8c319a549b0f56c20ea517ad574f7fe242b1ceb8fa0e560fe232967a92079e337af5dc42766e17d707150b864e54048da52ce5f8c982b01befb58b821792d8af65aa028760a +Mac = ed1fb08b8473af53d2fe4c607e5ab9639cdd11f728462294 + +Count = 205 +Klen = 74 +Tlen = 24 +Key = 25cdcc9cb014784dbbdbb13f56ffaa63fa234c916f02367dec0303e8810fcb13b29fec7965190abdfe5c54e2c89909ba97663ba1ab0dd46bd82ad69ae475e7d431dc0c959bd5b522a4f2 +Msg = ea526480a096a4d89306b3cf86eff742ab46e4e9ad991ee7f344dd9f24e896cae619d8c6ec5774312f40e0b77b03dd282e1858ce3d2f8efd776674eb0ebe56c253d0bef4c1bc97cf3d6392519cd6c93d660da36ed9ddf76c3124743d2747407eb8dedfb227ad57d945d79145f04e03a9da8e8c738c8b9f5baae7a43c78699b23 +Mac = 4cb070e34b3a2ecb460670ffdd457f23c9a1174bccd35f25 + +Count = 206 +Klen = 74 +Tlen = 24 +Key = 3ac105a2bd07056d3e1c3ba547359dba94e8f79a6c32ddd532bee4ff37641257d2f192a5b326ac697403f5317145c34bda2de49c068390d00adb9bb48b17efdfd02d3a981b2ae4f43a77 +Msg = f6eac4c4099c3232df018fb3c837527b8021a1a20cbb5d1be5aa5ee5581800852dbedeb38742dd540bc46da844b40bc546e60a4492e8943a3a93ec6a46e0f5b855fdf8e188a0a26a9b9c4cd655b2801c23a9b85800a068c197a43fdbac7eaaeeb8ce9bb6d35e885cd7b0b6a5c3d9b76a5d9232481c8de2984405e1a15399270d +Mac = e5d5cd2e163ec1c883388f5f01980d3bbee914586ddd5b0e + +Count = 207 +Klen = 74 +Tlen = 24 +Key = b8d9d674cb623d7a449411fef509558992b7f6e314c64f855c9ff2511946a681ebe9acdec9b94732a0f87bff3c5314716c73ea9261cf64bd58c43b5579e780b6fe9ae16c97dd28a40d67 +Msg = c9f902c8c02c5b24bb54e2dbf5c9573bd46bef39ccf15462817eee152b7561f03f8f57884c2b7f5d22e5d60d3a6925c7528aca03588ebc7089ccca2eda7a233e97c01b374a102c3adeba3b2704bb1d11d6d65af0bae731968a73dce5f283153e19b3d83c83866ba336fc9c931b674a02a87a2669bca3bbbcca9baca03a3b3dd9 +Mac = 64ae3ccfaa118acc556ac50e53cd9fdf7d7e3f4b785b2e20 + +Count = 208 +Klen = 74 +Tlen = 24 +Key = c39ce5407c0c03ddfebe82dcca408c52f26b64027e38edd00dd57079c0f89a825374c46e8d0a7834db8130f038f860d94f7cb773e4d6a20670a6134e0bb680748f882e3dfb31af82156a +Msg = c1490ae9579828b2d6d2935f417e0dbdfff5d424de5ec50557ddc7c3140867c4af9bc0c7bd6c9e780ba1e341272029642247a84795de5a0ee2495e6fbc029bc2ea47a5584710e40e0e44f322542c4645d62810f1f5a163fcff3e996eb05bf490f9b78145ff6c429d67258ba8d18bad88a200d2ca079028f737244265f8f9bb53 +Mac = 0d2e37440adeb6836d7f47d9c516124ebbd64abd435d4c98 + +Count = 209 +Klen = 74 +Tlen = 24 +Key = 318608b213046a3badd1655c51135c7e1492c6cebc0f2f36e0d77f8b4a987f08a07299fb4451e0be787b50e9c66556c69fcb930542ffddb1df828663fcd1e1b6198103fa8f8ec72dbef1 +Msg = 45fcbdb93acd8300ddb88012ceb55950f4da61145adb0d4c3dcda868632f4777ae2a008cf01857670144f9510ff0ad48369d875c50865e590f6e81a6499ba66d922323fc1066616c8bdc8d80c41190cf08ed42260439da28db5faa37767109981c6d90d142c08956a408a465941eec2f9254fa381efb6800ca2989e393b9573e +Mac = 95b0a9f0ed9fc80581407664300488f5223720148618b1b9 + +Count = 210 +Klen = 74 +Tlen = 32 +Key = 81574323c973540719d192833ddb51f13a52dcbae294aebea51be5f6aa47f3571f5d97facdcf0c7befbe809f44bdc73963d8514e4fd559774bb96087ef8eda6e7c64275d6d96c42b4e4e +Msg = b9e944e0b42d0ff454f7f8aa24f00e9ee039058ce4094111e39731b6dc3ade2a4acec4cf9c5be078e4f10a72d3d685c1e5e4d5abd92cd07b64dff87f266f0853ddf1cd61d9c637a9b07ab0be32ecac119faf827218b17ad4541a27519477f76ed918089f54b63d0e1e5a92982979ac187764b5e989e066a61b1065340e9cd203 +Mac = 514bd18495f6de0e237054b8e3ba1a74c3fada4279ad6b8550f3a14712c528df + +Count = 211 +Klen = 74 +Tlen = 32 +Key = 44f71c2317cde52151c84260d1d3c04a28cc15ce5b3802b2e5357e2bfcaf10ab15d77dfaaad1a3883bada502939948234c559dcd95e7e158338fa12ac6fd21874ec2ffabed051416ef77 +Msg = 2ac0bb0524c22b902de34ce64e6172d1b2074e159f517ab1abd152622cd10669f03aed8e2eb51c65bd0f38d084e288c532724e512fd558ddd257d2b1d41c5eb6040767803ddbb18b95a035c5d8492d4d35936b7b3630ee20f625b70f8e71d9dcd0efd0e3387d138c1f5eedce32dd88f223334b9a9eab65017f04aa8442179f62 +Mac = ca0053d51f6cf6f9998ff1e0db00b90e82c7b18cb5377acc8ebe9afe20da1c3d + +Count = 212 +Klen = 74 +Tlen = 32 +Key = 7edeeb6b63c3b9c836c4843ba46bfebd8ca9a6e205c7ed68a29f9710f50c65ac519ff17ad494d9b0a5041f587b5cd05e5f0de4e8b28566e5715fd5e9b8d6c9388580d921bf39bd8d775c +Msg = f5aff283b3aaa4c71b13c590771d8bd3358d76988ecd1eae653c2f9d72c9b2dc9fc08e44b2e34ec52dbd245872332e342b5cf945e99344da0bca069ee221b2c913b7b9973cbf50fadad7758b6a962cc7ce640f78f38f0571b19b527ef2d9d09b173b7b64976633cde909be13a56d0df3e64ec019f2eaecdb1d571b27ea1994ba +Mac = 5131ce486de164491b4bbc84e7e461a874a2cfdd769355584a063e306960acac + +Count = 213 +Klen = 74 +Tlen = 32 +Key = 6e1b663e808a6986f29956b7b9708066696f9dfe0d7bcdb55696d8bef9b3b7c052c857884d2499fb86039d4eaf604079330ae3e818fa6f742ae49593560c5bcb545bd46d89b22e7f2b7e +Msg = c0bb12a5da628363a71f1f5c9ce715ce8995e607148d772b669f6532242f9830a1931bd952bd2a44821a8def46b92504b4b0c5da50bc43bfc727cef5e0ef81faaf24390c0c92a4ed43a09be40d78b204bf680db0c288755f439eaa9d2b3efb5352361547ef2919e65479f142d86ae35714856692523b359442cba333ef662ec1 +Mac = 665344e5618e0c1fb8758d049409a484fa69b89b009746067ea036bfa0ee8a37 + +Count = 214 +Klen = 74 +Tlen = 32 +Key = 208f91ccc87965d365cc325d3262b64277f6112b0b9371a4174cee721c2eb32638735ff2a5f8abbc82f24c71d6dc1b9cd2b473375666dac0b789e490c0495569f6a4864e20da0a97071e +Msg = 854b32866273c6eb110e380b8f3bfd169cc87a6f6149c75e5667b305637b0895465c10c134745773c31ab3be071c8215fb9a33ba231b087870da199564619d03765965d6b8a1a9fbb79d0726a3d1c90cb0ae67d3bbab4cc63198dd4e2d2fb81de0ed39ad362043e9b6403d2aab825a6481ab1ea271221eaf614a0716050ee14d +Mac = 42680195f431e71b592899686af630e15996dc718cc29030163d677688a33021 + +Count = 215 +Klen = 74 +Tlen = 32 +Key = 915794a6c6540f1ce9958c2784cefcc13772198cabd4fa17c88de45c281d648dcbd59a100cf4d8c8d3106c960db7b91f59578dd0045bae203897b61570e6210a2f11a5aff2f3c25163db +Msg = 99494422460ec858a24394f603b1d9b940a24ad9c6a3d1e9e88781fe77afcd139389f7acc057cbba3d328cbf914e2f32667fc7259afc412594645162d4feac10ce45780cf9a400c3237ead50077132e421dc066bc19e176c5f21bd312e98ec29f384af8a187dd13afc2fddf08ea34a971ac0eff36311bd86f1c8acb5ac03f627 +Mac = 2ca1bb808448eb29085286594de21e254fb3416f9ab01e99ea33ca83c1d14dc3 + +Count = 216 +Klen = 74 +Tlen = 32 +Key = b1a95aa80bac5acb7a18332fc03067600610f376d99e77a272be96063ac5a0ca8d316e6cbe978e575cdca1b8b4a8008d9718a6fe5eb34af12aa0cbd97116d1ceb613b2e3975192b40d76 +Msg = d8efcb416f237c7e05bed9212c543011c39e6a5f25d7e2cba065788a29bce1464d8041676be9fb91216cc76d049806ad943e534a6fd45b10c41bee5d0b005626f3c0e73a9c50d7cb07fc502acb4ec4d2093181a8a1568581a6d793e5101b8613b1f9e6446b20b9349fb69bdfe83f11880ac11b00252508252fe18ea9a0d41a15 +Mac = 988d4a6fa87f8138d754c5de9d176c45eaccf8eb8ca1799d87c8f04a966b6f4c + +Count = 217 +Klen = 74 +Tlen = 32 +Key = 9e4ba7d72b76edee6a6f290ed318bedb0ad88c8411f9c449bd4ffb3a661b7e41e32ee662b552ec4283e57ee6c7c712bec6773ae2c578789b7afa5425c1b6adb3901a4db42da6c0559e96 +Msg = 1a0223261ab437a4ac1701b4780776c43f0f8949b3e7a1618c3b4ab6d8ae2aa6921f38a2772b28d415f32905251fd3bd1a235bacfac00a486dceedb8143acdf11b4b611f1229c346f89f21299920b56b1b08f7f4d32511965d7693f0eb326893dd0c096492b6f0427ea450e87d1203146748c3e9e51d9e9183baa42806a0e3d5 +Mac = ee6492a669e22bcf19bbdfc45495cd0efa9c2f2ef5d42831e3f13a545cbcd6a1 + +Count = 218 +Klen = 74 +Tlen = 32 +Key = 8fa12bc017bfeb6c894020e420c5f76f9080e8733b998ef3a7d0b6563063b66afa3200a82a21f6ba56be003a3924dcbdac1f3610d29079c19213e4e14ae0e009c1ef919b5e60ab4a9819 +Msg = faa6ce40d931f3c0cb4538a82a22f0d4f3221f027b99d3d85dffb729b751e57496b4fcadae5c72404fac2c54949e4c4cde664b948052479abcf59e1aef84bb9f088030473e9505c603c350ad33bb06ed928c1196757ea3e5bf3ec97e0f3c43f638529394f2a65459cfd1cd3d7041c6bcf8db9a91c1e58ec24e2461dc81412580 +Mac = 9611e838fb1d816a0ff9cd269217d93258c34df9e26b74476fe4da0f7dee2335 + +Count = 219 +Klen = 74 +Tlen = 32 +Key = c18bc28d496beedb25ca42d1b217bc81891d4c2bbb35380e5bb9bf7e3dbbfd37fef70ef14407763447d6c06e915766430277f124165061236b9fcf057d785199b4381e49a2bcf3ef85d0 +Msg = 28b18b862ce9541ed6daf81199f9a331133b0ea3e48ff486c1acc6d5c40e9f8f063b7a15704ba3d3cea76b222511206d47e53c93a49edd8d639b7551b224c3f65aa802189648607e259ab1fa9ea665910435b7dc9a4c28aef8f32cf85f3a23e94a7e8a5945e9736702383261aac15ae571b4e8466da1bd31a83a5291745ba7af +Mac = 0bb4127d89d9073ea425c303adc3f9db39e40adac23ea61fba8b6e251d79390f + +Count = 220 +Klen = 74 +Tlen = 32 +Key = dfd4faa6b9ebfff6eb33d4b536f3f18785fc33e82ddf3908735d0fd94f1f09666fa8f2667f876611a8d17d3256ceaa7e3ff3e224a11000a5cacb68e6de4dea84d53bea67c3e8be9a5cc9 +Msg = 80f20152d12b0a5993a2b17d1f55cfc0c078961ed00cd1c21db36d7a92c339691399eafca830621fdef232b06acd5d33108a5fc8c35a6d5b0eb2ff1bb2598c2d91c094a1ca91e4a5268a16f8b38c57a2aeef6de3a619f869df4ff7c5f5ca8f20c10e082a807719543215653f41ba45746350c855c170f85459315f62a13ecaaa +Mac = 109ebb4cb2ad746762b6652fc63b99019857ae89acfe9807648c3cfa151fed42 + +Count = 221 +Klen = 74 +Tlen = 32 +Key = c96c04a3bb0816fc47e05913a715fbac9a3ad09db75b48e8013d9f27bbe8532d7e63dbea88bf968f575602f377552e35987872a4e3155ddb8e5cef30aedd08504d4b2123bd7f3af62bbf +Msg = b11389c7dc20ffd0c4a5f887f2576bdc302c7d2af7089a012799c528fa7f2ce23bb10071b31c83d9e58d63e6fbd04670ff1aa6de4ea4dfe94a9986a35032fdb7ea1f44f2452a1202e517257e97ced627a7bcf06e5476c236819f73daad0d96722527fe527891d4d42c0ce658af97428890da04e1efc56c6f337534d7fb57209b +Mac = b53db6bf0c8317586ae6c1a1e2857f241bf55dddd1b423578c6949d4bf014611 + +Count = 222 +Klen = 74 +Tlen = 32 +Key = 9319838432ca096960e2196a06398134ea06e4e8799ba470c54f0512cabb9045f529b6c4e749b6e27626c11df4595bf5b47c04ffcbe218351485f49077405ad96a3f17bcb7b3e21e80ca +Msg = 57e1d3ff5fc4785f9370df2e5abf454579752ea934d2a9bab568d5aeb22ba43e4bc7df9f31366bb40d91ca822026e4e426cc088081732ef993ff7f676c571704a5b809278b50a3778108f4589fa18caa9f0283b3fad0bd594e406b950329d5242e5e5880b53aaa0eb57c66992055c4ffabc0a72ae712de42add2a321c0ca6808 +Mac = 4a34bd4dfeef7fa1dc739280f16a3fe1281a51311c10a920ab43d406d4ae3370 + +Count = 223 +Klen = 74 +Tlen = 32 +Key = 2914da23e86a603cda1eede153be2431c2947cdaeed6a1ea801d18e2c218220ca682e40f0a51c4c13a31163cb730f83437bb7a88ecc903160956f0d483137d1d145ce948866ad57f2eca +Msg = 6b8db9acdfd24150808a92368596557181d445e5a04e91112db2812b58035d72378d8bc00a1ef75ec373b81dc6f1f0a2ed96f302cf2eac8f42ca3df11e6ee678440a28b0dfab2a36eaf35bcbf3c759a71e47120f6c03292a3d6b9b111488a2259bead9a5e7e2a180fcf1c467947f59271cd0e8360035ce8b287fe2b3c3b95822 +Mac = 4de7bab7fe9a0a9bf7b51a7cdf7d929f2b1c6ff4575fd527baba1efdf4254890 + +Count = 224 +Klen = 74 +Tlen = 32 +Key = 4b7ab133efe99e02fc89a28409ee187d579e774f4cba6fc223e13504e3511bef8d4f638b9aca55d4a43b8fbd64cf9d74dcc8c9e8d52034898c70264ea911a3fd70813fa73b083371289b +Msg = 138efc832c64513d11b9873c6fd4d8a65dbf367092a826ddd587d141b401580b798c69025ad510cff05fcfbceb6cf0bb03201aaa32e423d5200925bddfadd418d8e30e18050eb4f0618eb9959d9f78c1157d4b3e02cd5961f138afd57459939917d9144c95d8e6a94c8f6d4eef3418c17b1ef0b46c2a7188305d9811dccb3d99 +Mac = 4f1ee7cb36c58803a8721d4ac8c4cf8cae5d8832392eed2a96dc59694252801b + +[L=48] + +Count = 0 +Klen = 50 +Tlen = 24 +Key = f16ad73790ca39c7f9856c4483202e7f8e0c8283c7d50d6da79cc07d3dc7b76c2ef76100fa3ae2df8083b5a1c5579628f1c8 +Msg = 9870007654ebc3d28f883bb832e0b31700f923d9c9b10168e0605971cfb920e848f1c64c5f240a2cf7f412ea7a73bbbfce432eff84fbb49e52cdcbf4c36679bd2d16e064e4311381adb528a0752c8e4443d4a12b6cfe7cd406b40e3f9e9e71f42e27764649db85d99913a4628bd5d5ae49f6a5e6e9810211e35d4ddac929b093 +Mac = 79e24a203bf42074e72c8b4a0222aface3e8ce7b4004cec2 + +Count = 1 +Klen = 50 +Tlen = 24 +Key = a5709ba5529cb9a1a227f0be448e119a356f92e13efc3463beaae46aa929df4ad1991a3964fbe161b6e5be34417a9c00eb9a +Msg = 4f569d60405663ffd4893777cbc37155d403e2b0f5485da42ca67503579889465198feca5eedcc39c9c53c45cb83f09daf5a2319341b3238334b5bcd8179c5f517cec14c70e6506133dee56712af6c2df2ba8a504ca427afd3632a1f57998360e9216f5040e8f75f5bffba4368eeedede54aa0bb058a43ef551668609fa1cb6f +Mac = 247eb51a397ba369ecba43b95a46a933cff0b1005714f0e5 + +Count = 2 +Klen = 50 +Tlen = 24 +Key = 187c047e4ed5490305225355fbb381682932245b01dae04df5e456723842ff66c8905bc1ac484ceb7a35bc321d2a8619d5f3 +Msg = 16263dd95036128119d781865e4f818a867b5066551e711f1179f616e41cfb7e82fb73130bc427093370fb43a01973c6940b776dcb1d53dea74202bc8a5bac1f834f6d412e5e587ad5b2bc6edb37a5855bada69b0cfcd6f968c719840d43a135634ab4c97fabafba47c54b6dd7541fad248a6658df6203589d31c2d5347de1a9 +Mac = 74118d1b4c60c9dd7029829e27987f40aa9fa54b7f9c0c00 + +Count = 3 +Klen = 50 +Tlen = 24 +Key = 07c64541d0cc4c2385dfc4e7f49da4396d2c4a8ddecec0583db63d7f261bef0fc68af730f780b654ac3847b490c24cfdea55 +Msg = f7457e98685564e3d36b5a9a2359394398ebeb2e0f1dd14d848b6245d52915c5c83481175069c3f50c74219d11abed28e9fcab17db24762f6d229f8728ec98df9b601033a37d6090e9d32627ab382fa0c0bd9bb0d6e13beeff043ee26c1e0d5f77b07313e7fb015d7071b15e7a69c9532416022287baea323f17878028263df0 +Mac = 22e16ea2a8a7377389f23f92e1b689555015f2a5f2e3c87d + +Count = 4 +Klen = 50 +Tlen = 24 +Key = 365b145e507e9752408829c69c8732da163514b3517aa61df331e474fc2fe5c456810d2facf6838f80dee55d78103bd2f932 +Msg = 637d2092a1f5620fa2ca9f65b1a722c9fe92307a9ed62f52d4410e9a8f90e0233328ca929c0720fc61f9cbb3550fee5f544dc9503ca3dd12391f5042466094a1f04e44675d084eda8e1e571ee1015b4fdab794cd22d39ed7d0a5d85ce8ae0d0d215654b7ece234d0b1a00c505c64b2c218385b9a5a50bbc9223c6d8f7e619490 +Mac = a016274a2e3202547be4f9a3830b2b8eec39dcdfd1a8ca7c + +Count = 5 +Klen = 50 +Tlen = 24 +Key = fd0bcb3f7ce9612ed98f7ef27f0908a8a40801197c415b3eac100e040161694c62d0a536030fc09fdc8889e85a44f7f9540c +Msg = 2efa4e54ad137e94bead8e127ffa33bbf778461a572422297feb4e67c4615c2af1b510378be5c5905a2e0d8d24c7982ebcce57b03c83e05e8eb415aa3178007c392002ca986b2d699df9ee23ba02ef098a483b0a124aa4c548bb629cd132fc0a0f236c365b0e7ec88ff679fbc81501f36ace3c5264e33406b5e87c642ff8177b +Mac = b5d46ee32b82629b49bc47f258cfd578adb86c49966bc91d + +Count = 6 +Klen = 50 +Tlen = 24 +Key = a8de6c601fbd3de3f36fe7e71a99c8648108cba90ca38df0d89ebe34c3f1c9472e09b71f01bd5070f0838481fde40a383e2d +Msg = e710f78f8a4159c802b3b5df8612177aafe301e62c68bd14b8c3f2e2495d769c8a8963c38c656d0db80172ac09c453d3780b0377b712dd5321183b2ef2be4460b3b10593f988c4c74ff0909971061dc4bb04cfe8e020158adfb1f85c3394f4bf4ace0687397206feaec6372b26a11d5460178ec111580cc3d9d652f576a62dc2 +Mac = b087712d244c70b4686f3bf30db4460adf065df56d874a5b + +Count = 7 +Klen = 50 +Tlen = 24 +Key = 01e5be580aa049c2eae411e93600fbb0921b6296d1c85ce85edb3e36da7a6203067727c0e4dd3afc19c814d5967ac4b277ac +Msg = dcd732ac494218c4e5025da961535c1519716fd24601bd3575ac53e9380d77ed1bcd38e0d90c4a7dd0031162b3e8fc157f121448b05ed55cb4d13c25a07f21ed22abc7bbb62fb2d51d1fb8830ca95b16213f56291af976274934ab0d43805f71d9b906c44973f7d4b59b7a94d35c2220e7405dfcee98499c1c1dc92a89d7d983 +Mac = b0521d21418f6eceaef21f17918a8d95050e2ff17874f7bd + +Count = 8 +Klen = 50 +Tlen = 24 +Key = 0e9d0054cf2c1ce99b66cfeb80352db2c7ca6f201b353cd5ed3228a116467b3fbe0b33407dc84c45c1453e7170dec81eced5 +Msg = 96ab1d64acad8cf69651c13e4eb42d7382e38019f3a927771ba6134c12a1bdbeb2206793fa35a4a3b09a1a8d4a0087aa0fa5023f7a2584f7df92a69050c6acd4c2f8c3cb6c8e872f7032c820bd288e1934df5a230ac6af486d60d14b6a9bcd960e5eb974cb613d801e41535e6fd44aa839ba112b6a34b2540d391de526c727ec +Mac = 1f5f98a2e9901f755dce5ab0e9e485e3a53c87d7621e7fad + +Count = 9 +Klen = 50 +Tlen = 24 +Key = f755ecfe7773f5fe6a044b27ac3ed6108ffe98092ec69845fe011f3fa68f2756117d11bac114968c66160041af449a486023 +Msg = fea931efe3ebd8f719a6d9a15487b9ad67eafedf15559ca42445b0f9b42e7089cfbd62154160cd19aa086eadd12e6ba93b148d0cfd4da99fce7f5fd5606807f6f11fe97c1d9cacbef67b12cb56fde2997450255fb610943fc60d5228e84fd7fb8b572cec1da85e2c24862dc58bfe04c539262e9ee9a646cd3577efbaf3ebc6df +Mac = 6f08776f8d86fadaf681c32a4f7b7cf639a7cdb5f8dd836c + +Count = 10 +Klen = 50 +Tlen = 24 +Key = 79c92036d1d9e350978b077b993ffab6e59f4ba997281a44efe6cea4a77e06368372d11e29a121da330d7d2283e1f713d6b3 +Msg = a62bf0d3ffaff7484b0f493517357cee3635a444097fbd57fe5849ab578b397e2d5b1159b4bd48e6c0c4ed01885d9111aa3c60997016910a521101dcbc791adc11b4fac8ef78d119b53b8b2042ebb05400e088eb220f82a72980d6f3ad026a2e5a1df34739485c8a305c6bb9cd49a25f3f076361a5d058d68c8d1218b28ef01b +Mac = 6d8915109cd5240f4c1e44c5b303aa1b9616f3a256742143 + +Count = 11 +Klen = 50 +Tlen = 24 +Key = 314c2ab1ad359b1f606372aeafbecd98415c39c6a89874874364788862e0b401ac2b9d2cbe7865fb15650a0a2e8993d3eb4c +Msg = 557e8462a2446b408f2ceb5e9ff9c546c91bc072298cfc57f6f883a2b42021c1ab8076a5972f49c6a1081f688e070c1d37f5ca8c39480870ed4504e49b675cddea0422f89b2e2e7677d8b884863926c0827622fa8b7bf0371c29fefc3eb7bdc9fc52b0e31607c356fae3dd3bef59b83794e3f14489ec5bb46cee997307d8ec8c +Mac = e30f9c9e38b08f587b79c8a64ba5e928eb6743329055ca79 + +Count = 12 +Klen = 50 +Tlen = 24 +Key = 865aa6d8aedb7a9de1fc289b0d42361204891e652deba11e79e35f3199b2a5856f0286b0c2ca2d03357171c67a36aac4c3cf +Msg = c59f8dc2db55c453c403bf91bc44bf882f27a76329d40a320e7389ea8b495cadcc242e4cf0fa2e0bbacd63a489d13f8e8ad1787e2ccf132fd4ebc25fd3866f1a95a6193a1a9cdf2faae55afcc54f30825a5ce60139ebf6dcc915229cfe56073886edf5944385fe47fe144da15a04baed06919bf33772dcc156bb52abf5024c91 +Mac = 1e4f3de118bc66b4f15e878655d902d51d3ddec17b5b6886 + +Count = 13 +Klen = 50 +Tlen = 24 +Key = c64a74849e9c2f805d89325b5f0472c6e36ba91d2514a199c72aafc775b77d39c9010d7b6c1afb487fb303fe3931c250d103 +Msg = a87050f3761f3d88e5823f3dd3d1439fa7aafddde157222df650d86c5a006b04decc41133c5210caf0ee4e134a83e976c278393d8b0033d66b9fdf7ac9ea0c0c088e42441393f80c39e2072a3c055f20a42ff850597c0c64717984ed47e7b04acdbc3acc236b5d18686552ccd0e00b65f6d724607452179fb2e7af0ffb81bf88 +Mac = c26a8cbc47f328376fb6a315206ffa5b0afc8ef2e7c007e3 + +Count = 14 +Klen = 50 +Tlen = 24 +Key = 4ebc24048c2d89ecd39db53ab1e85ce317d28cd118b08e35ee650d1f3e90794c9d04ae3e5279d1925d817b8fb9bd1afbdf50 +Msg = acaae447da1dd1ebf0167788ab6c1fd2428a58b14ac4f539d7eb55dce51ee7def6e4ec0afc787fa47864d39ee451bd0e4f1e72e0472f91c8fb08647ba11a631f16dcf900c41e8b84c99bb76156cdd90d5405d4774eba0ff48b21bd7c7aff621654bc9291fcb8fc752ae2a839c8867db69c6606dc280d76a4ce60e9453876ecab +Mac = 05a0fc70e839f7697d8e9a2ca10939bf56c38ed77bd9b606 + +Count = 15 +Klen = 50 +Tlen = 32 +Key = c2f2f7985728b677a7ad062dd9605a2c24e7cdfa86986f35b99adcd4634714af8dd5864256366eade83c6100ac0126b6ba86 +Msg = 35af2ea167e56c8421cdab1b9fc99be4b85f74c706d43a4947fc3f020350e9517041b54e92cc7c00a64ff6d1c19b7c3eb54a12d33453a45738db9044a14e657a20afea33552c633a34f60f58ad4ff50f8ce5e18b9e5ea9d61534b44b2dc3bd4d10a0d539f72da798936a009aab0e8fc006d7e9d88b1ecf2ea7aeb401efd67a34 +Mac = 6e49e4aa01da45cc5ffb71569f257ecf114fe858ba9590afc23afac9c0d67f52 + +Count = 16 +Klen = 50 +Tlen = 32 +Key = 8f239b06fc6678be26307dc702f854f6a3d0d980f6457304af87a5cc83cae05098eb9cfb3a57a732cf29bc930d92577a6a7e +Msg = 35b127b52a9b4aece978ad17aaa700b547b17eab59da27819ef650ce9f7e5ef18fe3cf0275227a098e99176dec1901af643c3b57a7f9b12faf75c1b05d1cfaba60f12488582280e23be05194f86d9a205b772ab031a4d64eac6e06570931732d6f822e2d1bc3e5e1baf4627616cc5470f509529c3e041d465e8825adeae44fb4 +Mac = 4a13783650cb96aa0dcb4bca10ec30ee2a9d3768f2b6f1dc626f99545efdefe6 + +Count = 17 +Klen = 50 +Tlen = 32 +Key = 299b37b8a63c49e53a6d2d174a9203028626b1ffb564ce5eb547bffebdb51f1ce6f76569ea6dc05f2b8046d4f7d74ed00ace +Msg = 8c886d5c25bb1ac4e1e8ac0c59da0d7f746418a47652b7cb39a048e6b9ea469ad7242596568b7d242adb6bfdf2c33562c3962c682743d79465874da70361e3bb8ac7078f89976c20dcd068792e029acbbd03cfc05de4260dc0237347f422e2f72dd8ddf0c5c72fe0812e6926167f84e3ec13c954211dee5fd1dd826b95168b75 +Mac = a38e187371f1d2517aa4639975e1d2115c288d22968459019f8c7f8623254268 + +Count = 18 +Klen = 50 +Tlen = 32 +Key = 136933635a4f9252a65ecdb0a266fe7a68e935d597db26f5a6a61e3d78713ca830a2dd6746a158ccdbdfec664918f66effd5 +Msg = 1cd86dbe49225fc2f82758f53dfa3696ef66a7645dd284a93d686177e5776232be15504ef508eb5a73e7823e107cc2c1036dcc4e9d1b8af738cb42ba6a046b037e37c07324a694e0677e659de046b3fb297d120f957f7fb61ea9f0d79fbd2fe84488e7b43ec2ff5bbb35289a1522b24c49e0a431acc60befd94b9256ee6c53e8 +Mac = 3e92717865123dcbc7be18c72522aad889c29dd2afa16d30f0ad68cd9640bc84 + +Count = 19 +Klen = 50 +Tlen = 32 +Key = ade0cf1adfd3a4d83465721f9002c9cfa1ad70220794aae3b9e8b9dba4eba18d954b2e2358ae38a7228e26762c47b1f2a16e +Msg = 97362855760a948f87da5dcf39a888d0f194c75000ff045bd2ef3ecb67b5941007ce9f2d32080503d7e54bd2c644ebfd663ea70dab4f1cf943b69aa5101e33a8db7d1252473d0fee039a8044444b51627364579c227be1d2450990f19f1469bc7a0b29cd9bf2d8d675bea12d9d03e1887ecc7e054eca7a6d41b2c8b9fce05ed5 +Mac = 2eb416c1063b6da59838f3a6077eecbde42e4cf3d0f36723122e2d8794128703 + +Count = 20 +Klen = 50 +Tlen = 32 +Key = 5ff06d199ea158a07130d2ff2ead78eefcb74313354a0b790fd9493f7c9d218d4e2ca0cc9f4d4217700bb7ec9008e628c014 +Msg = 51555f744e6369f81b30a4a0514486df254f1279e0c7f1438fd3c32afb68b777dbb1595249b5ac847334798193d1e6a521774abe46f540cb95ebfb03f6ead919e2d73abfd690926901d2bd53405b93c54d4bbd9634d0c7ef06027551d00c5bd9ce8da8c3dd3e432e2fd4191e4228b5c7139511098fa1ab374ae0dc1c73166540 +Mac = 3e8de7498a8cbd9df8dc3f5dd825b0ee0899e226cd4c7cce1d3399ab9c558fa7 + +Count = 21 +Klen = 50 +Tlen = 32 +Key = 7a136c9d47c743887b92ebb6c5792769b0e8868dcb479ceb07cf93a0609ce3cdbf035d911f256e34efc4a2a5b85667270058 +Msg = 402aaa22c009335112abbda48e20e9c4828a1c131976839d816d544c4cc5575b17bda60c6acab19ee02b847988c34dad8a28189a0ef8def0596cbedb392f8a77a470858a9c366b7255f3b25c9a5d10b76d793de9eef8fa407ec7522b23e220aa2e69d1031cf56bb7bb2cceb48e933bcc71a412668021e07336a798a4d28621da +Mac = c0a992be294eb3414e4603e213de66b4ba8af1f10c602cc126b1a5a63ca008e3 + +Count = 22 +Klen = 50 +Tlen = 32 +Key = a03fe1eda0f4dceb1f517f17963538fcf913c03ded53f01e36f5d6466e7808c4fdfa384f45a009d21d382128811d7f23875b +Msg = a2350856c94b669d115dad9213f54fb0effe9adc86298cebe990e865109a8988d01ef79007cb38361ac7e977a1968d96603e24647aa800bfe14ad45911030ebbfe4666894a7bb707bca20edcee3a01164561436f263c75ce67993e1104d39d0a14f67ec7fb248c17e038474962a8563786b01e84f4ad932164c74e1653d2e17f +Mac = 0d0767dad7dbafd8174d1a007e1942af5a5c4e1fe7f85c092b446ba078ccc7a0 + +Count = 23 +Klen = 50 +Tlen = 32 +Key = 02c1ef58b09ceafe3bc94298c175bee5d875307c8b369d60a0f79ed41d3506710a67c57577ec0d5ec142b3b81278d73327e6 +Msg = b25347513090a731d128b0deb2109986d4948a7dd03ef53dc6f92aac9776269d54cfac98f66a98de4f216fa8409f3ab02d0d95f2aeef03b4874884c4db056a019c98681c46e4eca0cd59ae30d36089101ff98be84ba248c4bc7c735ed8a9afa072f8a26589c44b80331996ffd4192eb1939e93e50f216c754ddb1e03f6299d83 +Mac = a4063a744763458ca4d03ae156394a0443967b2c4df3bf111be045e06be7322d + +Count = 24 +Klen = 50 +Tlen = 32 +Key = 177470b4f10e6e95f548296d9b0fe73192a3ffb0faf6a71cd45507c6b7499229c4c0952adc68109e105cc60d580290b58833 +Msg = e9168c659c63b6f40523c90532bae743f24feb2e94814b6df2554365af73300abc933af5213235b8fa89c96ebfbfd196c95e02211204cdc93d5b86a5d64ac5fada6d0d557ac3abd61ca7e1cfa302448ef0be6376a87ea955388c85f11712c7e44b8e4eaa2f80e0f97365595064e908d36e595656df57a8b8edd18772fb34ff6f +Mac = 2b9910ed9f3f57180605b15f33e95d4ef40b09ee7ef7e71340cc4449c35ed86a + +Count = 25 +Klen = 50 +Tlen = 32 +Key = be7a9fd43c1e987ad10b0ca6f3ecd067c961d286489759b89c1b8d17c9f039d392dfd0259a0eae85c9d4a11df1cca87db128 +Msg = 7222bc21c60c8b4cc2e4e3e746964a70a7b95440b079c519e6d4f6fe100a7a47f74e00f46bc27b4286a2817c35bff114f330d9f2d844970cd3bb3e3734353b3c6dea382f199c40fc3dca2443ce271e66744ab5e08ea7e0d876be6ef50692a5755b5d2a79d88221a36ec394e31bb4198eb16fafb1d98aeaa4574650e290090217 +Mac = 15f3f5e9d459d1cfdec6f183d162ad32bc93864ac7a5ad9c40d8efb11e327619 + +Count = 26 +Klen = 50 +Tlen = 32 +Key = d7d2dbbe4f6574402121e53a88295b7a2e4cf2f342ce70aacb6b33d33c996836480e7ed8f782dad8fab6cd973cb5c31bb959 +Msg = a927bfb3d1f4c0b20fcbca263af59047bdfffca8ecbd215e988d7264e0e0313e4bf72add14eba0c3c5f0886707daf5dbb9e1d4ac3fa1d90a1d65b928c4a49ae6abccc7aea23fa99b649bf3e16b3f1c69080b12bbb2662d219f86610991ecb9acf32d00ed24f8c1841355735b0c2bed38d105209ded1504ed457ad3cff0be76d7 +Mac = 43f9dac7fb0f505ae19400b4c74ec21e352bf907a14f9927a0e78cd5ada3b5ed + +Count = 27 +Klen = 50 +Tlen = 32 +Key = a60727ae52ecf7fe66e99a8aa3c58879ebf141da5e1792dbc2f5143c286cf703ccd4fd703e93c933bfee5addee1fd395a4a7 +Msg = 8cd3b3e412bada22812f7b81dcf7d6937bdc21085ead7bd1c2872185f253e4036090db59f45355e4a48b11b9458ab244a0c16d2fc9cb0585acaef918e95dfc20e281a5241178681ea09ec5da33ccbf9f091f901143fb9b56834fa278b91a390a3a2e7a0f1334fb179cf0fdab50c6e6ebdb7df2767544258a6ff2846d0b92840b +Mac = 9da04e2dfcccd9db25c9f8566879c0aefedf0bf7a934fdb8ff7b8fdbb0568a04 + +Count = 28 +Klen = 50 +Tlen = 32 +Key = 73adc132087af20b6ead6ab3886c412f52986af87109e45b0f1b3420e569126a99d863de4bd867076be634f9cd556335ff4f +Msg = 5bbeb367c6a6bb49682556772657bb9817c9d33e953cf0c894a6bc87337a701f91294630e2e93036c2b5caaec8958d7b5f1f4687d13ec7ada532ddd72bd88263552c53ccc80c4486333f9229e0b5f9d2891028c66c647259a13bc60facdde1004fcec281a2975e0065c99630944066673ca55f448e36579431ca5f76dd0ff5be +Mac = 12153d31c6c4b874095ac70bdae80b01528d86aa64cdb7ec9a169e5dac2eb0c7 + +Count = 29 +Klen = 50 +Tlen = 32 +Key = 6dfd83804a57e35a1247807a0c828e54b32eea5f72960169ac23ee2dff88e227ca3cc9a7ec2d2a25cfb34fd4a6c2a779f265 +Msg = 0e9913001b537f335e3cf67ac5918f20c01ac83a5eb8cbdeb33ef0907c8182fd06b3c6ec4bec39715e0a1a630abb2811b6d8ad318cf5bb19db36b632b96412a9ec3f5e670b168244e096457711e01251ffdefb2cefd6fe9e683f87f2dbd437d88ae8e45ba2f9e114aa877f9d2126d34963d3ba12cd841bd321036cb82cfb78f2 +Mac = cf51592da0cc19c255abda08e6f460e011556f73b5ac0add69dc46e8ce644fb1 + +Count = 30 +Klen = 50 +Tlen = 40 +Key = 1ce7e20abbdcd1154d4b536714ff534a01b8e88c78da34d653638c39291fd80ad01f3df02067fa3bfae7907789ad2641c858 +Msg = 7cd750b5c9b2bbc3ee955a4f4fa7c956846c8b1b52eaa06fd90a5a300e426c106c714497e70a9b6c22754ad0e1b25f6bc140704b273d2f2a76ce3fef85c1467850714497edea235ac24e8f90f678078825de341c58bc7aee346fcef2711ec72d8ea0f7bcc39a7b1738e8d197743fea3618108097cdafaa467bb4ae40bca216b6 +Mac = 729a167f1986cac53ff3e111ff82f2a77b573d0863e1a3aeaf00041a03e1430188a202bdb7e9bfd4 + +Count = 31 +Klen = 50 +Tlen = 40 +Key = 362bc440e5dac16a4369581c0cb5be45bf4f170847873d6cdbc9bd55232d23b39c4978f93d4a08d15b43690dcac4b8e145af +Msg = 1af3aedaa8fac55157f30642a00258102dbd482198e0f13476411ff59406b4ce80154a014bcc19f48ef31bcbabee6f3c5537fc9f530c56458065e50b1729442f2da1e7627f2d011e6e36a43948632abbc910d5ede2fcb2b2b841c31af08a5c352a80ce25cb85437700a5e9b400c95332912e1c30cd16cd2226be004aa88fc688 +Mac = 6467e5a690bd32e157cf8ce674ac630b74ce32a78e8f78415346c00c3060a4a26c40c3e2eabd80a7 + +Count = 32 +Klen = 50 +Tlen = 40 +Key = 91a8c08f4f34073913e540eb276bacf07d7e6fecf317f2b8d5e1866da3ea4abf159f4e8d5df7f8b5aceea72df7359750fb28 +Msg = 6e0bf8d8716cd86b5b00652a308be299715df023eed305bcdc201bc5274da5300a7fc7e4dc79c6632d61beaa11c79359bce329134f1ed828f2d51a712359877c4d3a04e99dc5371411cb3ef5d2a4a044c37483e05aad2071afd5754cd28a399862c315af5b5811c730c54dd21a2bf1a3af976651b687c7e03aaa921edde8a4cc +Mac = bad0de1a7ab01eb36a28a67d0a9488a873a82770d5a8c30e4253e04af51c31bb131da8aab4ecde2a + +Count = 33 +Klen = 50 +Tlen = 40 +Key = 31d63a82fe80439196ad230542cf8c9474deb07b00b20f0b88b08e6538a8ca82b4feab764f083cf57eb8ba168c7beb578f60 +Msg = 4e9d424c31a7441f6d16d41caafc861ab8fe3c002d66ec7d5073a3f936f3cacb2b14a9ac5478296b9287dee3a809442ba1f4490c6c820cb8ca87e5b86a02a52751f21f1e806be76fd1e8599623e3ddecb6a36a1ed85649dec25f1cd8bdf11ee889ddac8afea80592f4e14e1d61b1d9c7c1b4a61ebb072a5701a3504078e9be76 +Mac = 00da1f3b95139c23cf91730b5aacadb0b6c492a6b08765ca7949c315a792d86bef38e7a747486cb1 + +Count = 34 +Klen = 50 +Tlen = 40 +Key = 917a698c82f44f19573b645c4879b8730b58dff4edc6a0d321f5f18658a5246692a55b59339741ae59f5fc486d515dfff8e1 +Msg = f51086fe78150fe48bd1415a4785acc05ab80ef00b2975ce7807a4212264b8a1ace80b50e0c2590ef3e421680a704eb2fc6d17555abf2469ad56f287fea578d89c560b72193c7fe596898f1040417e3a1beeff5eff9653c5e0eab1da52c0ea3b4bc34d0c2b69c890fb2651faf2e084803ea28eb20194490a992ba8c4249d56ef +Mac = 77bf5615ec52f706ca746401e9fde43f15605237e550b93a8472fd144fc39e5eca0fe890838828a0 + +Count = 35 +Klen = 50 +Tlen = 40 +Key = e3edb229240030c44ecc34c855c176d8db48d138a7615390538a90ec44e43b06e091f7c8fa606a0d91ac93a8bb815ea7dc01 +Msg = 5e56f4bdea787d8e6f434fc114d2647b3f86ed3458b33c0ad198e05b639512929a98504193d9477105c7f6367e411186ef0aa34a6b77f8b62c6bbad6d7855a6a0098b1f4f15ce80fa76395021e4e2695cf4083247693eff118ca2fbe45c7ef9c9b3f61fe8b6a271160ff73507c5f6d53e510d5e7016ee9649e9d893b35c299cf +Mac = 12aadfa5bcf4e356330c99c65edd086745e113f1f05569d9ea699db349fb3e6be2199a7007ad71bf + +Count = 36 +Klen = 50 +Tlen = 40 +Key = d5728055ceaca4b0a0c7dea23024dbac4a735c2240c9f2ded4f2053558081b2a144457e2e8154058336fc552f3667d942dfb +Msg = 96bb91b01e68ff49eb74bbaf26b94a269436c1410eb1d7a431a03e0d564a3496c42a55342594b384379b28c7c431eb2ad490624c21d937facbfbae3d4dd73696b0a23e88ff8a4957fa9c45100ee518c985d77d2afbef0e2c1195a1216544d8f5c1eaf4b39292ea4a9c40b992ed1cfa8a0fd3b9e4823b83c36936c0c384d8443a +Mac = 798429b7121b0f1de65c702bba78f51c142b483f96a4dcf12a95686074c1dbcd7d2ec6dfa1359baf + +Count = 37 +Klen = 50 +Tlen = 40 +Key = f54e582e3ffed931e05f2b20a599218fa201118f76473480d1f04f2733079301f610c2d68e3e949010e6594ef132dfb5101a +Msg = f5d2c18fc109854abfc47f1f39acff2f9b116e4f3594315d3d23d1d5132b599fc908002be3c108c05bf2e611e909a31281b582091c9ce3e8bb4d67daa975551c01553d0e7173db8a3d903d7487db2892cd64b99eb3d3489a035a9164f2e8168aa5a0bf5ff389c44f6d87cc6f9b8a57588905593682a2271c1c34979b75ec6392 +Mac = adeb260f3a38f1bcd2d85f03cf87ecfd4c8a6aa1820e132e87443a24f5a3f8d87124236cde9dacda + +Count = 38 +Klen = 50 +Tlen = 40 +Key = 6d2dd39eb5fbb9410e6652259c5402ea0a14e70a7b896a1ac48b144cd88aa43983745edd5cd9a5e3f54ecc23540f2a6aa7e8 +Msg = 5820928f8ee262201abd8da3c07a8f38734a9dcbbea22f8b6249bc9d41b0c4117a811415d67a4668637c87125edf9d53560928d98f3f2735a5babf9071fe389a306749c4e20595aff1aa75e41340f8c5716028c409218fd2512efa1a1d1c7df0c2fab7047c2957dc0d6edf81a745a9780c7827f3f4f16e49afccf6a40bb19bf9 +Mac = f59fcfb65dc73bc3d07118f5a5d7d0c2b6b0f61e3f21916f53d5cd6a56307fc1f1f8c5f8349a3b19 + +Count = 39 +Klen = 50 +Tlen = 40 +Key = 32c0e6b478d33958fb40580bf369ec64e7c853d7d187e9e47d4a878e32504a0f94ba96cac92a5a81db9095c85d4119b9524a +Msg = 1b5cddfa796d6956a181cb9bd2295c8b57d9d2d4b64a15932b1c4e1754c040e72e95db0640510e7516a3defaf117b520bd39fc7f43fdeb3da05ea0d5f6466f1761ae7a712d06816c46d7fb79efa765eeb71dda4ca965e4c3c4d692f8abd2ca059deee1c1a653694317654aa135a215fd2ecc94c3514aa62c7dcc4907da2ef9b8 +Mac = cfebe44a614233360911ff1c0089a94ddb4beb91e81209f71419639957984f13ebb123c6e16010fb + +Count = 40 +Klen = 50 +Tlen = 40 +Key = c83ac14c3aefc2264e0ca5120e806a9d226499bef58c850c135cd22dd6dd359241107b612c83cdb3a1213200874e55d77d34 +Msg = f03c802de9dc4148c3109b96fe2d1fbac6788ebc10e991f4e62eaa2afff36bfb9361e67e6de4642842325aed418998a8eb37c4bd256007fd8cfc06ca081f147ba47da5029d2d06cbb8ad4ce8d9278b6cd2f24814795c302dfda70ab17a51eab4ca99a7fe9f3e90face8a5bcfee8f5ecc22b102093364744be2379d297c12556d +Mac = e24da31c2549ec584487da6a78d8ab43ceb65b013ddd5a503fdc58dfd5eab0333a4c8c15ea50684e + +Count = 41 +Klen = 50 +Tlen = 40 +Key = 4669d93298c70519df3a12fb618216a77b15f57ce65ccc36391e9007af3df2ea2ba086347970256bd787905cb4255568b7e5 +Msg = b63cafb63001021837a13e46410ca942d4f92b2341cda5148ebe849fb438962c0b7f1cc40297201b136109cef6066ce9159825ac41f7a78fa3f29083f5af817bf24d2c2b0ac7ae0f5b1c20b0ddad6823dce655d2ac20ec7f98c6fc851bb7f96153ec0672b25b54fdf71bab745cc846f81129e41cea101cec5582f12e8e18a6e7 +Mac = 53dbb4f115e1cb292440d84d583ae02cf07de44b481f65438a95a14b72a3413cf5763b86277adaf2 + +Count = 42 +Klen = 50 +Tlen = 40 +Key = 27a50a6ef6f71e5903a0ead724b587afcc69a6e1d1c973f173aac0839bdf5f2860afcf78cf861c61ecea00bef4b14e2be571 +Msg = 4e9a4f18f6e00790ea2ce7e6473b84e8ed7d649b2524bde5887b7e8a1c7a935abf9765a8c9dea1fded443b0e6039b2ec3d7c957b29334625333bfecffdbd110c21027491ce887ceab255e86b1d8b2268633dc2a98281541804c65bbd276896ec3c8281bd4d041fbd0205f7e3c55a5cc62567f20c78356e26c5c59d3be1a4a861 +Mac = 8c00cd98e39787a5c91d20777f1a8bb4f0bab8ed8a3a1698805dd52ff01420459da0011ac4d1781c + +Count = 43 +Klen = 50 +Tlen = 40 +Key = a6990c41a94ef7a358fcf1e05dfd02b41193730f33cb2719e0a72f73bf7b98c07d9887657928898cc059246f3bbeb2d327f2 +Msg = 753e66d2913bb74a2d9b3b112223b6ab7217682781a2e3a482771b142fb9bc40bd19c00d0f3e40fd2a698af8e959754df16cf1f4e808e216e2392fce1c9b1532ed7bc28df9391fefa8f0ede8d7591390cded36ca704a8bcab8d8e9d565ac2348edad94dcb9f5fb28907a8a6854ed397cece26034813285caed9d72b070b48b8c +Mac = 2d36562d9dacf9fe8cda55ee2099e2e9c18b8c02dae8a235aedc4748d68d4563e0d93c420e2eef01 + +Count = 44 +Klen = 50 +Tlen = 40 +Key = 038bb8d2cf699af839d597806b2247edec8c830771c1d580f7a02ed70e40d77d7834aa37f20d82c35221f0bed28b30c5ac73 +Msg = 32947d045f6c1dee7dc055edcf1a957a7c536ac488b109f603532cb880cf1cf8c9190fead1a7b54dead20ef138807e766600235697356626a0f7d01874b620c5df609a297885a1efd1ba88eff03ba6f603d4a8c54f012b5c6a548b78aa17f55add33c4ca3a500a5c983e6cf2de933482bb96a119975c8120c93102df0a3ac63f +Mac = 16f50fcc2e87a8d525c4402d45146e2dac1f9e9bb4725aaf90c7df008437e7411974e15b169d599e + +Count = 45 +Klen = 50 +Tlen = 48 +Key = 5eab0dfa27311260d7bddcf77112b23d8b42eb7a5d72a5a318e1ba7e7927f0079dbb701317b87a3340e156dbcee28ec3a8d9 +Msg = f41380123ccbec4c527b425652641191e90a17d45e2f6206cf01b5edbe932d41cc8a2405c3195617da2f420535eed422ac6040d9cd65314224f023f3ba730d19db9844c71c329c8d9d73d04d8c5f244aea80488292dc803e772402e72d2e9f1baba5a6004f0006d822b0b2d65e9e4a302dd4f776b47a972250051a701fab2b70 +Mac = 7cf5a06156ad3de5405a5d261de90275f9bb36de45667f84d08fbcb308ca8f53a419b07deab3b5f8ea231c5b036f8875 + +Count = 46 +Klen = 50 +Tlen = 48 +Key = f86902e5e5db478ec6e278692728a812c4cd8745f90a7d9f7915f5a94345fc12d2770a3c94b01ffb9e0412999eb6261d11a0 +Msg = e0bcacbe96dad6f60e51129f35acd03e12276a91fa13fc15037c75cabb0aee3a19253bb8b35cc0e63208867a032c8f4150a066642f6ff9ea197dab7e9d6da67255c16e051a43bce174a489e85464693006f11a4c61135dce4187040937eb4d1c7eda6e2c315771f0bc6f4273911a07151c63afd3f8c8cec963e4a8f5ef4b8b3e +Mac = 4bb4eb2db2cc921b159b78a2bb9edc1608bb2a1ca9873b411ae30a63386e462f9f69d9f5fc838ff1818748aab74da94f + +Count = 47 +Klen = 50 +Tlen = 48 +Key = 0d729c7e630560f8e8dbeb745e021f1fcab754bf6c8af0f4f4bc37bdf3ec653f90f2fac27c0c56fd2838859335e05cdd2cbc +Msg = 009b71ebbb05a82c8c13388f65c4b3b57164c5e5ed0eafae3970f7ce2fce5e53b34913008b6226f272ba3f84671b906f4bbc0836abc1cac1db02dd47440d2572fe6e92bea22e97235999def339443a05d24fdd1303e8cb6113108e9ffca22b110a9156eda571e2056b397ba5834797bf2da4aa459d8a99d70923729e01945a78 +Mac = a7d1b0081f4884bfa7b30903251fa2803d96822a2160772a473568d41ed3adc77c1b4950a22a14ef5b335a2842046cf2 + +Count = 48 +Klen = 50 +Tlen = 48 +Key = 5405e1f28569138976b03675efcb88ce373e92c84080fe381ea0a853bd2ef8b8d4596eb115557eb5a7009f32d5c49f8a08bf +Msg = 3a7f4dfecb333e44f0258d33d69ceff70ac07e948f5c6acd2ee3ec450db17ce48394447c2b8bd4ac37cd1705070d866cfbfd9bbf851189bc82852a1ecaa13908053cc1a7c17fd514c2eb8277999d027279d132bd45a6470ded21bc3bfb738ea2697facc9b697a9423986b5d1b4d4cbd12c452cd4f8a30b8a19bd8ae4c9b0e578 +Mac = 6cb9ff908bb72c45f49da3f4a8c5265983c1f4d811dfc098cc3ffa58aa6a6d0ba18183455cee62992b4c3a6cb53c5c16 + +Count = 49 +Klen = 50 +Tlen = 48 +Key = 6c075056122218f595bb28753e87ae6334a0adc24336e85bdb8202545cfce30490ce5e067988108c4e158bf6c0eeb4a4818d +Msg = 0b9b52ec0e46793a179589513f117a956fcf98717339373f5010a268d8b254cc7b996b6460255925b59bdd28436d320945bc868d7a1bad87799617fc45f3ff852137e6f5a56c403c12a26d8be334eab9a44cc9e607a95e5e35a03cbf6261605fa47cabe805a49645d7b221c247ed0c6e35884ac4436cb38b2c38f9fb5886dd21 +Mac = 58c6f879aa6ee523dc374a01e541f02f4c3dffb948b071468d2b242bbd358d8614aa7fad660348e61828cea1b758b91e + +Count = 50 +Klen = 50 +Tlen = 48 +Key = d137f3e6cc4af28554beb03ba7a97e60c9d3959cd3bb08068edbf68d402d0498c6ee0ae9e3a20dc7d8586e5c352f605cee19 +Msg = 64a884670d1c1dff555483dcd3da305dfba54bdc4d817c33ccb8fe7eb2ebf623624103109ec41644fa078491900c59a0f666f0356d9bc0b45bcc79e5fc9850f4543d96bc68009044add0838ac1260e80592fbc557b2ddaf5ed1b86d3ed8f09e622e567f1d39a340857f6a850cceef6060c48dac3dd0071fe68eb4ed2ed9aca01 +Mac = c550fa53514da34f15e7f98ea87226ab6896cdfae25d3ec2335839f755cdc9a4992092e70b7e5bd422784380b6396cf5 + +Count = 51 +Klen = 50 +Tlen = 48 +Key = 5f76d094bd102281900a1c1973a1d7a6da880c85f8382022e0885d24ea7d83e458637f24391c7afe8eb9151aac47f324e1eb +Msg = 07b2eb870ed51f53b01cfbe9b01469d96f69f7cc03aa8768884b4774bbf0e43dc5e9fb3854f8d1e8f05b43028d0600d05c31f5d3e71209ac5dec0b3d2a48e80bcb8222e6e1887dcd84dffc0cd9e70ba7e75ffefba62bbaa35955b2991e53169dc48846dbdc0d8dc813b00c4dbf3df427b7fdf98e687d0314259026d1bf97d4bd +Mac = 9891feb5bae6e7f517783322943d7074275f405e54412f3f27ab11f5fdfb57bb54067852789b55dd21107c11a809836e + +Count = 52 +Klen = 50 +Tlen = 48 +Key = e339f1caaf630eea2e88fa5989bec005c780464f935d2e6140edfbc20a0975279f3b4e8dde740584defd0bce32b025286b68 +Msg = edd19cc1f4e6185c362787bf3cc3e93a2a21990c4f2380cbf9ad88068e615328d8ad2e9fa108403e807807e0f258064fac58b76430c5c76f9f0b82d8ce788d079b42d38282ccc1556b25b6b7c6d1b5eadacd5e635acd1c2b3ac89f85c0b68dd1de9974b0bfba0469a0357b8ce1b760d55c877452f5c3e6c872edc6548ea6bc4e +Mac = af65cf67f4b82a1f1ef5ff3c7b99266daff3e134059f5ff26261fbfd6114f13d69c1cf1195b93cc9814255ca9a3e9267 + +Count = 53 +Klen = 50 +Tlen = 48 +Key = fa0f033f3293389e5a9312c6046757eee20fda34e4c8b4d8a1ddd2a8f8c0b0bbf7596362fb9edd5c19646d49bd74856191e2 +Msg = ab6d18f2c0756519657eab694e73f35969a324c279d0c994008214c863a12395494383e744c3f30db3136ab1e7535b0e84a2375d2a34349055a44d43828c89f09454816275471c6c00ec9eda1f93e1a8302ee172ae627f2c0dde7e13e5ecd2e353451a4b9d2a6b9e14b04fcb3f5c0d8f35ef2be94b8332cfefd7b11fd4e884d8 +Mac = b075d10aaf54eec1a14ed42d77a9d961452b480bc6f655995dbaf7acab6befbe7bf6945fc0b28ec1898b3a912b539a7f + +Count = 54 +Klen = 50 +Tlen = 48 +Key = 19d7b971259fdbdbb4cc0977adb704917d2b3c68b97796df05c26d75349fd777b1e229751db1bdf239def25f0774754b2c8f +Msg = 5ade9519477fbfb754e1427586417618202ec140cfec68ed2517a4414888f988ec7dc3757ef312aea257b78ce05e9f1b9a32606942ce12fdcaab60a55b9cde7549f69e0c47f5fe19d75bc31e055a6c7455b4c090fa21aa8448f146c86cf23c3b5b944d65084b2bffda358eb55dfd842a38ff083d5fadd78b89317f34e554b9e3 +Mac = b50fa5b15b51f7b9eace48a79bbf3e392150fef2448500e56a1b25cd5f41b3b159872985b67a6170503e0ace217e6ad5 + +Count = 55 +Klen = 50 +Tlen = 48 +Key = f915e9a8a822b2bc5e67eb34cae85a5178118afff44a130732cc1b862db31d9ecf54ea6b11d0ed3863eab2f34e15aadf58d1 +Msg = 9185eaa99394c63ca43f67b663c0f03ea998aa85b1264bfc7c79794473638ae54fce8e4436538fcf2609177b979bf3705c9e3702cb2182e41d858398188fbc2aebbb861e59d356a719c13e1a7da2b7a1531b9d3409f07bc514d209bb9179f3a22df3dc21433ca32c450ee57a5dfac33a54b8e502b2bcbe0827091294294ab6b5 +Mac = c19115c8ad223d0ca3e2eaf0ee5bb33900b29e9a8bcb3d93b9511f3186b2c23e4dddd1be36cb4d43cbb40936126f19ac + +Count = 56 +Klen = 50 +Tlen = 48 +Key = 35c28f3bb2ca3a2d3a5089df8b6f3ae27af3f9072dbd31d98a6a216aef2f3253240788f68e11d706a533784aa804bc9d8fe9 +Msg = 268a1505739c34e36179ed0b316a33311cd89a28f361189c032b0d033b7882d1917baeeba16bbf5f97d5d7525036543abcc9544d879e7838f8ece91519a899971856cc88ed20d6763d2526a97e1383585df8961c5c55a9a4c075aeabaafc832784c374c39ee302901910e2f7052949f3c60c677dbcaf3147236d64ac379dc7e7 +Mac = b5385799bd110ac1152146e295331f3ff5c2d676765b933869c9b507e0715f73ef00dc42807e2e9313d973fb114f74c3 + +Count = 57 +Klen = 50 +Tlen = 48 +Key = c1a8b10b8f7cb5ba8e9c4198b04176cfc70161c8eda3809b233282ca38504f2eedcd48315678d03e83350b766050e5a5da11 +Msg = 24a5551bf8c75913467aa639ee6f3a6203c0d8167dd45b942e824b15f879ae553cdf205095382649c78ac011f2be3d860c4a535a8d0d6f166c7a4a5e4bf9bd76ef8ad605f2ac2b19bc7d6e6caf2242e6a2694d6291ad8fb592fbf2ec0b7222d623f09ec376eb108a0d9cdad18d63f188ae67eeb7ef7d627a894b6a49a1ad847d +Mac = c4ab31ef4d7b1872a0f926db17ef4e4e816c16815d7163566460afca3dfa3af3c6846eb1f6e9aaa08dc14754977b08bd + +Count = 58 +Klen = 50 +Tlen = 48 +Key = 8c185fbb4055ddda5111172aaf518688cf85727343c51d718e5a3eae3680b0e71b6a6c860687b50f850492baf7928162e369 +Msg = 935848ed0f2851a4b225e6866d10127d533f21bb9e95bd4df3b157f3e766c92fc16b399c8154408122c14ba61dd642662eeb68065a84834531833c34519cc8482b0ac8ae0a806ede5163e2730336e43a8956b289b0e72cd2f20e3677f6605ee05a9bbfccaf9424e4c571719629183f20ede8c7eba7a6011bbcba0d64df9bd11f +Mac = a0eadb390b490ad39f883482995c790425dd7d01c0e1f86252527f2fa92b948e320a54900fe2b95c588d3464b6462a9b + +Count = 59 +Klen = 50 +Tlen = 48 +Key = 1b08c4bc3cb4d58339073f6575ea0eca0b1ed58eb28aabfbe4d374f43f2e62722b72bb35bd72dcb3db897e55a17638e2046a +Msg = e735bacfd46777da284e5ba4aa638c08dfe8d002dc70ff5b58a1b989053954d1214f18ae47dcaf768c79d73bc76a5aef30dc40cc2d6b43f368e7835425587bcdd33f3496e01fb8dcd23ccaac94a3d4130d6a2184f7394c79ef0af95dc82cc2aa258e754f473a7c5423209cc0b815e3bb9f1bdbf0e4e304351490816e97be12ae +Mac = 2fc24f969c156e34093dc51a683a489a12afe0ef1837d8729a3412ac41de04940331ba226fb54e37c9425edb8fcdeb74 + +Count = 60 +Klen = 55 +Tlen = 24 +Key = 40eae6b8e3abea17c069f0882649577b1952de40f47c6ac0530a036b2f1a1f714b7b2335cfbe27ff3390f9f05f47653c11bab4937e5673 +Msg = d2813f531ce4931cb290899579e6c75bea8a324db875b440b2463df5ecd90748191b1fa93c1d21d0806742ad638e949e1a0986e53140aa5973e6bc5b0989df0ce66729be628462a824f909dd468f987fb48c0a2fd5cd99c96e15cc4ec3a5b122ff0d6778d541e00a68efe50d68105b647ebec414eb4509f86c7c76b6605606f1 +Mac = 3f255480d645369298f7724f42bca1b984233852777ff7f7 + +Count = 61 +Klen = 55 +Tlen = 24 +Key = 4e589674030c40679c343874d6a2d6256355eb95484e4add84a087cff2c7fee7703a177e4144c941b00f5de2f602750d5e4c4c9ea7c13f +Msg = e9e83561cf23ffd44a79ee7654c8f3c7802a5a358f2ffa883e69af7d632e0ab1389946c1f7d27eb0a78f1e8935db9845c61758ee4c3ef905576db9222fa22ada1fc32be513e3178066c23c11f5928f0a78019d0f1273c55b268fa5606dfed2ad456fcc154cdf310e2e173057bb7641de3df013e00857c65252d95b8045cb69f4 +Mac = a1227528f8c21cf04c7c9e6c020119bb6ee907a9e1107c61 + +Count = 62 +Klen = 55 +Tlen = 24 +Key = d4490fb977fb66aee9f2dc8117b4ea926e507cf34bfaff28b2f5bb2b42b663b46846eab6d4e8992d29fc5f17f92368c0f0a4f0434f0e5a +Msg = 3ab58484ad678e4af118384b2cef66eff7a82b09a8d232add73a5d421ba7abd715c75fbbb06a5f47a6eedaff47fa2dda767008ddf49ccceee1b238e87f7745eb3a3e4ef6e51674b7474241a1d6e98c40c20f9cc935c490f6da9bfd109c5eda4db000995dd5d39740dafbb65a612348c9e46f30f6f5b1436acadff5e4f8c531a8 +Mac = 47ffe392039a44404bf63783b2408f85f25dda84e391483e + +Count = 63 +Klen = 55 +Tlen = 24 +Key = dbe1056299fded39ae361a693b75e1c35fb563b4626562c8330e546d1536b6fa9584a3efbf25a57e916dcb4bb0c2fc715ab68ac59c730a +Msg = 522315422009b6a85766d1f9b694ac7a3f160cea83ce9a5a1f708b3f873780c602d7ab67f6b234bd664edb95b907de45bd011d3feb617ce5edbd899f5dd05f2bd073ca3513c9ab28b4b99e43c4a1dbefdc485a505e153b1afd7f64a680c56c45c2dfb8d4feb4e390498d632c60ca6a21a4d40b4663529ea059a0657b777c70b9 +Mac = 087167ec881de09e711e3ef401bb3fbe40fda71790f74c06 + +Count = 64 +Klen = 55 +Tlen = 24 +Key = 05233efb47ca387cb8d82c87223c5a2dde3c0181461775586ce9724c0dceb007c04ab7be73e9f5fb18220ea09c817329190636314cc81d +Msg = 6bfdc8539fe6bf99892c1c36d521f7b17c224ee3837755fee57a0dcecefb183e09e4cc1dbc19862253a2412eba0c67d2cf0ce61117668767af0d7c0a868c376fcaa48310a037cd6d1865c25060f4205638f5c5aba5a40d15ea915a34b4fdf408958714b3b3083b80c2bbc8252fa1ca459e23133997fa8e107c4cd2d4bf17f60f +Mac = 615219d2c623d5f0b4cbb5643bbe62d9027c7e6436060f8b + +Count = 65 +Klen = 55 +Tlen = 24 +Key = beeba7959995358a1c238dc2f457f3c0aa6f47372f5f3471b85fabf1cba590589a74b385915501002ba5fc99094f684c45db476804a808 +Msg = b22d8517c117ca7f2558ff3733c23f42fafd1d30d1d0dd8a339ce570cd296e81d4a57ffb9cea1c236700bbe87be3f7c3778688e1e617738415857ea72240e7e15640558bb4480f25d26c6cf6e8d18bf327b443e24cad5dbf7435015f32676f53df03f00f31b80b4c0fa3fbaaa413619ab38f377b2a1a0503f9b557e124266ea0 +Mac = f1afa54e4a98b1ae4cc1cdee67e42386a36d7c876c677384 + +Count = 66 +Klen = 55 +Tlen = 24 +Key = 2792a9ced0630f51705317f4920dcd68b367bed3fa4552ce23ba5cafbd71f00e954c7582724afaac02aece77155e4a9d0989f26e858cbd +Msg = 13adde3b88ea960a7740685976c0ae6fbd9286417df2c89573793b67bc9e088ceb7c6e9559d6b8f6bc586c68fb1fc68b417c64d051f54396198dea938946e576a5e375cad9f2861e8d0ae163fa52a3953c42ee9ea8aede775f00bf9023c57d726a6b5ba3b148e8c913df30131a5f2fd5d56d8b722b23827f6e5920253423b6c7 +Mac = 49bb81a087bb434af90af426bad3e1ddfd83785f415d0633 + +Count = 67 +Klen = 55 +Tlen = 24 +Key = 01455f93e0e8f592e423b53e57a4e4db40e85cece4ae2e4a8eab8b748c7fe5267ae8512dc335307964fe0e74f313ca92e0b2f729fcfd83 +Msg = 9626bae98c3fc215767776230ac0cfbba413b7a730bc12cf4af8ff67a4c15b67a8e9883b5f666cbc92edbc602fc27aadedcebcf433f2b03b379bdd7b6396ab0cfc26265d0554ffe86187d3653954b03e9d97d6446ec3baa07b76510cea518a43da061db546b283802c6e459cef207a55fb988bffa7d83ae55fb2e382029901f4 +Mac = 3604cd38ecc643116b67e173e927af54b3882d1acbed1fa7 + +Count = 68 +Klen = 55 +Tlen = 24 +Key = 7cf34519715f64da17f163fb9bf0028cdd8f34067fb7d1313d078b447c1a234e2508ddd6b32f31be8b33c36e8c43952ee89e7bd23256d0 +Msg = fa4240b15010ab3b94dcbce24fdc69163fa57ec5ab378f7ff33a31d96b876a0f69ea65ed9d266aefa13a0ea7d1e3a75f5d6203009d7f5a32a4ce80c517315f50409ea5175e23ba323f27f5ec11f20f6a7670d88dd6312818f9b51916d5e77376a4e768f93a0c824e962ad97bb710897eb1556334ff55e37b1b7662934cb08dcb +Mac = a62d888a3b94108f7094a64d8b7ef34581689f50aae08d63 + +Count = 69 +Klen = 55 +Tlen = 24 +Key = 2afe865562bd56043eb122e604588301357f1f35bfab7bc274b8110bbbc0a39a863ece638473e24d9709f1ee88f72696faa458909c4fdf +Msg = 77e654866c79866f7841a2fe60071e62ed77c5cbda76b767f1b6b19070878e44b1f00ed50afed7e1f35cb985662436ce8cf54270954647bbe7f96cca7c3317fe856cb0ab54c2a9107893bb8d2a4a7210e879ebd15f29dd3f8e6ed639293ec7823b82c36f106e04e3520e2f7d7222d810492c495400c77fdb2d3a76463e4da7b8 +Mac = 39183d83b1b1cdd5ef1bfbc118eb9280c89d56b4a2929976 + +Count = 70 +Klen = 55 +Tlen = 24 +Key = c13b8fb78341d426c2248f091b597123d263ffafc7f82da5a55f2f395d1c8ca4d3cf7428d65a534e5642a673d1580e820f98a2030f518a +Msg = 4fc6b2e78759822123ecd63ec36c773494221c2e2335df337370ee024d468341d71316d768a5d1979bfb441ea24c5afedd4c8b1cabaa545681dde46939201912acbbaa748285a6ba49a71dfdc5a21c688794df9ac1b7434b592a7a333cf40227f546d8867e00e9d35677c9a3d375a7baba8281710d62945b24df1727ffc928c8 +Mac = 5c4311312a0a6a1882ce939c8ee4285f10ac6acf61eafcc4 + +Count = 71 +Klen = 55 +Tlen = 24 +Key = 23ebfa07e8183a33de0742decda84f27e7bb3266b6f1ea6c524f780cd7d4efda165bcb328bc3837c904c62afcf449214fde47a4dc6754a +Msg = c30907938846e570cb36346b5f2791ffe708c61aa4e340c78ba8c40a9b2c5d0b6d7199770d28f424087495f4c6f138fb1af56ce41816fe9027ecb50157183f77f4846cd85bed9a550c9f714b0180d0673e50060eaa2f46fc1d60552bba4c86f67fcae87e1a9dbe4dfe3e2f39b7dd3f8b7aa2fe610138ff51968c0c4f6dd218d1 +Mac = 0cfc3607b4e9bc8bf78a81fb78b1448d373bd7c198e5eff9 + +Count = 72 +Klen = 55 +Tlen = 24 +Key = 72e3f7b20f0001b2f6d621ac38be9ddfe812b49fdae482a8abf023b201d01b45146ff5cf6ec02bf4efb0462513594674787844a69a2156 +Msg = 5e9c92ce2d88ff343cdacdc0f1ef30eab51e79d3f7a637d573e4a35fb4ca3b00d78cacc1939cf5b876d9cada710436119773858f22096161b7653b47eb5aedc3059f9d7005c8e495e6752ffa21ca66fa721fccdadef82759f53720885590ecdc6f3e2c828ef412f21517c6c7072a08cecd8a165d345bd0e6b6c21acbfa548274 +Mac = 0db147ee434fcd355c5c41cefa376ff135074c624d19e228 + +Count = 73 +Klen = 55 +Tlen = 24 +Key = 820037b251f283a52f6c19177dda02fe2416060fd593158e96dbe6647a3bde72afbc3325be56514a0f617d24ac4cb8bc4691e6797de82f +Msg = 8746453e63f5acf4c8794ad8219c971442f599260601ab8e36767dc9add35c83ba3cb309c685d2fd378def4d94cd6a65e93056a46d25340d62f301403d4e74a8072781f503c821cd911f55be525a68788db57539d1902a88dcc5cb26bc387a4234b0b5ec61e520cc9dda8514a46c19b3f62b01cc7c6a14666d92e36573bcf6b9 +Mac = 77fce55d8e0f5ebf731da846b4b4ea50c0e35d8bca153e61 + +Count = 74 +Klen = 55 +Tlen = 24 +Key = a8e05f9a3532bbd1ef24c93d235ce5dfa2f806dcc47fe61bad17640ecff926d0b0238271ee4c9f8e801dd7243e9e60a5a4ef2c4cd3380d +Msg = ca51c4875c2fb06de814abc6440dd8325de32fe07c4ddb5dc865e0a90d590190bb63e13732fb68f63c4b6865dbe381ba46ae42522e24908d45c24cdf01b730249de1fa3462f7cdb82408d43c0f242885a459f424fee1d74b5a9989e0d6b5c2d079b257a6748da65ca73335706738963b7fcb8e7f74ea763f0ed2e0d313ba7e3b +Mac = 5507bbe3f44c28bda055fd996d45af1284c26a8d39ff1909 + +Count = 75 +Klen = 55 +Tlen = 32 +Key = 8860418e48ec77a2292c518762076b7a0cc6392ce1c9ee1743789c11807d9d2254313393af536b47b900474f13df1bb8609d38a70599c8 +Msg = 107fd2e4bd7a19a4ff6f482d62896da583c3277e23ab5e537a653112cdf2306043b3cc39f5280bd744fe81d66f497b95650e7ddfd704efcb929b13e00c3e3a7d3cd53878af8f1506d9de05dba9c39a92604b394ea25acba2cda7b4ae8b08098ba3f0fdea15359df76517be84377f33631c844313ac335aa0d590fec472d80552 +Mac = 512805c9806a4739d04c194a1f1be679e9e50e313fe63ec5d12cfc3cf4b07073 + +Count = 76 +Klen = 55 +Tlen = 32 +Key = f15776976b372abe66379961f0787338760a9a75ef51ec4957ad5ca95f5948526394070b9cffc12a97478359e503929a15e00089dffb7e +Msg = cf857754d18e6b8b32941d69fe4416a128910b6820fc0ddaa7130099e3384eb7aea4ddd634ac3e8dbd42270ec7be230658df88c5920ca99f88e04e9250e661295aa1ea9fffd03e485def722d630116f6288d200e81e72701d2b0d22924a08f89788388f95b82d384bba4e80ef99559393fa5bd8a1413edc82e8c74a587ef40a1 +Mac = 6b442d4f5cd3e4bc609bd2096db31f2b2e1e413aabd5db0aefdc599813f6dd1b + +Count = 77 +Klen = 55 +Tlen = 32 +Key = 6fa08ac6d358f801de4e18dbdee3d860421d336a0a4e4b697cf0b96019d42130cf7c091970c5eb7e63c888e89a03804ec3b42094c3867b +Msg = 5659b56248400d7cdf101c0e2a6e887b10748f58e3fa3dce3914e340f7dbc62eae71145a2b3f1c294981bd4b0a051f9ee62fa25063411445e6d927b8c9bc2224add1d6651271d41a25dedd4fd8109a5938b88d00fc7f48e4598edd191e549515fc83e5cc255c9d191a2d6360bd186072ae1539b0d43a41743a3bedac1d2d88c8 +Mac = 6454d29d2082a32897d3d783259033c1e877ef9060d4a5ca8cb67e3cff73f461 + +Count = 78 +Klen = 55 +Tlen = 32 +Key = c696b906b1edae7f82050db23c1f1f9293744fb35cd53b0c438f07fbbc91f6893cd13bf0a8eb0c5a0e0bf9ec930e7c03ace4d1bd913907 +Msg = 283a9d5d58e33def86ee9e87d20d7e769d2ae928ed44b99d137a5e1d8c65db2826ab11ad63d1407c2251cbfc7ced3b21ed428799b4a093467c19f6f13bd8003d5bb5fcd91806b2fa29b73009a29dca981907609b0796dfd5724f0a90c9ef7b91107ee44b3c279b53e14756140ac433c468a0fb97b0cea7323e442362fe51530e +Mac = d5515f18cb9fa799f1064f7a242e53052b6a0917d528b40d4e87ad95822fce33 + +Count = 79 +Klen = 55 +Tlen = 32 +Key = 68ba6148eb2c56c1b764272b236496d19bfeff2efea5dd60457d8fd966b45d587715b61717dabb460ac202b9236493de67c337f16f22f3 +Msg = da1fd0acfd4ad64d4539fb4a4c69d7ab8cbfd206d2253946f07492abb2962d1214ecfc77b2eda4b88010d49bbbecd613209e64bf5b6cbcb4c2a8f77c43d6965e9b115ee0c9aa668bc3136eee67fb72e6b4bb7f1c3af1c6cecf6aefd38446afd9d8569df22bc9414f75086e4a37ded2aab2dccc2358fc7d1d808422b75d2da10a +Mac = 21f753f59e3a635536f4077dc15ce736e6490cecdefd56bcde91447f03e62c14 + +Count = 80 +Klen = 55 +Tlen = 32 +Key = 882c0422041c466469ad9c8bbe94749a059ef869cbf43d03fe9dbe4cff440ae7f83cb95670c1a4631c8156bff85bbdea97662552b73568 +Msg = 33cd61eb27d7ce4389b95180bf8fa4476ac88b1a9888acd83c4aa183dbca4c4687226ab711336b597b468265acf3f8ca6743c5727e1161c743b6d87640e51d7228d3a03d0d9b2263d2e2c847e4b66f2125bc4048298b84ada553b9a824c2e5f8fc282a0581d99b6778d34eaccfa0b2568b7e232401bebc93496a6da3f02a4dde +Mac = 204f1ca2db1afa72419fa024c757bca17505002b80b55e86c01cae05fee6a26d + +Count = 81 +Klen = 55 +Tlen = 32 +Key = 86fb0597fee58d6f6df38f27479c319f004ec141696ba4293c929088f51ffc4ae4f5d4f6817b70d6ffe4c75924b4e0b5577f8ad0fbf44d +Msg = 69e7b951931a4f41ecd9f8d9a857a5966392f2f5b49159d806eaa52ca388a9c912ab3199a33039fd48135d6ca632915e6c541268e4699da8c814de6356662beda6ed72c93ced7012daed24199775845035176e67b0ace1b413e06dd88ff1e8a0ceb3632985d85c48496e3628a3a9e63566e3ee3940e18fc590583ad377af49a9 +Mac = 0befe5d0ce9d18f38b890822a8a0856d77e83e93757fa3cef1654027e371d25f + +Count = 82 +Klen = 55 +Tlen = 32 +Key = 5d20020a5dd409c7e5344065871e57e01c91a443501dc8bf619890fe231319b5480c3879dee618d319962596539e2970513fb5c0c8eac3 +Msg = 0463fc7ec28c9f7e4c90efbe3bf36c8f2c35ab076fb2a601ffc75664b73684a9c2ccdc9754414351975f6a93e966a33944b0f401fd916a91b281b0bc7e7de0016eaa9954393c52222b96ee8f63b290023ec4b0e3131a6fa3214727fdc580477cf1465e3ed94675f7ef7da238129fdaf202ba073618165a3e3461e3b1f6085f23 +Mac = d70579764dc3f19717f26fa40ca089d6262198db1a1384b2380dce8a7fc926e0 + +Count = 83 +Klen = 55 +Tlen = 32 +Key = 90fdd9cd8ced9b0c7a60cc2184aafab1c93a6d32f7d75c511c2a6090b97d283419c26f5ee0d72b78e70807d247d6148db4f6bbb90d9df7 +Msg = 8e7e9bacafae86af937fe46b25b9a41a858e87900a883ccc88bfc9cdce4f2ca7730942d5d369e9d154c861e2eed3f935ea3ce730e9b077032908688004c3922cb9b4cd966ff80fe7772bd4bbd2dbc32ff33d8e3bc51f1a43f01ee0e859199324e7e602968d43411a850f039dd9ba4b3028fa445aa7bf6cb3666af8aed53975b7 +Mac = 217d613003f59911efa218758f537633640d7e68d5c0bf0a3268bd796de728a8 + +Count = 84 +Klen = 55 +Tlen = 32 +Key = 78bca5fe23d54e6509120e05cd1842d3639f1466cf26585030e5b4aefe0404fe900afc31e1980f0193579085342f1803c1ba270568f80e +Msg = 3a9f2fb04c0c42b2dce178313786aa7713256c96c90ce2f2be53d5ff22bf054cdee7c1c1c795b625186f05e21fd7980d360fb5a1f5a1d30ba6feadecf965961afa060ce83f688fa76608b46cbf4375144575cb86d3637f3894d63cf5bc89eadd754537ad1c4b7640aef2ad567d91e995289fd5cdc9198b807024aaa2d1f4a99d +Mac = d03792fa24355abacc837376d23bb6ed504a87018aced2efa5c97478dd321523 + +Count = 85 +Klen = 55 +Tlen = 32 +Key = d2f055e03e94f39e7bbd1d7a1790e8820017cf9997fd616206923660d315275bb633be05a8cbecdd3df4fa543341c22e4b441f2c5750a2 +Msg = d5f3fd629cdeb3144002593009941cb83cd312fb42997ec406304fd19f66e9862fe428e30bbba2b41c402d07851aa2e38599e0379f4a1311f9c8361003d4d61c58a81954e9890048589ce969a2fa58be0106f6d811ffda0731d108ce2c31379519e8d89e7f6f533abdbd943da95dc6af78c35ec4dee05c0e75f4cdf263a49559 +Mac = f4d1a62fbc71184d3ccf6fa3255346d005269d0e5ed9d8655e1013d9a5a9ada6 + +Count = 86 +Klen = 55 +Tlen = 32 +Key = 3e7c15fe168a67d56f21f95f513e9fb1ccb9a57926d51133391629a016523574ee0b864f33fcb7effaf233a4a4ddf704bd279adf24448a +Msg = 6725cf53ae93f5cdba4b7f5bcf0a84c274cf591931906d20982b70d3829fbb3f9b7cec952198d07de80487aca23ee2b95da8102c4d397ad9cc73eb6c9f95f4447b118f85c7400268a45506d62b902936f5b47183e1ba42a111c781f1365cfa230eccff4b2bf45237f5264600f26620e045d9c343757a8d21700f7c8ad05c9583 +Mac = 6f4001a6fb68457ef43a140b5da5db50ba88de93ff2326d25eb92c69f9919761 + +Count = 87 +Klen = 55 +Tlen = 32 +Key = b8dfbcdc41f1b7994868eb6cbb8a58ec28baa6ad2449aeb5ed8e3c2f4e391364c3e432e6deeb560ee97ec0a9cdf438ef336252b5e86df0 +Msg = 14c5e750576ce3cbdc3d8db3ae68655b6674eb149fdeb1f3a903b4d5823feca1015722cd55140224ae3171c63a782170532762fdf7983b2d7821b9a6743a873808ddbf6541330021d36cc1d60eeee4ab0db38e0631ec374fceebfdf8233f3eba90216521030f044ab4b624ec1215d995fce019363522cde2122729d3769939ae +Mac = 1786bedfdb204f5a4e947cf3980348410b97fa162d89e73a254e3b2911420ec0 + +Count = 88 +Klen = 55 +Tlen = 32 +Key = ece8f08f7a942395d29452ba8b298a6ab736f6b17e4fa6f305128fdd95bad39bf9f1434b27e622b223a02c2e2192d7ecea6fd95b803fea +Msg = 2b5c2e7c754f246b7045c43e191d075c54f910a77f8a60ec4d8e4d7dd296b01cda0ddf1b7f76dbc2fbf5caf1ba11a706b4b83801f98340e78d3cf764779eb7b3155bf8c3b2647e925a64d1dded8deefc73983c08af07c13ef7ae96a8437198fa834f61ba36a077a3389ac24cdb1a44053aa20401ca9d4bbb32eb13925d99bdb6 +Mac = 11ba8965cfca0d25739c97793afc961cdef0735c021344621ea40adad58ad000 + +Count = 89 +Klen = 55 +Tlen = 32 +Key = 3abf1268a892877f4267594f3e72814073f8bc67b35683aa5c453e252a5cb5cd4fd7c753c6965e4ce469a28e308a6ddd746bffc714b2f4 +Msg = 8eda4f99accbd728c95ea46d31bc0bfb82193ccf128bc7ca8b1c5f65d81edda045be883be1dc9329271ae742de3323383e8fe1cc54143c41a83e8f111c727ee0178f3baee3c7025054ade621ab8ed0f5b905c54e48ca67d3b6cbbffde37e39144e75f05a7a332c86973e29735e751b1a3da46ebeb4565266ffea7790f5e91524 +Mac = c6e34c6379ad0db133962de9d7712bf2bca37fd2221d3e10ca095f1bd24ee412 + +Count = 90 +Klen = 55 +Tlen = 40 +Key = 304f1de5e8fcd7aee34d5fe5127fcfca0bdd112bb0d9a41f0b5b9cf77d59eb7218a8e0304912ed69baa8addf765925114fc44bb27d4bc4 +Msg = 0b995eb3f8d1fb4c1be0a7fb364e5d1b4edf5e3eba5ddd147b97fc8ecbaaf742f87f9f1273950b0824018a8501b3db9bdffaa1b7884b11830d3eee0a5ed9b71e17111ff69d8ebd1c6aaf0587a5ce7703f6c516da98b01cadb0f5eca3dd8248c61056c4a99e437a4e93f200484a27971d3a46a5ee1317665a0ac6de9f702e1202 +Mac = 03fc9fc8d4f186e8718475c6a3e8238916efa828b54042932e872bff0a1362a6750563797d3571e8 + +Count = 91 +Klen = 55 +Tlen = 40 +Key = 9e1c51d35e3636ceaec44d7ff427ca5e98b3fb8c0ca77364096367521bd558e85f35f22e8bf2353a30ecd2013ce3d86dc32f8fb0ffb2a4 +Msg = d77721f0ca5a83eea7821073d40990fb6cf00b36f006270b390bb1deb116790ec33463c29052bbe6e45dc97068a7a5e8198d4d27f857f55f035f9e5b6576ea08ea832f35b56dca97353bb610557a5d30f3dfadfd942e6fef565ad43f26ee516232abadd0a17359098266ffda034a5ddce430543f2b543cc518467b115b475622 +Mac = 6321b02d91591009913f8170fb0b5ea6793ee8bb32a3e62fbe11cbee2d067dbae2611420a03fb003 + +Count = 92 +Klen = 55 +Tlen = 40 +Key = 53a933e5113a62ea85908a388ce7858cfe850e09834130daa946fe18341585eeb6c9fffb5f9f4af715b5989ac71267b9ffe7b4b3b7146b +Msg = 6c37a65405b58eb6d79a0fe5777687975058dcec98ee10ac82ed15d0b5b3e345fe2cc9ec41f200e5b6b8860d51e829c5828be2f61f6a65529f72f6dc885d7eaa2a8fdee98e3e8323aad63bbdd69c47c48491b1e92b99e0c984dc6972f96d28235b2a9054d3e33ff61bbed5fcedd9071abc32efcda3c4a69b9bf3159cf02a0839 +Mac = dd1f092022bdb437755b8900df5d6990c5ddac34ded45d8bbb8a794c928a16feabd0058fca2ce160 + +Count = 93 +Klen = 55 +Tlen = 40 +Key = c5f1b9ab6535bc70ee5473555fe070b67533fdc3711803d31bc72afc071742e017efe2c941fd4ef992ab9e3b734f1dbe2ca2f023a674f8 +Msg = 25c2449f1885615129179a20929b0ff99812508160ddceb4037c8fcce49c26654251e3de09a04702ee40bae8baa18017e62eeaee69d0c944ceb3284b894c3bba8b9b922b14ad92c1c966260f067db23575c8494ce0ba1f05432a418c265583b32927ba4ce1b62cd6e210455d1d368c9b6d68d5636ca3b7408b69405962c0e897 +Mac = 6714fbc0b70c6b0ffb33a80aed3e511762e87c5c9a1bed95b67d03b948b215116a11b94729a38ca6 + +Count = 94 +Klen = 55 +Tlen = 40 +Key = 8a735e5b19f0aa6c449588ae2c10bb645bd4bcb5a76dbba55910e0448f77d625dfec8a123da330fe1f4c883bdfe95fee60dd58bff446ec +Msg = 980a7fb38f023ebed635d2bbf5d82c2881fbaa38f10e8e78ada3afb268766e11b0aaec87c3557a6ca53f51686fe78492eac732d95cd900a4a25ac6b57fce89533444aaa851db5c68ca855bb34d0bdc3dd352bfac76dc0c4182919dbbcec018784d6121dee09dcdf96e905965374d1c6f6522ba77e41e9b9974d19b8cfd5303c9 +Mac = 29e7c7ae061a50c471d5e7fe3faacb772d5fe1fbdc072e76bc4430307cb0f68bf8b064c1ff2a859a + +Count = 95 +Klen = 55 +Tlen = 40 +Key = fc63d7b0f56a3290c3f3f75f3f09579bbb45d6c48842f46ebc500d96316d7e32d171090b11887bcfbce58b62f2b506767052295b12ba4e +Msg = 36aa473316a8b206a22edc8e33457d39ccee612e45b7b186a98b74b9dcce555681aaa7f81aa3a6757172005838109492ec11796cff3342c0353780694fef89f8e79978a89b6b75956d6f37286a91c6d68af7860ad890715fd2f0a413135b1db92f1fc32ddf27a6cd5ece89e612f19e6d6f4890f019f6c6cb485ee79f71399900 +Mac = 48a484bf9b7197a56f34b2318fe88a8f133a6553073c055b6410907316be7a08c9eaf2dbb4791978 + +Count = 96 +Klen = 55 +Tlen = 40 +Key = 65de751a9abf91c5de639338618e3df81e9994cd5517ef7d3cb84fdbf26dee00b4cc1bd953b744e2e5385530bbb041b59431ddc01028f5 +Msg = 7197b130fcaf82b3d15a47555ca3ef1338080e09a324e8352f8bcb7ebbf6a3f5a2a0c85a32ef1ae260575037b97c8dc19c963424a71afe0a6f974a2274ddb4695465e8a83eedb93daa636d1f47045b1d35c5b96675f2af4e9e15af4fd119094eeeafba2008f1854d17454614ed8582af6c5d42d8f5f4228b23cea50ebaf1cb2f +Mac = 167601cab956a83d1013e78cae3ea29deb167b921b0b8627934814e9e60566d3cf42766e3a00ef7a + +Count = 97 +Klen = 55 +Tlen = 40 +Key = 6e375ba22837129d1af55e6306bab99cc29346e83b49fd76ba9309d3668b6eff0b5fefc619492f4df0c116ec5af1763b5969ef70241410 +Msg = a8fc55fddddf63e81780d2ea6fa51e14fb1bb0c7f24d17dc111595233dd1dd0f69ba1bafba7135e0e9db50c2ea2f9768cb4d37d4de52ae221a694603bfe4dc6d398be6914733b50e5c93f76446547fab0d6749851e9bb851a86f23a1472490eee017bf8bcc4e6bd83851ccb8cb3b60458a10ebc2f951bdd083ce33e51cbc80fb +Mac = fe9ea791bdb8326a8fad6ebdfa160fe129b36beb7c3f74b8d9cbe43e6e61e7592827a5f16b18d1f2 + +Count = 98 +Klen = 55 +Tlen = 40 +Key = 8968d657a6b3521038067b70c3aa05b2a3555dd7e7ad27486308ebbe01760b5f5801f92a8033a69424d93e73d807121cad5cd6c803870c +Msg = 1c78cd8373d9b3f3fee9b4a11c574d6b429aad0e4aedb2470d9813393372df0f4aa426e216aff5dd28b1889fb2e4bce09a67c358cd411bdcd6a3c1cbaf6da2a8d7f45208a40200afdb1faaf67e0f8d70e59ce0cc1096c1fd3c177099b40bbb7feaf0b9bdc6dbbbb13ebc806e27e2a8604bc26b34bbf48bf2677e876ceb5512dc +Mac = f1c322457c2229250661c76555c81c3e8a2fcbfbf37c89ac43940a47a9513437081936c03fd5987d + +Count = 99 +Klen = 55 +Tlen = 40 +Key = a16a45c20c1b98dbd2dc638fb7684690f626db9f9bfe3cff2e6cc62a91d21dc42b1370cd475dff1ab646da06bc1beb652a7436b9c70c60 +Msg = c05e649d3fe1142330ca683ede042dd4a64ac41609e9d461ffc73c628da44c7e99a03471fefdbc35dc27362531f1b162ae227076c3309b37fd4b33ee919d4bb939d1762e3ed27c41d6d55168b19947fdcfed82e39474ac6c1ea5eb7ad61510e545f9121d2ae6ba11c9dc9f4f8583556cb1b4e2a6a43b71c80bdc4b4e849402ca +Mac = 484c5d6cad99563ed7ff8b2b6c1d59056400bb6d29572365fefe82b55b93a3db6958e5893723284c + +Count = 100 +Klen = 55 +Tlen = 40 +Key = ee59b47d837ce466a5c6361ac4f64365ce5007de53372d17e8fe8d16c9fcf409c2de23354f411a300281965025cbd863a17aa8a01ea09a +Msg = 7458a8f4cbc15e390633de7d2b2df46d06dc6cb26d497bc3c8d25afdd0d734f596b5420dc7f835452fccd4547db5e6f84680528a4c7a85d5ffdf14284495a2aa761a05eeaabca4c73808235e77844381c7a1033ed5eb0cb11a834b1aa5cfe0321b7037c0fc74746727cd15c2a102d2b39225c8f79005d7fe20a449fa7aecb437 +Mac = 2a18d6e05b4e386716fc5e8b5395c79d04ab1786ffede68ca46d4c1dd7465c6c1b2731c4a1d8de60 + +Count = 101 +Klen = 55 +Tlen = 40 +Key = 6aa20e80402d8de895c1524f7aff11ea645805588014e1cc46990a6d51ea03fd6e6e28b9f3f3a08152f28d39ed14856f2cf6463ecd29a5 +Msg = c9947b1f99a8f4d742766ff968a250653b2ee24af8eff93eb23dd68e52ef4ad2dd871fc5f5a9b354a3d2e6f55346363a204a29a65294ecbf25003964cd847d61b6663b4110acab648bd5a8515fc6c94c9007cd2c702f3c67659d4b6fec690041de9a983af39a262d84e77cb4950a4ec312cd958359a9325df97ed454b9871b99 +Mac = e568392f545994c2ae2c845cc366ae8949b73d4c46485412f63be61e315ca777d909b2e841f65c93 + +Count = 102 +Klen = 55 +Tlen = 40 +Key = dafff4db046073b89d3d2311939d7fc9472b1683e33a80c1ee06964d1e3ce3d96dbd55e26e9f38dae275658587d1b7a43007bfd11a33b9 +Msg = 5da17f172c06192b866ebbf35f8e97ec0ff25a1c52ee54a593d6d99a6a71e71163ac087a018c7a2f02668e4ce5524ec0aadd62a4d9fe35ccc54c539c126d161d75d28150bba16cc30df3e1617240c78e9517bd74c91349974a0a32b0c5872ab81b7bb043632f350f2e7d7edd0e40497f590933332a14d92fa97a3e7d8ca76d09 +Mac = cb113d1aba8a763b774833c24f200bf28facdf7d75506cf3c9a16b14937a307eedf32fc640382099 + +Count = 103 +Klen = 55 +Tlen = 40 +Key = ef71b7b3ca0f904dc50447ae548096b2b3603b312a5e59d490851b270ee99aef259401bdf2c3efc3b1531ce78176401666aa30db94ec4a +Msg = b7216e9ad1289c89d8d590f9dd0487c897a28a6606c0388955e5c62205a9448f487f2212abd3f282f8556f405b94bf6dc3cef55a8b06da405a58ed32488aa84f42e3053caf4041d25364e0137490f1633c5393f55fa4b883fe2e2942caebcb156cf42000259810e0b1abea5a7220a612cadb6d1dc9c05bb80810833ad4f53347 +Mac = 13194167194dbc07f67581776840ccf1a160c5c465313f53e013daba7d405880ecd7124295e775c5 + +Count = 104 +Klen = 55 +Tlen = 40 +Key = 2bfa932702a35ad436912ace48999d18c06caa9e680476beb9426d0793d59241315d13ad5bd0218edd1dfee7391058879976d5430781ef +Msg = e8cd40f84cc8155ea751f0ab617d9f48d1984e7cb0c69f33ceeafdfe03c72d5a69662535c8b722ae527af51d91609d539d6e1b2392a3822141da4ea926f2f6239b2bc5864ad3e51be823bd8421647dfcce55f6e06ed1b06fd4ad36ce1de0b54ee5e6c5f2bb66872cd112f0e8f8ce64cbcc1587bd2c9950a5ee2a5f73d0d99064 +Mac = 2d44160a46ebeeef54c3f84cb644224279635fd8997ae5692b4710de8d7d8210e1aea092e62f2893 + +Count = 105 +Klen = 55 +Tlen = 48 +Key = bfe6bb4c9b171b93d28e9f8f86b88dbe509c66eed41818a1986d75b616fee4460f5456cd23667c8a9f1738289601519d33716a534db235 +Msg = 5b7a078f980bb8919743bbce52fd0ba3c22083d2b0254e28c8d3a05def4da33bd64fb502cfb5d00ce03d49ad168dbe5d1c784a190c7dfa0685908558fe1e37725a4b2f4ebc7eca209c1f5f361b9f2d2393b9911c73f87da24a7a256221f3fb590ef4de3b066e8e16f3726432063a403d4f6dc2a48b9fbd443d17e84200d6d737 +Mac = e82eeb7f4b7415a4c95dc82c46bb59715fda4e0bdaf64a7fb3af3c7058ec7d2a172b8293057b72f9664454e7dee11d95 + +Count = 106 +Klen = 55 +Tlen = 48 +Key = 4cf54eb8cf7bd421ddb0586ac4fab9c478cdaedd89cc5a195332211f7571b9988419843300fa1ded868d318f48909078bbf1839c8fed61 +Msg = d22f194a1af33cd8cdffe9967f677acb68500d6cbbf77a3f34f58840f0c16044827641dc43d6767ce98f85dd5cbeaa9fc5b28333e7f20df8b281cfa4156055e61555e04a1ceb5c5c93ba9210b2e89f6197f0a53996a2c091d16c3cd908d7059ab2545e5a4c39d6c0f10778f82bee43590993da4571107c51b83c35a6702e56a8 +Mac = 830b4a798f85c448b3d54abfee61b376597f65666d83a21052cb3f4466f44747431607bc659c91cb520308fbf4fcdb58 + +Count = 107 +Klen = 55 +Tlen = 48 +Key = de281ac95941750111396ad0e152be30ebf8c47c2dfe8bd5562b56c5d7f54c223c8c7135bd1ad51c10490c6d8207dd1c46863e9f0d8681 +Msg = ee6922e96d48b6e0b52a1cc6f3ddfc7b1cd11786237a1fa36ff6cc7b8cf02cb221c43b2622e3b376467a25c2bc4e49b21aea93ba96fd069c78fe4d2ecf11085d632e6472ec80ee94810ba98e53925dd39bb833bfd1657f201f6bddf5156a7f769ef1c55433e50e414e27cfb32271e2e58981201f3e7a31384c87a359c6c13a03 +Mac = a136b0ce4e8239ae848c5dd84a708027b0083efbb61589b2c30764def27e2e1b221ffb4d18af81f27c35dccf0683bbeb + +Count = 108 +Klen = 55 +Tlen = 48 +Key = 790bd8d4e9ff691a6bb8c0cd64d68d31195961e2c46363b9e63f44f3dea37590bb3297fa4f4533e784ebab80f42f70c3b39976266ff7e5 +Msg = 4d53f5dfe10ca3880f44fbc2d9bf3d1f97479f4f49ac3f432c085d918b47c71bd8e794ecfbfd1562ea7909927aaa10e87505630eec22c10fce07adbdbaa9d65012b0d74f517b20b49e64344ba145165b953bfd889ea94ff85d80cdb5c2be0b52223524d28a8eabc5528de5b4f59735bf2071d785084ad14401fc27414d8f4f6b +Mac = 856c255d058752cfde3e74df1c4a34986e6f7ad5a34a06c157f59d8d6b2039918c4201dd8b2d58617911555802d7c799 + +Count = 109 +Klen = 55 +Tlen = 48 +Key = 15e3ca0e8d9f69f7bc8f63f05b57586c1cb59eb33ac37d3f54769f667b6bc23a8ae3b0aeb50c71fa6582bf404415ba6f93cddd68c42b31 +Msg = 929172a72b23de3936037ed526238ba70aa8a695c04cb4c56500ec5f0fd52e94bf1c97df91cc528a3625b175a4937c130cd589b50d5e8c0b27fc31e772b7684590fc0089e0fb7807f44d12c846da288b26fac30bf7da6a809b2238682cd43287ed77d72d8076f8b759c3c95872bf391a405e7f1fe786f52daab92a6aa5f43263 +Mac = 8d6895c2b80f3ff362dfe355252578dfa31596c8f8b028ee9cd1a689807b6207a216e3516f3d782234d65eb1f9597f68 + +Count = 110 +Klen = 55 +Tlen = 48 +Key = dfd7e7fa6dc49cac285dac27f0968e1a8bacdaceea5cabffad5247ebe9e402a828005fbab16379e50a0ca140bcf1498b56f021c2b4087f +Msg = 004c38356decec9ee5ac710126e804b8f6d947eaad0ce6a4f5137b2cce7aaf92d5fda287c5f78e723e1ea7c1c56e457d0d634422746babadd19b8df66da12d404ffa650fbd65493aff970740663012df8dee7fe3df20af3d595e2e549178dba0f8ac49745c1c661bb17f5a271016b20600e1bed6f514377a16c525ee43e700d7 +Mac = fd24205b960f569042ec8db3c4e442eaa4eb38272aa36f40327ac9f5e3753d3ee8eeefa28ec5fb1e4e1c8815416515d9 + +Count = 111 +Klen = 55 +Tlen = 48 +Key = 8c354e398566a4b9bbe215f1ad7b40d70e698710753365fe56d301fa311503de0940a6c718f80e19c163ddc3c68b01c4bb03cfeebbce56 +Msg = a116269f6dc522d0abd6cd740c0879e7902b4a0b9bdfea334b9e7f3f09fdda085e2ef1fe08ca900f4ecd4bcb90e3b7c622e2da3e5b97dffee8c50e82666bfc5c3146ffd77697e5d99026e60e9187d6421e9ca00f815befb9f9d12e565467b332c0653771dfb48af619e88484367e3f232c6183c635b3822a25cbc601fb7a6750 +Mac = 36768ec85d992222b67619454918b6ad9369bd002d5a1d08079dbefd35c3ae6d28f0475747afad3c3c64981b20e7b665 + +Count = 112 +Klen = 55 +Tlen = 48 +Key = 1fd04f50423cccd5f884f5954c19c8a4c6efbbb0342ea24da92bd28ac79687c83af583cc8550f812012ea86422c14bacfd5e3107073028 +Msg = c050ea6c6b8bc0971c1c64e8b8df91397ab8f0a1f2823c004d48a4d8d6b8705fbdd4e8d217eb710b27c8fa56dc2996819a736a323ea3ca7d5c889fb6ca300c8463a0513705c7ef5cdcb50d8ee3091a8fa7a8b4974fb5c8ebd9bdfbb2a6314904391aec453c0880b1c34b6437d566638b29c194772d9e7e724c4e807371a57107 +Mac = 7bfaebd1b8b1950274b815c26d4b7d11bfebf2fc1e0bfe4ef0a3e36196ebb64dbea0e2aa0f342c4fa021f82faeca66ef + +Count = 113 +Klen = 55 +Tlen = 48 +Key = 5a63fe74efdc2a71b87ba0557452386fc3d0bb31dd9e3a3684c8a584371d990ea9d8787d7180bf2f030c9480df4b9f4908831ba7b8592d +Msg = 5802a9f1d0bf3b1af5aca2a16a6e3988f937b9add7f9a59e29d3e5aec6d0b0493fd0b0841dc661f86924bbd172941022cae9377c9255eabef7dc6d2efd0870c97cdf37d86712f8c45477852b39b92a33744fd91f0faa842041b3cb6d3874d79515158614390bc825bf8c49d8494650640050e7bed6613c6b0f404792ff7bad55 +Mac = ab9aedb3bae00ba8a335bbcd2ca1c610a5e07fb090a5b7058f11ca5c5d884601068aafc2491ffae62db3d5799f6f7997 + +Count = 114 +Klen = 55 +Tlen = 48 +Key = 52b3069b60f5375f4dc447f866090a3a44c902eba0a6d66d68a9ff9c113ec5fa30806a0a44b7a5f9d61f5283c5ec6715db8a2a2fa329a1 +Msg = 503f4f781c453afef8a77661ca7c4f0d622d1959c27c1fb1bcc5dcf4c3836e1bfb15471c92c3260d53fc458d78e1d460c008a759c2792c7d81fd9f65409981e4985546eac7414ea84bba16f5b0eab0f1a68e70e856fce979f66417f79b56de0f4f84b3ab64ca9a17086b5062199ec9083a49ddcd260c3eec4481ad717cc26de4 +Mac = 5173199b9551905447d3e220c3301f99006c61d2013a375601fd3b162176adc4dc1ff3c345f81f5b71de718b650aa3a1 + +Count = 115 +Klen = 55 +Tlen = 48 +Key = 05b2305a6264fb92280197a579b4d336395d5b51148adbfec2a3671589641b530490feae24e42ce6744a355da150c02839d87466b31118 +Msg = 27852e97225f7966e2da1e7ec5e615853167878f32448fd964ba43ba14f7eed6a2e4a0952942e9d462f8e1dac6ab6b8df390bbe5517e16a2f548d93ac649bd16de4059fd335fe9d1769e4d793b55551e5b0a3b9a9687712d7d309d729094e392a34262b886de01c5e4746b446c0b58a02f7e0f94498728e4c41d974bb900e6b4 +Mac = e36f45d68614266248a91553c18818c049ec60e233cd5ba37d6cad12d9333962a5d3610f2dddd3c0343cafb82953dd9c + +Count = 116 +Klen = 55 +Tlen = 48 +Key = 185f150008c482249b50548efe89c71aeb4e0fbecf6b98c02d6b92263daead6fdabb21809bd6f2e13fd672294e3107b7fd592ea3524bc0 +Msg = f00f1d6331110716041ba25d28fe48b7764238f7c372993a08bbbc1cc1b6a22c9281be9d3014fb3e7fd201acf85fb4c54eb2fe61516bcf3d126662384890c1c2f2f98b913e2bf595aabb0f2f691d499e08bc35ba514a8ee470557a3d541c0c1658a00da823fefc05ccfb534f42e10c28ec8a64698cbadf1769b28c93ad018a10 +Mac = 47c51f9c7346bd7b4ffe38b2feca74f43df543916a001c880483ceabf6452f7a3edf9d80bf321e9de27dba18537de349 + +Count = 117 +Klen = 55 +Tlen = 48 +Key = 4a6e36f56637c7b8f445b4f096c544507e2fdd3dd31e823a575f9aa44848f39f844b0650f0cb7d4d192df2511c33fa35c485621bf391b8 +Msg = bac382a645b43242a8274704a6a2b55905a2993ee59b295e503aeb7a12ed260ecba5973242db64befcd156b10e1a42d42f5cc89a1155404bf21cf2616ea985339798bbd0472a5b2eb58d6e84475dadf4a76a3b6d19bc90d00cd4b551ee35b7214523564afcabfddafae3f743fa73df029654587fa4d8ff34c6eb9e123d98a320 +Mac = f194e972fde5d62f56d5fb99137e0f2f942d0b2a6a22916951ad03bfee22b58287bbce5d24700c6c395452dfddce97ea + +Count = 118 +Klen = 55 +Tlen = 48 +Key = 83fb4a69527469aee5d72be40f3c9bfcc94225c57a4bf9be76e9b029c4933260249dd76c5067ccd483d4b9b338fda00d34270963c6f35c +Msg = 2c97ffb7f1937176ba699943c435b3bc481fd8e34ddd75c5c07afb5ac656d8ad516fa73cf2dea3a2eea5627393a7c068ccf819bcf457bbd5e8f99a27608946567f6c1b9aa849b76894c9b24fa19b89206dbcda51a4f5d7a316a5f5030dc0e4aedd18c499bcdb9610d45df09d9718f52b53f2856b06beb177730472b675059aff +Mac = bc852d73029f8c2dd6115c5949598b9ea613be7601a5a224d46ceae0bdc0ca43a8cffb86d9f322cdc09361868e2345c8 + +Count = 119 +Klen = 55 +Tlen = 48 +Key = 1b0bb110ef8d7139773117d7308dac5d11ce7c756f071df11ec8ac05d9f35ab4e3cb2789ef4eee873ec5a2620799d7f01b6884dac95807 +Msg = 21b801681f2ba3d51ca2347f4bd2a75c5319f25901626459394a397b33816c9ce472cc1eb92652e78b65b2acd01f306f0e0bb546968e225f6edee4418f67c954506e11a423f4c9e27fdd54ac1d514b0d676387482ef07bd19bcac79d68160b9b4ff3f983c35dafcedf5043059c309f3f46688fe6315218b9a8570c172657db7a +Mac = 3dd9d0f426054cabd0dae1337bec5682c0778679a9a3f908c66b90e1c28814bc6b9a61d710b0041a2f17d576a69dd4e4 + +Count = 120 +Klen = 128 +Tlen = 24 +Key = c63bff382de2bd2d076538ea88ff5413d11969f50a0df16db12f8405310e0761b7f720da41bbec68f8b2f5c5bf005ecf0c17612ff67efc3890d0e6117607c817a5faaa7d9025ab3570a9f614db93f1319861b88eb2c3c9facb9e0135b356c756394d876a41a7625e1751231f034175ff1eff545b6364c27a09a1bbb911846ae5 +Msg = 992a5b8a639ae2b2f7fc9e1353a79e521cfdc98990937290bc932c7bef5edf636e751b6a6999adf92e31704c9ded6631dca9070c4c94d91fbb914108dbdd998bf2f28292d4ac7c720fabb47065f81c847febc15ddf4c5aa417b81c853846d66c8e6b390c8a1b77a6003111889311e9d46d8c9f8233041aa837d065f9f0e1bd8c +Mac = 448abce3c38e7f109073f1513455214d0361ca759c775452 + +Count = 121 +Klen = 128 +Tlen = 24 +Key = 4359b09328ddce80ccf1d3ec5437aba6a11ae789775f04acdefcf0d8c82eca3ff5c6e96a14c321742b2641763802e04219d35a54a91015052c040902edd97ffd25f618a21f8b12cd9a69c7fa6f1876fd732346f39fb788786e6c3d1a8763d80e9c914522925a29f3e2626c603fa0f53e79b4b44da17ae66b6edf9408dff35dda +Msg = a57195bff000d768e39ce6daf66e91b31a30fe94429d4c2f222576a136e67b0307d8bc3baa47a51889878f9f66e3e59f9cd6868ca87e6b89e94d8ac7a402fa0e4bd75799fffc68275345ff4f53202114c5c967b9aec1a4d7187cc8ac135905b6fad83080f70869bdc93efe93c50c8d391b7169c45b4e3f3e3819faf98bd5e322 +Mac = f215c988601119873340c4cff6063ff97ceacb3eedc40aef + +Count = 122 +Klen = 128 +Tlen = 24 +Key = 9f06fc05d8892b9513578385a5c0292f0b9e9ee7dd7c4d3cfdfe607b147dd8753ff1dd82051452c68dc4adb30da906cf86196db8af3881652e643fae0ed0170f6e6e45a976135e8990d6292dd4b9b144c38b98b6390caee49d53c2315b6db9c19447dd8114cd776784549ffbe03553162cbbc7e96340fc42b192940be19ce513 +Msg = a30c53e81e0b4d5be3a210b432e6f4394ae755297f7a45a08d3c7eba2cd39afbe47787ef23b2350d8d6391e19309b76b473e63c26e82a9fcd73ae752ecf8f78087fda96b07fd7006a2225b76fd534775f9b554f4d072950462ba0cf6c908d5c133a7a1a5f174660ecbe555bb974a0d1f0a530e08cdd3707ed3c3d5eeeb8a9c88 +Mac = bdd3e637be7317f62ffb955f7cc913b65507cc85d298202f + +Count = 123 +Klen = 128 +Tlen = 24 +Key = 2f4595e175c07f52d7be52a7a8191818535eb24cf01910c21553a871ef5820ab91be4e478ba263ffbf3563177078d9409c43c8bb8c8ce4c1a9e602239148ce2e6a10bcd177474102e827425df7dacd0e308507f2108565f9d2f91fcf8680e2bb6344c6c75e377f21fc9cd7c164ca5c4cb82c5538a58dfb323992e6bcf588c61b +Msg = 28bd1384c5786b1a689e0f305c5d3e9b754b0bb3f3b55d4faa3339f16080443d778983b0ccc4668edec3051c3309a910f71c8e46e7dce7b46d1223a00c4c6f10ffe97c831d7082de002685a966dfd77bd714deb38936176980425ba5f99661ce090385658223c7f316ec173fbf86d0c55e5a8264a26cf4572bea6966ef05235d +Mac = 39dd7e97281b897fb36ce83afe4c8b06417d05e10460cc88 + +Count = 124 +Klen = 128 +Tlen = 24 +Key = ab1cec025ce72c9cc162028506d527e2cd296b9480f2a65fe6adf24bf545174ae8dd471c91c90c70efdd7e4c03ebb9aee0878e74020d7979e0e6d301c4064957dbb98db488a04b63fef65f230e1845cd3d45d1361aa22057cf81ceabf5e269d9ad3a2693ec74d3be16360dd3cf65b3850eeb9ba472b88341da064a1330e26019 +Msg = 8c581d3fba1744dde5c8da61c90899ea1e7e1bf96c604e1a213822c7e1e884891deb9060e7df02650440eeae4377b2720e13286d3f56208635f30db02616fe0eb6a5d05ac9c5a28796a18aa5fe6786061b92b69f1b6fc8b04fdab3a87f49a843810d45f509d40d8bc37115109fe0ffed6d842c55a9b42ee098767c76948a6a6f +Mac = a3f6807e008f8df4f9e1c3e8f43d1403ab5f6b2c29564ee1 + +Count = 125 +Klen = 128 +Tlen = 24 +Key = 38f0a1720529576df8e0bed148c3e04b79938949d2ca59bc1280171c5f8f48ad7ff600024a7bf9bf5f95e2a31788f9c5b7d2dc1deac69c476e7714840dd77902cf20325d6e73e9650abfe2221ee58b15b31a55c1d38cc36a4148c01d675b36f09037dc8b575950e75f2965564522bec4d3329c3c7764f4aef3bcc5ef5562a801 +Msg = 5bac4be719240c6790176fcfeb919cb23af6bbb172f31104b5b46c56d458c2d613a2158b2cf199e7967219a0069497bb37bc33eae73b4e17227dee41c282648737922d82842d17d88a42a40e89a1b39ee4b15d4a24661eaf406e351d1cab4da64fe65c7529c2cc62f5eed9c37b9f3a84c93e037a335dcaf499f00893e8bac35c +Mac = 738747eb57bc8caa2e1b86673916d5a5b94cb87f4d3d9ded + +Count = 126 +Klen = 128 +Tlen = 24 +Key = 8424bb05a925a6b09cad2d0528ab8d15a56606f3701aec7498e6fb32dae5ebd7d09c4498659474ff8c471eee3241b6e1707f4b73061ba324052b8d59cbe673a434082f460f781ff2cf287cd4833de7d2097145127eb5cdbcf81a5f0178f1185c1a3123178f1ad212cd18edc005ea4a72d6039dd8c03192c4db7c1932c9510186 +Msg = e197e4a49e73596a1dc14d330f40125b73bfccc4b0e126c1e11d43327008f8f0e6d7386b011fcf9108e053f25bc258224e9ee45f37402374c66c5bdd951e212c0016ceac37942d439161769d240e80869280329825ad3b171fa002194bc3e0ead85d8eae675ad948634b9d7b91adf04fe86e9eb7a2add67093c2222cba7e9cf0 +Mac = 6947d49bf9c309b20edbd4eeead6c8a5f78983bc1950442e + +Count = 127 +Klen = 128 +Tlen = 24 +Key = eff520144c1a3c67a3689baee7937452ac7198f1e9ab56b1fcb89cd4ee0c608df98c3e12474663f3fd5fa9aa784c0373d6451c5eb9f73ba2477a6a347682d79886d97af8cf0df873bc66c8b7181a94d288c4e2455913f35a7cbfebb8cfc233359fc41ceb6ad7c58ee9643efd4d65ed16cad531cf52654682a371698983323c0b +Msg = a00e97afbd3fa6dc67f1c132ae81270567fef4112f25440eac909b85162a85e1f6e679c92eb103ad3aa5239fb57ff0651f5380ccdd7e0c3f81dd50974c3c3135f111a24e9c6bc88733255cc2dc5f5237bf2eb8c60d93e08b41aac1b4a6249b8f19f7dae710543d91dbda37422a0996a4d0f962a8c64c081d7361b7822aca0b18 +Mac = fe025dcfa6604cc3e74a0f0c775926e7a16f7396f9851c55 + +Count = 128 +Klen = 128 +Tlen = 24 +Key = 132681a6ca18ad6217f1282380eccf9ef901511cb6649b213e4f944bc1010b7cab07ed3c79babc58cb093ccfbb7870ef6e69c4bce89a8c9125f0ad0a65739a20c799839619c7c995ef15b493f25268797b48150461406f6b0fc95e43d9b6f6a09066a97e5348bb5fa99df735cd80a1814924abbdc65e2bf823630dc0c4d20544 +Msg = d714946141393b69701994acf9c2093db8736bfa20a4e3b3cf462b8e654cfda9976acc027f1db39436ebabc3a5ec00fa98890693148408f7eb3981068d238eb921a1a405d5fa7e03729f5a4f33b165aed7c374f3f5e1f42390d124d7eb9882e29e418234ead986fe4abe0b174a1a209f9caa1de269c4917ee5987cc926b6bf6d +Mac = 0505523b6ddbe352de5fdf9f4f9258dff68f8cd4c6825df0 + +Count = 129 +Klen = 128 +Tlen = 24 +Key = af7855435734415cb4680725471ddc0f935dee9ddceb4aba2f31fd50a27a7916dd613baad989abdfe88f4458f63df4560e01c6ce209dbebf011f04c2b31446e3e7f957afc0f21c8edabfa8538beba6126846f7310b969dc2148ad8106eef8e78d426f07b93d65b1191de7c3f8e8eb8ebaa16cbf0273eaf6e7158bf635b731c80 +Msg = bcc5300e069ad4f12df78c9de7c667775d9e70ed8d972ff4ec5c72b450814d810e175f0e5f7e57dd097bb7fa3b8ad8e9b8762edd3726ce2b0aba2dfdffd72b4b843e50070ea45598bbbee68a369ba684db36747a1b4ced23226b31aeb84ceab165628b62d9b3d6098ae7a1b59f9ed92e0d07c72c00af92c67c96062d4488939a +Mac = 39341404ab56d3424e7a8cc4c36ec283a748c1d2da6aa582 + +Count = 130 +Klen = 128 +Tlen = 24 +Key = 82af0ac2ed6449298b517034353c3687889b4de0ddb5f3597b05c4e70cdfd2274e56f75a0b5c6aad4b2b91bfc8e4165da2763d9054c275d9e7fd2dbb6655e87a91d79423d59017cc7cf22c1d227a6d0f6890b0f4ecaf97b878c5636679dd09edb3fb88253447790d866ee8572946622640b14f168bc3837d95270ff02fbe5d09 +Msg = 5ff26053b316d68f6de5b455377095681da77e47ee2664a4e552ef1988a57e17d1466b1f8cdd903400a50a90d1c33c9625d6170806cf997a080394062b7eb142029ab46f15d102f385d0600aeeccfdb89119b302b3f98a5d40b27e67b4e382d53b17c4ac179b33b5438d3f2a5636dfb6a99ad99dbc4c3e36d68733a2ec7bf7b8 +Mac = 64ab6ba0015c5e2ea69968f4fda578dbb8148557efd3023d + +Count = 131 +Klen = 128 +Tlen = 24 +Key = e06e730847c21b6867eb4b12f6d02142989ceb96ba11330bbe20f92859b63f793ad8cb3fedf22866fe6ceeb7617f434f1147a250f819dbd60f165b2dc600ae41a64d4255357a6ef81aa2b235814f410bc190bc1d3c4c41a987d5a4beccc0fcaa6cf562b2e802f50701b522f51ee9225cefa0c36450526c6d70855b45329e329e +Msg = 563dc6df2882043efc7428278642b2e47b2217ed01f1cbad64199f890ab84d1fa9ff51cbb7d8fb7022cbc3754222dc0d0c4b0cbc887fba1785a149cb8b69a4e011c11a3ff06f6d7218f525ac81b52a0965599216ad72b894a95f8e7903713438f64dc942bb9181cd44baf7d42d45c55ff01453045814ecae381d179d5c1924ae +Mac = 93bad5ef741085993a7fc789c4ab1246cb74190a607e53ab + +Count = 132 +Klen = 128 +Tlen = 24 +Key = e21efc602d0824748c60fc8e96736c8618ef3a96b5f4d30ccf6e4942aba398d0cf082d00af59a98389e8e2628e362a3742c0d59c251bf5e493436809e93115e6e9ab72a660604a7d0534bd96a5d9884c7d9f869ce88d77da3ab001a4ebb3f415f8b0d23a86468fcac8ec951124840b2e9134577e4471e1588b5c1afbf952bec4 +Msg = 6db044e59aa24693ab56af087e875f701e64d8173635502bcc4204c22bf0ce1e212efa306b0f565c6eb8887c287da4276547fe3336393d789f93b1d790d6e77c16297a5fd3fb2b11acea34b5c1e3da4ca28b4237c0de85f62116063658cf040bb5686b7ab9acf03accb25cbb320128683cf84b2abb6e502dba95abe66d244d55 +Mac = f08474f9d4b98f704d87dc646019649baecf154e47eecdea + +Count = 133 +Klen = 128 +Tlen = 24 +Key = 9918fae56359924aeae4d6111bfdc8c3ae8d7ead087526d95f22473c1f614a318c753826a968c595599e8e37c5b09f74fd77381de266d15d431d5bed463cc9880a75cf9f8ae6e94dc5a5a08d1c9c09abfb978ef8bb9bf0c2c77a8d83fea4df59594046b6ce7b07597420947de76a0e50ee1608a65bbb8eef335e65660f41958c +Msg = 2c46d9a814f4d8d35b0d042524b44be371765034a0c4103135a7c53bd9af0b91a32d412197a1329f6c76f4d593ed113a7458e5c5fb88470353886c68f18c07e3d524b5b40cb599827a2a43a8d6e7d7d1f6fe6bc44da6b081b2e9d58c629ca8894994ff097d1756a40c91b948f788e5d07ed2aad89e0693d0d930c95035c935ab +Mac = 6a7ff320888a5e69c9116e4fafd805c83396d8eafba87f29 + +Count = 134 +Klen = 128 +Tlen = 24 +Key = 1ae62dc371078f8d84baf9082bbe3c8ee5ece05e8519709f283e19a26ad77468da889f64ab069281ac35b0677a8e9dfaf3c45024efa769d52b48c448865e4e8770e817319f14a97b03609975fdff5b8fcc7e5a5b48a74894d2a6b3608b6adad2c44ebeb3b6f97c827382d9b91dd81f525662288af7e2b8e5059f1072e1c3bf50 +Msg = f54b64fa04379ca25e753ee942d8205ed77f382a6e0605e908f92ab8188e5d8f8a937fd203a50c226ba3b679a9624d76ada2e2f5b4412ce3c7af2b5185a20ac6230b4adab1481d009f9b10a47fdbed760c69e0056c66d88fb2233017a7d98fb9ca9b0d3b958897e4024594914eabc805fdbc79811edcd194d03e8435059cb30f +Mac = 42e2597c6bba6c32e539294bc4842df8cb3842c214b17e47 + +Count = 135 +Klen = 128 +Tlen = 32 +Key = 14161340bbfa1c4780583796f70731d202eea44297bcd428c3d9d752ef9cf9ec63be5e98080ee9c172675d2b1ddfc2cff7420be71fbff545ede032e832c0c7d1c178b3132edad12ad562ff8d1e698087009c9f42c4ad95250c48ad5f1349a6c4362c59d9b4c49c2ab23065e4820c339f24e4a97c0dee7c7028f890df1b9f5e6d +Msg = 6f24fa08de5244f30173809f1a141a9e00ffc2a9145f07e67726276b7aac25fe56981d1e1e04d548f1dc9473748737dd7fca810917e9b3089d0f5cf944ef73ccc9aca34b5ef6e65ae777557d686d3f9cbe9878038e56f3ad7c0d93c29dc93f5e2e2635948671a0b3490a6cc7df0c596324304e9e61eff15c7ce774cf6b80b13d +Mac = 642abab13c7678baa4460e4b6dec2f4ea84123999576250c98006a8a0a06eb57 + +Count = 136 +Klen = 128 +Tlen = 32 +Key = 8bcd182e78a9dc1d38ff52958632a22b739e0641aacf2ed8f8f1e4a50c88ec667b622e7607c9179f20fd3c30abe1405003f4f8923d83cecab11d631eb5487960ac720f9b402acdebeb90a392bc0aae4958395bd43f2cced950d385f290b6380127e604c4ab34c9a9a1a2d1e34117b2bd7a57752e3631f7aedffb9049223bf3f2 +Msg = 803b54a0a9b44cc935349e9d99af7c5aa600644eff8b3c9dd021a03fbd247b4819ebd46c5967ebc2c80785c87cda84a888f4bab97312ff49e981819ab13b5c2adf546b374b945d8341660b557af008c04b847a271d3729011dcfd6da35e3ce9a3a3dbf0a6783c9940a17d84b7d3b322b58794ca1e542e24ed4d546083062f921 +Mac = bc08205694fe5bcd786c785a0731b7b737a67bea10528bfa33448a7ea93dff0b + +Count = 137 +Klen = 128 +Tlen = 32 +Key = e4f9334635a1a7e89bd037227007aea379879dc96bc2feb8ad0f17aa60a1a1869dba2ab3fd1cb82e5fc1afdae5cbf41840be53982eed1e6f40321769e1e290a09400d14d7db1badf23f0aa4a74839fa20a2e9ee8ac26552418c8ffb3ff8b88e35234f1bdbc49f72270c7ef1a2417f5685d3f4562ee56e9ffbb3a9532c385cf76 +Msg = 0dbde20650041f568722bae9e11fe833d02f5d2355e4b4fa7da3105c2c5504a7195eb0851ad32dbda2e72c4f87a7d9bf09e806b1117d85b6b6add56605e402af02a8c66ceacff439bbef1686f61755eba4bc9abb97f6f3dcf2ed38d6ec8dee29d0826be448603b73dc21c3b9b6d5245fa895636b70b9c6143a4b81d466bb91c0 +Mac = 1a14d543d1889cd3ead1ac7743944b24f55c30d1f41b220de2dcb4beef915edc + +Count = 138 +Klen = 128 +Tlen = 32 +Key = 5dff263e3e98e792b8035e4c74531b472d6c4b8e12cd39cf6cac150c8048f594b77b1932fc8e73a46652664e176ccf3064f142163633960eafdaa31f11364a38dcd3b667374ee24b91685bcc885948090a67a792bab6d9d8956261e2d5cbe94115308545b7803c71836cc52d90c18ebb68f5036c67ff0c14646cd7bb94b0d995 +Msg = a4f311c6e485a66d0a0b6c4828dcb677b722519f93d2ad8147e23ed28bb622460bdb04ef6af740c587004886ffad46c0f32a032b0b10073dba9402f9c4ff6a08fe5e660a557aeb2e120a24005d281883ff0287806cd2141d0010aab189e518d706e4fec2aef5edd03491ca614a3573e96410a544beff1e4aa0bcfea4e15373de +Mac = 950afb4f2f0d973110b4b4799f6d9650fdfe55f6f5e47788dd51566d3bcbb454 + +Count = 139 +Klen = 128 +Tlen = 32 +Key = c5317735b9a564d1fbd62bac1e999e61199a09174a4d5e10bb278f7fa30d3c9a300d8ef1834c63fefd3fabfdb91e11fe5996df3806bf1ba0b24df6baa00a68af278414a1b302713b0cbd2b8cdb4dc7156a628720abb48d547c3d428729a5f9d332fed0ec4fb1d7b0b2b875008c0e07cfd264c9784116fa55a05d3b8d45c6392d +Msg = 07a5696fd7e2e98fdde3edae3cd04d5728988e0af0e306d33b49412191c1a4d61e5c509bb3334a760e9dd89e5ba62e8efbbd495883ad1c3c08cfea799a7df3630ec952b6016f262a1909f0478e823c7be9cd846a0cd7518573baa3deb933933a5e563768c780c6d2868efc52dc4cc0477c3005e79249eed7047235f9f8cbcd85 +Mac = 027e540cd7894b2043f77f52efe05495a035c3dd71bd1509036bb6b663818535 + +Count = 140 +Klen = 128 +Tlen = 32 +Key = 383ce7f3187ad66c1d5c982724de8e16299c2fde0a8af22e8de56e50a56ac0fef1c52e76864c0ad1eeedd8907065b37892b3eca0ddcdf5c8e0917dec78fedd194ea4b380a059ccc9452e48a9eba2f8b7a4150b7ba17feac83c61604c3cfcfe6655c2be37ef0ae6fc29072f9b1cfb277b64a8d499dd079ad9aa3d5e9a7ccbec8c +Msg = e3171cde18158c8e46172c051f11e80b9d2c1e19a1d15d11da036d2de8f38f35c1ce05f654dad5ef6dc1cb4dd92dbd1aca9412b17d568575190527c2db03a3247053c6c7a2a93f2f37c3a32916fcb402ac1fe2f68e7912eb60329f60f5dd9ea0b74d673b4aaa51b66cc5bc8220a9552b0b7395d21e638bdd7532dced7fa60810 +Mac = a4ad6471d8b0566987d13323f2afba3bb218c71f43aeae38ed5722a60e8e2899 + +Count = 141 +Klen = 128 +Tlen = 32 +Key = c4d6c342e2dbd2f94c2c758a6c951b38c5a1f10a92afa87eaa48787ca7b0658947bbc13d13e2f2f73e9675cfcfd523cc03fab358ecd981f05f0b8d200d87c7aff0728a17e9396637a7dc224cca8d011e4879457710e6f2d9ee7ed470afeac34685a326b6ad05b6234ea685eaa5e53e945fc6ae5146fd83a220485455d402e2b6 +Msg = 5404e7d8e805f4c2343b405a3eeb08b5527e26163bdfe66cba25161b30725cff9e1acdaecf08bafed45ecdc8b15c55eb5683df93d1fa06bbc1308cf00ec3a958d7a1a2f4ac6d9e22fe24b666d3004b69be9c9c420f5a97f54702f039cfab717fe9df912fe6fa47359ad320bc0d9e9039731185ac5ec6422333e16b7fdaf25c7a +Mac = 0115eecf3b9f368cc10c439b985accf2a1b251d74db0aebe3a30f2f0797ce212 + +Count = 142 +Klen = 128 +Tlen = 32 +Key = 85afbf16eb940e704877b4d16a8284d450451bab31ab0bb6c12c3954af4583fa7225a68245aa5fc5708bd16bcad727027c9e7a4e07edf5e0890037ea3cb4f8523f3bf0059913f48e7b3963e7c59ac08fcccaa0dc5af8c793f7228eb66785889d74586448eeb915f4efe831ec63b397a2c83155fe33b3c9f694f8065f3aa07803 +Msg = 55ceb7328ec045967807a80790b5f55b2a66aa1f6d2edc2c9fd0927ba3316c3bbf0c8820a3e6a5fda7458995551da1af278be86891c509cd4252c8a9a8769e9cb2f1a36dd9e9b2a16124c74ddc7aab28f18ad4e45bad86bf34283f5574a652b8b5e5d2c239afb1aa2d0c29d62fb65bf00fcd373cd2cc9b29fdbcbf2610a7d0b6 +Mac = e78a8e4d779521ed3169a7f30ffe84e8951752b6f8da75ec5e024ad00345c723 + +Count = 143 +Klen = 128 +Tlen = 32 +Key = c9b74b2ba807d65ae62728882a32c4c0a0b2d9019fb50ced8a2477c5f451f29507cf91ac26866e4fd106a8afc91cab1875a3b26a859d8bcdd5839aa194d921b4a504bfb8456036f4ef8e71397c0bc5188f07775230747e90b75d8b54ec7947306c00db364fbdb6af07658a108b279829b6842ea0e9616e9ef85a50c8445aeb71 +Msg = 1435f6f716806114e6df17b4fef3089a61c1f413820675e161ca4078f738a86dd4ad642b070f91e83e60fbd72e93989f359e550d3ed01505e665f7bfdd58d8308e781ac502bea35701de285c7b1cab5a276142a26a8e1b3a7a10bd1bc3b5909c8abda02fd0359e4b798028a9ad3749b37f33443acce78d6766f319f472f7d79b +Mac = 65bf092a7dbb8cefb9f05bbc8bc863b45909144ac9dbf327f3a6544e4e3a37cb + +Count = 144 +Klen = 128 +Tlen = 32 +Key = 4079ddf786334e067552706c25de34223844698f0db38e0636c7e4912d65c8ed42e640d5d877d484d1bf9f7547c3a56d7d0767bb15f6b5be8384c4a9c11280834492237230eb0738c89fb8fe28ab4e5136affa6ad64edeb25dd82285492644362fc6af54f459902c4038e58f305ed6d64b824922b883b1e9ae0926ae2b6abb0f +Msg = 8d8e0812bfcc18ca2a17d5f8ae9f42e77ca1336b293003c4023586c6a0b53e37bc52d2794415bb68ad6a41868c6ca6566063a105b28b0e4f6118e3a13776667bbfd59d195be5065291de89c0a6c4ab216ee904fd62b3f38af39f90cc1e86e2004120533b2dc6604f7c7c95ee252eb9124d3a469b602f1c3a61d4758f7e6d1c8e +Mac = f4915ab7714e2bbc8a7a1f270768fb405fe2513762b2dc02c35f6c04fa957940 + +Count = 145 +Klen = 128 +Tlen = 32 +Key = e0ac3f5886bc45db77b92113acc632721b14bdb7db6b341c8806b8d1e9a4dcaad0dcac1542b1ee4ed866a7d66594e121d979ac8e6693639de16d305d6abad2234fa09e812e56c4765af1d4e3807b813e8b46a48ac47f84873e065426717dfd3f25a01e8692d451bcc502b12245a59933f722ae923f591f4268792b154618e467 +Msg = afc595de08e9de221a59d897d5180af3282700e5184cfbf90f12e7bb76118d1f856f0a205aa780a849890bb07483f7a89b1e301935cbf989bfe0e19f54def3877ef52e984cca3534a47747f0dbd370f583f501a784f33f846fef584e0e559b6c405ee78e03d96490d32a72a13393dfa489b25dd62e4b33b1c6483211cdfeeb96 +Mac = 0d9556246eb7d1c36640a11584cb1dd48cf5adc66981a24b81897d1db68f0b62 + +Count = 146 +Klen = 128 +Tlen = 32 +Key = 0bfee65c1f56629893be1addc27564f1e81c6a2d8e5f393849d81415a4300e605b88d8d4ca17d711a414799ce8d6ca28113a42148e45e134710a7fd46bce5dfaf86bffecd7f23ef2bd94995d4ac3ccc83c94a49ee36811ddd5cb7d19e29c5cc34a6f04ab2e2fbfc445081f27d083925bd0f336d47611efb9dbe3b6ebf1e23442 +Msg = 40498dd91b8f781e78329ec1950cbf8de15e6ce403c124561e5fbe72546206db89adab9f69ca59c5ac2422259877227dc88463c02d09feb152f083b1e4c79bd57170ec3c701a3da08270db2af70f3b8b943ee04893d97f55ec8f62e6d34e0a8282fa185938656ed7827c9179b9be51e0ccf3ad243f1af16a74a321b92ade9a09 +Mac = 1f87f065d03d36b93280b6026bf48a834da01cfafa12b90c7771377f5d895915 + +Count = 147 +Klen = 128 +Tlen = 32 +Key = 42aecfb0ed85032c792b74e759945c06b1a7154ec6e32ce5b448b6585f75e7e2ab0ee0ecf060c9d0a84820e26b5050b11e1c868a6705c03e630327259cd09e63354a9b6a681a35c133937f034ddc152a5f52f40d71288f28a2501f9c1d9f3a76482ca7343ff9718680d53a51e880d2f9de1108e0ce95c02ad9f946c4ca2ae2a4 +Msg = 504ec4c48effad524dcb70d3a2816dc074805a81dd84cfded2bf07b6072ce5f30d2035bdbd2235eedafc53c6f21239e185f307656a2edf806d67a7123da90aa686fec0a75a3d10d1d52493e501a63aa1f78692ef4725475d9a99e8cd96fee96d0211eeea2bfb47e1866ab69796e679e9106384863e120f5ba17d504fdad38a31 +Mac = e6c9f32e14fdb19600870ba8ebf650e40a85fb9a89ce7b48e7cb7e29cfd6007f + +Count = 148 +Klen = 128 +Tlen = 32 +Key = 03aa9b8a2aefdfc59f5c779e720e1eb64b60d3d75c0b7738949297fd16dd87fee923b0c9f10e2aea1e1a8e6ae33f0595eacfa50006a1fecb696fef24177dbf0c9a7b685ef7ad360de24991ad2e2117358781ef03635b592036a189c6e5f3b51f7e7a6d5026142bb653b12b6f3bfd7c1d8c3f58e65d80b1c064f10ceb6a8792be +Msg = 5619fdb97cbf05f4174e787d13d2be6f30deb3835589a03228b76b1adb9a0aa348783de241ae7dbe21f52f51a7e41e9105b6282f334e38bf8978741a8d72b7000aab410262caad9f24f224aee144d1fc3ca6943541c3fb08f8536e86399da9cbc13a70e1861b7de148cebe5b69fcbdf8fe37605e26f2d2549bd1c1278624ca4c +Mac = 09628d811b3285dc5349305d8fe6a868b0b9c5d9eaefe4c1f9d5de250cc753bb + +Count = 149 +Klen = 128 +Tlen = 32 +Key = 28ffcb22dd9ef0e43ccbc98327f4d215a80520eb20f1a5c4a18db04098a5b398af4a498bf169779c2fa2327aa35622c0d402a6deb9cc1857215c522e53ed719af1a4d90122207924ef525098ee8f2f751ee3c15213a9ca705358ac35ffa02fdcb6b6816cb6ec7ce6448428c34fc6819d50507a2d74ae4175fd2ac53ee5e576c5 +Msg = 096a4c817f20206bd71b682920fcd3fba6ad31cac6ebe0c4000287474ed80700b42daf541921b0fe55f7d0fa8b1862a2b95b75188d834ce37b0a0edd0c1dbf4c79e76f4f7812b17c568b4fc746863ca5f9c3ca726e0f1d100c0de0d2ee3636987e1ff43b45fa0d2b01604e56f84e4b4c8d6d99a111963d93db9565ed9b2d562c +Mac = c1e67187124dc3e16d3df7a39ac7cf2013204549302f66e98e8c3e63b237bd59 + +Count = 150 +Klen = 128 +Tlen = 40 +Key = 665812a554fe084339553e3cc29dfa8996362e2943c40568788bbc61761bb3c2c132c4cf1bded3aab2e2a6d1995bf7e875a3c8b97976f7799453124ce8256c0c7f23714639f53686091855d56183f77feb8b321a7a0496c340a902ab41bebcd307f3c113988c5a61a5bff050045d21d761b5145430b609d0e5533485682ccb9d +Msg = 8df0a3673278e26064cb6f688022ac2a0f2e997341b6edf29781663cdf765d1265029de768ba759dcb420c900d6df5d57ba503c4a48e5fb30ee6d70527b079647e91614a337acfc6ad877d7d8a272fefdc7e8bfb92072ba5347ef118d4fd9ae7416596987dff176371636937e09981fe9a7fd822f26a7a507110597ccca6e825 +Mac = 2031305f71c69ae3ea4d554727f83c7d9c485765968b19796bb0187ce04aa7410302e2fb09cf4b07 + +Count = 151 +Klen = 128 +Tlen = 40 +Key = 7108c0d1e115bf9d6131dc37052b760bdde7b43ad5b1828fdad1d6b63e6038a85e5a816a82f4e3f7042f297bb5ad40c17cc3f7ef40d1037108ce46336127511301ca2796a97d43d95075ddcb7d246a9af552626b966f454e8328e0718138cd94a18139bc205be92c8b2c7f912639fa7d8fbb7d169f36511091062cd8663ab412 +Msg = 2c723d78a66c536494cdf37da0e43e2e171a09c79dd5327e209c34b40a7bfa79bba9f151366861381a2dfde5d501b94c1427db667dff5534a12a52022cef0fe95fddec97c1b2c353117c783b7efed1d01b5588b58ddc9fb4064cf402782815c4025855d1af1320ba5f038b0805a42fc413ee383d3333b905384a433d54edb512 +Mac = 826a2a11380c260873663815ff5e02201a17dedca1b20c613d0dcc019095b444fa0e96c8b2df5433 + +Count = 152 +Klen = 128 +Tlen = 40 +Key = 96391b89b1d2d11e09c44a069c698901bc159fb5084034f29ae7633a822fcb81734ce231bda18d717b28eea70e157d3bcab65b9fee9ee38cda02818e7c63c7c20c6dbddef9207973232df06f4aa30ce6c6caff12794fd69803a2510c349df2b8c76654994d96beab679bf867385b5d891a193216909d369e7d8f7abe932573ea +Msg = b4e7da4b48d74985480b4ecdac6cc6de523192614ded901181ccca1d6d19eecd4704ff694ea349575c369a83baafaf043972edfc7e5952bf9efbaa38eb2e06890dca6af254b0c6f44c0b27b692d62fa7e79fc365838a03deab987fb58629a7e72dc084ae0107a6a541135e2ddce82d1083407b6503888cb4d22cb15ae714bb2e +Mac = cead49b07d7a98bc40e3f9e484bb562fac1bf5296f6456f22196a4570924252618cbe524a249c477 + +Count = 153 +Klen = 128 +Tlen = 40 +Key = 0ca2ed9ccda936e0e5fabd1eeed393b4219d516a767c59a40c245eddccee27504a2b8ff8ebb8d1bb4dd302e3e32cdfcde03fc9e557e20ed2a01a6aedfd33cef87d105f0d21bfc2d43e5097f922e843ddfa11f38cf454def0a00aca449c6fd1ca70f865c1b7e79292801c834af32e484c38bad64894fb4f67d59b84c8f1c9b930 +Msg = 4f472914ce9cf0ac7f663c06f3be53a1c2b1a188da40ad7816ab4b4113f0126e3f8e1028328ebd5842c42e0c51538b1cea6fc30d8d677e3546e2542084683c332925478fdeea8e39a9756877c1f2e17da1c268485b7ac8cb2f2f5a495cf178023695341179b84a95dd00540feaa53d0b0e30f803ed837280f81ac5824190ae22 +Mac = 5dacef52a951847b5b26922bf7cc74c4ecf3708da5005615a6df512fc0edb1485bd8efb840c90fd0 + +Count = 154 +Klen = 128 +Tlen = 40 +Key = 0996b05111989bfc10db56819c2cc6464d52e95dc3fc0211ebf7f7bf7fa4f7e8ccaa5f83b8e8df9803aed90acd2c09b5592a6bb810fa5914c9abf4774780c65203a0a6312c0fdb4ceddd8459ee9e37a51d1ae863ae450c446071ff4803c2a3d337e24b0376f7d74155d220160669964022882706a5c363c83bafdedaba52d693 +Msg = e0ae386c4a7222433f63230fb8a59742aa66c69b2e712155e000c99e84d2514af07ec5c92607eb56c0b0c87291126691896bd513d9397075580861c9258868638ee2d8d6314ce21f61dc151fcc99264f5ad8edaf58c6b1ffd541a5324cecb2208482777bb56a8f04ec8c12feb0645ee3e6541757f23f6c5a1f539cc14126b9e7 +Mac = a93d059bd930f765514c55d0013d96bfd55abbb0c0432e898bd20266b64605f07fb9824f6c50f129 + +Count = 155 +Klen = 128 +Tlen = 40 +Key = 4f36c18e476c006a2d8e603e12f719738f6f262d065da3202a387aa5c23f3e0daa6a57351aa0605a2a2acd2f9668d12dbfc27f2bf3e22f2eee202382a13e6a0a325605d4431049f07718848332d0e317a1429335fb582736064f3a56dc69550aefe213944b2682d41b41cd616f9718d83cd5ac74a42754df78ac0648fc27c6b6 +Msg = d32f136a92049bff883fd5d1d649162da47fdced7032bc9fa5f29be3700c2115cf516b2ceb1900e2a78807167910b76e79370e40b79bc6b3d2338521c6d754c006035282cbd8a939ab63c2ff6d22b5d51cc4048a5a3188dff7caabe8c2f2d8b59fcd3032da477f4cbb596e555b88faaab5ae249300fcea6a3d4077000c64973c +Mac = 42311c23850d5e3460fca8d6870127d01ef4932ca6899632b92c895c0fcbb44e03abd9e5e753b983 + +Count = 156 +Klen = 128 +Tlen = 40 +Key = 3f318aa4d4fccb3758f58d2d05826c40fc4d38902d9af99876d830610f7560f525f7cd17c5498431fc529b8e3dccbac90254db86b6bd4d5fd3aaff22485cfb391dc8316959ed76c02464ccc82939e4013ef9e18e470c5f2f5745b46f19b8751f6fcc3d025891a9ca1753a743926ff1cff865d412a62f36ee4cd1d7b24b32d78e +Msg = 22d3f7d1a1858d4cbec9324a3e1dfbda03abfe12dfcbbfaeaac8ebfb92e749f4b3a5edaae841afe9e07adb18749a2a6137b3f1124f29994384704fba9717fc0bd5067803eb04fb47fc7cd439f1805d1b110e2e77d19291beedad362fb73528faaf7d00a655d659b03b5583755ed77c51b6431b090c0f8f660c0608239b48b40a +Mac = 40a610d31345105029767e5843d46024239d903a744fe37ac4acc7a984330afb3e388462db552d78 + +Count = 157 +Klen = 128 +Tlen = 40 +Key = 5051b7f8c9c7e9e1d0b55d0a05426ef23e0132e6e5c5fe759bb72c2521a51b64799d78c148bbbc5c7f3ff69b3ae2cb1fe96bbbf7ad7da61305b38efba9ef9ec1b6ee6b330c207b56f4b7041007fef5254bed3a659efa3c235831a8e82c8772694f6c19b7dc9f2cb678460dd0323ef5eaacb0389780e5cb8cdd5b035571189f46 +Msg = daa147d9448d45d7a0b362127cbcb318ba4e57608930078b94afefe97940bc3f7c66f7c87dd6917927dabf896bf308312cc29bb13c28e79388ad66338f1eb97f197afafc25104e0a23e1b968634b37facee908cad4b54b4ea56fcee9a44325b318a6f97d2581a310fc91f9b64e0d68fc068a44b5371d5b4253bfd0119ff52764 +Mac = 4aec1c3858a3ecee3a73be5211e0b12331a502c4b8dfed805f0b2ff6fb14167eddf5cd2fb1048ccd + +Count = 158 +Klen = 128 +Tlen = 40 +Key = 7cc8dc6957f74970997160de77a2aca2721a4af337e2f143c3102f6eca99f5385a6756f6bcab8c8b9b753c966782fbeafc54103f7f887b278965374388b1bdb662c8c9da5bef603238e512a0a4bb7dd8d4e6121567931c0b903afd1c7676bbcedb14bc7dfc69ce4db9e96b63f6f63a5541f6d8deb5a8d9d71eb80a625e91f969 +Msg = 9954cc20df9ddf553407ab15c6157423a2b247e9d5c83ab2d10ef519132271c103d700471cd08e754c4e26b99e46b8d516b719d7dc3a4b4c9edbffb12f27582a7486f27780cb2323fe0a80fecfa9a3cef5ba2c42b0880627e670ecdec8f32b0eb309a99654b726c610e3c2cea368bf760766891097dbf3ab7478c48a28ad72d5 +Mac = 9a23a86d0a12817e32816a5ce93c9a0e80f01862d06c5b4d53d5e8329202d30e5e3d0117cd44951e + +Count = 159 +Klen = 128 +Tlen = 40 +Key = 06e7210def086f58b210a7010668e0d25c52a4421c1f4f4832a3b871c9e61331561c1676d9d75b83607c06fcccf3a73dd7a362f0569e4ddfbc181906e01ef5ed0085af3505201c700836bb3616329575309d6708964a038b46d0f46ebf3d61490a09346ffb497ac6b5250dd66c8c711f6f27fdb0658b3bf5d6b291d1eeac20ec +Msg = 4b1a16d7a190920c470b13f5916893f06da3af78849a5b018213d423b101d6fbcd0310cf142ed5f09c0c14e5e9e48ac5bf3c36e5359d0db30b96f0e23d03dbc8d8905f040d7852638493c505f38f36bbee7d07b401902f59fc2230758ef8499915c7ecbfb5f7722da7a60e9cd4f0ff9aa36e0a2d0ffc28b9fcc07c23cb688737 +Mac = 4121e1c375037dffba6eb6814d1f512a81d6009cce96562ca1f460cdea0b8a59d0a3e3c1950f554e + +Count = 160 +Klen = 128 +Tlen = 40 +Key = 1731bef761d689a566db84e07996b85523ba1bf7197f1c476cfd7dd300d961fd3f24a6fe0e80742b00851676ca630937f8c8532dde0416bfd06b658896fa56131a3e59e36472c8b7c8e8bf0c5eaa2de2b3602bc3be748d021675b74162b9b335104780ae4af3acd125cb25a81cb24cdebe4b4bc3a319a896a4e41b044b5e9dec +Msg = 2726877bc4282dbda4db6564fd25c8bbbeca5cbad39affd7a5e8091ee13d2d847b4ea079f22c7dbcd5bb69738665737b3e0f3dfd514c6142b4d10ec8bc2af29528ab5dcb62a8a37d02e9c2c1945844069bfd67a8d62c7cc2c1fd8d445ffd42453723059a9c0665a7324cb875ae660505dd7b21e4e8a11700d653cdba5220e53c +Mac = 61b98a431a1b55c2652520f2181594ad39273da29c4ba1fd7902af99d234f5cb24ce75f41bf0a5b3 + +Count = 161 +Klen = 128 +Tlen = 40 +Key = c071c63d6574232cc3183b2171ace81bbf4cac24e16df5854fb69f366b12bb9864038f665b39dde9c563696c1145b5f08a0a0f217edccd88a0b3d801ab6a677048180db0329df6cc987b6e72c3e8a2a4f821abb1a000c864a6d1eb7b2162785a3359490130caf53c03095219cebd389fd13688bd8d016d8129b9e28b141f75c0 +Msg = 0f66d0b45095ae1b59fd2db7780135a1f52156f8fd1e5d29df5f256d7b94b093f69976ffb39dfdf37f83aa0d0c88d711a12726e90f3a14eae761d159eaa74f2ec1639817ef5d66c00332ed5212fafc3a6427442b6eb0f76600709639c0c904c5d78cde05ea1d0f0c4cd29e8e729dcba2a7eb5bc600cb302493531c14e43ff7e1 +Mac = 06c3568bfa7c4af9d6f2900c80afd15d6880056bd42d38620fcd956d36555688f2634ce632bf2006 + +Count = 162 +Klen = 128 +Tlen = 40 +Key = f5c15429b2ebf430282b8e92b0c76162a4fec17416ec6a65c2ad14db42c5470e81bf7188721536290250076d4b70f6f20a8ec83453c04c9b833decb977c282ccfb346d8b8586e31f24dd886fb3f240a052b842dc17406f5300d9e1802c7bc6ae4b666fba5406a41a761a3b1e5015e97664c457f5c932789521c91bbacbb9bcbb +Msg = 1c72ecfb8439d9ae3ed4eff8fff3aea771692ec3852f11b90aacb6b87f33af5c25ce768a593a5b9b2132c1bc05f18a9420f2d02876fad6fc88583e7b266b7c9985668ab79150ddc7844f99b0b82501f4b9fb31909f5e0f249b877f53cfdfd66d63c2924bd583487b90b1dd9ec199f90d660cb9c3a763a4776abfe1082296a71e +Mac = f5dca0801674ad8f4654f195437367b1a9bc5afe198b85bf539898c6fe946fb0ceb19f590e68aa04 + +Count = 163 +Klen = 128 +Tlen = 40 +Key = fa90796c79d6a728b50d788e35b9345b109e5f8f9bd3821d44182fe6be693fe85fd45eb3c687ca1dc02d57376d7bb7809e05f85882574eb78241131e69720ccec848ee3999e720b62289c3781c15f0c115f24053131d92287a7908622f675385fe9731e4391e3359a2c8c4398baf67873c0c4068954ed6d7f569179a5a719d75 +Msg = bf92a10983b14561f1491d3b837724b4ad7105d91ebe847544a21a280edddfb9f595aead3d90831978a627b44d761030775982cb1094fb2110d2ce4411d10e0e555badb60978e5a2cbe2d77c6bb97388ee789735d9287bf2acd34c42ac3c1713e5cde94c70d135a5f2e375bb65a614641bb78c3fffe0cc901f8fdc4b6786c36f +Mac = 8dd24a94d6dff09273336c22b17f2bf5a040e16e08d04dbe191d8ad084ffa4e52abf6e8111c0b642 + +Count = 164 +Klen = 128 +Tlen = 40 +Key = 733abf560d9f3733e221f37bd6219ebd8cc9889486a0f1d68e5b830e55f7202d5b04de7c0e4450d536740813906a59c7b960622d4e90475e5201c2c6d0a0dbd9c192f3022fc907dc9bd533a59dfd75f0ca8fb499da7401fe0b071c6cc0283ad86e8b05d0b856e5b1d9ec7e1943037a9f85fd88c27275a42080189ae96eb6c592 +Msg = 76556fee3b6a456a0c64558a00cd88df726730c85428f796c58315ede6e9c76dea90fc926d7351d9079a3f25209b936006611f653c2cb01e16d940e982646c4129ab289ab774b18c76b2c33422040dd8f97fe2c911ad318eeed5b73e547d732e5a2e5accc0774dcb82344881ad11dc8d7249dfbc79b4622e7800e3b4033ec47d +Mac = 4213b34ec9ead8721f33585d1231393b38d1c1fbe59ddbfe2f2f2206910e38d1c964a71a92959f3e + +Count = 165 +Klen = 128 +Tlen = 48 +Key = b619d9d07461c11bc9fb66117d61ed90001366bbffdbff583556777584b0d65244af5c7bdbf3b7358d7c791b966cc809760e57398d1896ace72d26cc59a6904fcd92365edafb8af7986c7d90b2af3bfdbcdb1593c78fbe8e3378bbb0c519152bf9cb51c19a02a12a8fd35cb6f8b3ac337a828711d6c8e0c4c13e1e6af090cdae +Msg = 5a81e711adfe5077dd8c8b57c95e8e1f3de39f4fc448c523bd3e7c72b1fdacd6e489dc0d2a34a39ffc6460c1cb962b7a94a30c04b5426a75ffcfc69f0c4ba934d3a3da2e7935d56d6b9079a2a97b016d653a35c2cc0ce19124f887a617c951ce4e58493b4209cc294f983cc20b16f63fd52e8451b1ad13bf5342275079818deb +Mac = 8b4258be4c094aa4056f332ede8c733772664b088ba22ef8caae7cefd77eceb35e83af8d9c1283cbbffe4a372b699c21 + +Count = 166 +Klen = 128 +Tlen = 48 +Key = e48825a5503a6afe0bf9a240c67f27acd4a8f6993834645e03c80c72dd370cd2e10071a3ae18ef19bae9d697ea9a4118609190cd95361907a7fa1b58f499f3f5e79b935f12212f437dde399e3e6490244aa1f5e38ba9be2433b6ce924f6cc49e9f627321a5df9343fce1b59deb647d9a3ae00b234414ba7b4e020d67173be693 +Msg = 8561865ac2ce12832746f82584a4b98e7f4c3ae2410e18196f4e3b475c62ae207d3cadbb1d490096519888db2f3f18e13bfb86f62216015cab8ea491ea734cd3b791a7e45e4f8e0b98d7955bba77e0372d4738161e0d5d84765d9e6a0d05a88e1aa89c5defa864e9e349462e8f14b9993d7a78cb9dbad69aba0551582ddf6958 +Mac = ec780a915ec7deeba2c8c9e2ab15c9762a3eb18fafa2d48a554ae1fe6c4459da1a54e2d58bdf06fea0740098eebbb699 + +Count = 167 +Klen = 128 +Tlen = 48 +Key = b9280949918c582fa63ac4c68cc7a0e74971435e08035aef12f98397f9e51713161146a736666a18918c95fafc536c325f5239b368ce3b8b81dd412300ca77c29ebc7f542b93c36a80130a81b4444a879318bd9b4b4f37156998b7c604f93c813870dad9d7db0c2d5a154ce21e62e1f0cd0df9a0194ff794b1730e076d380f56 +Msg = 9b1d9b8060067187f19e09e2bfe17c11d0092dc1b7b25b06c43bf2e5786fa7153b65430651a43f230b8b92553af1c7c8e90852f14c8724d0f3087d7243ae02bb270c0f6203424e3dea6989bf1032bcbf82c96f7a140042dc9ba9cafb5d439be5c6daa69b5d28c65df600952828ed847e01162b65f964ddb225e78087ad769b1b +Mac = f9bf35de6f3888828b0acf7da8d2a8848c292a5ab9e6e2e3475d665d398e5ab424183e9beb4db0d7accc6315c53bf0de + +Count = 168 +Klen = 128 +Tlen = 48 +Key = 1dd0942297cba8157069925114b832018fe31f35450ef6e2e382f22a950abdde7a9c8642553c5410851e9abf370b0b04da05af9ad32e373f72e68eff2534b0b4ec67bfce0dfd545009c3131bce3e826f2e4a1baf90019f64e6deae85df2295f65d77674e29d44fdde6a024ee431a3e4975f888fce54ed75b25b27a46299e13aa +Msg = 8428a75382510207600c10573c4c0f6056a74a0b7cfc33d7c559b2d9821cbd017258299e357abf24032c932d9e7991bf853259cd6b914d00e71de7b76dcd514c7d702f991a4cbfba7e0625150cc20098868a414280f43de515ff012ad83fe5d50d3a644a1a112a5038636f166e6e8474c077ab72a46c2c0eb5c9a53aabb8a225 +Mac = 8d032500ea94fd8686b465634d74047db687a1d1e56fc17100f40ea0f7e3288efbd016daffd5d3c32fc6988996292788 + +Count = 169 +Klen = 128 +Tlen = 48 +Key = 3dc1c0cf6978292dc6389fe87e96335dcbf493165b528940f867c45f68f0db4092498f2fe33a516bf01304d75dfb03f2fd8566093a8481acb821ae5e352a4d90b4ad08d1dac65c3f98b554410a3398789f07a7f27bd461a11935c80c350b0745e916b41b16c3529005451a8e4ee7fbd5f9a1df38e4e9300964cb9ad22f3c1345 +Msg = b5e3eefd6fabee2f84ac6b7b98ca4493a1ef4e49410b49ad54591376c5e31ca4a5481a637ebdfe31e45226434e77d42524bedfa219e2a8e3bb0950db484628e2c462699f48dc262c9d2e7e750a5216e16985c735804b93b58fb3de8c26dcda6d39b8447b76104e66d6c8dcd77365f20f99cc6dcb1f4cf26af8df255105ad1b8f +Mac = 40d43eb4671e6840050be5fc38c2709eccfcc47388c380afd52331dff3868227377550420ff176ff97088cbf9c5aaa05 + +Count = 170 +Klen = 128 +Tlen = 48 +Key = abcdb92d96bd11e85ebc4fbd6f17dc8417701e188cb59bf53153620615a6a7b8bcb4ad53231ce98afe49645144eb61eeeda84053fb0ea2abb7cdce333d23534b3a97efcdf5eab09d8c4b598180ca0733740f14b5324c3ce5ef70fe51d09e454caddd48421411af48912af7f72c9b177b340d64e73b55b2cb62a4bc09d7fec6e4 +Msg = b5ef6f15a59e24f357e578b50c0f6016e9c0b70c54d1ca42a15b19c9ee125c0b4bd5c5001f8385a4c70f91a87fd7a66786318a1d7d4796531026719ed9111e89811b39d029f57dcf08048a3955b6e50d671741c61b9ffdd3764eed468bfc5dd09fea53ed8c9c155c63ebebd2555626efd4996171f58107a819fe162acc7a22c7 +Mac = 3802d4c92f767fda5187cfee5eb73ae20b6bce00e8cfdde4879a0f8906ccba8a0ae3d4fb4a7f1188c3ae9b1910bd07cb + +Count = 171 +Klen = 128 +Tlen = 48 +Key = 56cac4042da649666fe7b1efd4f70f72b55435891687d728e35aee787a465be26a2bcd697a44e43eee59978e0536d39fc65d641bfcf819ac801123c8b605bfcf5a3615537d015fb6caf04dfb0e30a8d6f84537051dfcdfe33ea10d3bce73595aaf5563683dc601f88d139dddf6cbd83fd17473ef7e7c70f8a8737477c97770ac +Msg = d292a7d9a314845d0468665d59ae01891dccaea88b59bd989eba0d903c8adba9ae40d89d540b7ece9701a38a1e794f8d45b5cbc7cbc5fa60caa7ecfaedb3b136dd376b79fc5ea7f05656eed1d5b196e4b40cde4335ef3b5e97f5ec41422dd41a46bf89f503d3a9cb29ae6dbbe41e8097501911a233a12798ebea34efa5bfee5d +Mac = 375d68bebc28b9bd0d7108bcb9cb779df000d15090ce6b188ebd3b80cab50c431929ec374c693ca4f08654ab378f3648 + +Count = 172 +Klen = 128 +Tlen = 48 +Key = a797132ce5971a3a9152f0e3521f9de381406a2be0c53ae189ac1da7244d23205df66eb096d28b84d80f03d3103f2c6378ff454e53d7c206dd62e59782af8e2c4ee654d5a52fd48734cf496527945e3d9c7440565871f669b9c0f5edec29ef9760b1ed227b779d4c8bdced21ffe6d87bd7e780ca59597e11060d7631cc85ee6a +Msg = 30accaec827d47ee5aa21603cf62b6c3ee29331cbb7d47e97334c5c614e437231f9cc6989dd15b78609b04a98b2299b355529f1609d76ce151458c80b59664d65fda158c212aa4a8b9de5761530062314f00c22d45a86a9246539da0655a9bab76d07f6f166f68a4ecd1d7d22ee458676698650776da8723d9c6becd2d1823ca +Mac = 3ddf47cb13e49e5cf054bbcc073636f30b05dc9ad979a017cc8401d3f1f7f83e3034c41db41942a671b3d3dd706b3619 + +Count = 173 +Klen = 128 +Tlen = 48 +Key = 657fcef962db04bd269ae5fef2cbd5e6558d072946d235e8706394d4cd250796769a926fbaaa121b6da42cfc82808474dd672f9362756af252bd8cded78d39b9ddf4d99e24824844934fcf25d03e54df0d83cdda2563fb2be73b54b8b1c4419d429589cfc9ea0dff41a3b7c20190adee8febca47b6264e5bd8e8d4aa8552850a +Msg = 989d5d6083c85c2b09be202c60f1277b8c5e471fca623b812fd05b218d42ab8896ac177e4437fd7c784cec64e1eeac701f4e7e682899a419eb152402346cca50d0486c0df11f7194d4519448a070e68592de12d7579ee56ab9640ec27eee22ac8d97e375532ac15965f4a13e671ddea32c388dd31e18065ee1e5a0c93370bb85 +Mac = 4f1283e5446483a4f8237650572c8a7694d5f8e34086e81cea1f5bcfea345e33dff699a36aabaaf95fb2e0ec6e0e3b03 + +Count = 174 +Klen = 128 +Tlen = 48 +Key = 900f404d396f4bee526db4c9be701896a60d85bf1a203b15fb1cafc1189fd67d974a9f0497cfc2c6134bb8e109d70a4ddc59cf56f8a17050b4b1af867c5be8732f129635c6fa183e3741b64d98b2df9c8887b45bcb7fcb5e34312c13c8a0a0b6200f2cc80f17d8bd85f6b4f5b32a1ded703f3db7dce5d1a743452f50449587ae +Msg = 7eaca1335bbbc419f930bb7562b9090f50023d84f7346cec26bcdeb98e4d08e26128ba42209b9a3baec7d19ea8a704cff94e8624a870cc8ff524217da5e89afd9ae64d25a676beb1a1e39aeeb972a8d70aa0fc7d6fac6eac97554acb5be549044e6ec0a5965418c6fb0b7e2d3e22db6eac810756f2ef3a8a33d7c36c584bfc3e +Mac = 52c63558050e88a4a934d389c9d973f9901f2db74428d642a750b67d890910d7028c26dfe1e76010a9b12c95dbdbbecf + +Count = 175 +Klen = 128 +Tlen = 48 +Key = 3a9f2fb04c0c42b2dce178313786aa7713256c96c90ce2f2be53d5ff22bf054cdee7c1c1c795b625186f05e21fd7980d360fb5a1f5a1d30ba6feadecf965961afa060ce83f688fa76608b46cbf4375144575cb86d3637f3894d63cf5bc89eadd754537ad1c4b7640aef2ad567d91e995289fd5cdc9198b807024aaa2d1f4a99d +Msg = dce5adde1d996c50f9b061ff8777f9b0450343475d675596272bec73eef9520df7988580bf1f95a685624e3008b117f692c21a8c35eba5165594d05d67ed6122f7dcecb2f03a3fba183efd5dda3988844884247560b75aa88e1c9bd573642652e5982c9c37523134ba2cb5ac837914016f33ab2b65353cf3dbaa93059cc66a46 +Mac = 27808650572d339546aba818c11e07274bcbb7ef5b46f5a2917d7a7014e3ba58b5c162d2dc4ba6986eedc62a061b981e + +Count = 176 +Klen = 128 +Tlen = 48 +Key = 407cca4b390ceabcb37c48dde081d1b53ef41075ca30fffd71bc1da2c72ac02ffb3ead290b53e65834fbc382ade6447a9405a65a29ee340c3a83600fdece12776630403691bbbf9bffdc5918e83d1f480ee90030f0b29bc641d052af98caa04d699aacf9340c1e8dfc673126fb4f092894ea48828942dc336eea1a0d5ee511b8 +Msg = aea7ac414ac7b81df547ed95800cb443ae141cc731a2710cd59c10cdfc3179574abea690a1f39c3850323f6f87376a770ffe3fbc37e1bc1112028f3ddfe82cb6c96d1cacd1d7984908455638014da36486e3b2028a7c34d15f7428a029adf512937ab69ec0bbd5d98549dbf8d59486907c8a1da110bb00d325bb83ffc1c8fcf1 +Mac = a205326b6c4959d91bcf22e97ed4b447977e2a3af7e1f7db41e493521ab6a218a868365ecffdda6701ea4dee48e61bf6 + +Count = 177 +Klen = 128 +Tlen = 48 +Key = c8d18c4707df3ce945f3d7d58d39e73ade087abddac37978c2fd3643a2e04432c9cf8b5f7c4a9be9ec12413c658e5893c76ee2bc3a8e581b1e1d3ef241fef9e0556ee5a7a1e8a332f645b0d6e5283cd82f99392f7df0b28c51f55e983d45757c53f8c2a7dc80facb4dd44c2976cf390ffdd2a69f0bb12fd145cdbfbcfe7d5d11 +Msg = 09e7dd407526d478b4f6ff64e4cb92bde8cca38bbcd9254605cd193ced0003322d119b4e6be2c635c7e3c470b194ab14fd4514a23920142c3e6a6eb9050606ebbc3b99df19b7ac55efd3c211ff18d2811002f89f42056b199fceafaff3cb0cdddded3ebb27ad6e21534d610e7660f04b4a8cb84b7e8f1256508046e75e57fb52 +Mac = cae7cf6fcabf725e2c23915795a8ec62262fb7c7cfeaa93def9079e7dcdd7bfc82eec904312a588c03ee87c43df6f702 + +Count = 178 +Klen = 128 +Tlen = 48 +Key = 8dbb6cdc769851fbe90dce3183cd19e9cdd7893076a6fb7ee0a874d3dff20806bd32fa5a81e5245370ca99c8d5968a38fee966628781450fdbae8733f705b8347159b78ab9e71888a0d1c67916ceedef381f17588ac595d280f1204144bcc09eb318ed92a806f4437e0a9d6ed0dc0bb68361e33b07d9b16fd95a87254d7de7eb +Msg = 8dccd462fec7423d3ae5abf8649553170019058b4a8a05d6cc1c456f2fa3db685256b34e99d381518864faa4908144272896ab4420069516326fb8d1db308a5e6928f94554c15dd0d12dab6ea5f0eb55379fec6beae73667a9d04033c443e395facb0f0fd798bd0440c9241b4ceb30e955bc30ca4f35cf0f59c8455f92e7ce57 +Mac = 5704dc3750e47330ad7dab4910be0cb5f7f74dbe78f5c9a19ad718e71aea72171fa2a5dbdf7cb5579beb97930177474a + +Count = 179 +Klen = 128 +Tlen = 48 +Key = 25fb23a07e55306e77858cce34f09edf6b49dd8a74548862a0f097cfcc54f16c3699dfad8f79c1c5515600c7527d430b9aade6d371d3a82ebd18a31d8b1d82f5ec85ee0402b549775ad79f7b7c25d9a3c164348a65aef2b9dd7550cb6bc5b7cfefc936ed0091304d3b125234db6fc8708b77b1f7786ed0cba910842093d3fac1 +Msg = 97710070793d827315be46998cde98ceaa8ac00b1817d6d4d3ded806dc2afacf32553dfefd2d437d0c9c621b8189f78fcbf9fdbad57ade2d7dc188eb4892c47054e0c3f28e36fae6245531c63e1fd612e9b3969553da2fe93ea27f3daf48e156e65bbad4931f4fb74730da212967dc5dea01b421fbfe7110fdc8e5837915fa89 +Mac = 13706c202ea2e52d614c90dad127e72ee959023d9ac45d1c1266c67b63810d43c44067c36c5417fe8487980b703d8809 + +Count = 180 +Klen = 130 +Tlen = 24 +Key = e62c2ce5ff8e3d465d344582f2dd566e0d29ddd6205184cbc614563a04f524c3cfa328c7cfb9e9c363a75edde5f056bd2f97189e5ed346a5d60a077186fd64f36d41f3805ceeb324fe9b383a17890839091e44d19c958b37fef51bbd093f39a5c5ecd4372e96651137f619bf0e0e328ba2a7aa9663fe1a2848bbdb4517226b81e18d +Msg = 7ac240b4bde64b6b514237f122dd773a6adc2f2d8304a449fa7bf28ee4cefd9b7538a914ce224e4617e6660eced889f65e879ca2f440456b8ed4a149559b3af62cb9335089a0c60083d7f1592df96b822300ddd862c34f8e5dbee0964d12bbc5c8cc4632956a9ddfbf9c3e9be8470626e0cf5c977696acfb8ec0173f743a6850 +Mac = 984e2dc5dd3274865d0a658e1f6d2eb0854db75e1e02937b + +Count = 181 +Klen = 130 +Tlen = 24 +Key = 4bb97c7c53368716938c836519e20d6484a7e6a1bc794640e046734280b191080db7bc128d92540d93dd980d6ffa7717a2b1a2e29519e6de8abcb976d2f61392409e7f61dfe87155e08ada6fd61efabc26c87520b818aa52f3324028e92c0115ceb7ecf0af0285f660db7013b7183e5df73587e18f3e39a305ef2fe02d1b06969e4a +Msg = 4fe1a8510ab36b97c613d309b5b7ccb243b328e7029d3a88e3efa082acac6098a647376496c02d98ef106d8a46c754f006f4c8e76545cb3b976f4fe241d04cc9305311d44b95d820c6469c8b99d12f76313f87c965585838ab0ce9c58c12208655cfdea9107993b5b27c0912961d84cc2a5d0d94e9200b08898e133475ba0158 +Mac = f2722378f02bf8d104b3b50c77d132fa35ac86e4da34f1c8 + +Count = 182 +Klen = 130 +Tlen = 24 +Key = 9f0f91c95ba3c5a4a867b84e5f61a81e4cbf60c433c65cda100c2ebca3e7209a2c251bcb74fdc7640c46f40ad9e73904d18fda94ffa6ef88cd83c30c82df7bc20a89f815f65cfecac36f95d75f8baf79e9e20c81b8fd5beea0f7a2c170e9df0dbfa5f04ee9a7b0fb5448635ff83554a41e20bc3167b5e63611d0918476ed96a3d5e0 +Msg = a24f0a863531d225b7cfc907fc7d87b47ea06b61acb68d158496f40a63f80a561c374cca4856461bde42bf3f0456311a24247c5a4173daa08c8416e0329af90a79b806ea0bad674d914e26658403a06e408537925be5480a34d15d87cf13a3d0e05a9eac253d1b02f97d663f278abef8fc4906d1a015bd9da60430c6e16beeef +Mac = fe1f2c8f6af31f96dbef868d461631a7d159d47f6d081eb8 + +Count = 183 +Klen = 130 +Tlen = 24 +Key = 560d76c1bdde2e56ff54567df6713e4e243c1a42f7fe62fd4bb1786a31b68c0defc6bd95482b80b1fd30462593d6591d57c807c1a0910309540d08d3ad1dbf333d9fe30a309ea3dad2c548d8511a1743c3e979f56afd59383716ceda8e98fa8449813247ff9d5e7886fda3beb6a540697085b605dfab2c2ffeb611a85b8e03a81a52 +Msg = 5a62ff7ac98a6bd1324596741a5554b7193f1eff8e3965ca914926ef29acbf26bf7501cad37686deee63444fd83563780acd4ceb66da036f26fcb645132a96b0f751e5b4543d501d56bd80c30702ec0dc249f1b4eaba24c9db8fe7fa21783a11e93ed4bdb4a77395539b705a0f84967c28fb34e081a071e19949e095bd605451 +Mac = 5030272dedd382ba3dc06d2eeab9e163a325ed293bd6ea3d + +Count = 184 +Klen = 130 +Tlen = 24 +Key = 58ab9d7a7d912959917c3416046bce4d8c8c81341a5de1da0c1165b1a435754bb993c461ac57e0199e700888e0393d76ab599b6212e8eac634d3719db6810a2171b67cd967b804d3fcb1352f635503dd56c41aa60ab2747162c52abf633e8a79e8dc6beb96fdbd101307641073064707f397a308ea04a662fcb0392191b61dd885cd +Msg = f83e9f155362ccfd8d228911abf7b5c71d29cfb1fbfa5a528e20863012790c2abafb5a0cf5eaf061f04d0a895ca27f0b71d1e92c335f06c0f4e45e401abf261d22086554e5c655431a620cba1d5c5b56ef3df70a7dcdd6ff2585dc9e7647b7eb374d0814ab60c349144ad8cf768d13509d55407661ac94b829ed4873ae7b873c +Mac = 2090dadd774fe71fd9617b2595309e1a024694d295bab147 + +Count = 185 +Klen = 130 +Tlen = 24 +Key = 26bb5e3c7ca428929e0db5d1731c28df597f038500f499197f0fc75aa138df9b80f3e5245664fed58f12250c23eb20c92288b21091b3138f74269d812c96c8d203f0588406e3d551139e3c9232dbf45f281c03f84a348263900a4e57ea9a0159d73c21253329974f503b622a49f48ce993c25d04d581d0defa4243a4844b7278235f +Msg = 49a46c7b476b17bef5395f08ec18bb496a188ab2ed944a1a01b60aa1563d2293157e218f74a907e8894eb54b5b20a1a23ff8ce39621dfc1fa2c21cd0a2d006101de66e1a7a9e14faa1133c380ea05eb623ea1edbc3207ef11c8153ccc41ff6ad08e33b6681d2a7bee88edd162a205a4dbff462e238253a5818fc98dfe5b35830 +Mac = 8d93d5f35311234c1ed500a0baf3a64cbbd20608015ff59a + +Count = 186 +Klen = 130 +Tlen = 24 +Key = 1a4e62c8a51715ca8cd3c745ac05bff02a48fe5f9fe37d32799eb58d9ed464c852ca8f675a3fc34c6144a12b9c4e9a3faa8af63bbe701b84ff9b0c9d2fd830e28b7d557af3fcf4874bb7b69f2116388090d70bff64a600427eeea22f7bee0324900fbce9b8752fe312d40f8a8485231da5d94694daadb3d6bf3e7f2cc83f67f52829 +Msg = 4715c0ef816030e7fdf591a65e40ac9dd9eb95673101380ae5543579a81cee5d11e0dd14949a2cfab1167fe86b9b15fbfccd0f97c7d20fab8eb40536e506460ae6cbdfd02793284ce9e79ce292e7e7595e3241e05106fb4e70a957ae30079dfb2f9c6b2822944d630e318d9bbc6e4d4067e2d24ab7e6237cf3fad3ea72651bb9 +Mac = 965b9108e15614b899c23af2712058eed518965019ed8ae2 + +Count = 187 +Klen = 130 +Tlen = 24 +Key = c20eedfbffd65f8ed00a0ed925a994627d0a76e5b4669ff61c970de8d01fcbee456c1f80225b040052fada9e57925d79e1e5d4069fb48ab6558482d32fa267ab5565c2f1bfb370604bc652a10c30466fe51d56f957d930889892d661e55e97ed18803e177de789f6e2f7ddaced8c378eb33c668585dd78b30d47725a9b5b44fab945 +Msg = ca72a059551913018f1082fffcd93014a277ec636b3894e1cad3dc07a1b24cca639188cc7648d4d4dbe5d77c10fe9f293546e6406f5d94978aed852ae2f28b108359b7ad8fcdd428e0ce351fef03b19af4d1eb3e4f2cd7c427ad79a951e5f02673f2b462694f1ce7e7f12352608f6b4f274182c5d54c654eea3c42eab73482f4 +Mac = 29d3481d3a4ffc24f5b832cdfe7140058d8488aca2011aaf + +Count = 188 +Klen = 130 +Tlen = 24 +Key = 4f52b7f2ef19a88156ea68ea5f4053a9e893cf18342bd4e28e35abb92f17f54c6201f073e6c4f6ad94e846cd41f807f0e6218ab2fffcd0a230a74cf32e1ae974ddb84fc2b62562bb6c580c37cff13df3f0cc30ce86d6ef38901f19e73c31e3cb08a15d4527e3f79426624390cfd0fc9a4ebb48d392623a8cf6c69bfe2104ea3b2ae1 +Msg = 03785732aad68bf0a688c39dd97a8ca6d48a9cf99a3db45ca6b0cb0430d26863add1504195d2610e68e5be77f3382c37d08bbc302ce3abbacc83863b521891f8bd346a2a30fdea55f4274cd5bf1f91b9378922d5b2edb81340ad790aeb3b64d23d88ee1603c0ed6a5134b6dfc69882d5116e1711b4c2a4100818ec9a82a3a69a +Mac = fa89fad64a287027aa65c4389641c7d413566e92fee79be9 + +Count = 189 +Klen = 130 +Tlen = 24 +Key = 39e6d49c3d5d23d2746d15d616bebf3cf720c6e6012a71cae22002f5021a47d0b8636ca3bd201357e132a680fc5dec9b28a9db932d08ae8b3d3a37d7e2ee754b342a69b94fec26b50412289bcf77e6d4095faa545f15a16783d22eae21e18464150174e6db0b837347d440307655d56f0409db307f9773e81cb19282a93c9ca4c3b1 +Msg = 5d20020a5dd409c7e5344065871e57e01c91a443501dc8bf619890fe231319b5480c3879dee618d319962596539e2970513fb5c0c8eac3a71ff99962779cf1d7e916566d0e29d121c5cec5d7302a18ed00be9316f3de8c669a64c2a960a588f9c8a42690f6867cda7146e8ce27aa6a7fb27606eed9df6a235a42d17ce7162744 +Mac = eba38453b3a787ede274e9400435b1a11b4a751bdecd3b22 + +Count = 190 +Klen = 130 +Tlen = 24 +Key = 732b4a0b9be5c5e08cfdf90afe1c800a7a77486c6b9841aa7861584d114ea95548faf0dbe3e541f5af74fada1739f546f4750220a7db945b6697ba1ad38f5117d3e979459dcd45b4116cb7b54c41eb4079969292e94ba21a67d34c96c57f2f7abbffcb91f22638e65bed17e5c5bbcabeafe3e00a5a6ed3b1231cf60b10a5a945a944 +Msg = 08ba7f516b9cfac0c0f625d111b8031106f91b77098ec09aa9db96203ce9527ac9b9c1cf25d80c355b343a27512ef634a9f093f4e6014d40d016d2a2192c010b40d3f1c4b6cd35a740d75e8f9cc7c20d67d77c5d3e41b498240c212a2325cb8736b1161a67a2fc7e35889af138aaee060856df9a5a757d086c628ba1a4fd3b56 +Mac = 2bbb7e600e9ad59bd4dd2b47714309ed53f0f55e1741ea8c + +Count = 191 +Klen = 130 +Tlen = 24 +Key = a36eed3e91b717f21d56aa25036a5e7ddd74bb3296002fcd21885e306b95b9d78e27525d4757ee42aa3b5ceb140a06ea6280c6806084fb608409dbb6dd320b6846b96d9cdf91397abeca4f33e1b6cb42674adaf200c6cd20a3996c427f7e8da833ece50241ad1d23c0cc280452b5d50c5698a08e5f0ece94e4ffb9db39c3681ebd87 +Msg = fdab2a03a7a1b55fe050da9d5f661f7df63c07c3685b89dd7c40c1c54f5ce629ee5f7cca24b6ca2291528f49fcacf119eb06b69170f3b677451990411b369d36306122d12093ca66fd655307a11b87a943e26e834956c2b75d47a334c3bd8cdbea3986e1413e9b744b108ea1f6bcc975295897629c8c93e5ec526166eff99b60 +Mac = 4b5571d4f15c3896ac39caed4d7aed73fa6ba7fe84afa961 + +Count = 192 +Klen = 130 +Tlen = 24 +Key = eebb4ed3f628aefddf7ad08a9679aca962dd6de66bbd17447c4a6d8c08bd12e46b8eeea373e7d3641f58615aa6cc27e3bbbc0a5f10a2eb4219b1846812c393a943933bae832ca702fba1f06c2cff417d348039654c01900b96b6fe5c161d58e2fd30fd992edf70fffbbd466b2ffa439f5291c0a028c24fc67bc3a20f1ab3a9b822cf +Msg = f186cc9a3877e2de21e274f0cf6a67b5e72f2b6df5a33d2e0b99f191ab9f6eabe68efa3fc65f7831ea402e3e70e7cceb1827aabba5c152a5877c3ec5b878e352e4bfeed0cc1dcd87ec3271335bc552fdf45bb4aab3082913618658d57484fc49314030b71358e9c670dec4375aaa02d3c4f4d0a2e522cc5ee2dec627a76cc378 +Mac = 95a4986acb7cda7e95775adf7ed7388e0c7b54bef073e5f3 + +Count = 193 +Klen = 130 +Tlen = 24 +Key = 350ed4bcc51bb92c5fcc6435688ae8ae2afc9f9c657eca4b06cf799e3609aba396d7b56ac9e2e818348c6e3701e175506aca90bc348459b779515cb6ab6e30fbd644e76625e2a98ea8ab9b10544c05274cf2b57d5fb99e41d167c57a5e5a5e9b7cbf3157e10543b64591b36969b4e25b58dad688ec04e11295787d9156b67bab10af +Msg = 4433ee59b964f1cd20212245d5e95162c6837a3b78f1ecf84ba0aa9dfee11223759dbccdba43a5b943068db673469d55624b4d43e13985d5b94002e53414fcdddf9d06118def35529f7c84bf838877df7bdeffeda0c29e732626cb1be12198c1089c92cc3a4fe9bfbeecd10b0f99272898a458e3bc727ffa19b9cde60eef2ef8 +Mac = b53f7ae9e9c677897739b85a8188d35c6db029703b6b5153 + +Count = 194 +Klen = 130 +Tlen = 24 +Key = 7464290c01b494fdd96cecb8a07110f04dadd5758010fb5815d46050f906745c3c42edaa68bebcb812893fb9ae15b83aa8f4fe05b0df724555fc35ecd561985233d4d41e8bd4fc6aa3de2f22c2e912adc5337dd06f3f75cf011e5bd50aef629581a2473211013c5cb4f025bd83f30693cdf2bc9e6639ec3c41c33ad341b8bb6f4d34 +Msg = 25dd3a089ae04bc7cc3e97eb85e6647847a45c3a3e45280974fb414c440303bc1184046b38bba3044255e4545f1c7b0910d626ba236a4028e44594c492fc6f711033f98addbdc4274605a69cdaacc4431f73f07c835c35f1950caf1f7574a01289b0c16f722fd6b83f1585cce0dd68addd43618648612eedf0183d65d7b1c127 +Mac = e0f9223c3fb6ddbf6da7e51b5d7ce9368cab016c4cb34a9b + +Count = 195 +Klen = 130 +Tlen = 32 +Key = f3ac4422cc724378100d7515ddfbf3fe340002b7976c43acd69c2acf26c3b18173eb4eb6f73622540c6a73dd3eac5c4ea58cc34772428c6bc7370c0accc8c1feff4640d2cb416e2a5d06f35eb366ec69f5b9e0020923f6086216652318182ba93ec702be701a90c0abe9dee261b00b16cd9042318596e9494e401b62333d594ad975 +Msg = 04a3c1e89eebe7b99ed3bcdaa3cafed8956ee8da93acbfde2d29a845d4e1bc928e0f5e6fef4cccf144faf51c11e38baabe1e58088d33d5a2cf7ef96058d94f7030754b478b09dee2fb2f4852e50a2e77322dec0c46b82ce336c4b87235028c8f509e30785c6a44162c385c8307870fc958634beda886eb2ccac38c8455a59c76 +Mac = 07f73d066eee1780fe9488ca2f024ed56600920f6e0c728640d1f6b53b24002c + +Count = 196 +Klen = 130 +Tlen = 32 +Key = 6f67acc56e8929e491df252d3c8d497a6fe7a662f6d691bbdf7db15d311c5629db340c4aebec71bb00b343090227bd5b103524afba829d66710a41033b087330ac15710211932a7dee4c505bab57ad098a3cbaf3dc576e01758254615deee088c85203734848fd3342f373a89fe6c18dc34191b4c31dad93d22b1100fd9745391933 +Msg = 4f34c874a909e1a3ec1869236116995baaafba7b02bc8b54c6bce76e3582a354742bb633d4539ca35889fcc572ff888e0e862462d1ba4be5a37aaf0e6b9c207d19deaf0eea1f13aee7cf4c6db0a486d5778e3f7a4feeacd3a703594811a4118c4935fd2d72d40f6aa2d3a244a16b5ad8eeae52eb03be76c7da3d2d46b0043c2c +Mac = 0cd3c2f7ae6353ec7d70ce932f3980cbafb77159b2fb7a5c85a1cbc3a566ba86 + +Count = 197 +Klen = 130 +Tlen = 32 +Key = 6d82e6fb6ac5ad3b3121ca955176ec0c91ffb3d1358416117cd102126d68437ed373a8ff87fc620bed60ae02c101b476143caec9919b4cfe054b57c91fd096e874f7eeb6c50cccfe854ec80d96a0820b5481d08bd43e1c606d6607b2787f525255f7ff4baf5eb3ba00d25fdf57ba1f7359b7633c85d74ce0bd0c59f702dd4263805c +Msg = 95be84de7f82fb79f493b3c7e378300f094836d76558dca8ec16e2117f3544ee1a0b0feb4e377443f1861bce1418ba3a35bee598b6a7281b8e3c531d3f481563085ccca25b729c4291d0be61dd2f1b1b7e1d1a0939a0b607071cd33b0b76d253c67a630d8e7a9afd3c38468b26077e3b4d2c7c31d78aaff4bf7f0b72cb09a444 +Mac = 6ce9ac951ad8b75b3c76fc7e82b498258a58544cb4ee50bd5c96138f37b1fc33 + +Count = 198 +Klen = 130 +Tlen = 32 +Key = 54e6051ab2d16e9654e96a1d91fd16a49c3c7377a0fa1a200fb12b8a37468766168e3fce6f114c281d0e804ea8bfbcec16dd642903671089f4a08411e957e3ad316a1fd0828db45a494896be3f3f67643db6ee4c5154c5f51127517d2fe9f7094e828d6714cd0ff2819f94b67f0680d5bacefa2ab14aa12b0e517a1432862d4215dc +Msg = 6250c2a87119c8b62794baf18496af65722d0b349d25f53984d10cead1085583e56d7861b8f32dabe0a1f138ef93fdad024278e69705ec989fd7f734d55a430e4d1cb7be5019efc66782ea76b6bd030d8bad2321373334411df5d9d8085e5c54c2e6e888e293f84fe5bf0f73801daacd35f772ad25b9b77c25b31a9f131b899f +Mac = 9ca65056dd811103ff8b38efc557d9759e0b7ee19c7ed557aebf3b6fa9a438df + +Count = 199 +Klen = 130 +Tlen = 32 +Key = 13ba5f52beddcbce4a797694eb05caf10463ee0490b8482ac07c41bae5cd48f391091932f99b3f689e15d7cc2d8098cda3ef104bb45b30066eaa0b571a11db1e639c45fbba0bdec1f8e0ed2745b673c139d4682f42024895469cce4b89e4ffd5d09c6b15c7d5b0bfa0023f0efd5063b5103a7f19005797bd8f7711fdfbefbd002131 +Msg = 7f471a900ee49f2cfa1d3eb37c951d810c349364d4cc3b5b64fc479da75517dd16bc0bcd2b0f95e1190c9255ba6eda71c958150c51f7d14f6564d2bb12c7a96d92c289a1c20d5576d75dfdf14c8b0b431ef2794f3c19c667399249564521c4a45b213c15bc2408739bda298d1a34d98075c866357d78412b494e527728ab8f09 +Mac = a7d699dc5cd3405ff692db8a910db64e2e2504f6a3da92a65830a748bd89c2fd + +Count = 200 +Klen = 130 +Tlen = 32 +Key = c8608386aa689fd9fadc56b98ccec4e2fdfa050cf3fa9dbfa6b91769a02aedaec13aa8ff8503486e8a42e6c04c0b98c433bb95e4d12f9afa64338c65a33d5e5bb75c3580876bcab8388a103af4cf18e7eb3831d998e4533e4683be67d20cde1cb2ae72333608ed610e9c1c4f0d810af02d592113d28391345392f698b6fd3599bb17 +Msg = 267aa69989d062695016065f0282791ccf578a7f231e27107b33cf9f78844928319697facec9261853dc47e0b9b3e3ea435869330f410c7becd12ceb6b2011fb39ffdf93ab37c6709b127aca731de334872b15c3a89d8272f5e16ec5f539a4ade3be68ac49a4ac39d1bf87665746e2c042d8757715bcf2bf416d7f753e566a06 +Mac = bc0c2deda203839165de872fc54df9300e31957e115483a57c0d370f3404213b + +Count = 201 +Klen = 130 +Tlen = 32 +Key = 783f153f2dcf9a582c3776ca094984112081a2a4d93813ce2b1b22b95fdc08cc172710368ed8f9cb216b9c100fb3cf917dcf887bbd5b4666cfe3ac73289d6f97b357733616ae31f436815cc8fda5c4525bda7a6e8afe35099781f4331e19e57655b786664bb90a7a7261fe1a5c862cf9c289c0a5ca8ba95d89dd4222c7b83210032f +Msg = 5495d82b4e44351ab1cec03a485e4a2d00c2ba49a81cf7ebf5db090dc9ea7b1bb4270303bc17658c59d894e8c4571a8c71c3bb3fda4155717fe10bcf2bd0a21478d02b2295e6e351475257072ec4cc894acddd10be946620d3caa1153fe08fffa8779aaf64187812832552be0f0f26cb92ca6ae4d97ef29df88013078e800983 +Mac = 9deb737429c7b52b6a51489022a77bf3bafe73876d38c45b749cc65a725ef577 + +Count = 202 +Klen = 130 +Tlen = 32 +Key = dcf32810f1efc1db0e5f6555ae9c954b729518bd74ceedf7d9a984fda5e52e2cd364d11fa631e0d03ac18aff5e7932d8a67120d0bb7876d0f65865952d5ba057cd0d11a82944cca0125e4137a8cab5f26fcaf3c2a6763e29d4058b9ea348ed33f177517525306b93bfbdf0c3349606e2f826f95adcd22f499a385ee0aeb4fc096829 +Msg = f2c0a5bc165710222a9053d9c9a193fcf69487f7be553a3c190a0c3712a2fa8327b1205ef37b7c5a0a4ef55625169cad7f2b31ad7e6de94b96936e146bc028673557bbe26911d11a964d198f8ca790dfc4cbff39fc8cc4152230d622730e0480e45c7d30c14295c99432c66c487cf5f98e1df78380d8540284894b4874b51637 +Mac = 17c459163a9d421bf7dfd4bb1577fb856760f789039ac84859df13526d84c55a + +Count = 203 +Klen = 130 +Tlen = 32 +Key = 8b7cec45eec9e4000eaf9ed1e496f1fd2d93b0e1638c3636eb9d429390bb063330977af9b5c5f6b1471e0099c1636320612381edc3dee923106a2ce47396ed14cc0e385fa97e157d72fa5cb4e39eca9fbf71552fc38fbdefd988648c8f035f94c7a7cd7eb03b67ebf50b592b348e5103b147d5ad4ce9d921b0be9193ce49843d8a2b +Msg = 24c631edf1b1bca7ed767d72a73c9144485494996cbf141830f046738cd2f88fe40dc7e5d986922865242f2727da5cf6fbe2f848ce467320b1a583a92b341861d403937d1f82328a7843cf508f01cbfbf3e2457de2f98f2e600fe2b586a3502c1d2ffb7f6bad85154d5ac7b386bac69d57dce2fe50df518965b5cc6144278836 +Mac = a26e75b00f59658aaea24d3b0f283e280e820afbdab1f255e00cbc8a284648c0 + +Count = 204 +Klen = 130 +Tlen = 32 +Key = 332d0227fd1f7a1282f8f5d5df338d7218958570ac6d7e3a6c1beec28ccfcf69fb939423f08c61d6c67c7b04098cfeaad149ce684eeccfe1a5de5965fa7be6cece170ea78c3eb6945e4084ed45ed96ad699e738bae75416687e539e60f74596156bf58fbf8bfdf12f54cf6d9bcdfbd42899c5c22f1903c90bc37788df2418eeb3895 +Msg = e8bdd28c63fd43e497ee0aff3296e63384173ed4e084ada746f3be9940d3f4b10a800e44f51588680d8265aafade2c0424fe31091b46156335bf907f796a6e87bbd4d89109ebd516461011a5156ddcd8f9897588ba19893d0a1af7e8681cd6d545e1b9db652631d689c194574becfd9949e194b785a7101d0c2b7a3cd6923383 +Mac = e5437da742ffcc8fdd58dc08b68d23d766be75c3ff93a21d98b048b6d116a70f + +Count = 205 +Klen = 130 +Tlen = 32 +Key = e199ddb8612936d2e46b4e301a1e772b0312d5a903e713f9381754fe0b376d900579511fe576cc99ef2a758e8640de93fd900de4abe7304d3d068c4a50edb76d405907003a8b4aec994bb7d96f2d259761137bbcb9f3688fb6da5425263196ca3740e7a38bf016918ad5fe57fc6bb600d7a0077b559323894a9c93d9b58c72709536 +Msg = 10af1c219f304fb2b6cf06124a3e7d9c16d8f3aae1d9096303ca6cd42640b3434ac68bbf0c1811fc27927f5e3be70b54cd160ce78f9a5f93e2e109559a001d0501a5e1e61e4d2c7c37b7129d9498c3cb8690b1c1a85df14c654fe45cbafb165b3d3466bd5f3768d9ee2607f7deb86faa482e2a60b389883793fa45120f9a66ed +Mac = 7395adbb0c4efa1e2bcdbfc55407ecc628a78e36a32085bc897f28a9d8e61e03 + +Count = 206 +Klen = 130 +Tlen = 32 +Key = c3d9b6761ea20f88ce1662c1cf561c699022c96f9af1d71673409debc22a9cfab33904419d7c7a65e3d918a418a5b50b667267e930284783f658740979cc5bc9206335a39b1cd0bdc6709378d0e5bda29ce0eded67bae79fac17958c44734c41d2fe51835eaa9cf84082db23403dba96fb13626289cf3fd35c26075a6b47f8cb90b3 +Msg = d7859c229eb0d77abb3015c9fa2d2c959981e0ab076dbf6ceb8a49686802542e9fffaf617664060f98bc053fbe6fc0c92c3c536b7ee3c518a42233932ce32a3dbfb4542cef77577c305bfaea230b8a9e1b257c49daed53709b43c40856d218423f8bd3a88f52936988f63af1b3674fbd6d23a26ea1f22f1cd7d345ec6e36e8e5 +Mac = bffb2babaafc27251a4451f262dd3cdd8d9d79b9a6fb3ca613b3ab6da1ac719b + +Count = 207 +Klen = 130 +Tlen = 32 +Key = c1ca87f626ca3716770d0fec1aee4ecaf2558afee02f51eb891b115f5a663520ca3a91c8df1200d3f4714bf7b9d44db47be5552ba6f1cc33889c18aa57d4bf097603d03bf4897fb056690fad9642f5e66b823a4ecbd6212eaee50a74163d964e4c8d0cf86c16fbd3235c21b6b8218c884993ff0f58c59703865cae679d8b0019d441 +Msg = 182cd2ae62596fad1c4695ad0af75253c9e73aaebe3700784c0b47984a32b5ecb4054946a091efb474f852055714f288e55e7617270e4354c2844d336ee72db9aa0c7503af994089a26a0da40d33cd4e90673a29d4596bc4c1a2a519f1c2755a640afbed75b989b50c656d93169c0a2c32cc2eedad609f4db12cf752b90bb257 +Mac = 8abd962b73c97b9566d08fa5c96a51c7c53843ebd12069d0066075e0980d17ce + +Count = 208 +Klen = 130 +Tlen = 32 +Key = 455b64da72b1100896812d4b3d78c162bde6efb7691fc7e20921636f87772fe1eb5d88f68924892d79d8218648216989ed673589ff39ea2a25f08f21cd8f263b21ee3ca13618bf5a87f11011a31c5919221b21aeddb81d7e5fa44968965f3883ce57a862e1545a96a7132175b431381a434cd8ad6d640ae59f87bbca4aad0ec0dce1 +Msg = e7f20812443092e998e1b61788e95d2c70ffeb49faf97587f04a2f964ec923a59cb429827af413037da228a439cbd4719f709d278ad1599694ec9e492e407b69f0d665df2d8274b9cb67d0cf51b966a642c7df94aa38d225f69438be080721808b62a66f84631fd42a3696e0f83b7b91000a98da82b548febd4de43d05a77fb2 +Mac = 54ef0088c120d11add7ebefb1dffdbb6ad31ef6556215a1625c641e91955ba51 + +Count = 209 +Klen = 130 +Tlen = 32 +Key = e402c12a30cca01deb1f5826828bc8f4f5d72d2776464fb5321af88d6f57aa7bd7c9914c1348b7329c3b776ace5b341b3fba4b824e03454cff0352430668f32d21c9f6f1abe7a7fc6f3345e3ba90b34ab4597004efa6c97c41cb4d53cf22824a6b0bd6632030d8430a0ea8db6bb1ac47fcbe85f681b7420ca07bd304f30cc09a5c95 +Msg = 9b8bb10d82b6d109bacb9cc75d8c9e39e696cb0d963907281787ec5060abc728d87de362be530b30c8194afb0aa4f5581a43eb3872971c5e15a54817762a0925952e14fc6bdcbc318891b82ffb33252c72c4cf5ba237ac63e982a91132f4a9491ac9cb4351fcecf4425c6ec9f6e2379b3542fce0efc0bf1edb4596a65eb2af7e +Mac = c4ce885753645790fab556c3e1ddacaccdde386ab7bc39283d4c84d3798df5b8 + +Count = 210 +Klen = 130 +Tlen = 40 +Key = e486316b3ac5ec100f43c0eabdbc0a32b3b9bb6580580a332d4f6698d02faf495ee6a551c188a1fc2a4f83f4a9e0ebaafbcfacf7a3667d043ca2f2670d7fab8ede75cc610a43ac23d6ebd29901fe1d6f9c1942d71cb07c73ae0a7e75ca8dad050b3c8ce33e7e774db9219523ee9e08493f9f664d14be6d492b90f20b30e21b748e42 +Msg = 7a04f851d50cd135256ef044ed740ab59e964565b040edbef0d568de1cf36cf5adf96feff4c65f5468c4946c3f2603a63b6db43ac731760e421ed1d79b3d3c801e7490cf8d51bd467303bb47b5a9c47c6ad0c176ec3602942fd43127521c89d374804339c93351d2ed334f1e7887b7ffd2c5545f49d8f919600072176a1abbb8 +Mac = 24ed011518825f9d39d06a2523271521dc7949d154d6cb378be20ecc2281b2ceacd349a61a2806b2 + +Count = 211 +Klen = 130 +Tlen = 40 +Key = 0ac01a0605adf7c608264ebd667c38790e36363ebd6b0d937270d40023b44b17aee76eb112624a7adfc310b0ebd7682747be0791714984fccba7679c4c4184cb76e2874e881bcfdaf4e680d61389d36318bdb19a4310811457883eb04d89cc904af88c65cfa12eed2fd6c6ba47592234697d5be19987abe4fc5a7ec48d54cc6f1273 +Msg = ff5611cc449662ecf2a04287a828ec0400ee6c4b15364ad84278680d2c582dcd02d8e34603cd5e0e4190df72a5f5380b3481309290d728f4c274ffa9369c344207944a427e12712fd5f262e9402a8b3a2e006cadcb7b41a4ca17e1a563bce6f597f10e68bb4ee177342f949380b02eb976d5e947ce08db0ee3c9d5a8b8a18c0b +Mac = b96936dac473277b4f7f632730dd16a8fbba0de0acc0213cc44efe4af6f381af6c0fe5be563e7072 + +Count = 212 +Klen = 130 +Tlen = 40 +Key = c08eb5bbaa85ea0b2de93ae86fd6a26afd30c1c112db3d12172f638266a60d9053d8c9a76daa37f301c2b375e03e345262a57471ab1d52442ddf74e66ee930670cf2ad64fea345da1c042e3be2355ac2715e9b04d6e80bc98feeab194bee4a9af2c5a919e5dadc668799f365fc23da6231437ea51ca5314645425043851f23d00d37 +Msg = 66db82e65ff854365c79a601fecd3cc75318bc674dd5c0e673c02a6cd7f3b88f484fd8d4c81dbd7341f5b25b73dfae7631b9292ecdd92f30d1f3b370ef3c256d3bcf47b698503cad70d0e18ba9f161a4d44b04eda70e48bbade833cd3c29e78da8257793b6d9f96b53d2dd98864b7dd8a496f4aac3bd340e7068538ca5012677 +Mac = a6b6958979e726d66ed908188648e77b0b35b76011800199e40eeddd0d44f28a981aea8d2c335852 + +Count = 213 +Klen = 130 +Tlen = 40 +Key = b8fd9f9a77243dc528bac1a968794afedefb594cc02e7a01980227c14864e9fd4b70c0c73fe2c5e4a0ce0e23d792d2ee7308cd1fb600e61553ed100676de6e9605b0baa92582e776016a05dec76666fbf296fffbcfa8102f3a93085fa988a3616d2555e934edeba3d1f5707f40df4d4de40cb589140e4078d65cd674ea4acf830b38 +Msg = 0ea8885268bb33e52d2ae60a4398c81c28db6c302a5aa59ed6b99cbdb2b91fed2f593cdbd9420f00d161d86b7dd650c17e0d3e82e22a458d9bab00e7304851b8b31ef596f30d5c06f25fb8409aaa5533abf728c9f823aa6cd386e7c9c6d3d1d4843fdb0c1ee6c3007a6aaf1202dd7c7b99e1538fd30d7d42659378ecda204a49 +Mac = 97ea6505694b21ee748dc9eefbc753161812642b6574b9a66301a4d54e0ea090a2c1a487c244b7af + +Count = 214 +Klen = 130 +Tlen = 40 +Key = a32c359a9fe350c9cf5efbb393d0afba534c432cb92abcc51dac667541e224643fca0434bfbc16866d057fbfabd3c90c82517da3df12f44cfcb36a201cbc54917bc8f3ab85e62a9a463e8d6b22f8ba17c659ecbd5e2fcd2f08708cb0891e30fc406d2c895828330d41514d4060082be305adb7019e49f0752b2af5acf2ce5fac7403 +Msg = 3215f9112d9e2d511dfad07ba78bd5876fb3209e8a8295dc35917554c72dea54e4b8e0ebf44d17a9d3a376a6ca34a3c5bf9ed03aa849d84a464a8a520f87440b6c1cc50c24fe3c9118dea47a32515497982dd2222536e98d19fafb7f0ff9981930094e7da7f9c39154750200c5291382622ace5ee791f02d18696fe0b0cb0b04 +Mac = 540ad3fa372fddece3b61e3e0d7d9531c92a4418327dc0b152be8eeb38bfc92b2166bb10b243f8a3 + +Count = 215 +Klen = 130 +Tlen = 40 +Key = ce499f38ce5b7da7a4b0349faa0e07a26f9b12ad07e43b60a624665e6ec4e8f7841e3e0569860013888b10c50b7a1774f324321868e1e86b4dd5604b1872d060e13e3900b8d7524f3c34c1ab6a2d9147b23ee1155088d9ead918e3dd146c17f00c33f6f263555ca3e933b01a6d305e64d470876e68e0f724727657db0abaa3ec2e85 +Msg = 9e3d2da55720996355c025b8acf42140dd47b70ffa922ce80bd163afaf2fa321076399c3cf3fa118ce86411771fff6dcb3c7349e3feba8e1d936c0edfa486d7ebae828bdf39c336fa476216d93309854377c567dd4957230e81ae414c61c48ea8176df7b0b5cd7cf9e37cca05bb08e0e320b259501b7123b0023d80e5cd3bbcd +Mac = 435b5499b7f3e8e347d1d087134441b3b56fca7feb80befbf6476d1657fcde324991d526b5b4ddde + +Count = 216 +Klen = 130 +Tlen = 40 +Key = c5ff2dfdb19d7022bd4263e6dde7a8b3ddf3a0b93dbadd933e43d6283d4edfd0409558b9cf53248805035d43e66a456ef3d78074fcaa81493613434e8d1c39753bea87a59a3f7260364415a32786560d9e3e1944bdd5b495aca7a2dae9087ba1df84238abb6b42f17b8ef5cd4743c4d805afd3f128445cbec8885c95f8188d9d54ed +Msg = 43ba51cefe257a4fc630774174db94d14fe6e0df8a44d60d0ecd3d167a334d62683713d7f31c17f1765c3b15959be62282d9624a79eb83208d2c8af1a7704858cc39870d9e2ea5fe26c882a1d04f9d88b705793623a1463150febd5872154c77f529731909416e9d5edb148c2cdfff2a77d2ed4b914c6668e0ac9ff2e10a9fe6 +Mac = 319a7bc1867beaee22b2f8f2b6ec132247d2b81020fee310816049816c34c717f651267cd9070cee + +Count = 217 +Klen = 130 +Tlen = 40 +Key = 34972b6645a47e3d87c5a568693c2c4f7de0dea57f12e4f892f33186ccd51d53f5ef4f788c54e1be0b26bf6b6d06505cecd059540f851e94e489caac8a0f1090f3d113eee80483bf4e8b091da76be654dc7fd73b396d3bc5b9d877d384d79a4cb6a63d70629cae69d75d4d232151355ed3551f0204b084b2984802a3c11601afc4d7 +Msg = 0e072f73a09fc1ede5f39444b25b302ef1e6fad4399f6034a20e57c3d70107576c8cc445724e41c649f600a0b6060d0235d7ecaf91ddd05eb12d0e61b53cd08642ea0e3b19bfbaf5ef743bd279b51d7dc6250752d1a3edc257cc86f9e6c001bf3729f49cbd7a95407e752c2122f0c86649d8310422761f273af1a9d3911500cb +Mac = 3896072563c0c2865483af821f0546fb21cc1604eff53bc81b77cc975ccc53e3a696be832660b324 + +Count = 218 +Klen = 130 +Tlen = 40 +Key = b7622c1d4bea038b6b8d5331f7bb992ae59b34ec2e5a6932e8c4aa3aaf1118314a0146ec8c2b40d87791cc34a879ef7def78b32a3dd0289ac3fca94b5888604c1b260df55aff02d5b34772ec7914ec1a5a7023d83eacf02671f89ac4053154a572fa07a1800e526a67d5d0c1343599ea6eaa0b5dfa99cabe3ce1050f7fb4fb2597a5 +Msg = 9c359eb6a7991e6f11dc19764e6cd05eb51a61158ed986c36cc27ff5bd5c4dfb9f1b218ef52614b7ba5d18ec969b2f7baf38db2cc2d3d521724e0102e019a2577bb4cb351a6f161d48759721de081348d80e6e3461cd630230f3787217d93048d90882f23dfd8a6a60297f5e4f3ce58fd5a30377924f982e4db9ca8e8c235f96 +Mac = 5d7af8c97f7d6550b5d4f3dfbec8c50a43e583f762631f3020d9a9c9c0d6f3a152af83eac5353860 + +Count = 219 +Klen = 130 +Tlen = 40 +Key = b35dcf54a3cc008dddb7bd1c1b764f388c12e95c90fd899abc011f322577f163dbb93e81b3da21484a94b97046818781df8e17e99faee34c65cb741bb002ca681a0ffef92306269b304579b8d4a6b42c4df9bc5552b184690cdd310d625a7c23794758e37bbad52d98b1451d4b4c9de1df391ec7316f349ab71f9e2fc1e7cf3bff4a +Msg = 870f1b7e6c4dde00cad1bc6ac28603a2341db17d33b08983b7a566f292d6d006a6eecd785416f94438d2d9b013256d8a08fc04b10cca54d7986fca84a05e1f5ec9ff2ca9d752ff0a64d62e90d8a96bf495f0592072799fef6b9f3a34976e17fd5a08e119db4718d7b8a46311f958276943c158d34e068f5499fe5d095d4ee06a +Mac = 938bba0d6845a29865e47b56b965b2bc52040859e9ba9c85d92ea0186663c98a7bb1fa2102637344 + +Count = 220 +Klen = 130 +Tlen = 40 +Key = 0ca6d30a1ee6f05d64998cab5a57b1600c0e64023799e267ab952926f370ba4b38c29e4f63e1a74782b0f85b6db7c77aa979624c8c017068a2bf7ac85092aa79b726d297db80af7905d7702966a67217fcff4e0eba221566e34eda7cb7d7715f517977ccd0ec925db5b8fafd8c4b399fcf492f30072358c934eb522a6f679964ce64 +Msg = b617e6965eec432dcc4684bb749ed016df232b884600a52c5fddd19b77a879c8c1959029ee636818fde2267855b2729b114d73639b47faa87cd5fdda728d48e8c36c6f60d21d07d7f078158b744ac7470e54628758967cddaecd6b93403afd9265a56a8233a286334c133b3cfaee37e27f40e23ba67293939ecb030e0837028f +Mac = d266505b5ef935dd8013ca6ee3229c96ea6f571aedfbfa33e915ccd5953de0469331ea1128f6d973 + +Count = 221 +Klen = 130 +Tlen = 40 +Key = 137c94037fe2a15b39aba093350eb9c181eb1de36f5f4719f695821156dfabc2fb05385da4dd7980c41b1ead286bfafcdbbd060c47e0a93f9c5336277658b73bba49e9cfc02f8743b891cb7a468a338d701e81c1bace05b78f6a1ee3e327ff3f17f2af411d03530adcb4b0e0d694ecde08b794ea1151e4e89783422de7750b37dba5 +Msg = ec16489822821c1407092268101d992f7fcaea78343b226bc680a430d28e200c9387bfcdb33ca06961f188e2a460d56cef00b4d2f5869416beacdb58fb32d7f89723f7ff8e5a3bbb0244e9aa8ce8829ad024f40d543911e2928a40324ba072791f7258f65be3d454128dad896fbd86ff49be11f1f85b8019679f3c886bdfdad5 +Mac = 84cd11c51881c491f78034348a4250485f1b56c81092da410fa0658b05b5d3e715ddbaaa08feb6a5 + +Count = 222 +Klen = 130 +Tlen = 40 +Key = 6933fed3a66bcd401155d22f84725361139c998aec52f34b8150fd5fea622119847b5f0edf014a0fd76c535a000f4a10483522ead770f5283a2e47cbc18d8f042571f4ec6ed35475145c8aa16532f1f2261224217d9f08130ff90d086592b016943d45d61d88f35d124c006d7a824eedf7582697a68535f147d9d47e9e188d351808 +Msg = 6f85955d51fd0e8a3b261b0fec9783e1938c27b12be5f1140b7207e0b96d44d90048e88d42aa8e7c0fb45f7cf588865c9a0ce3c809eb046c4add515d352986b48768677c368bafce021f493a4dd0c2692c2cff01beaa2bc9bdebf40e523ff7452e6b78f1d6aa57c73ef13f109a7721507175e125f32a4f718c2358bbb9b97ed3 +Mac = 1e2c9fe55d17da4ba342480eb2d30e1ed4fc94baccb9194905dcf0350ca6b0eb5202366d646a10a9 + +Count = 223 +Klen = 130 +Tlen = 40 +Key = 9e75186da77aea91a67a3510458694ac908d0ae4562e8d6bd2cbc5d88adf119f7891cb406889cdbea1023353c720636200844bad561feac85d4312ce15006c5211adbc98d9c566058ef532d5cc724c0cd4908fafeb910233fdbaa33686ad646db3f274dec4d7bf4fb47ab8fe1c24569255d85c52dc2cde95fb580179a68d02d8a488 +Msg = ec94d16bdb3ead89ab8ebca0e0cabcc1503a651d7d2f5426224548f10ce490df2b0dc47ce953b4a7ba279ef4f559a44ee2dc7ce114ca6a37f9a76ba0afeab3d819b95ae433f5533da2769d309098bd85b6f66b5fba758c63bc85601c2ca3fd9ede22fc6a602c72928b04221e588df0adf5109960183aa2f394648e2d2a18547b +Mac = ffd507856b7da1d6d2ab4870003fef27669c2e06df3e628fd0b871b99b71663fad824f677bf2f2ac + +Count = 224 +Klen = 130 +Tlen = 40 +Key = b06e828d07796de7eb344a656dfa57624d19fabbc086a42870cffcccc5503a0a63aad09bf47150dd27258a6ef864f4fa335d5051338888bdf095dd9239a240063db000435058a6bbecba1ebcf6b717444360ab165bad430d7d73b5b1e390b00846685aafa596372843db4d76ef5a86e787085532bf5e9cc11f51ce504b8351b787bb +Msg = 3df4fe4187f59bcb01814904c90b4585288a37a721c163e84ac42390dbb8959405da91ba85c3defe78eaa534716a25f0c905a9a33669b7069fb38bbc2f32c433a96d5ccbfb67dd3a1521d22ffb617c3519b2c7dad8ac7c116e75b8d6fa889d10d0b547bb116902468030ba3a9078b31dc2987a962d111bd25e13942563438af5 +Mac = b322e829a7644f36f5ce147a9bf3271ec2578f474a465ba01fc0ce928954ed391e50e7727a0001d2 + +Count = 225 +Klen = 130 +Tlen = 48 +Key = 74f41a6b1c4e5713499557d6f7e889f8a8ce2e444e8261fe6a8e5518769bdfa88188349a19b9f3a26db26675b3e40539c8c63b3a16286ddebbc539dbe817fba7866f9631204471cefdcbbf768cc9043006a6d4cb4ec2decf1c0c2ab35ad09f50ced0c896fa97d87e400aeb3f4a408ec5a993825fbcf7bdb8d48bb208956ed28ba0d4 +Msg = 9a121482c7775a8b5fdaf1c2fb7de1a86ef931b1a88cf23ddbb47fc9dcfd0267cb173a6bf62b7c68fb6ff85b2df93e2539d1013f0a491aa9e991cf23e98656a082cb95f87c1b2cdd0eddb51048f94ad4aeeb48a426165321145a9b4ec3e85dff0755ac8f20ee71d2e24cb14a13280e9e15709147c499a68da23868b232cc1f6d +Mac = b0da90c043493511d94f22fac35b5962749c49972fb43571b8478764dffc1c25e3a7523fd405338a048d38dd1b75511d + +Count = 226 +Klen = 130 +Tlen = 48 +Key = d87fb6ba27215e5cb65c3b5b34ac2a32037f30e1f7ea603d5a9bff8a330fe74bc70529596132f6334f36c0952dcf9c4c664ceb48f74539f3768a65c1535902085fd4fe138ab18172f1341893185a139773582c5e2c4369e4201143d12bc0074ba5d57d0f2c08c8c0a43e8d7e7db757bb34893a4a1d4db7b95f18e0e140adbcbba3f0 +Msg = 9e1a5d9f236ef93f2cda60489166c82dce322327046644cc406b42e3005c2177f3b7af2a0159adcc8ba92f2cf413462e60b8db1ebb63de44febfa1b9adc87e79a480c0b814e3c17ac91c4f5eaef954ba929db6ed2c757df15d6d3430b66391993adb58f265f57c706d9d8785c7023df9ed497c3c5f8267fbe7dbc4f12213a100 +Mac = 3c7cee960221c9d9f7464aeb70d198bd60414dc3ffbfa7a2227a3a375ebb8f6448e524706e1e3ae95541bdcef2b31d9f + +Count = 227 +Klen = 130 +Tlen = 48 +Key = 4710d3a0a835d5913a96ad54499f2a5329a95150251ff1a6b8e07ed200e51b336f24f90ec4b4e0d539310ba9fe62391de719013d625b66cfabc1abd8431e69629e62de7d1bbf88843a0af2a10a63cf93e01845af4ec78b2553c3b685d0b9d0823b942bf5979df425a4e70b4553ea123e7c6ec5afd3ab893219ae47e28ffe7a1ab080 +Msg = c6cbf0916dce3ee4fdc3ade93875b2d3d6cb5ff627e52d7ff967f863bc154b95e4a1de7c8fc05da468836bb4cbe5e7a02aa16e1faf462160228ca8f80ee977201f604f1dcf9a08ff41378f8e6d662b827eb304f27821e50f1e79411213e174733fb04c5c7481c85d52871f61682004e19bac2957cc9f02f6b5d5cb981426ccf8 +Mac = b3b489532bd5b701e3fb7da0601ce9c94536dc3d8acafafe835c503b0be50a0e852b551456a328e65c76892f448912f6 + +Count = 228 +Klen = 130 +Tlen = 48 +Key = 2cb6e84fd408571c65af8e26743fed236cc3593383ecd41eec6f51dd4ea8c65d7683827f499cc163fca57ee68709886956ced8d542c022dbc1ccaa8159aa59da5bbf1014cd413cb9a89cab2e44149e8010ac1f5f8647946b5e0e95af0211fb6b433139174a3df0a4d15bbd0593aa56ee0025d5dc36cb53552dfdb9713127d39996a2 +Msg = 12f2890cdbd85863ce570fe3a418431bbbcd74deb16f3fa232cad6260e3cae588fba777509135172b2793d9bb43dd17a81da31fa67353acc6423000a3b2c7b1ac78f7dd69085e7e99cca1d7c885ab713d7787ab189f58643efafd03bbf58d37c6479837697b68392335397d045f75cae63b0374d40388bcf7d772f03c1481f44 +Mac = 4c32a80183ca3f1b5d07d91924fec55cd3c8e0a3719beaaaf3b7824aad1c1ef49608d5ba7a4aa5b53c244e896fec2fc8 + +Count = 229 +Klen = 130 +Tlen = 48 +Key = 1a8e273181755e05df15946114db513993803b32c4dd9610a700076dbb7f9db11e0c113ef54a4deb0ee02cb4c4cb81b023f85a434d1286941c99544109349e524d48066c46c980471b501162a36ed6f6834147289744bd82946b32a4eb704837f0678d233b99fe024e8fcad4796d58f4fb828a4b6a1c44c355a128fe27dba4494e94 +Msg = 35ae3481efd30d5d668dc0e147e6ff837d30a5465199f8ead6ff2b5f8405288023668cfeeb89f29ae9567498a4496f7001c487c664aaeb9c1829dac7f1d7679f2f0179fba63f155d1c4ce069f315df9c0810823adacfe188efd5453c73a8ea3223280360691eff0cc8180b3c7b75d86f59bc9e8afc32611522ab73a753a03a9f +Mac = 432f310947c3ef1f146401824f451025f4c24be8b4c92587a5c4263457924f426ceb8aecb533e4788d20fac0b25856b9 + +Count = 230 +Klen = 130 +Tlen = 48 +Key = c4b6e18a87558d2ce6a5946c65a9446f66cda139a76506c60d560f56a013b508d6ccbbaa14e24ad0729dd823bf214efcc59e6932cdc860306687c84a63efb551237223641554940a7a60fa7e6ddad64a21b4a2176b046dc480b6c5b5ff7ed96e3211df609195b4028756c22479ba278105771493870372abe24dcc407daa69878b12 +Msg = 37b4cf3789e40a62aebde9cd9cab34eb846dc10d057644e39f94693f6acf201d089438e1d81330df6ce54a203ef2e0639e92fb63eff2225813ba70c024ecea5f650f0f85788eb08fd15b01b06ad7f1f2b8f6b777df9ead05225162c29d0cea3b366f79abd11d317bc366370589240c9dbbe21bd23b448ef1b2a366cb3df7cbb8 +Mac = b3abb0141f7a5b4c39a1e5e6ef8bb64456200d42d15402be97bc516497adbe241cea596fc9493e91c84b9cb601eaa38c + +Count = 231 +Klen = 130 +Tlen = 48 +Key = 9147253adc883da2d831a57b55e742aceaf10ae4db91088b4095a6f864292be46cef831e39523f818f17dc24763448d0e0e6a2b78dfe41622c7bf9ecc35e996e50bab8bab10bb24cc1c8ed7dc43c61fa05915775bd2e709a3743ea4532a11ff287d04e750b5b9eebb76f60f006a495129f1bb08634c99d1aaa12016b7a9ac4585758 +Msg = fed888f3b12b8f17d450b4303279ad29d90f8ed71ba7ed89d83244e1007396e253b756496bc08421fd0219925c12a5fa3e5b373fc3137d63b36d2c580710a216acc9cbec837c4113ac61b789046c971cec0deac54d1a7938d90a31b99363cc319175ae8100490d166ad555be3471cbba6b8f7014c0a62833d06f1baca9545c5b +Mac = 380f48d74b2a6b7ab206cfee0a4c0fa5dde0fae81fd0240b3da352070611cfd45dd389f9e6b5570c8c202d4178cfef9c + +Count = 232 +Klen = 130 +Tlen = 48 +Key = da03db48559d2e361cdcf29eff209d75339c291ba45709848c76619745be76d35c556438e6c80f6517525bfe105ca050f940583850521b408021ce0cb6fa17f5f0ae13f357954cc0ced3e53acbda180a6531e383af73fdcc459a0f42247d2118bf9852404f0ccd8f6ae6f81cd7a4efe9a1f630c56ac1987002698e0138507e85f09a +Msg = 62c1d149567f05a0b76c4fd32d1f365d170cb165cfb38f922f1716225472eb36a127327007f8f5c08479ca7beac4b0aee26f3bb130bbf1ff390ef344c2a4e0b8fa81f6acbbaa7a620d945a22ecdd128a4b3acc2658b1cb41020809fab87d1f9a74b76624f9fd5c2e59a649f0b9d0229b5855adeccefbe60092eba26abf657283 +Mac = 35931980eb488506fbf05def3f501c90cd99e8d18a48999b4f9b1e95060d3a509050ac8a7a8461a9fb011f2fe6815a4e + +Count = 233 +Klen = 130 +Tlen = 48 +Key = 290660f114130cb1c66fe88b2d9a87969502a765d86f0989ce9e80580b2c47edcab79770243f799886d2da6d6168dd53230c7544673c325d68935b9cbca53ee83f2bc4514d60489a34aaa9f4e87d9e0df97c4a49c3e2114fe521a9c8f4c9746370aa0d1df63d21bfb84080a82ba173ccff9d51fd54294d6a2b9192651a5f9269457e +Msg = beace90b45258d290fa0d56c359ec61505083be3562ad93418ff466e2faf969d8256065e4e07edfbc111efd7c480740d18e75854a45de5260dc6fe2188549cadec4d7fdf0c0e1d9d4350df0350aa8c06645705577a3a348ae71f3f78324401e22518ba5724420557bee50bb88222f74914dfaab680c7afabcd92713cd687ab85 +Mac = 3ba6d5beb3b97d29c93887bffac37cdcfa407cb7ee9730dc0551144048dc83e4a2d24224f02fecdded21bc805cac3418 + +Count = 234 +Klen = 130 +Tlen = 48 +Key = 033f79314407bcd35919d1ef3725fdc000540ef085c5faae0a3dc301491a9d5cb98953720ff9e74b05d079985b5c69441c0cc04b23e0cccfdd1e0b6951474bbd5d490e5142f6339f63b5d36849776a4cebed37982cf9e55fa6626acca6cb30b677e67275e4e5eaf4f831a908085f4600f4603a7ea9f78b85ea70a8d25190947090c8 +Msg = 893a7f54d8739af07d5ba0e1e4b911353130ccdee25bd663af1c57d6b530e506d40705f556d3ef8dd1e0928e4e23d8cbaa152b963dc23879ba1cf3275696dbb12dee7ffde14a417584875afcb8ce1e26146881a8cad3db0d8715e8ab9b5013d65a97f453c200170f5efaff1169e16aae37d0d7fcd1b74689e0ad3f4ccc8715db +Mac = 7f0c42b9e080b844295fe9de114539436aa92d184b6a3cfcec1de8a84ccee0f38f5d16e34f955ad20d6a20b45ecf99a5 + +Count = 235 +Klen = 130 +Tlen = 48 +Key = 2a452560cb1f964b927daac63b72342755a94806ad044dfa0a8252a41a66a6efad96a2952141cae61dc415c583cf88f39fc30990a55f73de5a9ce64911d561a4d92b92b6f528ecf58ca3fb91a2e3f4b4470791090ea41b7bc1b1c83f53a0481416ce9bc92e1d250046df043382f7a1f4b43a8579d21c6f57a888a38eca0f84c6cd45 +Msg = ad3d83020142b3f1f07a3d02f602146749c9c3925efd0b4eafc3ce08bc2b2c6d4f63eb3b052b1c500a88fb0824bd18c5f377b4cf77486e5fd2561ff64f5502f3a4b218657411ca1e18fad1099fcf53bd13024e51fe843a722d81eab4b44ab4263393d12957de0682a33784ad70220e7432d259c1fe9bb8b149aaf9e9f3f4892d +Mac = 21a02fc0c319e6d7fda5a5a0eadd1a7505a7901dc5a24b91792d2f5952982b20cea4b55fac302a5d4c99700992b8a7d7 + +Count = 236 +Klen = 130 +Tlen = 48 +Key = fd545d84fbc11f642910e828bfe7d548e422641d227586a11753f6776d0fc82b0c4245ba8d6cf655f2deff6295d7afc45fed545c3aae54cfc988798a56e68d040c9c27436685c4a2e76a19d10c26a81d7f0892f28d79ac9edadfd45753c18680652baa286c54b0d46f7edf7e0a1eeaddab3dc5e7021eb695b221afe64de7db267fb7 +Msg = 21a9873b258290a981be2548cbb026097df680b29a96f68c954d225c6e23b6951e4308cc350ace6cc25e25ab7341d9bdfda5e047be822716a127921143ce3e6c5472091f3fe554970d1d07ab86ced6d19a3fc3920056e43b1df467d62789d3588adf901c8b3aaa902ba3d22f4e81a6af1c69327ba837b663cf5ea992647cffc1 +Mac = 78bd2b27a34ebec53c0c15732a23dfea9030a6e63eaf4a9f1263c7a933b6beaa4d3b647e801e61d0c44bc9afcc021f2c + +Count = 237 +Klen = 130 +Tlen = 48 +Key = 225374e44a65dd0fd9cfa2f7bd90572f4b7a17ba92357528e988b502cbd43d68e5e146f96cddd7f3b4a2f49bff3813e0939bcf3b0fbee0d9fecf4bfcadbdd69f3af8bf59ee78ad83cc00e79d6aa4c4ee0089636bbfec9bda646535370c6d59574a1f47cb773b48074970e3c4a7db53a2bccb39124bc78f7342d2dd7b91edafd93cde +Msg = 267d99cdc5989ff8d200f39665437b4d9ad862e42b6056a8442bf40e92fe80999e13dafe5962ad87f71feab501847529a6d01ec45390d20e831d12d4d766a51669ef8a205e1a31f6baa6ebf578759eb8db92bd39ff727738b37a2fe18bc22da930199379fb49920ec29cdda0f29e5ec1de252989578faef07d4b327bd49b801b +Mac = 984f82f1b69bf49cdba99b702b205fd50a7f618b6732a48639fcc37d0f5b868b30b53411b5167fe7f09b34d5d73d2d1d + +Count = 238 +Klen = 130 +Tlen = 48 +Key = 552e518ddc1a518c2c853897083b7ae8136273f6354ff1ed409ef35cd481b02e8058dbdc298226e1b073056dcf07b45d44167b6b324931a2c42cff16138466d14ae28310087892b0052cb2e3f9ebe727b9406579a3250cc53d192fa21972993cfcf5d2913ea49ee174d7c75f4d8e1c2dba06ba87528a8a3ff48c0b69aef45257ddb8 +Msg = 6f55443fe65938a33f0749655bc60f4c3ca62b0622f38763f30ae0c1e06b82c846105357d2fd13bde919e22d473c036ce689dfcd21fe4d5f1949106558dda106b446304676b9e535bcf06b661c35afa38abce5df7c35cd6c4ca2346fdd66bd90819fe1f61ab635728035ebfa23d89c5af2e645267bc18ff353bc53c6b82e5dcd +Mac = a9cfee8005eb9dfba8a2f919a0a19925b1f8d349a9cd9fd8ff0feddcef9fe687c5213aa77c1a05a72ce51909c240b746 + +Count = 239 +Klen = 130 +Tlen = 48 +Key = 3609e874c69e9f3516387502f9eb82acd029be530936ae7be6dd43628062ff920bb759b25bf263a1a7ffaac68e925da15760b2a67d8f864c6b6b4461845a07a06612038570092160822de9a903d6a59329f9c3e3749e7c037c94b352ed6320bfd082ad960cca20992c2bfb53629ea0a9cc5ab9b2f74bd7c9a2c059e0c4649017d06f +Msg = eefc0676e9fb74262e727ffc07135b6ceb05e6ed48938a4d802665473170a757baeb3ccdfb82ac215c8d3f86100364c19beb533c9114f256a106f5fed3384a800e84b49eddd7b6e3722db234ecbd52a8d570279aef9890fc30dfdeed0b7db58ef1afb51218645a157b39212f22a7edc8a37ba82ee9872de43498663e61a8b12a +Mac = 33a941a00df494796c3ca14caaa71a7e95479a60b9d0274cd1f58a0e809168bcf1e6e5c47753237d4b777fc4cca86920 + +Count = 240 +Klen = 145 +Tlen = 24 +Key = dd908ec058f137a44d76c004821a4750357615820de32e5d51df25f258b2356941518efee482ed4a07416fc4d662a7878d79ee5678f7fadd1d95b339b8f641bbe7876ae9a7ab1bc67f154454fb74e9565c56775a8e4654f75a38b954dd28c4e939fdc98a8ab3eaa11cb9e7bbdb9837460ad65798381a62347090e249b18fe57c9d7a54e775e4816245f7ff015c16b6deff +Msg = b9377d9bddf40ce17628b4570aced9e4b132e655d4a535af35752fc32f1cb40440b8bd96c4bb3fa703e453026e6e95e12687c903be03c5ff42528bd878afb5d1659b1683138a9e2c92dc7e4a3d0e8d693e32ea39559ce3e3d5df169deff8d67d32c8d18a53c8ef192af87d57fe188a22021b911d1fd95903f4041a3b1c5de1ad +Mac = 435e4ac37f873152151ba089e7f3925ccf3746df525b41cc + +Count = 241 +Klen = 145 +Tlen = 24 +Key = 7438c5424ae95acb1a77f27fcb4338edfc777fb0339a039e37617242bac8ab8d3b62c5c82bed53cd4f2ae67765ecd4570a6e38a8dbe93a85db66915a15d146998250baae2cd3ea3494ebf26951dfd0dffbfd6b75472ed48673cdcb60e5b985f80fa9acdc95c0a868b2621d3dd845b4ef96cb1ffebf8f5708c93d283c73a8f012aa16a439aede13d171366fdb404609eea4 +Msg = dc6430d14e675dec5976e671af07b9a453a38d6e5b97c9b0f5eda2d7a89a84b1dcf9b47f9d78334b9c92e57b76fdf2a739246da825d734f1af411723cc1b3cdb6b20c1ce43c1a419d019e0d29823d9e3b32bfa188a829d76df762bcf0e81849392c1a1e9caa878fefdf51f9d9de33501c8a07ee71400cde78c732703f6352581 +Mac = 4f9c9ab506d2b2137defee277fe205c88ceb16a6eb63fa9b + +Count = 242 +Klen = 145 +Tlen = 24 +Key = 9e49b49d15016f006dba47b8ca55a161e9e95151581e6b1de7d6555f5a1321b760151a10c9c29d25f34b2b43850dbb5060b5550cd3a8dc970ea22c34da9c654c87f485b625c83d35f7a2fd42245b520cb03971beab5b1400a85784c07121f732f92f1d1592daf6396008e63e0e080b9ebfbdceee48ffb8609c3e888d87688271a00d09b779c2703718c30ebeabdc900d77 +Msg = 6a90ace01b9a7edf02747f6de85756a34c551d4aa890c0a8f6aaa69a737c94e3a30bcec495b77fcd68b65af20ec182e1500da793127d7221d91624da8ab37a9275fad33c918e94bc0986ccf6f81f142b71adba85c3d81ef0fb045b2caa112a20e845047298868754eecd1ba12fd7d528b81e9c4842078abd645d94b959fe6e36 +Mac = 1cfad85f7f5b21fba6a15483251ff307621f8f92549e88ea + +Count = 243 +Klen = 145 +Tlen = 24 +Key = 22715d8208870414fde08df9129caddfc68cfbd879dfff1523fe8cf045b450302092aa892692bb63aefac0ddeb839f101fbbbf980ca81d51abae9d5e21b29e70ef80d044696a4a6e6932d756442b9180fd9ab210b962a68d73e165e5f115ffb1f70378bbba59d7bd97527a6c05daacb5c9f37a476957c251e25e8c8d9d239d7da0e24af502a58bd9a120502817d91839e9 +Msg = 66580cc5cd10686af49429771a7f96ead165fdaaf8ff47c8ea88cf04f56675930e0dee1fc2215e1070da280ab6ad04b6292953c6491fb033b405c8c9999c6be670d1e37fe8e1846321c184c41cbd0df3705f916b3e925e11660772bafbd890eef56c93ec269a03ed7011e6ad34f7d8280dd05ea1bfa278e96a5675de04620b32 +Mac = 447949dd67cf2cfb6a090c696cac55dd79d628308d04df88 + +Count = 244 +Klen = 145 +Tlen = 24 +Key = e107f34583d99654ad98e215b8c99952199f73f5e26ec01b8c634e69f3738da3a291f17a512498a6acb82d3556f30c232ecba62ad1f727db60a357ee8368bed7ad7b0c9aa225b8df3773e649592e8e04510ddb9d462ad11704b3333bfce2a42f8b2f0c4a7fc43d27d731d7f8ca61681d0bccd8f64cef05f501f9aaf766c885d4c313b934eee971a5125ac6ebb074e397e3 +Msg = ff95d63521f4aa2744e30fa310ff7e4d6927aa1e393063b570dabaee490366b6ce1b661e9ed8e8aeee2b6afbce721f7badef949920799305df71484e10f8a2b2c95ffc35d0dffdf0a58bbcacc28228af2169a8d6ff19fee4e094711ad33e2b08f74ae0a23e72b09671eb4fdd74986390cc7e2dfe5e786cfb792b7e7b173dc95f +Mac = 9c4ea79f8c3c19ac173cab5a10931d480a3f3b7f5e121b1c + +Count = 245 +Klen = 145 +Tlen = 24 +Key = d489d4235459afe93b34a99d7f8b7cdbd788b9c66ff41805e0570c0c5f619b9d34886d8e6ff323ccd697eaa021a04f316a12554bdfb0c45eba1dc5ca7341ac5933ee150d8dc3321d6951633a407d07168f2593278507e1a9ffdecae2b7cdf6a9b801f329169385e3dbab3df244eb4d932e0b9be4cbc014ec99e343dc95cf2294ac0b30697229c32616eda05096b2c9af2f +Msg = 6f81a80f78d2b33478c737bdd7f60197e34ae39a1f03aab0defe4f3a113772af5e8c038672c4435797cfeb3d894faa7e8558d56ea4745b9067ebf7ff9341a90c3fff66292bb70f065342a0f9c44caaa3af1303d1bc6bbba0a00653e5f2f22acb3a6338be4cb3fe88d4a7bdba31f4e74e8701d38a0fefb428b2d7ccb3d752dd34 +Mac = 15fab21a2cb56c230237260a57e9edf573225c86282ede7c + +Count = 246 +Klen = 145 +Tlen = 24 +Key = 4d40943fbc79937f7cf628df461783d87f45b74171271e1fdc19f9beadda58010d843af69dc2f4ad003dd74b9b570d5a981cc46331758fbf2b9f08aaa0dcbb9902693fce5dafa629dcbd18418ff6bab36b07d4ba931d3400d654cdb47872a4dd35d5edee83aa709a186032e9ac5c528c00ef316e1f85d58be31f9005bc03dc74adb18a7e971a1ca9ba0d6f6c79f29d8c5d +Msg = 61d72517dc2c10d953d91acd7c86d68ca4210e09fedeb5ba3b7c1df95acb6ba9c26b471c8ed6d83428a0efc919fe824b1f865da9803514719fb63c38cde1da3c61831c480b5d47d8656ff17ecb7670846db392d3a2ee8f1380bb3b14a9fc806d67a70c63fcc9470c33cb88b43bf4887fb53017500c100dea0511845597214484 +Mac = e947661a5621e499fda0fbe1a823c4a5cda8e3f71b541f8c + +Count = 247 +Klen = 145 +Tlen = 24 +Key = afa4b912e9adbceded28f67dc34dce5a3a02a730dafb6c081a266cc9d34669fef5ddebd97950da7896464c6838519c68aed0bc6fa214ccf04fc1eb5cee774de971b28d9274ef455e7111dde63302a0118d9d15234bcc8cf669edf786837bfbb48dea4743c4d22527e4504eff9caa03e03f315954bc6cd5a2d07238507a989ce7b04cc0f65041a15959cd4abb5b8fec5a2c +Msg = d73376199cbf8036d6a075ca00afe0061847bbca0aee846b6d3894b46de9ad2a085ad2947e1e5bbb02e4486fb69fd6cad6e550b9339528b7e4bd46dc38bba017efa20bb8a9df50319e1c831d90649081fe8817529bc27a38fe9934929b046cbaf2d2c98a0649891f110ecddc764537b2f7f8b79f28bda275239305dd7e0e389b +Mac = 7e4524628629714cb10759f724b8e1ea910276b926feec54 + +Count = 248 +Klen = 145 +Tlen = 24 +Key = a05bd170c0b3e42802ed73fe3a610d938e6538a9d05c623f0bf01afd5b9b80d3026cfadeb908298b44ef1cfe4900c3b56240a66871d7d634345b24f91951920153f107e22d2a47a59ee621271e8febc0b9d22b2362a3978589814002f0fb0a3cba735f45c52224bf395cec4161156cfdbaa530a04ac88c7a33e9d4df88a0cfcd5f796ace28f7aa203dd8e414ba9b30b48e +Msg = d19c7a8ff3ce59d2cc9c231d34d085366210a28aa7be632b5d1c0e151ab41bb529f743ac3a24d9d0586b5d731c534fe920594144b7d93062db32142a6726b612877fc2e46cf81dc3445a786969e626b2d8f32a5ee6d895122e0c0fa1ce8cb38ad37d20c2f113ccb378b19c848352b29b722787609b8139443df22603b5afb925 +Mac = cfc2c7263683f3c8bcbbaa46efcf0ae1f41fa16e5fdee84f + +Count = 249 +Klen = 145 +Tlen = 24 +Key = 84371c9ff40b745ab5300bc914512c1468f98b339704e204db54dd9ac6c534d88462163f61d9ce058a2ca16718aaf5404a1eb9d912460003d486ef636adeda0e6b1aaa56ad4882e3086fa2055d7e8b48d7836349711d9cc9b934d100d3e7f033c0c69e89e142d71bb661d54aecb734559791532bbc73fd7d12c5491809c9be720cd0bb8203ae16d51d6b04dfcc3b398f11 +Msg = 007b9519c21b4497e5176156adf75bd32cd00962fe23f62a3702fc719a74141a0c1b6c6b4814ba14d31fd16d330071005c2564476b88c6b796d7a5fd63d3ca8719f6d546745890b29dd37d0f5965b1ef81d7e5f9b29ccbe845fc9ed78272fdbb1052f931b0ae6d7a2c7b8ec389f0c2aa842fb6ff3d27aac72db910875d1956bf +Mac = 23391185157dc83f6f4c9b3337882eee11dbc64607d18f34 + +Count = 250 +Klen = 145 +Tlen = 24 +Key = b3edc0ade4b88144d315331bccebadf891c5e05dadd5c4ad053a938fb07e36970863fc2401df9284ba65305f52661052fd1824da57760874f888360248e479719475a499627b836402d312336679ed7d344b08b9180fa07f5fb871eac2e52a407fab1ed5af943c2cd3e74160b02a2cc25de6f2c49aaa74166352ae0ec589314df18dd3a08f33a524542a25aed783b569a0 +Msg = 3744c090cad18c19a41b5fcc4d2091ab8920b70e224e80f5e7ccdd9df5d66551353ef7832618a11bddb6c00f4ad76934bc1b0854a7ba4780a67632a7bcce9868df75b425b7020c59a3e99a2bfdaa2a439f4803dca5fdc91a752ca29efd9798593cd23f9d04f8977afe9c3347ee029b7f388ff0cfa47fce6c5ed676aa41992dcb +Mac = a2854198f88bb729acb19da0f6ffdef962d7fc6d904fc704 + +Count = 251 +Klen = 145 +Tlen = 24 +Key = df0251af61d9f87520a8a464bbe6004c4c9026afe3cbb58134cb242c8cf356d70a3e6ee80bdde4c7e622d9e5da9ca7fe4484bd9b1557aada84c5777100ca3af1691be8487fc36b8a9b0ef4f19da6932225fc05b106e9cde8f79686c48c997741656068d7a6d3b445a635a08dec4beb4057c1a6fb9cc94632f605f82c18a7344f67d7959e6655e880715f83c3afd5d8e042 +Msg = 4d5f76f718ffd84ce27d09fd4d0359a1de1807115c72c0d8790b63e4b57707827e743f899cc39dd4cc3674f6ab0be22ad6780e895087af802424ce804b74ccf7cf69a68031947856093a400feca9e58792cc781a38feb916441cdd6f28de8eb5886734449f1a73bbdfb0f4afd78769a05a3dcb2bde7ee682221a181a145b56a3 +Mac = d1423a9148699c8bda93c8fcf09d6e6ffd0c8f6436ebba7c + +Count = 252 +Klen = 145 +Tlen = 24 +Key = cad62de2048c1b274cae09a6311e9b8900852ad18a00aea62716e1ebfbeea11678be963f248716769d00455adacf81e8b3fffd90a4afab8ece0760773e7133127205266a194408211b0a9907d9bef0ebb6cc1ab2d65504a626259a109ce53108c091228c6b2db8d0ceb44dd5b752af3d10d2c95ea85a7f953756d9dc9cb2649f684cd5cca0a9f02abfe7a8ebfbf28884c9 +Msg = 31068b9f6924197893ccf4b0d2a10129cbc4ad2709a479bca018b58411ab8b936e3640acbfb5b7b3a35337653bc76d4743e3b5dc826a951b65238a20e72b0822b38fbca58d1a14f1ee6c01c2ee4cfc4167404733585a757187542c986be02a01483986f49cfe3818ba40dc2eb5dab3ff7f00eb93521b20a44fd42252666ff919 +Mac = c2475ba7fd88e8207f78679b7eede8d1294fcaae6c705c86 + +Count = 253 +Klen = 145 +Tlen = 24 +Key = 610482010c09a931cd0eff41a9974af03086334f008fefd38aed1fa91953f5491026994e72e9cb85a8f9c9447f7a73fd7191ad1225d305eb39fe96473ee72bcf04b4a8f1184ba6eb8c0b5e26f6b9c8c6bbbd047f8e8ef8aa336b3b98894c3126c71878910618838c00ac8590173c91749972ff3d42a61137029ad74501684f75e1b8d1d74336aa908c44082ae9eb162e90 +Msg = 0ac4075ab986937b4550272f2020d50b14e6dd247ae87e8aac650c12bd7843596740db05443e5c4e41fe34be51fa07345ebb462f8541034982a5040269fd16bf9880a313e9eb873c2c2320f1d41ba45bf0f8b8615d733e283a7f6eda9d2c28a784cc880a0f54bc4eec051250124b5586b2e55a406a46d62ebd3b7223c0cf2218 +Mac = ffaa7de925467d40a8a8ec9a006758eb888c08ae910863d8 + +Count = 254 +Klen = 145 +Tlen = 24 +Key = 295692c6db3d276528169b52c458d2f44cbcf5e0ccac14f284f8109decccb87ff5df323992ec9d7d7766f4692068351316ebc3656e3b092b92ac616a448834f3df4d6239e015e460a656b09676cbdca6c2b207caab38f5c1c4327922190d98f07008eb6ecea045353d4c9683cd6b0fd6d97b87ba8b8b1edfa2f3206e73422c9d2e78958263760824c5b26fd82d2f16cbe2 +Msg = 751009ee3c0c5f512d314bbd9b145e903c20a6af308bd41f3f889acf63bf57b886faf6288c21135b9468604c7bc748caa2abd2cef2ebc70c1dfd17c8266a79eb237f52564245d8760ab47719e3247480d904d0b59dce6f1fcc3a795374b3012dd507e4206462f4ca167d56cbda1329d86795680b391e127dd6a98817568236a5 +Mac = db1b1d1978f71cd6774d0c87a731383fdc74c29222911207 + +Count = 255 +Klen = 145 +Tlen = 32 +Key = 7eae9b4df81fe3e13aa5b291149a892835c3a937fbd584b88a3771f11c0aa39b98675c4465e75ef28069a309cc0f4d6eaa8ae0edca98afd841ca94f1db8be48ab25ea2ebff67f3f4312dd2043c9e0519345450381a16e80ff6a22ad925a98d82f51cd60b6fa68b31747aa9490c4e996ffaa761df945818a3d1459c6fa46d87c988285e6c5cac0cef72d68fa2e328f2b925 +Msg = 2ae09db7a59a2ffe199f37e4af4b2d51bb6c3b17d901f1d63b423a1d41e08fd14a8d6ad3cbbffedd9eb125ad9cab9a666d8468339f65a22df6cf557f03e0bbc7f8d2b1c0bbc46b1f39bd67bafdee9fef01370344c4ed264b9cdb38c94e863416dcb65ac79e31e08b94cae553fb9aa6b61e8ef4936f22e6f8d66bcb42495b6286 +Mac = ba84b3d221ac589863b78760bf6b9839d476cf8d6bf14faa9329b30a61831407 + +Count = 256 +Klen = 145 +Tlen = 32 +Key = 760c1da063e104fa69d2676a8673dc458cde629824a98dbb1215e329bb88858ee43e1222bc3bc8361d84ec0c0f8e6cec8ef7c4748d741e303a0bbd6b84829b44da175104367138ae5bd7ced85ba05bba5bead4859a8ffff6b055d82a146534b4e1ffa4edda6b9c8bab33d475728fefd67d215b7055e27834fc5dfc0f741b9606805ed185af123cf49500c88c5c4571697c +Msg = 42145074b26d8840327fdde4979ce4f630a48eef9e879fd5e6056117c5b899b94455bab08b2f5990fafce16476dc88dd019781b08e26733913762b64df688ecd2e1cd126fb6fecda15c24bef75fec731cfd4d68d674afebb26739020ed7d92f229f2fd9da8372965ab59854d3c088b38c1e4f34fd2f827a24884f81296008f6e +Mac = 24b4b0ca2348c219c151297f220b2d19def3bc0d8d6771748145d6eb1efe5a5f + +Count = 257 +Klen = 145 +Tlen = 32 +Key = 55d1a4864299e24bb53181794b5992ee301651062aab4e23d9c5ca8d3df6647d7864f574d5c3b8d10a80aea3ba3f40bc3e882707a5bd891bf950640fc4323090d38fc0323ab86a04996167679d0c7c20c9c5daab761044d218206f7fc449aecfefb8cf6779623f0bea3a756dfba78e425835359ba48bc673bd9db384422226605349e8bc98a7810f8574a15cdcf8be4b73 +Msg = 846573a89bf96dd9eaa5db7799453bd92f8d7efa4df05e7c9cc1f2ed0499804a1ff892c1ed2f4cbbc97dfc1a9b78f3bf50ae9450878daa388d80ffef8c5b2a7bfff9a83769232ed347b43e9c43fbf9fdaa613446204ccdad93433f936d5275080eb0dc90799fbc274d94c884f898f49b27ee866580f670e39451dd610f460af8 +Mac = 18733c84f9c0258beeb6b5d426e408ff69fa7b915b2a33ee43f08ef27f8bce96 + +Count = 258 +Klen = 145 +Tlen = 32 +Key = 6a2584a7acc2ba137771c3f90450d20f3c7827e38685857ddd53e54025056c12bf4c9bbd5be6c6940d64c759a431f35e37d04deb0065fae06d77f59b75f4041c2975eb678bc4df2aa29c3da0ceaf7cb55aed616b5004717c9123ac41240478d2cf29dc6fe466ee1f5e9f8f962cd3555ccd59c92c1d6ad39b6fe072fadb3db07cdaefd69c10d3dcb968f7230366a4679bb9 +Msg = 2eaa2265498645181a92e52f375b67445bfe8dec5f46fff465152bea57054fdf904ed46cd8ebdef396f82127415ff6cf18b3aec7135c264719f59b6773f2c0e381860e1cabc45c609b04af6ba988532e975f2bcf7f8a45f0095eb134e12994ff6918787eab58e6e8917c3703581fa7e942caab0c8b1885789f1715588af2f2bc +Mac = cce77edb3896dbb2dc8eb9c3c21dca293b31e89ca5ac70054ab58c14b4eef28d + +Count = 259 +Klen = 145 +Tlen = 32 +Key = 24a262e7bcff1c84c390b9028baf3831393f00b175922cfc668a26a6ddff77e4d061dd4c0b9f9edb22471d3caaeeab47a8d29fc94abea983d52e6375dfb4295cbe9a2b7940c9c0949de9fe41a9ca87624e03a5ed3ad99aefd56231d176ea99dad69573f6c5462ab61bc08397f20b7587121a3aa5adaaa6494d6db8440a686f690099de4c00de83498612d5c8eb791cc0dc +Msg = 4c1723a365c8567dc52126be2ea791bfa321d7137c582b69b91cafb497879f8a6186ccca89944d82f7c97110a114f8875cc58254f14e4721744a09f9d1be47ada89fb4775b95e7de65ff54d9ed377b379a175f3eaabc3a933e896f5af86fc09dc86cc1f203528c58b6cab763399883990721561bcc2a6c88c0e2c91e34237222 +Mac = b8e4d0e1ef33e45d46c11baf98be472d688ed629e3ad98a229df5881a944af8a + +Count = 260 +Klen = 145 +Tlen = 32 +Key = 5425c3a3074116f7626c227450b6444e40a380cb7930755cae11900dd33d81202facebf5b15f602e87a28c10ed8eb02b43d1533d63b23454314f823374294ff7e4e343fa83478df8318a1f707bd11b4db5f388c648814a834c0451015a8510379b53317a2500879e88ad445ea3876cfdbd92892ed1a6a13228b765402d59ab297e821e3c3f923467b39261a00db98b8383 +Msg = 5e1e09f59a1e2c5f1e8a3f697b40f1108d3f9b5ffd17db87099e7e3288e5a415286a1ec4fb8f1bcb324b04fa2820a400a24d8c3c5544b6cfa85e68f6bcce5b97a9d41d190b33b479bee4849ae50c73dd312c4af260975eee032a719d8537d31969c2cc9bd3f03f924abc87f2bceca5cfc2439d2a26f91d0ba36860d0eb0852c4 +Mac = 502c8f03f0e293a35dd557fed9de8c4674b1209c8b5cf4002fe76046c654f039 + +Count = 261 +Klen = 145 +Tlen = 32 +Key = f04cee99d3a813c1d47381422d14d8cf14f99e65e02b83806e26e98ec3e7a3a4f246fd704086fd6f872be95fd80b09f864a8aed79dbd74bb9817c3f3b6a69c1783d492f7de1516d15bc0f8c7e51d2b8fa8bfc96d2e14565ec73a49962f14c82d6b9eb416f47de55017dbb7609c71c5fea6e5f40fda57b4d3c33782607559b14f714b6bb5c9e6f35585232c1344305fac27 +Msg = d4b531125de389a12f34832f539e0b88b95c41db22407cb23c498f270f784c5599e0470eb5fdddcc424674e980050312bd67d6f932cf8b4a287061e15f1bb23aaf55bd28f0ada9ca184dc7bba3ce188a38510f6a89cb972a7ba05867877436005f3d1bcad59df785f970050f82a14fd870417496efdaa93a7d00fe224f2ae390 +Mac = 572afac574fb3e28920fa83a792864cfb55d18546e6cb4c4214652cc2797fc4d + +Count = 262 +Klen = 145 +Tlen = 32 +Key = e04aaae39bff1b1d82c59b6883602ccd4c58882d0faa089082bdc4b92b97fcfeda51b75677c8a9b4fd965a93c74185d20bb1bec3a4e8587f14ed867cc909c0619f366918a7d5ae25279fb137e1dee7fd98ddbe3bd19d841dd7c984cb01ec723d37e20951b38df21b05c9e87c5aa11af6fdc3d0be1e315213d33a06cf5ca9d83cab3cde2824573c3ca1fa4689b9f1e56442 +Msg = 292a2ff749c5acd4ef56adfa4827e0a9a5173c4dce9cf2a59904a024bb00c898dd628209f3266de4c9afeb59de548e01761bcdc4ebc4fcfa440a7bd008252ded55932b562c18ba8f0f047b04ceb4e2a79e5be9d96b03068e6fce5aac04822bb5b64494a69da47b1feadac4c3bf4fc4e24460f956f75ef8aa43d9a682551eab36 +Mac = 136467c874c375f53ac1dd50424c06cf8235c78b61df5e3dce91127b271b66b8 + +Count = 263 +Klen = 145 +Tlen = 32 +Key = 62e0b401b2054a6d1df230f0340b0c2577df0235bafd314bcd0980485b0f9ab71316370306f99ee750726727fb78867e20cb85d74fcd11c03193b81b6c3cf116c7815d5e8f8e4c90391083f148903d5e72ff6f86fe92505670d019b568e90972c849ad7a156d5e4f20f50bb5e5fb39afb3a447a98df4f7f7d1e72a7e17bdebb15c95afc0603ddb0b4c4987dd986282572c +Msg = 6531953e391507d0056929520ced0aa1849426605636414a1f8596c67a4231bc81b19aa8914ab3ed4eb1e36be7e874539cc43a3a7d9d766d744af985854c8d3b554a907de9bee2c1b1ed0299c51c73876e016513e878911c6677656c5744618fe8e5c1e4cad95cf43505cc032df1cfe50434ed13202d5bfefef420a377907660 +Mac = 0b7ae7ecf74b17eaf751bcfa7cf35fa4e80f5387869d40773429c59e5d4f8e70 + +Count = 264 +Klen = 145 +Tlen = 32 +Key = 5e675b4371a86ecfc11b2c89f59a9ea972c7698f2c964562bc0cb1f7b446e6f42fbc0935acc7a46e1c615712392ccb741ab7e82d04fc48bd842deb75bab02c94f868f3b08c362d57d9bf79f7ad7024fbcec05837d6b5908641aa4fb1c54f1293e2f1837bb9fcefd221befafef86d9285b76c217649ca07051e0c47757b2c803b14e12060dc21d4271ce443f0c22cfb5cfc +Msg = a3cd8e7f41ac042091604398ca0f62f0e1ae18565a802cc35fd92cda0f2862121834041788a6ab6ee0c806586a8cd0facdd0ffbadfe03fecba3d9eae129d8910c632f779b42fe446d28901b37bfaaaff064c18cb9dd4d8c44c3d7b81598790aed44ecf6b6e5097ef8f2a9b71a262d848b4aaca513d63df913d612c1b8bee5e34 +Mac = e5d4c900d1ef54282ddb2e7028deed0fff987275be71d904bd42fab55c45bbf5 + +Count = 265 +Klen = 145 +Tlen = 32 +Key = 64c673e5532ce4debe2682a3d104eaab398860797ff0c4c09430c1caad80481a50163d51af35704e3666ce996006d902ce0055859adc4471e9f915cabf1619eb1817366f3406df5232594354e073c59ed26dada8b1151d5ad6374672171cdb25e151c60988a91b32da854a9bfa5398c86c55d0aa6ca435c38474bc8b5d997811d64b56e553260a365774493856af39c8c4 +Msg = 1230545c1ad282d6df24e5e35a0f544c3f4545ffd2c941b3fcb195cf9e2b4b8825be584a5fd2175a8d73f6b9b952704b490c3b38d5afc293367bd53adfe59ffd71e2d90289613e67dc193f2a8786f746a02e611f1129c920a6e080a36415d4111d243f4a4188df47f7a026fe6cb3d3856b33217b2f3e3ea4756afed3d5c2d10d +Mac = bb51f90cd491daea50cd34d3c0e73b7386d93ff9871f7ccffc9d95adc62cd233 + +Count = 266 +Klen = 145 +Tlen = 32 +Key = 78c0924cfc00a9bccc71f158e1b9c41d13e1587edb089fb35d596b55a63ad62832c6e138b17e5b270a3b05c5a168f3e1d66d355fce6eb78b753666adc36e94de3f139e19c227cc957ea678523ebb73f2ef34a4cb6034f23a4627653a83fb8735a88e111ab862c3af2f989429421c0bfa691dedea1bc01869d815af236d4a77d6741e81601a990a1d25fa9f6f35f2859e49 +Msg = 5ad11407eb3acb52fb72295ab8ff76de2fccbb4c6dc012ece4951f5a11e8df395c8ca026402451ebabf1fcf5a8e891093b08e5328ceafafe489a81e945a59d1a6573ea4dbcd7be11f5e5af33f104557ab244519478f18d512968c60ff62948763c2ef965a87b992b9ff748fbdd7a499a5c27055b77fc534d4fa7f6b36e9b67b4 +Mac = 477db58315957a9d4281f6b6c1810a401c73d7df6ac839a8784538a10b293dcb + +Count = 267 +Klen = 145 +Tlen = 32 +Key = 36dd84a5342524a4dd7887aa7eba8f612a8505bf0c268c2efbe8d3ea4f960faaf33ba982bc2c3308f948a1b64c7fb68fb891bc05fa18781b1dc95dc749f7009adc58cca2bb0cf790ebdbb4165bbfab9304a2a6f234688dcf273094dcd8d7b38416be57cedace5783d8b92993548256b5373f2b4e621eb19442a6e0f3a53f10b0ccf5b0ccc1793a2beb6866f5dfd09f3d79 +Msg = 6dff76ba60cc61480efc62d01545aacfd41d25922b725b94819c94070c903fb14c5694f9d9bd79425f4da277e77dfde758264d543d381446c8acb7a517b9dd87b74b184767b1c7d71e953b574f3218e66bc1feb8a83469680127d6907d142898b5c649cb901014b052be7397d5ccc47215d682e6f3d021a232f739f0c607e789 +Mac = b0c443297770690d2103552d566b2e2bffc3e69871e1b90aa48609eb5bc94cf5 + +Count = 268 +Klen = 145 +Tlen = 32 +Key = b3ab0ff054819c5343a88e8ea9717e1c22ddfba4cb5f3ad89de2099df90e056c83c70df834f7f611ab8e80c8c4c789d46cac8134b4dc1e16248c51f851cc780db10bd5e2afde3f41fbfd1756248e7e1068a7c5cacb0e252b6643b14a02c08816e57f4ff6ecbddfacdafe3a7ff051c499bed5b0ae387cb8de0c0f11dd33729e51c62a647b141c3e1af197d18c5195c33715 +Msg = 7eea726322a48f664ebea63bc1cd7ede984b402463522b9e7ea58ac09ff0e342ab5172c7ce16d5bdcac909848f6a95d20dfb055646429a9ba7ca4030982bc006528b3719f065c752c9898cacfe64d2974f82859a3351e83b27288a234687777e1aa1aba1b217cceff40718fd35459cf407e8a63752097e46a7c751e3d08e6e73 +Mac = 4aaeb05e3eec82801b11606cc12978d5b509438412343bd292964c003424074c + +Count = 269 +Klen = 145 +Tlen = 32 +Key = 26da41f4d72a6d5f059496ef7a08fea8b8525356eb3f3bd11d013080a9d48e1cf2e2eab65464a6fc5b0bc2b8339ef59960e4fd36afc433506dab6257d62ed930d0f1bf36dac7a77f3f1a64608f8e1f334fe1a757f0160779fed25e129a06eb312ace687b4f999970188b24f0751fa3fdee11f8c2947be0d4383eccb9dca3eca767428c8d9d23a3584d24a96fcc9aaa7fa3 +Msg = ca6fb305a240774c51e5aa8d423692819cc7457daebc23ea90dea4f507ee5487aa391b78436cc20078aab36eabdc001c1e48a7a25b66154ad3eee8c4c536f91b61bb9ae82efd1cc6a99195052f71dfa31c96e47735c919b043b6497e0142940f381eb7bd299c8e862bc2d7bc959e38fdded88466038e3a04295b4e8b84b92c4b +Mac = d62bf0f254e4eef3562a201d8837763af8d136e7f045bca38e34bb75667effb9 + +Count = 270 +Klen = 145 +Tlen = 40 +Key = 816aa4c3ee066310ac1e6666cf830c375355c3c8ba18cfe1f50a48c988b46272eac0f2f02a0a2d2fd8fab2e62310cbc73fc0eff90a818cc7ee21049a095bf5248babbedf60613fb610f5e001e39ad4b748159fdf77d0d548562a257a991297ec2ed41278d832210b1ab7f6a15648b07136fcd9644b2e33ccf4d0b4538201cf3199e2f5a3d9a65c98bee9ffadc543e65bd1 +Msg = d0db3ff9cf2da10d1edfef389ba71780cb49e05dccb87c088b7e60f5375f539ef539c583d52f636f0406e8fc44cf36599ac7a54b467b9b72f8305dce41812482484a74d7bec5a98314f3d32ceb3ec328cc5c668719765253438a9f163e0ef89d32d6f1fc74379bd2b46d57ce783ae772c9d0cb172bf1ca32d355cfd5154cf679 +Mac = 291957f798a32c65954d31289aac24d62ea47469e5b1105cca372eabed44746316cb24fb13c24853 + +Count = 271 +Klen = 145 +Tlen = 40 +Key = d9aa1a8f94471a4c69e71fd256df38c600924b42a595ad1e5211f06e5669fc4bf61d61d762efec7be844797368cc078d0865122d283d1d9599378e630991be5bc2c3516795aac3dc10e544fff880c6c8f3cf54e6849da5023c87f1482fa20324a664904913c1c7f84a94297fed419b002898b9739ffd6eeea5c6c124afe5f22d08c7c685c67c1f56fc17cffa3158aebb11 +Msg = dcda25e0850a555368ec4adfc4135e47e4f347374e42eccd3ea478575286ad5f874a7ce564a5d2eb7546b437fbb98e54e28ac8daf3ad9bef4b1d230e0cc4b507529b724769121c5a3db229ae1101169a74a6fe9e71cd6bed07cd6c28d908e86d25133190fa18dca8a678d1ce6eb49e21838d110e316a05ce58fb7c2f201cee98 +Mac = 9711173e1c86fcdb11b7c224ecb76ba390c2e1218d26f353980e656a08bbaad9ca8e8f27c0aef6ad + +Count = 272 +Klen = 145 +Tlen = 40 +Key = 7b2d69ed2cbd0f37dc44f26506e4fbce7ab92593a50fe07413d2b3e83245246c59f7dc1b08f4077f7238faa73869187978c5f64a0659bdacf973d0876a5baf6c783e1c258f6b7c91ebc27faf576803f83bc036f2d597fb02c79f9081d21f6d13e1e86f34498b35144fc9cba5eb4b85f2cb942eb29b33621d843d39fef2fa260a9bdf1e70bdbcfcb1a63724b27a79661031 +Msg = 7f737d59c6afd85eb91237ec52c3f4845d6ae92921423315427035abe693e0ad179c32af69e0fdcbdc6bea970397bd5466dedb6826ed090fdff9764dd256fc274446a312210f67ace5503baabc944d11e8288caa642a68afc7e3d8cb6a57a242cd19d76b37649c679d68300dc5e22b24acef04d52422d65fc1d4640df6bb5a66 +Mac = 2aafbabcb09f72cc887ff2ea74e59a271afa5f160e8cd9d8b5fc9913deee6c9127f59ed78521a516 + +Count = 273 +Klen = 145 +Tlen = 40 +Key = a9c911ac37745172987713087c13a84edab4dbb7e1197e9430b549954955e58c43044375c02b32b41ffd319df3128139b3527f47b315318252891f22755364a5357904cfd57f80f0f7d0a8650f60b161179087ee8552642e7a8da2e73cc3ce3ee6f1fdc35eb663ae88b82168b9445f4e6f349bb13f1640210e8a7beb84ec4ae0be33d658431902773a7d44afda05b48621 +Msg = 9bc97c5dc1b1fb7ccb9973c71382af696a0e9c2eb7930939e16eabf9ef9a64596e81c4371311d118a213031a0eb8932ae275f676df11a425e7fd1d461ae32e073e81702864b813afc8e0d9dcfa5f655f3b7ab6c92a6bef41a0b35978d8b1aadfd3748817face49a806a9fdf71d9eae723dc4e60edec672f3d3396675722c6147 +Mac = 691863b1bb5451493fcfac2843cb345bae42785f1506f8bd8f994b9d044c07600a8c944140419eb0 + +Count = 274 +Klen = 145 +Tlen = 40 +Key = c1b9199017aca6fbe0741e5f9108b0fdfa43dd23c1868af30fa553658901239082f101256e672d3c9ad06c531b3ba09305be9b56dd1535e7508d9c882421ecba70e200b8089c87453cb65aa7c25a0df4f0d6c38c2e4247e7ac63599150d04672f353bc53cc92db9e2cef8f656cac1ea62453fdce9e55e87b8bf13186f4575941730eddfda29352d0d443b495037afc330a +Msg = 92621ba35ee326197b59a3464832972b9983169dbafa63e0b1145877c48f083b3b23a4ab676d9b83e32c05901aaf42c2098ede834799b847420e6464cb0fcd25d5521f19791be4b13e676d0a986a7308ae3cfea460d08687892558d781c03c51e75955989dd548cc1374a15fc94c72240ff63ca9108713c70ec1fe77ef8b9de7 +Mac = f1dfdb6f3b095c096d342819a21730c76fe46626adf3c27703a207ac21b509a61779e6dcffdf9847 + +Count = 275 +Klen = 145 +Tlen = 40 +Key = 1783e40062c8e1e84b6b23df731405e4a4f540d815fd5748ea4f3288fbf20801d6ca83cb07c71f7f975cd446d233f4364d1f56df2852b42091d052408923e039eb50a257aa0bce025a2736d8f2502600d0fc90bafd9f663ab31e48b61c875fbe5dff89ccd3fcb61c9cb492bd5ad564e9337635921d4d363d58235c133b864d3534be7f510b029e7366eb2f1d9228749980 +Msg = 7f44275cd31c629d7833517c19d41c5041b3bbffcc8a0cc39c05222e8ddce06caa3ec7c9a1760d7274c9ef80729d483266e1617a0ea80bbcce17ebd2a682165362d2de15102aebf0b7ca8dc5463350bfcb8bd1d9e544d1a17cf9883baf983ba80ec611490a7f239ea9fdd2547fdc5d7fd97bb3243ba585fa0d71a07191667af4 +Mac = a63d553fe411517492f32b274278bf921370b8a70a27b835176a78b1d812a95f11286e65dffd70d1 + +Count = 276 +Klen = 145 +Tlen = 40 +Key = decd5ff6fa8843501dcea0e98730d868d32d7af02a9c17a2b74a52645ae337e1a116ced1f4f4ef7b0f995778b60ffcb9a36f9eccc4499f5aa34614f5260c1c107862714f47953c02301a2eec7774cc48fc590a0e6a101c72b21d89adb82081014bfb70f75b33d3ec66994bcb3429ef1cc432e73e86b737f0cb15d81779e70dbb0327f45298965b419b5dd6a054f40e3de5 +Msg = 3e3c5774c11abe73629e400891857106285299254da0b6f799b6c41d7a5c3bbad5edda28f0aea3ea905e27e25e0e03c48f33abcbc4fa66ab2fdb9ac6f8714aa2df89dd9b227921d5a1b38f754099d1118d938164a35f34474ea9b7dd6fdc980da237e8351f23401cdec40229ffcee1d3689aa459b07926b33c48a2c8a7442de1 +Mac = dad2422f9474b3c8cecc73505aefef0b5bd8e23d70e66da3a71578b7b0499546e5c9ea59ead1ea9b + +Count = 277 +Klen = 145 +Tlen = 40 +Key = 74b555fb6542cd797d87959be910db67e9278ea378ed1e8d2faa83cc676280a79ea929751cb7a354d5bf2b1e927d59994c0fa6eed8052d5dcabbae2e93e7d8ebec6ec8cc787ccd73a4d36ed9d363ae89b81b8e0c0200d4a43f7c0b3dfaf8cba027ad3aeac2b6d33cb26a66b5f3ea609df4f64de33e059bca5794a1dfe6bee02e170d88b541903e19c72d1c983c39f93fca +Msg = 769b0eff7e7bc710d9fbd289ddea554ee7ffbc67f21bf36168cfd8f1371ef0db288458126d37ff2178ac13c9145db9ecaeca01aaf3bd19c9a1d3c15a9638fe992eb21316cbe1ad12b5c55e2c25804c3d9c5d2b80791268f6cb42a7086446706f2f2d2551c30138ac374c9af838db77085ac22032aca149af8f257444c8d1ad22 +Mac = 23f73da7fef0c97e39b5a9cf19fb52507443fd2669953ea3bf4939fdbd678ab58b2bca3a4430b203 + +Count = 278 +Klen = 145 +Tlen = 40 +Key = 087ead1bca05ee15f09e46ec0ca272f96841b609edd5d754437069af3ab7510269f482fb15660a0454dc52737182a10193fae37e9aaea9c34a6570e7ab1526b6aff8ea5e16e2146c8fd275f720c7e01bc7d5e8aa6277ec1dcc2751d1492c0f7024b46fac96221334eaa936e0df1a352f4efa4ef40cd8a84c12dd94d3dba513180e4d984e5dce0f44ad891d977723aa266e +Msg = e4476c025e67a3d5bc01f3ce55e578e84a807e935b5ef156ffed14b7b384765f92a3237a267d175d7eb3f86b80630439816148f013c412f31ea5aac233233d1f1caa1a6fb8762162065277d67fa67ff9a9b006aee912be33988dee005a0c67f2abe4baa8bb5aa82e7c66dad8f9b6d371e9f62295844fdc5c952d4939d146de21 +Mac = 42af9bb87aa1037114f53189c0d05b5197f42083fa6630445e5021d81f525550e8316d25ac5e79e5 + +Count = 279 +Klen = 145 +Tlen = 40 +Key = dc454e19f3e1181ff3ef0553a81be2dbf3cf3d9d704d28f757fb39b1a0fdd5306b09aeec9e778b24d09848d066491dd7fbc8238206c61330b6bd514c21832a7d9e205a1c6fddd2eba49db8043b70ae0f8c6657b8e5a1176171ae1b135e169abb3e2f5a93ae3875de36a55dd871b81eed6e51e3295507bcf04e779eef9edcac5213e1b437a3b3fd63505940344f48f4d768 +Msg = 8e4c5174a7a7920055ea1ba5e307af6c49e71e33fdf4bb4f0bdb0f766890cfdd83920c9d1e70aa5b5c8c13281b1f2ca6837d896cdf9bddacacceb413f0d564f1ce1a409a5635100ca2b2bed21e1452282719205fd840408320893f3c187c14f2946c5634f9fdac5b4ee4846a95ee08395b444dd38eedce1c8f941ab7888cc926 +Mac = cf6666f246b6bc5cfd0a9bb8184f8c0057d62ff8dec5285c2d9fa18bffcfec9663374422caff1add + +Count = 280 +Klen = 145 +Tlen = 40 +Key = c7d57e7568f937194e12ceed4af8cd23521bf054326a7e7d7e73d947cbcb548b1eb04615a5ed5da8a5fe3443b47527a3289c6609cf5c483de15de2d3326fd9adac2974c1fdcff51c8d792a27b3723f2a28dfd60ebca15967477c8fb2e3786eda58873102d869aa7eedcdd822afb9bcc03a2b69ec5f015b029a16096b44aebd1b0a14a45e9e8121d5ac4067bb1010476d46 +Msg = 4e462ff4568a9185c42651cb9cdcb7408682d20825056b18a5ae379e93a4509df2b3e6d88b4b32f284ccacd334007e4e36e93800bcbec57b26309ea4d4f13d593877d5572ffe405b91cc398806b8cb091ced09f797ec007d09d0ea3aa2d6a5e6481c6339eaa9a20812ae5fb2ba0b86ba6115aeb55e97036773178329a55a6e8d +Mac = 968d6d68367e361e137ebe60422ed2c309167402038c67edc11ed9961df1bb08c359996740e0da83 + +Count = 281 +Klen = 145 +Tlen = 40 +Key = cc65da6fca9702fe44f2d808bff6aa3591b21f1c4792c0b74379b613aa0fd54c7d5ddab90597f16475387bbdcb540d8ff72abc323ffa9803e2167611fb3af319a920b5b56d50f4d0d336395d557666487c84f7ad486f8749d2fd962e30fd89ba99d9f2c9c96b122aa7119d502604bc4a69e558f62a9996715c579ed10fffa11795ae1a5fe38f545a39f42cfe06a5187c06 +Msg = b04dac9b967eaa2c89f887f25d4b641fcd566eb71c60a944fd64edccb1ab2e006fa000b608e15999cb92991fa6f6c9bc8f40205622a6ccf88cb8efcaa7f0e741668ad2937495516e184b8de95c9e78bb6e1356aa46d37b47890056d9ae45ae975fb12c1a22c51a1138cb6a37c56afa823278169dd00f3f99bee32ae00cd20c6a +Mac = bb402a160edbf81ad5f32e89f3ff51483a699755b31ab50c03eb50f4d02a285cb4ca49536e16f1d3 + +Count = 282 +Klen = 145 +Tlen = 40 +Key = 96f763e5bffe0bf5bbcd9b942bcfdb3e32ed26ae2a6ac1ea960b6b7f587c350e25ef94073506b5b53ff3107ba4de405deb8612c16d2cdc7751ad10f8bbee10eb417c44ee9f746b92aba12ea78be5fbbb25da10ddd7b8d6a7687a717b3f3c950cd3e89b206311d495e71f1da246adb360c92f4989d0d8587fc4bbb7904c306b78c479c027eba599c5dbb504f43ffe1155c0 +Msg = b59d490ba4adccaf7255d9b6129013866786912b58539041230a6415f3f9b507b42fe733263cda503038d4d77807bb6830da886b33f9f8f350c184e7e5e89463b009f05ce35c778376c4136cc110ecf04a7adcd0dc74249ad9a55dd1d02eb14852314acf02940b11ec027ebd18330ee45e6e77a37b4c7a0165bed51adc51727e +Mac = 7a95bdea413b7997f94a6d16152fc254bb5f34f2e6d62bdaca1efb7fde569e5d8068bdbb7ace2609 + +Count = 283 +Klen = 145 +Tlen = 40 +Key = f7d56910205345c18409bbd42bb13265d8cdb1b0e1304ebf3dc1ea46df7c1bcb42b96a0946b1bf973a3e19c53ae282c7bb0b431564955411209116ea714544c10773270b91df0a37d30bee90f8457f642ae3466661ce1f51783deece86c38e986b8c0adea9e410e976f8a2fe0fe10f864ede226c7fe199c7704ed8b9c7ffdf96988b7a4937c8b7f44b8e9dd724be1b734f +Msg = 23db86c1510c083f02ae3d8c9ca54dbc2bd8540c4c8465d349d7cfb585ba9e1a1bee65dec25a3b4bf4a304444ffef2c23b424b85cd426c03eb590ea5b146c832143ad58bc530189a587d5d85a6a8e227707b16c0455aa0eba5d4a3d16678409d57ea5d302436a5157963d0b76a4c25d113ab3d277b770974bf7017a36cf81041 +Mac = cd2f37c7d7cb19ba0e8021dee4a3af5d53e76729370fe2f05df74eae6e9566814af0ddbf3d23419d + +Count = 284 +Klen = 145 +Tlen = 40 +Key = 4810d4a682e216f0b461a373efa1469b7f18b31ed5ba1c3ac562ff3ef274424b86c0815c26aaa7842588bb77f74cfd4ce963328110dd3c407fcdede0bdf31daf7798faef71baa01ec269ea7b417187c53b39504667ebd8101bd54587bf105f1f835fe7674d592a47f5cbd685b5580b8edb62b574c12e1a33ff42af38df12302412dcefcda1d16d85267527a03b48b23033 +Msg = 1ac164a39ff2d0a2195f3e7c5e506362f016dfc38a4c70b7f95d669e2d475704909e13c997d3da7e96b6cd11d83aa3adef789ddc49f7bcef042b319f033b15f442085a66666a024399bc8e50949cbab3fdec6710f41cd9f3e9ac226eb0ecde03d70721c3373faeb8c97a6a81bbfe103cc37925a9b4442f8b4fe822525be21bf8 +Mac = f611b272c28453f7afa7532e2c06507c5fffea12c1e7282bff8b1c337e85132911f67ffe76c00a89 + +Count = 285 +Klen = 145 +Tlen = 48 +Key = f05d561f5ad70403264c5e0a0edc12fd473b19c0b40f8cd85a99ba2a14987705876ab76359755b6c9ec54a3c93f6c4e68f55f3b93642c3c2f0d9f4919ad16e407ba3d4b279ef5b198c1cddbb744029f5a73f9e808e36f8f3f01a6989af9cec25b250d693220fad11d99a3e0e177fea317741419d22b3d27443a54099bbc299bb15b9e48fbc9bf95c6b8496bde67eaea3e8 +Msg = 77d3f3e647e67766e5f4cf1bce5f631bd575ddbd02f29643a0c64dbd92191f2ae68db3dfadc3b62d0920873e87d13340af0ca3c5da99146a4492c8b76267fb477624192960f72e85b7ed9e8318fc1668be46c203539cc1470641d639def1600d4e228c8b098ac9b817e17cb329e8f5dd2aaaa23c160283220f5dde09aec134c2 +Mac = 724e5d2d51d98c15ce2e78f861d7b6f8952882e9d93d40850b78a23e632c4e14a222ab3726b1a0aa7c6b2cd66082ed95 + +Count = 286 +Klen = 145 +Tlen = 48 +Key = 95ece1c8ae5e94d16ec9983b1089a37395ad5b1d660916c13c87e4c13dbecf8f68c6611c324a679471def5487a93aaec86c935025b4518962884ac2cb04e66f7aa8e584b6860fb55b86c2b0a0873735dcd278bb525401f9ebaccd2beeac6830c26ebcf3c98c9d77d09194367014e872f306e641e0c21b241bc085e61354faf35a386cdd70aac83752d8d4449af4f6ccb78 +Msg = 18dbab9f86b9d70bbdeb018f6a76ea7af23eb2ff111e9be3c13811795d8ae7d006c3e42b46547eb1f3c9e566565a435a8dbd42212e3fd0822d131f7300eaef4600c40f1d130521a388cb9ffe427f1bff19aacb9c7d0a44a15ce686a2469e3934d086365d36f449484498353d760cf9d15eac525a46a881a617584eed79cf4d03 +Mac = 2be1bd6a766e30792154cda00af97cc512e81413e0fb761698f39a26cecc3face6f9a98b7c49605126dfa5aa8de1ad72 + +Count = 287 +Klen = 145 +Tlen = 48 +Key = 70200eb90526e89d3d139d4d057398534fbd7d91087dc0834ab270c4d27553d4b4dc38184d1e89227af82033074f5bfe6b1673afb272092cba1c029ba20895248044a2f8522246923899ac3de0e926d6417e7cd38c1784845f27f2993c7b72e53b1ef461fb7a4774debfea7176891f623abd40047eb35612a29be8c68919119e4c33d55c306db550d63281d9b2766e2abe +Msg = 1e6a0d7f4bf483287255148e2e9346734c14751421a6c55121c35b0eae12cdd92e30d6cd60b14fb6f0625a7649d1e1a7aa103f817cb53cfee3253f3d9313bf24e543fb4a2994eb143e3d761e6157e5dc439c98815e6ef71f881bac10c95f10966a2ae2be4ea43f8a866ece4e1f2b3c5b3e40e8db70d7dffc3b2a0a51f9fea675 +Mac = 40497133e82d9b6a335002f71585340da2fdc6bceb03fd911c82abe8715191624671bf476b89de4d9a7bdade775ac744 + +Count = 288 +Klen = 145 +Tlen = 48 +Key = 332b091239699daabb4df4d8d45527a288437b8c586791011420ddf5f1a159c9dcf17b6f0d3564cede325a68de0e783a2156a4e3db46c2092d4427f93fad518d8fd4d553894898eb575642b1facff09d9a0c2a671a2e14eef0aae8da3406a380f6ddff07d529a2c9cdc295fc5121f7929a6af35d3eaaef77045c06e1f733b96ab913e1d31a60e830e97c39910b8bf5e2c9 +Msg = 64c479cbb5c9c6167db18c881f23699354c8f4c67b4facf430b52f931fc3ad621ad89b4f6ae8ac9763c5fd2f3c9d8f631dc4fbbd78b461289d53a2558974cf5eff9fe1a9db15aa10a20f0b3e5d47685ca8b959ee06aba2f777eb66644d5897a73ba3b1a3af57a8c861171e7f2c27dac81e2f7621cb3b57abe605e3881277ed87 +Mac = ad69ddfcbf2e6383eabb9f561d947eb5a6cdfcfc220f506e591881291ae85524394e4b4568eeabf1b0103d07fdfbb8da + +Count = 289 +Klen = 145 +Tlen = 48 +Key = f87e5d9fa8d2745f9aa442686bb0e372c190db05d42fb58f2e80ebb4af7006e5d3190634383804665ae1164aa171734a9fc5d84092a92a8b31935c61a5929366d581887ee6802ee002a5966d59ee0f3f667a918474f95c8d6062dc22a0e4d019841eab27bc923af51b5788769b0fff79a019cf7a810894be4453339fa94d04246b5837d4c25670cc2c61b5106dbc8a1fd4 +Msg = 38bd6300e7ace5d0be9713b5fd4ece221bfde5b80c5b7e14c023b8ececc88e5a0c65ff77a9f26b2cd7be41450319d7c7eb519984eee166ec86e4372613d00260da60de634dd2676a8d5364342db8a758396e35d976b4a7faec07d053a2dea025a99848eb5bb39f31e53ec5a90391067c0b3b01de2d3c09e5f975cb9b215c3152 +Mac = f8c0539edea90bd9cec6a408a9d47dc2e341a68c5d91fb8cdd48c13f7667836dc4b68c8ec2519121a3fe02e571dc5c74 + +Count = 290 +Klen = 145 +Tlen = 48 +Key = 7da3134a85e28a852e16a552aa34d3767d444a583c15f05b942f7c6a8d09d8d5107cca5ba878d48885f65941c62d009df8095ef6d9d9cf406248a49a058e842334e70c0f2244b9facd41087b3c58dbfd05541fca1308ac69a6406c2a9bf8c0ffeecc1f8d7db001830fe1fb2b941c2b3faf0dd6fd710a507d68011c43d8af551148134cfe402373cc52bd7a7757e0b70afb +Msg = c523fd03e54f1046e7282756f87501c6ed0835a233e6c6af09a8f7f5ec21607b534142529d3918d448e06e2e6356f61c46e7d9f480324be6118a6282da9c287a5152efaa79f8e455129ee7b20cbd9aa7421db8d465f5a9d3365553bef9c132f2261eab1361d39d51ac283ae9dcf115ee49717b49ca7907ffe1d071b232d7a76b +Mac = b1fc08f7a1d0bcaf9cd23024cb0f9ebcb826d9facf84c50d644031ce69d99f5d07eb72e02e25b0a3fd395759552d0dec + +Count = 291 +Klen = 145 +Tlen = 48 +Key = f85000b579f5db06206f5cf43e9f700e352bb6bfd37e7c76de10e903f0e77b45855eb50253251116da893cd03bf582994db987d6ee0b3910974b0252348c42d3324ffcd5d991d0cddc0929c42eabb7fd187020d88959f2f6adb2dd9ec0941f6025ad3ff8b243fe754f778b9abfc7f684bdd7e78d4b71907147cae0af3f07f93286ffe531874384545a5cc9189553267465 +Msg = 40ecdfd2810f09de02dee7a3d82ad794fe124af3f81d818cb78695a2bdd7ba2a81b9c437150bebb60631cb5b84afafdbc2f60e5ca07d56298814e9ab95766595fb1d295ea35a15f415a490af9b31d083a3c3567b66c5b762c796a2c37e251f1575be152f72230f02f7df3f8667d7c4f569222838911a2d9e3eb3c9d4be0c6f12 +Mac = c2fdc5b35ee992e0cb4c761a705d8cdeeca26edc2e392419f81173b478cebfb3bdc8787273639da8882020150ef120a8 + +Count = 292 +Klen = 145 +Tlen = 48 +Key = 59f3efcd2fc8ab28aed9165424c8962fc883b232fa767649cc0019e1c224dd42d682371fbf85306b73dd0b6feb30281a260c289870215226e4ad352430378f6b98806ee23eb7954ca0ec216462c76d2c4e7a328299f4f3f4675798d592ad5990a7d7dd3d32c5a3723ceda25c11f52c0e47b31818fb58205c5ee8881d71ee01590c6dcc59251922864fc7d47e81232f6719 +Msg = cfb0db236306e51c6b540bc1797409ecce36c4fc1e0d2f2793086f1214043e9ec6218d05d3726d276bf92f1e09d2ca18f8ae7e661583b7d0d682342c8b4a682fe45b2182b4cd6718f442a7c00b1911f64de43effc11c16352714f19f392cfcc43247dfc18d7f9c9a0f17bace07b0a42ed5c04ceea94113fd8da6ed92a613c008 +Mac = 761c1b719e554e261f783334770d59879926a641bb5f8db8583b43c52554639d4f00e19e9e08bfef181a406e68a23a2f + +Count = 293 +Klen = 145 +Tlen = 48 +Key = e6fae88e7e75e970646091815949c55f9554a5f85d82c1efd83389411fea06289351c83f737d20e7ae728feaf5ea7d5f15522ece8416f394391e9d88c19937de90f9f54c953e676c1178f262a88781beb92678a4eb28ea2a08000b010f87e85884fa55fd0b4227c53579a42f9aa9384428d76ac1ba400d78ece2bbf42e3e7f5c185dd299fe11c9bbc37d8c99f2d70ab80a +Msg = d3d906f23fd6893e241066457047acf137d3a374b396f8db89301be64d71e61749147f097aaa7f03dcd454cde8b5e4c25aa77227372dc6bb0f2a888f7f50ee18fbda9783ca7eb648529d720296be8d7efd3a44125538773017dc0a3aedbc8b9871941509383a74360fd4898d8448f04ca9f4e1dc14a054612ab0698f9e9e06bf +Mac = 002b1474834e0bd0ef8baaf4b38ee412ab1da2cad89a54ecba9cc8e5a74b44a9f663e23f6dbf419e1009766c3d7275cc + +Count = 294 +Klen = 145 +Tlen = 48 +Key = 321206ddf2d6f0c29b10e34444cad455a4324738824066446c9950e5acb4b3e3783b9de769b48f3b2f60d4d1826310875b261ca965fa11b7aefea369a342b1f13b2c1980721bd10bf94b344f2cf9991344c72aadce61f4c75c613a637a700f1de3ae24b0f555debc6399abc72ad29781c6dc1a4ca5be34fbdc8bbcda1986f6efd8896380daa8ddd6d311e3406436315a48 +Msg = 19583b5e7cc08b189ac798ca2f45a83c345d23c0070de066c603a26efbb2e3037fa6d026981494e865b6d9dc7cd58cccd1a8e1abdadc98cbf0747e50f9d336e5441739adb4a91c7c21121248fb11b1da30eaf9c9500092a9f0a655804c330e79305480dd18a7aa3e968549f6f41f9ed01acc7104b3a156698c432fe63cf9f229 +Mac = 88aa8e3dd920ad7684acc468021c4a9fd782766c6d80c339e81efba5121b22c80f872895a544c42a849b9c9c2838344c + +Count = 295 +Klen = 145 +Tlen = 48 +Key = ec96c4a5f1b32b78a8439ef6e98dd93b712aa051360bad51f8beeecb19eced68ae2790ced6e202c44bc1f1973614fabc489e61b6069a063b640094929604fc3f23df22e23bd3d55d4a690535cdfe303b657d1e6b296ece144130b039b18215377249e3a9c78d8d89cec44298555365fff0523e36488fef25b6d6a98911701f9ac4ea3beb23181091ff581187771b805112 +Msg = 6b1bb1f05d08e59fae3d06392a2d4d61f63432016a20dfeb1ef0e4bc48dc2c06459530ae75cd6a924cfa0d6fa657f3035b2cd76e1450c4de5deccd6bfb81ff407f2d94fc1b2a6958b597b3093a7bede835071550a01b17c7f90c8ae199a59a62426b45a3f725cb37109c5fcd8da02358ab4b536eb58ac0ee1dd881e6cb4de5b4 +Mac = bd4cb2284374d21c465ff20ebb88616abcae7c8a1cbd0ad966352c7a47e1f153c7e0eb62be767aa56fc5bc78ee5867e0 + +Count = 296 +Klen = 145 +Tlen = 48 +Key = 0b0d5aa89010d5ebe8e2144e9a7a82a5fa6eab54a967e8655fd33fd7e8d985386d92c576f576e6f22b1487d662072ea9d625a22035f995375e74868168dfe6bce6147aa969ee001b47fe154d9b7f56788d8cc6a5d49170c079004defdd456722fdfb3feaf5606c8ec306865c4ecc423da70dde8c8e17c02838df5ac84ff3508f3bafdde1a0b473742796a1aa82d53a1eaa +Msg = e68bd3073773cb4d15fef2bb61a0be80d5356a7a2f953f6092691141293d0c2d0dd6b13269c51b8adc3c87121e2113fee761c6cb0c87d176eb8d14ec0af1e4c1fb0c0c2483a01113fbb0bbcbf594d083234c23597515cd8d823abbed292d699078d6ecc7cc2b36513a0196ce2e217e76529f890bb267bc0c1d190d2cce172103 +Mac = 8cf8f7217e2e9c3dcd14322e19eabcac17de11128f944441385ed984f07df8f446577c789f8d301f37c62af374a05602 + +Count = 297 +Klen = 145 +Tlen = 48 +Key = a0f93cfbd5f5ba6b0dfaed5310fa07eebfaa031f049b36b205a627e59d8ea0270ce1051fed1fe5f0691ecfbcabad67679378b89daf2ccc1667db7a1877a1803ea388d279a5a931546b94fe7c7ff2517fc76946d46ec0971c224470a7806a7e3accb54a0fe6dac51e7923239b7611edc0c14552cc2aa0bf4c9eaaaf999e30c3a2f13215eb96fccad6fd92e622775164b1ea +Msg = 66dd7620746dd224582e8857079059417407f79b06b11a114939d046e4fb1419cb69a327b5ad0b90d19005ffb49a04e4967a0e04bfa9cb343c4bdc61d6566dd445f50eb4a02fbecd18c4498fe657d55a82d2b7f916078b6c329383eac108ff263c4b5ed21d3a14619792fd128410f22a9fd79980f312813f93da6ee88c5af196 +Mac = 6a186858094b8e9ac0f5b519a309fe89ee659b2a919f7f942a83da674e5163c65333e56458aa3bb29a11c62f65ff1c41 + +Count = 298 +Klen = 145 +Tlen = 48 +Key = a1360850ee9e253d9792b8736df334679990370ed58f6257dc0f67fa1e0b6370b9816f42a5d471872e7039a8a8acc9675ef4f320cb272a4e0d3e9250962f596e25104a17f4809f6c33431703b62c49e4eb4038d80e1827e4a087af10157d0e6ccd2bc255456857f58f547d09ff3b5de728bc2dbf062a02217d32e6bf02be2b75991aff86ff55402928eb9144eca0ad77fd +Msg = dbcab7759b3e83d957896333952ca4329671378e7efffa41b6ac3af38f9275b6286564f3910438a4304d25c464361d046919dec07c502e313f0265e45e3c2d6b73448652272a0d559a9f7dcf060a76769fd97d46bd1545bb3c3a2c43234509f3850e2579a5d887525d27753dc1d237efff581e088a77c54677fb97f827d591b6 +Mac = 2789ac4f72d6fd014b1bd5895e4812da977b8c6b3473a18270db1d99ebb9c47392400cf6a3300d88f8774f52b405486b + +Count = 299 +Klen = 145 +Tlen = 48 +Key = 044514e7de18bad8a149fadb8ce93228089129b739a346a8d3d200e12fe596f99eb70055fd832590895e4e20f505db37bad935e8af28038bd9aea162845ccd7d9258a4da1444ced117c3f5afc0397ba29cd36cd531c8b1dbd9de8751d02f30bf8b2de8c04be41b63f37fd5d0160e7a2f5586b7c5e809b8607a689cf63ae726892f40b54dcbea760dc49ad8cb1f0b40a78e +Msg = 3ebada6dcd96f06f3c2eba9a5f174c428b60451afc6a55a474f9fcec258c9476d1ea917530fe083d92e46efbc544a3a439df2e2b6267cbf75e942394d874daa92c03ce2acbfb9ecee2ed6ac43691daa2525b629ee54ec4006615d6d7f95085eb962c1af46836bc097371365b7aa5fb2320fb67d94dc748a7d3a59d1d52c79e26 +Mac = 1da79416a0f61ffdd39cee60fa603e70c08061dbd9c1693683c3f54d6fee4a20006275edf3bae040df289495a89a6b01 + +[L=64] + +Count = 0 +Klen = 100 +Tlen = 32 +Key = 726374c4b8df517510db9159b730f93431e0cd468d4f3821eab0edb93abd0fba46ab4f1ef35d54fec3d85fa89ef72ff3d35f22cf5ab69e205c10afcdf4aaf11338dbb12073474fddb556e60b8ee52f91163ba314303ee0c910e64e87fbf302214edbe3f2 +Msg = ac939659dc5f668c9969c0530422e3417a462c8b665e8db25a883a625f7aa59b89c5ad0ece5712ca17442d1798c6dea25d82c5db260cb59c75ae650be56569c1bd2d612cc57e71315917f116bbfa65a0aeb8af7840ee83d3e7101c52cf652d2773531b7a6bdd690b846a741816c860819270522a5b0cdfa1d736c501c583d916 +Mac = bd3d2df6f9d284b421a43e5f9cb94bc4ff88a88243f1f0133bad0fb1791f6569 + +Count = 1 +Klen = 100 +Tlen = 32 +Key = e245be9a9c8101263830ad3515c1c6cbf285a7e4b362ebc062cb8e7e75ef50ec4f315a9e09d9243d7109962253f26e23f847e1adedf2851405076e26a1f697062f048438f1fc26f80021ffd09068876975e4cda2e78261df82f672a390f534628ba58490 +Msg = 425315dd8eccd17a84c1aa00ff72763f99ddcbc2c381b8b21567b2f8e263d1a210983d88263ae32fa7986ced9f596f4e7b05e5b71dc8de4930737308b9c4fc3defe783194d3c789ae55ba5b3f75665a7c23e11b69ae8bcfb3bf020955dffd705894acfd72a5bf885e7143f9830f1c010178d37066268b890dee7a1e5f69cccc1 +Mac = c5801d80a14391720e77eb7ffb1a0b21a16323641c9a312b05fdc34e90383c85 + +Count = 2 +Klen = 100 +Tlen = 32 +Key = 7eb72f117b397cefcfb4e75ace3b081776e46b13521e93559d453e32ab74ebc0859b9a8dd4d1d39000ebe95f984d80a3f5004dc91a051dfbdfe9194f4f9a483e4e7955577fb0933464c63eaec771044d59abc3029a079519f8460a693b25b4ce207ae9d9 +Msg = 4e6611a6d76395f2b0e23dcafcc672c090e7c00a5fb5e23d351f1f59a9b3da064d06641d2756146a656e9ab14cca90ee72fc52e12d4e10ca4ba9217203b59a6a2c422097ade7faef35e86a7d2c5d3eabe991a2c025a938a8af866bf462ec002155e3ed1d515d6f07881a573683c9a47e5d7057ae2f0d835dcb7ea4e7ad9e31b2 +Mac = 531bb20800ceef736d52d323a01f91fed1b80457947b1f865d1f6b3b1102552f + +Count = 3 +Klen = 100 +Tlen = 32 +Key = 12720cff0ca649ff2e1c9355cba8020fc96dbe05af9fb4bc008d8d8ac8dee0fb741aa674e66def16c9a8d4e52289ad2a283c84165621c9a7bed046d0a05b56d43bd352f3e30d4d4854a501f246440872421f5054b3c0c91240096035597631bd10a2f8c3 +Msg = def8c9acee9d9f191419982551804a9a9411c7d1240b22243dc32fa5fef28b118353dcff4e6e5a5debae8f1dd3ba5a2c92023aa42598c942a642871a2bcdd989eba4526ca2a1308f37222a699c606906f7fcd444ffdb9042a834c71602e7a9be5e11b159b4dd2a98419df16f74197c100b261b197a7b7e0c8cc178014ce90297 +Mac = dc72f7049c66effcb820848059516c44f934ccb2ffca6f9f8f884e0e1c67eece + +Count = 4 +Klen = 100 +Tlen = 32 +Key = 83488a05032905754cc8fc569d37cae05f0c370db6acaafc56ca9a93982a4669ccaba6e3d184a19de4ce800bb643a360c14572aedb22974f0c966b859d91ad5d713b7ad99935794d2222570a3167733a532eda0b0eb17510bcb581e4995440101a00ee2e +Msg = bd1170af91fdb2160db3522e1bc3b1a349d6e50479920ac5d9bedd8a16a787a3cdc2b6d24392f25555cc2f20b2ba9e6b47ddc96cfbd6df669d874ce21a758d3cf4704362ef7786d90ed67b01bd91299950058885accddbcf44e340ed4807864218653ee7ff7215aa1e176157a611f9374b984ad7f53ea70ab81be131062718ba +Mac = 6563097db04630821c814912828410d2cb056219f886786d6bf57a5b5b0083ea + +Count = 5 +Klen = 100 +Tlen = 32 +Key = 9c054e983cf5488714bc48ccbe9a5bc95e34646a84e61d13545a59d6e45a8ceae5e28c58867a99f895c29c9ce74fac8bfbb5d631dae51e1441bac10a02cebdaaa89293005a9e4c850245ba4dae6d0083369d55131f5804a6bfaab7d3a200f6932d3debf6 +Msg = 7da3134a85e28a852e16a552aa34d3767d444a583c15f05b942f7c6a8d09d8d5107cca5ba878d48885f65941c62d009df8095ef6d9d9cf406248a49a058e842334e70c0f2244b9facd41087b3c58dbfd05541fca1308ac69a6406c2a9bf8c0ffeecc1f8d7db001830fe1fb2b941c2b3faf0dd6fd710a507d68011c43d8af5511 +Mac = adaa76f70a17b99fb65cb7625b4e19de5a539a21982fd5b5fce26772a0dbf488 + +Count = 6 +Klen = 100 +Tlen = 32 +Key = 9963406c515852a8892ba6879e1a91d7b4058711f0d0eadee80920db57cae89916e1eee9472f9d56d34e34f218771c56dba279e484eeff4f8a44065e2c37e1ec622f6c3413c7e54b8873fdee21662e7e46b34e49a1b2650b8aa5bcb5c39b366c6695e3d5 +Msg = 274376f90a39f49c0dad642cfa4f810afdae7157050847646d60cc6adcd27f7c6a24dab9049dd7c6111ab37c555ef2dd16aaa34d7e8de5ff41feaaad80a8bb8cec85fd7f2eaef28a8772828ab3a5fc24143a58fc0c15bf27ab1a4de28a8a1584f68f65b151154cd1b6dc5ac0dccba7c73d8816cc7745dbc5f2dd3b73c31f934c +Mac = 0ab30447b762dacaa6d2ca8a79265c80defdcc510cad72636b0f3f97cff05a3d + +Count = 7 +Klen = 100 +Tlen = 32 +Key = 7f87d81389a6062e8ed501ea964c2fe35b2d3de9fd676c04f7da2bb552bdeb7f183d2fa60c67e2379848ee4807530a81f403d3dc02c11fa8ce078ed422c6626a6c05905a6ecb1679364090c9510f06fb3c0e09321b21fe0aad5cb9d980674e35612723b6 +Msg = 381dfe5c3405f0c67216a34475d453af05f8ae8fd47b92d561f119cd1d18d34ecdb152342f8eec0fe0edbc1d7d04ea7608dd2c878e648dc107bf6e927eddca957252be067b624878315b4fca4929e3570124c76dbf2c2c01f4f8c0a047abe7a9f0a848ba61a88c682c0a6233216ac7b8b6748429adfaf8fbf04517dec0a9b3f2 +Mac = 69dfb148b9527e61b3bcc893cf098e21183fb989736591e80074baa270896136 + +Count = 8 +Klen = 100 +Tlen = 32 +Key = 424f288fb5a07524c162c7adead1f4f4e99b87abb79f714fe8f4fb523a2dff786edb58825654970a30b3f7ae322094706652d75db851356d4e8119ab17dc1e95a77f82c64268d8d2367efc726ed14ce14524158598a94cd21f0b7f6cfdb10a8b95428ea4 +Msg = dc54c265659b8b724812ffc57f20ff8f05227ec58b54d7246df56473e4a64c087d149c8dcad69a0457995609df7a8157c0b3828ead7ac734a32659f91e94b43f8cc9d5d902d894132e0634f38d2d39bfdd5e79bfd6ca764415e3ebea59bea519f1bc94d2756922a8b5a4c30cef01cece456b8be16d0e8d5fab7442ccfcedc89f +Mac = 3c571546dcdf6491797129d298b478a3c672a976989bd89d9256fc64b3f715bd + +Count = 9 +Klen = 100 +Tlen = 32 +Key = 340446d9caf0c0f70f7d43325606ce5daeac0f3f5af9794e81c498ba2754a1ad5cc84ed2b3b5e814f612a5a81851354d6bcf98d2136e32d9bb8021dc87e8ce6d497bc2c2f7adbc705d6900770f40f17fa2c6e2611b392ae9a86476db8ec3643363e84db1 +Msg = 7ce5cbe79d08104f03435fa575cb66f1b1fd6090685039d08b89f2bac52e482f493c9037cd1ce695d6d4869f377b7a4cd4ef768facca00e31791d3274b2f86ad25a2698e27f5b040bd6ed36ac40834f64c2303689d7b5e6f7957bdbaa1038e0d9b7f1c94b179b5773d790cae245cdc17a103cec6444c9d9c3a41781bce90a878 +Mac = c039cc8f9026d1c90e766a4bd723a1fc6ed313b99dc42bfd09e6c3f39ccc5c0e + +Count = 10 +Klen = 100 +Tlen = 32 +Key = b636c84eba7188fa32cd65d87b8ba7df3ff77b58314a47e5fdcf3bc17e452949328596bcec64113fc9dbc3246565486b4fa9bd89ba591a69755ac2b11d255946916dd612a602d9051cf53e59d1fdf21b351905e7fe7701f31d957b4ef0a6e76ab937b1d9 +Msg = fa0f033f3293389e5a9312c6046757eee20fda34e4c8b4d8a1ddd2a8f8c0b0bbf7596362fb9edd5c19646d49bd74856191e2c066a19a23d7bc3ca4671d2ae8ae4bdf511d3d823837c2ba77fe20c52bacfbc4b8a479590da8a474294c106addabbd48d4583e66d2981b3f39ce757fd136e85ec8d6b62df8b2212e694018a9171b +Mac = 2e22dd9af3f9135dd49b88b2391dd2924f0b5b1d8154498d15681a329ff02813 + +Count = 11 +Klen = 100 +Tlen = 32 +Key = b80c19c671cd50f1c39dd0e0e89bcb50b41fcbf326fae8ce3dff3edf0cc29e04119f8418c3fe495f6ad69a24337029a0846ea21e8d0be15d20a46236c278f97e02acc32e09925cc1732a52de5de9da37bfbac2b1fd43a7c5b8696826ea16daa43239be50 +Msg = 490aed3e0c539cd2af8cc9052a204338e9150354c537bd0a3473b560bc81d469aec6fb53107897a8db0376cd67abd9cf2373ca5e893eaf1a5135200ee568f67a16b8a4d60df4cb138442082436c111bd936c005bb942ee84a0a4c45094fe4e28e9a991ceea105f9d121228137fa8138ca3c84d503d89a1d087874a2db18905fa +Mac = 62461e063c08dc191e4bd04d5f553dd38d7679af84a1d0b140be7499b34fa43f + +Count = 12 +Klen = 100 +Tlen = 32 +Key = 94753191a7f8b9095102c5a7691e847623c068a735d972cd39a9af4d53d4030f13b9257a9dffeba00770c8b5020b93c6bd5489a706ef962eb36dd09e40664466b9c8f60cda6e236476f5c90515cb6afde1880cc4c382846fc99bf426cb5e93d84e4bac2d +Msg = 0fa4952307a137b5250aeef287dae233b4c8f79ad2b3a09a1a43f8b98ace0f94d9788124b09f4e411776e5642eef82b11ddfba354d5d556cd96a5b063fd871ea5c64667c97260a1b5c2b3feecc6052e1b2b18beab9730291ddffb5af20a0d8767eb06cb122fd134dda722319c9f3f9ca5c8890427fbe5212104a2d3d93f0ea3f +Mac = a08df9f841a2e227c4d9ba9c87e5d14a421d025ff4bf5d533a03ea449cd89ea4 + +Count = 13 +Klen = 100 +Tlen = 32 +Key = 986b190803ae085510e96c2bc65c956b14881040089478a542ef8e28a7378ced5a5ab7f5e8fb34a0c2171c71f1e8d312050995984edc51074f29bb1970079d3bf3006dd9297025dbe62e4f70326e5f0a41e646aaa630445dc370fe068436d05f4da6643b +Msg = de48fc7bda19796ffdf455ce423c79b0f55db17e67ae03fae69b3e7fec03d58a97dfee7a5925b794f1ecf94a9ad0efbd829858807d16cb9ffb4f4be038dc1b48b290d3e1e05bb4bb216e3931f3a0ee6d6511852fcf0d27c9c033086f38d63ead17a3d339d68419eb75c53d0ab4761fc986106111c35bbf811d8e9eb455b8e7c2 +Mac = 376f040e59dfbcd2936028edd6ff6011d2e2c8ddd98acc3e946e1880d103d343 + +Count = 14 +Klen = 100 +Tlen = 32 +Key = c35b2d9d8a383db4b0c6d46a59a6dd8e6843ebfba0627bc809fa79be9645050f04177644056f9f789e4b52c4cec123fa704c6e9662649cf1e751a1b84a40c99dc597b54ca086a0a19ddee8189427c9855bed6b05e85a1f34ba0ae5a0751a337ecc82f19c +Msg = 76e84e9a2f3063d740eca3fb6be583327dc9ceaf2d7ca49f48b0c25c0bb504e4d0922789ee54d4eadaa6da2192a2bc3e3be76bf508ec54935f949d363702ac3ec5aeeaff57b8c6b8807dfcc975691720b70c34f5f26f0ab725a8274604ac7c629b651c643304412b7999905adde09ec1395eb218b3adcdf3e415e7f23a5c7c38 +Mac = 2c4b775af82a21615fe47e4c29322f9b91359337208378b036b77f809ad83d54 + +Count = 15 +Klen = 100 +Tlen = 40 +Key = 6aa11466a2c96e20544c5b34c91f90d17f9799a57c73ca00e21d7736c42d6845382f87b7ada6dcca7f51bbcfc9ac3cd07bbaec75ac02c22831d755786edd4bbb6cc915f82c68da043be3b0ea87411290712d8f9823fabf8524e47b1f29994d182ff826ef +Msg = 2771cdfdd77aabbcc95740bbd94075876ed3024f0b5a9949214d60522818a5d5ed1dceed2efd8ece64135f61e0422c2e19f14d7f4553b9c226ec7730275156aca72fdeee958e86e03d5728486114b1a88cf81d62a31fa320bd162c73349e0abbfdade74634b6fbbcfb2a83ba853f6ebd6ef059424e45bd2b8dd46765798829c8 +Mac = 2476dfac043e55518ddba312e63699b22a587fbdccccf3981207ef5cfc2e27eeb6a4062bda6b19bf + +Count = 16 +Klen = 100 +Tlen = 40 +Key = 3beb75373a0a02107b2748a7b9a3738b1a9d75fab167a6f8473aad9e5b28a4b567537783655d8de5921fab9e729e15ef143af668972901fded24595cdf60ae7e51c0a97cc8498ba529d611cdc40d9ae790918bd7b879f38157026b26808041f0829bd5cb +Msg = 0405555d89a8117794c64285cd30047d642a1d635f6eeb6b33739b5e92ee9c3e859a532dba34118b1fca425fb036e7f88ce646d44fdedfc09cffa341f9896133e0df81b0128af4332f816bfd84a7c7b82496d15b3a9b2c4d9d0188cda59317913e5c45ad3ab1a4b7ec722529f28c8e0652c228c1c9aeb85a5f02b1ca3f14a8a1 +Mac = fa58f0aad7a3116caec2193a3dffb0d1c0b3172c3b59a9a62ebbf31d21c766818f1cefb26052af72 + +Count = 17 +Klen = 100 +Tlen = 40 +Key = 6bdaf94d6a351f76604658c7b9949f9e6d0dbafb8c4a6ce21b15ed011e289793f638e284ed3292d610c52f433d20b6247cfd8e9192debdcad4965cd53a0c4869b43c1b0bc17e5b773d0bf1417abddcbc9316261bfd8417d65fe3aa50a4443db64eed8c2a +Msg = 2bcb4303bc51438dbfa7630511c50d3a13184a25ae77e37a9458c67dc844aa176088f6298a2edf20cd2bd1ca91da1168e2a9a00471136204dbce7f002e450ad1aa48e1eac402d4ec712c0974a0819e3708729152251adddb7d74e6bc28cc17c18f73caef74b768183312d1ac47a2fed20fd9e5b7d2769c2602b4c25abdc11b10 +Mac = edbfe1cb8575c0b6ee7f31f156a6f5fa5d2ec3e433eb5f2a64a0c8e575cad47cd022a11f94ccce1f + +Count = 18 +Klen = 100 +Tlen = 40 +Key = 521f28ee6c3019f21a3cf988fbf10fe739666504c6522963e57c532ded728884497e3e13c4d622e90413b68753e43f37a604dea0d769fd9836bfec394014cc37aed5ad70b2f9f3c57d7cfe29040f0af7040e538943b27d061a88347b3021102e880bbb2f +Msg = c444d8cf048b327b1459096f0a403d5fdb2e8e56713755a0fe9472e78fec859ce4d361997f91bd04fb242d769f88515c33354c9e12ea787f81a959c53f02cf195e958fb050d3d32b450451bcb58e6a8b3874a5589e1d5b613c57b486849bd2abd9934b5ea1d9ddb99b025d8a72dbf1b293f27fcb3c58650ed6a66b73853ef519 +Mac = bcac2df34ef75ed3737537d84c4c02cf2520a7b04dd47b90734a65c2fb4d237d138973feb8c7c1c9 + +Count = 19 +Klen = 100 +Tlen = 40 +Key = 4241ad5de14a2198acb4c357c4ad5759bc09b335a038d9ee367563c78341245991100ce270424ce07b54bbdfdc58788f53a2d11933c564b3adbe8473506edf60d14e5dcf085e4bed3c5eb898a0411f731ddf473952ea6851da238fa3cdcd43ab896269cb +Msg = 20e0b7dba419fe76c427c77bd3e31d1b4f9f99dab8acd638a22024910ad58142e6b5c50dff351cbf0320b90fd696c9ca2a54a62d4f364e924cf913502e4694dca0eceb34bc6e287d21bdffea4646bde10e2f80599cdea88768bc89b992386282770e931783c90af94686ffd4c9fce1a722b9902646aecc5d1feeee95deb3d57b +Mac = 0741bd432e785b3e1e62b2e5064167b84e15415a7b21d168f91b96bf89efb2f0c3e4a12ae089e1ae + +Count = 20 +Klen = 100 +Tlen = 40 +Key = 1b0bb110ef8d7139773117d7308dac5d11ce7c756f071df11ec8ac05d9f35ab4e3cb2789ef4eee873ec5a2620799d7f01b6884dac9580797ffab699bb394e4cb8149a235965ac8fecc41b39b163a81441f55d4a62ec9d2d94d8b7191aa1ff1983dafaa7c +Msg = 10cd0c9fe541169120a005d9486737eb54bc0847134751f0cb432f2021d5063a389cc5001d896b0663f1ca660ae08ab6a6b17237bcdbe34f700ea53a5d7fe7fcc580809aea537b89bb40d367b3e57be9ffcea115df4534b14e6ba4fbe588e99afda0c6d514474f0372b5a9420b1d116ca83b1f47422d4cfcae83b3cb809914fc +Mac = e59e91f69d6cb65db4781a1dff144dbf9dd61c7ac6425d2612d8535d2e404bbda2cabb349d7528ff + +Count = 21 +Klen = 100 +Tlen = 40 +Key = e4b77ba343cde0bf4cd888b0ff6effe0ef5f24c38deb8bb0a9331fef36ee0c134e5ddc897681df72228bd1ae7c94b739618e0abbac7b175ab8dda6d3206ddac9c90f585d2306abfeab64e882b5c58d76683dafb30a8f55327ea01f220a2b2b375eb53844 +Msg = 180bfcbdf15eadf2b90bd239fa475e104924aeaa1a110494d9a03798368da9e2c0fb7861b500f970186462b605a6c64a4240471b162c87905ea75f6bdd35d4f3d4e54652d2d6eb3ccefa7cd1731a2ec5bb1be4bebf7fa3fdce2f4641bc7773e87c52cd58f1e86b9d02558a53edac7ec7dd3bef59be11412550be54e27a5a6e09 +Mac = 9481e91ef436ad8a6975300201997106dc545b261e7183533931d51aa19e1844bdc9ef5e5a860b8f + +Count = 22 +Klen = 100 +Tlen = 40 +Key = 180deff707d32ae0b6c0b58f030a7b8a6a14e9ddd3ed5ebfae19dd724295066b421544b3a290478da8feb55946611cb8a7022cf108fd2394c9ff885dc44f1c5add0b0e50dab56e5c76eee4d6b080a27a69a297ca2e78e5ae53da965e41568a811078b497 +Msg = 09d575baeef7e337621e239c03035890b68a2730e8f61bef1a5948a09c4f2fd198ece25b53f36937b0496393f6a9f025d298cfc0a09cc425e6a93d1b21dc34c2c56c57247fdd670dbd76de1d70f6d41b1083238ce1e3ca8476ee8fbd7343e9e6973b1c3df91ba660918eda60fb52cb1878316bbd3633f4b6d11287ad19ee13e6 +Mac = 0e1328e618ce2d3668a3af236c695409eae4ae963a380ab4ef458b68d0d313a74019c2a79d65bb02 + +Count = 23 +Klen = 100 +Tlen = 40 +Key = b522b2664b0a3669d6ef3796ffa1d5dd0a288c1c6605628b82bb6557e28e548d718b9d3a19c887d191edb1cc76f3bb969e2c43a9a98413f3d806987f23a29751852d1b929ba9b2ed6dc7d8388caab4575dee025db4e951f5a4306e01965d2080991015b5 +Msg = b3db592d3736d262fb074b7391258e13b4f2c7d08a8ce5e82648435f515c884e8adbcc7e4be7fc358e227f5090651992d5b5103c6c728ede74d2476cdf8e5b9476db7e4f1d9c56b759d624180f64a7498fec3e3dd0114cd5fdeae0f831b396e680c3b8c936bea98e630c84f2978a00e0ea7f97fa3fd1e776ca79582bd034ffeb +Mac = a46f4c53e76cf37f354d2101df409db5a1f717c498bde11410187880c6a35249755cdff928c05023 + +Count = 24 +Klen = 100 +Tlen = 40 +Key = 703df657c2480fa26225874f5b7fee03cad062afef274a6f832947b34c55679cf08d9ca907d26d927350ec74f49ae82ff736630caf5c46a467fb54fd17fd5df535ccb4e4cd15e37dd4cc9cf5ba70f3683e90cb78868e8e376fa322472223183fe8022651 +Msg = 32c3d3082cacd50e386a307cad0c89f7ee78fabd8e035bdbb73fc0a0cc1442514d13031efb066c553dccb9d6c364b8c76947cd885efb3ae985e59d9b1b5fbae59b0a7b98de653545879f2dad9eaa5b797b916e2ce60b10557c506a09552beb90e351455f1df1b946dd8c95eb8707fb77ecffe38f6e5c638664292fd1c0a35cbb +Mac = 2c9550074d5acd1dcb9ca0e09ddf9402e09388b7ac96393d4747750b7eeae484bcc0f4aaf6f74142 + +Count = 25 +Klen = 100 +Tlen = 40 +Key = 29fbd8f37c84f5b434abd16b6a36ec2c34f2ab55c94aa0c0e5170c3d6fbaa23f5a698ed5c9c6b6dc76b64074547054b073d4239224ff28365f1cad4d617c92cd99ea4ae7c538263a591ed64620452d23259e2472d4f822955dd27a1b596d357eb0261311 +Msg = 5df0b8cc7a1fd4b92ed482809f6a46e98a7cd81792ef1dafd733553dcbc596d341f979f3c7f613ae3602270e870099b2e83626b80f5453e0cfb2a3ede9da0d4f2446ad00a06bbaac67f6b8144555efb4da791ba3edda65bc03bc92fb30b17b292e60bdbcac84b1f9e8389f5b80712e3886cc1fa2d28a3b8c9cd88a2d4a54c6aa +Mac = 4f689f159b02f42863d455875a4050b15ac7626ffc9128e3dd6208e97a1bbcb1593ea9b6a3dcd4d3 + +Count = 26 +Klen = 100 +Tlen = 40 +Key = eec8c90aa52c43e76ef3caff62a0648de4dda52a32bfda383b4a8781b138141c5ef6c391bbf0e53cbf0e4ef7f57e06f3d1b541e744b0916d8e805ba85405882bf2fa7c1612314c827e202b20329d261cb6e61248aae4c276a2b17d253557ae6151dbdee4 +Msg = bd1df1cca29d293a5ab75588360ae96ee616b0953df3b5ee344264483265ed228aebe9bd454e407623e14a53dc0434dcab9aa62c0dbda247c7b0b0ae261438318a5f2f05268bf516010b7e9e4003b1f7a8b80dae5f4692d8f291dfa99c7d9842c6620acbcaba12c2fc1d3a92eb702668e4592f42b8f54d49bfce3a601d07d4fd +Mac = 00f5519dbec8caf1213ca51f38bfd47291bdddf530cb56f47f0d2331924ed2711aeb94edf603b8f6 + +Count = 27 +Klen = 100 +Tlen = 40 +Key = 9f8586d89146bc0bb7dd1cbc756d4dc1dd0e198d26717ff759c3033d4ed34948d776e2313b2b6605e6fbc3c55ea3d4b179f536c6ce7c5786695fcff7c387f4eef104a88d1bad760b3007deb3d869ec30aa5d1007a0482965c74ee31b3b7043e753f780f5 +Msg = e998038c09f9e420e7d23baebd0aa868ca700dba9af2ef1f890f1f38838f991f0d71acf989255bcab5fb048e76dc3f85d43809ce453f22372e54b354a7be34ce7fa18dfe7f2d7bbaf316366f67445170afcbe18e2a1de1e9477fd50647b9ae214512eec4747b0c98a90b1a7c19aba5d46313dd23d1f5f5ddda77cd76ece7cfbf +Mac = ec3dddb720380ab8300173797377e65136d139dc7c85886bb5dfb407b68decca1880fb7332356dbd + +Count = 28 +Klen = 100 +Tlen = 40 +Key = 39b877b8e82ecbd9740325828faf6721c129046eb0136144a03182b13620e2498145a2bf3b03e6b64b317dd48fcbc018d9e7bc6e37eb938178fe1fd1ebbcd9056a2ef98297f9df3c66d5b2ccdc4147c41676443f8c9985bc9734be2c31e76249fc5bc42a +Msg = 0a331ce20089b29e94b2c5f518c8dbead40417a2a8d50018f32f8512b3263d54edbbf3134ff661ac14353c9628c371958cacaf31fdd02567d0378d9e21a469dd2c6d8c3afb89dd9642eb5887870e559685d20dabd3865ac5c146beee8387a76f91f0f1404d6cadc2e67d21b07dd30f53871d3bf6731f279a8c0421eb20f67f72 +Mac = 97168f5513c2e9bc4bc525ce2703740bce1a06ecfe99a570ac66c83ede9667cc07edf664617ce53c + +Count = 29 +Klen = 100 +Tlen = 40 +Key = 9427feb606205df574911dc02c5d1dcf1798b85d90013cd076cd9e9c80a76c65d1f40264cd5b010b2a85fdec4a2176d7c82c0a42516fe8eeb54988c83dae9a0e40703cb2f1bd6f037beacc8a506e7332bd3245adc3085312227895cbb6c3e0ae0622126a +Msg = 8beb01cc36cb03235d113c97dc3ef8dcedb1ea5f9179b8c43268bb938668002eb6129207c07dfb0f1a540872982ccd818f14e9ef3b6d0b415efcb5802a3d403161fa2187bb1d6ad688c3944b96917bdb554baa7939a2d98c604eb4a0755dde5bd4cb36b3ee52595fef83688b9f160bd0867fb56354c22a8d80873f5b2e71e196 +Mac = a8c6c8f81e845c251428f4a87cabeaf88c9b45c1fd613a072d58864ac7343fa4f401b43ef1892afa + +Count = 30 +Klen = 100 +Tlen = 48 +Key = 79867559c9919f394cde76b31fe22f793b88987001764e111591300f70c31339b1fcb8a3b476fb00663e4c53d8f063c792c130da29c311c114654808bb39ac7ad1fb9e40e4ce3f4d32c8e1f9bfb1bbeba408e03daa4772db1769122cc8a89cf5808b117a +Msg = d1998d3b3ff5bc1c8f724aab792de8a35c60fba4eb41f2342227d60380ef2273709ed6570847c7fbf5303966b630afdb095b02a6a3e2b115243478c44a69241d65e1a5200b2865600c1dd84ea85455ba00b82497cb75d8ff4a15de777ee8577398aa231db1603e52bb8350edb8607f492abf8801cac30efa7c1132a48334637c +Mac = b6b18c4c5364b47fd78c3d321dadf60de187fa68f5d7e55ca7fbf71f42c742411d379c8c55180d3f54cb9747b51aef7f + +Count = 31 +Klen = 100 +Tlen = 48 +Key = e9168c659c63b6f40523c90532bae743f24feb2e94814b6df2554365af73300abc933af5213235b8fa89c96ebfbfd196c95e02211204cdc93d5b86a5d64ac5fada6d0d557ac3abd61ca7e1cfa302448ef0be6376a87ea955388c85f11712c7e44b8e4eaa +Msg = 42657c6316fbc1bcd69a87c7df3ab06dcc1e471e9764c10a00db83943314a503a5bcf67b3f28402dbe32cdca5a44293da5b22a99b74d2e508835a4a79deece66e7b6c4d4e816bde217b88aa78678630cc2bde6c9fa0a5d9064d04087dd87fbfcd0fcf05558edc045a9d3c646acffe543e9e88494aac4d6305d555f1e3b06b42d +Mac = 0e9b3afab50782f1751c80b46ced531c07c9ae4af50c77a058a2db31dabb013b719c4c22f5e5adeafab72154cf1fbd21 + +Count = 32 +Klen = 100 +Tlen = 48 +Key = 18e18c27755ab04f7d00c63788da883fc36f314ad6dc3c72c3256efa11c916832b99948303c918f4fa48ac49044d75a607333550858615637b5ea2c389eb15545252d76e26b7448bdf9bb0430869a77b454b79d9ee42f67bfe7677e82ccb1e4657b45ece +Msg = 3b0b520933f465a422231fe07270cb6c5f31317da0525f7c49a8a9fbf082efee0e811e18a9aaf9c330ba1ab4a7b9335e03d29a56d8620507314f92a7bf9b0a6a373966f5f51f9215e59c72b1a3ec23fde10a83f10ac5f3fa24165beffbb16f467cda31885f7ab70209722fbeb02f20b1c07ef3367da2b1bbeaa50ebaeaeba7ec +Mac = 6e29ba429cf494661280e7a8702913bfd0054cd83c613bd6e837f1230e65cedd2498f639966383c87312c1f30bfc3245 + +Count = 33 +Klen = 100 +Tlen = 48 +Key = 9ac2e1ad014d3fd6fc343ffb64bf964ab83fe435b44fe7d4255aee84fb5e91d5a0efa0a3887e59820adbde606ef9e66547f2b21e034a43dbc078ca5561a26094e1a9f710e86590179c32af6ebaab0c3be5b58c223ec06faf3449cbf49ea3397307f8ce3e +Msg = e2b3d90746200181461d55df5b894b91cde375afdeae5682441a7446dde0ae2e9f6ed0a9ce4465e4719ecd9006538fe575fdf0e7435ac4e808f2844e23faa196ac791899aaa9470e86a0fe51c02fda63e10bce31b12a0319a970e2aaab8b6fabf11cd85f44174d086e6c13aaf1e7d411f9543a1590e8bc1d11dcb7e2df5bc076 +Mac = a7d14d03b1e40581db5ba0f54612809c3f03cee5c722f36d3d03608e2804b4f41fc5eb51e1406e1cc8dc046d29c92a64 + +Count = 34 +Klen = 100 +Tlen = 48 +Key = 92f2061c17e008f62cf70480508a914cd964db1f8c0de0516b49e077cee20e40b5a78c9d5db5962511f5feb743e6d861db9d7680cf0a9729f47cdbc814677a07406636f2677c8e58289f3574e577c2cc1963a95aebbd6aea035f08c39c65bd89da35ec62 +Msg = a01d062181b8bab5f1209dfd836afc630bee6688af02612e41095b54ccade3a26c681908634963a36af562e045ec25e39a0d9c2a035d4f6d62044fc975986d1eaa9eabb6344ef0275e97007a1f63aa8cef1c44b5da6f54a8d350909a4a3e09a701c8a3711b50c80a760f5d143a59f526b22245725bc2d9a53bf5050f74261d04 +Mac = 27bf46dd28ca5eaabb2fc9824095e7fdb8efefb167409b7f7f785897a05a3a8997ffadfcd5c6ed47ce218e72304bb79c + +Count = 35 +Klen = 100 +Tlen = 48 +Key = 6d81ede1cd618f73f0acd379a0956bf4ac3e471e31e3fe4618566fdae0aba8c69d3407fc41b09e541bbfdc979d996ad662005401707369b5baa5e454e92d4c5b5b7f98f06c1b97bbf5048ff7137425c92ace7cd029d4a1fd0f1a27a5aeba0ed4ae4aeae5 +Msg = d07e91f235ac32cda78a381adec42f86e8fdbe6cc114d93e23a637269fd407eded46df1b816ff5605e1391322f07c2b8943951e7baf0f3eb2e54c2c8f330ee41d2f7b0f9f10580d8a72888b08f5f5820dbe1dbb9eb618a601f91dff3e9e50d302699eed2aef53dfc29d005db2553598866ff462b7df106669d6576f1a97acb81 +Mac = 246f366361163cae164ba273d2b52844511462eb094d77bc3b7684b7995a6ae015d722eea129d7918c53acbbb5908acf + +Count = 36 +Klen = 100 +Tlen = 48 +Key = c10a45807b39df778490c743d9a77b7496bd9651b964ac28297b76e2f75d2fdae3583df0226114d95e0558b9ffa341f3a9d9443f053cf0fec54c16cbe2a72c53287cf366f543584e3eab985fd2d4a8cfe3bfd4c8c203a6bceac109f940d9ae7d995eaf0b +Msg = 899c13c9c430c4ad724f268c0d1f16da00ec0168ae1c02f0b5654aef743dc5b2cb92fbb421bc3427acb0dfd1ec76341979dd1962ff6d4297879d9d07f846ed74dd58b46668cc57c5b7d97da7576bb86707d167f7beb5db77ef52b8060be19ed848540988a14776b01d34c8b855e6e9eb3030b4d0f2de13b775ec6492b5f62206 +Mac = 0595246c12a0ceb9b18ed49d2edd2251782d7e3fe0afbd163834b25a31654a25409976513e12c800f5a4a2e05df1ae0b + +Count = 37 +Klen = 100 +Tlen = 48 +Key = ae9644bbc297c7dba36f11ce9f447a157bd3a06c5dbf68b4ea283f31ab80a6f5b59aed9c89043e3a3997de92cc4cb089e452fbda9e5d6c0aba405f9ffcbe5a8dd19ddaf136fd5301d6e87243722aa5fe8663ddef2a5a933c369409aea926d21a4cc79420 +Msg = 74e8994d0bade0f0fd90547cdca2512e0a8e63b38a21b6d5100ace5a5ade7829c35f01af16fda581a09d4a43899a6fc864095f7a0442aafd919cd50fdc7751b3f080aa8eea3001910a96bcd809577cd2adf34fa39c4928c66e5e8cf7055a8d5021d3fcb22f4edb666203110405e1619410d29df4f940177accd859d97e8e1649 +Mac = f1c7440f008ed213f33f246469a3618a49120e841a211378ea297c7540c2f2365531e2b1e932e4661f55033310780a71 + +Count = 38 +Klen = 100 +Tlen = 48 +Key = 222037722ce86b719e85f8db721b4507eee37328ccc69b80972b56d1580d83157250446ecb554a602ccc533eebc9f0e2c71a8ca113d9aa7f173d6e9eb3b55ffd45386b5fcdd62c884f9469af7976e03186dd42836213806a0f25456e47f1c38c637fb32b +Msg = 785ff8f78955df2592bd56e810355bd98054f275c482b586c90d8bdf6779b84c881716c98dd9a1f2ed6439bb1f67a461bb2bd3a1dc6c6627c8687249d33581f58057dae8ea92032162fd85965a58ef25829f1dcd30dfba1e054904eece85cf4ea849cdbd68290c9b39b1c0e087b1430d1cd85a638984ba53c8d9cb371f11ab3f +Mac = c56c263ef9c7054fe982d4ae76ac38c6accd30dc29a19ccb52a212d77496d9e1648da47c260b2427d81f0b65f17e096f + +Count = 39 +Klen = 100 +Tlen = 48 +Key = 3d017f59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729e205e7d5faab673c57258865705aa71099a2caf7322b79551e9acfa577f5d0ac7fc0fdb9da66262cfbdb8035dd80f7def347c54c611744416c7200e62f5511c8905fa8207336e7572e +Msg = 93fb9be674a8e2643bd12f68b02d2b8470f4ffca93f11a838bd92e244fdb7c7dba7852342d95d2727ccef4dc080ecfc5285c14a1cef8dbbd67a7a22e024b9208b5b605d03cc04633e49797f7a857793399db27bb83d264dfcd157655a13873734d5ebba1e952c60f3ad420a3d731b1368a1742fff9a63d4f86cab47f73c9a527 +Mac = 2482e9bc78cd1e5ae912489ae9b51f1f21721c5856187da29a41a7d10c5dc1c34f8d47b2994aefae3cd5dcc7c8764f64 + +Count = 40 +Klen = 100 +Tlen = 48 +Key = e1d89c4790461f936cb9fca580dac01efde745cb8db798c9e5f83bed99bc8d623534869489baa74d4415311ec5f996012dce2d3cb9b229894fc1cc735694d803cb07479c91403b2409ed3864e3cc91b2347120cdc8443a08b9c9e2ab40243d96ccdc4727 +Msg = 6ff1b7b637e6317d8269c1be2781a4d7de97ed99022b6e9e96c6dbdc87302d7b30e245e423bed21b27fe744e7d6b22ae68cfc97decac3568d52e3518fb5ffa04c59ac189ec42b23c81b3077f32797052c9c1b66cf50c9f8b4d2b130892677cae340073cc18d998899971c178cd15586c0954fe8ea7b474ac06a3bcd4d3b07b22 +Mac = 7c7c7245d6916052fded129f08de09671350d26fe704461e446816ca790d53e1d9eda76e8e71f3018f442f86f3cee737 + +Count = 41 +Klen = 100 +Tlen = 48 +Key = 6af240550657a89df868051711bd5c481b1152d37451ec35fcf39ab23189748f9996c38261a0c3674386a734ad14de2f1fd5955fd4287d40a696cebb2c638c54256309a6190fab0c3dd8efa298bcae6c64169fd4b7ba1e5a62412b8719a2b622d5031aa7 +Msg = 381d043cbcf4919fb7d6b70a1df2b74dc9c9df0e1f405076f0f3052a9dcd117d80d628e4874b61aa22f43ae460b2dda85558a27abebbd407e80db816cd66cbbb80a44ccdcc75fa9b18b21fdb8eefcde37d50681cfb9e64b3ce9950918d90148e023077e1d39ae4db61b86dd6f1d010680a5939dc1d0e89e26c42d6852473735e +Mac = f3119898e26deb4a0f1177de7d8914ba33713d9226ff2d3de986798a6a7584b04cd3c7889a3d9e3803ab73363340362f + +Count = 42 +Klen = 100 +Tlen = 48 +Key = fbdbc0f366d4678654544804b8d6fd6f171668f2832e4623cdff0785f7d2de51e83f1476634fa1de3addfdf3bf4234627c31391e24df7ca9c967be8f4e6e243320028bcd21c81cb4e55720d921df1594600e01a4f83406713da53793f45faa980becce02 +Msg = 660ad30aa44a6b7dd2636dca34a1cca5006c1ce10862542a98aad2f6a2849fb91824f5589ac0fee151e8df791b16f596e8865e6e6447bcafd6933570475cbf67e8279a5dae1d1de03f5fb638119b2d9cd0dd28a501a7f402e643826ea158b0df9bbcca00278951e26373fbee5f58fa1f8219816e29a9858d9063c1d7f6a1fc88 +Mac = e6c788b11374ca821dfaa8a26d64364694e7be419104dd83368dfee6b0af84b66d85fabe37909f4706df9776a289c81a + +Count = 43 +Klen = 100 +Tlen = 48 +Key = 6656198bb79bea7cf7df472111bc7a70b076c2763f23ed9c140f292ae85e18098bf322cdd5910ff3e040d56674f3ae48c3676ef0574e142f48ad9fd8b283237f66ab1b80e00301447ace1cbfdf579a3dc1d8de5fcf991b60e15c229d76f978556146acad +Msg = c3593383ecd41eec6f51dd4ea8c65d7683827f499cc163fca57ee68709886956ced8d542c022dbc1ccaa8159aa59da5bbf1014cd413cb9a89cab2e44149e8010ac1f5f8647946b5e0e95af0211fb6b433139174a3df0a4d15bbd0593aa56ee0025d5dc36cb53552dfdb9713127d39996a2a68fa7d904aedfab5d745c11d83d90 +Mac = 20cc7dc22b3ea35062dee1ed9d271600b3b19e8b15c15de5e4c3ac9d9725f620664eb8b239b3a6a167c24bbadc4c4595 + +Count = 44 +Klen = 100 +Tlen = 48 +Key = da71f6b6ff3b2e902ac99a4946e8233a0dfaf7e7cea374476ec5475faeafd516ab91da44ab334f0c16e7926cc3bdc11275f56671a6ba5a15830de33337ff20856c23a7540f436cd75452e5bbfba26b03d157e412791c9f066c147f483f135c61250fa610 +Msg = 14c7da8a6ce161b9d8f26f09b72b82d58763264757ba0b1e7f7c5aaf8e48492a8471ee1f42a450413ecbc4697b3277deb9e847d3e969d731e379e2975b53cf9f11038664491183417b5f28db4b545861bb3a4112a0e5790053964d14a81f565324474d5f6a6f1f41f77644650fdb4de6f721bd0d65781a143599442f5df205cd +Mac = 959fafc3f154f612a76938386ded563fc09cf76c5952f76988b927415ec31fdd32ebc009dc69734881adc6eea6dd4d75 + +Count = 45 +Klen = 100 +Tlen = 56 +Key = 2ca67ae3ea3c84a2544ca8794457340e1e424a8ab3aae292657712798bb48eb4179e6b8e76fa281db7acee74f086171add5eeebbcb63b51eb4b1ed57ac22d13e7b67241f8c582cb30689ff4f381efd5c3ae09e07d1906e39947b55ca4d4e1cf2a22c2d00 +Msg = 84371c9ff40b745ab5300bc914512c1468f98b339704e204db54dd9ac6c534d88462163f61d9ce058a2ca16718aaf5404a1eb9d912460003d486ef636adeda0e6b1aaa56ad4882e3086fa2055d7e8b48d7836349711d9cc9b934d100d3e7f033c0c69e89e142d71bb661d54aecb734559791532bbc73fd7d12c5491809c9be72 +Mac = eaa9b697c83bc571a029a6df1f440e8c646ac763333d5f7a57a6ffe7cfda7f904750ee4c3ae887e1c29429012d0aa736a8326ba5c974fce2 + +Count = 46 +Klen = 100 +Tlen = 56 +Key = a8cefefa109facc85cd6f65b91b42a988af51fceedfbc5f75d28003bf18cb7b6e5c0287b90117ed996e1a5dd5f4b5d17c8068da1188cda5e357b7980183b414d7ee10522e05320b8a6ad51a698e4ca2795aa831e8791d457967243109c109bb8d9f93ef6 +Msg = 6b8bc0971c1c64e8b8df91397ab8f0a1f2823c004d48a4d8d6b8705fbdd4e8d217eb710b27c8fa56dc2996819a736a323ea3ca7d5c889fb6ca300c8463a0513705c7ef5cdcb50d8ee3091a8fa7a8b4974fb5c8ebd9bdfbb2a6314904391aec453c0880b1c34b6437d566638b29c194772d9e7e724c4e807371a57107c7ab83a2 +Mac = 9cd00b99f73ca0e8cabba5513b575698fcf7a27a396dc33afbab9872589efa826b2cb2eb661ad8c36f7b99d623f440a04f0767c2500b0598 + +Count = 47 +Klen = 100 +Tlen = 56 +Key = 469e10b87afa551fe02ebe13b7d58da068fea2f100d19416e2760004be3221ddbdd3a172fe4faf0746a85256f312fdd63258633c727c8c42199e29a8751e2579f5057c9099a1505aa7703adea040defa7293c2efef4860207e787916109fadc856fc4919 +Msg = 25bf516bdcbe24c2a72dade92fda0ec8cd91781c589b9e1d3b856a5eca23eff4d6d3a0da7e06bf9449fd181372d1eed983b6365d258003b1376742621d07a7a05babe79e62ca283ca9d2b5e40025f7b12261a1d789e52a3f8691807190ccfbb7ddcc8f7f2f124702f133ee2382de0f9ad11b21512ad1fb0e4f8b8e53cb7bd283 +Mac = 6517653cd34e77aa1c7cdfa793198aceb26b7e211eb81d8fde20e89f4fd13f1016de122524968087386e6f6f9ada63cfda9ee3e276d7ab8c + +Count = 48 +Klen = 100 +Tlen = 56 +Key = b37cb20cff52455a433e9e3a22622601ece6392d7a482a535af388582d14a0e44ca94314b2daca6f168d561c57355d521dea620fbebf030d5e5039f25b9adcc6e81065abf7ebf8c85dc1a2873059df0074be5fb5f792097f7aa541c811c666fbcdd99f39 +Msg = 6fd8b486cb00c5f5dcf7a6493df96cd250f51b13dd9f6d74fbc1cf3734d1adade4c9efaae233c43662839e851aaa7e2aa4e8718724e25a882af4f391dac80fb44a2822282b1002f6ac08eff69bb0d2facd9dc249c163cc4f80f3f492c72877e8689c53e8eec0099e802ca2830833f0ab94bb1641fc4b4b31c566da2445186db1 +Mac = 0777df7e26b053d025a49599d9df51dc826221e47879bf916dbe1a6b79342d757de7af26e36706d5d81f9244c2630fa4d71f3a24e03106eb + +Count = 49 +Klen = 100 +Tlen = 56 +Key = b2d6b897153734836e180ec29443f60de8e37b8a8beadb4fceb01922eadc5182f28849ec05a04857c88b2b01130eb56deb6d27acb1d310dd98f367f05df0d7af327a5afefb3b0961bc7133c052dcac6762da675190d147a6f1cd3382c26a69f85af51457 +Msg = 59b911d1a4a61e6bdb3519c5287522924abb87f89699e62e3c0e9249ccfb3853f9d6c39e9ca27c57fc1f765e4c3e295575d75df8169e4aacc954fd5aa93afd7d11cb2f7aa6aaf73197daa0d1232dfef05cff51db2b236d2a951e18983c93b41229ff1e0ec8a7d51e34ce5fc5b52ae88988992d49de1198d126d5acac8fefa439 +Mac = 5fd16e1abcfe6fb1b815f680ae1dd7d6cb833cfda5f75e1ec41e3dfa48aabc198b05b6cd2b8765d628ec91a380cdeac267f5bdf34f5c45d8 + +Count = 50 +Klen = 100 +Tlen = 56 +Key = 10b1163b3d936d7af844fc2dfb1efeb5fb995f5ce579212f6846fe0cb3fd4ffb80052cc15164d5b3f93350c95f4f54f37f5266b0b1c242dc2e887cc9d0a36792191d36ac773e61bec6014bb317c4210db043057c54c76cafc49bc46a85c05bd9e4e17c24 +Msg = e88b8e34e2e4ef0e9d1956ff980154240c4107f51eb5eacb5812f1a05ac9d616cd2eadbb99d9bf8c584c95b80ad753a60ab948384188c25299d32796b4054172df8cda5d413b895d58edcbcda76c555da891a95a08ace8301325e72d6e64848704ef3ba142d2f48a87441fc6d6870352cf1053e2dde8036db05259ebeeae475e +Mac = 0247e758bda41cc1b50221d2f64a689ea8dabf663296ba0a6533f84e464b532f0c2f6d93182c1e6358eaa32816dae8982e366e7572697712 + +Count = 51 +Klen = 100 +Tlen = 56 +Key = c4b4ed564b8d509d63bba83602e8433d9b4cc9d49f24d72e445feae7859a7f976a4e78a68948c262cd5a354e7651bbbd6126b5a08a799a9dcf3ae161f7aa2236f28278d8627129845bcc895367821bc6ce4efaa2143077fec21d049a6af65172e5b7b493 +Msg = 7dffc73782ffdbfe64f56655b6363a567bcf009743187c59978c120297d789cee23110c1b6eb7ee05947dea0b78d2b9f4c5b5892443d937ee17dcb2c1e3d70d792c27a279613ac63aac31ae2150be9c2cc1c56dd95b2f9f96ced4b3f265d67ef545b0d516aa0ecef2110210119d7fb29c3b701607ea0363000829b25f85ff67e +Mac = f201e33cd8221cd4efc0fca3e5af2838f9a2abf0c62a7660782ca0c9750efeebcb3e0a0af9fd51a6f2d7daab503a3d874f4848f85b9f6aa6 + +Count = 52 +Klen = 100 +Tlen = 56 +Key = d0a9fba14f144d37250a3b38021286705373a87f0ae9b92c9d9d93fc51543504b8e765fb78f39a934fd1180954c95dfb8082bc7b6cbd48615c43f3e57d1cf76d6b0275a3f6165ccb26d18d547d3c3dac7b649a596808b1464d968f5a4456a64ff1e473c2 +Msg = 43fa0f5278e7e15159e73a788d92a6339ddf8a65b3df07b6a1ab212f249b21046ab837b0d3746447f5999708e2801732ad83201a2ab4d179f6d0460ab76e0155a57c8ec54aec660185ab1579d5d3983fd421091902a97ed4c4c82edbad5bd508fb2e5ab965b8af271405faf3eff3f2021ba18b8bc225d56e147d21c88cc867c4 +Mac = 1fefe5f8ab295f2249dbd467097d5f4bb19a6e82fae3f94b098c9689276bac58534e8eb0d4b2238d81e079fbd03cdaf08ed35ddc367d4485 + +Count = 53 +Klen = 100 +Tlen = 56 +Key = 6eb9d2ce6f7a80287670c52b360c9509f022cb43f255cbbb5ecf66112c35fe2c72d9ea17e3321b0f968a00da0af7a85a668c276105d03ac7316f2eba2f30fd567d27bb75572c30c97f8cc7283efea726a6d81fe91b824739122be4d717bc8d10150a0c91 +Msg = ed106130abf2a2f6023549fa4a9b96cce9c739ad24b8c33c35915b529d9bb22abb8c39c59e0a918c186b423813bfb1ef28104caf6ee808f090140d8523a8afc43643a1e62a9465b1c41d075480370b922857a422a68f27561758befc208e618285bc025df79a08aa2ed4ff16380d8efc1124a9ce73b607b6efe4d77d3d56afab +Mac = 7e5bb39abc1c723cc0cc7db4c45867d235ee56d19234533838edf1e1e55c7c43211b2d96d5f40bb1c80e0900fedc4d9621106db1ee57eea8 + +Count = 54 +Klen = 100 +Tlen = 56 +Key = b54e1636dd82b1fa0faf26ee7bd2c828b1cc44b0641685d86db0d4d0125a447589074d6ab88fb76a3fa4b9dcb80763a83dfb394a2bfb212526a87f195e059e5710e652744fa6dbbd04190dcb34c1ae578145204ff41e3f28f9948d77abe98dbb52d46c7d +Msg = 93ac6811ae7ec7afd82b7ca0196fe026ba3ab24e9eb40f1ad67e9ede6f3b0ceb8e50b86bc0e7af8c8b3adae1490e7605367dc581c7f903ef3d8e9c607b679cfc149467e8a90baa6d72ec91561a093b99d0a56b3a9b7c806ded04a7fb7cf34fe64d01dd5011efa199b5c809c83567152cb1390b43c2446cda0e6826761ae50bf3 +Mac = 4ed9c419ce128ca28427622a62b8887028142c334bf9ad64e1a2a1e63b99814bb9e7894d92e5e6db5baa8750d7016178435e27f7e3b84f6c + +Count = 55 +Klen = 100 +Tlen = 56 +Key = 30608b4bf71a69c879e650729b646c9603f0be05cf816b1786d15af04ebffd0260f16fd3babdc001134a8d8314f2d331c5eb048746275ba6bf786d9b99f802e4efa822303f57736766c6c2eacb09df1cda30ae21b4277be624db8e61d69eff1ac3cdccea +Msg = 363b32accfa593e454cc3ec83b9d775a0dd027b017ca2ff863c1fcb9e6215b5cfb2e8fea10eba2179f3bf88061472a31be1f116a87a420a3e7a5f7cd974836db52ac8f8189cc203b57a7ff92b79e169bf51d31c0627d55c24c2954ff2d009ef123fb5af8a010b55963567a86a769e4a09a10b03a101d7560799538d710113ba7 +Mac = 359bd1e49bc1c69e3662ef329b245f659142f3ed348cc552c01bc10ec72497893574156cab5af2f4d216cb4409e62e03bb53deb53a4f22d7 + +Count = 56 +Klen = 100 +Tlen = 56 +Key = 22943268c52744116c87652ed6476a919a73c03fbbd0a6d17c66991a753c100ae7636ad24d35254933df508f4b1d43f0be458d0bc0872e3367730715bdbb8e9b143bc61199366f872ce379766f28bfa61da5f24e9ef4d37ed82fa6ba47b3e3e750242e6c +Msg = 2d912035dca0d990741fc9ba4dd33040cd5cbc6639bafecaca0f1f4504a6cf1243357f32975fd00ed17d4b5fde9e524b54cc56d04b924b666ebb59e0525bd59406146fbbeb92ad1bc55898e313bfb5d69c3b36ab4be172b43c2693bf17ea8e3a9db5599a804058fd7837180d933d3f28cd31c3bfe0af5bfc5dda33a8fc59e44b +Mac = b226c29ce8b20348c898769e3f370bc89d9f1a00156f114e40cddca52dcec7f1275591c02d9b3e1a49bc6bb056f950a71d4c0f344ccf44b7 + +Count = 57 +Klen = 100 +Tlen = 56 +Key = de48fc7bda19796ffdf455ce423c79b0f55db17e67ae03fae69b3e7fec03d58a97dfee7a5925b794f1ecf94a9ad0efbd829858807d16cb9ffb4f4be038dc1b48b290d3e1e05bb4bb216e3931f3a0ee6d6511852fcf0d27c9c033086f38d63ead17a3d339 +Msg = 77914129b7af927556872a8eabe5343f668cf904217b0b6f386fc3cadba9eefe61f1c4b4dfdb1ab9fa49d8a7f931acc21fa1002037002a0d7096e3ad6b4ffbe393bb4b72ad5aea62af17a4a6d612a7fbf3a28013069b46f30dcc159a1eccbee3b4f7bdac47b36c381ff876d2690f8db38b996026b5d4c7eab81a41d81caaa1c5 +Mac = 4c24ebefc034892b90e86904bf4670e94710595fd6368f643b5e011b7de022fdaf112a21c9fa382822c9195b1fef7e2788d77de0fe00d073 + +Count = 58 +Klen = 100 +Tlen = 56 +Key = 7cd4636116d91f0db16a82de94032cc37ebce435956d2f789f15211e747d74ceb318d743b52e8897bf3925c27c90c05eaa4231ad1345b0dcbfd0a3896805b4842ed327d28c1b6af88b11ee7635e636914da42e553d59bddb50779dc8217b6b1654cdfa17 +Msg = 8b6b7edfdfaa53e67816ad445bb053303680030744e46f3e7127859abf55f3a3e84eeb56451a231aee7c21f523cab500eafbc718fa0252d7d85bb1c240e31ac4c6ec68dcbd911d125847a7af0fb5e2ad44c6df6d27fce4a8d707b3a8ca960fb86e6d7dd910b748b6fe9ec7dae81ae2218c06d36c93792a99b55314b32416dc65 +Mac = 7d5fd0ed7cc5102436c6cf22dc172ed00372b111a25731a7290bae7b87806f4ecaf213726f28cd6cee2c143abf89aea94cb44e77946a6f5b + +Count = 59 +Klen = 100 +Tlen = 56 +Key = 782bba866ad86d885874acccc5c049b122be4fe4fe13dade77b02caef4b1fef91685143feb50145f658d985e0bf88264efab9007e08730cce0d595ebd92d0a538b9786eec9f18126e59107a8692b0b6807f4fde5d3079faeb008142508083983c1a9391c +Msg = 7dd26a4d522342a5e9c081e18925c6f2ef6adb5141674240481b1052d94fff2d9476be8fd2d88b8fd8ef042651113aedfb500828a09fa3044836711dad371f43ef91ee7e89244d4f8427ad39eac791807e11e431aa129062b93d4cbb460db536f4eba1226051b06e543024243e8ff234e0751873480a32e303f948358e18eb8c +Mac = e23703c386fd6f868ac392c75620d5bf3d0e3fa247c84564859367de317deaeb796177446c32b23072ee27939da4ce89a7da3a51baa6cede + +Count = 60 +Klen = 100 +Tlen = 64 +Key = 57c2eb677b5093b9e829ea4babb50bde55d0ad59fec34a618973802b2ad9b78e26b2045dda784df3ff90ae0f2cc51ce39cf54867320ac6f3ba2c6f0d72360480c96614ae66581f266c35fb79fd28774afd113fa5187eff9206d7cbe90dd8bf67c844e202 +Msg = 2423dff48b312be864cb3490641f793d2b9fb68a7763b8e298c86f42245e4540eb01ae4d2d4500370b1886f23ca2cf9701704cad5bd21ba87b811daf7a854ea24a56565ced425b35e40e1acbebe03603e35dcf4a100e57218408a1d8dbcc3b99296cfea931efe3ebd8f719a6d9a15487b9ad67eafedf15559ca42445b0f9b42e +Mac = 33c511e9bc2307c62758df61125a980ee64cefebd90931cb91c13742d4714c06de4003faf3c41c06aefc638ad47b21906e6b104816b72de6269e045a1f4429d4 + +Count = 61 +Klen = 100 +Tlen = 64 +Key = 7c98912c74421362e112a2f98fed9babe0057fc778b4453239aaf5ac724b725553539770a5bc8666b8e13d0e9ce36b2b934c8137c7f20b5f391f41cefaeed92e9df8206cec3049bcda0c05deb9e6549fada19aa2618ff560f892ce6e4782aeff41cf53a9 +Msg = 74e8936d83bf3f16b8d03fb73384ed8f46bd32343f5df8358107e2fdda293afa103a2bffbd4030e75d96cc7ca6ec7c97188fea88d4eb63b7b14e8b8c8dee4f8de12e1cc6981d4e6e223fecc7c491924632c7aef45fd8ef1494bcfb06c074616b0f4cce8abd5d83f32d550661357b18e5bcede841882c869251db9a331ac456dd +Mac = 4cc28818486bb9b1b52e333dde71f73acc227488453fd907c6b51d349d67af1df29a9f225532ce04f50395fed565e98d78978626df93462d3f012f7373347298 + +Count = 62 +Klen = 100 +Tlen = 64 +Key = 662ca8f53b97edd9bbd43b1f9e4ea49f2ac14417faee257aff93608bc49a85abf6913def235a2e76c2241ffa749a5da489595d25c6a8a2026563e12f5e3964e0e518ac9c34e45a938a6f503174a613f34b08737afe5d6fde11a45344e64d23b33ca83c23 +Msg = 0c057a2b56cb7e651c6339e4c91a1a72d51af2a646de9dfd77e9e42c18b8a2b576f526b9fcedd90dfa442090a6e784bb614311793bb5fb39b8418842d586294746f1ea3c02320d6801ecf2ba44b13b60172d2d9693a158bc66947aacd7c5a14a0463905d6e80649db8c4770cac5e858a7f400da4568cfaae08498311265b50e5 +Mac = c0d6e13c5746369d49bef107cfc9a465627691320b8203233359e6a49659025ac96a6db6c4d460224f6aa1cb7a6b8df311e066f6109bd466cd9aee3058dbc5f0 + +Count = 63 +Klen = 100 +Tlen = 64 +Key = 0cc5bca2025bd6030fe0818e0a61ecc730b2e5526da942c0d7897fa97bc1a8fb5dd77991ba9fc50890b014ce6118907b334f2265db6ad86e7b918a214ab3bdfe9378c711017834ca19aa6908081f87779ff0921c9c75d32e2bb77a28ac28881cb792ec4a +Msg = c532714f570982993d4b22c7d07a1e79ff5a75c94eee75dc1fa222b630cad753664b30f3c99826b5cfe17c67dd875b9d0bd2390028e6ffe9fef36a2fd6adb13d3ffc69670cf4a67e9c0764a15e7925579315dbdb561f07b7da892394f4693e51d9abe65228034a1b2b26a01d5a3ac5cf208b2301e27fd86e3ecc159090e8c3b8 +Mac = c34bf0931b2dd2e41956dc86996e1427379d0c89739b1c33fa3be5b0770673a20c5335c6d22c766826009938fe1f4d478b882b59a3b19fdf25bf18f043fbb3f7 + +Count = 64 +Klen = 100 +Tlen = 64 +Key = 7d407fda74d3a127b2ed14c727d0e81a04f6789d20eeef629b670abdc18b1f41318e5eea3e86579c957dbccc20c4687d2b8ba16fc6af9a936ad33cc1dfb226ad5cb3f318f1bfbb43224fdca9d5c9faed6e0c44123849f9ea07162bd11bbdc49b48dac6ca +Msg = eabd8db90e6d67a41f096e4369f77cd6ba23da4fcfa459120d9c9ef9725fbe9bcad80bce26292d6a8a927450e6946cab4756b2764f47073fe305a32a237ecb389f55a6c9c7874d60a44e21a7c64561b37ecdfc884db0a3e09b052328ac54f2ccd1fa07b4dbceef0fd5041e4ff3528374c5525f8eb028567d9f64c7fcf62a59de +Mac = 771bf59b658cb17576761d078cf6b1474db746a2201d30ddf289fa708366a27d6a53959bb7eb2b963622b326edaae3dce086dc364c93c874e50089b69c5cf52d + +Count = 65 +Klen = 100 +Tlen = 64 +Key = c367aeb5c02b727883ffe2a4ceebf911b01454beb328fb5d57fc7f11bf744576aba421e2a63426ea8109bd28ff21f53cd2bf1a11c6c989623d6ec27cdb0bbf458250857d819ff84408b4f3dce08b98b1587ee59683af8852a0a5f55bda3ab5e132b4010e +Msg = 1a7331c8ff1b748e3cee96952190fdbbe4ee2f79e5753bbb368255ee5b19c05a4ed9f1b2c72ff1e9b9cb0348205087befa501e7793770faf0606e9c901836a9bc8afa00d7db94ee29eb191d5cf3fc3e8da95a0f9f4a2a7964289c3129b512bd890de8700a9205420f28a8965b6c67be28ba7fe278e5fcd16f0f22cf2b2eacbb9 +Mac = 4459066109cb11e6870fa9c6bfd251adfa304c0a2928ca915049704972edc560cc7c0bc38249e9101aae2f7d4da62eaff83fb07134efc277de72b9e4ab360425 + +Count = 66 +Klen = 100 +Tlen = 64 +Key = 52d3e26c59df9bf3f5c01e311fd6611b895dbf6e8e918ff16916fbfaa6981033d7af119e880511d775bac09afa078684ca22ce1ee462a517c3a483d1d5ed68202f512b4e7f130f62420d98a137529d5613139dcf76bf57a81e6e944c5b8048b8c281d982 +Msg = 2485736977ef55a55abeba3b8e857ee2fa5beb144324e46f9e12625be26b25ede28ca30bf92e45d1e6e8d234daf52be5d0383a781d7d25c64802c7901b366065fac08bc574c3718618603d778a7dd044d6c5b59903f0578aec4571334b5dc79b172914df1037438c9830e14cc4a6d3c5b30c44be1e06e28331e44a8b9968c059 +Mac = b1c34ea9d837b4e0b0771792384fb5f5b9bb5af7226d461b5ca81ce8079c6472c5c44624a640f01960c8a94f6aaca5324c0da2cbfdbcb077cbdca7f6c6a38e75 + +Count = 67 +Klen = 100 +Tlen = 64 +Key = ce1e3b693ce203166bf045472fdd1457c8f6591a0ad41912bb30f6e63df8f90f6ca18ed5cac0d07adad407b5c9666f6253553c77e56bda3aff3379b1dd0fc95a5685021d04da287fa5e28d18c11697478ee7c3241052eab684b5c467ffe1aab45370a029 +Msg = e2542c06864dd3a0499493e144a97fe04006b68c83a5dd4ceac3cde238e48895ae17728fdc7bbe84b6022694ea75df7371b8ccc76450f2d112222c504f7d1fa20f5b712d33e436fda234abae9c5e278d4bb14efa9b3a88114c89b28946b813db2caa91a73391245435b38cf8016d3f77f678a6eed06b8852c181c754c49d4a88 +Mac = d5e6ef77772459874a73fc4f7665cd3ade20468bea1ecdac41142ff32350b8cb15828612050046299f08ccc486acef0d0c04e0f8feb29045ef7e3a3db093d512 + +Count = 68 +Klen = 100 +Tlen = 64 +Key = 3699d9cd078a20ec0c96eb01aa60df6cd5dcb554260eea8e2e15b7c00b6943c638611854aaf8d3dd18d020b49a77e67275eabf973557ab74fd2705481c3cb6a9e077a825af7e7e2a53bc822396a9dee40f4b10483bfd9818d06ff32f4deecddcd6e57388 +Msg = 9186eaa3b8e785dd2a747297bdbdd4f5532a47b7008c21686ff7f8d881d464cd383205f6d45dc8203bb267ac9eb12f415a5406be1c9fac73497941909dba08dd12856aac03d83e0d916147404694fe70f8fa929ef0cc2edb4cc07abaa2236405e62820af8e806d0af32a1b3afb8dcaeaf5c4f43dc4392e074075aa3ed93601ab +Mac = d8bf5ff4392938534a7962c64985f163ce7c95e6c05f93cf704106f9bda7c9ae963f5ea87f73626f67ed3146e8611ca62ef2eeb4f9a13847dc6e7ffbe3d851a4 + +Count = 69 +Klen = 100 +Tlen = 64 +Key = b0c0a896096bc42bd0c5ea646779a4f1ce541f9cbc04df29ef20b180c069e10efa50ae68ecb8fb31bdfc473f0034dff988b452037ed6261eb0fac9492ccaca2c0ec349b796f1ad077ef995898a5d106160fc100d9ad81c451a1c46269d5e5d90932163cd +Msg = debcf190ea6ab2358636af5cfe4b3a9bdc1bce160bf350aa3cd3956b897e255158cd3e2e83481ce3b6f778d418764f992d48e4f7fb6d080e6b3799d3f35949c17241a0cc5ba84597166779e6a38ce45681ad944cce7c432baf9cd8caf2b33125f2c12052bbb0b3b76f2cb97be9b4813a9ff1e5fdcd478769d0ab5b36cfb466e3 +Mac = 2180018c7e9c3287c3d2928fdf36dda80be4fa21d3a879c0f617eb0e43c58836b0cd714a8081652f8dca9a01925a4f3ec5dbe07b5160be7b1ac58ea623952293 + +Count = 70 +Klen = 100 +Tlen = 64 +Key = 1ce7e20abbdcd1154d4b536714ff534a01b8e88c78da34d653638c39291fd80ad01f3df02067fa3bfae7907789ad2641c8582b5a45d03dfa24344a676614f5c56ce13b30b6a15608f1e7e18c31033eab7b76351686a9dd9ac2dec0ad9a663a47f61422f3 +Msg = 46ae8403ebb4c8723652b9848fdaaa537a50e3191bd94442f9702bc602db98b5cfdd8f142aaebee7cda8608f6d436156f743c3491a30404605073155722fae3be3aef74d2b9d128331d9b6cdf1fc68aac38ce4f6e072be0322ad49ec0b47b82609888358f86b0d6de94e83e722ed077666910ec9768506a4d7ca3d33d60bfe9e +Mac = d032bfb5a538197385eb70673cf8f93e31fdf9c22c0e90008a454ba4d69bdc2232475a41723c8a5e3b29c6de929a7a1e87b64beecda29683d0d925f00ce23b35 + +Count = 71 +Klen = 100 +Tlen = 64 +Key = d7148e81b94a9a902b5980e751a5a59ef4a2397ad4df251240443e30e598bf7ae445f65227603dfaf4e42cfcc23e0dc94c0f90a0e52dc1b10beb36833e9a8d93134f163e84e7cce08a498a3eeeeb7b215b98d344b970bc70b63093e6a5b355fd8cb9540c +Msg = 251cff72773e93021e816407edbdf5c1b0dd9a0d633f41e7a25e932d61ae3ca5ddc78642d2c62da3eff06fdd8799627a89458ac2b20cab390143dc686c58dde0d1feaa7d2f8a50e8169d005f5c0462b912dc2ba4b6faf232aa8a4094e5f5e625e90993aaf554a5d77bd04016d4c69d8533eca53dd8d0bfda867ae638364dfe7a +Mac = 9f783389d7905291a0446004816233918acfbbc1d4443f4dfdff55f3c151a7a1ad20d0a18d0aafc4bde38e3bbd9c7f672f8b1d14649e8f41c47a0fe1ca051d8e + +Count = 72 +Klen = 100 +Tlen = 64 +Key = c821be1cce09579ea899899d24f8329994c2c839cf0084e27857c688837fb5c4f4f72527eaf7bfcfdda75b37248eb153ba4d31dd418d2fea473643c0c9e1f0ebf591838e349d3ef868f1b67772777a71f8cff5b0654696fe31062ef2628a99095355a0f8 +Msg = 98b0c5e030490c0de1cb08d49ab64560693160acedab1a450ec2ab52eb6459d114344823fa2f94cba48f9d73a3efa22f47b19206139d1eaf6fca13989dc2e72deee1915636fe9e417d4e8263f7842cb9373ddd549f9c39141b319fb40f20b6068d7f4880ccff54f8d5cf5eac80bd0a859f9fe99d79f193fe7abff6ad28c6ede7 +Mac = 8af5f3e56ba1a151975f4fc6a784aa050572f7b163a93f24f016395ab4688f39172bf20f1bc246d73b971d022b3d49d1b31f40b0a121b9c3a66e09096d4815f4 + +Count = 73 +Klen = 100 +Tlen = 64 +Key = 8ad2ff9cc9e5979ab79e2122f2b6c0d75f0f19da6bedb79a9762aeee330a7f6169f93ccc7ef2ed2b55d931a9356b29fdcb2d91f973a23060b3c173f908a655e1e6888125faebbb90b2177cc2ffc8dc825a27b55605f906509317952aaa1ed996086716cf +Msg = 18aa61677eb2e25b7f5738c929c4f4ccb69749a1038b1a6644545722f7cb8a06164badf3915b3f3cfb8d97ac83a677cb27fee45d242a352cb1d96b07ecfcc00b152a8321fa4222c8b25289158eb7aaf74d865dc08f2b6be18d50e5f50601bb027d0d89fba1afb4890d6db60a3141b6db90f75cd22dd6e30f3f8270f52c21a273 +Mac = 3aed2fb463393706efbbb98fd426075af837a8eab622b95da9aeb0393188665336f0d46bd20773fbea36aa289bd702d6ed4d6080449b680c92b0355fcbf13ead + +Count = 74 +Klen = 100 +Tlen = 64 +Key = bceaf34d50c1f202539233630b16dd048ea23f093c9f713b8d3a385b0d5c2bb6a4dd14f91bf59947dcf31c89f931df0570476c33ae7f34cb51897623327062b8a3cd7f0af53b4aae3e0a209e58385dd32d9cc6163265241332c332af4de4b99b4022fa29 +Msg = f3bfa5c1f1055281a35b48f86fa3ae454c03eac56ff064cf268b8da20431219b3e4da9ac55714309f5a6a5241e0060dc817562f12deebfbc6a9fb11de594ddb40e8dd754bf0ce9b41eac1068c4b448101fec09d014b01200e94265246365931e2b2739a276fecbebe51690acaaeaee4aed12e8486e5be5036b1db39fc4c9cb41 +Mac = bb714844b6be93ccec0acb8780996b2a4778c42a8a76a49eff87ced3a258815d76685dce4c8ae37c244229f17e0503de089a043368cd300d13f842f28c111fbb + +Count = 75 +Klen = 125 +Tlen = 32 +Key = fde15ba900e6648c9d8471f00d9b32d71e5383b9370c931c96944565dd9dd6eecd6ec15851d8df23be6cd37b59eba5551afeadbbaf27b364c4f854888283a7f255112157f317b6e69a65412098a126ea11f436e1fd03d3ed702154191ec2aba21e33444dee8931feb8d88587d3a5fdbe8d9de6d228873adf22770dbfba +Msg = cf65959c760826becc0d3c4cf75740d8c8bebb9835b26b210a219773db9b9f363db5d74336ab9566f1498962b60b4d361a833d9f73fb89de8f5c89bba64e50ca8ca183ed2bec6c1a31734a5f064eeb2301c87daedb06a2ec64e9c26d7434a5b125f241a33f12d063f4552648ce6a4226e55723cc551addd1ef90eb912f97c772 +Mac = b1a9135311d32f5bd6b73abf54088b65fc1d23e4bed1d33879a707c5c93e8fba + +Count = 76 +Klen = 125 +Tlen = 32 +Key = 18519ace346e2e9987a25038d7642b7fbebd3a49b904005f7bedfa9c87c2d24ffdefd5e1b4c4a7b88a77355af868ecd6eaa92960cdbef03be9a1e0dcf10a664cd8ec32cee743e7c20d0d17c976966e2a5ef92d7428e4da65aa9b360bcc407029515198dcf472567eb76ddccb78771942c5b530cef1fe28a667e3e5723f +Msg = 7210549b3edd9a0a700b061f65ce10437477d9e5dc95bbc1fa612562c059a6e5622a470152d31e446f08209f7ad43725c98395103fbf47057bf90d99500b6913751bf6737ec2fbb40b6d404f4004200075cae0cc2e853f434dde4e03860a827d14aa08fcaaf058e3ad040d35a0a6f45be0146322912ecc04d8d891a84aa01aac +Mac = 2b2649c399f3716bf33f7937579df12deaa8ed00f656f8240468a3b022d411fb + +Count = 77 +Klen = 125 +Tlen = 32 +Key = 739e4ce0bc133f599fbf7b220a650933ead7c602a6670a9beb9f88f3af3275797031edefbd829278f88f76f25a3b3b85371a787c84e15f54961b9d132c1e82dcb03e62bfba403bd5d612978d87b9b4418c8ae30d619d2ee0097f3dd30b277bbabb2b74f9ba34819ac0b0a89c99c6be8d6e8fce5b4683bf67cc3130db53 +Msg = 8deeaf2e1c03647268168d1276608fb0ef3e5e4088da94c6c108c061d26e0089e2e8d2957b2b27803ba8b9ecccb39f6716e41eeeb2bdc3afa28eae13409631fc756b9a4c2b9c4ca6059415784dc1bb392ef6d8ef230ee8f5afd3a1fb4f1e834ead3faf5a169efc6d2ea348bde2d40cad9f3d334cc1152d1e4f9e3f20e54d1d06 +Mac = 077139064096116bc4f0bca8f2237196d1d9a244e6ead5cd6660c9ad77a28d82 + +Count = 78 +Klen = 125 +Tlen = 32 +Key = a5ae601409a8433b6e34b1f95266be2cf4163382139178d4f98db7b6b8633e4cb478255f61fc31af4ed8f98b63e147a06752c10fc479c9c28fb0a1ffc38fd33dcd60d0374ed3d7401cf418d68a591a79e9a05abe4e19359f96bf0715a86d95e9fa4ea8c65796fb94df6f57014f36fd6082e844b738d7831317a2311fef +Msg = d2c5ea2b497f97d48372243e4c4076503e3383b99d8d56e07f19591e3006d32cd4f5b0d74e5181fb61dfc3ae159664bc5db08354f6017800928814da364429fee1484d3b6e12dc0ebb193cd00ba5652ea9e3a0dacf398e80c5d76dfc4d8f97ca3fe64bbd716bb0f4d947170bf616818e6bf561b3eedca348602fecea3d8f2478 +Mac = 2d16656eceaa47a2cdc4c4100a0c5e343299cdda14be213d1253fe0afa17cbf9 + +Count = 79 +Klen = 125 +Tlen = 32 +Key = a39a510d232f92835616987d7f9a50c8841874c59411511b0c7ccda99c61a8bfa6a3028de61e1edb58f165fb561daefc0150bc21e3fb0891d3aac1501895126ed172a37f948e624b551c83c689cdc5428ca1f8e340fcbc53f8fc8bb8940afae3edaf3bca73a9e739143ffac460d12000ebb32ff3f33cf4c8431932c757 +Msg = 76aa892b7824da3d74dee1c05d0dd6a0be232e0e58e8612e0cccef10fc7ba5e2eeb31c64f152849c42b49fca703b109ebf2fd6a9cac914126d8a138ae2d189812aad1c9aaff0225d2785ab2dbb03c1796981ee36a7adff8c491808cfa4d4a8b2f4418eb7fb243ceaebf90bcf868b709984c17d9c35bbab05671dd6c98aab89db +Mac = 0cf6ccf2f7810a4a020d0ea97e9ee72cd36f41e13a3ee3ca41030ef0f45ba03d + +Count = 80 +Klen = 125 +Tlen = 32 +Key = b65b916e8c8746e59d281f6448f8800b34cc7cf32b1747cd2cb0eec5bbd545ad7c6f21570097c842df5aa67907b942b953f470d26009c74f9c7755599f4792d9bf4d93dddeac803d8798487e3a6093f603abf93151017194068e0c40cb23e33aa67e4dc8cecb561ebe6b6d3988f35d0c6c787fdaa90a2de3937e7942e6 +Msg = 037d44818301e6466ae7a7f0ed1b0ef184cce011a61ffbc0d32482aad8093a8d4f8d344765b8ad34e0c932b660710815e43eca8a915a5496af75e098f5006f9f069c6b7d3bd28a1da304f51648a3aa7fb4a31e06b42c273c5c931a334b88304b31912f498eb746a9bc7e38362f1bbdd7fce225ac98fe3e59e26478a2640a4739 +Mac = a78c0ebf5aae01aa7a33cb0a5ebd33dea4d010ec10b31849bf8478fc33ab5b15 + +Count = 81 +Klen = 125 +Tlen = 32 +Key = 9cb615e2eedd8df96d56803e7fbfaccce3a9e66f45e454090ffedc348306dc2807951ce0bf100178612703da45a16099bc5c121da38fff01385371b92c62c578f91e675075d5fe9ca743e39bda58d85df13cf7e3fa91e88206f8578837d6a5221a58de7d37b4ec2ce7b20aca666c7be029517b087270765321f478e9cd +Msg = e3d0c3abdef069e6e4fa35015797bd8a9d64bc9b75f20b028b12cca04a4fe80ff1bbbd88e9ef1003564d499fec88df4503671188eec5d7d089dd18b812c41db43a3746f77b97fb94ab32e6e3d2c45f26393e286cc3c55bb680fea0598089a3a3e5cbc6c13cf113e00e317493b153267564716b0f9cfb7ffc98fdce4a3ba56424 +Mac = 62cc1fc3b61fef9c4e9089b86229bd43f651d7346baad2fb145cde64f3f56d92 + +Count = 82 +Klen = 125 +Tlen = 32 +Key = 7b4b528be9e0353c0156dc685bf0517ef4cc0ab18cb96a614c4889d6ac26383494a840abc1a8ebef6b90c6e825b4a4aa04e5e6a70342fa23a65222e9de50773d2dc62d110a5e187c87f46f6731efd18a38d28597d00e06b4d61bbf2fb7c6136d8ecda0248ca9c5ca9dab614e484ade05d7bc6fe7b9c395fb24cae810ff +Msg = 97f669cb219bec2d7a57a47979ef5a254d2cbafc26c9a91e3290d948cbbf9a55efb0f305f0b9f1fe6c523f108075f7bd394bb8f94b04f92e06069c83854bc65e2904ef27468335501b57f69208b99d79fb27bc222c4e5c440a2d916d7478518e2d3a85ba8abf612b6eb1f1867881f55f7b08ef002f6f7a66264cdd8d010de0ee +Mac = f8839b532c1ad2f0dd2671dd607253ac20c5bd6a515022451667cc636e20f837 + +Count = 83 +Klen = 125 +Tlen = 32 +Key = 3860b019c43dd5b6028348d2974e828b74e09248b5f21daac948a3bfd4880379514c425ffc768883efc46bb40ba470f49949cf2d31fe771fdbba529d75f5caf955bb8cbd2fff8c9b383149a78b1352c4ccc8095c0c2da755ed6d804007d089d38ad41799247fe9e825f36914e1432fe25585c73f0e29b4324789b41052 +Msg = 76baf79762efacb78442c86c8cf48fb50ba43db7282a52ba94c42e75c070dd8b4d983455c4f41de287ad2f3c07be82ed38a0c1c2422680cf7aa6d0b39059111e09040890f0d83263c997570bc7f9619d3f4e6f8e5b6426bd13ab47b45997872b94469bce50639241344a6760346dd7cb08f670a2dcaeeb8d491dbb0084f3e6bd +Mac = 694c01f7f952a909842fff93a565389aa687f3d91df092ed0eecfcc18f07b88a + +Count = 84 +Klen = 125 +Tlen = 32 +Key = 787ce775ce65a604fb8f55af0e5f1428be380812f6f1fd1391864f2b620d0a4477ec500a9e4afbfc29c384c3ef6024c393c638f109adeae455940e2e96b34aec44327a9cb698522fe786455f79a5a643fadd0e2167c8fd83ee66c48df812a28d67b42dd41c39f3c5bd40622bb516e5d07ce5504b18287e19e46238ef90 +Msg = 2b7a171a33714b709557af416f295d0cce0cf4c56634ead88704246c4c76c4e416be43ac382abf32f44d9632a75c333740d8285ff66d7d5e3b1b48c5eb937e85cae409ae2d561b7df796c196c714bb8e70aa8bacaa7eccf10729c55528193e54303392a979bd065a867c59f439199d1846ca4536e82e7e99d378c3a469cfab5b +Mac = 9387b868d66203470b5762cc10aa92b99168077a17497c0ecd244ec71ce72185 + +Count = 85 +Klen = 125 +Tlen = 32 +Key = 1fc4c858845af638e18bd3952eb74883ba4d216fd5a36317cd25e0da1db20832e043027f8ccefc06dc6abf390eb386394f7010997473f465eac13562f0f3169803dc2f0e9a6cc1d514d44747efeb4d913ad1856f4dd21837b78d3a19785501a571d7778d18fdeead701393483929469563b8a97ac98877971cd018861d +Msg = bc1463e3ccc4efa58f9d3f657e84b3d51357bd6981d43a5da2b602f93120bd14393ff9d7cd2c7ac3fa0fd1f5fa8a31a9aa557dfe3f25a5f934d333cb86ba21572461eeefa15af15e2d69ec2cc3e9e41da46c30fb03a2d195027c0108dd900e3d65c069b3b116fa7f10f3b79141697538e7e5fee93711633cf4f894379d6c2dcf +Mac = 2f77cf7f96eae7ebc838c9431522ebcac360b4406cdb3ef25d9cca93350bb671 + +Count = 86 +Klen = 125 +Tlen = 32 +Key = 5f1149eb978bbb35182ca938e77ad0cf414b00972435c4fe1147459c11f66cc7f65a4761e39baef50ea62602c5240597afacd72055370180e0d5a460249fc4c6deedaae93ac9864499a359e990461218340af710954b4725881b1e13aa349892a130392aa5fd8d49408b0b9351c73f7957cd290dec59e014907f7a5da8 +Msg = 5d9d92c853dbbdd5c20fd8a14bed15a25eb01604460b0d42666322f4c23b15e8c1f0247331a62f098b821a0c781a73e29529544a73888bf0e359f93f708538762c6a81feb0cdccfb5e163821e9bcaec818fec143c6d4d96e2e259187653a5d3f28737010d838ddd0c333fc87a5bc0f7e6f95259846d83fe5cf2db275aa40cc6a +Mac = d4b5684f15c6431b25c4f5a8689147ed904e3b2b5009f080e3bd3069aabade42 + +Count = 87 +Klen = 125 +Tlen = 32 +Key = 84a72b46b31ff2a3bfd295ca63dcce53634794327a2ca7f1931b693d3cbdefa457b8589d12d35dc91a5b2a780cc56c6f2d94ace95a7edbdb42ca2e7cd2fc2c05f1b405b56ed4251936e1098acbac51f7f13117e5abbf80b365599023735d4316ba63d997ad68711b7c2cd90787d8a57319e47e2e5338bd026691393906 +Msg = efd2510e18699c437982d63ecc061b3e9c5c0408f27e6d9531537c083f39dfe3e5e05479795f6fa7ba8198bffb6053c58436c4de356f72056c034b002902e892707113f3ef54867de10cf6a832e35038e4e643b5b1f3fe1cf2123bd4bf087ce3582a9462c3706a2eb7cafae1b9b79c0185138977af309b428a29546c4973223d +Mac = aca1080fdf13b259f71db18ab0a8add74059af9d50f7310b1ef0bb0cff76fb72 + +Count = 88 +Klen = 125 +Tlen = 32 +Key = 63ef2853fe6dfe1fede12081b2134522dfa0a52c859f0b0bf0852c75914637a73cbdadf2944e7377c3ca262f6e92ae2ee7001628a5029a34f20802d0e4212f258e60f48d778527534cd9f7bad15a7f401d189c2307dffc25dc16788c53e7a46ec2a1a42b915a413befd83c2ac5b2e1e0e8b2e026937e5966147736b2c5 +Msg = cfc04f6fd5c15870c1770633517926a0e08805233914df54a9029ad358adb476d82b7ba7ffd17c07f2f93d5883022f99bd99de72bc376bd3c3eb3cd9885af2f1d2049b3f46c929417eab24af5cd59ba69edd6006b2467519cb49c17534d40723e5d4190054b049648d15210285f9540fabdaf3a7c147e46ceaa291700424dd55 +Mac = fd71e14e6d8d13dc91807d290f3cfca47b8c7f8a23aa18238200f5dad7dbdb3f + +Count = 89 +Klen = 125 +Tlen = 32 +Key = 6bea67b37a53b090f6de495442793d6b641f67d5abf234db958baafaef8ea9243e8171285ede656e69660fe7dbb96344f32448665cba54160ca6d7f76dbf1cb8ba5deb8eac6b52e257bea6474ea5c4ae0ec29cdd9a18f11d62645a3369b18d92a727dccfad240055878e165ae667e7127fa16c22ae3492575f6f3a982e +Msg = 11c81f57e7c3fc99d60c16a6d9c8d1e9fae927fdb8ff3520ab51f9e56b2d5a29ad7c6847af99e690d76406f5979273079347942206e610e461288de4366bbea1554d9cb9357af35c95c221ff626f1a55dcd5b07bf52a1273f99892d37491abbe516342143f0c2ce6594ff12d0507cfbb1cbc02714c7443b3bbcb8f19ed462967 +Mac = 35c4eb549bbd8afc1b033ad66e4d02315a62fca1741a26e85e2533c5f5e816b8 + +Count = 90 +Klen = 125 +Tlen = 40 +Key = 04e866da69ea0939b02a4e9e29052fe6cfd7a5f87d65794a5e7856a7a6cb242f7f27919f46cdf0d2f8144788e753a367b201af3f731b85923ac6c454bb36e3ef43cec58af1898d8b2298b35a2d4d58685137d671eb8f9cfeecd2392d8bb0b6b437252924d0e6876b16feba9d62b9f3f494c142154c8764945de4dcbb7e +Msg = 2f77d8331b2b92c856c811889bab8edf75c6875c024da90bf6b2f3ffe2d4192eb774268286e8662c8913833c6794ee6eb43e8047b7c8626171c62a04dad846f56e229e93e8fc751f4eea905c2dce9b58265cc889a9cfb91b01daa08991e2a56b5d6a888fcccf874aac35821076c15d43d309a64960c877e1aed79eb78e58fc36 +Mac = bf29051be936e6a324f149da168236a5af7584ad0b8ab1e7c27ce03c02768885e27d065f26321667 + +Count = 91 +Klen = 125 +Tlen = 40 +Key = e5cf7ede640ece05e6e08e6435fa6e752adebbe515ade1005e3c2e6b6d69d811c8b0425f7bf97bb4bdb40713d028e31c2908c33ad1489e1d0b2e6c6b37ac2fb2f6ed30a28f2e8b7992cfedbebbaa9d3218a3b9046e80c344dafc5c9ab4164e38b8afd00d6854063bac59c8ccbc27a4a03fd626aab5ff565d12cb8360ab +Msg = 0c36ca43e7c113ed9fb71670b3ea73bfd6928c839f36db1a82d08ae0ff2c3dae199133a10aa38d1d3588ed115c4a437c137ce4307421ddd615c9863237fd5aa840dd05ff6c08bf66bfbcd9b43e3f95f45e7d3b21bdf2692e10caab495c474b616a646be675b850d0259c01e2c1901130a0dbb9dfe0722a2c5b1b20afd7d2bbe1 +Mac = 719dd79984d1a74bcea46ccbba7ae09fe246a47709d993d31555a20d57dbd5b1be9f8fe55473ddbf + +Count = 92 +Klen = 125 +Tlen = 40 +Key = 4b07b5387cfc8303b4bd4012fec0d8aa55a0c76aac1539de32247050d39367e102a0b5d9b6f3b33cb2d0e19e0a918637e354973a7af1da63682f4bcf2437bf11c948c78219add7d8c2eca8fbe141da14c54adee6f504136174f62f7443ace1242867b5dbae1337026d795bd18bb61c6683ec641525372c00dfe3e4e73a +Msg = 27d367524b267653030bda2babc4dfca0260685822e08377b69940c867d9c4b097cd995c52a2480281eb2a6a61437bae3433b03e37560a26d3ba6c94178a6a9466eaa21f6d234f5458001b0546783575fa8ca460d373db3cfef58dbfea15c2a1fcf22ba385efb2d0f112560341aa36a9bb35ebc8df801b419e104b52c7c1f55e +Mac = 29f20b053e817ced2a92c32da8cf9b281c4d3b209e086e1512513016321e7f8d60c6bb42cb86fe15 + +Count = 93 +Klen = 125 +Tlen = 40 +Key = 180df5d78fc1cbbafb80c955ac28df292ee51b5c1eb21c603d1ccad0c349449af63a1a63fa4dbd27eb063320290e0feaf37ca1e438546ad9a94dd2e013d81e80ec5d9c182cc8207e5e44b4e7f6468c07e5ce38796bea1d602c7b264f873bb76623ffe3beca3ade087bc3b570bad83cc82b6248e25f7a1f3dee2d2de4c6 +Msg = 1928e560892d145758e7b25af656d00819a5f596b255b9141f988ff2a2fbe3c21248653fd0aba48ffd13dec5eadb16aad0aa68bdc2989a78df92f3d5ccff501162a374b0a3c4a0c1f38c636385afb488134e3ef9d21afb9ba5bc04f09075a8e07001bbbaeac23076a21aeb3dad19d02b48582053ca240503d7df6b4ad7a412b8 +Mac = 2ec31bd36f54bcf875421e668e9f149b92190bdfaf75308a3d345f08043f087de8229e9f0abe25d8 + +Count = 94 +Klen = 125 +Tlen = 40 +Key = caa3f071e610a88a12645f8ae6a98961a3ef8640c491d3fed5b982bb8826e7c3062d95b483fe89e41529a4fdc6615feae87fbaf7a8ca7533e67583194469bc707d45d270f9a386269e9e1b1ae8910b2e3c20fac9797de835d1e4aa46d7689b3dd8f28feb6f87081a54c9ad2875c1f7f548db2e005f3294cc3d0ee08968 +Msg = eca53fd1eb5c3ea44227ad2d69af5a8e484d11f89cd81b1e9dbb05eade4aa36f745653205afe863f14c97d9893f2516e590336b6dda5008331b7e7c2e29d872720db2b671ee24aa8bc2952356480a57731a2e121570965aabf061100f1104c7b375d4c0fffaf92c78271b36ea3025e8f1a519ba1d1aa517b8ecf0b0ed34bfb52 +Mac = 14fb39fd8aeafa7c3f1367bc918e2595ca5c9a7e663334f38b774978cd3a2fef78cbc22480ff791e + +Count = 95 +Klen = 125 +Tlen = 40 +Key = ada011918a63fc7727e2b9c8d1499b24fd4664cf2e5f4fa61988545807f5a7d27c2d82fb166024a2b7fa1ab4e778bdb3737afc635a1a5bc7ea7d3c4b27a75d436c94a394558416b1db962ccac1984a40301e885b9ed1b53ff40a9b1cefa083a6c6fefcc50e78d98ddbdf797029524bb27a58901ec02c63f87c58f73228 +Msg = 3419a1928ce7edc8e3400c30998f09bdac6f63ff351eb23d362e8dc5927eac805d694ac9563dcd7fb2efa9591c0d827af9f39146f0424873aa8e3963d65734b1713baf0a44696b3eae595596a3bbab69f5ad5fead230c0448fdd57e9a3d40f26f7f69afc5d540f2b5de6d88f3881cbaf27039794e4d162d76b83b0fe02dd8709 +Mac = a4e125d37da73c03071878f8ba0fe6f852cd23208efca650d560baec8b718425ebc80270b5c9dda6 + +Count = 96 +Klen = 125 +Tlen = 40 +Key = 9cc58f0fe886a026073a8f75ffe12d1fb9cd5816abb1c2d6b4fbf4534763922fccc4e031432b85f32b2e8fdaa280b84bcdc2e71c7a9bfa49040ac3e977fb5060f51970d559e472e71903309b71db4d99be60ba99282b7f1883ceb84f7764dd65df6c47e470d7f06a9b5f7ba1b41b74705350d873fb8bd8a9f9ecda6d8f +Msg = f87e5d99ce24330020d94c49c5aec8296b22783724958bfb21ff6a48bce1e0ccbc7c7ee6d5423eb76f8a667ca987af1b9c7ba7fbe42854195d871a592abdde1afc4b6c0c908516467a459e9322e0570d0c5986ee5cd50ea2994f4d21b18d417b3d53efb407d605d3c973be3638a106284125dfb6938503be5dbeca4859394f19 +Mac = 2f41f4b3331273cecae809af52bee4afb56d89d9db9989cd6933b97aca92c092442c6aa426418421 + +Count = 97 +Klen = 125 +Tlen = 40 +Key = dce6add843eb2bf17fe66cdfe175dd68ef95e179accd2b021aa96a07fc6a2cf5e0fcfc325d28cef79a0b9e620fc753c79078e948876acfa581898e55ec18acd51ea6d0409a3e26208fdf0583a22bd052ed631adf48930dbdc70a0cd4840d97b49ecd6f2a8196fb116848eb6b210b1bb1103fba6777b2abf2f5162bae4c +Msg = 2c99f9d18ef7903dfbde905e761533d42ddf4496517e8c9124f68e925413746587ad483f372b6759c04633deb71009077e347384157f9e1f339f0e9c962b90e397e47061013bedab2313ea6424c7e662976f2e0c4f5f510675f1d511d785282c83c5d9ff952e087a4dcc1cba6544b42ca118dff4a7278f9011734bb8c1272589 +Mac = 057c5754ac6b3377b5eff6877cc4cb2bca774fba71e7029d148939ee822e1f0149d8389b54c969d6 + +Count = 98 +Klen = 125 +Tlen = 40 +Key = d736694dd886bdc5588a6201636fe137e2c8932f1230b4033530b9238863e39b74d7159908b7e329a727eb44fe706809395d044a77e5ee4a7b092dc5a40034311f92b6445bc2bbb6bdaff44896bc4b0552efbfc8f2976ffebc32f4ad308df4b63f2df457b8ee6ef303ea2416119cb3b493466bb16a8f5ea65f71b7e315 +Msg = fbbdd756a8b2408130425e0262caa7bf9c0384d49d84bc36948930967cf2ca89ac8fb0e5aa9abd6e418531b2d3f7a731f01148c126f53f311b896c2dda785d616b7a7ae2a6d67fc9482530214758480363fcb2fffebdfbbe2d2908e60fb7043e5e089d13436c70da6fa8c11667f7707c1f4e2855cbe4da25f2f26a8ac4b7a866 +Mac = 36f27970deb7fa57271d345a13f71708a9ef95dd9e149f9ed35ad7d4b95d3c6bd3c3b284b33bb440 + +Count = 99 +Klen = 125 +Tlen = 40 +Key = 05af3c25279cbe03a617aa6e16f3d2046edc82ec0c48ac66f9ab42a66feae4e29813bbaa994ba578cf08928858802ee9d661c0d56fc2513e195912a914eff83fb712a921700a9bfd070e7adf22b7cb490eb4d085bcc0ab3a0ad1c53e449271abeb14cd35b5c0e9bad4912c1b7b80f34b9f3f7aa5fb290083567a260c08 +Msg = 64d4ed1727833969d2d586f9f7288746661a35ee96575c2146af5a54636c233a2de289f09647bb78eac50b68b5cef4e3e2b05bc92069152b8abcaa0286845820ed495b666d116c382c78882eae03f20cf9b27bf5f7d401db1b1f363a4700a206ee30ece276885592e01685b3aa708aa9f4481edae341281a4301866570880ad4 +Mac = c3845a354bbd890438d78c1be026eab77862f3a6b251a48aea3adb1a91f42c1554f3f710c88a197c + +Count = 100 +Klen = 125 +Tlen = 40 +Key = 6ece2d8258c46d99d068990ad493b5209876bc351ddfda1705b8dab1a6d0e2e75ddf5ec124c43acc671054bd14c83158f267ef9033237af04c71033904cbae4dcbb18b4b4eeec8fc481c256e9b6aa7de9f9d91dbba5590a9319236e43d76a965624d9d6afcca7ff01b93f3649001817b48208b5fd9fe830b5b225bf879 +Msg = 1c72ecfb8439d9ae3ed4eff8fff3aea771692ec3852f11b90aacb6b87f33af5c25ce768a593a5b9b2132c1bc05f18a9420f2d02876fad6fc88583e7b266b7c9985668ab79150ddc7844f99b0b82501f4b9fb31909f5e0f249b877f53cfdfd66d63c2924bd583487b90b1dd9ec199f90d660cb9c3a763a4776abfe1082296a71e +Mac = 9f28bb5a7db53b7d2b3d4e9a5e50c42f68e5f05e1e3c7f8f6f6a9d1fe6093ab0eba1858c3090923e + +Count = 101 +Klen = 125 +Tlen = 40 +Key = fa90796c79d6a728b50d788e35b9345b109e5f8f9bd3821d44182fe6be693fe85fd45eb3c687ca1dc02d57376d7bb7809e05f85882574eb78241131e69720ccec848ee3999e720b62289c3781c15f0c115f24053131d92287a7908622f675385fe9731e4391e3359a2c8c4398baf67873c0c4068954ed6d7f569179a5a +Msg = 3744c090cad18c19a41b5fcc4d2091ab8920b70e224e80f5e7ccdd9df5d66551353ef7832618a11bddb6c00f4ad76934bc1b0854a7ba4780a67632a7bcce9868df75b425b7020c59a3e99a2bfdaa2a439f4803dca5fdc91a752ca29efd9798593cd23f9d04f8977afe9c3347ee029b7f388ff0cfa47fce6c5ed676aa41992dcb +Mac = 7fc9f8e88cfb59f850bcaf25345aaaa669997f1f2dcc13e6864a44e67b9978e05a0fe33128c51a9a + +Count = 102 +Klen = 125 +Tlen = 40 +Key = df0251af61d9f87520a8a464bbe6004c4c9026afe3cbb58134cb242c8cf356d70a3e6ee80bdde4c7e622d9e5da9ca7fe4484bd9b1557aada84c5777100ca3af1691be8487fc36b8a9b0ef4f19da6932225fc05b106e9cde8f79686c48c997741656068d7a6d3b445a635a08dec4beb4057c1a6fb9cc94632f605f82c18 +Msg = 48b9c72f2fb4032f503134e7899fdb60126c7ba4181e5876a8a07f40cfd9064d00839538b53b26a559d4082e66f12aa1cbd39668906f3c48bcc4f14f776bb7076c703ff07160ac2d6aa39a7e6a0c5f6e1caf90ce62f3c8613be8a4d9eada12025526cc3eab4c1f314946f1bddf180231cea972bdd5d1842aedb3a1c7714da0a7 +Mac = 3d5cdd58801ed86d5c97930b7388b22d1f49619026049461c01db6e73a3cfc14f8ed25049c21eae0 + +Count = 103 +Klen = 125 +Tlen = 40 +Key = bf229362c49dc718e7a7933a33ec8174b224fcda3b96c0888cda8e8599e424ee233e6c508b95f455e9779ea3595b990195e28fbbc95c2048a28e902ba8b3bc17cfc0535648ec426c9d7070f7fd8bacd9d5cae499a0869707ffae8c1f0cc7c530eb30af3ea3ab9ba42c1971fdca85a3459964613c681b0c0bcac2ec2a6b +Msg = 04e38071f35b901bab55743063832c8339d5f52d6de21a1bcd890dc970d8b64ca72c0b96319ae1f6ae8e01de56b27fe9eb12471cec7df96d0c2ef781e3acbcbae2ee6f718cc3b780e371d204219ce161a96a86863de5b17271a1b7f6609ea5bd9d6fd38b6d9cbcc233460c2a2b09fbf15b27daf1c7e2eb32e52976b05077195e +Mac = 710481e7e1b77226cba0a0ce4630ce7fe637a615cda814ced3a30c0b02e3940ac024b56fd16f7043 + +Count = 104 +Klen = 125 +Tlen = 40 +Key = 557c91298dcfed52937609089637a8cca82c853f71b0a22b207fddc7a718c4372866aa53aaa0fba9116eccc54d4db6b0d134e5b647786c6c82eddbf2b44e1476e1de5af99350ab56d0e4508049d4b20bd4ee6fee1c82ad87977eafdfb9d8a630682cc9a4afa7a760b623bcc1f29343e599a24c6e59970e82497c7e1620 +Msg = fb0e03450c407afdd45d07e5ab697336387d3d039562df6bae5f5313ea4ed6d40ef5ecb05e94a40b05bb1d17b65e4991942bf1ab4f1bf9499048e66f98fe9dfa24146d8f937d50d24a1a6ed858d2e3de56e5c23b917d5a936c87b84effc06d48041391caf42207ba6d23030ed7edca864752b99ba3b089b308c3d19668bdcc25 +Mac = 31e3eb1cdf76f10b80fb7ed8e614534ac15f6ca3624d1640f50bc8206429c5ffd944a1875cce4601 + +Count = 105 +Klen = 125 +Tlen = 48 +Key = a6198953522d47667302628cdc705e0959618cb7e636de921f66f97af8688c35aed4e0b4fec5b19794813df3c65c9a5282d94cfb85131774ce5b12465323fd00f21bd47eaa99a46b0b3e9e05ebd76a205b81be6eda112efdc8b246011dd0d6d45a358d3bc072c9ebc081ae4cb4a8767ccca007974bf7cb36f3b3bc35bd +Msg = 2909532550db4940485ad5c1905a88c7608480cae0b038219796a4c726a67e5e3634db74afd801062a157c42aa386f91868329d5aa8bf8ef00df428528ead1026f1b6fdeff43b31f533e1a20eed559914de3f2bf1ab70615a2ba6ae38951fd5fbc0538eaa8e20694aa1cd6e1c6f9efce9bea040f96fb099b676e456ab1a3a77d +Mac = 9b31714df38d74da1d31c20101823a7a51129595e96885fe4a3cfb31d5e32c632b2f0e8318c23392c4e1f83f180aa9f0 + +Count = 106 +Klen = 125 +Tlen = 48 +Key = 91f9e69e2bd3a0dc7240d509c7ec14c85427f79ca030574d60b4bc8d919217dbc3e1b4a8b8346ab82d1c15ccf8ef467e53c8386c78cf06986ebb1c0f2295ebc9b9bee2d1253399a5f6104fe073539616eae34d0044d1cfd9dcdd6a07923c13fe1b9857629b59956b75236b8e619f6e5ac07f1ea02dbc19d655228ebd08 +Msg = 8e9b8a2af5bf4d8efd51e33223e35e69c3729c2d3cf6845950388c19c9e47e9e62df7d16e4da43db9028aceabdcc7898c2d74c8016f1fbc0b6350465c7425c237d8e6d4a3bfe5ef5fcb49584f1297a4d6b7b7e8ffc085da7d93b9f8783a66563a75162ad42522844089ea5e9071fedf288073a423663307882f36667453923c7 +Mac = b771f39b76ea764e7e3b488cff14ea8e337cdb173be0d8600d2f565fb04cee85011a26b5b9224b30162dc3ba48c9b121 + +Count = 107 +Klen = 125 +Tlen = 48 +Key = 71c60834c9ef3ad38c0422e43a94e390a92e9f02a8763a1ae3776066073bc94e2699bb8e5c4fd1eab351fc1c4460c7129fdddf566de0d2ce548517a51b864f890f0fca17a5cd4d93604912ddf57411a0ae827ecd0cfc9348b0118fe17b2eff85f5ce3cb5eb9235385d946e0d97f949a49dc5854eccf304f1bfc6d10070 +Msg = e9a877d87ab357733cf63620940fc61cdcc24de1b5f99f4b9f094afac73710f71f7b9a9ab4846aab3dfb12c7ef0ca305992369daecf3d53a1abdbb00a4cfbe906c4b08bb12293ee37d7fb25fb800db2000c303951b4740cdebb3a5dc4262b97ff89e28033bacb962270a80b096f455b53a2c85dce9fbc74c377371544af8eb0c +Mac = dd608e1c1464bd8bbd42c9ed528ef3a8036f66b38892da4d4aec611233eb4af89f7b2d9fed2e9aaf177175d674dbd516 + +Count = 108 +Klen = 125 +Tlen = 48 +Key = 3ea973e74567002dea56ded27e4f1214581ecabe28864b4d88862b50d4dbc0153cc6d881170faa407a4a0d1f0a59e8b50e32ea49c9e37bf006d3f2f6f44a087f34338c6e31215986b09186cfa86fdc3c53db8d8a852c226b3d35b6e479c862f44f79f8763aa4f448b2b2afadff97d6f04e9f1b4b056b2a065436dfe30c +Msg = 2308e98a09d74271c2a336c572d424be7c0eaad198fa5d8d274abdc3c4f768e91ccd8dc0ff2aa435b7035c859827d5a5d8c810e1a137a4c365efb23672d51aebc6beeffc243229d067709a3e17b124f53ab1281b6c6c4134322533468cad1e3ac9e2f8869f7639097bf2d83616fa777549d2dbc622219ea837f528393a08db9e +Mac = 91cbfa1b604f0c2e6b85ed3a4838f7df6fe50353c94251cec2feffbf84ecf98deed44bd62c5406e86297dff5b7fc94fd + +Count = 109 +Klen = 125 +Tlen = 48 +Key = f234a0b1af97eac1f791c02c2dcdb786a223d50ead60458cfe454f802fd288789cc446c2755c57431162f3a7856aeebb765632162b1c6dffe6c9078b75c65706045a169435711418739c295583586f545b93ae05386c1828eb3b376e73d123dcd101f871185f8708c4474c804c21a119fbe43021fbd9aed1b3a2c77253 +Msg = c48597527e4d997da811cca724f74fc12a2738dc9ad28549907356ff3954593ee65485725fe90b5a7a618969ec6d816d5edf0b6ec4b3c6d9ea4c14de4f01871637d89669fc91952fa5e7e495b91266425690343b7d259304b0212409bfe15b3cdf9832fefc501f43502b43f135efe48a37c11d0b6e31d4140b77ed4830fcbdf7 +Mac = f459c728cf1350639d2778ca5dbe68e3a5916588cc55a8739b461ed508bb358005bede01adb15875f03761d07484c4bc + +Count = 110 +Klen = 125 +Tlen = 48 +Key = bedd2d63c53fe1ff0874896cce3357257ddd72c218f99c1006e0136715b9b438bea866e6ab43b6d77646bfcab4874d6b322c42247e1b3837a9b2670a4cb9c9c1c9947d12d3bd6a55317224dbbeab1381b54fd2852ba7d598dd134f342cfc522f66093891479643a3c0628048f687f1908eb0ea8b2886bc5b296b918dbe +Msg = 40b107b77ddc1cfa73fafdda84f4c895451c5138df05af12b697fb684862546a573326664ae5ac3cd17ab412c86ba3485e3bb8ae765295f54d09fb645d02d5cc82ba78be5c6129fbf4e9df2ca25d4bd42e74168235666a4bcefeb3776ef0a77b096e84287af69821256e0792db72c91ffeedf21be5e636fb819dac0a41d7d25e +Mac = 4fc42aab05538f132034dea79ada4b8c3764211d85191e3bab99a04c776fb25c940889a1906ff9309bc8ad998e5d80a0 + +Count = 111 +Klen = 125 +Tlen = 48 +Key = beccc5dd3e0ff0bdb69caca5ed6b1df74a9cf766441593b91a6d42cbc409e1d72984adf2925459d95fab5eedf99c937c077ffd42e596e83051f1366c688ef898d2c53b5739e3240dff1640e73089151cb5cffd72cb853403b4332f41ac742f381f57171319047ae2fea3f99a7b79cc5dbc549efce02a9ebbaafdd35479 +Msg = 5a7079ab9de0bf5c46f49aca4079f05246d0f275a5a0fd2b43c8be79e0989a459c404d6ab988d108a3c2811d2dfd7e5a1e7c522fec67d329c7bf4a7dd997d5e5cd820aaa8e48dd0251ddc49dd593197be98ebf003078084a2177d6c2515c01f1f51ef996a286adf5582bab71bfa1885db0ee8210f73d643758d7aa70d04ee614 +Mac = 56323521c9acbcef43b446cdc709701ad07c2f655e630cd4de7033096fb58c47842e07c78f460b13a8bb690f9579e141 + +Count = 112 +Klen = 125 +Tlen = 48 +Key = 78eeef30512f01b5cddbe1ac68c81c3849d81af52c1fae39a048ec9a72343bb069e5ab1c339b88c8a03c2f710ef92063252f5584c48bd2943a727eb3baa03124090f0e507a1a130e1ce2ee2132f11202e31d0be133af0ee632c5d5bc73f5aa50c033c1d60cf5ca0ea995c7c5bcf61b9eed6ae41263d38bb6ef099abc87 +Msg = 655fec47e10300503adefa0091e11a664c2819270c22bdc3dff3ac19b8167e2e1c47152a1da031a38c023f1e6bb672d3a15415b1f1e420a22d440910a7cadca8e9298e5ea6998fb1f0329e30aa99e13d41df351197a6c3004086d4fef1afe66335cffeeb62364101cc38be3d38d28f2b9491204ee5b0ce648080b4ec7d0dc1e6 +Mac = c683976dd4aa6e5a359e3f6359ff2bd9d44a54fd005e0b90d02b547b3aed369793aed0465cc8ebcdcc36175ec6c28fda + +Count = 113 +Klen = 125 +Tlen = 48 +Key = 1977183650572f0cbb8d65228d141b67cf5f4212a692c47dd5f21f37829a53553d71ff083e58c775eea8f8c0aadb6f6ac389b7dec997714609abf9a354e2461d02c61297377a3b8765386a0512fef222dc83fb7aba70df0d84cdd44ab6b9cc6d715f990bc22555eb272601184fe36c342235560f0187d6794f41f95430 +Msg = 99d4482daecfeeb8d44226a39f85b42f9513fdc2d798c698044c3eb55a803f1e1e76d1483e76f0d1361e8f6e30fadc256f55c6bced4ebc71432eb8ebcaf87d7100421d5a2d44bdc4462f9c8911c0526f8a14569f86bec35996175ce52ed5cdcd06df3449c160dffbcd1a57dc8afe9e77aef9b655e81062b8c3af318cce3eb79a +Mac = 20055e634496d6386db2dd25f2f24f3336c9f3ea8a28c4226ff8b34e91d854a0886a0584c858665859a54534e1b1281b + +Count = 114 +Klen = 125 +Tlen = 48 +Key = da02e70f3f27b04720271048f65d81fb12aceee8eb7baf59b7fdbbbc38b6194ad93b98e6f939c04887b8085acfa14ae2937e73625e827f3c15c9a51acfe0ce8de6884cf54fb7c9a026e07d368d74a554b7a93077407abb1cc0efbf259f9e097f2b726b02e7abb2982626d7a2d9df7a97a6b48bee3a6c4b3fdff773a551 +Msg = 3b0d45434969e3931fd801367b32e7e680206cb1582eb9a71f214fd6fc8a4c78919be96a963a48e0c0546d58e8748acc69947f2cca33a10b9da7ba99a6b552d1405f2df3fdfd15358d8fdab5e15296b38f9135fd79be35aaaac1ab0b809087df100018c6c6dbd3f94c325037adf49503bbc0970caef8feed0d172916d244720a +Mac = 48dcaea229724fdc6a01a19b9742c1ed7fd57a86ecc2164c9f808f62a0c8cd6da6c57990db306499cabcf344156f4a12 + +Count = 115 +Klen = 125 +Tlen = 48 +Key = 939cfaa5c4b2f535c8c796f4e98726116cb9a3a5cf711d8e4e87607aac47d3422f6aa07aed46154646414b6eb28b05b5bd0dda674f9c97323173df36cde0145f353d7bf367229a67d0d9e5770e129a76fad8eae2e6c4593b23716715c72f706dacfcd139bcb04c426c77ae368784aef92d04193d1b512c522d69413f20 +Msg = 51f9ab865146187fe650e49d45421fff28c45c3bd8c465458b762d93f199067e0afd14ec3a42022c9fe2f321a272bca3cc245022dc917b8c16b5d471dd3bed6684fbcca762c29f002451abed67a8860087848683b126795f4056963c46a8b4ea68febafff04e57c21da5f348bd6ce5ddfeebe6a6820bc584b1605d3a5366c5d3 +Mac = ee3629c6388cf97e6f6f36cd0eddfada5a44c4417b02e68bd46318eee178495aa18bc701f940e29d9198510d494e3636 + +Count = 116 +Klen = 125 +Tlen = 48 +Key = d7d1e2a4b1015678e0acef1fd748da61498b86413e2d58de67efa19baedccd7e12cfddd6b23517212714fb2c174d7a7c071e63ed71ea1e99173d9cfb960b8e553e38d54e215d3ae06aca6071f1c7f6400c203103a7e07acf975c64372b73e0b80415b4552702297e51d404368b40b875fd99dacb0795d5478e54df9794 +Msg = 9561d6d7e4018c397d3ffca92595481626fd14e65ab439de853eb942e7aaf83d12172982fa7706344b93c404ff5046992f309134291b8094c460b817f0f7df23910909c48eb17396240574e68150b0148ea28f3b0c8bee14e2231418b54de7e5ba3d5fe3c8383c27b29bf498d31ff050ea5bf745298beb28888fb38d5f37784d +Mac = 93934bc65a3163ead3180028e8104fc305f2ae407a27b14975fa79f0aec260e963736d9aa1d0069db5fff91f87e77512 + +Count = 117 +Klen = 125 +Tlen = 48 +Key = 95bd8ac4e11edcb1b21ebcac3197b0f72388ca2561b7c4dc889b50daf178a936e4cc6ee808eab08c1ee54a63efaf709b83828bd0947f44d24296dfa909a5cbd6efe477dc028067ff0186864c5a03bed9546ac64e8e353ba4a8cff32d40b28ed520cc4da7b5282893c4ca1a6e58dbc03aff0622a83521d1db2110326f7f +Msg = 4f83fa4a7033fc574fbf1cebf8d4e4b9606807f6f6f996be7c1677b3152114e79f5350fc4200bf89491d16c031ffe04e00657383d9b923b3cc93b5dcf27f1788ba004ef57ed5af745a7a520f3df2c46e40c4fcfc37449045861329a237e935194992db7f4a3734df28dfb8204435f6e1c88c89a83b20473c529fbb4f09e8d660 +Mac = 2e13e091d6062a8855b6372ce7e16ecacf91e4535c4f590824e95575a85154d333c96574402f9a30935bf30edc61c030 + +Count = 118 +Klen = 125 +Tlen = 48 +Key = 8c679291067ff88fb4b7c9f2470fd1e6863ebfef380228da44b4cef4171f21794692064f7434d8f47798acb6b691da22d548b9be958ba9fbf56857659efb3c1d7d846789b2bc7d4aa96afe6e8631c9e7c7ace33c24bd747fba21127f6948423e7b643ca686c1ef77935445847f96a81fa293c5d2af3d9050db0788aa42 +Msg = 1763082e69de7e54a36f4ca6ba48ad036061845527129dc4e8e1362a6699bec72f9cdc37c379b3a0f8c165309d17d5c75e87b2f0e719b1164da519f5a9e8854e06d8e5df7d35c7929e61d5f512719eea7f8499a0ac5366c1e60a58eda257316863c02c0fde3941915cf6a4db617e8fd48b01414bbceb472d7cb9fafc980b497c +Mac = 6327d024f6ffea558be652633d527bd9b023968032053a3a2ce183affae4721bfd81b965bf247b38498b1209e2955ec3 + +Count = 119 +Klen = 125 +Tlen = 48 +Key = be7b98eeda81b741128103c2a5cd5180ae213e384c37708400971f4f56add48cc81d7127df5b723c9b7672881534f11d63645459bc702d18dc32bd29aa08b8ff192b47a94c3c5305fd2001301f0e7940c2e6ec3638c5d52e76d67fd9bc6bc72d794c235b694ee3020028b7a20b83725395500db7075eef2d942c6b47d4 +Msg = 82af0ac2ed6449298b517034353c3687889b4de0ddb5f3597b05c4e70cdfd2274e56f75a0b5c6aad4b2b91bfc8e4165da2763d9054c275d9e7fd2dbb6655e87a91d79423d59017cc7cf22c1d227a6d0f6890b0f4ecaf97b878c5636679dd09edb3fb88253447790d866ee8572946622640b14f168bc3837d95270ff02fbe5d09 +Mac = 156277ce3ddaf28e60541fa2c95f58e045bc5d68d630d5fb94188de015491dd6bea7bfffa185cef131b6ae514e7b2422 + +Count = 120 +Klen = 125 +Tlen = 56 +Key = 480be758a9b7ba9af001bf21db00c451cfd66f06c9d8d5d698ef47974a3d6f21e4049d5556c45b5fada447378b13226ed4af2427ab6692649ddb93831b0b40082e30fa9c66e60056148c403ab8ed6effbd1f541664ac69e7fff0a45e5fc292a68f57a734c362d2088b80532f4cd4d18df1eea7d9def280e925f62330fd +Msg = b10af503590665c12e96c3be38b6ecedef0bbc4da1be8b63138bf7e76b15e4be4d7dc22845320f3b650b1c902f93133cb5a43901fe3771c6ac7a0245dc2399044e049286c6e073c2b17eb9d40cfbd8f382647da3d485162b7efb944a98916f26fac9eb85a3b89b3f5c1723f4989841fa9f760f99eb50827bd237375e66066f0c +Mac = 6a2930bca4229aa1f1ea1d5a26d02d3c350550f2e0817f52671dc8638dde0fed40de2cfa5483de8ce941d94e3501f6ca92131abc64724422 + +Count = 121 +Klen = 125 +Tlen = 56 +Key = 2d0cb6d45a952e7696ba75babac052a0d44c5fa77a6d01ed5edc9d97238309736f3d41dc42dd5cdf8671be9ce7c88eeee4316b4e26865af4116903409ace1e5958ba2814dd495a1746f6db3e1117353d2fa706875a48f86fa988f28d626490640f0bd141d4e41066ffd13668e1b62dd6dd35981bbebcc1a64dc2d24824 +Msg = 7415f6373b8a794877c639f009b3c49197f388f98bd3f0ee5f7ad00a196703ca111a53e1fa1098d220f524bdef165f79b515afe4a9e09b772be32f1e4d7da24693b13637f71f60a430322980349ad414fcfdc14f87e9915d210e8b7be5aa3e09814468e0399d17e72fe40ee1e1296a89f31486e12fd71bc7ca61acc9e8d4213a +Mac = 76912ff0f180d62a86a2bbf8e1f8d4438ed5ded0cfd3bbbb430384a60f18d9e9cdeb7e49ec43a61367686b34633601a5aedf8e3d669be282 + +Count = 122 +Klen = 125 +Tlen = 56 +Key = 6e1d5f581eee884d330e4cd26b51007f4e3009b0111ce581bb126bf6867053798807f88a92715db259a46eb8d3c88918e4463db13a2252be768a09078cafa4596cd32933e2a364c2bac82b0f29b9e67868d34e5da2ab741b10a3053e63bbcdf262aa7bbbd42ea466a0a00a4033cb1d8522fec21b10605480d384e802d2 +Msg = 0b8cdd9bc2dec68748a799c1c10a4199070ef57ba7975d7f2d95f63ba27bb7dc52f3f575d3cf849642431f21d05209597d87f53c24e52413b820cd47cd0ec1765a584fc6bd756579ffd9f9c25a69a7d7f8339c48fe5cb28fc959dce87762c563aa24b43788b7b35907cff04d6736633d007ab1483de3511ce9a7edc7a9610bca +Mac = 293fabbcfdb855289377f512efbc370152cb87197d12f661b6cae18b8d242cbc767a6f663377085525f0f27b390057dfb99b57b73f52aa2d + +Count = 123 +Klen = 125 +Tlen = 56 +Key = 030d2ff93bffc8241b850829f5720812c4ada593783279328d590aaae25b4092c9121d3a5a00a8d60e932ade89a79db4b64d628819cb327961e457fc3d591c8271af8255293334c38d3cbd7f95b0f9441fc9c9bb3f190b9fd6ccca1f662eb184246dc6134f9f5535c10629d5c493020a26aa44f69025edee139bc9da04 +Msg = 942405a1436a808dade61cc4207fb8ff8846af793dfb4f981fd38dd0e578f6c5b252e9afe9050403433bdc501fa3f166193ae1beddc9db163eae575c82e004cd002e025eeec7525b74ff8b4e0450ce22ee9ffb882fc1259a8a3e44bedb552acea740b976f7b952dd67bc90877a8f377a3000679fdbee166c2e0abdc097df500e +Mac = 86abebfc1cc5ebda3fef0a08ae515176378e189b577b51b8d3cbf6181bc1cd070a086d881ebf31ed79da1f034e5decd30a9b69256cf5ad34 + +Count = 124 +Klen = 125 +Tlen = 56 +Key = c169eca1b31e6d7f3c59747c486ae4865ec824f5c8a967bef5cf31e91ba51745208ac65abb6d469fd79a80ed38d3fe3460a3f36db4ef7bcfdbce2346679bac21b7480c0a1bf4b63c3ac01bf0b1df7118fdedb3509b82e9126d06a92960c7de684c48c89b1cdd44be2e744e6dfdb6c49cfd4f6c88c68939ed7520ca7a4f +Msg = 4fc3b9d3c4a2a4b95c41d441b88e126304cf134ad02ff2fa1b76dd36b1180ea1b871fc23854fd38eb4b1228277ced48e2e5962973804477e0943b3fd7d5283d26c7971207f8f881242bddcc17a847758b80196762e7016d3c2f0292761854d4796637f915b6aab8b2fed68c768b7e20acb5017ac5a7c47426d05a57b04ba5348 +Mac = ef19689ca901092506af1eb87b16c24c898ae68ecdd2577ed6fdbae5b0e2f93e9f0c1a839df6e509bca954bd881ec03edce3186a9e529490 + +Count = 125 +Klen = 125 +Tlen = 56 +Key = 9d10d596d5845f84a6805feb81fef632c044617a930c86dc3de1ccf180cc3098553096f3e1f35cb3a5de3596f547352dabed28e31c23283b4b316f595df769c44dd30d6ae1c56ee5ddd18dfc76a5726d097c7bea0d42f36147f9e6803c5b3479ecc1e502bd43bca0b6210f26ed62d67843ba01954eb10fd59702dc6f06 +Msg = 1fd2428a58b14ac4f539d7eb55dce51ee7def6e4ec0afc787fa47864d39ee451bd0e4f1e72e0472f91c8fb08647ba11a631f16dcf900c41e8b84c99bb76156cdd90d5405d4774eba0ff48b21bd7c7aff621654bc9291fcb8fc752ae2a839c8867db69c6606dc280d76a4ce60e9453876ecabf7a940256aeddb5ee261308e0324 +Mac = 55a1be4a6c9374fba4d41ca5b23f436c82c041cfe3fce242f404444844dbda9c49b2b4e52ebccbe0c95cb6f04a1e4fca51b26b09e05f774c + +Count = 126 +Klen = 125 +Tlen = 56 +Key = a1b77e7d35e194c8f30d1f3b9d4510d5c71fbc688c9a309d7f4ac438e4b5f39d21fc69936fbe5e49d539239757b2fa856b172b11ace4542dd2430108e2777c8ea27ae73250e587eb9311637cb27c0ef9046ec187a8dcac63758c8e26347a84470d7b1ee14020b8b616dd0875166af3387b6aa551e64be046516d941a44 +Msg = 6210041f1da920551a12029bc4dd81bbcdc5fee0c3f09afce571a66734115cc9cd4fcc3975a518a6760de476aac4096ed54e89d237bac8cd6227f9124a87d6c49ba394944f6016297f4061c4792b5024147088a74007afb3e119d954dec1432674154476d16080a4deb25fcb5c9bbea43233e4a8055db7750a4d2f7318480cb7 +Mac = 232df75b5b6d63a2f4c32b739bb13a5d456684de17ee1f78d351feef5d082d2efab21d6143c405c0f015808675ccecb2c398e93874c7a15f + +Count = 127 +Klen = 125 +Tlen = 56 +Key = 8966e3236aec1581b61c8e3960e90380d8d48572df6bf8b19b10c64fe6fcd5eeec84b625f59a1f267f969b9e903780dd4ae42137c03846aa08bed9c192f9e2b7b7a8b6e095476a451bd98e8e60e5182639bf9f990a08ca41dc780721b0db8011135a4b1cf3fce026b16dd1d177fdb5a2cceb656066e46cbd3fc7b839eb +Msg = f5722154ecc1d97bc585dbca18091604ed4474f922af5ffc0d5384966126d67c5697d6bf0468124310bcec728b719d3117af7a134cc175cd5a24e6ebefde8cc15b11cea3f2d04759b13182cd25a402078983865b2fea8be121c811260736a2214b0891697ca280a5f00e2443ae4b4d6d8ae7203892d0a71fa9678db172d62286 +Mac = e4e76d5f58ed574c96c42b565d53e6676d2c3075217f4c1a0afa79c3b55009617e73496c1af9db02a70ecf08b2c95dcf1be5d94b7760637b + +Count = 128 +Klen = 125 +Tlen = 56 +Key = 6bfadbffeb0d23e34c0243c51a7e5a1e7672a7fdc6fae407ab85d5bc343720fc518b5fc98a3d744ef0671c2054eac8c5b80fa873036e0819f90fdfa469d0a57ba806664b3f67150ae1282236a0624e5e60babfe48b414f0106992a09645a98f15ab3170e7355ad1f058c7c8e64af97f355bb14dac63b63c6bc6bde768c +Msg = afa6ac462474f97c6f12e3b4260ed08c04837f95e23d9c9fe21d9138eebfa06f615b2ede03e962e73b89ef3d80212ea611487000e6639282e60dd2455abde003a2a2391e26d2b0e490a44d11395a5b95e004bd98a2a181bc2686b8a2190484afda45721076770afbd62ca53837017fe1db7e0d66fe3e91d30c50eb5611dcb2fc +Mac = 599d768f42ed0c6a81898955e38f34e17b0619891278f4d8e05ff4ee49ea30b063d6e40f44247d36de11a2f346a16395a218e94c7b04510f + +Count = 129 +Klen = 125 +Tlen = 56 +Key = 9703e403d09f821808d19eee46151209d02cf23feecb6c12f190f23d74399c8de218c7f238c203d60c082cadcf28d6ce4f44ee817f129f597bd673c4c78dbbe0d76b3090d588dad09ed731450e5783187d8d950589318daf16280f3794b2a70c81e567052e5ad1adc526f7de8b0be09163f02ef4948ffebdcb6e10be64 +Msg = a3acb88dd0b141652e248025ba606fad61ec8d52b75a30dfeb6e1dd9fb835608242b33329d16b42a8435160a191ea4bc2ab3d0bfcefe82275660b0e681eb2f4bef0cc9c8d86d8ff8fe1970e0e0e20b763100c25f88fa10fd59ca1ca9243c8e3dec97a1d6eb7f79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d1ae7 +Mac = 7100161e04dc2a98b6ac04b2fdcd16e6b64774e020c2a94b7bf0714b1e88b7c6fa55b6d1a25d3eca9ba04ccb5a8fc7e0407d01d98c4bbd3e + +Count = 130 +Klen = 125 +Tlen = 56 +Key = bec9d2afddf5f48ead7cb48d31ac370ed58981cfed6e8eb55ef79ec89b1dd07ed4a3f23c6ab2981aa5c06be7a9b6c46da6517af550c8f80e8fb0928b771d19cb7a0bac3ddcfcd22268e2c695623e12c9bc8a5f938cd58c28beadfd27064136da19c7a8b91d1cca2f5eaa6ca1428f49ad7ffcdbaf8bda738a55b488a532 +Msg = 6a15163bc2f7e899660edd4dd56819faeff7173bb64293f1555ba7dc62113469606683cb88442c4dc96b37e70dae820fbe5f62d188088d22615b3872c76c7c80491efe7249dbcf25008991c2c3b9dc928421e0139b4c4b4bc7906d5c6f4199592e24cf588f2699c8154e33057ff1ee2a4925d627767793138de18dc3e2f6549b +Mac = 091f47da39c7040d6d76064ee8017ea5e9a85ee82e5632e66901304d515ddf5cc4371c3cd3068e3b8a8a6ca5127f376b5d902c0fda382e3f + +Count = 131 +Klen = 125 +Tlen = 56 +Key = 44c3dfb2f9507384167f9844865eae22cb36713d95c9280a93d81efa89e85657a3467b6f094916f5b3d704a47f2a262580d45a339901aafd4bfdc4ccccf6aae55902abb1cc64921b710b1d3a165bb13061304b526720ba8979010cf741ab46de0fff58be6d294fbef921cd4d7478b60916512de024aebf75c5edddc512 +Msg = 0487cc84f63e3fa27576b32e5781c5a23c4a3fef65df8e1dca2c773166090553d678c6302227379edb3d7c7e665354e797bf4d818219342e8df8d0f0cafdd0078413015918f4c41706f0c09e48ead49be3a34f73bb3b64e2abf4d8e2d53afece37e0e5c780add0572117e654a64e2b07477caf8eba4b067f4ca9f7ce30c878f1 +Mac = 5c248c052efc46ab0baaa9af71df991103b7b83773bf7129d29121655c28d90ee5fda29c90ffb6ca6c5a072e95cef8ec2b706a9fbe4d2f7e + +Count = 132 +Klen = 125 +Tlen = 56 +Key = b4351406709d4572693c0a7992499023232a732a3e8983aed2aac82ac0fcc4a73ceef7307603a9857a29e3145547bf247a15e154643046447c6e3d923c6eb2089574b2138e742c772f6df5429df90ffe86212b2bbf756ced2c5d6e01e1aa87f586704d99001858b14eb149ecb0870a1a0ff7589999817f10ac1f6560f5 +Msg = e109e67f994e1442aa4dc46bc18cb6cc3a8eae289b4a194661dcf443007bea2c25abbccd3eb3e6c33c5280d997ae6291938d8b00c3c7c4dfcbfc80e06982073eb7a1d398aa033affdf664e4e979402b900958ea9b62314c8895e835781c1bcc81f55f389e624581e1af1f772c826dd6f060e7dcc7c445226236cc5534d2050f3 +Mac = 4a5e35d85e06a57fe6b6f90a4ec3b90d9c4d8896648f0496c5c453cd1a2c25c4f627c688f3f2bcaf88d7e7b33792b40c4a4aa6737b423e1d + +Count = 133 +Klen = 125 +Tlen = 56 +Key = 67f57e3643ef20e5bd2cadb13f38102c1de95c6e289d036f80c34ab4a99df92ee143575fb1ec55bec3690a5df3f25fc9a8250c31654cc3cb9bdfaa74c24a0f97a7ef584f086f38d05e252903faf41670534357619f45e344a07ec152c183c06e610168506f0030e23769f2ea7bc69beac64a2744fd11cda237a87695ce +Msg = 7f87d81389a6062e8ed501ea964c2fe35b2d3de9fd676c04f7da2bb552bdeb7f183d2fa60c67e2379848ee4807530a81f403d3dc02c11fa8ce078ed422c6626a6c05905a6ecb1679364090c9510f06fb3c0e09321b21fe0aad5cb9d980674e35612723b6179a4afc51030ef4dc48cc5819980575af50b0317d20d54cd36a57e6 +Mac = dcaffd5f88c2ce438bde469813643f87e841e94ecb283270564ae0b07db0b8c006426bfa7ba91fdabd5ef9b1b8b9cdbf860ab0ba459e2c9c + +Count = 134 +Klen = 125 +Tlen = 56 +Key = 31671f1a2f8f8495038b707aa10a2216f0ee457e8600cfdcb3e22a08c24692587b5ebeb8ed93c2fd6a7a3476d2048dc415f5d3ecf39775ab06af770a03b0ce313d2f0e806a9742dcaa1e1b47c5f74eb4b4c937196461c2c5b6a48bf4cac744a17dc2589b3001cddbcc5d6f15024c2b8dd854b92c61c67ed3cba8b0efa0 +Msg = 77e16e181b3dcbf1faa2d371f48400b60207b23219592ea45245e6474905fb49c258007e93d50156be7fc30ddd994e21c3bca9096026e524e5555cf029d53b7c4b563e209a01bb6bb10ce25de68c43d6e68b914f995ba5c84c29c5010ed527ed5a02b164f76903181d72b7cad905e7beb29df06c8d9f7678ceeba9e4c0b0c685 +Mac = f421ee42006f668e1de1a54b0cf7778accf1fd8859bbd46fc98c10170985a3ab690826862818c97b7696762898f25417caa5ac9f21a0a3da + +Count = 135 +Klen = 125 +Tlen = 64 +Key = 13fb1ed6389f32d1de3139cb04bcdd53525c9889b85379d3535a25d290351c95938a3d0cdaf38dbf1d5234bf7965c8ddce9ace1b66247e60d74ec7702a0f931a3cdf4cb465ca9fc458c380004a3a6e7957f1f813210b8038ba663fcdc42a8965d6a252b5224bf249552b2575bf64568db4091d58323006c3c34994d3a5 +Msg = 88ad812fd34e55c809e817199604b4a7f7feae42cdc4c9e930db08e845a3d74313db8a57926706bf0551be758a0fe239f004d237c849d9e4bfac18292bf9c0c3e37985ea54b94f30d18c32ad2b53a059827cddb95a49b4bef1d369ead14eeeb4a18e592e40ca96e515a15908a05a57cd5570b611ab4ec23f7057e1725f29c9de +Mac = a481e713cdc81ca5afa0efcb16e35cd20d01aa449958fd2eaede2e25a5ba540beafba2fab4adfef2e146b4c1b2a1832e93dd373d63fa90bb61490f6568191f65 + +Count = 136 +Klen = 125 +Tlen = 64 +Key = fd5070362296c40d65b105d5ab4653fe34e0200516933f3eeae03ed0c5d9f6016a8560b4bd86ab2f7bf98b22299ed3e54a394602d538aaf3e6951f2db4feaf5dc33426f15bb124da388d709083a28f5701ef96c28b3a3c75bef9332ef373b90771236af5e25d589504345d28a19ab0dbc1c9b74d1ee21c4bd8d423de6a +Msg = 8d2e68d7e9846cfa30d931a38efb59bcced53a14164b3163d2653888eeb0bb1448e1a80c65bcc6eb633447e72ed4a075f75d980fe2b19f35ffef62b27ce09c2019922faedb427321057fce19448d85962a08d1baddc936d1110e108e33d46f97e7882445b5df1ca4ff03edc237efaf264f1c0d9e705d9b3eee076ba57c56db82 +Mac = b6cad1ca5ba505498a8f66a9422bf539426a8a55334fab9c6b9e08e3a5179d157d1efa0f91d5c5e26ffa43f5c1cb7ca5f906ce4f0efcf4e871820b8353e890e4 + +Count = 137 +Klen = 125 +Tlen = 64 +Key = 0f67caceedf8cce39a7223d32ae1b6badae2c2ab01bf75f543dbb8a408514c4b2cd81801f9eac1aa52257c7830f120b1536380b23161f734330744ce204a98bbd9dbeede484e9b03937c26689526597c8edb98e6191b72c95fbc76468b8d48437e3af46bc36f8176c540caab3fc989a3f511b54fa2350e3d31c2f6162f +Msg = 3173a712ed715b321a849279be6ba237fc90dec0e48b0e1290e81cb86c2a10eed50f3e05e616be098e3f1da2e6125238c2e2f45a8753aa613c1ae250e304c6ff093a6b799cc34ca2fd4af81d5622076c2e8752593a27649576e12ba075ccf3e8f57b9635b77fec448e2e89b2b5a3a81d65066285a70e24f868c35f6ecb8981f2 +Mac = e913fccc25f84a1390ef0b0f86050fe9e61146c1b4ef0b4b60d187baa36b61458bbda925b96e99cf8a4330291690417fe194cb9bc2b6232d43e046d13f038ed3 + +Count = 138 +Klen = 125 +Tlen = 64 +Key = 5c8589b3845970145e12b34713455eb6b5ceb132242024e42fd9a886fc9a30d3aa15703b3467e4dc99a915ae3ac118fd837e571dcde5945983c52a2c849296b4c96f3763488d52f818b459add51f6db2468d21db3d958196bf3a531f65bf9cf702bd66928672c14f235c08aeae0665be472397d43cd9f3822b5fa9c767 +Msg = 7f2544a478961dd012ac705e12e74587e2df6b2ee1406a0bfe13b908853f31eb384fc236a275654ba8cf51d461ea726228851754ef97ebfbd69326fcfcea04f594d177633c4618c38b4d64f7e98025eca4c62e7a40634b8b0e317880002c51d0bb34caf2ee0f207ee2ae108f53b1466b7f2d18667cac7403ce75175d390e00c5 +Mac = be73d57ab3a7c5bb305451922fa9b11d0ae938bec886fac5645a8b72de93770d96465291da2bdd5d11692f2cbfae69adb36ae714f1e5cf43b9d2841ddeba4ca6 + +Count = 139 +Klen = 125 +Tlen = 64 +Key = 7198b12a22014154578f5236b5a0d4cbe29aab3bf289bea2220a4a13c9677ddd8b03400cd0f954337400a069c192c9929a4d04e0f89928999b8b081af909ff1c7b2fcc36e8f2a0a32103764610f6a3ebdba4aed05dce6164d603204ee1c37ab1a7e4feae5335502bc6627cd38b17895e0d6852130771918b3d393db76a +Msg = 9b2e0306e73662c94377e5a99fa9b63f034ba91c8b95645eb0afc381c8207b77d089fdfa6a939d212226f331f5dc81b614b597d3e50c74d74bc9ae1027d9d4e41fdb511d9e1c93851bc66db39f54ba248149448e7422e470c589eaeeddcbbedc0d8cc8198bba8e1eb7bf1cd6a3fba9b1d37177f441c0fb53a4563ec1f2e08387 +Mac = 165e1cc47a7433270f1673e1cee581001708195a3471c9ec71333ce87299e72abc5dd490d43676d10c1375125d4e7fc673adb15342ddb7e72eb24ff36f54f82c + +Count = 140 +Klen = 125 +Tlen = 64 +Key = b5ffe36117589646ac097327e4147dc9fb13f7346fd97a6fb756448b32bbd3e25edfb3a14ae194844e109fe1f9070ae84b1cea2924fc4957fd8f794bd622a74b6fc4b38dbbf040f7926d0729a67370bdb80f63cd0cc85bb61a83bd1c86a4692f52768e2c53cdc226e1ea5206d39ed6d1abb309290d87d81776fab9072a +Msg = 1e6b0799e857a1efb3cb0aaadf74c78c31d5e1c72547dd1d863eed463bcf6892646f78cfa6fe136dc2042ce06d3a2a465c4c994a9edd1f482ecbb2b2c9b509b2fdbb501083852057ce87ae33e483431e6d4fec3b09d87282e7678c1e9423541310d8f82427f6b2f4feddfa6bed57fa5b8c6642641141bd15d999e353442031ff +Mac = 5702e9898e96cf220c6778cc1d07469f13ef0c2ec0e335ddd1791ff265ce865d200e4e6238b52eaa9be880adfc9076202625bf83bc07d861401a17d4a51d84a8 + +Count = 141 +Klen = 125 +Tlen = 64 +Key = b8100034c20a0b6e423c9f6c541fe9fca08fde8ce7177191db6f0929344332fe0036926e3a2720ea9fb3909cbdfb114d4da73b85c22b43f42248721015d6d5003cc235b9c35349673ab12b0ea0a70971c1a81d33c310df3cfbad795e057e7b3813bad05b8514f1acba3e580a26ac3830a59a6bdc0f50ab310da506592b +Msg = 29aaac0418f6bb3890902888219720b59878f226d06c7e8bcb42e9c0015e96f4f802520a15cccf3fb280540e7108b251cfb97aa8fcd86d1eea5d340aa3f65234e14f5639d89155315729978e0fca914732b513374138c3c01f74cab36964cd740a1b1f59094d3554a6115ad2a6e5a3e2ebf3269a479367b692101383faaff1fc +Mac = 9c87ca3b8ee3849224833b477333d4fb1bea3d8167fda445dc677d0d70b9ba85d0c4fd79909703481fbfe99caba7299da8c514a7a0799d59ab6f9e3f1f63a372 + +Count = 142 +Klen = 125 +Tlen = 64 +Key = d62dd5837abfe25749b0371803cc47ff4b386e840b4c7ad115a06a76066a765e70074f0238d7a7dc3c4ef41f394871a5ed9d662978f6aab608df665fb51d1b31aa41e766867d04db02b791c5d3dc959fd27741675a827509f17b861c2bbb3fcccc0425172d59ff3de1129671972fbad542ed85a57897e4b2189f521330 +Msg = ed3dc5fa63bedb28c12a423320ca6dce3afe8f72712ebbf61304495fdcd87bf9bc6c61a7dbdaf977dbca9b795de894d2c696120c43dd40b00aaab117e337027de7c7bb57889677e6d210450df1414d60f28db77dcea1c89fa4a94e7046c33f1ff7b49db373db9c9f30630796e4bce0a0474b476e1a609cea6869e8130c667908 +Mac = 1e5b3b965cf268d5f9529d0a256e6512b41bf2726d762e9447e40af239cf3673fd91257edc6739cfcf9e6893bd9955e4166e4fe2eff2265c1534abaf5b11544d + +Count = 143 +Klen = 125 +Tlen = 64 +Key = ad9e1d5774ee7e882b2dd772c7867eaadc56299b7583f67b430fae7efbed4a49f913b6a929d0d6852760c711a5be67450eb9178e684abfc37f25135a408e15dc636edb964da6939234a3c4c58432d78a8196d54f2ed9728e6e5f4b006ac16c0d32d81586a717be96981e58f62b8dd6617f16ec488fd716c65ae6ddd641 +Msg = e76411d3a1a72ffae3f9363389548084510d61fae1c251400c8e4d70517e7a29a4490ce2723b667edf738220524e94403323eafff33117b74dd550d7cc0116ee8ee9160547ff4d3288226f6a42128a978628e6ea8e4431730106d8ef7341b8e12bacf6e42adb2b3f696ec5ba6189aab0d0841e66bbe3e69baf88ad604d27a82a +Mac = 313a41518da2a8194451b01a4365b1d99d9c46498c24160b51a4b494f669dd2d0bf0922dbfecc703255f7ab74fff2d7bee9ff2a4823d26874f7532594b96847d + +Count = 144 +Klen = 125 +Tlen = 64 +Key = 054221b2a3507d491e5f0da4292931f63d105152316217100adbdb72146b5f88323abd5072ea9d22e41cab4bad3549f9576280576bd93df84262ba7918163a626267f94e6161634cf8308484bbe1c01e486dc45fdaf3bc151b45c6363aa6a7c43ed2bef39a3f368e01a37f977bb6fe2eb93903b3a537fc2f3e8be9f0a3 +Msg = 56958d7871c6b901f42910b8d7a17c3172fd25454b77e5b52d81fd0f7ac206d6c15b2add936e93f493e124c6cd5f670249a0c7b9dfeb00084cd9d3f6865bfe9f4dfe6b93036ea879bd3997f89ad667d754e6c26214b948108b143d643e327e112108ba6168ceded79abad114e70f62f7bb567f0893eba71710bca120494e6f72 +Mac = 6d3c6a9a076d3a3506d7beed3845521f50b2df2c5f3bce0707d66e20bcf09445ff13e0e445190e7f2c43fc73ae2bf68858a721a67feb8083dfaf498c8b86e192 + +Count = 145 +Klen = 125 +Tlen = 64 +Key = 42d6852473735ecc21b107e3e0a5d3c5ad2cbccf7e2d9dc31d1ea26e35cafc88ad51d9db367093a82002274672c7ea0c3965777120acec72411e56343baf69eb85c975fa0293955cd5732a4276d287fd051fee1fdf16bcdd7042e0b848c0915d704741c9fe65ccb0e70bf620154c1462b9620921e3f274cd5091284282 +Msg = 2679ac7911bf024295d61b25aaa0ddba9328bbfe6ee3e5b10a36bbfcf8398857e5bb6daa27869bb295e3c5a79c61d61c8fd3df263f9853c0cc1f766ebaa9132147516d5bfc4a799383694adbb8e3cdc00257b672e40fba25cf83ffb63b1ed192f64596d4bb9604ad066d910927ad2b6f95bd2a2986d083a6bc6a3e1ca2202a71 +Mac = cbc45d2f971d684010caef1c2d6124f56be8dfdcea7050c417b0a26f6058f6401542f8cd4cc9f81a28f4a4eecdb8376d8fd5cb15ca6b2bcafe79e1e209f55c16 + +Count = 146 +Klen = 125 +Tlen = 64 +Key = 0748bc683d617a4e668f36907eee655e454d6c19e43f6309d3701952fa36582417686a335f73db6768aa81d446debaecf52ff5f3f72174b43df350734b2cbd2298768fd833affd7eac3ea5cc32a3d174f952f99cdfc289924ec1e3bb640aa8cd5119343e013e67fdfcf1ab5f8a65325c1a6080fbe4492a0bce83dd148c +Msg = 2b0b018d11c1ebeecc2a1b5bd17e3be5b87f577987ac3eb733b82b00643aa4d179a6a350cc7cf42537bfde8bd7a905a70f9d8f18d05d86cf187d7d21b918771a5cc10415c5bcad89596f9226dd13522180af2bcc1c476369b950e640536830efdd446d0285eadfc33a2081536b24eafa129d73bcf2d29c2d1c1aac86b89398f7 +Mac = ee313f4f6c8ad4764f81873d4baa3e9f9b7f6481904a01fb1c827eff0314c1305cdfb0595a4cb8a6f979d9b7ab337e38eabe823742b89c2a1ce88c5260896ac7 + +Count = 147 +Klen = 125 +Tlen = 64 +Key = ad8db0f165d0ed6e9495e6e53ea1e0dee4437cc156db2e83c999f084298738b8b1ca2706b82503edcebee76d0725b92597925db99f6e2876471598390ddb428c5d4d0b1361b99b271af00fc0b04aee9806eb5f8d924599476cde9a1ca4531c30d99ec5e107949e62a1b1c6a5e018687f5ad6ea07d667673f5f7b60f697 +Msg = b6d8212d828dfaf27a03b79f0cc73ecd76ebeeb521058c4f317a80bb5afd41dff5520e525358df7851469bef2c358b2a97df0f5c0ba68f985fd8b5369831d97802a1bd6e80507b1620e0bbc8f2f229d11beb275f25f8be9d994fdb1ed0b8b87f064c9848b07db7140f5781f20606020a29979e84160302a508695a3ba99bc43c +Mac = 9210b074bb645c3a36ce46f9921de1d6cd8c9f37829c251d1d999c193dc30467d44c830084914cf19f4ba761a0e774c103f092b51ea25beb1b8277e99fde26a3 + +Count = 148 +Klen = 125 +Tlen = 64 +Key = 484babc2861503d442448c3c43d7569a380eadd9eed2eeb4c651997867e9a80bb0471f2df0d0e5fe5a3fd2c0b39009df4e1e882e3a08fd74bad8db27f567ae77effbac8fb8b38c17e4259bfd3a450c75b1898f3e984a2627146e34d3cf44d7b9efaf786e4587a127c73c0e7a41bc06644797ec906e6111d6bc59cc035c +Msg = b04bb381f91b8b64478391d6ab6ae306e796020418bf917899e85a9423ef924739625eb4c39496e2f9f0c8b5828e801ddd04c68d017fe9af40127b56714d9db44e127dcd1ba41c2b890155d3d9721b79446002f09b6900e42bb375cbe3806a19b90316b34973a7a7bf5d3f1af83e3c82e451bc152fa66080207451ddc1b081df +Mac = 0d73f53c10c029069a2d1d5733bc6be8a1e94de821573daa290fbee3f897f44297cfbd515cc5ddb0df7bf44ef58c446ec085c32c8d6ef779a5518e63328de957 + +Count = 149 +Klen = 125 +Tlen = 64 +Key = c4e631adcca6a4735c905c369c7cd44d132200b362f29a0a3240b7e06ba49d32a6a1d82ee6848b3d828f05416657941b7c6b9e716436edae6b274b4abb0f4f4bcfca760c2a21753d49efce2bd683a2411e46c6cfc59d190bb811145664aea2c026a832cd02450b7a97f6e07b52c7a5c7e3faa156edefc3290248398cce +Msg = e8ab6a06dbcd52a245152d3851ceac0551d5c3780da0a44f5a7fedfeef222050755c5550dd262b6af6e704ce3ff37215fa51ec2781c1c65cddfd60e195409d5ec40596d56e1190ce14b32cb1864bde73f909a07459f7e8a8e13ad7f6e895b3ddfe2e975d37956915c7020da9cfded866778548293d4bf27c8dbdbb0391294b17 +Mac = 8d9725605aea94c3ef125b307f7acd5a906d10b4908fcd21f678937cc4605b0800af50480ef6ff1439cca60cd1986f04a1ddea0abed6c8dcb9b485a923288c03 + +Count = 150 +Klen = 128 +Tlen = 32 +Key = 39cade3895b07abb4c100d2ac97586069efd1cfbd35c41097e23d1e194439092ffccd364f1fb7d0477742de251ccb6d8014ad00c22ef0d17fbb30e675412f6e188c71fcbdcd80cea0fd29fe733568cf8bbd40ebcd497d966f9024f1dc119f6a3fc432a35ff4d0fb33cb3ca01161bf1adf3233fd2925c8d3c9f96fdcc845f791e +Msg = ffb6b2071ade0ebbecdfe6dcc8ccd52faebb66a1281b1c397248b64cdd5db0f0754a0db2e226548c8cc6d911038e3deb9d87388761b2960f239c8099f133fd9eaed8b9adfdb5046061511d90a261b1c572e29ff05064fe5dada961e34d6e595ef1893c5f33342521b1a93cbf6def38a574f32244beda5b0b5696e092bab7cd18 +Mac = d4080ab37e7598c78fb4c5e43e95483078c1e15e2b015edb30a5dfe3c739e5a9 + +Count = 151 +Klen = 128 +Tlen = 32 +Key = 12dd35387a7d0ccbb91f4fc9afb087a3d849b46bd2aaefe719e44ee4165508cc58d9d97b213fa84f24fa687e8d193cad427adebe683a41e92a6f750eb51acc4987573bc8ead702d9bb908f4770b3a0e75adfa96e26947585aaea0f20df83e30b29be21c5df2d6292074a8ecc6165fd7aa8e1dc2414a0d3e523bce4c199789739 +Msg = fd64d1d06d7b92b77e33e39997ecf3fcf674a5453d7d36ce2d4e2138b1b83f031e4c335bb9cb05357ade0d9b0f07134424d8b468e26307d2b5f1813753f716c6fa45a100f88186ca71d496c15de333cdd001b4f97ea20b827e13a42d4e6991de18b8e56733855d9eed7d46b288679abf82576d9f1a2487040f1d53c3abf8f873 +Mac = 30871176e17a7e99a6fe06ed5d679f1f07049ad445ea9122f736e4f67151aa6a + +Count = 152 +Klen = 128 +Tlen = 32 +Key = ebfd4b4363dd0f062c8c269929b0a9815f8ae7a3a9d9b44eacfb047c0e56b855e3f6b7f56877416ff42680122b6360eb754aa18aaf922b0920b4a14bae50388251cdcaf4c94126fe8c90ab5903d7159cf50b960244dd296ed7e123acd7f00afa1ecbabc7ec0067badc12cef617d46f9dc816ed92d0835684bacab128f1fcd6c5 +Msg = 4abf62e4cac5013498615dd3de6310c71aaa966bccfca56f7135bc20b5a4ffeae5b2421ba3c464e9dd63deb7009b9b9468a00b051cb87304b8548748aa803ac7a17ed57a43ae46601fb2bbc5e2ce70c4cd95c50b66c294de6e64c15f143e130c686d4289124b51a044941d86edc7375f30cfef0514e3b1057dab95eb5ba431c0 +Mac = 6d537fee2a5a8c97fae78299bb72e2b86793eb3a6937a2708378ca01d6c47e29 + +Count = 153 +Klen = 128 +Tlen = 32 +Key = 856c0e585b5d297fb90a0f44480854f8e15c36f2503480e258d5af62f8d552ceed8ab75678c2c35161b422d43c37a184eb32d7a864540b83b50552e0459cf8ee5cd2214ee576b06b7363680a83b0512201265eed0df74c3ffeaccd17a760e673da2c96692be2b874f6fe2a0ca4d92f79292012e8d1850dbf3db4682ea889e506 +Msg = 5f419909012f911c154b7be2774c44659831fc422d282dae29af6cbbe9f92dd8af93dc97524729b43441a35273708887642fdb1b3d25b88d1169e55702eaa973b20fe11efa9a50dcdfd237bcc1e125ddd67b1131d7c0a681f964deb21f0dd2464efcd12661f0af9efe475fa9c867c46fd65cc50c65c2a093c9e68052aa285158 +Mac = 613c4ee61a140bdf293e8c1136ebf7b350a6532ed0238bb21776828dc82fea0d + +Count = 154 +Klen = 128 +Tlen = 32 +Key = 00bd4db7da41ca61ba441aa9778eef4e608a1e9a2b5f3e9f2e5c72c1d299837444db32476db9cc2225fdfecba34debaf380b7ce03e79f75a4b21d48aaa74cc110bb132c5790886f88d0048fee1160ae9c8a6c9973c0f7def1813ef67887ccbc9bd05f638e577216e5a139f47193073837725aec70f69f8e6fff96c5f54faa927 +Msg = 913aa422a59507de05f89840e0a3262aa220a121c8cb87f6f392a0a53bfaeb7dc562d881988cb70fac5971bf44d4768e7e72f63c299954f2d65ed8283293a4c69301e989d0f25aa956f3e1b978d791ce07ffdde323d9077c50a7db8acd829c8f219e3f02f6cfd7f52a4c51f524b46132644ebce05e9588dc89f41093b3cebd20 +Mac = b0920234c63ae297b519fb548fe5e47e221a5cea67fddebc557f18575b869e51 + +Count = 155 +Klen = 128 +Tlen = 32 +Key = d282396db948b2e4f3057fb12ac64774cf4b9e00bc16cc0c17c2cf2c7996a3004f5ac0ab8169e5875208141888f6dd3ecc45e0ae53678ea2be8c2fd03f2c2999fedf7f84bb7598eab44342f3c9bbf6c1de405eea8138142ccc62ad5c8d69f6a0a5ba7ddeae935374e15d112a363c1964cce41e9d8caee7100aeb4fb8ab78917b +Msg = 2fb3b04e1f5e7fade5abfb52efe19edd2ebc80181a657b85f7a18d3957497fede1fac453500da4a6bfca9a8523d8fa0119f8d6f5e2f42396abd1184a124cd7bee7854f322ff561186fa541de27a220089cac0881da2e0733fa738fd5a1161d04c9ba1996c4fcfd2b7da6ba04022558193f3edc650cfc6e856bedbb810a8e99ea +Mac = 48915cfa32566c5047433c0a69ddf522bddc205dcf336fb2863a2292fe0f9c00 + +Count = 156 +Klen = 128 +Tlen = 32 +Key = 671367d3011146ebe23d97b3944466dd97fc408c0e478d5cb93921a3237d0df61df4bbef6aa03a2ebcc1d69ee03decf93545fc8f6236004348bdfcd6363fd7685c78693b8362d5bbfb5819bbd47be3025155a70699bceef7b0f9f1ffa62a66c90ee59a40b21ec099854b8893d9c5f4fdd27268791ba10081d73525a7db066321 +Msg = dcf7145eca1b1c32d1be48a7c23d179622d65cd480b0345a051c3ba34d1b00567520b62576172cf5b1a5ff3fcbb20eb6ba252e2a20ee1facd84abff3cf427efe167512fb35186c68c13bea78314eceb8ede3eff2a8b6ae51f0ea2cc70395baace57f91a8af27c4d22a0772199c1940e4e29a06f5bf0ec9937484eae8911b9ca8 +Mac = 46a100f52104b12053e29d99b0a2f504d48e37641d590556b8308c4872f96576 + +Count = 157 +Klen = 128 +Tlen = 32 +Key = 10c08a87af4ee0cd4d67f79fd3231b690deba0840081d15b7e4029cdf7a6c6d3920f1a637cc3e49480335e02d980b874443dc6bc5976f6df1af18476cdb3f15407c6b1690a3a24e6506ac7a26881acbd013c278345f1cb9368d0944080696637976eb662feba870de5939948292cdd8c6d6e2ba16cf837be8d65c2f3b9cd0dc4 +Msg = 485a200ef7d07627986786ae1bdc734e4a61ed0109da9ee0dc4bc43aab911fe3c2510dce1c2ff4dee140e0fa2dc16d601309e83be2bcb177a642e3d4f2773739dda4264c4baf4e3f6e8e17ec8c0196250281b2458973850bb8a205a9caece317a23cb3ad0cb84ef1463b74aebf05b6461eb193488668e245185570e0ba58e925 +Mac = ce00915bb0874fc3affc15c66d336116edda115e2b8667aa7bdc7a4125888854 + +Count = 158 +Klen = 128 +Tlen = 32 +Key = 41ecd9f2f9206805bd1ed2de2f0c74f53a411974ad58c3eb2883a9453c227cfbce95ee87bc4e751cc42a4c94a101bcaa767c996970260fe4a7c69f2846ed646feccb9b96524662d12d4ec09e566ae6f72897b4cc29537fb0edf512d3383ff2306336e7070131b78ec23135e497707a46163d738521069cb7c2b70a2d5a43afa6 +Msg = b20315814413cddce84df335c154697174489fd08d9b15681e201bd2a865dc233f439a1deab33ba749e3057b7a8aa61f3c78771655710157323bc1fecef62842d5ace6a708296874e30d9f687d1f04a9b1e4d9fd7b71b13ca47d3206a2ba1ab1ba668085671c5d2cfff14a6494bc8bf718b54dedc5422c00bc0df850ed5ab958 +Mac = 38c958f3f6f43943c8c1843814cfdf6b58ac8e4b55b8e4f348c58271058aa3c5 + +Count = 159 +Klen = 128 +Tlen = 32 +Key = d465051d1fa80fc5114ee42d64fe23c8c77325de78c72fe915f2ec40b08e1af221dd83f5a00c2f8093b9d8b5a4b49e831702fccb5a28fbc1dea6a59626c1bd541e85ad09ad0bc0278df8912b5b46c47dea47f397dde6eb6a753119fda7143f5872676ba06f2c2a83aa11f9d7b03dfc7de948f38c288b69ab819b2ebf5b1008c7 +Msg = 600e55b75bc37ea69641bc0184b9ce9e76ca27311cf49566484f202df67d35558add045d580126876963832d7c5373584c34238f11e83bed4989bd77b85a30acaefdff5d88e61cbe790fe8be8bed5794e0a44f9a3e77525fcb825df714ab109654d60e5ef458a7744eaeb559b670c378bb8075fbaa8724e354a2c85811581b3d +Mac = 2e2b59d7843be5a3e1d815fb12e806864b4ce9513f51b96ed2423fa3a1004815 + +Count = 160 +Klen = 128 +Tlen = 32 +Key = 6ad551d1e6989f5f14cb11316d9187b186bfda6891487a1427f955fb4566fb80942400f4ed38a2ae1cd0ac5ee4319b9e44f1fecaf9662312445eefcded100e1088534d80f70e436430f037ff41613e1c91b8a4ea68ae8d0ab112dce7ffbf5446cfccfd1e0d02caa9d99378bb8a08b953f37c926fe6080225f77ee4f0825a1648 +Msg = 0e2bf89372b47fd8504f4ecf7fc90a5ae6bcfa6f346c601bd1ef0ac7149124bbb67650e08681f9ca5f75e3f5575a074f3a239ff7378d7d45d84aa00a385f091970cbcb065269622d5a1745f6e118bf5894b7fa9c252d5d6440c517ebc13efc8e2471918c3c34620a287d9c5a84cbd77cdcc134e56614a880f0a897f317f6a523 +Mac = 3966ea95938b8bb1a2dcefa33315bf9bd3de12370818ec4703fdbbf52bfc6b6f + +Count = 161 +Klen = 128 +Tlen = 32 +Key = d136f9cc2ee6d4be1349b91ff6c9fd47e31329e9cf1af03a2a5f6456b37169df90af69e79e55491006b79cf111c717bc3ddd451e90b87c672cc010eb248dc6a88ead8c29d9a267aa612bac7c41c573ab687049dff0b62580abea9e1dfeae5a0ff2b7ca5988d514d34d2d51882fc9f95c8f549bf2971ed2ccce6774b4e9d90c5b +Msg = 6bca8be181694dfc4fe2721b8aace6891f8baa52bd077b56931dae9d5b345fea9753ca931a90f98fcbcca0d1a69d45d4038ca3781b81510cc87b9fac8c84c1cdd5e52f167f964b729bf844636fc63b99bd49a5c349ccf1a595506a6aef815e3cade88013b8618bca47d02878ed1012fdd62c78db4ed2a3488204d8818b118060 +Mac = 45cc9db51d4a60e98c24451ee30531fc41fc47b118d3bdb8750659d8ec05344d + +Count = 162 +Klen = 128 +Tlen = 32 +Key = 475678927334f6104ced3f18cfda5b6063130d6e0ed8ab12e92f2c34d1cf83cf603d2c3e1b3504b7ed4b5d15d5d252dadbfd5874484416bf160977cca67cfde1b1bc58c0813f372c61735eaa52a5f885ff232f14f39dfb3f0ad137402568faa7221a24a10c1937798ead695fae1bf769b8ccbbd777ab019babcf9719b85a232b +Msg = 3a606b4770adf9778a9eac15cfaf182eabec2ec3a412c91490f1831f0514cd6312a43fe92c8a2c856bd47a5af75ab09cbda1519a66ff69fb890065471f0927aa383b5af5ed9a03e6966f59a93debd79e520c8f5d9fc5c1f87f59ac804b08a4ca16ed65729a27a7217137f30c89a9b4bdd2f7911639aafa93dac201cf71586c4a +Mac = 41d9552bd694baaf36aac029d04fd84501d7231f60f28a1e7dda9f418928fc28 + +Count = 163 +Klen = 128 +Tlen = 32 +Key = 9904994b1973c4a0d161f84d2f5729c5ecf9fa6de18b2f491cb465d43382002fd8af667eae236b905bb90bbedf465f1524d8cab7d53b747e74c2f9e3a743621ed364548fec15875d8c5e7a5d425b65352c8570c1c83222b507601c84a3ae0781b3abcb447d5301508bd7acf3019d236d2d88525460792236fc163681cfcad8a0 +Msg = 8ca55de0457a2202c584a0f2fd05e31609b6900f585b29ec0e9a8d9da60dbeaadc96e725caf39edd519266d4baa678f39d7ac3fd020531c2c7c02c9542b461ff26d7c3b5ab98d3c8e9b91f1c855d091b9062caaaacf0b75c7152c2e60f0543d4340ff97a30924b2c57a1d4b2a6521ff6aa15af009e444324d4fb587a5629ee8f +Mac = 07ded632065d67a08e9c046786308095dc1002f748ca05e52e25a309d12bb546 + +Count = 164 +Klen = 128 +Tlen = 32 +Key = 0a7e6849757612d578b9a9304303099d9f4d5285dcf582bf0a194a0e6c431aeb294c7f85457aae07d0ec61195d38e1a9b65264ebceb09a9ef7ab8392552983679379b897d47e8bb7ed1085f9d19f65f64c196faaf50e06c05e137d108d642b67b0cdbd860ccad06d37edc0d98780ba0bca6c19cb3759efada517e193fb3c3973 +Msg = 8cb6c466cca91344175d7cbadecd1d443cf80c6b2c3f3344fa0e5e39f7be920b71baa118e2e1fbda682cc7b1759132e2c82707df9c8a81c91f815d3325de32291ea60570457218101b150410147f078190e29fbe0c1358f19a32e2d98e8d66cb7bc21af75e2414ed18605c60226144297c70fc8ee6a061c5536916b49b93d6fb +Mac = e5ae5b5c9d5978cb74a8eaad15329f68d86b55fda33c202f21d3df9de6b17157 + +Count = 165 +Klen = 128 +Tlen = 40 +Key = d86f48541803cd411fc34aceabc78c660c6c8306d8429944df25429161a9d4bb7fbc9ab6f086239bf594e0f18f36ef2cef2531732e69a2a63e7aeaa021a62fb958b22e8f9fc48a07d781638e44722ba5f8acb59c8fb08f9d1d9092ed6553b76f4c9b2d6a8d85a88badd1fb2e3243e9d91048380964dd083264ad6301967915e4 +Msg = 3c283badcbc4cc09c100ff016d7e3c652fb2786a379614fc8f9f01555cf029cf61cf0af6c455a4e2156996c48cef84be923cbbf883cd18f0b3392611af658688c5f79453c60d479a0a2e5943b581a8c1393cdd2c1c604b97fca41a9ed0aea43e70891fea58547ddaa83790a7709c72152b9b242f89b5759a72c6252347354b9a +Mac = c01a4e9e331774e549a56d23ce4959249d6a0db06d8c42a0415a99697c96c23798f8c1d978fdceaa + +Count = 166 +Klen = 128 +Tlen = 40 +Key = 0417b7fdaf3b2080271415685fd8bfc47c2c057137f20c8e8362fe31705c0b5850fcae2318703240090674a68f89ea8669cee47e0a8a12113f66475413567ce9f026183106566fbef027880795f623604dc9fa2946284845252e88cef0df7f062bbc7c914195dfe2269fd8f43bc6713a7244cfd8b273b4137ddf4906d0a01b97 +Msg = bdb0cf79966248a68d3fa4f9a122e4c1f1784e7c164762f7b67011b756312a9870ed15b4c630c386f5eee5504d0b5cb9e020f1bbd97d47bc106a0dfbdbb3782e2663f16ac6cf0b420ad6b7339368bb40664560d940076b012a634fb04caca1760698cc623d470622f381836b1b40e89cab6e029ef2efb80e2ce23e9e54248cb8 +Mac = 4f8823e76cf5777c21dc05ebe40717fe559fbf9cfa8274cc34f742962f6583c7a92b268e5f6d76f3 + +Count = 167 +Klen = 128 +Tlen = 40 +Key = 34d7efcf2202c778d9087283d113be98e6181b78a30dfdd5c0568267e980553cc231d250275f6b5db8c14af4958337cd663ebd5c9f2788a402871250656b7f00b59cc5e13bd10f801e2464e029c383cacfe812646c0bf805ce560848f459df5f15ff0faae5c07d881319076e16396a3629fe63b9941f159f2eabab7620b23e02 +Msg = 4d5e7ddd7a9bba85a00812e19c23d888f9589b5f58d1a80c158fd0ad27ba6cc948359e865776d91dfa95a38c87a2998b253cb4c02e5fcc36d87e5a0c15d2826ab7f151b9d8a2431479f008f9697d87456919245f8d933eb3e5cffc625d194a37e2b91edec6c800506642c9920a5cab9f0c1771a33d15086984ab3f17c839cb19 +Mac = 829ef13ab3c509c4e0c833bb14d174f166579a19ed7618f32c8be69a19797bd0da86b6234d8f1ea5 + +Count = 168 +Klen = 128 +Tlen = 40 +Key = e32c7692015f78ffa00e00e4bd98082144800f0bcc5b6c6d81ede1cd618f73f0acd379a0956bf4ac3e471e31e3fe4618566fdae0aba8c69d3407fc41b09e541bbfdc979d996ad662005401707369b5baa5e454e92d4c5b5b7f98f06c1b97bbf5048ff7137425c92ace7cd029d4a1fd0f1a27a5aeba0ed4ae4aeae5d60b404f87 +Msg = 01a6f9ee2e42008898a245cdcf2a696729e324c3adce420b2f78ec55bdcf291a3a34a5e949d1b05c6d2d894c6efddd41fe3e8b2c9c80aa59b985cd9f190a85da7de5289b7f50d11dbd85a87b398b6421004f0e800af6070762724c4e8653f99411e00c6b97676cb2d1d12ac4fa7906ef783f3528bfd861fc7368f2cacc528c30 +Mac = 203659322758826f2ac7e2dff082635017cecfc1035f254aab25d3a3f05c22a1eea02231dfb0ea64 + +Count = 169 +Klen = 128 +Tlen = 40 +Key = 668b5017737b7be1739ee8580d110cb1f3cdd2ba0a33e010cbe71b92e9e26d1533c3c65abd66603d3ab8482eadca1ae541240b52745b2dd37be6efaae22de3ae74e3c5405a96b8818784d2c353b1db3d65365202d7dcb13495e9f374063a529eef9255b394320a1720aa90fd46eed91f29acaeb279ddf499df9b2dd99c32424d +Msg = 7ce7c4013b6c2e1644b855c027ace60996becc436cf1509cef0585f252eae3e87f7b32391369aa4ca97558095be3c3ec862bd057cef1e32d6237479c81d2d03a3e1abe5480e6e5824cb80b7f4734923876d7572349e5d9d2d8a39ec86cc7d28b412d32fb8acb28e1b6e737cbf2879a18ef2a284fe5b57bb5d8b0511e1ab23203 +Mac = 3eb6f1996b9bb3cd45e97adbe15c7c53b882aef08a0776c6cb0a3ec2676ed4d36ae81ddc1cec1d04 + +Count = 170 +Klen = 128 +Tlen = 40 +Key = 2e78d82d417e5169dcfd1c69f5a972961f57248e51b37f77e9317294f046f315a0d79e3423f29f7d9ebcd36d6eaa2a3fb2f4500309478cf09dbbe8fb600492a995ec822193015d85c58a9982f6c0e326cb3bbdf291ab6c3139c81188a18c16cd169fcb1c161351285a51b8d0145364f37514b5847245e7e1c84236603d44462b +Msg = 706d477b089a26e9d90f4f1991527de17724c128a9b4ddb4a812ee3d17e64fc6c062b92dd875af00844219929cd02f4eae03984c46cbd3226c9bd7fd6f1df6f0e124078be3e2c4b0a35b71a22219bf5f3b21ef30e1273a7ea8fe71e78652e191db9979beb0472fa13c419f71ad95f5bb25680efc0230da6f62230524e6eed652 +Mac = 9c1df6b8ca24cff2b505fed7efd8aa1a027893e286d8cc4d598478c2e9924ddcf96a0737e3053954 + +Count = 171 +Klen = 128 +Tlen = 40 +Key = 4e9d424c31a7441f6d16d41caafc861ab8fe3c002d66ec7d5073a3f936f3cacb2b14a9ac5478296b9287dee3a809442ba1f4490c6c820cb8ca87e5b86a02a52751f21f1e806be76fd1e8599623e3ddecb6a36a1ed85649dec25f1cd8bdf11ee889ddac8afea80592f4e14e1d61b1d9c7c1b4a61ebb072a5701a3504078e9be76 +Msg = 9a6fc18a62f8c9cbd62fa8e0b960c9a1514453a2b4309507428da79973884e19d30a21d44aebea77a1634f2542c1b2c73f5f55a396d5c231b46d6a2937d78ce1f81e58d649db55887ba9008ca4d8b6dc9e66d371532a1c1438535a711811486d1392afb9e630d0a76de9023d660f9c897740153373996a59d927c0969d9e4b64 +Mac = 32d1db1f537abef5c170b9d204eea2da1bed58c990f4b720cbf3212474222a99c1c518ddb8db1c82 + +Count = 172 +Klen = 128 +Tlen = 40 +Key = 860880cface9225afc6c889d13c3e983834ef984316c671dfb92aa7d9e9afd82d75da8e3c98382af9f9ab4f67266bfc56d78c1582f02f48c70ea7793e81d51eb6c26b3915bff7d723827042298f412d03f2b2f7a86ce1f5d0035acb05c60a6918d8c274029041b8b0f3a00894d16eb8b418ecc50fe77f278f09bd23bc40b045b +Msg = 142875dfe08d2b5013a60a7989afec181af08c506f40f54c13c83a25cd0968062e21b98e66490a755ca38f73fd33c65dd32aa992da6b28959048d6fb4c8ce388d0bf4a9521a54bb497081c9730b7dc2e29cfc810d039b11c9474ae605e950e3a248c90bcbba8d755ec5e18aecb4616d344665093f7b3782946d5281cab2bd163 +Mac = d5d40a0d99b0f1e52a9836896b27ec719ad1eda82ed80f6d2300d885b9b9813fef778c04714f1fc9 + +Count = 173 +Klen = 128 +Tlen = 40 +Key = a31bc73a6a73000db291ff45b0ed2d36b2a7f91f4b1c1f60b0b82ae7620b37ec0d1efddeb0070a9dffbb4fe90624df1b0e73f412c4b8337198af310864dd358f4edc409aeff44ac9b5ebcf3f851d8a56a5cf8191dac041d3cd016bceb3076fbd2dff98566d6149fa9bc886307701b5513f61a685d35cd2ed1754e02299af6edf +Msg = f776c8cf705d589211ff2260640b2ef1d492548c1db151ca006f1b9c3be8728fb8acb84f0562026a04b16f57e460b9b74fbb09dae5391085ea5d53f33bdac61987fa9d2fbb405f6bbe4d3c105f00a0a78ce1088cc4c015adce99de8facbb8b92cb2920757c41961ca89b3091be340c4af1ccf9aaa18c88c916ec667874d4e880 +Mac = 517a096bca0ab90ec251347661ce9bf7a2d001520bec592439bc53e32cce7d36ecb2cd4fa9ccb416 + +Count = 174 +Klen = 128 +Tlen = 40 +Key = 02257ce15f10f124f867c93ff6ba295a36836eeaabfeb725fd3aa3b976705cbd1f95d4e8262b4e01835c2196db49b8f1a5a0de488b6c3834133213647e396193f129fdb7d2d8377c75608cf0f875b5806bf5e42334c14ad5b2ccdc47217157d5be0a81b82bbeb27d149a94b513e327efd1ab08e36fa3f2f0243085c927c1466b +Msg = 25117774deaf7c068cbd4ce82a595a584ecc9dfd541ad81eb9d71f12c53b97f76d797da7774d6ae8dfd4d5e37aa1d9d8d90d380f70cea112f7cc2e19113031c62cbd3012a8632e883b112cb194ccf0cf3efe05cdc8100377233a11e74b9aa73f2984999eb91a514c681c5b38c00128a546460b20a30688b503cbce62bba482cc +Mac = 942bd05f304ba8681912892f43e59f9d0ef11b03fea2e97135a9c495e945966b02022f2409c4a926 + +Count = 175 +Klen = 128 +Tlen = 40 +Key = 82d0e0b45e5f0ce5ee8c33a745eb29ca085ed8e581dbee3cef70d3e72084de31425fc83ff7ed61f2a7be810d1a52429b46946c8b65a4319e4bd91b83f707424068fdc2d3b2526c195062bcf0bc930b983ddd066000895f7e6b38c33eae280b5f9bb3b6b9b7189724917ecb965236ee8b96418eaa7a12e0a5f694b2616e6fa157 +Msg = c21f5b610ef4f0a966a3ff66ae8e312e741d23bfd30e66ee970dcbe1a185dd7e8eb5ae239306d798ab9cba42f52b0a99570c8edc689021038d94fef562553afb5b869274aba067cb647a07a7e0192e6161c9cdbbf46c09cf9b138745aacbe7c972ba8ebc1d6aa92ad9646efd3901a570d77d68c63f4d273b08b2ef3b448febd2 +Mac = e3e1930b791eb77a200ab551a591b972e31d1133856759f7a607fe358c46cb9174af099472e11d06 + +Count = 176 +Klen = 128 +Tlen = 40 +Key = b7e2a930f5ca534e8692c4dd752df57f2e6a4d93e1c51fac27837541e8fe0ca67c3d9f3a10c768e34cb9e5b73317d8fc4a609153fc656f303d5aa58d6e2e3ae08018544a5d73b51183cb8650f23853ed49ea58cc2c06fb42e8b199cd5a6985020d9c4ec6a27341c175ef2f107d38713a743228663850c9cb72adda677559f6f4 +Msg = 71695a2754c18a349be576a7d7afe04e70741a42ec376cbd6e1db62b7d21568407094cd8a6999c2c2106f48436ae8f41970559ad32d354d5b59d3a97526064fbc086eac782120c4d6b1ed1886287ed6763e7e869c6c37d6ac40641bd37ae857aa1c67c197094a140801353dae2a4c269dc000f9d3071af25a14211c5b47380a9 +Mac = 395dcdfb1daa4d0ae503cc0e218e6300fdbf85128cfb8f5d79c70c575887faa3237d88f30682aa5f + +Count = 177 +Klen = 128 +Tlen = 40 +Key = 1c96b62131fcd9f823fa9fa37263a31bbcad912c30973c34460eea28ad52f2d785558a73cf64da4d220855e09f2f48112787b3b5cb2b59548381132c236269798c7c63f41ff59d9a78519aae58965a01e2ae2f710b0cccb04c939f4799b361da97d5ebad0af94b678c9d171685e1017457eaac69d984bed0070b377ef88b0180 +Msg = 94090f38c01096160bbf1ff92e346380d8b4a3c05e93f443ae54db508612196de31fc823bbeaa701ee26b3e47b28f775ef91a4f2242e6432271cece37a30d0177c959cff25b720f5f6600bc03021bc1445f454598c1f10ad385cd62c8b360d6f47b6b252663fa8fb0ab75018b7e75a67c025db7cff309fbfc95bc0b421ee777f +Mac = 85052994aff398ecddc38e1da6eb3cd326462290f007ee3c77273337905a6e47bc6d6766acf7d1b9 + +Count = 178 +Klen = 128 +Tlen = 40 +Key = 9c18af3861895790a70a1baf5042161076364c785c6a3e36a449bca9c2c7fb04b045e74ee3b5baad7ffecee3c7a2af19d79e75dc95925165e521651d1c9bd960b8d92b814e69c60fc3ecd757bfbb5c2a5fd17de12ae5209d47d6b8d4ed4c5d091a9d22da88eda340dd9add1321d743cc76960e8f03acd469322f5cd61b23b186 +Msg = 305d9717bc532c39f7fc633b38a46b64386fe5a0c7403c80bdda35813445c791f4742ccf2f2438936f07eaaecc2241f3627350f602d89513282c87b22db36ecabeb877a48d7408e2463251bfc5b1249886ca06ac5d5286206742cd464015771e7672a11d3e0b432e66c5c1f78b19bc5d8cba2e4a3e78b6ad626430c3d4358996 +Mac = ade6d0de71a801126e8b9d665d4f47dfab6a6f9ac1ef8cb258cf03e94f2697aef912140a76ead496 + +Count = 179 +Klen = 128 +Tlen = 40 +Key = d9361e9afb0840ac9be5b17ff2b3133c5503fe2cb68ba2cd6dd6ad25393a6f56810b3b73e00e1192e1307b220778b57f113b10c47b8f98e14801f5edff8b8fbdf4c0f6b5c84a80de3396343901cee6535b08a41a48bd51ef747c90fc2fdfe4c8b8bf1508bca4d5b91a7fa36be99cf0e0bcd280d524fd142077ae46fbd020b4a0 +Msg = 0266358551e3b84d465f78b16753d81ec0aae7f088d4292e01169b74a024f1306ef12211aec626bdc092fec34581f6d084cf27250ddf3f489b8785fa3fae176abb1a76a82c83455cedec4eb8b733c6ab0de6d258d7584ac64df4bcd916d2b481b1883a3115439d9394166f7a0591d1182296f1712f68d00fdd0549f76db64fdd +Mac = 9b8b2d10a2faa0208ee3043d2a0ba3132bec4deecf8a5e201bde20ad9de823b2bce29d48e0aa83e6 + +Count = 180 +Klen = 128 +Tlen = 48 +Key = 3d8e7d7ec30c16b7472ee0078b04be96a98cbe06491ef0f8170779d17575e3be6c93b7f5e9f44e3e2635e4b266deeec3e58aad7d0f48040cf040877dec9ad4c9b09b260f6811272132f20642d340ca2eaa2fe65be28a0d7feb5347522aaa4595efeff153a82b4a6755ac6f3e3cf0f9dedec58e2729adb459ef87e2d7976cdd2b +Msg = 1d00e440026f7efd6d8864fba48aa697e6c91ce04e015f93fbea194a6e0c7ff033d51b78c4e9cfceaab9170ee5578ef58e89b495bb1cee4ca37acef6037f9562c089f603cdce1de84ff3f0eeffda9535d0bb34d0d376fec157276e2454fbceaa0a43fe49e5c77132a45d7804babac33ff48724fb5db897da5f19803b2a2933b0 +Mac = 3c270df99f8b2ab166fd29d5fb347c7ae5daef697fc20b408dd6f01b15c713f1c626442dbe5dafe3287f2e2c8651c332 + +Count = 181 +Klen = 128 +Tlen = 48 +Key = ed8fe523ddc1939262facd6d722b56bff66783d422e83756025311b6563ce4cda0ed68c47b632f312e9ada82810b8c9fd0729fcb5dd496cbeac1534b88d78b7daa8776037d1ccb0f7cf8ebc93f215cf193fd7ac5d05a692567b14ef5bbacbfc332e578a98bf14f75729d6a085177affc6a917c8a238198aaa0ac6a7b97c569e6 +Msg = c0ffbe82e2aac87bf2cbaf241643e00b34ac9941aa3f435f40f402c75aea8a2c730a3455c6e8511d4ee9bebff1abb950f9a1f28dc3fee5d7bbd5687c887e8038833b79fc6e1b36ed631fc5b00a9c36e50fe0aef1d318b7016272da4ca67e7098dadab5ff400e1ef317b5ed80c8de02d160b1f4f6425660e41e1281bd1db30152 +Mac = b94cd94b82f7cbc2a992b413499e941c0301ed8714c5e07b3badec2be179756f996e338025fb35dc729f96717c5ef8b3 + +Count = 182 +Klen = 128 +Tlen = 48 +Key = 732957d1867047f2904817b4f559649059870d38b2bce77ea2e8b27205464ccbc6e02589f655f3d81fdaa736d57f9fd88fb41d4ab50bf857fa3f9128ec7609b0c9c3b14795efc29469794fb10edb778acb0fdf867a52606ae128fc7a40a017e127d9e3528ac51df0172df76bc7f5556cb4a23b342a19868000a9dbaf294cde26 +Msg = aa609dba1271d02ed605b2f3824d3b75e6a3ec7eb1ce069f4282fbd2ba27225d56dbaefafcbae134135d7d1498a07cfd6ea900d5f6268d65e0d57603414a956ee5ed3ff9e64277ec7d6d622719f5fc08aec8088f507f4dc000e4ff49c6b17c65009b3900f98ffb1cbd3c4a732cd1225e4e08edf5e663ae784ab57fee71e53d0b +Mac = 21c616f2df44961b2e5ea64d706516f8283732986ec9b6a5f43e28f0344454f218eb29500aea12500e86d8f5c78fd962 + +Count = 183 +Klen = 128 +Tlen = 48 +Key = 107fcc04358c79cabaaf3467ba6c0907bff2f6ffd8e6a0b2eb6245b54d3ef231908ef6899c6b963d01f7020f8c9b8864199308eca7ada885b24dc85dbdb539572e83a9b15e7b62e3f18735ca63fcb005e41f98a066e893eff40624bd4522dca79168cfc2a34446843069b3e16718eab4c99f8d613b20c8b859933f1d0e0e45e6 +Msg = 8f330972e6324b383793647431e00d0bf151e929c6886590377ee43047be19f8f7d1b3ed0df9407914224b05a415c8cae3efb3e34cd1f3a7afda84377952d55336286f72549fd8112a44b74b392338aab13ab23d372e88eae53d4d0692742b2354228529448cdba981e2ee6d78722554621c305d0d06eb01e09185c61a8be111 +Mac = 3f94388f059a158574ca542ecd2586493fafe193e9e33f25502fbce92f7ca3ecf8df7ec2ce74aa96399d9300c5ae93cd + +Count = 184 +Klen = 128 +Tlen = 48 +Key = 08eacf6fd640cfa8bc15f77ca18978a65ddf182213802a4ac143bd4015eb148b83f25605948587f481cfb777007a79245e7397efceee044d01ab129af677e5b814f528fa769efe4086073c63cd62d5d30948967e80b613f49555e1c999fe053be37dad1523951ed4f345ee07af4a73fc87e57b98d2de3d87a5c99096a5885b5c +Msg = 88dcd82dc6e1cb894bc7fd88cff38ddb13b6dc6d227cf03ad6461b649f5ad7838038f53d5ad1f7186df4ba8b1c09585bf0014c25e08dd736d08ea3a357cda797c5ed4ae7659ecbecff13e091a1b59dab9f199889d92f4bcc3cbdb9798c0c554d60e21f516eaf10ae080bb8c1e760267228e408c294cb13a424baa50ec47ea94f +Mac = c62015a3f4f85cb142f2ba59daf9f1d3b49cc14c87a30a1583974002ad8235aaa15a96e7aada71a3f7f22eae6a4ad336 + +Count = 185 +Klen = 128 +Tlen = 48 +Key = 8fa70b480660c4b14a55e58c3e29953461b167be00572f82aabc13d6e5a2e51d1f08b001e79690fc5d3cc71de7170e092694294029d7bea1e05e6731d3e10618137d59ec7112ce32efea9822749b02abc42e03b7ae8013b088e93e43d81c7764544e2e920d9b255ce7a57f244c7e1a2321c81eadf91ad6b689a6bf965d19df09 +Msg = ac098b6812025ef3a8e024c21a2f88e40b95e6545908b0cfa33f10e30966ce49331675749584b16af1f9fcd31d82794f06e8200df5e21c9a118a71f6260ee2eda4a812a4ebd0e973c5b039f234d8a2576f33b3ff2739514a0e675dac9aec910106a6ab219b4cceb52ded2549e899c9a24d5ee55177761888a3be1a2def6aa32d +Mac = dffac17c47937c172b6c514b303cbd7a4003e98658c46538285f3e43f3bdaf370535633977f8118300bebf44e474d5a6 + +Count = 186 +Klen = 128 +Tlen = 48 +Key = ae88c3a96652d3764a00f8b2d0027adc8a709b77fb9311b3a9a7ba4973df8ca725aacb4d4a357e77423123fc94d6a276852880a3e979550b392f80e3e6c71932ed1a2732acdf13f9f3725d585fd48e04e3f26ef3a82a7609170b88f4345cde552d60412032597b45884b0e90d90226cdcf56cd31e1ae5ef56cc33c4405a7c357 +Msg = 230dd0f85a13fcef40420552de57426a687ebd6a5918e650c5ba880ceb79fbe40b659c1777537ac0ebe052fe21b2be52a101a948d756065a6793c111c534f66d00d46287def317752ef6736e5a6f522e3c9f839c323a79ab7569437ea615bfcfaa630a91b87b3ad4b08e50eaaf1768c8e06133ae9549a70b9645f59bb8a5bcd2 +Mac = 3d7a25ec84d04e21dde859fefbf185d63ca270acd9ad55a1fca184045dc2bb6e72c926c2ae3a84a35ce346cf02e7aebf + +Count = 187 +Klen = 128 +Tlen = 48 +Key = 132c680e41a727801bc50191466ed2018f0301e7c6e7fa50cf3ede29f6f4785f830174448eeccb35158e827a4c19946d34592dde6f3918b753887bdc3dfdc2552879d9af7e8d9e9f2d3c96e9fe02de80231565ef0eea59f78afbdf7a04c80798291bff17b79187088c56a4a70430998481bf13e04b03a45a9b1e72cbf25b316e +Msg = 0ca8cd24bc4a0f25a50f82c60c373279f2cfd0b53b3afa330f11bb5d812d56046e013f51a82d6bfe5451c9c5911f11195bb5bc15ae2953b2ee65ed3c8635f407d09e275e3572e5bc9521a83fe8d2d05926b2a2c9658c90c9419bba89819cb6ddf8268c32a83e05c72e27261a5a77f7a01d7089b8a88c36e2d25a2b2cba8924ee +Mac = 8447823ab1787fd753de41477da2a8e306dfef910e1476bcc88fde6716e9b724562c7d09c80712e3a49aac5b33f5a790 + +Count = 188 +Klen = 128 +Tlen = 48 +Key = c05e649d3fe1142330ca683ede042dd4a64ac41609e9d461ffc73c628da44c7e99a03471fefdbc35dc27362531f1b162ae227076c3309b37fd4b33ee919d4bb939d1762e3ed27c41d6d55168b19947fdcfed82e39474ac6c1ea5eb7ad61510e545f9121d2ae6ba11c9dc9f4f8583556cb1b4e2a6a43b71c80bdc4b4e849402ca +Msg = f1567c7dced30cf724c2a2463f98f32090492ec2ebb0d47df331ca72d29dad9a2d55650956b3fd73c4a5b1efc19b49fb63a4a6c0bdd39b9856e8fecedb2cfea5109db69b0c4b03eea60293602b293f3752ea9b897194cbb6f03d9836feabc395847598bb5765c771b2217021e30a7ddd446534a36db90ce0a877c032a6e0a372 +Mac = d056eacbba508214ba434d286aa0a1a56406a2e23d92d1eb9899b6896d4773dc255c58f4831a98e42adae1ccf8355d8e + +Count = 189 +Klen = 128 +Tlen = 48 +Key = f4c540778b164f86ec8a71e4c468e3ac5440058c22ceb1c8ef20cb82eafb1938237c558e42fb814e79347badb7a9d1d01f42d68eb837f678662f461619aa5f74449c6ddd915a83e7d3ba32b03b765966d0d23e0d197fde7c1cbe82a98dc993273f6eafeddefdfc59e064bd75b99923784e386590ad6e13defb15a7c2ad205d5a +Msg = c32bd69f97a5c6f36ee7eefa21b7055a4d8cbdd14baa5376638f65423c8e05ce97ba0b5e3d05af1f36a957ad3cc7add8704ef5a84b1f9e9fd66f163d1e6ce3cae223f04f90a124e6705839331ec5cc333d50b0346a7488256f1f9510b95ccce50d2f2c7976c04ece82bc3e95adf989f11e59977e91f03b92956989c3f7a5e8a9 +Mac = cbbda582978d51b1d033acac746dcb5c03ccf826738a127ac4bd049a67a26a900a5674e3131e91f15906426626a275f8 + +Count = 190 +Klen = 128 +Tlen = 48 +Key = ef4360affdcfd92d09596b1f758fa236413baa39240c07efdc99863fc2a37496a19a0d89c86337bc5e597102f69206c5636386a9ce26766c063a4711164c853d1dd551e15ae41119871e665468035fb6a373ecbad270951cd7256bf66f273f290bfc13fedbdace0d2bb0345ef26b14cfa872c3b55972cac6f861dc37f5bd0b21 +Msg = 931e6aeca959828765b7f3d8cbba8397800994b2891d039f563e4ff0ffaefe28cd243ccdfc7bc6bebfac06c785fa7f737b6c6c215280a45a421ec1624fcb810dcb1f6dd41c79b828bff169078d8ebdcc3dbac64b2bf2591d57c22739b1f12ac494f9432b90b9216e6c6e64bf6be0024bcfd9ea589cdbe8909e12c99cad88bff5 +Mac = 72de2ff4cf3f8e199a9dcd25b54688c0e5067ac6c985f1d18b4825d1a7332ac4547a6d7a87b877d943595ba1e1cad5ed + +Count = 191 +Klen = 128 +Tlen = 48 +Key = 72ce9cfd27b714419bde4dcd9b377dc840bdc3adaf5a734c0307af128834378b2a6a81252d2f0d371e2af3410987be76ec9d7c776cce1662c7afde0b0a696789846099f57a12046e1c417560b854c7062efbfc2ea4128d3d7ac8fd728000b46f67f70bf57627a4ef7e6cfcb210664383ed1e6b59beec7fe5069836d054bfc844 +Msg = 84b1b92aae4aebd81021b6cd7560e9a4df97248f85b1f8ee18274a214a73f89a91c8c03628005dcd58d6f208f555ac722b90a3d27b9402b9009b6857f7828e927e7d295a9c0a12368223a42310b8659f9b5ce901ee3ff40b8e5cdfc243f33d7dd33abe3d1150533c167292c9cf715d52b863bec3e699160f4bd2770b36ae4e83 +Mac = 8b2b909349d65a6b5a9b47c716a3696099c6806d6afdbbf905c87b18b3733e57dcbfd2a081b183716ac05c4ccfb8f585 + +Count = 192 +Klen = 128 +Tlen = 48 +Key = e89bfca0ccafc188ae7d3cabc8e90e3959c2169eeef8dc57e00930041ebd0ebf2c13c5ad6c7b58d29d45252aa15ac4f5832a3252b8e52f0fa5eee4c0628dc90ebee4c65283249963fb0077abb262f6817e5d2ab3bd640e61deb9261223276301a4f447b8981249e0d0957b58846a6a84524546e884db43f592523e22e7f5a43f +Msg = bc97d32ab16b7cf72c8d9d4960b7105b27a7ae753c801f6eaa6df16f8487e8f9d7f9952add612a3c737a8d4ecdf9ab6769b40fb84109b321457e16f708a58e05ba43e0d056b00e201c8170bb42650674e74d0d6448d0d07836cdc12cc852c8954dbcdba58420cfab10ea6e1926c4c98a89bad003b89b1f7965a21b942a553eb3 +Mac = d111d592e3ed96655f6b9d9802198f46467954bf63885a4961e4af40ab9816cf476e8604cf39e527756ead2e4f4d69ce + +Count = 193 +Klen = 128 +Tlen = 48 +Key = 1a63bd7c8d60023be7cb9b24498bdf07d29cef51ca6d8b8e20872a2c177049823ccf03119bd0e20932caf50fa620223d3565be6aecc35bac1a9de11c0473e1d9da062550eabd8cba144815e57e833938899d7ef2037949b29e54f33ca0a9207add514cc1e2efa756748b2331397dcb00b48d566f7758fca793f6881454d9af6c +Msg = 67c52838515ca9247b4cc741064937f802322e44d3e5dc1ed958363850e6f9ed74e6ec78e98265655bc70e4662f8e9a7a82892444d07c5798afd1ff9957529c3c57c9252f78abc14309f7b1e8492191e36a69d91205f4c36559471c206c45ad5a2aea32d411bb71a43ff933134c0cd45f3d6d59314947c3d8245b2fa697b940b +Mac = cefde7818c038cbf0bc0fc908625f4fa5b54c2becdc8d20921e4500d6d4f427db0c3fa007d40102e6b31b6e3d1b8d2be + +Count = 194 +Klen = 128 +Tlen = 48 +Key = 89745d553e42690dcaca938f860ea01b05665ae7f6d290124c8f5fd99de8b00dc84f02c4dbac6a5034f5d76de6ff9bbe5e94277b46c51664a9816ef9586722ec8dd9dbd7cf52f72b15f9d2682e76459460046de650c7aec22161f7eae0c047f2203970f4e1db1b86b7fd0ce9281aa78355dfb38fdd815f14fe548213fd9a2705 +Msg = f05e56198029c2a4ac8169eb68daf7b4f1ccb6f2037462444d1839bf220951ed71ce2e15f77e94bdb36e9a6e9a0c00b78d0bc27488c1ed511ccdb2891ffcb9f4a26eb84023f4437e04bde6e13c3271c34d1e93e97612aa082908da88bf465c876b8519216c5378ef87b674cdb512f1e1194c50d9343041735c10d8436aaee4b1 +Mac = 5238b04c6a3322a2df3b6211b56b2427095fc957bfad3a783527851fcf88a89ef4cc5eb53a394fa589b2a64701346662 + +Count = 195 +Klen = 128 +Tlen = 56 +Key = fc5850b25cdb1b94312fe03f7ca6bb315935dab4791c8ba5d2c9997a95fad98461230070b60fb714acc9f269e5bd7dd3c01bd7a9cf7c44f18cc81e6b47576cd26356b65ec26d178d7e9e9323da71ab6f784e2fd1cc2a5479d0660671f9f37fde6abb1983693c60860f766c7743086e8ee9968834566de2c5076afa9593183b31 +Msg = 85d09be10ad030a576a896eb7c4cbf6d3f6a74606ffb9aa7b519b3475210a81b03b7c5c9270105f423cf90b30608824269eceef89aa52379f91f2d2da11a9ff14b7e900c70eee464ae9fcdf26d6b9073c2218d6094207a21fd24ef7ef25f275627cc05932dc0555dddc2558efa9c736612b25981a59327058aceff208d07c7b2 +Mac = 7a90a3f4a47dd262f302d257d6acb916ff8192b8d2d4539119fd72c2b7812194cfeef34a8c3cbd32057a7477085caf7291ff7f83acdc1d7b + +Count = 196 +Klen = 128 +Tlen = 56 +Key = b1a85aaee55a9b2bf4e2284e663282a95c7e56448938a1357f3f17712c54c6e2a4cdf7ba218d550647335186ad92c4bc9a62d6430c342062ffac0de1ebea861b8f49ce55ed4caa4e96d5c6172798542514d0f6a5a430de0f3d1d33fee21ab73ffa84a828537fe42b663050abdd2d790d52317c135a152465c2fb537118cda375 +Msg = 7fd12b616030479e3066ee0a0fa6dc7d40b50b1a2ce6d6dfaa485e7a7d1e2d5e1e8f1917bd9f6bda825e4161185f31f66c6c2fcdb278b196aad5115321a83267ba9966f0eecf8f57521b85261873b819d9a31777923f30a2ecdc98edc07f8dafda56da96fda6fb3d2805820018c9b90f0ec089c1d2229a2bf8c3bcf2628d865d +Mac = df5c228bebabdd4d48cda20a869f12e6d44f1c881a28832ed4d5e404d91817e3969a36137f6c062e4c97502fd87f48944808a66be3be3923 + +Count = 197 +Klen = 128 +Tlen = 56 +Key = a96b6a8aff8fc36ae0ad65cf0e4f403c11a84d13d1d4c3fe64618e8e250dfd2206d1bb0b271f00eda7690868bae2c5f8fb88d11a0462a6b13c0611a7f15fe4d7a7adec2bafcd2201fbbb25d43055e818fd62a865acd222d8f64702b71cd59e533306e433bf22916e84ada55999301362be3dbc3cefad9e3d3a2c4904cdf8935e +Msg = 9728ad23a2b44003732c59791383eb35c502f2dae9986cfa2071a541b1c9b8f02b03538d4cf5bad922870f03707cd01b538fa1c925c24c3fa2f3066c49b0f473054ced5b0d328208097a3b6a76ba24f44b1f8850ddbcfd510021a0296f30a2dc6e2c04f4ad139e77702e6616ede6efa7f5d930d5d72d87168224fedee9f1cc13 +Mac = 60eb5296e3ed5803b13446c35995e25bda93b88b8819060e52aaeba31d53a43f9a768cafe2fc74eede8653b71c555449286a0b399bd0613e + +Count = 198 +Klen = 128 +Tlen = 56 +Key = 29c6a168c0a4644fb8ed30346ee159ebf19b9b11fe3aae4c2f3f1ad46f364d33b199eb49e2f165921b3ecdac1c99e913f618863007f20e922be35d7b31d2d19e8cb2a0274ba66ffc4c682042acebeb24813fb0cfccb68bc1a945aa44c92c5b3522d9690ae50aa914b133d000061f87a4fcd9c2f935cd4d63102ba7391f8c1481 +Msg = 5c99ea4dce3f3ebe7794910bffebfdb4786236714b091a7472478aeee87979d45edb42e330ac3fe2978d9727202b575c5d1dc583da10f13852218c36238afd1d0081b273e65db4e851fb7fdeaf601028159f3f1231fd4fa28054c41ec0b574cea951e103d89ac6590ca5f03894d34fa108b04d27381b5e3b62a8d9ada8420670 +Mac = 68639aadb98735b55c7a0ea4c02f681737448700dbdf350e8c2fd9cb02a94c9510a108849a282bbbb04d9d2ef04407108a68b728dde1f138 + +Count = 199 +Klen = 128 +Tlen = 56 +Key = e619cb4bb4a96f9c44b267be0637b7704b955897f9678d3b83a774d21816dbc11bdd5620d4748ebd65c3dc64ff87175e55f8aa3851a9e9c606afa566e705fd89362f7870bf1e5134c55412093d4864c33a0c269aa92dbc2a3edbaabeae4961cd1f5758c5dc6f5f084eac3134284248a8e11af54467bcaf6f1272ac5fd6aaae95 +Msg = 6483bb473b065f14eaf9c951066c573106cf4b4152b47c4b9dd74b7a755bd9c0185677758a905e41e488a13befb85f52f11a3dedc7eb13ce34afe63c79751761265cd9f12f56e80c422c796658c36ca58b9dc90a27a26a540321f5e112120e17359eca0253e1663eacee39186a13e7f0795fd8e29962e8a5b23460b267b926a9 +Mac = 1f782910a5aded6af9b64f81adc1ae2f924c12ef7ea10aeab47e837e2dd3fb7454d92d90676f78d65c537ab0695ef5fdcf45cfaae2621417 + +Count = 200 +Klen = 128 +Tlen = 56 +Key = 3e5b392c1da00340c8252126987148cf8725e9f538ea58af37a82d4381f9eb3b47dddfbbefaf4b115c57c48e6fc2d994cd8ff5f1e30b876b28605f9ca2095b01ac89444df65df303cd2fb8439d4cfce4b45824c44841b95cbc71c6981f4882e5f6c92f8b3b93423da513c4ee2af9f8e7c3e83e176f7237aa7a432addff9ca710 +Msg = 59a7b02ba466cd03ce1d50c3f0ca4c02dc4b3d1c0e7b9a77df9eae0bfcffa32117d7e05adc7195f4278c93497401629897a58d08ad7141ea52e0163f14992d7a284e7b875ce4640b4dd48ceedad1ea17d8ab1e760773044845e0899602f1bdfff4d42ab80c0765d1a8bde2ba0a830c050923956d06c80b182264ad19ae4f7c39 +Mac = 805d0f62925be637b1939592753902b256d855a45e696d7ba75053c790c7a15be2e6f4995f8f7442196c1b84550edb69fbddfee6226af31c + +Count = 201 +Klen = 128 +Tlen = 56 +Key = 4c74d1ab0049c5be3c75dddceb8a79b8866df80487fcce3321f4d7842e12ec3c6979b332dd54bb919dbcc8dab6dc6b286253d6b87ed9efa83e26a3ff20107dee1ef3775628551089d1ca9e554916e63f8b92ea0cd7d1028663822e7c4e98ab0bd5a9c41cc994eb2e406708568c80118369f2db077a2a3053f7d22102a0f59d1a +Msg = 6cc698b3204f51cc47c37a03cded00a0aa7935bb65607652d7a70b9932494e9142720fdcf2ed38d011e0adca56b776c5a25e202b86b360ea053bfacb9b13e1007e2aa0fb23aef88704c4cb11a17c3946c40408e40a1c49c99fc93851494e65dea85811b8bc79db18a7d79c7fb4268f4c99d3b58ef98277172dbb8ed244e02056 +Mac = 21062149d0eb65362aca8032306973e4dc673d61952d1bd25c9791b9f4542af7e061235b23e4cd369fdf77ad21db66f804ad2858ad049157 + +Count = 202 +Klen = 128 +Tlen = 56 +Key = dec973a8215ce8f9596fbc96738f561e23ec36d81ebad03f8ad69bbeb2ad65b8ff5ae9cb240ea35698b5e33849d621db8fbb90725ed3f57ec154ba9783243e692ffa70fd3cc19c3a813d85abeff0b3827e3f0edd68d1ac499638e88457d3b48858f230c4d13c7badfc4ec875cba5b51adabed9a3a37b9ca7f1c94c0e97806d1b +Msg = c7e5ede152c50a935e76b59979e08638a09cfffd01ac7008056a18ab8ebf8d347e955e06788ff6efeaf7c3b54bf898f2a10d502247b9b5fbed79a0fde0f761498c8060b63fb805222f8cd606bf69df4dfeab576770598099120fcf97983b4d54f98c3d192da8ffd5351e34b45d9b23f2be605cf206f39a8a7c15eea13ef51afd +Mac = 85ea4506f6d077324b20d06afb02cc633e119f4e151200130a96b642985f95ec5bf48f29462c8902b297854428a19b5f5a2911c844b57162 + +Count = 203 +Klen = 128 +Tlen = 56 +Key = 56cacae4b595ea3fb4a8c5b57c14731179256608614c95c9725ddad5fbfa99111d4fa319d3015ad830601556e8e4c6d012d7da0e2c4f60f1605f6e4c058ec0f46988a31bce1411d9b2461e0c54f693627371d8b4596d179618439e2c1458853fc1dc918faeb8596bc3c1a780c73221ef245929a2ef9001df236f331d2d403017 +Msg = 5fa0402a3a131e24cd15291be50fac77603d8ae53d6de844f50327c20e411542edc56402ec535b7aacd5cb87ada045c81bf98a48ebd8435e27ecf2d286de294140dafac3204caecadbe7b94ea0ecee27f0a9f0bab040e9d77da97ee23ffa023101e6e9b6008480de0152dcb8e87a105a8754a481b42b42779e44b13a611c08da +Mac = e46e5c8450f6a06ea679347b98811bfee1910dd52820ba6c01fb8090d58e5943466e660efff61a7ac1b441ae954b0067165694777d4d2071 + +Count = 204 +Klen = 128 +Tlen = 56 +Key = b6265ae2d0a6b68022697e2c4ba3eecaf1756caf6107555975d7fc5dbb51f0a0d39f7eca19c277f885e234b2cfe2d61cd638d27042fcaeab683e05876f9dd1aab115ea1d6419c9ff7ae2927bc50652f75f4c848e49bfdbc152013b693be208f01831a4c1f9d333fdca11a2707836e7c3565a8af3be796402fbc8a7ec66481edc +Msg = 3250d12c31d11a36acdeb944fbc0e58527aa1959a29a675536800f8e3ca250140e3f7ebcbf725523095a8def8678ae58235826e8d374997e8055789947fbd5d3e47f76ac6bf728893a9a55fd2b25d9460e7d121b569536a51292eacb1f2d10b29c59e0849f263a7126e63af4518e0e58ce5f047a94c5e7d0d47f8caa2c00a8b8 +Mac = 7b74a7ee09d02964f3fc34d8310742f7c2e68bb02a5f32e58804f9608dc11620c225fb0d66cbc9f3a0d2c4cae1d48853364ec2a34f5a6a22 + +Count = 205 +Klen = 128 +Tlen = 56 +Key = 36aa473316a8b206a22edc8e33457d39ccee612e45b7b186a98b74b9dcce555681aaa7f81aa3a6757172005838109492ec11796cff3342c0353780694fef89f8e79978a89b6b75956d6f37286a91c6d68af7860ad890715fd2f0a413135b1db92f1fc32ddf27a6cd5ece89e612f19e6d6f4890f019f6c6cb485ee79f71399900 +Msg = 7cc5ef15a41facba5b47876cbdfe0e0f6c6aa30d7a657f4c891bf75d30d4fdf6a10ee9a289cf7ab738391788025f5bdde557d1a06c91fcd9d2669bdd6bf42ac1402aac15f91fa8cf01a87286e429abe1fcab0b4e4c2f5ef7ac42cdf227d25fb7a140c0d8bcb640ecfdbb1ecc2b050703f88eda7fe4eaae8d5dd716042b16a4bf +Mac = 651a25ec186b3615f57d925e735c11b9ecc8718cf6dc85c31d991f1e65380ebf75441cbe33111f93684d529354b919a43025420859f629bc + +Count = 206 +Klen = 128 +Tlen = 56 +Key = ff333ce688f621ef84fa6a52e47d30522c08a7e4d345a31be8105be4fcd06df33b0823fddc29f528bcab4fc0455b942b95f7621fdcf8181206af95f29b934317e3da55764d464c171142c0c9152d5d140ef62c6fe7e913b366c8a0d00d1e02be3ed058b7a3f52fa4cde745d51b9a93f4de2d8b3cbabf9fe6508402e41918b2d2 +Msg = 6cc98be75b168e5bc9ad673a30ae01d275fa0d216da2a5eaa09f2f084dc38503aeef53e17c87c03eb623509f9f87080406d6d4bcc902277d9c87e1b40759751aae1a4b88d591630c23583c3ca6d4f4ca186ab05961f03e8f5c62f96cded7eddaf5b33c856d1dc1ec99b4f2b9507d0b4d352069a03b553348699940d7db25356a +Mac = 77294f4cc025128e50ce07ab71cdb6017dcf8247759e1b59632aad789600430c970cfbff31d9f635ff58b149f38da5115ae339a0aed6db4d + +Count = 207 +Klen = 128 +Tlen = 56 +Key = bcb8aff6d0a89f2c5abe7f6372824bf416cd072a7ad0ae5f9f596c6127520c1b688ab471bfb9d06b26be4c96092a06a756028362d4c1e1bab59d0c3a6e0b35a3c68580d72d8bfdf550e8dac6ea36d758dda4f9e881f783053ccf22f3532c684eff307befc4270f14fec491babdada54ed23bd3852a7a7d895b7815557dbc8d62 +Msg = ef9486bfd96e72d068b5003d15100a0e19e432e8d2256c83676cbd5eaf4a42b24fdd73a423a0a9bee087dea0f74cb4f3bc03b99fc7f5ea3e9aab76d08549c4b0c71eb6c7f67830ffa1bdd4fa33b710051a305b4729bfbb3e3be18b6d1a4b7b4e9f7fd88e1a9e0e79f37d6bb492fa252a7d919f48c02ae86d9235849c35f97075 +Mac = 4af995ab01e4d303884ffdb72e2ded3b568c6690dffb7eca47c021a567469303f7c3979e7e3af24b9920ee377af4b8072a8a64c56650e0a0 + +Count = 208 +Klen = 128 +Tlen = 56 +Key = d6d6c80c2890d096e581c98d9ccaddc4de8d360b4eb0b70df8deea79e4cf3a60eaca63dfc76826fd719a41d6a8ed9eface0dcb10f888aabf45d56ace6f95b5899f182b67862310eba9f141c8fc776d48b3ed81ee5589645b128ee56e5685f2af9eca0aee8b4bf427348db2a9c1f0b177363342ef8c3a4ea9060f44a2c228579a +Msg = 781f396e34e537c4853b9e91507c2d2fdbede621eb4d5a4929ad265bca82be926ff969a24a8a8ded83d02df9da98b0228d38e48c7c22425c8bb87428486214abcedeb7bee9d82a847abbfbe41dc63b3c0a62835339b33590ca6d046aa3e9b7205b7829aa57f795ef32a31038622f57e51914cb5f6a29ba4dad73e00b243e2e57 +Mac = 786a521200443143a15a7bc18abaf01dd079d67f11b9b4562aca9949cb8fee812341e745f98bb3a2718c3e58bd4af7957e38b782f21a4680 + +Count = 209 +Klen = 128 +Tlen = 56 +Key = e58fbf55109e26a4d95dd60d754140cb8577af913b7786c4bfdcc8e7d173de57af92953839ab67af5320fb518b59efdcfc15d42571fd7a52ce7f6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f5c16897a360a6bde2dfa57228f90a54b182497a5b8783d1397a695a35756f7659934b07ec2a2 +Msg = 629667993c18ea3639ec4cb509d1df73ac96c75286ddafa4b520bb4ca2f1bd1fd686ab911074518d94bb43a4c503166af625cf1d7eed9c880a1fc22738b7d78c61753101b5999e6f8eec557ffeff2dfeaab70d86dc09a45bd3035a935e0c867aa96ce134560f3ba4cf856c8ddb4e8ef7705569d5c9ba2fe4b7d46ad63c7732b0 +Mac = be4d9e32041a8af4f851c6fbea171a41e4e0967da0b27dd2c34e23bd3b94262682f15262e4031579698a1ef5c5542ce6407d59905e27b590 + +Count = 210 +Klen = 128 +Tlen = 64 +Key = e9e4480d1c4a621e0c4e1505992556347a7ab34fd2b289910474766cc969116f8040d96dc5f66cdc4454fa7bcfb9f838af19195038467ab8a16e1cbc12e598e6fd250e21b2145f1e2e859cf73400be12a0c69749f7100847429875351d5a76970b9ccf700c2ca3ad72e9e4c0f0840e8cf488158136989b0891f867211350134a +Msg = b82eefb2081bd14dab0e9e345248a34ade73f3291886b91ea3e8cc742fd884f6ee0ccdaf4c9879f4db12dba58cf491af2541a1d5ef6cc8b1af750ef5d8559ef7ff9cd56d8f599974be3aecd8c0f4c08f3ae50d86f9f822a1e4ca39fd2f0b4d78d22630733a24d8d63ecdf9555411daf205a761c39ef46ff6292e74129bc13a7f +Mac = 90093bdcc45da7338bd2efe92e30933b14f75582739c747f7572b3270b104f33af0c939e3c8ae53b2066fc8c97ccf38785cd2ec3d79e6946499d36121e44a3e7 + +Count = 211 +Klen = 128 +Tlen = 64 +Key = d3fbd6fe4e356ac1c8c120d432d7204d9d579b2a5a5d0c8b6016bd1eefd38dda735cf2f0ab873afe0a0916865e8b58a0af01fceb6a3765c9bfaceacc47a4916bea791afa003240d9b6563bebb3038949fc3aee38157dba596a9c4a20edccd187fff95904945d04b8925298e97b643ab24cab7af9a55890a2298de5022872d697 +Msg = b967c7d9c0a941f02e87723cf282eada4347b28193d3e0bfbeda6985886a37e646cc7b1cdbab45cce677528b3a0c24a08f8f580b779935c79398814d067298592a6bbff08248b5a2f0b48b0d28e4b6a2657763ac5ba00a8d6c86464b1eebe44ccd0c395e9dc9b9fbb306c6caa551c6682ec57869272e889ab26e6189b91f4248 +Mac = bc9a83d782e50ba5a801146f8da39095d92387d759eb4ad52bbd9e99d9f68f4a0f6f6470c653c45979c2e19543804ced592ee9c53eb68a5b1b7746ed403ebe67 + +Count = 212 +Klen = 128 +Tlen = 64 +Key = 19d4cb1d72c73e2577a23006f31466ff777b9582fdfb25e8cbcd34649adade35f889bc20ebd5aa1ed7a2ce52a151d63d1592803585796013b3d5de2df2bd7e84876b643e554e1756ba5a8592b4a347b5482a27f624f6dfb28367245e51c8e3bf8f23cb5dfa590b35e7715dae723143ced7eb90ae209a2b2b012e10df00239750 +Msg = fd13a5e109ee583bda183ab64e4d27855bfaec17449f14991378febc435c33b8bde5f79106d11e98b6a821362c9f71e580bd0b7fb93c4dbb403208f49571d62d41abae530cdab5c16fde570a4c6897f2dd18a3bdebe2acad40b6f4c65e6029d471adf1af83cfc6beef0204ba187040b45a52dc5a4159d876f94cebb706f2d3b4 +Mac = b201720661830a671c94421958f73c8b666fd8a323629548a29afa163cee2ec24a01201d901ccf5b0adb1d20fcf0c5ea1c7483fa95ffa0a9590b970385d5779e + +Count = 213 +Klen = 128 +Tlen = 64 +Key = 69d9440047b29b8e1dea08482a506d9afad24fffe9ef7f18e36ff9ff6d510cd9e905bbaa15db646ed6bc9f65341869aea51f82178e341334079e94aedf81eddedf0ddb9a53f6964fc724b1500fab416e8afd41c9a75f35e6a7990e01a5f24ea4d45b6c7809eb7a5c798b05b4c3f33d0331d555bd3a572d564cc72f9fc98a7752 +Msg = 18ec13250ee9c74c0fc4dd564b3d24a825802d5ae402a53bacace115ae3bbb329be79d1e5e42dbaf0a6446431145fe49b86a8703c7c41f8985d54f12e314c16ff89351d8addf66ebba2783f2d1a11965182aa0b0dd2de53586c5a695c6265c2b173958da648611090557bdebf11a1e042f089fe98e049f4796c60d26be38356f +Mac = 921264559658c2a0f948d13620312047326ba3ab84d1795c9e438fa76daa37ea5f16024306be804aedf8f91b586987254bc0ca8d64a79325c46b2f0b7371e3dc + +Count = 214 +Klen = 128 +Tlen = 64 +Key = 9ecc24e4faa8fd520aa9a49cab88fee7fd39425e13ca502eef8d45d5ad794c9dfeceb763d8f84e9d6cb6e69c597b360e1f15e7c6d68ceac0204d0e5f5c87d2fa1cd67797d91f5af6e6bb81d2a3d77463f31a4e27f08913e2dda844e45be2b18ae02b8f0766e4ca6460ff9dc6f2635ff06192a008c989749e0ee80fea14529255 +Msg = b85c46b5d55b896d67b87ac3313a97c7509984211ed80b0357d4615c7a1eaa4f7206c0e376f830fc2e0c868a17d8cb0028894b08b6329c749563db7880fe3917ba46b6dcf6392dca752091956e647613b2a3d3ed9003069af6c6188eda1f43aed844b1081dc587c1831c224efd85a0e73610a33975f4515cc426a004512ad0fb +Mac = 9088a7ca211f69835b3786789afd93f3704de4a34116ec5cd5ed0a43a3bd611ca08619718d9bf287502bfe07b6d79b3b2ba982f99442752aad29ec23856bfa47 + +Count = 215 +Klen = 128 +Tlen = 64 +Key = aa42b41c544fa928b2f3c7f12c41e5c56c910860ca257cb3080c24e440470e951a2b4a694206fdc41a05b1d3ac55efcde2891078f93c50ee33f724a1cc55ce9d30642e0d6b4fdb01e13a726e3f6e2e76b1b6b9ea5608420ef168d09ce10ad60b53b70710b6716b666f5ab3cbced2ca4b41e0acc0c8d37b9aa929d0dc65af4f67 +Msg = 2b1f5c46d4b819bfa1ede55a14077644b642aa3963d177a6e823200bd065afa47a489f486f04d991f39de23dda6452d49dc2888bad319c69078b95a80987dc5e8480f15d12795d57aa5fe846718d0b0ad396a854d33ef9c49fc9c74e6879dce27052ba4c65208d59edbb5f3b828a8b2e8046745c7c0076fed8661dc594429578 +Mac = 16d83f28f335f8d876b2fc85512159147f4cdcbb5c3ace09367d8f1b557bc977cc6cd31db4f93b144302f2712a05fd964f21f5fff11d28b703b9de3a01f87764 + +Count = 216 +Klen = 128 +Tlen = 64 +Key = b04cada1712ceb8b03c37c11034d7f6723c5d185cdfad3d80ae56e37a33a5418863d88046ad72048b6e94aee9fe08deb918a519ad128a26960c431d322c49b8e3fc0ee05ca916a08a1aa84c294ac31ecc93460415ef7c8325112e5da9d9b3d34a67ce88cd7814f338aaf347728d8f3d2916c0762be92cf99a57792365ce6c274 +Msg = 1bfa498a685e81f725583a0f4fc5722fde8c01199b23139a3255db6a884286534ea76e95d75f918a262a41864cae1d01f1bb3ff830d3b790a8ea38fdcf6a12a28a7a6079fb8083b69ae4cfa7881883df20d5ff93cea7314424ab519e2a97cea1f6fc88fe7dc83fc4a90f4b3bac0b8e109361a8b31ea569fecf218c1741d2a297 +Mac = 175e9a5606934304d65f5a2357d074b3511b597afe0167704aa457447a7015a02700f9c00aad116217b27daa9898c6c1e134e7624a7488c3515694b98a2f6ec4 + +Count = 217 +Klen = 128 +Tlen = 64 +Key = 95b203c6488fc5b5215aa58c6e34148dc277cd1552925b139f14dcbe55060488737e654dad71edd10fc9b069e2b7e7f8d34b391d52423aab391f325aae7d1fbc4aa3fd727b59449f26fab39d91cb4cef818ba0779f4b4ce92080c480a5574ff06048539b79eed307b016369043164a5a1260888a01569ab69e601a99043c9d0c +Msg = 2ce3453903e4f074dfe57499a1506187f8287e79849e0e373cdf538e0d3151fdc33ed4b12dafb4b47cfd5861ed84791ba8da283ee75e13565a14048fcbb0aa6dfef09cbddb2f9bccce3817d66f58f5c15eb7900b71e7fe0212be9433e261ac24a3a2a546548c2c259d3bbae26ef25ee3e467bdc96c6157a22a850c609c6dde8b +Mac = 2302ffdac9cf3b7e284d80fc470ed42cac01d218fa1b851a4dc3edc80c2f3c8f239280da93ebcc249886bfc08c7f0bf22defb7e447dc8bdbb94093cb357cc5ea + +Count = 218 +Klen = 128 +Tlen = 64 +Key = f84d1361c51c3e50e245848383fcd37b2f7b0fd916010a7fa41bb1f256228302cd0548ae2148ff42774d18c2d6d3e38b36bc4938da13bac3e04d66ec17cfb0df10b1df1178c2176ba4cc89aa6e19e606403519116ef635e3c9baac7471f0c349eada42537290701492493e03f4d6c332746fe82e79b2652686e9ec500c8ca389 +Msg = 2bac5a6bd9dc5ee714606e2262bbd3d3ef73c9d578688321676370fa40f2bd673b741be63370c25fbe2bb5579e79486658d3e0eb22aafbfe02fb70a63524f74ccef6eb709f0b4f9b5c591095fe0889d766814c4343c82013350b4610337b01042a5a5571e6550e83361504444b119e0f62a69547a369fa4848bc7b9e019fe276 +Mac = 5f3422f586e6dbae45ddc87f8d04b0c88152f90fabfc6dfbb0ccd7edae37de528460a7bf16c4c0521355d5f28c88ffeb55986f8b919feb756693b076c1690d5b + +Count = 219 +Klen = 128 +Tlen = 64 +Key = befb1ce10b50a8dd71468834cc5c1174bcc1885f4a67e49ece59d6b3104e0730ad7ea126bcb410e1b2a50ad28380cccd0ac6a775ab5cbcf437df04ef0f3793b88d6f1dc69fc3b963b5fbe5a5def8ca9f2d8dc2d8629018fdc6300fd25788256e257598a8fca52acd43f1219424ed9353eebde072b72a802045f5ff462f6a45b9 +Msg = 1283748593d539417ff5701cac703c3dfcae39608382bd14ec005e26188fb45d093f6067ff5c4c14e04335c2dd74671953e9c8f8efa618ae1692776e848528fd33a294ae7ee792908602e5e6d56606d7419f256713e26aa669e98027d9fe54b457551a40599e921d39db8970da6fa2e18e785697375f3a63adae803b6021c1eb +Mac = 6d4aa62658419fc842553c70118d90da3cb2a37539dae4b086b4a7f0303dd9c5f5a82d1a7700fbc1d5309a7f668bda06ac53f6f77ae26878bb9225651b1523a2 + +Count = 220 +Klen = 128 +Tlen = 64 +Key = 21251ddba377e48fa35ad148389c486a84e623f3dc49f9af281aa0af8d00f0f74a4bca77e087593d765198e87b6a15608d0af4c49a7736a445d53c718b408631a618c177319c01938ebb4b06852656392daa926e10bd6af68a57c6a47203d583fc3509c4dede63fab23ef08a9cf9945c2c6e06d786441c0dc04549328b706453 +Msg = 41da7852d48d59fc2ad0fffb9d64b9ae213f3266d5d4a2c7d89445725eb50de1033294915f135467daee1a4dc1aeb81c9a93fabeb57adc94045ffa152c2048b8dc8303145e7be8466ca7a394441c8a50ff648bfe1ec663b966c811d2eef38bbb76d6af23fa4e7c63870482194e369712f7bbcc6e3741a0fea5da73f1c9b73db0 +Mac = 41a4c83777750d4fea58645cea32ff4456c44953b466a5980d2b8da234603547a6259188f8693649dcef85e85110026c006ab968297567ce823965a1df6701fe + +Count = 221 +Klen = 128 +Tlen = 64 +Key = 5d307655cf8f7c1b3b573bd75e2374942ee3e56b6b2578ec7793bbc067bc908d5a17261a094427b4a09633d0cdcf8ef1162a15cc6f9f77aa0c62a10f74ad7a99d7bfd12aa125934a4f3842c681e7a29d51b6b61de407ea4a3e98927f5b4e93587b3160cebdb729a4ef454f03a5f31a618890aea7f1e63b92b73e755945274491 +Msg = f91bc92f97c28b011e7bb1dce84cf9154942094ab908b49635b87906e2f14c51f42a9ac3ce46877b6a687ad6fc08db2bd2471bb97f7ff5dd381ff4897eb636f1fe4d6f87b5fa302a57b26a9af25f2e30ce32b6cc993ba90ec0379bc920a9d3b4de2c526393071176ad0289111278788c06aee36b4e63579095a875af10f2ae03 +Mac = 9f5c4fd863f070b85d29b933b1379e7023335b74aac37186315e959473bf2b3c0f1f893e1feace27dffe35be6c607a22b02d695e41948b3b6b2bbf58ae7ae84b + +Count = 222 +Klen = 128 +Tlen = 64 +Key = ffe01cbd0ef36a85e32adf18931c4761709fb382228b27bbf9c1938d816c041f57871ce03ca0c06e68db10b720399c5e8b1ad460c201c1f72698f3bef6f4bb1621199ac958c1f8ee6859190dc74d4e836c856827e430722da3c0a04b9835821b049f7dc18bde7ccd8cade363aedfc599bbe75620b29ea3271741807c8eb9c2f4 +Msg = a32d2fba17f4b0f08a9ee7edeab34b1b8f7b12ad6e65fe248fa97a18c12de5358ca62e8467ffa1eb2bfe00f8c825d6da36d608b0afbbad071c651f9dcd33526b6c7665e334d277775ee8bc5adc31d08a4a2d4b0e22be957c2fcefcbf443803172de6fd61e637db990ba3439d90a1e234b2c8024e2d355f8eb02e36058e04a041 +Mac = c1437541647fb134322fe4809de516ff2a9982c16132077dac91e0e06f14cfa943fc8539a22c91faa3fa8fe623dafc954ebee5c17136281e7f8a3038f58bd80a + +Count = 223 +Klen = 128 +Tlen = 64 +Key = d65a384d328a1c8908a53151d8fb1e029c6fc44958c2728bf314588445a73f2e71e777e475a710c7ffae4d61837255888a232c854debe27682750af176ac6eea5cc501d7e47f151110a9ce7e44e5d76d9cad53c1819317527fcd169051f01c6a3efcc06ea9999431e3a09ef143dd0c79791423451f4179e7912464a9fffdb274 +Msg = 0f280564119a83a8482f57b7c20b247171a985d8dcc55b17157966c4eba613626095952a5ede370ba589f1ef08743940d9f41baaa2bf8c23150afc2946ee2a4b18103cebf5810f42c3e3cca513cebc069b725dbde67db5894a3fe6d11b0b03301ee12231404bb25788850f614be054cb9f68719811c57d4f9b5f4d44d0c64518 +Mac = 9645b0d953f9f91de98ca15845b7edc24434d3a247c1eccc99b71e9a3c3ffc79e94ac59ac7bb6ebfd10cc7645dd9c8449ce36bd1b4d1eae96de857cb04a76c0e + +Count = 224 +Klen = 128 +Tlen = 64 +Key = 69a9f4e2dc0ec5a720cb369e9a7ef804a4eb5254dffc1567ca06d2e0944e4ac72fcc2674a62fe9afb021221585cbe6bef09c7d1ca6465c26d60a53b6013608300ceca4659424ccb781f4d37dde102ea9e88d28a864ead78936504e62301914ef2890d57d4df75806bbcfb19e4c53b80db146b9bec2ee6dd8136129aac8ff564c +Msg = b9c8680ebb44ac60adfb20716c23b7bd9ba54908f51e888de129355847e094f1a3a01d3a580d749a46569b5b9ebb6751f54c30bd98f3cd7020b4bf344634ad67f87811e9acf03039f4b44fda520d24fc4e378b58c7657a5c870637881a47c818dfd9ace35ff4c883de9ca4b63023d704ceefc0a2297d77973ea6031d6b21ce4a +Mac = 73eefeacc31d31fa658517504322a759664bc1a94c3f31ffcf333f678d236c743066f05f92c99b30141a13dd65d0fc9881145af6acc9bbc446e0194d68b64977 + +Count = 225 +Klen = 139 +Tlen = 32 +Key = 9ce66be0e16f03baae3567aeb7ae8400fe601499999c7b5ab668efb0dcbddc6974f387c68779f1d1c9c9fef0d79bd6bbbd598c0bbbd4fe534935fc345836ac4bdb922c4e86b97a57d5c9917f51bad5af0fd8b1b379777f9050e2a818f2940cbbd9aba4a0659965f5db1d6883ad724985fcc6cdba5bedc7b9d6573c85333fc561772635e5ac807c52e2adcb +Msg = 6456643e93196695b484f8a38179486c3e3b577a9cc800d2dc69362837878d4f7ec0fbf3fe3ae08aa63745886cea61d2ec8a627652a46a997bb5d7b157f8c7f4927ddb0f737b3c1c04e7dcce7345ffefb8bff90d787439702912864f78a78943e7b48cfbbb84813215bb46de5f3227aae902a5a7d4df753e30a8cc6a613bda24 +Mac = 27973b3457c6bd4136a33ac61d41d5dd4395dbd0487da65a0e4eb369d9482d2b + +Count = 226 +Klen = 139 +Tlen = 32 +Key = 8647453889476b944eaf55b97b9a7bccec873657556780fa29f4fb5ebb45366ba49f2bbb648f0c4e4c353f7f9be3a736e7e72560bea45e9c8ee8bf37c279bf5b2ef16483adcc093208c05ee51a4db04632946ba2b96cdd9d15b33c25cce2eba4ede4f97aac29ebaa4cf6bbd342ff2063973710078ee7836687fd7b0e23a741aea921f187a8cc381dde7f5d +Msg = 8d4f4a896a5d6f681c951da1eee6143cd83a271750fba88762d5214203be447da334255101c6a76343d634c4469db2163370b2f15341ea852468e580aca4f9320d5c7aee5a2b2db4a99cff0e6932f738f6ac6a836b866efbb8c39048f4eacad2f44faf291c93e9a3756ee54700accde94a76b79741d31c34466f8b63839a9ea7 +Mac = 54a6fe3515e84298c9e3b1f2eb6f238fad2cf61f4e2e9686464e087ece4567c3 + +Count = 227 +Klen = 139 +Tlen = 32 +Key = 6e573e5984bd566a807c3f800da68f65216697b926939f2f588572f96e281e807c4ef559184ad774bcbab4976ba44c0b97c53996432530a965ef84d98e80eb93ccbe850cd0ab1a784c3aa47c9f610de5b46f399a27a047cfaaee147ca82b010e284df75cf309a8dcf9a31717f1045a5a400d9eaf1c2b6d0bf12b2cc90350e85756a35230cb8b070a8b9d15 +Msg = 35430b4881fc4991db8b046d64df7bef6d53afe02f8ebdbfbca76a06368d00af3fa759f7b0b739628e04e1ff3ab8e0ede7872d1e5191735bad8aac88db18f12ae37c90269f7560cbb5615113c9a64726f050292067fc341485f49651ee9b38e40a0cdb5eb5fe66d738eb7e32787158a36ef8cb6fd795aaf32d2e50e8d5df7ce5 +Mac = dfcd236af05c8204f1e68ea0a389499cf7601371ff190c66228752289e1b11ca + +Count = 228 +Klen = 139 +Tlen = 32 +Key = 4f48222e6c000f73c0db3321a59fd4baa7710d3bdee1c4447b27dd78a0acad2775cdb22b78db810f1466ff7776bbd4bb9cab1dd6ae8e617f9288c795bb0b86c0419d9c5637dcc37b39bfa18d441e3fbfca75bc0306e5432e8e7b3a5627b5bc7fdc424a77520abdff566e7f2bb8d1fb0c5c57528c8eec509896899e858cb239ac6e442258706d58e393fc03 +Msg = 16a5c0cc8104031e789c05f885df407d931b9a8d534ee639df3bac7a9ebd2d22675ca212e91ec5ae4a9f928e0e644f763b6dca89ba09e2b901ef4882ef8987d8f793425e81e5bdd88d8da0e39a21f7e4c6547c3e36c619c8b821a97ea761ff76107329161202f5858b8eb55ff1be40ad7df739148f2d944c4ef955d48eec9be4 +Mac = 4efd257f9e855323846b91da50c392de2bb9a29ed31970c3f01dec6dc37da66f + +Count = 229 +Klen = 139 +Tlen = 32 +Key = f82e2ac9e2a859aa38fe8fa0d4f298130bd68e89e0f2aa2578265b6eced19553a8f16c6bca8be181694dfc4fe2721b8aace6891f8baa52bd077b56931dae9d5b345fea9753ca931a90f98fcbcca0d1a69d45d4038ca3781b81510cc87b9fac8c84c1cdd5e52f167f964b729bf844636fc63b99bd49a5c349ccf1a595506a6aef815e3cade88013b8618bca +Msg = a59077774b861c354922c7f7fd5a687c7a034e642ce7eee7c017e0c73e832a8378c7c1cea8484d3f55802d4a7696bb6fda32d1b1c78f8c4ae2d24f9d4e9a0b6c18d8be4bd3e13a557fc1281db0d24ce8ec8e0b1954a22aec8643d867c3c5ef8e4d6a77d713786cdd908ec058f137a44d76c004821a4750357615820de32e5d51 +Mac = a8c446e15a39765fc932e0db9a715119622413522a6fb5c1ddacae1be8e8b9d0 + +Count = 230 +Klen = 139 +Tlen = 32 +Key = 6d5f17f536140d17073b062536e893f982e91fe83e582df6b26ce145be94c2d4c0c7be66b8156fbfaa839c16441503c8c12c554a0d1283612ad43895d250a6e35e8e86b2e6545a08aaf4f6feb0693e71afa231fb2c1e2721e3b956ce68c69b010e5d78c208f6595ace371bc3c30bce5e14f4bae4e3a2a19fa5c444dac81e289699dc9a7e6626f11ddff413 +Msg = c35d20d1c500794332b0c1a1bc67dfc033c4c360a8a3aa5fd2f19d2db1bf3b807094b949900827e6438ef5991692b539d3c42227a6b362847e9d88a1b6855db7f58760d953690b26bd7258439a7f8409ae53137a3f2f14fa77a2a6bc0aa3bb7a19dd1c69554aae6c6703f3879057d3978c1a9d41bd3f492985aa0064f43fde2f +Mac = 5dd809c012393f579be168109ca60d1688df32bc5eea2024bddd91cd45ed43d1 + +Count = 231 +Klen = 139 +Tlen = 32 +Key = 9b0e2154665d5e5b57bbfaab3fbffbbffae6bc1a51e5ed391f3edbc6b312f10e76367fb5cd89bba841840654de127016d8a27df2757b2a8726502b42f71577d32a1106dd1f33d9f278a93cbe7aaf4882b5a5abc5e765ac461ed369341db663a101c63d352405c11f42532451da3d8bedd717cdfa704a7b5c4dee1e03eb9cbf62417dad23a4a77a19e8aa47 +Msg = dd2efa4b6d340de657823a5959b441ab66bae0f9412201d04b9532da9aa555bd4ac699401899a9b02c71238237104b39beb1018ab64cf0be50150959164530f9371e34801f2905754bc321a85cd750156aed910b9a64548ef3fbe9f96d9739e84b40b454ab6c8a005c801e14ef94b808117679c418f29506db51bc03c720d951 +Mac = 6070d709a0a26fb5d4e3a006f9913c4d5bbb1d02e6008685e006b1cf7a4783fb + +Count = 232 +Klen = 139 +Tlen = 32 +Key = 6d6017f05b66ccb88d7011068fe678b12c7bbc1a8dbd0362a5ea60dacc069cbba92a3618561fa810bf2cec484b2b3f99bfe225055f91adf056c8f68c577bf29685586a409058426e2195ff24795b863f5581266414fad9371ba7c7cd796f0c63c792bb50523a23387d545183609dd60db500ca1ff51f109fbe30dc83780a738b387f3230e4edd2d89910ea +Msg = fc46e832af596bb15a22f89741e09d4c7c61c12756d3ace1f4d84a4a37d82b3ae29bcfcb001721c58086415a23bc861498b8c40be579ca5b08132fd5de014ff545bd90147d8eeadfd5a1a608835c653cd3ef6554842c00cf6e98758069c2eb846bd3b377f067cee79f9baf092a6741ab762f2c6afc9455256f90a3b29ec209cf +Mac = 1827aef6f794fda16cccbb3e1ac5e9b84c5f4a5949e313f7443b9d9ecb785d7f + +Count = 233 +Klen = 139 +Tlen = 32 +Key = a6ec2b6448a36dae7f0288fa095dcf5c778e04a334ea79e6c374765f4851db7c4a7c0634b7bbf79828d2b2aa67f6e5712f84cb4d32f350896008762f6748f72076b32c6347af2dbe5c433a8389855aadb256412bd64c777c4cf0b77c4d2a967eb3f9659a00675749a2bde72f76f374378a6a2ee527de36e80f9601ef03ddfebe88b67881ebccbd6083a880 +Msg = 89745d553e42690dcaca938f860ea01b05665ae7f6d290124c8f5fd99de8b00dc84f02c4dbac6a5034f5d76de6ff9bbe5e94277b46c51664a9816ef9586722ec8dd9dbd7cf52f72b15f9d2682e76459460046de650c7aec22161f7eae0c047f2203970f4e1db1b86b7fd0ce9281aa78355dfb38fdd815f14fe548213fd9a2705 +Mac = 857877efb8dfa0d46601ddcdc52cdbf5fc1a34735d36773008d190dcd57c0b95 + +Count = 234 +Klen = 139 +Tlen = 32 +Key = f05e56198029c2a4ac8169eb68daf7b4f1ccb6f2037462444d1839bf220951ed71ce2e15f77e94bdb36e9a6e9a0c00b78d0bc27488c1ed511ccdb2891ffcb9f4a26eb84023f4437e04bde6e13c3271c34d1e93e97612aa082908da88bf465c876b8519216c5378ef87b674cdb512f1e1194c50d9343041735c10d8436aaee4b1b45d7c413b62da1725a06d +Msg = b5df01a9bbd2517946829209dd27a6019b3fa763858ed8b61a64db652b1e2462ecefad0e4ce1eb5d82160235e85435180dc1a00305ea2996040ab4742c8a96eda2c44cdbe70c6ec966f1de5b49c045ea914ac06e66e7d6a1abbbae61d6387e56ffe447d6365dc0051a9a8f41a873bfbd50646f6b4e8ec72037fe31f3d232c5e6 +Mac = 0485e3bd7dd2d8fff30f26c32c60a04343f22d7b4e90980a0819ffbfe66209fb + +Count = 235 +Klen = 139 +Tlen = 32 +Key = 13ade41b10d936e3bc007d1f1ede120e8163b7c0c8b78636017c27c53d5346bb9ea14445b1932d90fe5feb2fdecdb9bd8df7dac3804c8adbf9db3516d8cfe79cb43504922a0639417561b2743f188d21b76e8f4ce41f162939a14f8169aaa9567df28aca233a403d498d3ab6eac67884285240259c371366ea55dfcc98ec7633205f3fb543382bcda16beb +Msg = 721248d5545218f96cc0e8756e912dbd95661418957115ecd0dacb3ccc61036fe54413533f636d61ffa27343bb8f8d932e4579e63190e309e751368a3724b17a7f41bd7286a07ed4b361a8537d6a94b6235293d89d7e82f4d2899e1f0be99a16a8d0ef3a125174d9f0c42eaf9e6b69adda5607f9c1831935fb4aac0432f8e5ca +Mac = 3ca21e282bda0ea11c8b1dd7a8986af19ac75a3e6b1c0c02131ecbb786edafc5 + +Count = 236 +Klen = 139 +Tlen = 32 +Key = 5bd7b597338c27d20e9772ec0fdff39ca56ca5c3bbc9f1f22facc82c86d8f0edde439b6a23743e1b8630a0772b5532ff22069e7d9908a28e506c1f5e4d6f6db3d09ef22d893ef3cc09eaa9b2777e982a84341ceaa00d45956f73e484761ce6c61b31e165ccb0edeb7e0fb5255922ce27b13e4790399f8110730740276ba8032fa544919c5493d583cce5eb +Msg = 66aa32cece01bfaed925c97614fee37a52a0228bf47d81c868d984b8f07f1c96a5b3cbecbb67086406b2e5dabd7defb57f805678936d4e94746ab4818dc5f50c41e32cf32e7a8aafb300fb91af6406108cfbf5627dbd374903b10230b6a63d7642249c0ab0a20d38e7f953c27219f03383fb497038d705901e96b6edf48abb7b +Mac = 6e2ba26b55bc023c53dabb4c8476d240b60a5febb38d6f34a8f81d7031949f81 + +Count = 237 +Klen = 139 +Tlen = 32 +Key = 671fe8eb38047cafb577a5ed0989825fdecda94e210d0ef1063c27f54dac4d5dc381668c0b66c1a09e7e4102119dbe3b97b9a80ac69bedb39eda1d99c70acd0f1a31396c637a2d5d652e25801fdfb32e4ee7219833115715969500ba0b4ae92c7417a9b2c7aa878e126d988ebcb628de0d3f5b20f0d514bef854167fa2d26a59da1b0087c05e99dbab25e3 +Msg = ff44aa46bd6671aaa0c866bfc760b2d6ceadf1f04152408056059772dba75a6b6db42a53ebde01112af57e95ea0a7d1c09d4ebaff753d9ed6ab2ce0b5372621910c50887e3382ce7a3957ef4b1088dd42e80979a6b589f0fa137c1b2e335c3fd503fecea8dbc19b673700de504a10986a4799cb886acbd6d645b176e7337a4a0 +Mac = 8def5273d5341f709b16467f48d3ae46ec35dd20f4449dda7657c21ac1a2f073 + +Count = 238 +Klen = 139 +Tlen = 32 +Key = f795ab87cce39d5f7786037e6bf704ba3466a45c07fbf3829e6184c2438521102a9bbde20363aa92d0aa0d03f4138e878d175400044b3046e3e118c9e672d87854fb04e18f253199eac964debcb3cb7bb3a6abec6aa19ac33d61ee4a5c27756a1ebb67cb98b1983d6febf257ea5f235d4b1a9367608599c055e8ee8dcc2c62af2fe5cdea4590494604189e +Msg = 331c94c1ed01e9f7ec5f0448564defa62082d8968dc5b741f1a431c8bb69bcd9b24a05807fe08f3f6cdb9c606bf3508a5a221493851039956dcfdd44c8c8137ec8f53e24a051be29458dcfe87105adbbeef2fdc911e1681f8564890349070984fc850856593cbfddfedf6488716b4e60645c5ae138208d08c1ccfbad490ee713 +Mac = 9ea4cc85332df7f5f73415ddc94764227da7845adf1227c39fccbe0254970195 + +Count = 239 +Klen = 139 +Tlen = 32 +Key = a686aba184bae89ac5af1efdcb55476df8908b015c4706f590b8cba0e10e29a6b1352d6f1bed67d8d61df1285c6aae454b09d0280bd19d8eb19572f023b008b67de1f6a8b45a77a57a136e976164a7a642d360ace02b08e9c9ce46f97d4b3d02d2330f3297299f6978399c32216bbbf8a7974377237acf70a00a4fa1370751f478d37ff70c83688c993683 +Msg = 8c562a0b7e50074e62deed2a664797b853fc4394641e1e835840fd58c66e4d18b16e4d5c5c457bf75ffe4bd9fba61f33ab9b74dcfb0759f49da726c7bad16af386b525ce17e33802770d197af80ecb82c72c0e29c49ad3ea9141f28ce9c11f4734b21b28582f27b7d195bed6048883ecd037794367e172af5c99ca71fd46545a +Mac = ae4cd8fd5518706daab064f327553b23e221d8bd1b0b005ac634a14cceef2cba + +Count = 240 +Klen = 139 +Tlen = 40 +Key = f3e81c3dcfa5305c9ff15edf303103fdedf7fc73af841525d78bc4099b3818419d71ec87c25c60ce41218a26faf168e10a4719f49c6d4da00143fb51043c52c677a9f172123a5a227ec1a4e1ac3a71186b0920fa3a82441f5aae546f284ca442aa1793c6684706a07d5a16d6ed1406ec39c5784d31cae0ed0a56382db073f6ff5d433b4a6b8c4d90677347 +Msg = 155e66936d319f169db519d51763f9b43de5d54177d5689783c88b820d8b61e380acd1561b3c391347d4601228d6ad7372f5971c7ef85da49dbaf770ac764c1be841a51b04d862a2799cecc31edbead6f851b81d53ef14a811db1b7543b775dcf626cc2a4f8c828ddb16a33020fb18a678011e8c1f42f76a8a30dfdbfad742ee +Mac = 6251628d0e65b0aac304695a2059fb7cdd6e787b6d3787ea544a4a53e861bf5467d9d3faa8cca13e + +Count = 241 +Klen = 139 +Tlen = 40 +Key = fbbbdd42e5fc631968985c0657ec42ef0db17af0497ecffe3d8e1fcae1c454e88dec9631c744c0665a3b1016a87822c1401e1f3db34f3259a4ef3bc11faac8212c38418da3df6221413aeee4fc3aa2f2946a68db6b77ce4696efb6da34494f5efe26441e20d63391481e603afc38abcc301cbf9118fe8d0c3b18f9dec9a9d2e62e3e08ace7301900946ecd +Msg = 7a03ff3737a8b26de4f9fa293b94899cb9d5d9b2ac9fd5f28c59d6a78e36d03d77baceedae7a9b9d9623c2011abdb9078a315a72a50992c4f7785d62659af2f306fc3a09345f8703e3b98332327d673a401c6dbb41cc8731d188511987584456ced22dd2f0e1de6874c52402aa5bf9fe849ffad7a76f1b01c29299141ff8302d +Mac = 0f19b00a7f9c96a0d88fba43cc55cbd04c0dce844a945320c041e36c3f8c5b5af5eb9f38ed7b071c + +Count = 242 +Klen = 139 +Tlen = 40 +Key = 05dca0efde68f835650ca4a7eb21a907be12d8b159bea420d71e31b3ae28adb199f3e38cd61b0d629267eac9a2a911cc73e6853144b789fe92efb63bd47e4af86996c392cf0cad331500b89893c00d17d8eae2e0e4d14c83982255b26ac84f485d0c688b31017eaed61f349b272e45efd5661845a1d495b7cfff38a2d7cc63aa5d9ff9fe63c328ddbe0c86 +Msg = c1993dbf1dc2436639784627d83c581cb5af21a0d29bd06f0d375708f4a7d856dac35a902b19c15efc35fd3de62081241526f7689cdc32dd0b62643e44e691ce8a694340dbc680d480f0f9c4e27b84de9f5ecc72ddf7476edf4f69c8d6a0181cf9145f97d7d06613ec31a283735549927cde09873ef2f96cae86d06f51dd5588 +Mac = 42e45ef94ceeb15b5c5a1b6c6f26412e7e63a15dac6eb912bcbcfffac4ae7dae5f42fa7e6b1d7447 + +Count = 243 +Klen = 139 +Tlen = 40 +Key = cc17a0b3a2d1051123c11c5bd918dff0c0b93e5356f6cc19f29ab906562d00738773e1f2dd3692355645322c2fbdfe6eb687c7da5a22a47e04a3e4b8aafa469a21766d93328c8e4cf1d46cd14a5486f1dd018ee70c831e3a5139a7e1d57daaab3f292adeca59611e9b73b2915165df41dd2e7cc294a0a3148264eaca023e926c8c92011bcd287273fd2cec +Msg = ebdf5cc51dcc4827c2ba27d22b86f03220a6d206776a6cc1e582403013c1655ef4217db55706e765b8c7360a5c6ae1899daf3b3a8251a64d92880466ead26f8b8ef32a40fd3ad7f00807ea8fe38a5d7e7dcda6af0df5e609edc5630eac6338bb5f5f4baf37f1809059822cabe96ecdda6809f8ab41e092be9e41436f80fd28b5 +Mac = 30e125c44f1e06a333fab208db7b4f0eafbabaf3da5596daf7b17b17e215fe469ca829b8c8f31da3 + +Count = 244 +Klen = 139 +Tlen = 40 +Key = aedbe9ac8e96e95bb5c6a392247fab23b53c5d8a477721201a77ee927c6a0d92a6b320cce185621cedb130fea2bcc946d835521185451dfb25882a925f1bee0be5f754349c7d02aafd51dd4cbb6ccfefa56dc854cf300257eca28a68ffd4fc3f334e8dcc06a54f6dad50b164b4b74588e68dc73a6c605a9b396e14fda5bbbd975760d47c6926d3cec753b5 +Msg = 12720cff0ca649ff2e1c9355cba8020fc96dbe05af9fb4bc008d8d8ac8dee0fb741aa674e66def16c9a8d4e52289ad2a283c84165621c9a7bed046d0a05b56d43bd352f3e30d4d4854a501f246440872421f5054b3c0c91240096035597631bd10a2f8c32b0dc95d771c02c25f617daebc1d0a08ef031cc32e3fc2021bb7d97f +Mac = 6c5f36354db5957016edcffbff8e52148c35de807c320ea58a622910e4472440087212f5d7025555 + +Count = 245 +Klen = 139 +Tlen = 40 +Key = 89f6ce9c23e9f65f67b9f0736841fda218b64bf4b17f762354464e4ff04fdbf366089e18ebe21ac8ad6093c6b96d167c1cf3b93548a9248cba2d5024da528f9a23bbcdb883a915ec051157f8adf268eaa3e54a4f95f6aea456b2b70dcb81014a0736e2e6b5e5efb1b6f4c2710c75fbd5f7b385aa5d0b1b516ffe0a718a8438e95ba26509473eb1010a335e +Msg = 1784de20dbd9410f06ab0f19caf7a146e0240f59ca3899a85c4c452a7a3ecad223a5ad1baf0aaae55455557fef85010501a4e1ecf8fa6ddbb18207bc3a9adf14dcfe148f59f71ce072d065c7ac8a3c7354d1ef0bc12e2e88d97db7c5d7a233d94b785aa4610a5ea86706871a8a6e1a39e09180dfac3aa456dd279d6cd7bc8dca +Mac = a4271a7cc9f6e4c0eb1b8386cbf3119b6f333a40da853f09e119cedcbdd384973c55291560d44db3 + +Count = 246 +Klen = 139 +Tlen = 40 +Key = cd8e4a0a21484000fbc7da29d8669b4e6dd5004a3c61b36c6676011dc0628ec3285b47e51ac4998f7eace0f8c49823623382fe427e21dfa1996b76c2ca59660503ea410b6f6ab31b4bf4fdc4f736a5c44d746c2931cf81b669c8f488b0006dfa05411ec549c2f66c09a718d799c88b3d62b333487cf40074809465b997df0c69d76ac85bd055cb4961ce19 +Msg = a4946aa5aca018655242bf0fb9194e65ee16c4fb848ef3eb7b8d83cb676e3bdccda87c84d1eb0eff0e6c2051c67d897f3b6054fe5c5d7c6ca412f47e400bea3a70924d662fc88d4016f5a26f7e1d4f3ae5d4a8f89352d2c77cca0a8169f8e8ec53fae5310f601c9031864d512a2227feb319c7cf6f977c66cb5ecdbc2a5ebd5c +Mac = 12b4f4334e5498393832f146c7e5c0afad6ac9ba02021363570090a9140a786225c48d45018ecf58 + +Count = 247 +Klen = 139 +Tlen = 40 +Key = d6ec1de088eb1b2efab889a79233993cc211f67e2e7607c911c573bbdcb7e0eb21aa01d8b03ccf20001916f3d01134c60d6e1d4cf784a3a28089f5caf4a7655adf506e752cd2f5fb8a2bcffd141e847430865232b7eb75185753a68a365ae220d8856c9e43d415276196bbada58110acf1029c18b8d2069460ca8fe4eaf8dfa5d4f2043b3e6ab80c4d03e2 +Msg = 9638216939c172f74e845ecc4486eda080e6d0345305f29329e94f9703e409b02770b8e1155e020bbe306d6ef1c3706d1631d0911ef52ad1ba50cb11cbecc8e81ac04ca64a332c960b84c1809069f67242f6a0c0b6c10e4adc44e1fd7a821e9dd9ee82c1bf88161f9c49030908c1a6386dffe7c901b1c785f88c3965f7ee3355 +Mac = 11304e9a457258ad7be884ede48b466b976b572bebe8a615bfcdb8b6e8758ecc2adc99bad372fd37 + +Count = 248 +Klen = 139 +Tlen = 40 +Key = 65cd0e941290a0848c8bb67080c603caeb5719718133e62650447e3fa1bc1b9f1fa861e53bc8e7e4ce9ef45400c586c66a8499de77a3a5bc107d69bb7857e75e74f0b087b05961ea5e076ec220271ec22831d74f9dc09cec41a1d4f6522a4d91aecd80e23aed177f83efac23a695d4a76e875c2dbd33d29f2dd74758f6dc542013665b5ea0290f89877e37 +Msg = 6eeb152015e6939ef579840d299f0bd01289a053048964043e2eb19f20b1f6af988fc252de781e3c616820fe0114bd887e87dfed300db767f950559b79c1761e80399d37c9e065e7e54f152675f175709cafe080b4cc9b5c400d6591221e4fc00f31ce593fe80fa769758a0dee00da8f5548cc93f78eb6e9fbaf0a0a85902a9d +Mac = 1685a4dbc1af73b97a2ede015075dd73d4a07b3c059850307966ddb9d6fa82f520b5db07f5e9fd82 + +Count = 249 +Klen = 139 +Tlen = 40 +Key = 7668d18d60fe54739fb1286d927543268a6918d62bac18b9167279c1c5573688b5f35788cbae728ef1d5726c00ee97eee249be10f8d8e36eb940e4fc9c3087f738f2bf1caa402b173858e03e3453687f22b20a971d3a4c857602b73f9fcadaa3478e92b0c75b88f6bd62fa4bf64bbfc092cb85d462795ee795dd7bf194ca36732aee56aee8a88f14c81949 +Msg = 338ca368ad156741f6018e48a6d891e61ccfe19570ed7b2fa96cbd6b306278a485a146dd31db1e03fc0a25715f0ec7ba3c9807a2cd48136ddb121c5d30e664764e90998461dd615f73ff366edf32746a08a0b0644a824c0a31894826e97c5b67f6224364256259dec3a968450c8cbf7ee6af85e4d0e54d8d1598eace456c8501 +Mac = 602d5b37355707b54724bfd1416061ab895d3d7911d8fafd1da25e546aa07db0f2de49f324ab298e + +Count = 250 +Klen = 139 +Tlen = 40 +Key = 3ce78309d9f006e07308508ffde48da2a58aff635ac0a1f38bc40a9a323d935c1272bccd3cbacc26d833b89722b746dfb30c721b025b11db2ae4b47beeefcfb1fa061b626b6138ba92a2977bf5c39795974ceef87ac94ba6617b3a0cda4e47927c0b66716ecf92c429bcb5e37eeec8ecdab03ba2c9f0977bb9f162f40140432821e966a14bea226e23e8d9 +Msg = 768aa679f74bd6cf8822f6c1fc221b20b4be400c1e38e9097c5c0756e76d1c7a93609f1f5448a2236112b2ed5972fffd831dbdc75a39c9c2491190bcb30e2d7036e3d15a310768ca83687938965e4ed79ddd566c19f0c761a2628715e4be4d77e87b04d3957070ec768e134abdcd52d58867d4a364452b0f0fb6b60b8367c5b7 +Mac = 37a6e1502f0ac608701d68b4fad3b9e80121d4eb8af7573b6dcb5162121894f6cda020d44a74ae80 + +Count = 251 +Klen = 139 +Tlen = 40 +Key = 9a54c64057af3f7bef4797501ef71084dee1166a8a037c11430c09bc936d339250b22a97c31318db0a46a7f2bb98c5a3ca3ca4e4ade30407bd8db42ee09e5604653464af2fb8700016b3b0ed8ae3b942798f8b937317ce750dcf5bee830dfe29a1817a6ee3c5ce52db35b72bd30176c7b481d35e26c862c4f97b05e3c4e4b269cb4277be2663bb392075c6 +Msg = 0b6dfbe3665881bae120b8a3ba1d6bd0a73ba5abbd4cbbc68fa38c159ade085be103efe2d4cfdb6f764a8175bf9f34893f2bab1605d40352bf9c07702375b0188d58e814e991934cd35dd0f4fdb67c04d16ef9e8587b2d795b92cd2dc8f7db8a56936de16c47b13840802e883c0b4c29a52b178a7ee94025aaac64b25209919b +Mac = fb4cf434e81cb3ea9ca88dc827b799d45f0adabdd3be3722f7b5299bc3ec3924bfbbbdbdf2c48c9b + +Count = 252 +Klen = 139 +Tlen = 40 +Key = 16d9fd38c5d4345c381bbbf52952375d9a43db506923964d24168a3f1ef6c15dc3501b4f28b08b92e71f831d29e9ad4504a4dcde086d42a31475e3d86ebd492d131d7ae64c8b2739829a26f75341236fe6de92907b7ae74d464f0a467d8705a4b047004459ec7019b4958bcbd0e1ffa4e6fae3adebd2ee1461ace7d172df5c893fd697b3765ccef922169a +Msg = c9da201165a6165755cd01bdeedd817275989f68e1a7b3aae38c85ef24d9b26fce9f51f54d2ad73657eb386129b64ff7142e80dd397d9cb09148045830e112e0cabfb484762c5a0cb23e1359a708f23eaf11b7911506ab811cabcc2942172a66c52191e6671668826eadd9cef03c33ee4d2b8cabfda9aac68c9f248be2e2c4aa +Mac = 37d2820226c124868624270db08a64d1c218f34e907c8c7d8e0ff52e0ac641e8bc6b384d6c536e22 + +Count = 253 +Klen = 139 +Tlen = 40 +Key = f543ca501f80215b0adbff3b3a1822877c1fe3001c5d0d175967efaf16e0b023d29ee38bda085b3bbdc2418d018d63e11468cfe185fba10a743619684836f1a0a068ed348bf0b303fb4cdd0f77344d8311c5c0f598dfa6e80ecc32955c22adeb45ea0fd49901d0baabbffc4a04d78677597edec2bbd0c5b90e6f61bebc6d8c0aab6c72f26c035b68b564c5 +Msg = 41b7a26c17ed19ffbb2a26c6d9b9fcfc4d596cfe93e3fb0b7f2c38482e2d4d073c61d348376feb8054098a9a6114143cfb092d4b019bccb1499a905e9117588cb8c90e482eafc32ea9f70174191f5c2adf5a4bbf393536c8017ad0fd9854a7841db5fa73e2f5ca9020bc335be921fd4e5f136f6324f863d71195a02d2b2e6377 +Mac = 374afe237c3ac24e36368006609c1f8ef87255b0a25d7bb4020c0defc52de461f21495bc0f151845 + +Count = 254 +Klen = 139 +Tlen = 40 +Key = 3d31cf76288ba777d0da29e9ce21d69dc6419c153e7a4d2eb02f5001dde9970c659fd08d9535e02f80428de851167a22dffc591982bc5c842664ec779d489e883a4863319b51ff75c627bcc678615f27b9b55b8eb475458cc65a882fd5815a28e3b3ee29e2e9eb91ca0f1e4bea096bf37bf40a3b7baef08eb9988af32c9ab1338868db3e13048ecbb5851b +Msg = 7efcd40347389e6fe10b791e53753825b04d27323bd74cc1ce94ed937d5e535c76b4cdbd2b52f771b4043bcb6ebd9960e9e3a40101eecdec4a31e442b2f7dcbc61d2cf9ae43041dd8b2fa9b60fb32e3e78b5ae673ede0433af548b2490d4def30701e285b9fb071a2f34cac87e7f7f28276a4d4f3cce7affc4a4e81f611ae069 +Mac = 0829a099abd50327669d003b67678bb9cfe3559db9fea54b13647ba1db19d0a15b49acce0f4413cc + +Count = 255 +Klen = 139 +Tlen = 48 +Key = 77b60a4989c45160c1e2e41978530e6b5b62f99f1c480c57675076ce18390b61abdc504ff30fd1bd0fc8bbfd9b86a60f23ecb368ddafd7f397b37656ee713476c19c083de504929b1abaaeca3e7549d7c134735e5925b695f7c6a68bf94abab2a13e5a9cc66c3902c900e50acbe99dc91d826207f87250436fd12ff7a18c461e330a6ff2fe0f71fa04e189 +Msg = 534c85dd76baf3aa0e3cd31ace049d931b39ec18789d8d10426ed6499d8a393caed619930bdfdbe86fc241d0b34af318f9595f4e2b89c383a41288502cefd2172a3c558b15e36a732c7762ab67601a6bad39cfcb47763487954ac200ffc850842f48e3cf7d0cc7d2ab23dfb3d38e39149da2e598b5ad08a37ddc2c62ff5cda0c +Mac = 1577561f5f3c0bf523cd8cc470e9c1b9507bc6991a53dfe2735f033bbf881c513b3153172502c6cf0194fc00980e1fdc + +Count = 256 +Klen = 139 +Tlen = 48 +Key = a18a27748ef39b49be984e8d18520110008bc8a1d5aeb424bedcaee5a7e1a62c8666ee12e367e09297e8c7e3d4e4fd056587509b379daaf81949f27cc0fa2d210e9be951940adbfb55ccc7e5ccffa044318ff18af9ad7b7f9c7d1f939a0fff72c091e1daa7c3d4a97fab153b0a8933f2eb0d721621c86de0cfe100d13e09654824b09d54277912c79dec7a +Msg = 29c4ae3484dc27c0360343fd0b2058ba261ac3acf6f87fb56647f66554bc16c2451ba8445757dd2477fb2ad7d3c856d592a0d29ec3a348ff94977691c58d3d845cc1f59a99c304762cd4af17a69330a02ed9085a75e196fbecace92934a3d33ad57f3e3e3466c33fbf5679c76bc70ba3608c0ee7f2fb9132d44df5338848ff6c +Mac = 26a37c97b7c13097c5735bc31f8bdcdc27dfa96e991219e708c23d1b32c04d88a89a86a1c217724f4ce5bb580a1a71c0 + +Count = 257 +Klen = 139 +Tlen = 48 +Key = 988deffa74a9cb1073252f9fd70b89ae954b9b44abba7389b55a9e28bbdc99f74e6388dad38b2ae51eaa0dc04356fe50a827c4935fbd0eccb305a9e101b9f601ca269c8905327a29ba9de043cc87fe9317339c15ba0a0c23b6e35ddeb981d2d0345d92d0b3a6a1256e870fee1ba870c107f78c9265a857d6e67a23e98a3d14adb591d47585f0892163ef04 +Msg = 6e8c74df65f0a6708270eb9963f9075d0e4f442e4009670f01dde3f67c1d4d740e8210979d2962102bdb7691aa91f3791237a6b3b2b173dbc31c92a34356f87601c0125bf442b91bd09063a6dbac96b3fdada3a717be90b89669565248164db96ecee4f1124595db9b1818a09e53d752f736a3d11939a5eca24d97c933653487 +Mac = 553d71c6e005589f195283b6a4b190ebc88a2cfd9e44c7c283ba13666cb032de35a04fb8391fdfa7f29b9629cae6d2f2 + +Count = 258 +Klen = 139 +Tlen = 48 +Key = 2021755f1edb657857df8ab2ec9a307d9d984360e14706e135fe08a9b43d55e4e837e9e7e08d6a15825d1603237bfada55fe64fd00ff9cecb59dcf693e444cd97a30f3ec682ce98081a091c34bcab8982b4c103d7ae7e02adc86f93ccd7eec127d147ab8de404c82fbb0e53b8b10d47fc6892e6677873b6353c0706b89729d599aeb68916b4ffae39996f8 +Msg = d6a871085b50187629d6edfebed8e9476d68a512495e652844f25691988a140766d06fab9d086ff61ea196f11e0964a9cbc621dd32c3d6fb60e79d4bc7ec1a69e46f4af81f437b95f30b9c0a4e08b7c43b2fbc88be7f8061ff9105ddab71fc7898ac8859a8aa453cef3e89b0187cea8204cb0079b53b6c436b1818b00cbfc11e +Mac = 2f10f4d5303c5b237594ba5bdda13951be2fea63c02e0f2c1821c8798dec4dc7927b41bb7c41192f6cb1234a71de905d + +Count = 259 +Klen = 139 +Tlen = 48 +Key = b7c3c673bf96cd22a641eea1c83f036e79289af445e053607c0f8ab0efd2360cf4b1115ab0d0fa0d9569973d29793efd09ba16e92ed279fe70ca9daf48c17434dae2d0263393cb49cfef66a95e7770e8c704aad66e012842b3d6fa10bba70c8c723f4bfed047097f5cbca30aefa061d6bbef9de38bd428d34c1de9fccdedc7bbc3b0ca0b10547c5645b796 +Msg = a550b9edf71774d43ca00fa13da13ad1d59c421053b193ab20b87b44a28c30c95fa915a766fa393aebec208831c7c730ad3ee29d6845687fa522517cc4c79f22665f9b21d22761b7977f9e6b734199fe7451709f5d75a45e4b67d8e39829d6600099d3c40245f432898011b1ccb6b82573fc757efbeb502f5baf98e1e85bdf69 +Mac = 8d0af6a102ca32bdff8862a35f59726628818a3dd076158eef955e58e52a15178da59d8453882bd5af2dd84da7eb8153 + +Count = 260 +Klen = 139 +Tlen = 48 +Key = 41d7851e98c51d6da7e612c43aa3b87d56be5a01cd9373300f9d2003433bd66f97b4508dd479ccf935ab777879dd26dd371b462d722b16016d12142cc0dbb49eac935888ac987dc14c1432693ec4cfccabfee388c7f26ef3a83051b7586a02bf297b845748a9978e95272cdfb2de1b115a6e185cf56fe4cd69fcc0ec3272279bb575bc41d1348228b8ee4b +Msg = 767c2c4723f582437374f26bd6fe7e85882c6c9707d151a9cadd6fcb3081405ab79453806e3657faadb3761e03aae41c706eb784d4acf908a84efb84eca0ed3b60b1ac63f7fddbe58948355ec8cd216975988720d431e3e05d7a984db4da8696db9bdefba791358c70fdd8330db060f4ff748674eda738b85129ec30707934f4 +Mac = 466b3245ddc7a5beb00fd06ab35877ab60264571f16a1c5d7162442dad42a30c3b4a449c799846e44c96ba43c8c9b039 + +Count = 261 +Klen = 139 +Tlen = 48 +Key = 1c458931cd6ea07c7fdff6bf29c5d7a42033d8fe38b919ff2c39c8ab40f6e68c24ee4ea81c6af3b05ed3697abbc7a7b1826c0bcca2049e3c0ec29aea66dc29e0d3e27046334ecc91765c5bf7471cbf26efc51e35774c6ddb0d35efdfaaaaf8cff1caf7f55943b3878e23d51e15eba7692fe51b2301b80f42f13acf725385dcc1454dec9cd77131fa70cfde +Msg = 47c39405f78038cad3a5dde2bba4fc6f93df3e07e9be4068d8ff93672c4e082ac6162a9743960b0cd8374451801d37cb5afc97f24c2d2b05ed01cefca255bbbe0766079490e76fdd70515404b97b04b0c56a3b3ad66aea64f95d36483054c48ecf5c34e2279beba5629b16e3aee5eb869ed232c9cc9e05efc4bed4341d73ac04 +Mac = 800632a5afbe6e2d03bb2cf4e930b675864e93bf27b679b625f0724f17bb4a66e78cc06facc19945c46768832026e05b + +Count = 262 +Klen = 139 +Tlen = 48 +Key = 0eb602843c11877141d8ea6069bd65b7556c40a640c13dfe8838344769a5fb0d0b25887abf545a2a85c0153ad39e6ca291bc43c568b715473c6e941ff7b690ed89501a8d2d18e9eced7efd1a683a81a1d33cf6163ee28eed186ed691f6b798b5901f00e40cc4fd6080fbea29b2fa6e5c22d4a1be4aab7099242042c7ed0fdc0c297a81a9e7c25e2d461d26 +Msg = 67818341abb04645ef2a3f5edb0ceca2725a0f573993f81e9b88066b8c6d6c386d3131fb2f0b7bd5bc560c0c929e0dbbb1fb0ac8b89d3f174ba912fdb744e0f8d9ecfc9d3c0ff5d181d6183c044236fbbc7ba89563658f31d7736006c1c0a112745ced0f18e33ea307556cd77721f0ca5a83eea7821073d40990fb6cf00b36f0 +Mac = 0216330dac742a5b8023fb09812d8a08619047fd28cadc12f37c4443a9263262588d0c43661eb7d6b36a801dbdcee794 + +Count = 263 +Klen = 139 +Tlen = 48 +Key = 2c5354e0c3f86ebee987fe9af1db03c7f376877867c6d325f3a7df30822a0cc99694150fdfaa43770c2ce172e1a0f04a8a501c4d2f96ee2ec85742a833cefc64838bf71d9cbb3e02fda97f5cdc85bc70786544a7ab89e2ecbee3545682d6fe079c3fe05421b2c6266306be9f0a13cf0166bae8cc032617277e52fb8198cb7c7889b8b9fa971742aae64988 +Msg = f784430144b3ac1e25ae26b68b30ca8c012429013417ea2ab2eeb426f2d44eaf957704eeeb744d94b90fac263928d498636b0f1e6bc6e03f8b20e72b0248064e5d2bc225f54bec51b96c80ea2d90cd15b326d6d90a7ff92e1481ce57dc9f5272d709454e6a1fd07cad2c6ba96f51fe2b7abf46d917297b20d57a305387c37a43 +Mac = 993a5bd06cb1062b06a2956744f0d74b8ee6416a7e9ca44964953684d47250049dc7f603bd4b7e541770326cc0c8fe96 + +Count = 264 +Klen = 139 +Tlen = 48 +Key = 8b80d993c7f44057d20e8123f8377347ddd4f4f96f6e7d991810fa3a38f1d85dd2535fff86ab42d7bf0274d92d9b3efe76d68f4728549300f35c8642157ecbbb157638b1b453b54521d805f56c22e3653d8b515fc6cf2d18f66d05b5ef502c0dbbaf0db13a32c02a5f56db819c128b059bbbe3482f25736b8a0b1d9bb0b024dc2cc7860501908c0ce3459f +Msg = 003ec4e4208538ec15be8171a8e1cbbc8e19a3f4e26a0ce4d297cfff984312a1ac562c9837a2b8e3cbc7e8b952531dce452eb4d11f36223910264341f5bcef31881bcfe0d46e6e77edce9377dd66cffee1d45246d6d3026eee17cf7da77940a4fe5452c3df2f832fe19c2ab3305f09d4cad32559ef8ad60bd2341aba95c22e80 +Mac = 40e8c2efb1083622a677b59fab9c008ea81afbc58bf719674e6a71bb94eaac304631427abf41acb3c87dcc65dc485b62 + +Count = 265 +Klen = 139 +Tlen = 48 +Key = 0fe553a781639eb8b8c2b12aa091f59502c1a01ffb4ed143ad22dcd13436e236dbfaa6fe90f79b9796b242587ad4b2c148897805fe26a2c5410e171f4fd62ae735a76e3442e4cb1fbb0dd1c7d0e44d99cfce1ace987b3a3451c925325be6610684b553527e7455d7909b09808b07eca200572e82b097c118441cb0123eaeb21c30edff5f2bed62477b248f +Msg = 1a84994d864a65d08ec6735d025837e91730abd5b958441222f5258aacca94bbe3fdaaa5df1e4ee7d1656425db3b41ac25fc62592dfc5eb75ec81a67e5ae3cc5c07fe2c81793932ad00e76c95e62c14ed915750c54c5492b6b69e3051bd94ed0d791a97ed7b11ce1b449111332d4a0155c024ab6d7bbebb67060ea2cf754b325 +Mac = 1d94fc28212de0e3d3254b7edb00fe55d2a0fa823714329b5a2f7fd502d4c71955988f54e6a08929b687b9ea47448d5e + +Count = 266 +Klen = 139 +Tlen = 48 +Key = c0fdca48cc354a8cf616cdce0d80c39113bd5f0ef163ea346a7b5ced4ee22da3f0f06903d9580300be4f6b1bb0f162e293e00eb7d12e49d3507d3f8ba16438d17a15b2fd663db3cebb2c5dabcc36c32f6159fbe564207550ddc68a2f219f58fe45b4cec0d9ad03fcd3f5cc06ca188d7f65704f1f120013b2fba06661365b36333b15e4d49c709a94f0f1df +Msg = f3ec088ba8d08bb36350413144d285479d39408abc665c8904fe7caf436eea6b3f2dd08d9241acf4b805fe66672943bf1efa274e01e4f77ce43555aea6232f6dc011f2c51d0efaea2d9f4e2235be8adee9221c2a3cc1b3487794f598889a71bc9d1fd4f8f23e5fdfe7a5982c569840ee233986e815067a37e4a3c43593da969e +Mac = 2881746de7893d92c0a0421db7e7325dcdc4860d3b10df1270c508c531d0505100d17d48c2e55766200750dc03e1778d + +Count = 267 +Klen = 139 +Tlen = 48 +Key = 05d2120be33cff0014bd83a4da9e8eb642c248534e3a522252134fd09f72a4bc5fe47bf3c0ef0e5e55ed223ab91ad1c975eb8d4723a16220d41f7b60b0f8e86bdccd9feea1d6c015cabe1dff4db4f96f2ebf10c4a151d82b6f2007139a3155e1443583e5cd199c8d3cd97bd9e0958d0f37e6d8b00e723caaeabef9cfa74472865fc631c18de12a2f72e544 +Msg = e733c695bef2faec2b99794ea1a06f8dbef895ce2394a630822813aff831f7479e354d5c5b4c6159fcdf849886b00482ca1a5bf73b9ba7f0fd8f5a623e3e3366c9196d98d84136bc2a4962a8563d615e5fe36e7888400ac96a5ea941434dab1191688d10e0d9615de0607b46ba506e69a4da3719b48db704f11e6712b0654790 +Mac = 8ef1c2ddcacb92e5a66d02e008d4e6830c66082a1188047826a3c08842c126c3d0550a41309fb69c5fd12d5f0eca5187 + +Count = 268 +Klen = 139 +Tlen = 48 +Key = 1f2468935aa2a207dac977e94f5b31ae68191bc5e9883679fef52d18ceb78b5554b42ceb6a27f18327a0b8d86b4c8c19b876188f444e627f4ce9b652aa8adff3aa209e791a0f5406a03302ee5122731c7eb2b8b2d1bcd5f0991fba576307750eca6fa58490e43257ed8c3b752668508162d6e278ba5af7948f9d227020b6b36e5ba92b56f42df33fb5b34d +Msg = ea2f8f950949227cab95e57a1c421f4880f1bcb3ba0d4d978d5b4f0a01d2b0d809ac8f3062bd449cbe04a0362280751a8d445917dacea8aae795c82cf7e1b14a55dfacb63bf55a1cf153f95839cbe3e6ebe25799dd277c9005c3a367e252cdaa17f16d8f5a986fe48cab784629cb7094e3f23ea38abfd2332f0e692289cc0ce0 +Mac = ae673ba704e7b8f7adba1ca451c96c9189456220c8b5fd8f3cd87737c88390b250170936bd9522dc021a1d1593034c40 + +Count = 269 +Klen = 139 +Tlen = 48 +Key = 07d1cd3f695b642016a3dc06b70140a2cf3d479dedf42921263db19ac28d93be36d801cb53f9790fbc54e1ae9dbad5a09a8d40f90624296d5670d013d5e0fa6999838999b56d4ffab05b24da369a367b0e24a15b4c0d40b8c81dc254cebf007617198d31f87d8fe8da00ce12ea680b3b124c934b2776140b648caee517f04dec9ae4371c85f2e1e2228b07 +Msg = 156fce19f4609057ee8df69cf72b33e27026509c4bb972ee6f3b5c1d5e3c344515d08a4a342b96105e6ec1efe3c168619ca2dcfe177cadabf47c280e8fa01e45e011e7d79fb2a7eaabf9d0b7acfee83cf7d18d30b311b63c3aba3b68c23f98d43dd9eea87e1e4a4d9cd52ade9b093dd9495c6b1b679e150b099e9e1540402a5a +Mac = f3a6a3c11b618d5af52ec6f501a6eaf90c889297316a7ab6ae3e2c65da06e77338d92a4ac0fe44a96340c9ff18a25f6c + +Count = 270 +Klen = 139 +Tlen = 56 +Key = a08e14c2671ef79f81f732df2df3835ab0cd0db9e190fb88eb4f668c4f1778562822d218b34d2cb80ecc3b23401dd8e47a3a5ef59d1354d4fb3b4cda62e20ac95703e9a49fde7bc304a970265583b90aafa9edbafbeceba8b863c1bcfb5dccecb399210d32ba2ce8e9f59791730d6df4d68180b10504082aa92d8cd9207006e8c64d42fb74c78751471879 +Msg = 0fd5e53b9797cc3ea75fcb7e70a93b80b54091762b0bdfb7252a9e6d7042aa8d7c148e0dbd55025151b9b2e6e3524172cf188eeb87c9360835f35af5a24ea24b5650813f01fcbb1a19fb25e9c5edac75fa019975e3c314038736e64da623838de3b0473b29340080474aadefdd2585707c233b7c09a48190621ccbdb4467553a +Mac = b07d4e89d7fbca2db335e807f9ec131dbc75b878c513f6cf6595d7545571fd1361d8229dfa6949cd97de564462937b35b92320e3ab30d9d9 + +Count = 271 +Klen = 139 +Tlen = 56 +Key = ec4698b68d26f2fc0428f413a0ef0dc4d6b0e6233e2e8b1cdee8cb4fab90e11e4dc0540323e91b27878c053153ac585ca383b8cddd744b23ef411b4fd87ebca66a452e344e2c04544874c67ebc83955f72940d2f96ae703f03d200d1c179ac2dcb3eeff116d7f6a9d049019fe55c0bf5c84dadf070c44097a105427d6c6afadbf9115fe184d2374ea6747c +Msg = f1450e17beb57bdc8e2ab1b9b6b35553993681e8cc080d8578bb0d7900379a09e40cd665e6072adb6b04d24b23029cdbec7decebf4f8044c1ed982aca8792a550a7ce618215e0b838c4fde5b57415746d63f25c7d400f16feebce752393e73b92b3b4816b8e2a73dbbb4ded098960ffb1f243262b4495d58ad0c4352fcadfc9b +Mac = 664a4b280edef3004ca8032a424206083baf4ed3f055f1958d84d7deb8ec7eab7f9285a3b0dce0997c07b38eaee1853aa5c6de7989338d5a + +Count = 272 +Klen = 139 +Tlen = 56 +Key = 7ee879498441719e0d48af2010edfdc5b28bd4715fb214d21a29f7881133488a7512d0c588ca1206f82738196b014c335bbfab8d241ab7525b24cdbb628877783913e253977392103a3f54977b38745525cf31df87e76ed8c8dbaa167bc3320073f3953ad9c559857b99ece06719ddf3b9c24caeb1a0a02e095878e0856ce3e8cbbbd3c47547cf2c653be9 +Msg = 378385ff81dd16b3702920075bf93f3c48c658aff7e3c46623b0b0e90410c353181d02a8231af16975a8fb666b3d14d438d39d9fe5dd8802977fbc5411febb25797682895fcbb1b4fbe1ebc7b61080eaedd2499bf1bfd44552bcc1155d6f6c09e3f6cd4a3cd89cbb8c3bb8d24558c9a7ed2d244a2271f05adbcd87d3f0491f28 +Mac = 0c79d26868ba4802dc8af7d0ac89b608b6a1255f005a9cb65755ff98c4e6f45dba10dab91d0bdbe9f15b0ce693cba841c0bc12ecbeef8227 + +Count = 273 +Klen = 139 +Tlen = 56 +Key = 97449ca6c272484156c84d60b7afc1cc59546a46cba1df1bf56beaf89eed31003175151cc05ddb92493d09da385f13ad2e73375e0184a66d042be45a880371b7a25ca9812f34e9b01663f30dcd1594441f7d843a2cc88da0b150efc9891304b87463207e18dfbbc345a1d2a27db98abab4da17815454dcdc8442d3edaa05302c2ef141ba824599f25f616d +Msg = a0be64e0d1c2cd877e16048abdc5f7f007b30964eb83643803b78cab28193a67e25a674e22faa7763467b872ef695bd42fbd62ef85010be22cd08cd23f2def762a2520d95fb0455b4ad94df9861ecccf511a06db3d61490429ac815b703606a06065b808eead4e3da7b2eba7eaacf2ea55101cb07d6dc8a8e29392cf22fb26ee +Mac = 978c5b056ca1342170b158a73704c35885f5e8db7d76c2fe74466913103df9dde24e1100413bdee4347771ae355150256a8df0a56baedbb4 + +Count = 274 +Klen = 139 +Tlen = 56 +Key = c52103e948ebf17ea6b3303a479580ad0748c9ef2f45aee4a52c64bd5f64c5c21d02a04f58ed541d753f9dc33feead7d94ab7f2b5e0a689dc6e4ef0da4fadeed39da99e42007af138254af9c8a913d6518696419ba8b2e70d80872b12efcee757f7195ad88802ae634b90ecc0ec657edfb4a21c0290f29e6436198afe7b51ce0598f3db479a2ef20f23863 +Msg = 6f8f23414c2907bf8c753b13fd1b9e320fdcb80f366a4211907de8c4c8234dcf3a57502658d68e804c2e270cdf18c65f9907dbb129012b4a08ae8b375aafe84115308b2064c19beb4e61e4d393dcd611d658d11d012aa021e6ee43ad22d6f1ac47425d973a9139e8d937f8d2e110d92f0ff521ba868ca77e7164968ee9416ff7 +Mac = d65b12dc067e2b1eebb59c6aa1b13a02bf7c2841422952b4379c61324897b2906832dfde7797a644f5ed9eff9ef0dd723da7fd2fdb7cc120 + +Count = 275 +Klen = 139 +Tlen = 56 +Key = ed8269eb2ebcfda7d381d4f8a5049edc74674c905ae675624453f8c1adc2e396ad8593d7335b1d588ee4ede53358ad8fba79694329c6f0a175f27d0a469496fbfb20359aee16268ff979b015398377511197a1e2727738b95ab7cf2b9b726944de3b965fe756dff31b2964b03fedc4cb82a93d96be611553fb8a384a35c222195fbeff4ca784112dfcda53 +Msg = 23fe5ba70eab493c715416c16050096e00be19748e760c8fa23fdcdfb5425ef4e1be2528e9fea531798894f6af9896a2d9cc18f781217ce6a71e775c4d4fb85e39f5cb58f6fc3cb21c2dffa5d1a50f4d908656ff29eccddc0923e4a6bc1724d3b00b13e03c8e58e8e0ab1f75cf61bf96aa539a328fbf459b52b4ea660a80ea7b +Mac = 8749a3f31a8ba6373caf881459b4bbe7b57a217e399e61c8204557c6d10d45b9fb1bf4682054076fcd8b4dc5472a865b5c7e7bdfed9ef420 + +Count = 276 +Klen = 139 +Tlen = 56 +Key = 3e0913221bafacfce39482279ef2fb3f06eac4153b6c1eaeb856788f86e04337af3702eef668a0bdc58007be67f1ee967738f23f99bde90b68fb73e5afe0d1dadb77fbd9b0c4ecb73cf0417609a602c797bcc0cd0916e0241fc73622647ad65da911266db18b38f32e2b57daecd6e0dc4dbe5448f53daa03c603eacd0f74f7c6004cac3162852b77857a72 +Msg = 82e05400d01a7f3843b02d191cf0477e1ab1190c9be39e69056afea9642d55095569b6e0224c70d22ebf8f479483a61b0b7fcc980d58e5a13843232ff417cc0256a73d90444e2f42dacb39df0d4f96488ed52967f1b2be620f6d9314a9d017bd4e3ff1f87e4944ee0f7d31cad07f9e6d6d5b36629218b1145391563ecc80bea4 +Mac = 4b80f01d188bed5cc7aed1e9f5bc16595df37fcbc8732d668d228d4cdfa60b66c4d9b5becacb2eafc28c31db904c41473b31a987ff46d3f6 + +Count = 277 +Klen = 139 +Tlen = 56 +Key = af28226e910a27a751c2545db05f91b1dda4a121e8ae3f5179d76d0bc2db0984b239a1e16bdc88f9f7fb295d363e9c961b2277ad189ee7f1d707fff42b314fd746d7b9c72c3c80c86813a2b1fd9c68789f113bb02340b950357908b649aa6aecd4c91229bb72379b0bd26663ecc31ce2d0389433f0dcdef8f9f6315a0290824bc2d8550e00c6d4fa4aff1e +Msg = 5ff266343b057668b2a5c81ae08ef906e178afc639eb22457355dc76095abd46846b41cfe49a06ce42ac8857b4702fc771508dfb3626e0bfe851df897a07b36811ec433766e4b4166c26301b3493e7440d4554b0ef6ac20f1a530e58fac8aeba4e9ff2d4898d8a28783b49cd269c2965fd7f8e4f2d60cf1e5284f2495145b723 +Mac = 047fbd637fb3d82f6eadc40fd8ac221ef3e33cfddf6f4cbd8be6ce0e2278980c241a70962efa61b67ca13b8b15222b0a589df4f4a56d8deb + +Count = 278 +Klen = 139 +Tlen = 56 +Key = 8b5b16537dcd2245ac73db5dd4e6febaadd025ddbf663b52783233937c16f9293c8ea914ca35006dec8b104a6ff537e2bd0551f2b2fc2d5fac8d3e1ce1e4934ef6e709aecdbcc02f9e8bcbe249852c16ea25ffc3aeb5f529e61504b45ab85d23e0ef9fe92d6a4ad3eafb76ec0b9ec59e5cb796195c9a7bf94f50ee228f993fef232dd18d924786a1f96478 +Msg = ba33904d04c8b08bb2c9d104f62d579901f0a23dc8c3ee4b0802771d87e6e1da9efcd88ff4d5f4828cffdfc30235b90311d3bba9598d1b235f5f307ad6c7d72a1d33153008b5fe64e3fed509b48a74a3c118ee08525d74bab8f975748eaa09033fc09057c9d196dac0adfb019594502018a783823c9dbfb91ab78e3339f6410e +Mac = bc6f6f9ad5bf623506f1242364e4d9c94b8624c86b08a9af59bcdefbeea09bf0d8c7b2cc84578b518945c67abae81f9389b17c5bc88589ff + +Count = 279 +Klen = 139 +Tlen = 56 +Key = b39b9aa4e2c72a00ed85931dd26c6069108aba7cb0578aac86e8dedbb5658e9471bd1f570998e730248e728e4a962553a7c121280c286b133722494b54bbef4bc4625a251ce27d1971949b66d3d2f46017aea3c3dae4c747c20ee17407177db832f215b7258c32e25cffd44b720814b7e7bb08f52075e76faf136dffd561810445d516b42b7e4fb46d37e6 +Msg = 5c3a432b965ab1b6bfcbe3d2902895a2af56a8ce3cc560dea6f2cfe7c431916a21a9ba7997a00d1b1ff96ff2e7fa9b1ba55316562c5c66673c9f7fbc9f967e4f71b699cec0ac56fa55e6fc4dd05547dffb71608a587e0c4cfc0e24eea0c845e3f667c8733906f519089a732974c003b558b96fb2e9b2bc578d49a7c6f14e50ee +Mac = 653cde316c2a653cac8b1f6bf9bd5c870a606def9c113804130153d76df6ddb51109a96fc022acbc020f8688029f13e0cb0ad67301a6c4a0 + +Count = 280 +Klen = 139 +Tlen = 56 +Key = e7e687fa0e3d5d25c5a8a8dd13a541a9292e8386e733f4f2a2472844259ae33ef5277ee5da2e8c909ae5bd40086b022f3dfdf1ac266c6c253fce7d869d7485c2321d96ae4d691d166091c40b0654967a443564030fe368070ff92903a3e79e1d253096fd6fd758de9e1386e5164a47b1c63da433ad8133c09c2ef3643edb787a57c94879495e8411dcd5cb +Msg = 3d0278735b4bf056152f4e5aef2fe220541b0b1c3828fc48fc43bc1a92a470b3e1a5dd596bd529272d48e103c63241d1dcb4afe6bcf688c040761ff4f6a003677e9e81c134716a1f10411709caf1a9a341f795271d6b6192b35da89e2a6c64f1dc946d94ff483ca685c1f5524095a5fe4a8bc7c5a4ae0e281da05e0076311bb7 +Mac = 747d22793557864754598e570379f66cc46bc439e68638f505833ecf6c51b70403315ff216d6664c0c9b3065f8ee9a48077b23a7bbf68562 + +Count = 281 +Klen = 139 +Tlen = 56 +Key = 1435f0178e91c13ba11f03ee55d6a4fc9df0c3943641b840d2c8541a7684693e21888d7bae521c4efb597c104be5a56ee923e01a0f79cec00517ad3c8dcfd70a7f268bfdb1abf0341987574b3656c1ceab35a1f32e1ce388a06f2c2a7dcf64b8773672075e4346d743d21d06ddd000042c4e8e875bd3fc80ebf75a4d0e2d183051e1c8007ec3251ec16255 +Msg = f18ab3088ab39d5ba081437d3bed8561d3a03e06b5c0c6f1a90abcdad22102a6d52508953e884ebd1f1d24b7f972b598e0604322dbe0b43c8a204ea00bd7bfd41dd5605b86deba2cb3b84a639f838137f6490f2c79d66189a4ca680d8eec9dde12c142c22c5eea91a57a3bebf3c7f3265b83298a5849d6c1402e93892509a4ac +Mac = b219778681f759a0c9ae6b9a8f74d282d47c0278184c9c89629ac8be7cfc7747dc957ed94e5f1c5c6cd3081f98c0efb25f24e1c5d4984a71 + +Count = 282 +Klen = 139 +Tlen = 56 +Key = 67a259321cab0901526602d1ebbcdfe5f21d9a5bdcb9f3020ef3166ba0127843613a02df1b9c711918e9fd5be40c38f955183ac4c97ffbdcaf8600c549f53abdaf132b4d18d14a1f5546a90f9e5bd58491c8fd01783f57f7cbe6c0def60ba3835b141ba49bb45cba11654f16a0127c2faf132d3b715fd0fc6afd9edd2fbc7a3d6d241c0b2cac6e93552e36 +Msg = 8f18140963d761c2956c66a83f94b88c42c0dd70e7200b3bc60031b1e7573ca1289d9360dedee377bf0d2299009aced8ba46761892377cc3994719be71a2a19cb29009128b8fa6abada537bd64f4269c078f0b0d938c72fe935bde7443560ec4f4987e06b21331c725ddaefeb5cb4941f141a339324874547be188b9a49a0881 +Mac = 8b534eff22fa08f408f8f7ec5b300a5320ca0df43d41b506a38315be34536295a1e1c7b5bb9052d2be32e03fe0a48f6071d870be71ddc7cd + +Count = 283 +Klen = 139 +Tlen = 56 +Key = e6965a05cf02e24aa7c20ada24045aea3746678a3ebba7297bf0855cc5afb1db7d24baccc43ede45eb58210c2b199ca19798187e4ec4db9df504c23b651a90dca04d868f0ac73473d63c8e7abecc426df72b493064ffbc480a89ea9ac488a775375ae7d309658bdc4eb57aac43e6f4563f452329e632f332a0c924014ac19eb02b93042229df8b893c0c0d +Msg = 13bd4ca671b6688488a34f05a5a868840a1395ea4c35ba21fa7179cc7f9240354a6186862c78513d0151fcda92a237dabaed4fe9c852b05425a9a8bd37cd6d12843a62c01bdb9623301d8d41064844b9120f6ff65d6605a82a93fe75d9885ceb0b7068ba07883e205c308ba4c842960759a27d78d216c1075058055c2d6a13a9 +Mac = 56aa0a589f3f732d3828f8ecee6b22ab6a56af8eaa07ea840e61336abfd5f71583ab2577a3865b552c0b0efca3ce988af9096b8478f0677f + +Count = 284 +Klen = 139 +Tlen = 56 +Key = 45b07738277c0501b83ca6bbf19bab8544d1bb7e231a73dac16750351c54cf263b5bd218b447465572eb0364b513f3955abb77da5d7f06d89c53183ede744256139fa2dade807d08506d27f8f754232e17f28c6c3746b3c9df460a07a1d0412256e3ae25aa0ff241db2ada20bd45837702dec2dbb858c2d513a8ef386d5013b28b91bfa222dced29998be3 +Msg = 246690b11b6910d8f438d91d8799a8199a889a4359d942b60020f935dbce756c709c9e78fb2d9caa1aee3588ca42561592dcef53fe6b04054f7d02b9719d4f062dbf2413a0df9f58ece414a92dcaa570af00123a5e0fd2757d7d62779bf1ddc3c397cd88f4c6406bd0e11f86987bbcb158beaa005f0dd18df2e8c1774210472a +Mac = 6507b66e18d6927d0b525ad606d6dedaadcfc31e089c9038f5a364b48b97a33c1015b8441e9c8207a635a1cee6dbb4ffce58770625f7ecd7 + +Count = 285 +Klen = 139 +Tlen = 64 +Key = 95af10920dc788269e70b8560b73135cf7f6f5b04a502c7bd61cb74f3b8ccd160701224922d865636a860d949ae755b970d3858c0ff37418a2d24b7142378ba11ab352e5c876da1a076642728b73916b2d24f8024876572363e7036510cec7f413ed28cec749ed33be3adf56a8bece597612d478bf84de85628367946df887f73dd92d6de7faa896d7276d +Msg = 61d91f317a902ea0944e11e92e6657a589e17abc027fcd869ff8b030e8870662f8a9e91ed3239cecfa42c0343d66cbebd1c2b771a25df7baea5cafad038424c97afb720e644e7d1bf5b829944ea2cec69766e68e4e580976de071c2274c0c5eb0e5421c9d51bba76ac39b3d009204680035771d9ad79eb02a3805d58e243cf0e +Mac = 6e989ec9cbf010ad6691a672ff4ca90a00275f9ba4c81cd147cc506e1dbc8bc93b1d96a375e493503c0ac697f7c45e4fadf138242df7e06e677de245afa97780 + +Count = 286 +Klen = 139 +Tlen = 64 +Key = 27e6c9f270b9855c9658ad0e3d6c9a111a624f66fa64a49a0688a49b454733ca6230f451b0dd69b76b275cb241967e3c101b4fe8f2023d77772210a63157854b763239a061eec9df1aa6380f57c6911d23c0cd2edf00f63486218dbf35612a17ea5262878bd3edfb2b3f08ce8ae419dddab792e0c94517fabbede38e574d685546fa35ad37741d34275996 +Msg = df24279bf8277ad1091972b82594d84677e54fe5d65786d19ab5b2c1ae0a3cc9e7abb67f9477145d575e196633200f0ce557bb5278b8902e1496233117a7df69660bfa87068aa73de61e8eeaffb179799f275086029f47c323f6569bd18dea15054ddafa73e89c3a5f61b98cb2ce7e554d5df4cb9d95135a70de33470744c393 +Mac = e6f6061275a89345f5463cfa198d528e14047d478f69ad7a73432f18f88bc68a1b8aba2c3b025c93b25deb8f403763a55024408a97a903e95f0cb6178e7be389 + +Count = 287 +Klen = 139 +Tlen = 64 +Key = 59aa9d7f583f6ab90b472935aa6dea95e2fbe402cbf70c6e1992e61c96c49b63d0304daf0e4da7c889c7b857d92301a6aea3cca7c069c03809deb3a53155bf6e4aec984bbdb31c6e84112c089a63bb0eb0e5243d22d6c15c29d7b9c1529519162fa7275d4cbaf33264eb2e50d5743f57528b94cdd8873662e345a178e1cad2e2e729a1eca3a7519c921e66 +Msg = b9a8865c3a6ba8f2c13f35730b39fc3c92405c06bb6e116851b84d9d32d20a88484d9ff5bb03922265b4ae7e87f155b0ba3917db28638321fb3b3c661670505603aec6a92d0776a550971ee52d68b15a8293f28f39a84231e050b6ce59316dddd31221fff940fb846830ac316765b940d29416a95807f7a0e73fe35f63dd0a25 +Mac = d78285ab97dffed5f16d00a7f277eee9e9bbbc5eb14fab10c189739965fb3dd1c196fbe3b01363260bf688955278884812286dcf81c25f1eb17cd2503ffc7acc + +Count = 288 +Klen = 139 +Tlen = 64 +Key = 51f9ab865146187fe650e49d45421fff28c45c3bd8c465458b762d93f199067e0afd14ec3a42022c9fe2f321a272bca3cc245022dc917b8c16b5d471dd3bed6684fbcca762c29f002451abed67a8860087848683b126795f4056963c46a8b4ea68febafff04e57c21da5f348bd6ce5ddfeebe6a6820bc584b1605d3a5366c5d35e0bc63e0c6e923c31e7b2 +Msg = b96ac1ed835f1e58f5327338fd604fabd399bb65e6d9cdf716d57a512398ac86656e94d0be0142d4cec27327658aaa103e818290ea40429f0a32b2b9c1402d9969adf845853ed24af79fcc4974025bb23409acd0eee6370603c19758fa59992c2cef9352c060f743da9127a6100f8b191ef7e22dda14d5b26a48d236b42d17c8 +Mac = d6aa880ea45e0ab267e47374598086784a7db2169043073614c4a1917e90e8dd2818f63bf8a899d0bc615e60abc57d45e20638dec691b4750a36079a330e5270 + +Count = 289 +Klen = 139 +Tlen = 64 +Key = 9cb3288f3b04f0442f2ca8cdc41b0f39ddf93f898868e312d509a422e941e4e64e3daf8b8d33eea4ffebdecce07fc18ca55fd47f8f9780b38155d4530fa53383d7804a8c14054539700643811ac607651901f01ce02d2b6e2200275ee732490be084e2d8f7015ecb2b84be339b7a488ee0e97ca9a0b24b096013848a9a6f8f4610525db85fb09f22d76d36 +Msg = 96a83010f9d4f0405826e8cc941190e07c33d933362db680e1b1db3a78ddc47cf9c7fa3fc75992cf4d5ff680e5dee89cf8a7c3a1662d04a928940a2a340a1adfa05aa6060bbecfcc39f52806fd96bd215ca4545cef62f2348969a1201af7717fd38abdcf8baeaf1f621306c7a4e21756f05112cc9976870a4c582986f34cd143 +Mac = cb700e68aec9448b67ab8e15d491aa070242b4430d6c70db6b736ad66756065f417c0b201395e203c57bd7809272ce34d4dfe1972b7c5277a28d71c7f52c32fd + +Count = 290 +Klen = 139 +Tlen = 64 +Key = cf44b9d057cc04899fdc5a32e48c043fd99862e3f761dc3115351c8138d07a15ac23b8fc5454f0373e05ca1b7ad9f2f62d34caf5e1435c451f3d927940e8a92c805ee3e754117c45fe0de0545e7d1b3f0b71912aa2deef5e5ee661a6e95a06f8727ea158000c91fa067b03a7378066619bd61f4ae33b7ec2fabbf1d0dc3078c3ab0a5919004c159f7fd79a +Msg = ff24c8943c8e6d3db40c7ac16776f756c44803ee07a3c95bc594afb7c599d0031261ad0e4ed41f98495391b8d3416b7bcec2d1ce87c28e9e463a4b3d23ae05081cfbbe47654f7254ff794c008c631a3262dcffd1de9b67e4fa8140f8221f68c24478610627084cb8fd0515603be4ebc3a81ff3bfb4363d770cf4f7b06bf3e07b +Mac = 2c537d0edfa86126672ca6f0081e8c13fd161510d56c0bb6ef015ec35cdcbadf4fe68594fe70820ebfd99cfb83a1fd18febfde2743bf408479a52c3334e39141 + +Count = 291 +Klen = 139 +Tlen = 64 +Key = 0f55624e40771d01c2643c2bef1c97d5fd0eaa1ede76953064e96874a92e9e02ae50e75c42f12b5b26e1cb696ef02af12a006c14465e7d9eaf525538b7f47bdfbb42c89403706e55e97f394d3e111448e97cce69d11d1e1ffeefe555fb5bb4e97e528e604a9aefd855650c3d26285dc082aa5985475c819c98e89f333a0c500a3ea9c027e117b5cab0bccf +Msg = 0f565c68deda3bc803d93246a1fc18ede3cf16d1e217adfcc965faab37eb39bbe48f895e883eee12f8839cd492587390dc3cc6dd688560e7fbf8c9aced97c56cd3ba1e5a5c61a39879c97162c13d718a132f22247d8799825c3bc663c520f8672400a3c623ec6242ced3385af4541bc1d0d1b30ee8c55fb536577936862fdb94 +Mac = db88ffd6256ef15c09d67244d84d4ba61730ee6eaa565cfcc4fe587e6a950cbf69a7ca19ef489b68f8dec772550795198462e87ae414ad604591d765b6a2ad0a + +Count = 292 +Klen = 139 +Tlen = 64 +Key = a50b14fc2b1852542a497dddb86709c49b3285f26af9d93fef69cce2d0a3c92c6e91e2770e79155937d2ce1d5a57ae73b95b8b66815cb88f39da868860690aa4520621dd6ca7b20e701633632bfe6f0d5546863ab89f354495595728437bac3b1912da188ec9b1dd9fbab3977184d4fa389e7e5657ebd8c6c98e48abbfff37588a5e140fbc089b2d8a6957 +Msg = f4d6aedd9a34e0a1822362714d4e81794b53b266417678c16a97887bbb612cc96bc5e532b3a654e5d3d65a5155427ff09569906381138cc49e3fc2384c5d33c34abd3d617c487b52ec6ee7b5105f41584b7eb5cfb512b8c31f3f338d5236e30398a8ff927e801c8ed7d14fc5040d915a737967d166ddc266f68023a357530431 +Mac = 0d99228df5e7ec538be55d8852a0c4ad0ca61befb94f988d2d3cb68c006c0fed69b867e1a4f2a50348890fc1ec82c46ba72fb8d585376037f94c9fd18b67a839 + +Count = 293 +Klen = 139 +Tlen = 64 +Key = bd619ca4cf382df22b99f1310a6498633bbf0100220a578e011681727691b90645c57aeb5883a0a10459cb548e0b04f9ee41a39ad27e6feee651082d53cf82228540538232196f7c982bb19106197da69d0fa45858b1878f4a52805627677dea063bee1065e4e2ac6e756c9079754c92d190cbe1bb8de799b480b094fb41f2844f1c143efaca40590ea0c5 +Msg = acf723e38ad26db1560747fa39674eb6d8546af98625a677b7cc3f47b8b5fae79ef2bb817d96546cda5e9bf66297bf61dc3bdc2b5c5ecc93b9c8415842e410c4add9d0e950f6a42b945355fea6b5a4f16fb3deecc717b0b5e5873db91a656e0ac0f389a46dbb06f46c2e9e9b6d8ba46f7b0298c22f1afae823505cf3aa00bbc1 +Mac = 3c13c0897926d1d45c67f68a4e1c1bdbee8f601affa0edf8ebc6b567d920962fb9f14a4fc92276ee1a266258ea7f71e09241225053edbeb7f31130b36022dc13 + +Count = 294 +Klen = 139 +Tlen = 64 +Key = 107ed9ca1f16fbdcbdfa5211b1a9ec8d9e03bbcb1f0a468715e99fdb403695a80d742a37afdc4820715daf6b4be132f6b3d22316b5dc0c8146f59f6cd69bf0f0245de2b2569ddfc34994cdc526973d503698e594f7ef503f6f5bd4a1c043c50dfd42e8833ce32a8deca9926769537562ce5de98a0bca7b87372125c127b67ac83f2a24f28835904603a3e8 +Msg = 204058177a61aa45bd666bd0f3870645fd6b9330cb91a89ad3f072cfbbda04655926ee79de8e123c4e56b3af342fcfaa935aaf231f10bcadad22943fe9dd5d3747305a9e3c11bbaead1cba91a87de36c5211b39c20c865404a4e09f77dead6ebd1a6c10efab04fa3c200a701b73beb9320d7c82436814c5991bbf87fe1ca1787 +Mac = 1bc503398a25223fb9e93ea65228d2727b201f0a3fb544a300dc804340b6ab3676862b6320bce35adabef387ec628da38277f7de6929c44810c47f2a7acbeb03 + +Count = 295 +Klen = 139 +Tlen = 64 +Key = 8aa3ae798494805441b45a59bce230f9b2bbb960b15f2456727807636879983799241f48ad4fabbd44e7048b8d35e2de15605cbadc34a3e2ae21f0f9b087bbe73a312e7ee41fd95ee488a715971f118b5d96919eaa605a095abc468a45ef104414d0c362538a72fdc79e2a3f012725c933624053436daf921e4ff05f4f39fd15d00cc63b1f1ade63953175 +Msg = 20d04970ba4d2cfcb4c4e1cfa3fc6406011e8a31e869e4ac1b28e62d46e1489987d0ad1c2c938378bf272a9d4013587bb1e3bc14d8d8e1d540de562681be0c40c195ff3e7b8518777faa520c3a501dbd38630001e72681559e2849d4dd758408d70987002d8ab5a2fd36a3431b1a7a759e849d209fbc8cd53def095ee46c799a +Mac = 45560765e5e4644476206c7af9a2744de1768b44692a1e38567390eab59b951e6c311576b8c33b8e8769149c9bed6b5e1698ee209a8b464e032f4bdef057065c + +Count = 296 +Klen = 139 +Tlen = 64 +Key = be0a902d7d0a1a31c76982a5a4612e27ce13c887656f94cae453017554f77e08bf888ec8e8131fc139a5180cfdb1314ecfb10781521070f723480b9b0c481c7b7b18978332bf7b8b3f6561952fb5554f7f85e4e053b976e06a64dfa8523130cdd802d3e7c3d6d797c2f088c8a2364334c4d7882acf30518fa2f1a2248d7b6206c08d697b0320daeba88fb3 +Msg = 6e3662888bd3f3d6d980684854d93883dcd2da3637a8e6aa5618779bd9ced347d5204ec4d4fc6b961d1f458136882d9ca82d95a702ec2d9e20c44b8ead4590a8e745c994a2d5130890744398bf8284d063f74280d6544757ddda24b32dfad3b82e0e9aa0fe463251b9e52935f8ad85469797aa68bcc87efc14c1cab260d6e49e +Mac = 4a87dba3c394b7f9c0d55041043e9637bc5713a9664daf4077a37fc55ebfadc5fd04a28a9bd13caeda0a7db4ea7a01eeb1410d35a821b1cf4e8c66475549f43d + +Count = 297 +Klen = 139 +Tlen = 64 +Key = 6dfc8966adf3c592d0d2895f5ba20d3cce6d7eac6ef6e99d47a75bf672cb476f94fd27a5a7e0666efd117e69815a5eda41290eb5294095f911ad1b3ffbfd4b9395adfb8206e10f74e6589a3d8ea047ee9386f8f18dd1ac551d30a6662e70cc817af24d26505d864f959027000adb9120cc6e83872111f65871164591938c91e04bb664b910bc94a5129f6b +Msg = 97449ca6c272484156c84d60b7afc1cc59546a46cba1df1bf56beaf89eed31003175151cc05ddb92493d09da385f13ad2e73375e0184a66d042be45a880371b7a25ca9812f34e9b01663f30dcd1594441f7d843a2cc88da0b150efc9891304b87463207e18dfbbc345a1d2a27db98abab4da17815454dcdc8442d3edaa05302c +Mac = 2ffef9fe1a0a7ecf39d730564020b8f0ccadca49e4c1780e193e1901a19787db8aec9d7af3b9b7d5a96c2d948f81d89b0b0aa23e4fa350c3d8983556e1be2f4c + +Count = 298 +Klen = 139 +Tlen = 64 +Key = 1f2855e133cefd5e9e295a3c63fcb3f9185b5fdcf56b7ddc2b69e5bf76ed5e7ff67011f13b0c3da89f842d18d88467f7cd2a27e9a9c40b5b2edc10af4d72bd9af3889ecb25e4f4ce4f11ab2fd9a78ce2fcccb4e2d4fb4519b6045b80c3544287bd77e6b71adb8a9657d7bdcb8feb8a824c4af0129d9592dd69eaae78021d530dfd45cffd427b67c95fde4c +Msg = b55e84a2c74e837420120c9babb9813dff4d545833587664f4a71334d64e7c1ee8ed655b8b3150b0849d494e4f8ad4f8b66c2463a3588de233c33c430b8d26f3ef3e3e69918febc2a62cb9a93fb84f7a5711a1a7a8d6665ac427cd5c60ac6b35f3d9789580703cf2af47c473234bd90d08c533ecebdce914cf5b2c487db5352a +Mac = 61a87e67cdb1cc9b3aedc912b28f086c0a23cb5be98a51d60cdf1ab3e0d288fb443881a10205778c6f599d79dfedd4af27f1417131d9263d995748df45342d2d + +Count = 299 +Klen = 139 +Tlen = 64 +Key = f37bfaeac36a4ec9d379ac509b49fe50f85a995a89d8c22f59b87178bf0455b78373177e423de3df142d25236bf890be3fcd6583682df2154bfd599eb8da92c313acb3d7b27e6f4e878ddd75ff9e7b61299573251b441d499281c477d87bad76eb4e555ddbd4fb0074be5eaf1de4c82000da4ba96bc44bb2766b3d6be790adba5280867885e88edc23eb30 +Msg = a781be58853dcea37c1a30ca5db6e16b9ebdaab800ffea2670c695652b667d952615d0b7adfde2614a902db6e81c9796389ff31254dcc923a3ae5a9bfc9ddf5b0eaf12c7ff80ef775395bc2f10ee47121fda6f12f610e5ab74fa34d10c54ff2726f68a71c2ee7d4c5fd2e41d1b5579471b1726a12dc2c627ac522cefa5b4665f +Mac = 66dadec2dd4e47418e8116d5ce4c2a9e85fb82ea0a96257b661d5ee9f4b8568a0021602f698f20b5c3c77d2533e1c6760eca0abaff7f1cb0834cc5064b19b102 + +Count = 300 +Klen = 142 +Tlen = 32 +Key = 1bcaf96dfdbaab1028396865bff3fd9a87a6046e9130aae91aedb54aaf3fc542956ed95f67b316cb018fc4369d619a113c383bfd48e600837756f805f21f2df4b75829443bafb91d54b5f1d4577c70197d64e6728c32d3e8b36291ffb5bf94ec4a30f103c2d51d6feb52f725356b091b14d20bb4a63ca97f96ba872240478191159d3784414ec9278c0fdf137e57 +Msg = 9d1c57b3e625d6a7f38462459c442efd5d842c0b576c3104976654af9b8a97171259c9dee4afaad472f351c81f91cb9f0faa05a32f0aeb1d755ad225699613b9e4c2f90d17d9de22d007909af917facb612f0012c0bbaa69f5a7853c91d1467999beb1e7888cb9b89427e96132c002a9dc7be6001268b4139fb5359d1d227780 +Mac = ca7f6abed1c2252fb7f08706d119fedd83df9e09c12e481267ef733bc053f945 + +Count = 301 +Klen = 142 +Tlen = 32 +Key = f473204e1113981c4bbae6ab7207fabb97d6112a7114346800d2022b6f97b0643ffb4e71a2714c9425653ca49287d902156649cf9d409f5c8518a4e2740ad77482dcb2319cd52fbe29d28bf4ed964ad52e627bc516c53df759b6822518e01384043dd5f7c6e64a829f2a5a024bdd541c2cf23074a44d171fc3d2255a22c26d7c0e473d29e94da4c9ce9432387403 +Msg = 61a9c83487fdb8df536e2a79f5777f716e2a4c92adc7a634f88d9db48ed006218b4c7e380bb9ab9392a0c51dac6c55c9d0c43d848a18f968da7a2432d7b03ef69787ac11536a0060c7327bafd840d07479c92bbecf727268931dcb92b9025e514f015ca6a73640adb8cf5517c21a78da31e21f27c4fc9a9dee1d99bc7defef9c +Mac = 9ef822b71d2b1f44c0c478d0a16e48ae105fc01e4c0cc52e9dbc6821a1ca1e3a + +Count = 302 +Klen = 142 +Tlen = 32 +Key = bab50194e96f3edd4fb82ee8d860b4201440934a836fd35c10b96793db4c0cc03bb574e3040ba4fa056a9b1bd5a334c1d0324d645c71294c710b13a658b244d8b2150712bd0c1b25d3165999330696f904f9cb72978b749ded4b3598796cc35b26bd02499cdb6b06bfa4b18979f0a472ba7c559dbd277bf78c611590c6e051f2a094adb22ade5c44d4fdeb1330c9 +Msg = 11d69a89bb195025ebba1bfc00ed6d84277bfc73cf66cd815dd0916f211935488948b5e795ac31b98bc342c4ec5a8ee8a6f69a658b73e09e02eb221dfdd9fdd62b7ec1b06e8480418fe265d931ff47c3031a7ec73ae9f6f33f80829ca475729f5d4267ec2dea66465ee02c44b524c19ca5af50a0c31136097a5959f40035bb2a +Mac = 6a3577b4161fd63d6b87301c41e4a62dbf1fade9fbd73150e03e1d1e1dec72e9 + +Count = 303 +Klen = 142 +Tlen = 32 +Key = 232bb8903d88e295eb89fb358d617dd28c233eb98f2746a9f2afdd8f74cae9942f797759ce119881fae06e71151386532bd7686125bf6d604066d16abe5509f1dc27570103eb9bc542c96c4dfce9678ede90c7ab148c3773bdd3e42a9c67d58c107c7f0f46dd9469ad8c1d52aaa8c88b8e94831fc55649e94f3d3c5675c7f56cb4c1180bfeb02b732270a807881b +Msg = 807e05575f3ef05a4bd64e0b15278fedbf7ae63930679cde2bf7a9c68205855b87ea3c4ac459c186ec878491118f46f716162c1b682a1335e970249c2d7fa841e9871d7ca836890cc0dc0e5985cdbffbbc07b2805314566a4f32077805b2e0278d9ed177749ef1f2b11c15ebdaa7a10498959ef359ed0d8544847be27265d614 +Mac = ef070024ec611efa3315566a486300a0130447a3b25e25cc818bedaef568e4c2 + +Count = 304 +Klen = 142 +Tlen = 32 +Key = 88fcb4049978707d6c8ecae02ec20005aeb8fbbec101d452e635982d264248d53e032420001529a5f7e6d9704a0e3afae2e32158cf47b0b2e8c51ef7b2ddb6cf849b23d1e86feaf74338384eb9a2def24bb29a3a429f9830d1e43844f6931241a1ec387f182eba5b9aad70e44225f3d72f4eedcee2b093b4e7b96f7cb80d6312de1deb9259fba2b9426d0899af40 +Msg = 97115f35a4f5d6a41c7fa2446c3aafa4fcbec6b505310473a30e8bc72b2577acbee414921ed44effc166687c24f0f1af62f3f4c5059f70131c9907fc8efbfa15ad9d55870e9367b599f6751fdce8b086a4d26352cff071305c10ffffc4966eed8dc48cdd1c380b0dcbb632f53b28d272ece37c230a2cf1138afbda9976ffb97d +Mac = 35ec99a24129c23e90e4d299dbf1eaf4b76063d927ac7362550ef20c7b2de0cf + +Count = 305 +Klen = 142 +Tlen = 32 +Key = 303134472adab1a8be3c75e3bc73791991ca2d0dc92f1a32d2e5c5090379d7a9dcf77c9f905d09f9c050e19e8a0e99e1c2a45a557f6187e2da8aa018f24f67c434fe41c1d977de11afe01c2c1d9a29986173e8ba1d1d97ec12dfaed02b8a0ae3bdaf4a550d0f7a181353ef377dfd7169f79fa0e6aa4a9079024ab7d6b510092f01706102350d233572111f64b321 +Msg = 6d7b0d59dec1b52e30970ed18231cd2fdb0dc8d36c255db71569125a2b6c7912795e57a4843a0412144015b4efa6398ae88b61d1182c24d46c5a6105602c264c09f1d09f596874d39f347eb24d8a984dfe2dce94b79cef236d89365fc88e29c2271cc273e4b4cd1ad95991f22345b22025db5643d0dd874c22dfd990edfb4c1b +Mac = adfdf26fbb84fc8a43bb56affcdb0248180ee613cc52ecef61dfd18d3dd94fae + +Count = 306 +Klen = 142 +Tlen = 32 +Key = 86f7194925ba3118aa93abd532fbaf55500d7d295d895ec50f1ed9e24de929204239eff0b19525b188005319b77b05d742cc7c76957ea485192946f504f37fc2755771d6c025382a06ca1f2e0ad2146b3fab5a6626ac7ec8d6558cbddcd9829a46d905c2fb7353ca4e7b79dbd208c6586f337fc1b51bd4d8712d13027ea21cefde48157d09865fda859ac8e9b726 +Msg = 057df9cea6836a2dad42f66e7d5e40f5f6074b0d497ae98a0bca76ad89e0c5475cc05b213d0fdb9c1ad2c2956979548bbc1cd7049504fe2c7c6da8c0508acb2adbcaaaeea85a4f4419eb3506b4b545cdbebc03580b520a2d14ddb6824ada205daa224ffb926cac6fd314b78b071bf903256e39d0526bf3d3faa106bb20d7ad28 +Mac = b038ea88226289a74e946cfd88d5ccaf290036160c27e7ae512f7d7f0d05932a + +Count = 307 +Klen = 142 +Tlen = 32 +Key = 3464e7149f386cc608bce78676aab7885c7909956dde4cafb194e5f8d95924d0d039773e920ede9141489f4776ea3b2dd5d5a0c8e449a0f41da9a2cb417e98c8f0bf312c77504fa1e9c8bb1e7177180ae6a815a4a023e7a28af6f7187975d79cbc807ba8f504a64027c4a2d40f5a3467b878cff14a74080222044aa92846cb945d03be78b434cbb423c5bc31f99a +Msg = 39b67d9e4acaac11338d2f66ddcfe708dc6998bcac724a793bb6ef79a86347904b0601bdf5b623ff798fab696b63767927ab62a615c4b0382c58ac5cb51a8f7852b6a4bc3e07aafad68b7ab75915e982ecc2f084e12e0a5938e8de1e66231ecb56aeafc3ae260aaa536ae2772f4f07ca32958a7f961a2283684ecee644e7bc32 +Mac = 2e8d890e823b46ae168ec19c67e777809e8f94bdb0119222d53106e470e060e5 + +Count = 308 +Klen = 142 +Tlen = 32 +Key = 98ef836985b9b46eef4ec02a5a6f730b0d986d00c7e17582ae2210d5885a528b2d52f54b3c7da8d00e23a934e8be966f75a5811b73e7427aac7a11b928955476a15ab58137b878df65900b153416dfa3ae7b77ce96c9bfa2560e9e3839bcce35da50ec93dd32cba4dcdc0e53a43ff6aea26278a1984d93049425e0d923986bcec27cc10a95b24a255c51d978a200 +Msg = d0c0498f4dd2b8967cb7f26da95cc2011cb7d4a4ed5021b31a00ae76d7f876472506a4f7a614066db0f2bf90a0553c68711f697f8de0248ee29df25539d1f0cbc3b20d77f5b5771e9654539e170fb11a22b1bf5775d43c66f1a73084eeefdb3ed24cebd9e2bef2f05867165fb5930b6058f53ef4503353856fa6d2c99f5b1de9 +Mac = 35a6692e0928dee1d02af26f0b541019c0b517d387562e27d73abd6e6f66107b + +Count = 309 +Klen = 142 +Tlen = 32 +Key = deddcd62e35315ca2d328695b618917d21af8a99fade092e3e4191c91ed76f8a00fbe5c3c79688c25492e7ea4c926d091ce089e53ba60b18af62d21ed394a4ad57b95d44887d4c07d22ddaca836b6c6cd1258b661fc843a37cb0c8936de4607bec007c0fb0722842afe9a65de20b564e4867da432daa7678ac15bd4d732e6a9cc6b68c49c7dce61bf4b095caf1da +Msg = 7bc9db647d4a08111fa66bbed1a090591cabe8258647c6afb68eae03d80acf1f43cacea859b5c5dcaf1e8cc86f9837bbfa0bdffad107a6b5b559f53a0ddc08698992ad6805f34898b0851bc76dadc4a779c5077e4e6ece20c8286e1b87202c319448000b47ad992b6806a02394884104e202e81ac72548d63723a20c0d7d445f +Mac = 2bf0422bff8e360dfcb02f8a80a8c3de837f4f0af5a3f48331be6f30bba000be + +Count = 310 +Klen = 142 +Tlen = 32 +Key = a5f018b221cec80442616b4c1dfe51a727d048ba40ccc049f0e72d05f087ada6ec38eb3a87a143bda0b627e9d32fc14f4338d9a7976afa6543fad08d0930d5c7bf1b2db65284cd860b20e3c411097273306f3d5cd88be7a569d558a5ad7763f7a601a5cd8b5eb0870d076985de76ae3974de3c800b19d032e9e28df7e5449e5d2a521c28391932ea2dd37fd3435e +Msg = 581bab213da5a7a29b1ebe1754f6708d87da8a32fd85a6c8c4d9f154192e31168cea06be5e516fdd2e9f919ad454b4a68ed08f725a1fc59fa216afb61e9f5c19f751d6392844a70a2a239cb4d082c98c7072cd424353585b0eeaeae202b4dd5be179a5f963235711d8d168cd0e28b72575e9ce0b81c965e6507d28428d14bbc6 +Mac = 26e309186f09e64b23db3bc2adb2ae4de485cbe1df97b96e304d4ef9767896d2 + +Count = 311 +Klen = 142 +Tlen = 32 +Key = 14c4e7563119242a560883d2546b81a3bce24ee24f78dc87b684354074ce13b918f3aa1bb70bc9d3998821943361e49f55719342a51a119e4c2dfbaeef0e3c85e113dbd7972e18bb5cccb8af45fc9ddd68d4999d4910843a95fd8cf91396cd57d7ec2293b9cb3a6c059aee2c7483d1e55bd409fb23a55ee2f9bc9129c6adefb8624525560529566efebb6b12a73d +Msg = fd43f5fe73922e22d7370c60de1f9b1ab2e0e9c24e927d4a2be025db1c5ef5c9761e8cc7757e9957db439e85daecf4d53440107aa12a04c871c648ec72bcbbdb14cde588cbab7f5ab50e35dd7d04aab87f88bddf2d570b09b1ffb465d43963881e7888aa3ec2e813adbf58d08f10c5aadae17859b9c298f433b2f1ac087df3ba +Mac = 6f8859b69cfee89dee650d16fd00749c9f660e6fc9b927caf02bb891c812def0 + +Count = 312 +Klen = 142 +Tlen = 32 +Key = 63dfb4078cb38bcc97bd250fda0e286ecd4e64046a985bdfda8b01b34d9dc0cf2ab3bf5168ef64963bc918f5f4624aad2214b61bfe4ee731069ffa23e710a663a0b779d0e589642bc1707aca809ef590cc207a1c16b69e4138e2a8b6583f980f0f1469ecca29947171d9d5f6476931ff1298386e7b7788f7b77b92d567d1a1bbbdf1180ee176fa51932db0e1116c +Msg = 1cc6063e9ca0afe0201a714d023517b113938ed73a89a5e55e7711478654b4e93f8d1fa93f10550c47a3d12f4e7bcb01db0ab8b0b3181061b415532401ae4e275f9e9b2adfc76732be81778289326dc7841f48934d812b0cbddc5fe60f8c9a8e44a082a8c5ec6dbc4b5a6b2cfc81866ad779486751ed7e4f40713c73f9162187 +Mac = 9a3819ae5774023c1d7deeca6f15a732f87671b5dcba791ffa5340f841b9015c + +Count = 313 +Klen = 142 +Tlen = 32 +Key = 321e8dd5b0b7c660b3090544612c5476b0d4e17ae0cba47a499f429556983279d2ec1e3462368c475325bdfc9671d5fa09143d17f9b6466de4690fb08396a8bf07377778a447dbd14c771024bd2353cbbd8446eda42795971c9eda0f2575be655c68614a7cd2fd252569c664dc291410548ec3a5eb06da2078a66c59441cbc9356e5a452f4c0386d6662a663fd6b +Msg = cfb4c87716df82d2a97ee4333417a67fd5e66be2da89a11ecdfda823aec936e17f79fa5a064e7ffbce34542c6ff46a260fabbd04297b361d8d80d092a806fb2306f93e47159c1f7b2c7e47dacbabe2ee251f45c6db80d3480b0c21c989d058db6c1adb66cd322afbcb450764d2a2d7801e294a4e7aff3e474e87e1f1d88e16b1 +Mac = 4c978f61005e9a04a733205f9e8f2f3a40b8266206558bcee20b5193792fdce3 + +Count = 314 +Klen = 142 +Tlen = 32 +Key = 36dc8b8b97c105dc9c03908fccda0e4844c4990d08857462976c41b2c2d974f1bdfc078077df705127a7d04b27176df00655623dd9f195d1d123ea521354b60dc3e077dc621bc24d5b927c00d8934d51daef523789fe126cc9e4b4cf0d136f0670114167027ce4195f4bfe76875698b4e919d1c5c1b4d37ba43707f0591d8525eb16cfe9fc0abefd5c5abc75db69 +Msg = b5fdea4779f5787e6b947d0b3333fcb115528b816b3862a353dab253a5fe382a28a0119f0595d0cd7b6ece77d59fc14999e1906003d4660db1e906d6a07f5ebe574c5ec762ff0ab40223ce132347127b8e5c0f13605ee153bb37dd0fbbe024b1acc978c67a7b4fbc687c26e9057218d05d8cafa06c1efafed88be004df68b38a +Mac = 0c27ccc84bf1ab92f42edc8188a1a0b6b38ef732ffda929f767c0970b27ec9f8 + +Count = 315 +Klen = 142 +Tlen = 40 +Key = 750d16ba014522c2ab475e8638535d5e729fce4a284aa48777917560484520471a7cb32402888cedef25be7733f6b68c3f331e3dae9c017986b130dfba24e5d1f38fa7ca8f636df1ea2006eeddccb8fc859e283f46fa79590fa2b838df2a783188acb953b3be0ff524a100923fbbadd7cb47b5f9f74c564c9acbd512bf3d2090613db3687381b822240e720c60ac +Msg = 6e9aef113947fafb961eefef891ea3f83ae018a45670ff6fb35b7b8033092893ea4d5c37833bad39df3ab360005a0f5a26e7abf7373e449564df26dc0ac437abd6f137512d4d4601cbb0a780aa3dc32125f271f35d7d7439dc51451a78fa149a7aad09c90024cf3aa0a953b74e70c9338029f10090d6984361da61a44553c54a +Mac = 90781faa0146879a3645319c5390bae2d0ad0612bf2e6e7dc741e7c74b2ab65c520403410f1eca27 + +Count = 316 +Klen = 142 +Tlen = 40 +Key = 3f64c815f2793ed4933e374950f77e685ae3dc21f309d340c9358f92823d1a499888cfa167d111c484293deb513bdcc7ced41e1fb2a384babb3ddc7f426372db128885637a8ef8bba1d14ab61a66c8beb8a50177a4e47b9fac86a439de350bea566bd0a354375a80923e47f0d400a917c05c6f70f05621b74619d1067f384e3e0b399aa81c549edcfe781de2a68f +Msg = fe7ae0cc9e99c1b0a2bb11d71db429cfba959e655bc80860ff5c086fe99d895fffe8459170bd8bac9916408f2af7258a844757cd66de1c20c9dfdcd508486efb44c796d507d0cb8b27ec3d1eee5416a177be00a75b77e8f88eb2028883200ea997c0d97facf906b414e60e6eb2f1867e5ba3a1db82baf54e157c826ea24cf0cf +Mac = 4bbba9ca72b720356a2ce80f32ed65f6988b8769721413ae44014a72cf34efc965cfaeb44b294445 + +Count = 317 +Klen = 142 +Tlen = 40 +Key = 696b28929d149b340ffd609ee488e7d420748133bea31456012013370560ad9699c8459f517023c7d62769f781b748ec286a73de38ccd45f04b37f875d7de44e639948399a49763941a5b1d0dfe4ee751ed7403adcb694ac801f9efa8a5c135a6fe519a9a325fc51f781227025974137a9c3cf90d3e8ba031b6d5adab485a48364b4a037928f1dd9a1c3a3217c58 +Msg = c66a563cfa22744dc310137966f1488f433efaee105f4352651c18ed7d542dba3bf1130e6b1ba3704baca0aa49e498200f5f0b61bd43d0fc75beb3951db0633760a48cecf605408b268f9bd28903a7b4101f7df448cdadf3dd9be0c75e6bbc8c3f6b08ff244811495d9f4c18acb53cf44f6796d13a64a4e0a599e7abc6ed0061 +Mac = dc6891c9ba1d783cd0ce19c2e009ecb70d4fe5f99340db8dcdae1f51c741781e1bbd5bca92af6f5f + +Count = 318 +Klen = 142 +Tlen = 40 +Key = c5dd58111a50eec6d5d19591733ad0b8b39f78834a2e0c43d85948931b38f9de62280f2245b9f4f394c71cc28de6de5f520482bd9a499bf6a642978e773f94fc3ef97566147835adeb347ca9c47b70b62312ce6fc01f39b98046d204a31308cd3f98b267ed575bfcc262dccf81c031c30e13852126788f964eaf217b097cfe594e4cedad391c0be8019765ba2a7e +Msg = 44c8c5204a8d2e01951e67d1f2e2cccdb7a784d556e6b1cd3148e943b06aea5291dd89c68072ec80e8b4f91d08b50ed2490ef39acf210d944ea1d4a61f55876793181e3c872580c13891f66a5919df6a631ea6d32deef2ffbc451c305c14e673ef806aca862e50892ebe44010d95a75cade085c897d5c8d8243cab26902f713e +Mac = b83b4c548687d6f09ad25065657faf047989e52ab5d4147eb09a1ee13e69a1ba59d5e3291a2e9b98 + +Count = 319 +Klen = 142 +Tlen = 40 +Key = c8ce9ef354069f3408c9fe64d39649a7d758d3d71e4608818808fd31081b4cf010761e0a4a6e891589d71d2eff6cb986b071a31e2696d8ce671fa18c244267eb33d0c8e24018ebcfbf0910bb24966be0575f3268628df5786dfd2e6deda219661824c5029ccd6b6b90a60093abdd06bdb46aa74039f2048784eccb5dcb020767a7ba3df2c755b4f0e6f8143cfa09 +Msg = e83b5b65f66715b9b53e9856a845250eabf61c48da130af5b039e2c66cb88b9cb9a29b418d226355520f2b8b44c1be151a242a5ce80ac1f544c663d0a8f600b317a058e7038105326fa1bc05512bd0f53a7cf76f387a51a8fc27a6d43876f0984b5d19c1202b0536531cd32b962a609854270dea9409c3f81f853438e5df6333 +Mac = b9e52ed0c04ef11f6fd3d17a35281cf18647df94a069a2a59bc73f007cba1b683536bd447eb915e6 + +Count = 320 +Klen = 142 +Tlen = 40 +Key = 6a53dbaa79037233321b9f88e341c68bae9eb8dc8bd7d662903f7a28714b926b43468ef185457d9c605e723e2e152daf3a17f71dc62bcea45365c21e1c9c9f3de41fccd7f1a473805981e25e7c1f3239d2ab26d2e70e5576a3208cd2cf186e09d5485d04c7079e0aa3eeb790d6471c52fec20ba2f46ab5000ad89eec91a646f89f2709210f55445fc80bb97b4375 +Msg = e107f34b5d86d7b32763d7345ecbb49b6f0dd5c39309eaae99e4cfd4e501b3bbb92d79c8b31a5e55970fdd044fddd0523015d76f7f78fd4d34af99f6fd3d732486b1280bf820d07ac0d2dd22913c4635ac2ee6345f4e1f02cbc5c23ceb3833cdd2fac8bc348073492815a1392cce616e6ac1c9ba3a7295f5e78e124db6dc3bde +Mac = b0d64486b92f3cf41e8a696ef372143673904dda2301635f139952587f35dbcc209169c07ffe065b + +Count = 321 +Klen = 142 +Tlen = 40 +Key = 796692a748b89bcb60228ab4bff874f93123ab6dc7c6d7ec852148545bb58ad157a83a5e186c1988869c5f75c026522656af16f9b933c772efecc53a8b764f68dd30540066e585b98eacaf049a0c4849d86448741c8a3ab070b39272089341ba74c58796196c08e7e21b236733f27feb1f0ae6e6da14572f713c5604b854874e842e7b261b49ca99e9b062a87520 +Msg = dfa3aa8e29f56b6d68dff72a4c23983a8484990cd487faeb6877692568ab6e6dcc0ce67e72d1b2016d8db0b1a16ceabd8db90e6d67a41f096e4369f77cd6ba23da4fcfa459120d9c9ef9725fbe9bcad80bce26292d6a8a927450e6946cab4756b2764f47073fe305a32a237ecb389f55a6c9c7874d60a44e21a7c64561b37ecd +Mac = baa1d4878b8aef2c59d782bb655e9f51b0c3210f39644adfdb8715a84cb9de57d3177f5a72ad5b6f + +Count = 322 +Klen = 142 +Tlen = 40 +Key = c6173613801fbde3223f883f158f609e86d5058c5ea5c6f275cd509602f0c4e557700cf1cb916eb6f7dc61a125c2a05305827ea2a24d79e095a711607810db379ee4d1400180ec637ca6f5163b2398236faebaac46140c6d1a92e042e9823ce9053b2d080c325e721b65e9a63ff96d992c2161b53243a8216c5665433b8f1083f23cca52d3f0ed6b3be0e859198d +Msg = a05cd06ae605a3c988227edf935ff24b38f7d5da1fc238acfe6e9992690c5abbeccf7290571163dc59976c305016ff8660f67524c25501c35f4fe2f19e7dddb47abbeb70d72f2f0a16872a4ee781328e5eb1208c4a7f4a9bc26fb10000a57b9e73a8a3d30f66ef9de8782201ffa873ad5bb03fdc5c45fb7a4d546c88388c1ac3 +Mac = f4247272014df37543abc7645722fd3ec0aeb89b6f49dfd36d11daebec40bfa3bfbb16f9d44b1c84 + +Count = 323 +Klen = 142 +Tlen = 40 +Key = 3d6f9ac66786d1eae1a7ffea8417e7cd49b96e355fd44f3f7a150fab6dd8343dfba3b262eaf3a6175a3c4607552b18f3a72e6357f036e44bf7bcc1a74102c36ae39bbf5d942d55f30676dd74778d9f5a836a42fc3ca988697c8b38977a3e5bbd9c5eaafd8cbb48468e5dad7911c5e2ca8376f46a6ab4a363b18c5ac33f1464fccff45c8bfb25e5d899f99c5d4b5c +Msg = 2b28f00a57d2b2cd36fc1a23cfa8f533f6636c16b91b8644fb31ee4c5fcff7c9687cdd91deed4e2f731e2894a6a28509e838f568fd9e0a8ca6aa1a067d964011209ca4c991c2fc97ddf853f0fc60093ff9ed1c1f532fa5cea26da6de7df5022e9cb0cd193af9c6edbdaf229f99898cbd72aa69a3817660f238a31a3e29934607 +Mac = 27f5aecf0d153a94598848d42272c7e36c0ba4aa658d2cd73c1ab775bd4812dfb2713dde11868ff6 + +Count = 324 +Klen = 142 +Tlen = 40 +Key = 19a76e3342eaa5ccfc6d4b92c603f39beb16703cfb4aebcf7b5d33b3dc525395aace6aee06c2b7cd564af4d73bd5e58cc48730cce1db6f991a8d841e80b72cf0e43ad895485fb84393be18e9895fef74f920b54b3856761bcfb725da7178320630b25e2ef00acfb41b915fd196e93ad9f4aaa8c1ea0327de03a5bdef95dc8c5ef4ffa7c3e50b24aa568b73964cbb +Msg = fdefd6dbd43cb817b132754633c0ce724be5572e4e732b7d4813ddef9489b20da9390df737ea2a4c73cb0f4aaeb3c0372dadb3ff35b4831e65bbe8c049f1e7272b42464e2c2143cc948586fa673153583939042d42c2b76eb50944e14ea772822a136a26dc686b5ebd68c09e83c1ef9f169034019f242d35e104d79acc33b9e6 +Mac = cf049f7c069e0954b9c76f22a517eca694e4e4abc5d41190b64943be8649da34dd9f0bb54cde4bfa + +Count = 325 +Klen = 142 +Tlen = 40 +Key = d7e34449b142a6e1edc5b7210ff3b0f0b7fcd01dc74ca495c46085da7fd862b0f4cec01a7267fe84fca7de42f08a4139e65032dcdb18265b8fb082162bac5e5827b589426b24cd05b4d074553a230a1a90746568cb90e3b1e69af3396516d7cb3940a8abe4a29acbdde5814136e894f97c0f71a7dfde620092c6df2a753e5471f216243b2408ed3e3f910ef02cff +Msg = 19c9441fd9382728e5de19e630b0cb95156b9972eed5bc1fe246c148fe683987873bb3858f5ce763c786345894594d9b655a2f83433c56ecaa5e30de9794d269e22aead3ce26f4f6dfceb1e3eb6ad5cb744b0020350cf0f7fb18f5b1b66ca5dad09fd051bd1fb7a9d4bd78d05d6ccdeeeb45f690eccff4067e7ef80984791ba2 +Mac = 024226ba95f0c73567a20f9077abc8a8ce1fa766dae177f3c8d39982654a0dee7cadf131f0c645c0 + +Count = 326 +Klen = 142 +Tlen = 40 +Key = b7c3c77899440e81200be3c06e411fb6cf96fdc3f67b7ef38a910b1be1615c250b4d9aa812c6c0bc80c0470c2263022c0c04472ddd534f6f44d6dfb7c3962881b318ed98898ee3e3574f5d829685281a2225b46c8625752d7ae98911aafe9b2ab90a077086033fa1aea06d4b520d5a261ae38ea87957b9d433b251531d017dc5240d3259918d9b9b8c9bbf8ede65 +Msg = 87b0745d346851f812070f3053c39a906c1123d9246bceedeb51abeb6e8ee89c68bc450ebb0ac77ebf3db17bdaf5b049513256845d16c90582edbd0a1c6a9f903b331304b0a1a11b68c0abfff99ea3ab7bc27b9899fa5c99e75a9a037781e812a71ec8883cb34697b599e601d945db7e93c9795eff9ded6fc5a02c21a65a29e8 +Mac = 8cab0aba5c0428a037b4a467c32d4d576ee3ba2de6d56c37e81d5c651435e556105caf703daed9d2 + +Count = 327 +Klen = 142 +Tlen = 40 +Key = f871dc8772df3e9bc76b342df66cc7ef7abf7342c16935fae07de5618541c67e2d8c5c9797727df47823abe67011a1083d512cc52f443c1adb763b9d14c69dbf17c8b94e0667d73e98cf8aa80e8a401369e817f3daa5f26f7ac6cd673bc44db61eec9bb4a70673ff8f35787cb81ecb98664cdbd4abd37f80233442c6e281fdebabc2acd262967ac2c41e1e685616 +Msg = 64c673e5532ce4debe2682a3d104eaab398860797ff0c4c09430c1caad80481a50163d51af35704e3666ce996006d902ce0055859adc4471e9f915cabf1619eb1817366f3406df5232594354e073c59ed26dada8b1151d5ad6374672171cdb25e151c60988a91b32da854a9bfa5398c86c55d0aa6ca435c38474bc8b5d997811 +Mac = 6427232699c7b9d67b7f302757a147f8d3e97895a4d6d547514cda97fa348c6b82afe0bb863afd04 + +Count = 328 +Klen = 142 +Tlen = 40 +Key = 70c06d7e2fde3dce44d5f9f8e5cfaf28a2f1843bf598ed211ae222862071d0b1416b0eac6fc593a52fc22694aab6551e01106ab9e2979b1259f481ace871ccc9d900348dd37fb361ac3af1967eb2004afd9d4990072dc6cb7d95725b52cafe7ce186c66a849303ca62464245884a15763c9e08068de1d6152fcedddc8603d0910106ac8ba989eda7faed01eaf106 +Msg = 2eba90d1335117922bf5cbdb66432159a97f9c952e89f180ed0c6a4e1af98888ef34ec5dab8d773adbf1b19ad8e1671e912499e08ab9930525105991217a487f60ddfb12edac6c663d165b4ab57ef4526d2cac2734426c22d4f1f11997ec7379091d849500983c3edacd939406010e1bc6ff9e12320ac5008117fa8f84394f9d +Mac = 170b060a7dcbbdb3ff6c2f6d99354748a0e9bf7ab801b91339252ba2cb842a19dda5cf637a6c389d + +Count = 329 +Klen = 142 +Tlen = 40 +Key = 01a6f9e95494bf281ed74fae28284e1ed375c1f5fc34187722f76beacb40030123971c9be7dbe9ae81d6d97d75131912fbf45ae8edffd4e8e4798b969f36d18da4af0c292955b9833425b1a2027dabefa62e03eaf2d2ba1c9a60bd4c97fd6af6ca1550f9e2ab36907fed5f83970c0d9f1a4a4463d155d0fc8cd38a747c3ed626def27075d98469bdaa566c8afe68 +Msg = 11f77655d955725a18ebfd1612b7a91d15a055280db75c7252bc0c61c4e45a691ad9d32e7703d6e83e06010c288ce92994440e0f1e2b0e37720a185f633fa47537c161b6455f6f17c348cfe4d9d018a7f9716b4b7310a8814482e2632f4f115710b607376cf1a6af4cba4fe64c0d9d60ef30542335f19418702f53b5539b0ad9 +Mac = 972ed368bbc123e2894aaa1ed0b3002f1f2f0f2ea9c3f55eb52418fa82c7878537fff0f39957d387 + +Count = 330 +Klen = 142 +Tlen = 48 +Key = f01aaa41528ebfecdb9fcd42948047bf9c2366861e5dc0a480451c95dddd8509b6f49de8e44a3493d1f6196de805309a4a64c506c30020a9fc2b5a0af2426f02a68c93c31766ca186d9db3ef771ca41457c7fc3f7ca6b551d14639db345c77e02aac35dcd129a804165e42d0270ccbb72c15b3393298a723675e620f8d75c62aa91a2b3afbddf7df33ff6e18e21f +Msg = 7bda43e90479f852717f4786b267ca874fed63805a2bd007a2027f9f29bba381d8ee879c72a322dac7b8eda52a83f1aa24b724dc6a8cf5bc0d1a26d8f106da928061ef239fcd8de0e1e2ffbbfbd0c20c7945dc92af916fb4f1088e0d07a74f28dbfb2288753f61ec29c528d10f976637b45d34a80f816677b792604653e62cca +Mac = 0201dbe5ef4095f4d4b3306d9b2d7552e0d68c591ea88368195f66280b80ba0f2f6ae436c423c5c9393aa9f4588b0107 + +Count = 331 +Klen = 142 +Tlen = 48 +Key = 931b7d98f580e6d2278d1b671117e6047a59edcccda191a81c4917de65e905e614cbcf79ca9fb3ea5d70e2b920d7e066646f2d833e88250d8b2025fc320fef19a9815010bba900c688b4c9eccdfcebd5657fc084108f9c0a74cbf70f614dceae592546865006930db0401828a0eecff98671ecf8ca1dbd46de31d53e7b0d694c2d9ffa02111f3468ddfc17942216 +Msg = 9f848cbef3e29e43766825a1c38dcca8f84eadda22d0672bf5477105c116ae8fa138412ff6dea24e1359f15b3a3b8b12c8b9dcfeac54743c1db95c838de5aa61d88c53c7c2bc41c8a0bea59e553d8fee80a9bc4df4deae026901020d71abff69ad4a6b8f40c4a23b845de972fcdaffc48ae6f5cfe2b640043fe90dae55b2d42f +Mac = 9575d542bc82ea5defa50698a7e77c4bc68f47fd332cb3eb52f009987a7bd289ad3837ee50360264c95467c76c0e8ac3 + +Count = 332 +Klen = 142 +Tlen = 48 +Key = f2af375607397f0793f7624c3fbcf530ff81da1d9fad72439f944f3d403de8f2df6891ba82cfaac3b1ad16b2877def8d080477d8b59152fe5e84f3f3380d55182f36eb5f7d24d9af7c99648ab8bea7ed4920887760f8ebce1faf263faea1b4a48b222d8b21be75949dc5341bfd08871769ddf642c769a57b8a1ece68ca826e5f9a323f879627e73abb396fae7ce1 +Msg = ebda765da63dcf09bde64e646505edcf8aa4213c67e80d925393f653decef87c1c26f7ac41d4d8896e41f05fcbc9bc0bd6bfd318fbb21a2764ef3794124748562d13d427987501e6c9e00839d8dae776d50056c45f4bfb7d7293e1d7815127c4c5a9f516d4a8b4e775ca7f38b3bfd4d8306e9088bc3b1a5c2685de645273fd8c +Mac = 0b7a197e76e58bb8b3ea8b28a25cfa35bd30c274d41ca25387d43d5ea7145cfa08ecca6e49e45bcf9a7ca1b280cc0295 + +Count = 333 +Klen = 142 +Tlen = 48 +Key = f6f938107a56a48534248a25a03c6f2f9274e2ca27c20d47fba589a79cc0775d3fc8cc55b2a1ec3492c47be2bee46f460bd16a503a9c483d27fcf31642f07f7a43a6739e1a9c64922505c9c6a66e0acc74a1da5ff1cac7a53bd80fb1a726b64c6b5bd5f59a8f352656af1cd94122674b34acd9003493b307a101857fb1aa435a1dae9b611ac186788b891e247547 +Msg = b4b884477b9691658c61733ecd7ad261e00b0169489b3f2ccde0363521d4c875c30b0b352443924f093def9e30cb75b3362b43c9b8937efbb90dddb543856b6951208883edd0319e962682f8e46779236fe1fdfeec7f1fe4999c9f23dc15b2b026a202191e66f7bafcc435343275661b52d739ef2c88aa4e3634856732ab25b2 +Mac = 343a2499482bcf541bc68e55eff02875eabd96b4e2adba90390ccbe7b8b02c095f29f7b681d97f5435108ef27265e164 + +Count = 334 +Klen = 142 +Tlen = 48 +Key = 409ea037d05a6c189bed16324a2ea9b0694838abbdbcd04dd7a5ab37e940a621d9abf5c094ed16eda5370303066aac8935d8a4118b4f1b5fca540ccef5acb7f0642152751782fc4e4becf2124b4805a089154c06ed6816a16d302286debf132109861e1c02200682b5934a25c2d29d3d8b8696518a0da95be9c356274c81a0fcf264c17efcd01cd30cb47305120f +Msg = c482a31e43855cee2527df70c1364e8f5fa66077929056b2c87b31901fdb22cd7ad7426ed54f83ecd51ee694a39cef2efb6757dd8064004653002ef4e3bcf3fb07e8ebdc4aae2aa98553736ab4baaabe022a8cc626509e3ef28863ed2958d240923d07324aab396e5e4fecb8999768899b7469f92b5f18e2cf9a3a4399b8a8e2 +Mac = 204cdc33a2b804bc8d1332a0f9b82e07c50d51c3f645898de4148a7005a13b9c7599e92a4540c2a23996b5547594e39f + +Count = 335 +Klen = 142 +Tlen = 48 +Key = 79d5a72e90bbbaeeaf84297bb7a07ad7f141e5ebf5b3597acbebc054516284ccdc24526b22231ee658d2674e97efbc8784a07ffb30c2e98f3d7e4ed7431da285711d3d287884db13a474e79a4c00f9856d3e9dbe929d564df779e286ededc08180e9f0cb5884fa5bdd9331c89f7a39b9f442c79ce3eca89b400505cb197be5a751aff3be8bcb82a84956ce3e5506 +Msg = 94c75d7a30d8b1267b527a6c0bba34a469ccbe077d1c6a6f46fd515ecfa2e9425e83d9f7ee020b8edf4f034ded8970f65f26014d80947ad4532007d98318d0b2992ccd48711adcd2ef8b11e3ee374da7795012693e1e95593fe7158dcb116c45ad8ae473a3684b7b12cd4a37f70ef23e211498669e02e3877317238290d7e482 +Mac = 68f507eb2c0ae009965302b8387196cc83860839d9e40f058642552fbe93cfd9765a1812b658d8f5056169fb608c2c31 + +Count = 336 +Klen = 142 +Tlen = 48 +Key = 52b400b5fe5956268f393e1418ea8a5329896e9ea447ed38cc2492d49ffb60b366bf0b0c8a0469b0a9c123eee954b0b48cc684f8c5518456ca1fbefb2b5557c16250c49bab2e3d3416916fd3da9f7282ec4efa6fd0ded192b0a78590ab145ee06ff0922c0ae0bcfafd318b8b92d4b70370a73acb6df7bc34a3424f5dc6415c56b525dd854e22cd49872adddebafb +Msg = b1e81f17c2b8e4654625f56ace0814f2c5b79317ae33ba13ada2695249fffecc70107991bb98dfa5f4cfdc0fd60fab2d13d03b4a9cd68a721ca95585c546f48b501480473f19360f666e20dba9f0f29b073932ced8cf9b50529ac473529cfd525adc7962d5a3b34aa3eb0af5d115aee5a8dac0caea84b553585efc447769e0c9 +Mac = 29fb2bd6920873e7e73c06e48cf21b2569e36c7da879b802ad22dd376cb5c01c9b76dec775d87de289c82555ca3a9c9c + +Count = 337 +Klen = 142 +Tlen = 48 +Key = e4e4d9924d57bb7741d86243d2818e8cd133acd74037ef5c0625a20ae605bdcbb2b5b609bc8b99718e3a5bf7dbfa6c1ab5e38b69ff9ade46263042ea0c47e0a94577017786f023ac5a604b0417179eea11692bf60d530cb4f962ada7dad16b8d05f161e592ce7eaf0e10db73701f4c844e8b368651aaa02ee7838c4937ea87005aed7f5ac86fd5021013b34bcd5c +Msg = 101c3e74ab6b30458346b7a1df2582490b7655c307845c59819dbf65017476cc64c45fc98b368eec5485e462c9e0e3769890c058c4daba1d9927ab08e562dd0865a21e817e09174f2decd9094133b982c8035e96c79b18232e7c73550acd0d27fdfda426ebaa7378f7c2bf1eaee8ad7681195604798f1d7126e541d4d97dae31 +Mac = 2aa697d6b6bc98c1295d74280b8b8aeca85b970ae9afce5a53ad846e1af75221194242cf3f000696f1ba6d50d613105e + +Count = 338 +Klen = 142 +Tlen = 48 +Key = 95308d9fdcf997893fab34e3e4e35368e956ab894c21b861085a00eb81eb9b7322a0f24a457ec7be535776492c9b7a09c97132702006e53d472505abdd09b0e8a66f7cc875ef74bb4f8b5efdcd89400cc27e225f1eac1455128d736c75b069b367c4b38234f3a7687b7175658f54ad591da601bd0fb84d91b1bad4951289ccbcaec81ede493267ad1e2e42ea39a4 +Msg = 88e1be9b171e8606c966cc153b77ab86fe26ef05e39979fd75b6e6adc6db6b7e6fd00394d2facda3a2d1af04a6944008b93be58c16ad3acdd233b37eaa2c8318ff03bc721f5fb891c699b9c1e573cce4a107f30b9ffd82437f01cab2a674f5e24162315c86b511793da82f75807e17c5bf7360aa07f31c07830a7370431c8a83 +Mac = 703898c05011fc49007a182d0e4d2adc1de189013f3080e4767a1e4c32e3e4aad2fec73ce44af52d8283981de55c1a54 + +Count = 339 +Klen = 142 +Tlen = 48 +Key = 8b78fff13bf0484ad184c56029f2546a27e309fba60fc53fb1a80a81f6f60df1773f0da583e9e4dde5e2dc8b5b40c3134a25424fafe66ad6596c907e56da5b1fab6f1b9a48af5c1a3abdbc9a230cf9a8e7364e68a92c00dbf69034613f5f037d8dd3d0d97088d98a38dd0d94689d1eb168dfd64e7a2aaed7efdd9d349bce2e948632d569e4bd83b3480a7882143c +Msg = 5af4e9eda7da0b4f6919028f7caa329003b281b3afb2b8a83efd2c8441709f13235d616f67c8bad131d68da8088235e8da92b3a540c90be0045feba1e1ae8e46892ee01aeda3e329b89551531c0183a0d24e91d35c82bb428eb607e44cc82cac954faf15c1d44cff063f97b9418fe35ff3ce63668a448f75e3ecc9760c2441ee +Mac = 5d843f0479edf1b6ab5483521cf5353706dcee0f8437b828fe80f60c44c33abef2955b612c376dfffcd67fea585c6d50 + +Count = 340 +Klen = 142 +Tlen = 48 +Key = 7711be3686e1a1d9f6c2a51c8455754c58edafde234c97556aad0d662208bc5a7c9195b502817c15e31a405c8be5d111773fad0448139c3116e99de70620202a1f77755559d38504f73cc0301728569c88fcaa70dbd00424bd7285a084ae61a207cd485fb35c256ddb2f0be050a56cb4322c8d6b050836f60751aed9c13be78bdd9bf51b37a6c41937fb0bb45de4 +Msg = 51dac8cff6c0d3b27fca03803e554836c8f10c6aee7ac38dee84c46deafc57fd980d0f593c415a05d3e9567591bee6d38ec806fcbd7f5bcc1d310e9b33a3db07b7fb65f48eddcdd2f8d5821f0bf55b2c60bfe3230c45f449d18e8781963cca12156c73a9d4de54a2565630839241cec9a49c4be8c312b48d7364d526fb0e4ba4 +Mac = c8909eccd81ac5c763cbe4c2ccb537298026781ea0f7cb7ac43c0aedf8d369bcf6f40d0ff315672e73294dcc4400e4c8 + +Count = 341 +Klen = 142 +Tlen = 48 +Key = 205f40ae5dd58fec68ad60b3a29041ad2110148001a108f3ffe4c853432cf2157e3bcabc354c30fd5d57cf21279098ac1d306f3c6e7923b386f4a498e2fe70bb23824f18610840fec1efb3714af6f8ccf402f8ab021b230792b7a9a3733beda736bf378b8811a837bffd7469b2cc4b56ce0b1894668eee374bb43f3b9deb5022e077e9dd527051f07c0a7ad2081a +Msg = fe0bcb445797a28e53597311250b23f0fa7763e72cdb86d2b9918f6ff3ef8f64796d2e846505874ec7e039b6532eba295656efcbef4ffa037b4d543951a11bdeb0daadadf5317531112405883b606566e2e4ab5de664cc5b07ebb2749ec58fe18b9c70496ee115401a6e000e4669ccb1866bc0257ae1a4e245b3d3a741249276 +Mac = e85d23f403ce6224efc217efc09d90f56a0fad52dc7471499199a126872d07834603ba26512116ecee901083e0ec7cd4 + +Count = 342 +Klen = 142 +Tlen = 48 +Key = 75e3ac050d30c6f8b3fc66496e03eb2cb0bb826a2fda9a05f018981fa436cc18383fa4f7a80e200b141086d2154b5719519f81654d4cd69283b5bdbab5642858804dc6ad34577963e3180a71b8e01c3e8afa5e09b12e0588198a7acf95634f74759678f15a13b849499d59efffcb20e38453801e03870e30d9203528ec3b2bb43ea12389c24bc5056e26db139113 +Msg = 404d7a28f4bbd3753c928114aaad41d7919fb0fc0fa36bb94bd27518fc99d9052b6990a539b0a4ea2309966505affe5bdd38711a9280a78d35e3dd0f86af797dbad8ed8f7beedd68314d846b809454511158dc789619ef7e0874030f339bd7fb7503598cc35cc616ecc613cf22428ce1b666bbbe23568bb44eefadc10c453ba8 +Mac = 3c226c574944ed5caa2d511740d995ca468185c426f47547c2456f2e262808fe55b0a0da08a720dee83bd7dc6e898924 + +Count = 343 +Klen = 142 +Tlen = 48 +Key = 004e324f0a500b652622671dd7c984d1dc9ab39db1adfe70598f0d635b374b4a0b3b44890a44512a10c0782ce9d68e1dbe9f9eeb96938ff71c41006ba34477ce6772bbd516567e7c8fe13f56e95c6f21b7a1d39e8a8b29a0b8ab0e625c3c1f1d9e595fda356ed9852aed8644de4270074e08185f967d1593b433fff18f098b62385af7416f74a96d694c139dd070 +Msg = f4572bea6966ef05235dddff26bec1853eb36840434604a79cd4d11702bff9258664b633d64db641bca7c306e7f6a33fee073d489226fee944927b72e72e580ad679684429c015f3349303405175f0f9e0d7df2c8b4875f5cfe6a394b71885c2eb7f8a46ea29d6c39408e4d4eba3705a1a0c9415b712317245b790a4fde549f6 +Mac = 5c6c83482e60d6d787074d18ef5b1fdd05cc4844235e7b8d6f705bb07c9cb0d32c1b66491fd638fbc41956041bba7088 + +Count = 344 +Klen = 142 +Tlen = 48 +Key = 61956d7ac4068b0f7eac617bb1ee43127067f9d1d1a26d454422a7a923a6fb4f8aab81416831c627d6c2c16ba8b1099c42a04510ae44e3ceeb6d0daa8740d8b270c7bfc907ad51927642269043c5178b26e3ae35187bdc0dada4ea84a3f1b25ebbf40f5cc700921805337730abb4d7a6c33a1f8739cec0cb33d1287da040f21c14375940d3b4f3802c9e9c940806 +Msg = 97648538cb39ec8887444d24c0b7e0eb278a88c7501514e014debe1034b0f8983eed6911b52432a56ce6757e33d6187fb500c632a16c370208f2b2ab074fd0eea5798289fe305566a2d6f5133880f072674dbdb2f6f7fd7d31a700738f0e8bd893b1d989f084df35f0bbd5c916ddf12c031a762d96deedba57a6b2521613b3bc +Mac = 9b2cf9090a25b8528c159e96290fbf41e077bc42cae131b89e4a212d20f8e0680e255c3906d09cdd60f3de1fcb68c1d6 + +Count = 345 +Klen = 142 +Tlen = 56 +Key = c937c7387738e5be8761a41603a204cd93128fdaa18698d3bc62c1613aafc0f2226e62ad492ccfabbad711645bd0d067ce415f4f96b1fdf27bd654db2faa46fb31c1e99bf2d9d09537b38dc4be2173b92461a1af06a93cc16703fb5b515be9efbfd666e9bb666fe4c49c201e72bd77295d175be43a95ddaa4792bdc9eaeb30369458e07fecfc35002a3ad35ac0cb +Msg = 92cf3716e22f68d30211401034fc3839c94f473695e0f836a0e4bfab1e0f8d95a2fca2048ecea3d8ce18ecccc6fa27b3888d1d014b81cd8c1905bb94c7e78b012afdceed88c31c624d456365ff407e3374840aca439c75ab78b157df8cac0638949b65d9b856fcf8e7624ee3c9156641f5fbb49b6579171b26b03b9354a425c0 +Mac = 490450772d57cde7f86f9d685d070c23794cedc113143c441dbf5b4d787fe6e619b6e6a286a3913e1d713f4b28af2477cf3453c41529c2ec + +Count = 346 +Klen = 142 +Tlen = 56 +Key = 49a75faf8232544d78234c3f4fd9bd7b35996217f5d579b2c9ae2f1070b7590481fc6493ff438f562d915720a4f033e1a27082caa56cc2b2390e02b90e159a2b4dd619a72c817f80c1a6ad6313f8193a7750c6511af574b7da1a14e85aa87ea8553e663232768c92d96b3450c678d64e5b4216f37bf8f68954d94be47cf76e45403b337e39aa1f5620e6d52ee2f8 +Msg = e4437faeaa8e071f7fd71b5d9b42db5643d0d7ad9ee17f5fc5f8dca619bf7e1dd94bb625f4a005881b78d35d1b40642c6a640952ffcc93a667a70d5c1667ab2afb0cfdaa57a66800ce15d7bcbf14ae02d17600e8ceae011fb595bed60a680bdb7110bd037ba71acdc0378e422ec5a01fa08e2336b290b112d44c55da9ecb8877 +Mac = a093df05d8df35bb12de09c9aedb23dcfcd517df6f0cdd1886d4c736c85068f9f19486051d223df48509a2a6e1b50ce22429efb8f0797823 + +Count = 347 +Klen = 142 +Tlen = 56 +Key = ab3ec2eef335aef9a9d3d0da7082ffdcf77e93ca737e77af4d9680e0175cfd3cc54a90b31a633c056019becc5c6f21bd815b8d2b646e60cc70b67fc0dbe4efcfd8aa9ff30f6788164a06f81c71232b24b8701c0b17589a32fbe29e823bd7dcad4d2798b6ba89bbb3cf6226d295e8469a0487e9737484506954e0852d1e7fef5c8a8923040311fd6557f4f0f4b204 +Msg = 81159166393b6f178964edf61b612215cb6af701001d24e93dc45b03f3d7c22c9ac2a7cfffe77007e0e7d008b61d41bbd26caea8ab3b6f1977bd7b7cf876d90a99fb58a6b9f980084778c81a8f610aa2533e33221e423ffcd58965da8fa08e4da6480cb50f778960e6a03df64d3465147769f037003a7bdc80af7fe55f5ec93f +Mac = 866fd902b3bca0ae39abf8712fc35ce9bc0ae280b6bff7078b5d17711d7662eb547fb5326a9f739a5e24ab125386392ca74d24d10335acbf + +Count = 348 +Klen = 142 +Tlen = 56 +Key = e5ce84beecfd6fdf2ba0a229dd18d214eeafec6460729fa1ed3f1ac8ee1e17407bd4180fd4b6f04effbc86dab3d6d64d7583382d019fe563eb7cb7ee863530d8053fbe69e0413d9c7a26becf007087be94cf5bb2abf2fbf6b39dec8bfafc7b1ccb37ff34da465eafe107d26f8c8ded5093bbdb5d2512e8448dc84107101afff514e361d9886c59717f864b211ed6 +Msg = db6e03879e21326121aaa331892a3d5199e7825077fc6f43b34fa35b85c4c4bd56b01f8d82918e4c5dfc9f6574d6f20215c7e32411ec69f3c0cc3e53468e41b71569183ab35b19ecbe1e6b692d5868b1d81246333b6bf72b768d4d2e99e162031f7f37b5b8e99be64cf84f663c166705ebaef3a57de1df93de7b18170625f049 +Mac = 478afd001acd85badaacf824427098bd5c574340e837bab8c8e608b0654cd2de85e3e697252803cbeccb8770b1fe3b5ac1915b1b9b93864b + +Count = 349 +Klen = 142 +Tlen = 56 +Key = 79e902e852b2e7be8347f379fa29b636ef0439acd1d792698056b65ebc8d8f9edec54e63c5ab035214af6a009bab08b412c5776f0d96ff292c8c665e928c08c999dc2a70c4418be0f6643cbae17ab26ec0241a474994eca8ddf2c39503fe6c7414f63c1538baa7f1902e0fafb5e0daed62ebc73c6d1b826cfc51760bf529e228b6db2f5c075f810c4cd58ce80023 +Msg = 7d1cb6b5c810a2dccdc7651cb460f4a5b9b315347586c4e65f05d54e926cdcc5d1074a01c85cd8ea94a729a88686aa0124f6bee2717e183b6faa6710e1bb39ce559d19db6219fb702f4cdbab3458a0e045594631cc9b3c5e560a0bde51e9392e13c76d691fafd319a4a0c24c473c9deb22c4f7480d44faf61c0b09dd695ea48d +Mac = d1004dc9d78d4559d2592cc1e8d960fead0f94ecb45e8f538883d930f227ba26e865fd366ac706823729977cdc50eaf03bdb1727d2818cf9 + +Count = 350 +Klen = 142 +Tlen = 56 +Key = 78d9947c69e6154472e40ccdcb41fc21a18329030195a0ddf85e77faf99856f57ee03772f209690bcfb6db8e0428976599548d559539926c2070a834e505802dba853d7a83587bdb535190dbd584114beb5899ee94ddc576135f83af4e3b8dfb74f130fee27b529a48ddb31e07fe73badeb6d537c62842e41a5291d4fbe28546f34b9765d819f632f481cdbe623d +Msg = 5c128db8116c5615164550d509171ee4b4d1014d847beeff3d1ce4d2eddc7cc51f66c28950904344a73e678fe08301c08a0a256f72b53a335f834fadffb7b3c82237bf3e2632f75fb205520ea860d50c54a46679ea90e0972f1d63d276a6eefdce4c2fdf7a9999eea164b85a47f4c14d7c686e72d35508b416b2c54838f155ed +Mac = 6ade4411b042e26847ffba81f9d77f1d6d452ae12aec7eb2926a6db35e1a339f2ad3c628a7ad61c7cffd301dd18403703059e6e218508f7e + +Count = 351 +Klen = 142 +Tlen = 56 +Key = b6ee6f1a804c6552d1b06ed4b3117b5e3f2f19da056cf4d6aedd9a34e0a1822362714d4e81794b53b266417678c16a97887bbb612cc96bc5e532b3a654e5d3d65a5155427ff09569906381138cc49e3fc2384c5d33c34abd3d617c487b52ec6ee7b5105f41584b7eb5cfb512b8c31f3f338d5236e30398a8ff927e801c8ed7d14fc5040d915a737967d166ddc266 +Msg = 1fa2f26ced0d74dcf81a0640c50a708990f8f939e31792c7673c5245fb9c224003d6bae80234cc706c2d7eb8b52f1e2aae9c11e211130d115af089a3d916711f06ec1dcf14a58422c9c5ad4e8ce06739c0a53a9a501c9d5b8b2c694333608ed1d0eb056b4ae906b8b7e77a4a72a6b3806d1c5baac8bcaa6fa2f7dc6c2f03e31e +Mac = e145c5715b9442347f09405640f2af5bec8d8699f458d4c69a0f823fe9e2a6676759359c8a73ccbc34253f38c81c7ebacdd433ee1913d19c + +Count = 352 +Klen = 142 +Tlen = 56 +Key = 63c866198ef4216d41106fda34c4ebdd040a39de8731f3585d28e639c7f97f8cbc9480553acef7bcdba9716ea8d66b4131780917de2b0b048045fcb32b5cac054808e1fce6e94ad851ecb47fe6cb802225d3551e08ea122093d0078dada564212eacf1d6394e0007cc62a1d595ab14ca08a284bcae76f2f4c0526f90f4de8e26970819aadc04039274919e375e7f +Msg = afc68ef8a54dfdea5bceceb387f88b0c0ee86c981ced13c4738e79f303ce29d8bbaeac22a0f4445f1c2bdd1a98eb40474d5a8ae256f3dcd20a8655138a803d14966d835ea5bb6a7734c17f065e00ce37ada85561305eb9e7cd3c385cd919dfeae60bfdf4dc2bd7fa4c989dbd00bf9da4d7d9b75fd0b411ca64b70c1419217620 +Mac = 2c547e05592dc04ea530c9ae8949f3f9aa6f9563e69c1de166591e24a6bb4e6b1414a079734ff28597cab217161e147fb51a1434e9fd21e3 + +Count = 353 +Klen = 142 +Tlen = 56 +Key = 7f432d3c5b0b0276bdf36541c2f180ee0684ec7e174fca642a070f8c0d901f9b5d639e79f933820db6d06d47554b3b64b25bd66d3dff5201ae653655f50b177970246cdd613d9d139f205dd68cf93a4c46b7728822b50953569a182cf57e688d214e3f707c717a12dfabdcf74f42a62e2c6068d6acb916e1886d5e18f530395fd6a8c13b30164291de3993b18670 +Msg = 15ef510c252e80f44e537b0f1fbbf3d57dc69ac349e8e6083dfd128217dd67e8fa31b949118534b5759e593a510d431244042f1a06693b864f296ed3f4cff9fe5355bcf4f2390c4963d4b42c6be8399b637863d3dddcf80b8b14cb615d5df515ea0263f511759118e09e94cfb4735ed9a2c93ed61669a6feba6731139aafe494 +Mac = 74787330ed257b3c1f545207d42470732c4415ff9f19b243128c9cd9724ebbc15cdd14b1d8d5b12a709e5709691c334207e940b6701661ae + +Count = 354 +Klen = 142 +Tlen = 56 +Key = ce7509e8e7c29911223037bdce5c5d8cda10fcc050ba1b4e201cc1341f44160e4fbfc5e4610aa4477849979c303bb2b7df6e9dac1baf3de17cc59068a25fd98c7a4afeaabee72e43bbddc64e570b76d352c1a0b5cc2f00d0081d92436fddb00fd87e7be206437d2d72538d7c4bb2f207bc70cb846d21ae404c8d8f6e8da8e3bfefc406334205da2e2615b2ce151a +Msg = f6152e7422034d9c5c8192d1ec85a965eb978bb555903d095fa2babb0a982e9cf85f64937ec68287fc82f47f6975a608323076d845b6e9b068821c87d0ccfee4ef09bd8c8db17e5d1a44517a438f64a8c32c77f87c488fa7c6a8ef4207ee440d841920a6764ca9e661d09308a15b4b0d4593755e21ce99b41f1c1935d68767e0 +Mac = 4a8dfd230cd6f466a29c8f0737f5c8253f06694a43a6f1bd78cdee2fdc397eb68f70e242992d68f23904cfdcbf4080b4fb91da0cd58f7384 + +Count = 355 +Klen = 142 +Tlen = 56 +Key = c73132626516889283f28fef56fa340450a6a592396d0a7b81cf70ded5990584f0658b7bb46007007950b9a3a5d551a57cee60a53ac00d7b5f9309654b1ec5610a04e2d9719ee9856afb3c8e8c254cefefa60d213e4ba7f70d286fc76ddc15cabe171ec5c55995e9fffcfef834748caa4ed6944f6c9740b53396884c645d5e88b4a42987d81775f4df5ae92bc449 +Msg = b1e626fd2455c59e04b0ff4e1d2894d9dff62765aa92a2474926d71bbc4263133ad1d88f764c1bee222d0aa4b1a7628d6294e0827aafa729d003e2118fa3aafe389c2a81e62801ccd624e7c526c49459dd86de132c6421edf44ee36687d7b8d4b32f64fcfd5140e02a7ddfd804e9f0e45ab46641491bd73abaef22412c46553e +Mac = 2b5ec29766abddac4939a3610ebf2a043873cd15bc121d8ae6dea60af0fd03b348f835b32988998630590994217d053cee8fcc4017efed80 + +Count = 356 +Klen = 142 +Tlen = 56 +Key = e0ff5e7b2612bbe69ebeb72d5826ff1b820f4e4adb8a86e96bd4ffbd727a1f669ec02be480445c5941df361091cc15bfe10c0909d208e347ed7990889485a6d6382a3dbccde000057b7a84c5974ed89ed1955d3caf15d7223afdc5a9f710ee4518053d0bf42ece70b559495450f46f3fbb74f2ea5af78a01ba27452781621f3ba519d2d9dd76ef2455422ec3a605 +Msg = c213d3695012190b4ea9dd66912db20d687b897d758328b9bb08d831f7a15ee834042dd69a83da8c87d7d016e11d4525aa1e6d6ed4d3ed4d572992ae8201432d8e7b347c79745d05124d2bd150ee75a9e70bb17b1da668ffdad6e799ffc63882f900502396ec8ac11793545f86a928e04acbbf6df80581166c973fbc19f9242e +Mac = 1252ceb41afebe8dd9ca1d4a01d1c07b6e39a0462c497eee7a778757aea39d0e5f0a1239f452663ada69d55cf2ba14836b40e2457933e37c + +Count = 357 +Klen = 142 +Tlen = 56 +Key = 59b5247df0ce81b59d0b40546ed185ff440be012d91d753702195a3832364011407e564a6ac66a8399e35151e71b8a485eda1e5902a6ca5f125560f48c7e6b89ef2d12b644db3fce5f9d00b7639b2df884c44b1411c0b017b126e86eedf058fbee2c216988f447bd789f132eea39b5373f312eea0c526d8766f4b84d5d744e90c6e14b0c3ef8cb796b53526085dd +Msg = 7dd26a4d522342a5e9c081e18925c6f2ef6adb5141674240481b1052d94fff2d9476be8fd2d88b8fd8ef042651113aedfb500828a09fa3044836711dad371f43ef91ee7e89244d4f8427ad39eac791807e11e431aa129062b93d4cbb460db536f4eba1226051b06e543024243e8ff234e0751873480a32e303f948358e18eb8c +Mac = 0c9eeaa855d460d0cfc0babe4c57110f0737b79e80fe76422832e47657afaf00944a061bf31c897e0a96abee0614eb755e37f1a7a2699f5d + +Count = 358 +Klen = 142 +Tlen = 56 +Key = 57c2eb677b5093b9e829ea4babb50bde55d0ad59fec34a618973802b2ad9b78e26b2045dda784df3ff90ae0f2cc51ce39cf54867320ac6f3ba2c6f0d72360480c96614ae66581f266c35fb79fd28774afd113fa5187eff9206d7cbe90dd8bf67c844e20228d8507ab87e993125c4643cfd8c58bab7053c64f4da5c6604a92f6eacb6380226e12a166ad54fdeac83 +Msg = ec99b8d92c7b68072a2e8b2d4c4eda6d3cab78b63e4ddde9c1b5123a336624da1aa4d3d3617c8a33ef04946c7fe48cfbab15154849e9cccdfb4c7b7b0249905953d0cd6fedb640e269fd7660d356ecbeb8e4c6e08043c3dafec97154460b9d33bfa30e767931735dc0a099d1f1abe1008c9ff2488b62ab56f2b45b8fa8b535ae +Mac = fbc3d7351550d40e77bac577fd9c180f2c9487d301a5d0e44f4b8dd207980c24973964ec21920ceac324fad4c88ca235d00e86ff9264d2d5 + +Count = 359 +Klen = 142 +Tlen = 56 +Key = 3fd3dd9d3a7c5cf7e2a1d60f489f84471902179f21f656ce0fff089278ea14441e04e7af71891622565f44c428044728fcc686212a32a5d809ce651bf90bc5f8a7756e8b8c2d4d14b799824ccd5a79fa4e7e56c119f7973c334cf44dc48f8ab1628f39d8924e4bf48cb656513f8763e495944f26f82f722315e27fcde060ab97d8ba123f8cd656eb5e1e89788775 +Msg = 05b2305a6264fb92280197a579b4d336395d5b51148adbfec2a3671589641b530490feae24e42ce6744a355da150c02839d87466b31118d0b0a6f89280358b5ae80254ae22ed068226a1eb0a280f86cd621b78fb1394a000c86a8659da1bfaa6386ff8016665cf8fc66d825417d76f4c3b8c2eb73dfcbcb49257d9119f00ae62 +Mac = 9b4f475853a268a72f31364df38438d3fdad705c9c50c8dab3d64e6c193dc63c6bbf399035641cd222c05aead20ba55c0df360483eadd7a6 + +Count = 360 +Klen = 142 +Tlen = 64 +Key = 01b95a887927ce31b1242391bbd00965eb77a903d4b8399b72e6cebda9ae721beefa779145160b626b110cc554671da0d8dcf993a9ab073888e02fa9b803ed43b3f6a3aa1d20340df6ccceac13cb0797cf612cb8fe5fd513228cbd4de249d16bb77587dde98f71bbba1a124ee046f0d239ccea7abb1accb5aab021b00dca491c623fcb3191a9ecf31fc680b4a41e +Msg = 632afa8e79b14b2a3604f5855d2bf182d3c56d6853f21fe46271da5286065f38b31f751306b63c57b679beb14729c78f0040f7e2a0d615224dc5a693cd0cbec8f87117656d6b6029853ed72b85681a63183c3a6dfccd128afb0dd7e81d36f0231c69070b189560a88c9b697b81b0930701026190cf9ebe23559194d6de4d9a51 +Mac = 210ad45ca2fd1f105c0a18f993774f933ece57ace4da619689e1cb8b491a189cc6e4ee1954a32201072e70f934837c0fb6e239b4fdfbd26ebf11b9a919eafd09 + +Count = 361 +Klen = 142 +Tlen = 64 +Key = 61096f4fe5340488916de293be38cc3ae0c877670c713637b760d74fc18ac773b2e27d5543cf16aa20dd3d83ecb34edb8545bb6c8a4aaec81bf1f0a4e0cf09774d1ca944242046b33be807677f3de18c39d700af90cd68d34f50dcc1e999fe9fbb20b9c4900fdccb6af607e680c0cb7583e60dd825e2ab81dce7634de3cff0148355757f90841f19366f06a9f623 +Msg = 67e704046f98cb5aa97da95b19147391f05788f811366b0ece44b12af2b11e0e05780bbfcbd90a950e0acd8e9d2a44e7957606eedfbff212fa1c163cfbdcd062d2be3259ce65abea6406e4292c64e9022cfe89155986ffc45b96d289919ff98d552243778122f68231d9b6d3cbaaa9093d57d9158674da4c781bacbabce2e2ba +Mac = 9a2d147e50827157f3866e868c1cca9f081579c92f25da8cebc9ed249928c82bead39d480ecbb5b5d0e0755029aebf3e0206984f3ea83f4d6372f4453390e070 + +Count = 362 +Klen = 142 +Tlen = 64 +Key = c5c06993d43f27e86bff96ca7511176974bb63e618bfc4b610e0854820a3a6e77453d5e134479ae95868d2babeed5efd79691c6d6d0816391915faa9b3c0cb057a1fd5b34872e69f66abbbe0a52eb998aad5de1b8a37f654972a12657986368e802c5250384773d23ed23b83535b8f01af068f3a97d4cbd13225b3c3997c504a2d8332012d4faa4988e439eceffc +Msg = b53127b89772ea1ca6dd27277da80ed972e82f1232a73d4ba537118418c5f17d9a311329a61e5d6003456fd4e90ee3466561d3fafeb99c68997be2349a87d5604c0cb2c183a08caf80904c011474f73909072ffbbd36fdc41077cdd8805cba7c93680c667621ff72e366c7964703d01825834afeb546e5c7d2d3d958136e2a39 +Mac = e3a4d32f262c6cb0e99195c7439ad2731185c58811f40ecd32af214a21c20869aef5297cd951fec2a145e15f982266c46f7a60c9fb0bd0c6b16f5ee40fb44708 + +Count = 363 +Klen = 142 +Tlen = 64 +Key = 5860501208a4c922ad7550dbd931a19ac1434750e63d5f34f528a0b5eb1798b37c0338eeb6d293bfe2b9e306abc4cd6382b3e6a94008758f0d5e7ba981fcf0970aaa507d8ec456b3518c07bd18c4f37d8f7db8a7e82ac776c5f86b9d58620781c8ff9fa5d79f9965c397c5e869599c50b048c53325cade4fe39e7879b67063d780aa2d4fdb8ee53fff82246fe7aa +Msg = c35b26bd02499cdb6b06bfa4b18979f0a472ba7c559dbd277bf78c611590c6e051f2a094adb22ade5c44d4fdeb1330c924d1f9a3330c55ac07035735fbb7c877b64527844f72ee7eb58817074f61dff8dfc1ca56ace9e782e06855af2f350699b9fbc37532b47023407992ab24980ee79de8337d0959fb11cecf8eb8f83108af +Mac = 8c385547a8eba518e777c3593c5b7ce0bd7c859af6d67b6238d20a58b8d0d74d80d18ab358ef1c1218b928a026ae8c4e3b73bb5bc0914de905d499c75e6f3d9f + +Count = 364 +Klen = 142 +Tlen = 64 +Key = fe4c83e8496a69b7a251228396a5d2b4849edcee0ab1f8dabd6d872a1da324d7c8c97cadeda05f0a041517e3bc65f807358538a870c1011704a3c5cf1216d2b57acb269e4fdc841289b0c750fa1e779184d59a9188fbcc4ca11492059326ec8d7e1a29c25866ff5699e9dbd2381676dad755a9b23ba68201fe8897d588199ae83b7e2e22ee85f95e9d89fb715e97 +Msg = c24fab7f7998c69063c2d1103e60a6c4cb03206add01d09faf75f1007a879e9047ee435a02b35257d1373791a4778d890c8f92d6507dd810be283eec3fa11fa82ea8c9aa6a723164aaa9e57a11b54127033ae6dd36e1682b0c5c47e420a4217e1e8525b8d95dcb7f9721c213afa02a66570c04c5b7b6e7b94219f430451a0cd8 +Mac = d725750a042de65607af5ef523e3c86d08be52427b7036ad514b9596c901e96d76b5e58f68907044282e695b3b875c09ad49ecd9950fe312a59dad691471c572 + +Count = 365 +Klen = 142 +Tlen = 64 +Key = 41f4749cded6e44c11b8118c38cd71cb95a26f9eff01bbbdd716e44e3ed02867858a8bcee5eb2603710ac28048d6a53f0fb6ac7d9f6c9abefa3fb01184597e95706ef83c789ecccfd19df3325e1186ea243bd4dcfedab157914c115583f7d5fee8e7e46efdb87eb819b7cd2be044bdd4ba7b0e438413a89285852ea4a371d5abd63e77edde02e3c731a178f23838 +Msg = 5c74212dfc2a80d30c39d680327d2488838c35d6503c1a8c4366d7eaabe95c7115f1b7481c7987de820eb4d17fd65d0f58d2123b346044522c04f98ea167c48ad2a0f5a8adb30db0e65775b947fd6f4d470d4cc8dd73e001965a332ce63779ffbb0a441458e1f98f619d800032f8408b75c74b46f47dd5e2abf1eb8e22616218 +Mac = 7e983cd601ff5837e7d170f3092e914e076c21b31761eb7b9ec211e3506758d8d1395ea914c0350afdd6827c0283ea4af188cf30c1fdf075e41363fbdbb29eed + +Count = 366 +Klen = 142 +Tlen = 64 +Key = fe27bbc87755aacc37f667f8ca37f8888fc9dc530fe4f8f38e8cd426e01307747edff012d96da707ee96338d1b11feba313a865fca115431dd8632268ff499224ceb69d31732dcd91e0cbd2b92bbd5b6b543a74735705daab81a0114b8a8f0be91d38cd3d8ad328cefe16c99d63c67c4446ca7d1f708f9a848d1a9b60238f6907420c3d9c5e48f67889ca7a1909c +Msg = 99841c3e4a41b53c30267dc056e7e9b8f9994494dfbba363ea761c38ec2433d3bd10957d8b7c093472e9a3084c923ac5cb3a1dd2c5270259ce6f3fa80c723dd847a829ac409decbb44395ed20045b694972b4663f2fd658458b9ac7d3ecc65c260d4409110aa481bcea016e41a07446c86f5250f0f45b32aaddec97f293993db +Mac = 562b5ef3d5cec882a2f54f8169612dba2b033325ce5ed924024e7806c745de9e7612dbcfcbb95ea3fdb93de9c6460a866bd412b45eaba5139939fe43d20f9315 + +Count = 367 +Klen = 142 +Tlen = 64 +Key = 29f8eb9fc8ab58fef681f9faaf934e992d42046f0ccd2fc9ab23d42bd5f5aafda110218196eaa408137a1b66ee4db5a35cd7e4f31107a9e8a81e11e744c000d9784b2d2264696ed721e1362b60b35b2b4d631dacba95658179da4af109cad9687653166c7a503ed3e85d4f334aeaca9bc98fb8804e9febfae70086316c3ac01162cde4461fc89c642f977065f71d +Msg = 3ac2ffbc5b6b2334809232c0f8151ed379a8634d70d3f5a1963a7637c421ad0f082f34a8f872702046a4c69c95ad0cea8b683e6528aa731956810f28c1b9396de8a5905e751c1937c9c17c55dc8771df447575ac93a7c161e6967cdabb9930cc03ab7ba8796e07c23170bbb274ad33facb566eea5ad1c7c16f0127155bc77875 +Mac = 38ca18d60f180fd2a40e342272190d9b84ba37bbccf59b29bcbdb08762a90e1f8b28349ca634a6f955cc08c96835ee70a2267444fde88b45b8e313b0daf6e12f + +Count = 368 +Klen = 142 +Tlen = 64 +Key = 345479ae901adbac7223f5f9edc419bb64665cba4e3684b7371e28ff07f3124087f0e89a21630cf9e8a6c0a3d8518e0d5eaee7f31b6d0aa7e59927aa0ecbc479e99e61a98b625736cf1506199d8f2f186bfc9fe2038f0e5b87754635b30888c063462b035581860b2f571083c4e5c6859338cdb09004597b2899cdc87f1224bdfcd08fcf07275f1f1156260ad5bd +Msg = e4b38e556aa285688979a55eeacd7d953f1ee0ab8109444c7cc068488eb83ae9aca1f783a59b944caba75d6e0f5bdc5b4cdbfc6147046e7ed5ea4c757e85fc2181a7580a17310b36fc873e422c4175b1ea24b3830750e50961ba7df9aadd5ebe6badf81148cdb4cd850192ffc9e6103d22e14f3a4a557197291945fb9a292665 +Mac = 24d2dd3d082e6556dbe27381640837a23e5d4a4d6822066cd09217a677068e5b8901c1eca7da77a9595be271abfa76f9d40656cfbae050ff6d8ddedb0f4c82ed + +Count = 369 +Klen = 142 +Tlen = 64 +Key = 2aa1d94ec83ce7c3c75c6bc847759b085234fd44b407d8f80ddfe93c243556e87e4be8fb30b4743ef1169a24732fb2f5f416042b10c3371dd9d20dda29844d58370700ce69f7df5e69240df77b96027a0ecec71b904f690b875da854de05ef047c5d898d1c0d116c580e2a0906b271dec8e5b0dcdfb2550a40092270eabf253376d6eb01f0fff1afe55d5b21bd8c +Msg = acf624e86580af11d0d23c19df6969fe2ec2cdc737bfd00bc54dc0b2ab4421ffb58f44cfdf8c1b1bc5b54bc45b818390de850c6f0adfa2048ed48360bdb8c511860eec5ba6f1bcc51cb34cd8ddc35c23cad4e882df3bfea0ad99ccbb0abbfda707be461622773b16bd1268dbcff89dbfdaf789871d9d8ae80ae4c44afa1571cb +Mac = b6e82d35182ec417bb33d9230a55690f8720d32191cb5cd46bfd591421911727a0f8ff64ba6e16f25aa10669a85bf2ba74d84a754ed947335b7a17af0297accc + +Count = 370 +Klen = 142 +Tlen = 64 +Key = cea946542b91ca50e2afecba73cf546ce1383d82668ecb6265f79ffaa07daa49abb43e21a19c6b2b15c8882b4bc01085a8a5b00168139dcb8f4b2bbe22929ce196d43532898d98a3b0ea4d63112ba25e724bb50711e3cf55954cf30b4503b73d785253104c2df8c19b5b63e92bd6b1ff2573751ec9c508085f3f206c719aa4643776bf425344348cbf63f1450389 +Msg = f3ac4422cc724378100d7515ddfbf3fe340002b7976c43acd69c2acf26c3b18173eb4eb6f73622540c6a73dd3eac5c4ea58cc34772428c6bc7370c0accc8c1feff4640d2cb416e2a5d06f35eb366ec69f5b9e0020923f6086216652318182ba93ec702be701a90c0abe9dee261b00b16cd9042318596e9494e401b62333d594a +Mac = d336f2002c558eb518c773608387bd500704156043b76104eca2309afa67d69ad9b00e6b83417e088d3f93435922d4e8242e9631f962cd9fc258f3505305d636 + +Count = 371 +Klen = 142 +Tlen = 64 +Key = ef71b7b3ca0f904dc50447ae548096b2b3603b312a5e59d490851b270ee99aef259401bdf2c3efc3b1531ce78176401666aa30db94ec4a30eb281494bef5205dd87f3350c1c4a56f3d040b12167214391b30b121697a7915e9224b871a3c355f111a9493be7b7df870ff5c589bdedbc4dada062b3072ac2c93590829ab26a09dd74d6eaf714e3e07532c57e09921 +Msg = 50ec304fa342839457d7eb28791b671ba5c425f711c3a351cc76149d481f0547179540fff239f054ff2c078454bfdd92b72b199aa783d562a1e6fd319cf9f8e4d6948b3ed2bcfa80a1d270396209a060051eada0544347f3335c1872266d5e6c1553d9b54cb3e740c631eef0abe2faac1703a7b21deb422d0c3e2b09f0647d06 +Mac = 39d94c4e1c8456bed8637e592e4231854df3a6ffce98463e4a85c477d9fd34d27035cdfccfcfd385d91e4e38e8c75d9ff941de80742e985baa9c94dbec5a6837 + +Count = 372 +Klen = 142 +Tlen = 64 +Key = e5606f31ca4d0f5d62730f443f6db0edd8224f1881eaf27f9af3215d06e2f72ddfbd78b467082541422ece34e323a8bd45489fe6db8fedd4c9dfec4954ba286e971db9d078a7d0a8dbfe8f5f166f1e51a4d4fbd21dbb916e65c40d75244b6db87747d98de672371995abfacebe983a325e8f0ae22fb706d7d76a2be95fdeec91e60581f397b1831cd8fcb688c4e7 +Msg = 082e7b4604dbd3608df7932475e4279bb288688ef998cceb8e16d9695a18e06f3ecce733a7b9e71f62473878b2824941a01b945d93afd1f5204c6a19233230aa0fd64c77822d78a61d266f569279a182fe9f2c287a2108abec16817724e7ebe32456915bbebfeebe659d20053d4f9926741d1837d576d7d79a7b06ca82c279e3 +Mac = d675982ccc457324e24a8ac6db3710b38e5f18c5057730cb7ea2a37b4ba44c41dde0874e43836cc95e97ff0b3ac10410497f9664177b0e576be8c508ab1c7857 + +Count = 373 +Klen = 142 +Tlen = 64 +Key = 8a0349d4d1ed8c4af533e9e83468b5859bb68237798038171346684499c9dc2b5970730533eb2ca04d1680630820f58d32ecf0bd7db7cab72ffc27651c94831cd1220e2113aeba6c889092abb3904d8a264b2332f2d9df0f63ac36d7eabb57c85be0c331587f5f330d69c7c91f00e606de9bc49ec22c9ea815203ca2ed867fb65d743a3beca6427f4669c9c432b7 +Msg = 035f55033df01f670015a828eff154a245e8ca7474b0b3330cabbe5fdd74e89560b8fa075347532aa46ae7ae907888b30ca4653a6419d0d9224944b43181a6a842c1cbc96fcc3b0f1e7b344c2956f2613c652eb27e44e5d773765a9521fb5e0c7125cf31d9a75f7f38ef96ea01b61b159cd52fc4095a7a94c7db0aeaf40a9929 +Mac = 3780ef695742f09a160c8dd7d35e2758b08284e8150934d222db31df2767d40d7c815c526ecee5f787030c8dc5f050c419ec6ea7563650dcce1480892d3088e6 + +Count = 374 +Klen = 142 +Tlen = 64 +Key = f78343071f61ee7d9f791bd53132e6d557928bcfe4b214bebf6f3592e46374c7ab148c3c4d6a1443a4675cf4321298c865b440631947b6b05f2c2a337d1cbb9b3661de974b4604eb41cc77c3659e85470e47e16f22a34619db935d59cbf5e1101ed401c020db069eff1035e9d1bff77bd8b3379e05ac0c20bc0e98aad7d7304dedd3bc5ed4136184649b5e0f7e5b +Msg = d63b50b54e1536e35d5f3c6e29f1e49a78ca43fa22b31232c71f0300bd56517e4cd29ba11ee9f206f1ad31ee8f118c87004d6c6dfe837b70a9a2fa987c8b5b6680720c5dbf8791c1fcd6d59fa16cc20df9bc0fb39f41598a376476e45b9f06add8e34af01b373a9ce6a3d189484cacb6cbe0d3d5ef34d709d72c1dee43dc79da +Mac = 086f674d778db491e73b6fbc5126233c6b6e1f066963356d49ea386d9c0868ad25bf6edad0371cde87cea94a18c6dba47535dfce2e40d2246ab17980495d656c diff --git a/firmware/src/hal/x86/test/hmac_sha512/Makefile b/firmware/src/hal/x86/test/hmac_sha512/Makefile new file mode 100644 index 00000000..01ef4d0d --- /dev/null +++ b/firmware/src/hal/x86/test/hmac_sha512/Makefile @@ -0,0 +1,40 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +CFLAGS += -iquote ../common + +PROG = test.out +OBJS = hmac_sha512.o endian.o test_hmac_sha512.o ../common/test_helpers.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) ./*.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/hal/x86/test/hmac_sha512/test_hmac_sha512.c b/firmware/src/hal/x86/test/hmac_sha512/test_hmac_sha512.c new file mode 100644 index 00000000..783561df --- /dev/null +++ b/firmware/src/hal/x86/test/hmac_sha512/test_hmac_sha512.c @@ -0,0 +1,183 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Taken from https://github.com/someone42/hardware-bitcoin-wallet @ + * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with + * the powHSM HAL by RootstockLabs. LICENSE transcribed below. + */ + +/* + Copyright (c) 2011-2012 someone42 + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include "hmac_sha512.h" +#include "test_helpers.h" + +/** Get minimum of a and b. + * \warning Do not use this if the evaluation of a and b has side effects. + */ +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/** Run unit tests using test vectors from a file. The file is expected to be + * in the same format as the NIST "HMAC Test Vectors", which can be obtained + * from: + * http://csrc.nist.gov/groups/STM/cavp/index.html#07 + * \param filename The name of the file containing the test vectors. + */ +static void scanTestVectors(char *filename) { + FILE *f; + unsigned int i; + unsigned int key_length; + unsigned int message_length; + unsigned int result_length; + unsigned int compare_length; + int test_number; + int value; + uint8_t *key; + uint8_t *message; + uint8_t *expected_result; + uint8_t actual_result[SHA512_HASH_LENGTH]; + char buffer[2048]; + + f = fopen(filename, "r"); + if (f == NULL) { + printf("Could not open %s, please get it \ +(HMAC Test Vectors) from \ +http://csrc.nist.gov/groups/STM/cavp/index.html#07", + filename); + exit(1); + } + + // Skip to past [L=64] (since we want the SHA-512 based tests). + test_number = 1; + while (!feof(f)) { + fgets(buffer, sizeof(buffer), f); + if (!strcmp(buffer, "[L=64]\n")) { + break; + } + } + while (!feof(f)) { + skip_whitespace(f); + skip_line(f); // skip "Count =" line + // Get length of key and result. + if (!fscanf(f, "Klen = %u", &key_length)) { + printf("fscanf error when reading key length\n"); + exit(1); + } + skip_line(f); + if (!fscanf(f, "Tlen = %u", &result_length)) { + printf("fscanf error when reading result length\n"); + exit(1); + } + message_length = 128; // that seems to be the case + // Get key. + skip_whitespace(f); + fgets(buffer, 7, f); + if (strcmp(buffer, "Key = ")) { + printf("Parse error; expected \"Key = \"\n"); + exit(1); + } + key = malloc(key_length); + for (i = 0; i < key_length; i++) { + fscanf(f, "%02x", &value); + key[i] = (uint8_t)value; + } + // Get message. + skip_whitespace(f); + fgets(buffer, 7, f); + if (strcmp(buffer, "Msg = ")) { + printf("Parse error; expected \"Msg = \"\n"); + exit(1); + } + message = malloc(message_length); + for (i = 0; i < message_length; i++) { + fscanf(f, "%02x", &value); + message[i] = (uint8_t)value; + } + // Get expected result. + skip_whitespace(f); + fgets(buffer, 7, f); + if (strcmp(buffer, "Mac = ")) { + printf("Parse error; expected \"Mac = \"\n"); + exit(1); + } + expected_result = malloc(result_length); + for (i = 0; i < result_length; i++) { + fscanf(f, "%02x", &value); + expected_result[i] = (uint8_t)value; + } + skip_whitespace(f); + // Calculate HMAC-SHA512 and compare. + hmac_sha512(actual_result, key, key_length, message, message_length); + compare_length = MIN(result_length, sizeof(actual_result)); + if (!memcmp(actual_result, expected_result, compare_length)) { + report_success(); + } else { + printf("Test number %d failed (key len = %u, result len = %u)\n", + test_number, + key_length, + result_length); + report_failure(); + } + free(key); + free(message); + free(expected_result); + test_number++; + } + fclose(f); +} + +int main(void) { + init_tests(__FILE__); + scanTestVectors("HMAC.rsp"); + finish_tests(); + exit(0); +} \ No newline at end of file diff --git a/firmware/src/hal/x86/test/keccak256/Makefile b/firmware/src/hal/x86/test/keccak256/Makefile index acfdf22b..b81c37d3 100644 --- a/firmware/src/hal/x86/test/keccak256/Makefile +++ b/firmware/src/hal/x86/test/keccak256/Makefile @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -include ../common.mk +include ../common/common.mk PROG = test.out OBJS = test_keccak256.o keccak256.o diff --git a/firmware/src/hal/x86/test/run-all.sh b/firmware/src/hal/x86/test/run-all.sh index 1a466aa5..54e1f7d0 100755 --- a/firmware/src/hal/x86/test/run-all.sh +++ b/firmware/src/hal/x86/test/run-all.sh @@ -1,7 +1,7 @@ #!/bin/bash ROOTDIR=$(dirname $0)/../../../../.. TESTDIR=$(realpath $(dirname $0) --relative-to $ROOTDIR) -TESTDIRS="bip32 endian hmac_sha256 keccak256" +TESTDIRS="bip32 endian hmac_sha256 hmac_sha512 keccak256" TESTDIRS=${1:-"$TESTDIRS"} for d in $TESTDIRS; do From 0e388d1f8a93a3c5db7446406b0af45a9e8686a5 Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:54:26 -0300 Subject: [PATCH 14/50] Added unit tests for system module (#211) --- .github/workflows/run-tests.yml | 3 + firmware/coverage/gen-coverage | 1 + firmware/src/sgx/src/trusted/system.c | 2 +- firmware/src/sgx/test/common/apdu_utils.h | 1 + firmware/src/sgx/test/common/assert_utils.h | 1 + firmware/src/sgx/test/common/common.mk | 20 + firmware/src/sgx/test/run-all.sh | 13 + firmware/src/sgx/test/system/Makefile | 38 + firmware/src/sgx/test/system/test_system.c | 988 ++++++++++++++++++++ 9 files changed, 1066 insertions(+), 1 deletion(-) create mode 120000 firmware/src/sgx/test/common/apdu_utils.h create mode 120000 firmware/src/sgx/test/common/assert_utils.h create mode 100644 firmware/src/sgx/test/common/common.mk create mode 100755 firmware/src/sgx/test/run-all.sh create mode 100644 firmware/src/sgx/test/system/Makefile create mode 100644 firmware/src/sgx/test/system/test_system.c diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 9ad08746..7b18d01e 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -37,6 +37,9 @@ jobs: - name: Firmware PowHSM's unit tests run: firmware/src/powhsm/test/run-all.sh + + - name: Firmware SGX's unit tests + run: firmware/src/sgx/test/run-all.sh - name: Ledger UI's unit tests run: firmware/src/ledger/ui/test/run-all.sh diff --git a/firmware/coverage/gen-coverage b/firmware/coverage/gen-coverage index d4a647b1..e8d4e6cc 100755 --- a/firmware/coverage/gen-coverage +++ b/firmware/coverage/gen-coverage @@ -12,6 +12,7 @@ if [[ $1 == "exec" ]]; then # Run unit tests with coverage generation COVERAGE=y $REPOROOT/firmware/src/common/test/run-all.sh COVERAGE=y $REPOROOT/firmware/src/powhsm/test/run-all.sh + COVERAGE=y $REPOROOT/firmware/src/sgx/test/run-all.sh COVERAGE=y $REPOROOT/firmware/src/ledger/ui/test/run-all.sh COVERAGE=y $REPOROOT/firmware/src/ledger/signer/test/run-all.sh COVERAGE=y $REPOROOT/firmware/src/tcpsigner/test/run-all.sh diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c index 4017d207..0f5d4a1b 100644 --- a/firmware/src/sgx/src/trusted/system.c +++ b/firmware/src/sgx/src/trusted/system.c @@ -185,7 +185,7 @@ bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { return false; } - // Make sure both access and init are in the same state + // Make sure both access and seed are in the same state if (!seed_available() ^ access_is_wiped()) { LOG("Inconsistent system state detected\n"); if (!access_wipe() || !seed_wipe()) { diff --git a/firmware/src/sgx/test/common/apdu_utils.h b/firmware/src/sgx/test/common/apdu_utils.h new file mode 120000 index 00000000..6510ff81 --- /dev/null +++ b/firmware/src/sgx/test/common/apdu_utils.h @@ -0,0 +1 @@ +../../../ledger/ui/test/mock/apdu_utils.h \ No newline at end of file diff --git a/firmware/src/sgx/test/common/assert_utils.h b/firmware/src/sgx/test/common/assert_utils.h new file mode 120000 index 00000000..4d85271d --- /dev/null +++ b/firmware/src/sgx/test/common/assert_utils.h @@ -0,0 +1 @@ +../../../ledger/ui/test/mock/assert_utils.h \ No newline at end of file diff --git a/firmware/src/sgx/test/common/common.mk b/firmware/src/sgx/test/common/common.mk new file mode 100644 index 00000000..fbf7a6b1 --- /dev/null +++ b/firmware/src/sgx/test/common/common.mk @@ -0,0 +1,20 @@ +TESTCOMMONDIR = ../common +SGXTRUSTEDDIR = ../../src/trusted +HALINCDIR = ../../../hal/include +HALSGXSRCDIR = ../../../hal/sgx/src/trusted +POWHSMSRCDIR = ../../../powhsm/src +COMMONDIR = ../../../common/src + +CFLAGS = -iquote $(TESTCOMMONDIR) +CFLAGS += -iquote $(SGXTRUSTEDDIR) +CFLAGS += -iquote $(HALINCDIR) +CFLAGS += -iquote $(HALSGXSRCDIR) +CFLAGS += -iquote $(POWHSMSRCDIR) +CFLAGS += -iquote $(COMMONDIR) +CFLAGS += -DHSM_PLATFORM_SGX + +VPATH += $(SGXTRUSTEDDIR):$(COMMONDIR) + +include ../../../../coverage/coverage.mk + +CFLAGS += $(COVFLAGS) diff --git a/firmware/src/sgx/test/run-all.sh b/firmware/src/sgx/test/run-all.sh new file mode 100755 index 00000000..ea5c2acc --- /dev/null +++ b/firmware/src/sgx/test/run-all.sh @@ -0,0 +1,13 @@ +#!/bin/bash +BASEDIR=$(dirname $0) +TESTDIRS="system" +TESTDIRS=${1:-"$TESTDIRS"} + +for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null +done diff --git a/firmware/src/sgx/test/system/Makefile b/firmware/src/sgx/test/system/Makefile new file mode 100644 index 00000000..50550ca3 --- /dev/null +++ b/firmware/src/sgx/test/system/Makefile @@ -0,0 +1,38 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +PROG = test.out +OBJS = system.o test_system.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) *.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/sgx/test/system/test_system.c b/firmware/src/sgx/test/system/test_system.c new file mode 100644 index 00000000..b0c0b760 --- /dev/null +++ b/firmware/src/sgx/test/system/test_system.c @@ -0,0 +1,988 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include "assert_utils.h" +#include "apdu_utils.h" +#include "bc_state.h" +#include "hal/access.h" +#include "hal/communication.h" +#include "hal/exceptions.h" +#include "hal/log.h" +#include "hsm.h" +#include "system.h" + +// Constants +#define MAX_CALLS 10 +#define ACCESS_MAX_PASSWORD_LENGTH 10 +#define MOCK_PASSWORD "123456" +#define MOCK_SEED \ + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x00\x01" \ + "\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + +// Mock implementations +typedef struct mock_calls_counter { + int hsm_init_count; + int hsm_set_external_processor_count; + int nvmem_load_count; + int access_init_count; + int access_wipe_count; + int access_set_password_count; + int communication_init_count; + int access_get_retries_count; + int access_is_locked_count; + int access_is_wiped_count; + int access_unlock_count; + int seed_init_count; + int seed_wipe_count; + int seed_generate_count; + int seed_available_count; + int seed_derive_pubkey_count; + int endorsement_init_count; + int nvmem_init_count; + int nvmem_register_block_count; + int sest_init_count; +} mock_calls_counter_t; + +typedef struct nvmem_register_block_args { + const char* key; + void* addr; + size_t size; +} nvmem_register_block_args_t; + +typedef struct seed_generate_args { + uint8_t client_seed[SEED_LENGTH]; + size_t size; +} seed_generate_args_t; + +typedef struct access_set_password_args { + char password[ACCESS_MAX_PASSWORD_LENGTH]; + uint8_t password_length; +} access_set_password_args_t; + +typedef struct access_unlock_args { + char password[ACCESS_MAX_PASSWORD_LENGTH]; + uint8_t password_length; +} access_unlock_args_t; + +typedef struct mock_call_args { + nvmem_register_block_args_t nvmem_register_block_args; + seed_generate_args_t seed_generate_args; + access_set_password_args_t access_set_password_args; + access_unlock_args_t access_unlock_args; +} mock_call_args_t; + +typedef struct mock_force_fail { + bool nvmem_load; + bool seed_init; + bool seed_wipe; + bool seed_generate; + bool access_init; + bool access_wipe; + bool access_set_password; + bool communication_init; + bool endorsement_init; + bool nvmem_register_block; + bool sest_init; +} mock_force_fail_t; + +typedef struct mock_data { + mock_calls_counter_t calls_counter; + mock_call_args_t mock_call_args[MAX_CALLS]; + mock_force_fail_t force_fail; + external_processor_t external_processor; + external_processor_result_t last_result; + access_wiped_callback_t access_wiped_callback; + bool access_locked; + bool access_wiped; + uint8_t access_retries; + bool seed_available; + const char* force_nvmem_register_block_fail_key; +} mock_data_t; + +static mock_data_t G_mock_data; + +// Mock helpers +#define NUM_CALLS(function_name) G_mock_data.calls_counter.function_name##_count +#define MOCK_ARGS(function_name, index) \ + G_mock_data.mock_call_args[index].function_name##_args +#define ASSERT_CALLED_WITH(function_name, call_index, ...) \ + assert_##function_name##_called_with(call_index, __VA_ARGS__) +#define ASSERT_NOT_CALLED(function_name) assert(NUM_CALLS(function_name) == 0) +#define ASSERT_HANDLED() assert(G_mock_data.last_result.handled == true) +#define ASSERT_NOT_HANDLED() assert(G_mock_data.last_result.handled == false) + +#define ACCESS_LOCK() (G_mock_data.access_locked = true) +#define ACCESS_UNLOCK() (G_mock_data.access_locked = false) +#define ACCESS_SET_RETRIES(retries) (G_mock_data.access_retries = retries) +#define ACCESS_RETRIES() (G_mock_data.access_retries) +#define ACCESS_SET_WIPED(is_wiped) (G_mock_data.access_wiped = (is_wiped)) +#define ACCESS_WIPED() (G_mock_data.access_wiped) + +#define SEED_SET_AVAILABLE(is_available) \ + (G_mock_data.seed_available = (is_available)) +#define SEED_AVAILABLE() (G_mock_data.seed_available) + +#define FORCE_FAIL(function_name, fail_next) \ + (G_mock_data.force_fail.function_name = fail_next) +#define SHOULD_FAIL(function_name) (G_mock_data.force_fail.function_name) +#define FORCE_NVMEM_FAIL_ON_KEY(key) \ + (G_mock_data.force_nvmem_register_block_fail_key = key) + +#define MOCK_CALL(function_name) \ + NUM_CALLS(function_name)++; \ + if (SHOULD_FAIL(function_name)) { \ + FORCE_FAIL(function_name, false); \ + return false; \ + } + +// Globals +bc_state_t N_bc_state_var; +bc_state_updating_backup_t N_bc_state_updating_backup_var; +static try_context_t G_try_last_open_context_var; +try_context_t* G_try_last_open_context = &G_try_last_open_context_var; +unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +// Mock implementation of dependencies +void hsm_init() { + NUM_CALLS(hsm_init)++; +} + +void hsm_set_external_processor(external_processor_t external_processor) { + NUM_CALLS(hsm_set_external_processor)++; + G_mock_data.external_processor = external_processor; +} + +bool nvmem_load() { + MOCK_CALL(nvmem_load); + return true; +} + +bool access_init(access_wiped_callback_t wiped_callback) { + MOCK_CALL(access_init); + G_mock_data.access_wiped_callback = wiped_callback; + return true; +} + +bool access_wipe() { + MOCK_CALL(access_wipe); + ACCESS_SET_WIPED(true); + return true; +} + +bool access_set_password(char* password, uint8_t password_length) { + int next_index = NUM_CALLS(access_set_password); + access_set_password_args_t* args = + &MOCK_ARGS(access_set_password, next_index); + memcpy(args->password, password, password_length); + args->password_length = password_length; + MOCK_CALL(access_set_password); + ACCESS_SET_WIPED(false); + return true; +} + +bool communication_init(unsigned char* msg_buffer, size_t msg_buffer_size) { + MOCK_CALL(communication_init); + return true; +} + +unsigned char* communication_get_msg_buffer() { + return G_io_apdu_buffer; +} + +uint8_t access_get_retries() { + return ACCESS_RETRIES(); +} + +bool access_is_locked() { + NUM_CALLS(access_is_locked)++; + return G_mock_data.access_locked; +} + +bool access_is_wiped() { + NUM_CALLS(access_is_wiped)++; + return ACCESS_WIPED(); +} + +bool access_unlock(char* password, uint8_t password_length) { + int next_index = NUM_CALLS(access_unlock)++; + access_unlock_args_t* args = &MOCK_ARGS(access_unlock, next_index); + memcpy(args->password, password, password_length); + args->password_length = password_length; + return true; +} + +bool seed_init() { + MOCK_CALL(seed_init); + return true; +} + +bool seed_wipe() { + MOCK_CALL(seed_wipe); + SEED_SET_AVAILABLE(false); + return true; +} + +bool seed_generate(uint8_t* client_seed, uint8_t client_seed_size) { + int next_index = NUM_CALLS(seed_generate)++; + seed_generate_args_t* args = &MOCK_ARGS(seed_generate, next_index); + memcpy(args->client_seed, client_seed, SEED_LENGTH); + args->size = client_seed_size; + if (SHOULD_FAIL(seed_generate)) { + FORCE_FAIL(seed_generate, false); + return false; + } + SEED_SET_AVAILABLE(true); + return true; +} + +bool seed_available() { + return G_mock_data.seed_available; +} + +bool sest_init() { + MOCK_CALL(sest_init); + return true; +} + +size_t communication_get_msg_buffer_size() { + return sizeof(G_io_apdu_buffer); +} + +bool endorsement_init() { + MOCK_CALL(endorsement_init); + return true; +} + +void nvmem_init() { + NUM_CALLS(nvmem_init)++; +} + +bool nvmem_register_block(char* key, void* addr, size_t size) { + int next_index = NUM_CALLS(nvmem_register_block)++; + nvmem_register_block_args_t* args = + &MOCK_ARGS(nvmem_register_block, next_index); + args->key = key; + args->addr = addr; + args->size = size; + if ((G_mock_data.force_nvmem_register_block_fail_key) && + (0 == strcmp(key, G_mock_data.force_nvmem_register_block_fail_key))) { + FORCE_NVMEM_FAIL_ON_KEY(NULL); + return false; + } + return true; +} + +unsigned int hsm_process_apdu(unsigned int rx) { + assert(G_mock_data.external_processor != NULL); + G_mock_data.last_result = G_mock_data.external_processor(rx); + return G_mock_data.last_result.tx; +} + +// Helper functions +static void setup() { + memset(&G_mock_data, 0, sizeof(G_mock_data)); +} + +static void teardown() { +} + +static void assert_nvmem_register_block_called_with(int call_index, + const char* key, + void* addr, + size_t size) { + nvmem_register_block_args_t args = + MOCK_ARGS(nvmem_register_block, call_index); + ASSERT_STR_EQUALS(args.key, key); + assert(args.addr == addr); + assert(args.size == size); +} + +static void assert_seed_generate_called_with(int call_index, + const uint8_t* client_seed, + size_t size) { + seed_generate_args_t args = MOCK_ARGS(seed_generate, call_index); + ASSERT_STR_EQUALS(args.client_seed, client_seed); + assert(args.size == size); +} + +static void assert_access_set_password_called_with(int call_index, + const char* password, + size_t size) { + access_set_password_args_t args = + MOCK_ARGS(access_set_password, call_index); + ASSERT_STR_EQUALS(args.password, password); + assert(args.password_length == size); +} + +static void assert_access_unlock_called_with(int call_index, + const char* password, + size_t size) { + access_unlock_args_t args = MOCK_ARGS(access_unlock, call_index); + ASSERT_STR_EQUALS(args.password, password); + assert(args.password_length == size); +} + +// Test cases +void test_init_success() { + setup(); + printf("Test system_init success...\n"); + + assert(system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(access_init) == 1); + assert(NUM_CALLS(seed_init) == 1); + assert(NUM_CALLS(access_is_wiped) == 1); + assert(NUM_CALLS(communication_init) == 1); + assert(NUM_CALLS(endorsement_init) == 1); + assert(NUM_CALLS(nvmem_init) == 1); + assert(NUM_CALLS(nvmem_register_block) == 2); + ASSERT_CALLED_WITH(nvmem_register_block, + 0, + "bcstate", + &N_bc_state_var, + sizeof(N_bc_state_var)); + ASSERT_CALLED_WITH(nvmem_register_block, + 1, + "bcstate_updating", + &N_bc_state_updating_backup_var, + sizeof(N_bc_state_updating_backup_var)); + assert(NUM_CALLS(nvmem_load) == 1); + assert(NUM_CALLS(hsm_init) == 1); + assert(NUM_CALLS(hsm_set_external_processor) == 1); + + teardown(); +} + +void test_init_fails_invalid_buf_size() { + setup(); + printf("Test system_init fails with invalid buffer size...\n"); + + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer) - 1)); + ASSERT_NOT_CALLED(sest_init); + ASSERT_NOT_CALLED(access_init); + ASSERT_NOT_CALLED(seed_init); + ASSERT_NOT_CALLED(communication_init); + ASSERT_NOT_CALLED(endorsement_init); + ASSERT_NOT_CALLED(nvmem_init); + teardown(); +} + +void test_init_fails_when_sest_init_fails() { + setup(); + printf("Test system_init fails when sest_init fails...\n"); + + FORCE_FAIL(sest_init, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(sest_init) == 1); + ASSERT_NOT_CALLED(access_init); + ASSERT_NOT_CALLED(seed_init); + ASSERT_NOT_CALLED(communication_init); + ASSERT_NOT_CALLED(endorsement_init); + ASSERT_NOT_CALLED(nvmem_init); + teardown(); +} + +void test_init_fails_when_access_init_fails() { + setup(); + printf("Test system_init fails when access_init fails...\n"); + + FORCE_FAIL(access_init, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(access_init) == 1); + ASSERT_NOT_CALLED(seed_init); + ASSERT_NOT_CALLED(communication_init); + ASSERT_NOT_CALLED(endorsement_init); + ASSERT_NOT_CALLED(nvmem_init); + teardown(); +} + +void test_init_fails_when_seed_init_fails() { + setup(); + printf("Test system_init fails when seed_init fails...\n"); + + FORCE_FAIL(seed_init, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(access_init) == 1); + assert(NUM_CALLS(seed_init) == 1); + ASSERT_NOT_CALLED(communication_init); + ASSERT_NOT_CALLED(endorsement_init); + ASSERT_NOT_CALLED(nvmem_init); + teardown(); +} + +void test_init_fails_when_communication_init_fails() { + setup(); + printf("Test system_init fails when communication_init fails...\n"); + + FORCE_FAIL(communication_init, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(access_init) == 1); + assert(NUM_CALLS(seed_init) == 1); + assert(NUM_CALLS(communication_init) == 1); + ASSERT_NOT_CALLED(endorsement_init); + ASSERT_NOT_CALLED(nvmem_init); + teardown(); +} + +void test_init_fails_when_endorsement_init_fails() { + setup(); + printf("Test system_init fails when endorsement_init fails...\n"); + + FORCE_FAIL(endorsement_init, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(access_init) == 1); + assert(NUM_CALLS(seed_init) == 1); + assert(NUM_CALLS(communication_init) == 1); + assert(NUM_CALLS(endorsement_init) == 1); + ASSERT_NOT_CALLED(nvmem_init); + teardown(); +} + +void test_init_fails_when_nvmem_register_block_fails() { + setup(); + printf("Test system_init fails when nvmem_register_block fails...\n"); + + FORCE_NVMEM_FAIL_ON_KEY("bcstate"); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(access_init) == 1); + assert(NUM_CALLS(seed_init) == 1); + assert(NUM_CALLS(communication_init) == 1); + assert(NUM_CALLS(endorsement_init) == 1); + assert(NUM_CALLS(nvmem_init) == 1); + assert(NUM_CALLS(nvmem_register_block) == 1); + ASSERT_CALLED_WITH(nvmem_register_block, + 0, + "bcstate", + &N_bc_state_var, + sizeof(N_bc_state_var)); + + FORCE_NVMEM_FAIL_ON_KEY("bcstate_updating"); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(access_init) == 2); + assert(NUM_CALLS(seed_init) == 2); + assert(NUM_CALLS(communication_init) == 2); + assert(NUM_CALLS(endorsement_init) == 2); + assert(NUM_CALLS(nvmem_init) == 2); + assert(NUM_CALLS(nvmem_register_block) == 3); + ASSERT_CALLED_WITH(nvmem_register_block, + 1, + "bcstate", + &N_bc_state_var, + sizeof(N_bc_state_var)); + ASSERT_CALLED_WITH(nvmem_register_block, + 2, + "bcstate_updating", + &N_bc_state_updating_backup_var, + sizeof(N_bc_state_updating_backup_var)); + + teardown(); +} + +void test_init_fails_when_nvmem_load_fails() { + setup(); + printf("Test system_init fails when nvmem_load fails...\n"); + + FORCE_FAIL(nvmem_load, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(access_init) == 1); + assert(NUM_CALLS(seed_init) == 1); + assert(NUM_CALLS(communication_init) == 1); + assert(NUM_CALLS(endorsement_init) == 1); + assert(NUM_CALLS(nvmem_init) == 1); + assert(NUM_CALLS(nvmem_load) == 1); + assert(NUM_CALLS(nvmem_register_block) == 2); + ASSERT_CALLED_WITH(nvmem_register_block, + 0, + "bcstate", + &N_bc_state_var, + sizeof(N_bc_state_var)); + ASSERT_CALLED_WITH(nvmem_register_block, + 1, + "bcstate_updating", + &N_bc_state_updating_backup_var, + sizeof(N_bc_state_updating_backup_var)); + teardown(); +} + +void test_system_is_wiped_when_inconsistent_state() { + setup(); + printf("Test system is wiped when an inconsistent state is found...\n"); + + // Seed available but access wiped + SEED_SET_AVAILABLE(true); + ACCESS_SET_WIPED(true); + assert(system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(!SEED_AVAILABLE()); + assert(ACCESS_WIPED()); + + // Seed not available but access not wiped + SEED_SET_AVAILABLE(false); + ACCESS_SET_WIPED(false); + assert(system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(!SEED_AVAILABLE()); + assert(ACCESS_WIPED()); + + // Init will fail if either access or seed wipe fails + SEED_SET_AVAILABLE(false); + ACCESS_SET_WIPED(false); + FORCE_FAIL(access_wipe, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(!SEED_AVAILABLE()); + assert(!ACCESS_WIPED()); + + SEED_SET_AVAILABLE(true); + ACCESS_SET_WIPED(true); + FORCE_FAIL(seed_wipe, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(SEED_AVAILABLE()); + assert(ACCESS_WIPED()); + + teardown(); +} + +void test_get_mode_succeeds_when_locked() { + setup(); + printf("Test system_process_apdu handles RSK_MODE_CMD when locked...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + ACCESS_LOCK(); + SET_APDU("\x80\x43", rx); // RSK_MODE_CMD + assert(2 == system_process_apdu(rx)); + ASSERT_HANDLED(); + ASSERT_APDU("\x80\x02"); // APP_MODE_BOOTLOADER + + teardown(); +} + +void test_get_mode_ignored_when_unlocked() { + setup(); + printf("Test system_process_apdu ignores RSK_MODE_CMD when unlocked...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + ACCESS_UNLOCK(); + SET_APDU("\x80\x43", rx); // RSK_MODE_CMD + assert(0 == system_process_apdu(rx)); + ASSERT_NOT_HANDLED(); + + teardown(); +} + +void test_onboard_cmd_handled() { + setup(); + printf("Test onboard command success...\n"); + + SEED_SET_AVAILABLE(false); + ACCESS_SET_WIPED(true); + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SET_APDU("\x80\xA0\x00" MOCK_SEED MOCK_PASSWORD, rx); // SGX_ONBOARD + assert(3 == system_process_apdu(rx)); + ASSERT_HANDLED(); + ASSERT_APDU("\x80\xA0\x01"); + assert(NUM_CALLS(seed_generate) == 1); + assert(NUM_CALLS(access_set_password) == 1); + ASSERT_CALLED_WITH( + seed_generate, 0, (const uint8_t*)MOCK_SEED, SEED_LENGTH); + ASSERT_CALLED_WITH( + access_set_password, 0, MOCK_PASSWORD, strlen(MOCK_PASSWORD)); + assert(SEED_AVAILABLE()); + assert(!ACCESS_WIPED()); + teardown(); +} + +void test_onboard_cmd_fails_when_seed_already_available() { + setup(); + printf("Test onboard command fails when seed already available...\n"); + + SEED_SET_AVAILABLE(false); + ACCESS_SET_WIPED(true); + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + SEED_SET_AVAILABLE(true); + unsigned int rx = 0; + SET_APDU("\x80\xA0\x00" MOCK_SEED MOCK_PASSWORD, rx); // SGX_ONBOARD + BEGIN_TRY { + TRY { + system_process_apdu(rx); + // system_process_apdu should throw ERR_DEVICE_ONBOARDED + ASSERT_FAIL(); + } + CATCH_OTHER(e) { + assert(e == ERR_DEVICE_ONBOARDED); + } + FINALLY { + ASSERT_NOT_HANDLED(); + assert(NUM_CALLS(seed_generate) == 0); + assert(NUM_CALLS(access_set_password) == 0); + teardown(); + return; + } + } + END_TRY; +} + +void test_onboard_cmd_fails_when_no_password_is_provided() { + setup(); + printf("Test onboard command fails when no password is provided...\n"); + + SEED_SET_AVAILABLE(false); + ACCESS_SET_WIPED(true); + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SET_APDU("\x80\xA0\x00" MOCK_SEED, rx); // SGX_ONBOARD + BEGIN_TRY { + TRY { + system_process_apdu(rx); + // system_process_apdu should throw ERR_DEVICE_ONBOARDED + ASSERT_FAIL(); + } + CATCH_OTHER(e) { + assert(e == ERR_INVALID_DATA_SIZE); + } + FINALLY { + ASSERT_NOT_HANDLED(); + assert(NUM_CALLS(seed_generate) == 0); + assert(NUM_CALLS(access_set_password) == 0); + teardown(); + return; + } + } + END_TRY; +} + +void test_onboard_cmd_fails_when_seed_generate_fails() { + setup(); + printf("Test onboard command fails when seed_generate fails...\n"); + + SEED_SET_AVAILABLE(false); + ACCESS_SET_WIPED(true); + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + FORCE_FAIL(seed_generate, true); + unsigned int rx = 0; + SET_APDU("\x80\xA0\x00" MOCK_SEED MOCK_PASSWORD, rx); // SGX_ONBOARD + BEGIN_TRY { + TRY { + system_process_apdu(rx); + // system_process_apdu should throw ERR_DEVICE_ONBOARDED + ASSERT_FAIL(); + } + CATCH_OTHER(e) { + assert(e == ERR_ONBOARDING); + } + FINALLY { + ASSERT_NOT_HANDLED(); + assert(NUM_CALLS(seed_generate) == 1); + assert(NUM_CALLS(seed_wipe) == 1); + assert(NUM_CALLS(access_wipe) == 1); + teardown(); + return; + } + } + END_TRY; +} + +void test_onboard_cmd_fails_when_set_password_fails() { + setup(); + printf("Test onboard command fails when access_set_password fails...\n"); + + SEED_SET_AVAILABLE(false); + ACCESS_SET_WIPED(true); + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + FORCE_FAIL(access_set_password, true); + unsigned int rx = 0; + SET_APDU("\x80\xA0\x00" MOCK_SEED MOCK_PASSWORD, rx); // SGX_ONBOARD + BEGIN_TRY { + TRY { + system_process_apdu(rx); + // system_process_apdu should throw ERR_DEVICE_ONBOARDED + ASSERT_FAIL(); + } + CATCH_OTHER(e) { + assert(e == ERR_ONBOARDING); + } + FINALLY { + ASSERT_NOT_HANDLED(); + assert(NUM_CALLS(seed_generate) == 1); + assert(NUM_CALLS(seed_wipe) == 1); + assert(NUM_CALLS(access_wipe) == 1); + assert(NUM_CALLS(access_set_password) == 1); + teardown(); + return; + } + } + END_TRY; +} + +void test_change_password_cmd_handled() { + setup(); + printf("Test change_password command success...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_UNLOCK(); + SET_APDU("\x80\xA5\x00" MOCK_PASSWORD, rx); // SGX_CHANGE_PASSWORD + assert(3 == system_process_apdu(rx)); + ASSERT_APDU("\x80\xA5\x01"); + assert(NUM_CALLS(access_set_password) == 1); + ASSERT_CALLED_WITH( + access_set_password, 0, MOCK_PASSWORD, strlen(MOCK_PASSWORD)); + teardown(); +} + +void test_change_password_cmd_fails_when_no_password_is_provided() { + setup(); + printf( + "Test change_password command fails when no password is provided...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_UNLOCK(); + SET_APDU("\x80\xA5\x00", rx); // SGX_CHANGE_PASSWORD + BEGIN_TRY { + TRY { + system_process_apdu(rx); + // system_process_apdu should throw ERR_INVALID_DATA_SIZE + ASSERT_FAIL(); + } + CATCH_OTHER(e) { + assert(e == ERR_INVALID_DATA_SIZE); + } + FINALLY { + ASSERT_NOT_HANDLED(); + ASSERT_NOT_CALLED(access_set_password); + teardown(); + return; + } + } + END_TRY; +} + +void test_change_password_cmd_fails_when_access_set_password_fails() { + setup(); + printf( + "Test change_password command fails when no password is provided...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_UNLOCK(); + FORCE_FAIL(access_set_password, true); + SET_APDU("\x80\xA5\x00" MOCK_PASSWORD, rx); // SGX_CHANGE_PASSWORD + BEGIN_TRY { + TRY { + system_process_apdu(rx); + // system_process_apdu should throw ERR_PASSWORD_CHANGE + ASSERT_FAIL(); + } + CATCH_OTHER(e) { + assert(e == ERR_PASSWORD_CHANGE); + } + FINALLY { + ASSERT_NOT_HANDLED(); + assert(NUM_CALLS(access_set_password) == 1); + ASSERT_CALLED_WITH( + access_set_password, 0, MOCK_PASSWORD, strlen(MOCK_PASSWORD)); + teardown(); + return; + } + } + END_TRY; +} + +void test_unlock_cmd_handled() { + setup(); + printf("Test unlock command success...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_LOCK(); + SET_APDU("\x80\xA3\x00" MOCK_PASSWORD, rx); // SGX_UNLOCK + assert(3 == system_process_apdu(rx)); + ASSERT_HANDLED(); + ASSERT_APDU("\x80\xA3\x01"); + assert(NUM_CALLS(access_is_locked) == 1); + assert(NUM_CALLS(access_unlock) == 1); + ASSERT_CALLED_WITH(access_unlock, 0, MOCK_PASSWORD, strlen(MOCK_PASSWORD)); + + teardown(); +} + +void test_unlock_cmd_handled_when_already_unlocked() { + setup(); + printf("Test unlock command is handled when already unlocked...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_UNLOCK(); + SET_APDU("\x80\xA3\x00" MOCK_PASSWORD, rx); // SGX_UNLOCK + assert(3 == system_process_apdu(rx)); + ASSERT_HANDLED(); + ASSERT_APDU("\x80\xA3\x01"); + assert(NUM_CALLS(access_is_locked) == 1); + assert(NUM_CALLS(access_unlock) == 0); + ASSERT_APDU("\x80\xA3\x01"); + + teardown(); +} + +void test_unlock_cmd_fails_when_no_password_is_provided() { + setup(); + printf("Test unlock command fails when no password is provided...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_LOCK(); + SET_APDU("\x80\xA3\x00", rx); // SGX_UNLOCK + BEGIN_TRY { + TRY { + system_process_apdu(rx); + // system_process_apdu should throw ERR_INVALID_DATA_SIZE + ASSERT_FAIL(); + } + CATCH_OTHER(e) { + assert(e == ERR_INVALID_DATA_SIZE); + } + FINALLY { + ASSERT_NOT_HANDLED(); + ASSERT_NOT_CALLED(access_unlock); + teardown(); + return; + } + } + END_TRY; +} + +void test_echo_cmd_handled() { + setup(); + printf("Test echo command success...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + const char data[] = "\x80\xA4\x01\x02\x03\x04\x05\x06"; // SGX_ECHO + SET_APDU(data, rx); + assert((sizeof(data) - 1) == system_process_apdu(rx)); + ASSERT_HANDLED(); + ASSERT_APDU(data); + + teardown(); +} + +void test_is_locked_cmd_handled() { + setup(); + printf("Test is_locked command...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_LOCK(); + SET_APDU("\x80\xA1", rx); // SGX_IS_LOCKED + assert(3 == system_process_apdu(rx)); + ASSERT_HANDLED(); + ASSERT_APDU("\x80\xA1\x01"); + + ACCESS_UNLOCK(); + SET_APDU("\x80\xA1", rx); // SGX_IS_LOCKED + assert(3 == system_process_apdu(rx)); + ASSERT_HANDLED(); + ASSERT_APDU("\x80\xA1\x00"); + + teardown(); +} + +void test_retries_cmd_handled() { + setup(); + printf("Test retries command success...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_LOCK(); + ACCESS_SET_RETRIES(3); + SET_APDU("\x80\xA2", rx); // SGX_RETRIES + assert(3 == system_process_apdu(rx)); + ASSERT_HANDLED(); + ASSERT_APDU("\x80\xA2\x03"); +} + +void test_invalid_cmd_not_handled() { + setup(); + printf("Test invalid command is ignored...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_UNLOCK(); + SET_APDU("\x80\xFF", rx); // Invalid command + assert(0 == system_process_apdu(rx)); + ASSERT_NOT_HANDLED(); + + teardown(); +} + +int main() { + test_init_success(); + test_init_fails_invalid_buf_size(); + test_init_fails_when_sest_init_fails(); + test_init_fails_when_access_init_fails(); + test_init_fails_when_seed_init_fails(); + test_init_fails_when_communication_init_fails(); + test_init_fails_when_endorsement_init_fails(); + test_init_fails_when_nvmem_register_block_fails(); + test_init_fails_when_nvmem_load_fails(); + test_system_is_wiped_when_inconsistent_state(); + test_get_mode_succeeds_when_locked(); + test_get_mode_ignored_when_unlocked(); + test_onboard_cmd_handled(); + test_onboard_cmd_fails_when_seed_already_available(); + test_onboard_cmd_fails_when_no_password_is_provided(); + test_onboard_cmd_fails_when_seed_generate_fails(); + test_onboard_cmd_fails_when_set_password_fails(); + test_change_password_cmd_handled(); + test_change_password_cmd_fails_when_no_password_is_provided(); + test_change_password_cmd_fails_when_access_set_password_fails(); + test_unlock_cmd_handled(); + test_unlock_cmd_handled_when_already_unlocked(); + test_unlock_cmd_fails_when_no_password_is_provided(); + test_echo_cmd_handled(); + test_is_locked_cmd_handled(); + test_retries_cmd_handled(); + test_invalid_cmd_not_handled(); + + return 0; +} From 9668e492a915a8c0aed32c05832a4e90f5cfd6d0 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Thu, 24 Oct 2024 01:06:32 +1300 Subject: [PATCH 15/50] Version 5.3.0 release (#213) - Bumped version to 5.3.0 - Updated version references in firmware, middleware, unit tests, CI workflows and documentation - Updated CHANGELOG --- .github/workflows/coverage.yml | 4 ++-- CHANGELOG.md | 16 ++++++++++++++++ README.md | 4 ++-- docs/attestation.md | 4 ++-- docs/heartbeat.md | 4 ++-- firmware/src/ledger/ui/src/attestation.h | 2 +- firmware/src/ledger/ui/src/defs.h | 2 +- firmware/src/ledger/ui/src/ui_heartbeat.h | 2 +- .../ui/test/attestation/test_attestation.c | 8 ++++---- .../src/ledger/ui/test/onboard/test_onboard.c | 4 ++-- .../ui/test/ui_heartbeat/test_ui_heartbeat.c | 2 +- firmware/src/powhsm/src/attestation.h | 2 +- firmware/src/powhsm/src/defs.h | 2 +- firmware/src/powhsm/src/heartbeat.h | 2 +- firmware/test/cases/heartbeat.py | 2 +- middleware/ledger/protocol.py | 4 ++-- .../tests/admin/test_verify_attestation.py | 8 ++++---- middleware/tests/ledger/test_protocol.py | 2 +- middleware/tests/ledger/test_protocol_v1.py | 2 +- 19 files changed, 46 insertions(+), 30 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 1be1df43..8a688477 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -34,7 +34,7 @@ jobs: run: | aws s3 sync \ middleware/coverage/ \ - s3://${{ secrets.CODECOVERAGE_S3_BUCKET }}/powhsm_5.2.x/middleware_coverage_report \ + s3://${{ secrets.CODECOVERAGE_S3_BUCKET }}/powhsm_5.3.x/middleware_coverage_report \ --sse aws:kms --sse-kms-key-id ${{ secrets.CODECOVERAGE_KMS_KEY_ID }} \ --no-progress --follow-symlinks --delete --only-show-errors @@ -49,7 +49,7 @@ jobs: run: | aws s3 sync \ firmware/coverage/output/ \ - s3://${{ secrets.CODECOVERAGE_S3_BUCKET }}/powhsm_5.2.x/firmware_coverage_report \ + s3://${{ secrets.CODECOVERAGE_S3_BUCKET }}/powhsm_5.3.x/firmware_coverage_report \ --sse aws:kms --sse-kms-key-id ${{ secrets.CODECOVERAGE_KMS_KEY_ID }} \ --no-progress --follow-symlinks --delete --only-show-errors diff --git a/CHANGELOG.md b/CHANGELOG.md index d680f359..bcdc3c73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [5.3.0 ALPHA] - 23/10/2024 + +### Features/enhancements + +- SGX powHSM inital implementation +- SGX simulation build +- SGX middleware manager +- SGX middleware admin tooling +- SGX distribution scripts +- SGX tests +- SGX documentation + +### Fixes + +- Removed compilation products from repository + ## [5.2.0] - 09/09/2024 ### Features/enhancements diff --git a/README.md b/README.md index ee086462..7c54a95f 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ ![Tests](https://github.com/rsksmart/rsk-powhsm/actions/workflows/run-tests.yml/badge.svg) ![Python linter](https://github.com/rsksmart/rsk-powhsm/actions/workflows/lint-python.yml/badge.svg) ![C linter](https://github.com/rsksmart/rsk-powhsm/actions/workflows/lint-c.yml/badge.svg) -[![Middleware coverage](https://img.shields.io/endpoint?url=https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.2.x/middleware_coverage_report/badge.json)](https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.2.x/middleware_coverage_report/index.html) -[![Firmware coverage](https://img.shields.io/endpoint?url=https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.2.x/firmware_coverage_report/badge.json)](https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.2.x/firmware_coverage_report/index.html) +[![Middleware coverage](https://img.shields.io/endpoint?url=https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.3.x/middleware_coverage_report/badge.json)](https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.3.x/middleware_coverage_report/index.html) +[![Firmware coverage](https://img.shields.io/endpoint?url=https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.3.x/firmware_coverage_report/badge.json)](https://d16sboe9lzo4ru.cloudfront.net/powhsm_5.3.x/firmware_coverage_report/index.html) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) diff --git a/docs/attestation.md b/docs/attestation.md index 3cc0ac25..bba1a8bc 100644 --- a/docs/attestation.md +++ b/docs/attestation.md @@ -56,7 +56,7 @@ Before diving into the UI attestation, it is important to recall a few relevant To generate the attestation, the UI uses the configured attestation scheme to sign a message generated by the concatenation of: -- A predefined header (`HSM:UI:5.2`). +- A predefined header (`HSM:UI:5.3`). - A 32 byte user-defined value. By default, the attestation generation client supplies the latest RSK block hash as this value, so it can then be used as a minimum timestamp reference for the attestation generation. - The compressed public key corresponding to the private key obtained by deriving the generated seed with the BIP32 path `m/44'/0'/0'/0/0` (normally used as the BTC key by the Signer application). - The hash of the currently authorized Signer version. @@ -66,7 +66,7 @@ As a consequence of the aforementioned features, this message guarantees that th ### Signer attestation -To generate the attestation, the Signer uses the configured attestation scheme to sign a message containing a predefined header (`HSM:SIGNER:5.2`) and the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path. This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device. +To generate the attestation, the Signer uses the configured attestation scheme to sign a message containing a predefined header (`HSM:SIGNER:5.3`) and the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path. This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device. ## Attestation file format diff --git a/docs/heartbeat.md b/docs/heartbeat.md index 6d4f5fdf..58ec43ba 100644 --- a/docs/heartbeat.md +++ b/docs/heartbeat.md @@ -41,7 +41,7 @@ certification -- to verify. To generate the heartbeat, the Signer uses the configured endorsement scheme to sign a message generated by the concatenation of: -- A predefined header (`HSM:SIGNER:HB:5.2:`). +- A predefined header (`HSM:SIGNER:HB:5.3:`). - A 32 byte value corresponding to the currently known best block hash. - A value corresponding to the first 8 bytes of the last successful authorized signed operation's transaction hash. @@ -57,7 +57,7 @@ transactions. To generate the heartbeat, the UI uses the configured endorsement scheme to sign a message generated by the concatenation of: -- A predefined header (`HSM:UI:HB:5.2:`). +- A predefined header (`HSM:UI:HB:5.3:`). - A 32 byte user-defined value. This value can vary and could be, for example, used as a timestamp reference for the end user. - A 32 byte value corresponding to the currently authorized Signer hash. diff --git a/firmware/src/ledger/ui/src/attestation.h b/firmware/src/ledger/ui/src/attestation.h index bb9230e3..51cdd2f0 100644 --- a/firmware/src/ledger/ui/src/attestation.h +++ b/firmware/src/ledger/ui/src/attestation.h @@ -48,7 +48,7 @@ typedef enum { } err_code_att_t; // Attestation message prefix -#define ATT_MSG_PREFIX "HSM:UI:5.2" +#define ATT_MSG_PREFIX "HSM:UI:5.3" #define ATT_MSG_PREFIX_LENGTH (sizeof(ATT_MSG_PREFIX) - sizeof("")) // User defined value size diff --git a/firmware/src/ledger/ui/src/defs.h b/firmware/src/ledger/ui/src/defs.h index afb7635b..8583a641 100644 --- a/firmware/src/ledger/ui/src/defs.h +++ b/firmware/src/ledger/ui/src/defs.h @@ -30,7 +30,7 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 -#define VERSION_MINOR 0x02 +#define VERSION_MINOR 0x03 #define VERSION_PATCH 0x00 #endif // __DEFS_H diff --git a/firmware/src/ledger/ui/src/ui_heartbeat.h b/firmware/src/ledger/ui/src/ui_heartbeat.h index e42db887..8d840c2e 100644 --- a/firmware/src/ledger/ui/src/ui_heartbeat.h +++ b/firmware/src/ledger/ui/src/ui_heartbeat.h @@ -46,7 +46,7 @@ typedef enum { } err_code_ui_heartbeat_t; // Heartbeat message prefix -#define UI_HEARTBEAT_MSG_PREFIX "HSM:UI:HB:5.2:" +#define UI_HEARTBEAT_MSG_PREFIX "HSM:UI:HB:5.3:" #define UI_HEARTBEAT_MSG_PREFIX_LENGTH \ (sizeof(UI_HEARTBEAT_MSG_PREFIX) - sizeof("")) diff --git a/firmware/src/ledger/ui/test/attestation/test_attestation.c b/firmware/src/ledger/ui/test/attestation/test_attestation.c index 31333927..eaba76fe 100644 --- a/firmware/src/ledger/ui/test/attestation/test_attestation.c +++ b/firmware/src/ledger/ui/test/attestation/test_attestation.c @@ -160,7 +160,7 @@ void test_get_attestation_ud_value() { assert(3 == get_attestation(rx, &G_att_ctx)); // PREFIX + UD_VALUE + Compressed pubkey + Signer hash + Iteration ASSERT_MEMCMP( - "HSM:UI:5.2" + "HSM:UI:5.3" "\x46\x8d\xa8\x7f\x6a\x85\xe6\x40\x93\x27\xe1\x17\xe8\xc7\xd2\x11\x0c" "\x73\x60\x22\x26\xbb\xb5\xed\xf2\x7d\x98\xc8\xa3\x1b\xcc\xf0" "\x02\xe6\xd7\x1d\x5c\x2b\x06\x36\x03\x53\xfb\xd8\x22\x7a\xb3\xab\xfc" @@ -208,7 +208,7 @@ void test_get_attestation_get_msg() { *N_onboarded_ui = 1; memcpy( G_att_ctx.msg, - "HSM:UI:5.2" + "HSM:UI:5.3" "\x46\x8d\xa8\x7f\x6a\x85\xe6\x40\x93\x27\xe1\x17\xe8\xc7\xd2\x11\x0c" "\x73\x60\x22\x26\xbb\xb5\xed\xf2\x7d\x98\xc8\xa3\x1b\xcc\xf0" "\x03\xe6\xd7\x1d\x5c\x2b\x06\x36\x03\x53\xfb\xd8\x22\x7a\xb3\xab\xfc" @@ -225,7 +225,7 @@ void test_get_attestation_get_msg() { assert((APDU_TOTAL_DATA_SIZE_OUT + 3) == get_attestation(rx, &G_att_ctx)); ASSERT_APDU( "\x80\x50\x02\x01" - "HSM:UI:5.2" + "HSM:UI:5.3" "\x46\x8d\xa8\x7f\x6a\x85\xe6\x40\x93\x27\xe1\x17\xe8\xc7\xd2\x11\x0c" "\x73\x60\x22\x26\xbb\xb5\xed\xf2\x7d\x98\xc8\xa3\x1b\xcc\xf0" "\x03\xe6\xd7\x1d\x5c\x2b\x06\x36\x03\x53\xfb\xd8\x22\x7a\xb3\xab\xfc" @@ -249,7 +249,7 @@ void test_get_attestation_get_msg_wrong_state() { *N_onboarded_ui = 1; memcpy( &G_att_ctx.msg, - "HSM:UI:5.2" + "HSM:UI:5.3" "\x46\x8d\xa8\x7f\x6a\x85\xe6\x40\x93\x27\xe1\x17\xe8\xc7\xd2\x11\x0c" "\x73\x60\x22\x26\xbb\xb5\xed\xf2\x7d\x98\xc8\xa3\x1b\xcc\xf0" "\x03\xe6\xd7\x1d\x5c\x2b\x06\x36\x03\x53\xfb\xd8\x22\x7a\xb3\xab\xfc" diff --git a/firmware/src/ledger/ui/test/onboard/test_onboard.c b/firmware/src/ledger/ui/test/onboard/test_onboard.c index 1e9ccebc..5269c6aa 100644 --- a/firmware/src/ledger/ui/test/onboard/test_onboard.c +++ b/firmware/src/ledger/ui/test/onboard/test_onboard.c @@ -313,11 +313,11 @@ void test_is_onboarded() { G_device_onboarded = true; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x01\x05\x02\x00"); + ASSERT_APDU("\x80\x01\x05\x03\x00"); G_device_onboarded = false; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x00\x05\x02\x00"); + ASSERT_APDU("\x80\x00\x05\x03\x00"); } int main() { diff --git a/firmware/src/ledger/ui/test/ui_heartbeat/test_ui_heartbeat.c b/firmware/src/ledger/ui/test/ui_heartbeat/test_ui_heartbeat.c index 36fe5518..5bb9924b 100644 --- a/firmware/src/ledger/ui/test/ui_heartbeat/test_ui_heartbeat.c +++ b/firmware/src/ledger/ui/test/ui_heartbeat/test_ui_heartbeat.c @@ -230,7 +230,7 @@ void test_op_ud_value() { assert_ok("\x80\x60\x01"); - const char expected_msg[] = "HSM:UI:HB:5.2:" // Prefix + const char expected_msg[] = "HSM:UI:HB:5.3:" // Prefix "\x11" // UD "\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22" // . "\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22" // . diff --git a/firmware/src/powhsm/src/attestation.h b/firmware/src/powhsm/src/attestation.h index 23d1171b..5b61be27 100644 --- a/firmware/src/powhsm/src/attestation.h +++ b/firmware/src/powhsm/src/attestation.h @@ -33,7 +33,7 @@ // ----------------------------------------------------------------------- // Attestation message prefix -#define ATT_MSG_PREFIX "HSM:SIGNER:5.2" +#define ATT_MSG_PREFIX "HSM:SIGNER:5.3" #define ATT_MSG_PREFIX_LENGTH (sizeof(ATT_MSG_PREFIX) - sizeof("")) // ----------------------------------------------------------------------- diff --git a/firmware/src/powhsm/src/defs.h b/firmware/src/powhsm/src/defs.h index 7413c6ee..d2eac45c 100644 --- a/firmware/src/powhsm/src/defs.h +++ b/firmware/src/powhsm/src/defs.h @@ -29,7 +29,7 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 -#define VERSION_MINOR 0x02 +#define VERSION_MINOR 0x03 #define VERSION_PATCH 0x00 #endif // __DEFS_H diff --git a/firmware/src/powhsm/src/heartbeat.h b/firmware/src/powhsm/src/heartbeat.h index 1026f2b1..2bcf905c 100644 --- a/firmware/src/powhsm/src/heartbeat.h +++ b/firmware/src/powhsm/src/heartbeat.h @@ -45,7 +45,7 @@ typedef enum { } err_code_heartbeat_t; // Heartbeat message prefix -#define HEARTBEAT_MSG_PREFIX "HSM:SIGNER:HB:5.2:" +#define HEARTBEAT_MSG_PREFIX "HSM:SIGNER:HB:5.3:" #define HEARTBEAT_MSG_PREFIX_LENGTH (sizeof(HEARTBEAT_MSG_PREFIX) - sizeof("")) // User-defined value size diff --git a/firmware/test/cases/heartbeat.py b/firmware/test/cases/heartbeat.py index 09bad8d2..d6ba7d77 100644 --- a/firmware/test/cases/heartbeat.py +++ b/firmware/test/cases/heartbeat.py @@ -27,7 +27,7 @@ class Heartbeat(TestCase): - EXPECTED_HEADER = "HSM:SIGNER:HB:5.2:" + EXPECTED_HEADER = "HSM:SIGNER:HB:5.3:" EHL = len(EXPECTED_HEADER) @classmethod diff --git a/middleware/ledger/protocol.py b/middleware/ledger/protocol.py index 4e6af5cc..86fbb91f 100644 --- a/middleware/ledger/protocol.py +++ b/middleware/ledger/protocol.py @@ -38,8 +38,8 @@ class HSM2ProtocolLedger(HSM2Protocol): # Current manager supported versions for HSM UI and HSM SIGNER (<=) - UI_VERSION = HSM2FirmwareVersion(5, 2, 0) - APP_VERSION = HSM2FirmwareVersion(5, 2, 0) + UI_VERSION = HSM2FirmwareVersion(5, 3, 0) + APP_VERSION = HSM2FirmwareVersion(5, 3, 0) # Amount of time to wait to make sure the app is opened OPEN_APP_WAIT = 1 # second diff --git a/middleware/tests/admin/test_verify_attestation.py b/middleware/tests/admin/test_verify_attestation.py index 3b1968ab..665e96db 100644 --- a/middleware/tests/admin/test_verify_attestation.py +++ b/middleware/tests/admin/test_verify_attestation.py @@ -37,8 +37,8 @@ logging.disable(logging.CRITICAL) EXPECTED_UI_DERIVATION_PATH = "m/44'/0'/0'/0/0" -SIGNER_HEADER = b"HSM:SIGNER:5.2" -UI_HEADER = b"HSM:UI:5.2" +SIGNER_HEADER = b"HSM:SIGNER:5.3" +UI_HEADER = b"HSM:UI:5.3" @patch("sys.stdout.write") @@ -114,7 +114,7 @@ def test_verify_attestation(self, f"Authorized signer hash: {'cc'*32}", "Authorized signer iteration: 291", f"Installed UI hash: {'ee'*32}", - "Installed UI version: 5.2", + "Installed UI version: 5.3", ], fill="-", ) @@ -125,7 +125,7 @@ def test_verify_attestation(self, "", f"Hash: {self.pubkeys_hash.hex()}", f"Installed Signer hash: {'ff'*32}", - "Installed Signer version: 5.2", + "Installed Signer version: 5.3", ], fill="-", ) diff --git a/middleware/tests/ledger/test_protocol.py b/middleware/tests/ledger/test_protocol.py index 13de3f4f..968b0d8f 100644 --- a/middleware/tests/ledger/test_protocol.py +++ b/middleware/tests/ledger/test_protocol.py @@ -49,7 +49,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 2, 0)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 0)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM2ProtocolLedger(self.pin, self.dongle) diff --git a/middleware/tests/ledger/test_protocol_v1.py b/middleware/tests/ledger/test_protocol_v1.py index 9a98ee65..63d6d042 100644 --- a/middleware/tests/ledger/test_protocol_v1.py +++ b/middleware/tests/ledger/test_protocol_v1.py @@ -47,7 +47,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 2, 0)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 0)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM1ProtocolLedger(self.pin, self.dongle) From f7ae4950648ea24a1ff354d3c6a407822d552f4a Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 13 Nov 2024 05:33:06 +1300 Subject: [PATCH 16/50] Fix middleware docker image build (#216) --- docker/mware/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/mware/Dockerfile b/docker/mware/Dockerfile index 6b90c912..b9bad088 100644 --- a/docker/mware/Dockerfile +++ b/docker/mware/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update && \ # Python package prerequisites RUN apt-get install -y \ libsecp256k1-dev=0.2.0-2 \ - libudev-dev=252.30-1~deb12u2 \ + libudev-dev=252.31-1~deb12u1 \ libusb-1.0-0-dev=2:1.0.26-1 \ libffi-dev=3.4.4-1 \ libjpeg-dev=1:2.1.5-2 From a3d2716d3b3fcb543e9ce9112d5aeaffc86dab16 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Fri, 15 Nov 2024 01:35:10 +1300 Subject: [PATCH 17/50] Version 5.3.1 ALPHA release (#213) (#218) - Bumped version to 5.3.1 - Updated version references in firmware, middleware and unit tests - Updated CHANGELOG --- CHANGELOG.md | 6 ++++++ firmware/src/ledger/ui/src/defs.h | 2 +- firmware/src/ledger/ui/test/onboard/test_onboard.c | 4 ++-- firmware/src/powhsm/src/defs.h | 2 +- middleware/ledger/protocol.py | 4 ++-- middleware/tests/ledger/test_protocol.py | 2 +- middleware/tests/ledger/test_protocol_v1.py | 2 +- 7 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcdc3c73..32e2bdcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [5.3.1 ALPHA] - 14/11/2024 + +### Fixes + +- Fixed failing middleware docker image build + ## [5.3.0 ALPHA] - 23/10/2024 ### Features/enhancements diff --git a/firmware/src/ledger/ui/src/defs.h b/firmware/src/ledger/ui/src/defs.h index 8583a641..b4577ec9 100644 --- a/firmware/src/ledger/ui/src/defs.h +++ b/firmware/src/ledger/ui/src/defs.h @@ -31,6 +31,6 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 #define VERSION_MINOR 0x03 -#define VERSION_PATCH 0x00 +#define VERSION_PATCH 0x01 #endif // __DEFS_H diff --git a/firmware/src/ledger/ui/test/onboard/test_onboard.c b/firmware/src/ledger/ui/test/onboard/test_onboard.c index 5269c6aa..933e13b2 100644 --- a/firmware/src/ledger/ui/test/onboard/test_onboard.c +++ b/firmware/src/ledger/ui/test/onboard/test_onboard.c @@ -313,11 +313,11 @@ void test_is_onboarded() { G_device_onboarded = true; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x01\x05\x03\x00"); + ASSERT_APDU("\x80\x01\x05\x03\x01"); G_device_onboarded = false; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x00\x05\x03\x00"); + ASSERT_APDU("\x80\x00\x05\x03\x01"); } int main() { diff --git a/firmware/src/powhsm/src/defs.h b/firmware/src/powhsm/src/defs.h index d2eac45c..ac150a22 100644 --- a/firmware/src/powhsm/src/defs.h +++ b/firmware/src/powhsm/src/defs.h @@ -30,6 +30,6 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 #define VERSION_MINOR 0x03 -#define VERSION_PATCH 0x00 +#define VERSION_PATCH 0x01 #endif // __DEFS_H diff --git a/middleware/ledger/protocol.py b/middleware/ledger/protocol.py index 86fbb91f..3b683345 100644 --- a/middleware/ledger/protocol.py +++ b/middleware/ledger/protocol.py @@ -38,8 +38,8 @@ class HSM2ProtocolLedger(HSM2Protocol): # Current manager supported versions for HSM UI and HSM SIGNER (<=) - UI_VERSION = HSM2FirmwareVersion(5, 3, 0) - APP_VERSION = HSM2FirmwareVersion(5, 3, 0) + UI_VERSION = HSM2FirmwareVersion(5, 3, 1) + APP_VERSION = HSM2FirmwareVersion(5, 3, 1) # Amount of time to wait to make sure the app is opened OPEN_APP_WAIT = 1 # second diff --git a/middleware/tests/ledger/test_protocol.py b/middleware/tests/ledger/test_protocol.py index 968b0d8f..25a076e2 100644 --- a/middleware/tests/ledger/test_protocol.py +++ b/middleware/tests/ledger/test_protocol.py @@ -49,7 +49,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 0)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 1)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM2ProtocolLedger(self.pin, self.dongle) diff --git a/middleware/tests/ledger/test_protocol_v1.py b/middleware/tests/ledger/test_protocol_v1.py index 63d6d042..91978469 100644 --- a/middleware/tests/ledger/test_protocol_v1.py +++ b/middleware/tests/ledger/test_protocol_v1.py @@ -47,7 +47,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 0)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 1)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM1ProtocolLedger(self.pin, self.dongle) From aa6489abaf431a89516205da90b9000acafb119a Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Thu, 14 Nov 2024 09:48:04 -0300 Subject: [PATCH 18/50] SGX reproducible builds (#219) - Updates SGX Docker base image to `2024.10.2391` - Removes unnecessary dependencies from SGX Dockerfile - Freezes open-enclave version to `0.19.4` - Ensures deterministic build order --- docker/sgx/Dockerfile | 16 ++-------------- firmware/src/sgx/Makefile | 10 +++++----- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/docker/sgx/Dockerfile b/docker/sgx/Dockerfile index 881f8bd7..57785c5f 100644 --- a/docker/sgx/Dockerfile +++ b/docker/sgx/Dockerfile @@ -1,23 +1,11 @@ -FROM openenclavedockerregistry.azurecr.io/oetools-20.04:2023.11.21100 +FROM openenclavedockerregistry.azurecr.io/oetools-20.04:2024.10.2391 # Install dependencies RUN apt-get update && \ apt-get install -y apt-utils vim && \ apt-get install -y tar && \ - apt-get install -y xz-utils && \ apt-get install -y curl && \ - apt-get install -y git && \ - apt-get install -y clang-11 && \ - apt-get install -y libssl-dev && \ - apt-get install -y gdb && \ - apt-get install -y libsgx-enclave-common && \ - apt-get install -y libsgx-quote-ex && \ - apt-get install -y libprotobuf17 && \ - apt-get install -y libsgx-dcap-ql && \ - apt-get install -y libsgx-dcap-ql-dev && \ - apt-get install -y az-dcap-client && \ - apt-get install -y open-enclave && \ - apt-get install -y gcc && \ + apt-get install -y open-enclave=0.19.4 && \ apt-get install -y make # Create directory to host symlinks to Open Enclave static libraries diff --git a/firmware/src/sgx/Makefile b/firmware/src/sgx/Makefile index ba906f93..5e7db387 100644 --- a/firmware/src/sgx/Makefile +++ b/firmware/src/sgx/Makefile @@ -38,13 +38,13 @@ POWHSM_SRC_DIR = ../powhsm/src COMMON_SRC_DIR = ../common/src ## Untrusted source files -UNTRUSTED_SRC = $(wildcard $(SGX_UNTRUSTED_SRC_DIR)/*.c) +UNTRUSTED_SRC = $(sort $(wildcard $(SGX_UNTRUSTED_SRC_DIR)/*.c)) ## Trusted source files -TRUSTED_SRC = $(wildcard $(SGX_TRUSTED_SRC_DIR)/*.c) -TRUSTED_SRC += $(wildcard $(HAL_TRUSTED_SRC_DIR)/*.c) -TRUSTED_SRC += $(wildcard $(POWHSM_SRC_DIR)/*.c) -TRUSTED_SRC += $(wildcard $(COMMON_SRC_DIR)/*.c) +TRUSTED_SRC = $(sort $(wildcard $(SGX_TRUSTED_SRC_DIR)/*.c)) +TRUSTED_SRC += $(sort $(wildcard $(HAL_TRUSTED_SRC_DIR)/*.c)) +TRUSTED_SRC += $(sort $(wildcard $(POWHSM_SRC_DIR)/*.c)) +TRUSTED_SRC += $(sort $(wildcard $(COMMON_SRC_DIR)/*.c)) # Enclave definition files EDL_FILE = $(SGX_SRC_DIR)/$(ENCLAVE_NAME).edl From 2e8d75f1206218150c1ae03be4439eb7081ede0f Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:22:40 -0300 Subject: [PATCH 19/50] Added script to extract the digest and mrenclave from a signed enclave binary (#221) --- firmware/build/extract-mrenclave | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100755 firmware/build/extract-mrenclave diff --git a/firmware/build/extract-mrenclave b/firmware/build/extract-mrenclave new file mode 100755 index 00000000..68b18fde --- /dev/null +++ b/firmware/build/extract-mrenclave @@ -0,0 +1,67 @@ +#! /usr/bin/env bash + +function print_usage() { + echo "Usage: $0 " + echo " or $0 " + echo "" + echo "Options:" + echo " signed_enclave: path of a signed enclave binary file (MUST end with '.signed' extension)." + echo " unsigned_enclave: path of an unsigned enclave binary file." + echo " config_file: configuration file specifying the enclave properties." + echo " refer to the oesign sign --help for the list of properties." + echo " this option is only required for unsigned enclaves." + echo "" + echo "Description:" + echo " This script extracts the MRENCLAVE and the DIGEST values from the enclave" + echo " binary and prints them to stdout. The script can be used both for unsigned" + echo " and signed enclave binaries." + echo "" + echo " Signed binaries:" + echo " The MRENCLAVE and DIGEST are calculated from the signed enclave binary." + echo " Both values are printed in hexadecimal format to stdout." + echo "" + echo " Unsigned binaries:" + echo " The DIGEST is calculated from the unsigned enclave binary and the enclave" + echo " properties specified in the configuration file. The MRENCLAVE is set to zero." + echo " Both values are printed in hexadecimal format to stdout." +} + +if [[ $# -lt 1 ]]; then + print_usage + exit 1 +fi + +pushd $(dirname $0) > /dev/null +BUILD_ROOT=$(pwd) +popd > /dev/null + +HSM_ROOT=$(realpath $BUILD_ROOT/../../) + +DOCKER_IMAGE=hsm:sgx +source $BUILD_ROOT/../../docker/check-image + +ENCLAVE_BIN=$(realpath $1 --relative-to=$HSM_ROOT) +if [[ ! -f $ENCLAVE_BIN ]]; then + echo "Invalid enclave path: $ENCLAVE_BIN" + exit 1 +else + ENCLAVE_ARG="-e $ENCLAVE_BIN" +fi + +if [[ $ENCLAVE_BIN == *.signed ]]; then + CONFIG_ARG="" +elif [[ $# -ge 2 ]]; then + CONFIG_ARG="-c $(realpath $2 --relative-to=$HSM_ROOT)" +else + echo "Invalid usage" + print_usage + exit 1 +fi + +DIGEST_CMD="oesign digest $ENCLAVE_ARG $CONFIG_ARG -d /tmp/enclave_digest > /dev/null && hexdump -v -e '/1 \"%02x\"' /tmp/enclave_digest" +MRENCLAVE_CMD="oesign dump $ENCLAVE_ARG | grep mrenclave | cut -d '=' -f 2" +EXTRACT_CMD="\$SGX_ENVSETUP && echo digest: \$($DIGEST_CMD) && echo mrenclave: \$($MRENCLAVE_CMD)" + +DOCKER_USER="$(id -u):$(id -g)" + +docker run -t --rm --user $DOCKER_USER -w /hsm2 -v ${HSM_ROOT}:/hsm2 ${DOCKER_IMAGE} /bin/bash -c "$EXTRACT_CMD" From 738fb0fad9753da2483c1cb35382fa429f8a6abf Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Mon, 25 Nov 2024 09:36:28 -0300 Subject: [PATCH 20/50] Adds MRENCLAVE and digest information to SGX build scripts (#223) --- build-dist-sgx | 8 ++++++++ firmware/build/build-sgx | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/build-dist-sgx b/build-dist-sgx index 31052197..a450cbe6 100755 --- a/build-dist-sgx +++ b/build-dist-sgx @@ -52,6 +52,14 @@ $ROOT_DIR/firmware/build/build-sgx $CHECKPOINT $DIFFICULTY $NETWORK > /dev/null cp $ROOT_DIR/firmware/src/sgx/bin/hsmsgx $HSM_DIR/ cp $ROOT_DIR/firmware/src/sgx/bin/hsmsgx_enclave.signed $HSM_DIR/ +HOST_HASH=$(sha256sum $ROOT_DIR/firmware/src/sgx/bin/hsmsgx | cut -d ' ' -f 1) +ENCLAVE_HASH=$($ROOT_DIR/firmware/build/extract-mrenclave $ROOT_DIR/firmware/src/sgx/bin/hsmsgx_enclave.signed) +echo "$HSM_DIR/hsmsgx:" +echo $HOST_HASH +echo +echo "$HSM_DIR/hsmsgx_enclave.signed" +echo "$ENCLAVE_HASH" + echo echo -e "\e[32mBuild complete.\e[0m" diff --git a/firmware/build/build-sgx b/firmware/build/build-sgx index cbe70d31..f71c86b1 100755 --- a/firmware/build/build-sgx +++ b/firmware/build/build-sgx @@ -40,3 +40,20 @@ BUILD_CMD="\$SGX_ENVSETUP && make clean $BUILD_TARGET CHECKPOINT=$1 TARGET_DIFFI DOCKER_USER="$(id -u):$(id -g)" docker run -t --rm --user $DOCKER_USER -w /hsm2/firmware/src/sgx -v ${HSM_ROOT}:/hsm2 ${DOCKER_IMAGE} /bin/bash -c "$BUILD_CMD" + +if [[ $? -ne 0 ]]; then + echo "Build failed" + exit 1 +fi + +HOST_BIN=$HSM_ROOT/firmware/src/sgx/bin/hsmsgx +ENCLAVE_BIN=$HSM_ROOT/firmware/src/sgx/bin/hsmsgx_enclave.signed + +echo "*******************" +echo "Build successful." +echo "$(realpath $HOST_BIN --relative-to=$HSM_ROOT):" +sha256sum $HOST_BIN | cut -d ' ' -f 1 +echo "" +echo "$(realpath $ENCLAVE_BIN --relative-to=$HSM_ROOT):" +$BUILD_ROOT/extract-mrenclave $ENCLAVE_BIN +echo "*******************" From 1d0044fa2843195cd22125224361eb60a7f9c70d Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 26 Nov 2024 02:40:49 +1300 Subject: [PATCH 21/50] Enhancing existing attestation scheme with additional information (#222) - Implemented new attestation protocol in firmware - Moved attestation context definition to attestation header file - Updated admin tooling to gather and validate new attestation format, keeping support for legacy format - Factored out attestation gathering logic from HSM2Dongle - New semantics for code hash and public key gathering functions in existing endorsement module - Additional endorsement module functions to allow for envelope gathering - New platform module to provide platform id and timestamp - Added and updated unit tests - Updated attestation documentation - Added SGX endorsement library's envelope function stubs --- docs/attestation.md | 47 +++-- firmware/src/hal/include/hal/endorsement.h | 18 +- firmware/src/hal/include/hal/platform.h | 13 ++ firmware/src/hal/ledger/src/endorsement.c | 23 +++ firmware/src/hal/ledger/src/platform.c | 8 + .../src/hal/sgx/src/trusted/endorsement.c | 10 + firmware/src/hal/x86/src/endorsement.c | 8 + firmware/src/hal/x86/src/platform.c | 11 +- firmware/src/ledger/signer/src/main.c | 2 + firmware/src/powhsm/src/attestation.c | 168 ++++++++++++++--- firmware/src/powhsm/src/attestation.h | 46 ++++- firmware/src/powhsm/src/mem.h | 13 +- middleware/adm_ledger.py | 4 +- .../{attestation.py => ledger_attestation.py} | 13 +- ...tation.py => verify_ledger_attestation.py} | 85 ++++++--- middleware/ledger/hsm2dongle.py | 40 +--- middleware/ledger/hsm2dongle_cmds/__init__.py | 1 + middleware/ledger/hsm2dongle_cmds/command.py | 2 +- .../hsm2dongle_cmds/powhsm_attestation.py | 81 ++++++++ ...estation.py => test_ledger_attestation.py} | 41 ++-- ...n.py => test_verify_ledger_attestation.py} | 177 ++++++++++++------ .../test_powhsm_attestation.py | 121 ++++++++++++ 22 files changed, 730 insertions(+), 202 deletions(-) rename middleware/admin/{attestation.py => ledger_attestation.py} (90%) rename middleware/admin/{verify_attestation.py => verify_ledger_attestation.py} (75%) create mode 100644 middleware/ledger/hsm2dongle_cmds/powhsm_attestation.py rename middleware/tests/admin/{test_attestation.py => test_ledger_attestation.py} (89%) rename middleware/tests/admin/{test_verify_attestation.py => test_verify_ledger_attestation.py} (68%) create mode 100644 middleware/tests/ledger/hsm2dongle_cmds/test_powhsm_attestation.py diff --git a/docs/attestation.md b/docs/attestation.md index bba1a8bc..530aa713 100644 --- a/docs/attestation.md +++ b/docs/attestation.md @@ -66,7 +66,17 @@ As a consequence of the aforementioned features, this message guarantees that th ### Signer attestation -To generate the attestation, the Signer uses the configured attestation scheme to sign a message containing a predefined header (`HSM:SIGNER:5.3`) and the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path. This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device. +To generate the attestation, the Signer uses the configured attestation scheme to sign a message generated by the concatenation of: + +- A predefined header (`POWHSM:5.4::`). +- A 3-byte platform identifier, which for Ledger is exactly the ASCII characters `led`. +- A 32 byte user-defined value. By default, the attestation generation client supplies the latest RSK block hash as this value, so it can then be used as a minimum timestamp reference for the attestation generation. +- A 32 byte value that is generated by computing the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path. +- A 32 byte value denoting the device's current known best block hash for the Rootstock network. +- An 8 byte value denoting the leading bytes of the latest authorised signed Bitcoin transaction hash. +- An 8 byte value denoting a big-endian unix timestamp. For Ledger, this is always zero. + +This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device. The additional fields aid in auditing a device's state at the time the attestation is gathered (e.g., for firmware updates). ## Attestation file format @@ -101,7 +111,7 @@ The output of the attestation process is a JSON file with a proprietary structur }, { "name": "signer", - "message": "48534d3a5349474e45523a332e30a2316e4c4e07e77ae65c74574452f330ed62752ba4c66f9c2101836d7b36cef2", + "message": "504f5748534d3a352e343a3a6c656413c3581aa97c8169d3994e9369c11ebd63bcf123d0671634f21b568983d3291687fd9b1f4aa83e348906e2efd6cbed98e39d17aea4c03d73f30e99d602d67633bdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b659a04529d6811dd0000000000000000", "signature": "30440220154bb544fe00df5635c03618ee9614d50933fe7c9226d8efce55f1a40832681402206289dab7b8d6700e048b602ac03516e0e6a1609796fc27c440848d072af71c2a", "signed_by": "attestation", "tweak": "e1baa18564fc0c2c70ac4019609c6db643adbf12711c8b319f838e6a74b0da2c" @@ -158,23 +168,30 @@ to then obtain the following sample output: Using 0490f5c9d15a0134bb019d2afd0bf297149738459706e7ac5be4abc350a1f818057224fce12ec9a65de18ec34d6e8c24db927835ea1692b14c32e9836a75dad609 as root authority -------------------------------------------------------------------------------------------------------- UI verified with: -UD value: c4207b260c5b6964190568e528ec0b212a70e512ed6bdcef5e192362852a3839 -Derived public key (m/44'/0'/0'/0/0): 03198eb60255fefc3478d0a78c11f5124c938f66fdaa62f9e9c543c6ced031ef37 -Authorized signer hash: e1baa18564fc0c2c70ac4019609c6db643adbf12711c8b319f838e6a74b0da2c +UD value: 13c3581aa97c8169d3994e9369c11ebd63bcf123d0671634f21b568983d32916 +Derived public key (m/44'/0'/0'/0/0): 0254464d36eaa08a2c31a80eb902e7400563f403c85ef51dd73aaadb57967b61e8 +Authorized signer hash: cc3c55563a4fa50d973faf704d7ef4f272b99ed7e0e0848457dd60be7d3df4b5 Authorized signer iteration: 1 -Installed UI hash: 17f2129265b071e3d8658a549cd60720c86e34c7a6b81d517ffef123c8425f19 +Installed UI hash: 7674c4870ff06ace61d468df8af521be6cc40e86ca6a6b732453801e6b7adf9d +Installed UI version: 5.4 -------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------- Signer verified with public keys: -m/44'/0'/0'/0/0: 03198eb60255fefc3478d0a78c11f5124c938f66fdaa62f9e9c543c6ced031ef37 -m/44'/1'/0'/0/0: 0309fe4c9a803658c1d1c0c19f2d841e34306d172f0bb092431ace7bbda334e902 -m/44'/1'/1'/0/0: 023ac8c77507fdcb7581ce3ee366a7b09791b54377af67f75e1a159737f4f77fe7 -m/44'/1'/2'/0/0: 02583d0dec06114cc0a19883398652d8f87af0175f7d7c2c97417622341e06560c -m/44'/137'/0'/0/0: 03458e7f8f7885f0b0648a8e2e899fe838a7f93da0028634689438e460d3ba614f -m/44'/137'/1'/0/0: 03e27a65c9e6ff0d3fc4085aa84f8d7ec467edf6ae6b30ed40d96d4344b516f4c6 - -Hash: a2316e4c4e07e77ae65c74574452f330ed62752ba4c66f9c2101836d7b36cef2 -Installed Signer hash: e1baa18564fc0c2c70ac4019609c6db643adbf12711c8b319f838e6a74b0da2c +m/44'/0'/0'/0/0: 0254464d36eaa08a2c31a80eb902e7400563f403c85ef51dd73aaadb57967b61e8 +m/44'/1'/0'/0/0: 02a7171ba5fcdf9ae8a32b733cbe748b6007b4633939ba1c8baca074e9358a281a +m/44'/1'/1'/0/0: 022e777db5856568da55947c1a60df4ec28b8fb27ea182de54575b3aadc4559932 +m/44'/1'/2'/0/0: 0307455520c1b365436741c98ddc987c8ed7adddf67b8b69e5763f930c0131727e +m/44'/137'/0'/0/0: 02ecdf31ca81e7c5a2949dad38536676eee2647ec2e41c0771cd4e918b5c2fc4f8 +m/44'/137'/1'/0/0: 0345ac500d260c1f6794b21fad8acce66548fee7a463befd5a0ec5bb73b9ae4df1 +Hash: 72237ee55064aebd5ab13d179c61bfb41c5b1d2ed7e018f8de46a7262c8cf1ec + +Installed Signer hash: cc3c55563a4fa50d973faf704d7ef4f272b99ed7e0e0848457dd60be7d3df4b5 +Installed Signer version: 5.4 +Platform: led +UD value: 13c3581aa97c8169d3994e9369c11ebd63bcf123d0671634f21b568983d32916 +Best block: bdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b +Last transaction signed: 659a04529d6811dd +Timestamp: 0000000000000000 --------------------------------------------------------------------------------------- ``` diff --git a/firmware/src/hal/include/hal/endorsement.h b/firmware/src/hal/include/hal/endorsement.h index 8b43ccde..1e508e55 100644 --- a/firmware/src/hal/include/hal/endorsement.h +++ b/firmware/src/hal/include/hal/endorsement.h @@ -45,6 +45,22 @@ bool endorsement_sign(uint8_t* msg, uint8_t* signature_out, uint8_t* signature_out_length); +/** + * @brief Gets a pointer to the last signed envelope + * + * @return a pointer to a buffer containing the envelope, + * or NULL if no envelope is available. + */ +uint8_t* endorsement_get_envelope(); + +/** + * @brief Gets the length of the last signed envelope + * + * @return the byte length of the last signed envelope, + * or ZERO if no envelope is available. + */ +size_t endorsement_get_envelope_length(); + /** * @brief Grabs the hash of the currently running code * @@ -99,7 +115,7 @@ extern attestation_id_t attestation_id; */ bool endorsement_init(char* att_file_path); -#elif defined(HSM_PLATFORM_SGX) +#elif defined(HSM_PLATFORM_SGX) || defined(HSM_PLATFORM_LEDGER) /** * @brief Initializes the endorsement module diff --git a/firmware/src/hal/include/hal/platform.h b/firmware/src/hal/include/hal/platform.h index 3b0af3ae..4bca6cf6 100644 --- a/firmware/src/hal/include/hal/platform.h +++ b/firmware/src/hal/include/hal/platform.h @@ -28,6 +28,9 @@ #include #include +// Size in bytes of a platform id +#define PLATFORM_ID_LENGTH 3 + /** * @brief Perform the platform-specific version of memmove * @@ -42,6 +45,16 @@ void platform_memmove(void *dst, const void *src, unsigned int length); */ void platform_request_exit(); +/** + * @brief Get the current platform id + */ +const char *platform_get_id(); + +/** + * @brief Get the current timestamp + */ +uint64_t platform_get_timestamp(); + /** * X86 specific headers */ diff --git a/firmware/src/hal/ledger/src/endorsement.c b/firmware/src/hal/ledger/src/endorsement.c index dd6708e3..1b2e60aa 100644 --- a/firmware/src/hal/ledger/src/endorsement.c +++ b/firmware/src/hal/ledger/src/endorsement.c @@ -29,6 +29,21 @@ // Index of the ledger endorsement scheme #define ENDORSEMENT_SCHEME_INDEX 2 +static bool sign_performed; + +bool endorsement_init() { + sign_performed = false; + return true; +} + +uint8_t* endorsement_get_envelope() { + return NULL; +} + +size_t endorsement_get_envelope_length() { + return 0; +} + bool endorsement_sign(uint8_t* msg, size_t msg_size, uint8_t* signature_out, @@ -41,11 +56,15 @@ bool endorsement_sign(uint8_t* msg, *signature_out_length = os_endorsement_key2_derive_sign_data(msg, msg_size, signature_out); + sign_performed = true; return true; } bool endorsement_get_code_hash(uint8_t* code_hash_out, uint8_t* code_hash_out_length) { + if (!sign_performed) { + return false; + } if (*code_hash_out_length < HASH_LENGTH) { return false; @@ -57,6 +76,10 @@ bool endorsement_get_code_hash(uint8_t* code_hash_out, bool endorsement_get_public_key(uint8_t* public_key_out, uint8_t* public_key_out_length) { + if (!sign_performed) { + return false; + } + if (*public_key_out_length < PUBKEY_UNCMP_LENGTH) { return false; } diff --git a/firmware/src/hal/ledger/src/platform.c b/firmware/src/hal/ledger/src/platform.c index ecea2a79..fa6dea58 100644 --- a/firmware/src/hal/ledger/src/platform.c +++ b/firmware/src/hal/ledger/src/platform.c @@ -38,4 +38,12 @@ void platform_request_exit() { } } END_TRY_L(exit); +} + +const char *platform_get_id() { + return "led"; +} + +uint64_t platform_get_timestamp() { + return (uint64_t)0; } \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/endorsement.c b/firmware/src/hal/sgx/src/trusted/endorsement.c index 4d995e2b..2fd21e99 100644 --- a/firmware/src/hal/sgx/src/trusted/endorsement.c +++ b/firmware/src/hal/sgx/src/trusted/endorsement.c @@ -113,6 +113,16 @@ bool endorsement_init() { return true; } +// TODO: Implement +uint8_t* endorsement_get_envelope() { + return NULL; +} + +// TODO: Implement +size_t endorsement_get_envelope_length() { + return 0; +} + bool endorsement_sign(uint8_t* msg, size_t msg_size, uint8_t* signature_out, diff --git a/firmware/src/hal/x86/src/endorsement.c b/firmware/src/hal/x86/src/endorsement.c index f127660f..42283b24 100644 --- a/firmware/src/hal/x86/src/endorsement.c +++ b/firmware/src/hal/x86/src/endorsement.c @@ -171,6 +171,14 @@ bool endorsement_init(char* att_file_path) { return true; } +uint8_t* endorsement_get_envelope() { + return NULL; +} + +size_t endorsement_get_envelope_length() { + return 0; +} + bool endorsement_sign(uint8_t* msg, size_t msg_size, uint8_t* signature_out, diff --git a/firmware/src/hal/x86/src/platform.c b/firmware/src/hal/x86/src/platform.c index 5cf96a53..e6b6a5e8 100644 --- a/firmware/src/hal/x86/src/platform.c +++ b/firmware/src/hal/x86/src/platform.c @@ -26,6 +26,7 @@ #include "hal/log.h" #include +#include void platform_memmove(void *dst, const void *src, unsigned int length) { memmove(dst, src, length); @@ -34,4 +35,12 @@ void platform_memmove(void *dst, const void *src, unsigned int length) { void platform_request_exit() { // Currently unsupported, just log the call LOG("platform_request_exit called\n"); -} \ No newline at end of file +} + +const char *platform_get_id() { + return "x86"; +} + +uint64_t platform_get_timestamp() { + return (uint64_t)time(NULL); +} diff --git a/firmware/src/ledger/signer/src/main.c b/firmware/src/ledger/signer/src/main.c index 4f4e15ab..b2c6ef09 100644 --- a/firmware/src/ledger/signer/src/main.c +++ b/firmware/src/ledger/signer/src/main.c @@ -47,6 +47,7 @@ // HAL includes #include "hal/communication.h" +#include "hal/endorsement.h" // The interval between two subsequent ticker events in milliseconds. This is // assumed to be 100ms according to the nanos-secure-sdk documentation. @@ -192,6 +193,7 @@ __attribute__((section(".boot"))) int main(int argc, char **argv) { // HAL modules initialization communication_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + endorsement_init(); // HSM context initialization hsm_init(); diff --git a/firmware/src/powhsm/src/attestation.c b/firmware/src/powhsm/src/attestation.c index 06399384..712fbcc8 100644 --- a/firmware/src/powhsm/src/attestation.c +++ b/firmware/src/powhsm/src/attestation.c @@ -33,6 +33,7 @@ #include "apdu.h" #include "defs.h" #include "pathAuth.h" +#include "bc_state.h" #include "bc_hash.h" #include "mem.h" #include "memutil.h" @@ -40,9 +41,27 @@ // Attestation message prefix const char att_msg_prefix[ATT_MSG_PREFIX_LENGTH] = ATT_MSG_PREFIX; -// ----------------------------------------------------------------------- -// Protocol implementation -// ----------------------------------------------------------------------- +// Utility macros for message gathering paging +// Maximum page size is APDU data part size minus one +// byte (first byte of the response), which is used to indicate +// whether there is a next page or not. +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define PAGESIZE (APDU_TOTAL_DATA_SIZE_OUT - 1) +#define PAGECOUNT(itemcount) (((itemcount) + PAGESIZE - 1) / PAGESIZE) +#define CURPAGESIZE(itemcount, page) (MIN(PAGESIZE, (itemcount) - ((page) * PAGESIZE))) + +static void reset_attestation(att_t* att_ctx) { + explicit_bzero(att_ctx, sizeof(att_t)); + att_ctx->state = STATE_ATTESTATION_WAIT_SIGN; +} + +static void check_state(att_t* att_ctx, + state_attestation_t expected) { + if (att_ctx->state != expected) { + reset_attestation(att_ctx); + THROW(ERR_ATT_PROT_INVALID); + } +} static void hash_public_key(const char* path, size_t path_size, @@ -83,25 +102,61 @@ static void hash_public_key(const char* path, THROW(ERR_ATT_INTERNAL); } +static void write_uint64_be(uint8_t *out, uint64_t in) { + out[0] = (uint8_t)(in >> 56); + out[1] = (uint8_t)(in >> 48); + out[2] = (uint8_t)(in >> 40); + out[3] = (uint8_t)(in >> 32); + out[4] = (uint8_t)(in >> 24); + out[5] = (uint8_t)(in >> 16); + out[6] = (uint8_t)(in >> 8); + out[7] = (uint8_t)in; +} + /* * Generate the attestation message. * * @arg[in] att_ctx attestation context - * @ret generated message size + * @arg[in] ud_value pointer to the user-defined value */ -static unsigned int generate_message_to_sign(att_t* att_ctx) { +static void generate_message_to_sign(att_t* att_ctx, unsigned char* ud_value) { + // Initialize message explicit_bzero(att_ctx->msg, sizeof(att_ctx->msg)); + att_ctx->msg_length = 0; // Copy the message prefix SAFE_MEMMOVE(att_ctx->msg, sizeof(att_ctx->msg), - MEMMOVE_ZERO_OFFSET, + att_ctx->msg_length, (void*)PIC(ATT_MSG_PREFIX), ATT_MSG_PREFIX_LENGTH, MEMMOVE_ZERO_OFFSET, ATT_MSG_PREFIX_LENGTH, THROW(ERR_ATT_INTERNAL)); + att_ctx->msg_length += ATT_MSG_PREFIX_LENGTH; + + // Copy the platform id + SAFE_MEMMOVE(att_ctx->msg, + sizeof(att_ctx->msg), + att_ctx->msg_length, + (void*)PIC(platform_get_id()), + PLATFORM_ID_LENGTH, + MEMMOVE_ZERO_OFFSET, + PLATFORM_ID_LENGTH, + THROW(ERR_ATT_INTERNAL)); + att_ctx->msg_length += PLATFORM_ID_LENGTH; + + // Copy the UD value + SAFE_MEMMOVE(att_ctx->msg, + sizeof(att_ctx->msg), + att_ctx->msg_length, + (void*)PIC(ud_value), + ATT_UD_VALUE_SIZE, + MEMMOVE_ZERO_OFFSET, + ATT_UD_VALUE_SIZE, + THROW(ERR_ATT_INTERNAL)); + att_ctx->msg_length += ATT_UD_VALUE_SIZE; // Prepare the digest SHA256_INIT(&att_ctx->hash_ctx); @@ -111,11 +166,41 @@ static unsigned int generate_message_to_sign(att_t* att_ctx) { hash_public_key(get_ordered_path(i), SINGLE_PATH_SIZE_BYTES, att_ctx); } - SHA256_FINAL(&att_ctx->hash_ctx, &att_ctx->msg[ATT_MSG_PREFIX_LENGTH]); + // Finalise the public keys hash straight into the message + SHA256_FINAL(&att_ctx->hash_ctx, &att_ctx->msg[att_ctx->msg_length]); + att_ctx->msg_length += HASH_LENGTH; - return ATT_MSG_PREFIX_LENGTH + HASH_SIZE; + // Copy the current best block + SAFE_MEMMOVE(att_ctx->msg, + sizeof(att_ctx->msg), + att_ctx->msg_length, + N_bc_state.best_block, + sizeof(N_bc_state.best_block), + MEMMOVE_ZERO_OFFSET, + sizeof(N_bc_state.best_block), + THROW(ERR_ATT_INTERNAL)); + att_ctx->msg_length += sizeof(N_bc_state.best_block); + + // Copy the leading bytes of the last authorised signed tx + SAFE_MEMMOVE(att_ctx->msg, + sizeof(att_ctx->msg), + att_ctx->msg_length, + N_bc_state.last_auth_signed_btc_tx_hash, + sizeof(N_bc_state.last_auth_signed_btc_tx_hash), + MEMMOVE_ZERO_OFFSET, + ATT_LAST_SIGNED_TX_BYTES, + THROW(ERR_ATT_INTERNAL)); + att_ctx->msg_length += ATT_LAST_SIGNED_TX_BYTES; + + // Copy the current timestamp + write_uint64_be(&att_ctx->msg[att_ctx->msg_length], platform_get_timestamp()); + att_ctx->msg_length += sizeof(uint64_t); } +// ----------------------------------------------------------------------- +// Protocol implementation +// ----------------------------------------------------------------------- + /* * Implement the attestation protocol. * @@ -124,44 +209,75 @@ static unsigned int generate_message_to_sign(att_t* att_ctx) { * @ret number of transmited bytes to the host */ unsigned int get_attestation(volatile unsigned int rx, att_t* att_ctx) { - UNUSED(rx); - - unsigned int message_size; - uint8_t code_hash_size; + size_t buf_length; + uint8_t* buf; switch (APDU_OP()) { case OP_ATT_GET: + // Should receive a user-defined value + if (APDU_DATA_SIZE(rx) != ATT_UD_VALUE_SIZE) { + reset_attestation(att_ctx); + THROW(ERR_ATT_PROT_INVALID); + } + // Generate the message to attest - message_size = generate_message_to_sign(att_ctx); + generate_message_to_sign(att_ctx, APDU_DATA_PTR); // Attest message uint8_t endorsement_size = APDU_TOTAL_DATA_SIZE_OUT; if (!endorsement_sign( - att_ctx->msg, message_size, APDU_DATA_PTR, &endorsement_size)) { + att_ctx->msg, att_ctx->msg_length, APDU_DATA_PTR, &endorsement_size)) { THROW(ERR_ATT_INTERNAL); } + // Ready + att_ctx->state = STATE_ATTESTATION_READY; + return TX_FOR_DATA_SIZE(endorsement_size); + case OP_ATT_GET_ENVELOPE: case OP_ATT_GET_MESSAGE: - // Generate and output the message to sign - message_size = generate_message_to_sign(att_ctx); + check_state(att_ctx, STATE_ATTESTATION_READY); + + // Should receive a page index + if (APDU_DATA_SIZE(rx) != 1) + THROW(ERR_ATT_PROT_INVALID); + + // Get the envelope or message + buf = endorsement_get_envelope(); + buf_length = endorsement_get_envelope_length(); + if (!buf || APDU_OP() == OP_ATT_GET_MESSAGE) { + buf = att_ctx->msg; + buf_length = att_ctx->msg_length; + } + + // Check page index within range (page index is zero based) + if (APDU_DATA_PTR[0] >= PAGECOUNT(buf_length)) { + THROW(ERR_ATT_PROT_INVALID); + } + uint8_t page = APDU_DATA_PTR[0]; + // Copy the page into the APDU buffer (no need to check for limits since + // the chunk size is based directly on the APDU size) SAFE_MEMMOVE(APDU_DATA_PTR, - APDU_TOTAL_DATA_SIZE, - MEMMOVE_ZERO_OFFSET, - att_ctx->msg, - sizeof(att_ctx->msg), - MEMMOVE_ZERO_OFFSET, - message_size, + APDU_TOTAL_DATA_SIZE_OUT, + 1, + buf, + buf_length, + APDU_DATA_PTR[0] * PAGESIZE, + CURPAGESIZE(buf_length, page), THROW(ERR_ATT_INTERNAL)); + APDU_DATA_PTR[0] = page < (PAGECOUNT(buf_length) - 1); - return TX_FOR_DATA_SIZE(message_size); + return TX_FOR_DATA_SIZE( + CURPAGESIZE(buf_length, page) + 1); case OP_ATT_APP_HASH: - code_hash_size = APDU_TOTAL_DATA_SIZE_OUT; - if (!endorsement_get_code_hash(APDU_DATA_PTR, &code_hash_size)) { + check_state(att_ctx, STATE_ATTESTATION_READY); + + buf_length = APDU_TOTAL_DATA_SIZE_OUT; + if (!endorsement_get_code_hash(APDU_DATA_PTR, (uint8_t*)&buf_length)) { THROW(ERR_ATT_INTERNAL); } - return TX_FOR_DATA_SIZE(code_hash_size); + return TX_FOR_DATA_SIZE((uint8_t)buf_length); default: THROW(ERR_ATT_PROT_INVALID); break; diff --git a/firmware/src/powhsm/src/attestation.h b/firmware/src/powhsm/src/attestation.h index 5b61be27..7577fda2 100644 --- a/firmware/src/powhsm/src/attestation.h +++ b/firmware/src/powhsm/src/attestation.h @@ -25,17 +25,48 @@ #ifndef __ATTESTATION_H #define __ATTESTATION_H -#include "bc_hash.h" -#include "mem.h" - -// ----------------------------------------------------------------------- -// Keys attestation -// ----------------------------------------------------------------------- +#include "hal/hash.h" // Attestation message prefix -#define ATT_MSG_PREFIX "HSM:SIGNER:5.3" +#define ATT_MSG_PREFIX "POWHSM:5.4::" #define ATT_MSG_PREFIX_LENGTH (sizeof(ATT_MSG_PREFIX) - sizeof("")) +// Attestation UD value size +#define ATT_UD_VALUE_SIZE 32 + +// Number of leading bytes of the last signed BTC tx +// to include in the message +#define ATT_LAST_SIGNED_TX_BYTES 8 + +// Maximum attestation message to sign size +// Prefix: 12 bytes +// Platform: 3 bytes +// UD value: 32 bytes +// Public keys hash: 32 bytes +// Current best block hash: 32 bytes +// Head of latest authorised signed BTC transaction hash: 8 bytes +// Timestamp: 8 bytes +// TOTAL: 127 bytes +#define MAX_ATT_MESSAGE_SIZE 130 + +// Attestation SM states +typedef enum { + STATE_ATTESTATION_WAIT_SIGN = 0, + STATE_ATTESTATION_READY, +} state_attestation_t; + +typedef struct att_s { + state_attestation_t state; + + hash_sha256_ctx_t hash_ctx; // Attestation public keys hashing context + uint8_t msg[MAX_ATT_MESSAGE_SIZE]; // Attestation message + uint8_t msg_length; + + uint32_t path[BIP32_PATH_NUMPARTS]; + uint8_t pubkey[PUBKEY_UNCMP_LENGTH]; + uint8_t pubkey_length; +} att_t; + // ----------------------------------------------------------------------- // Protocol // ----------------------------------------------------------------------- @@ -45,6 +76,7 @@ typedef enum { OP_ATT_GET = 0x01, OP_ATT_GET_MESSAGE = 0x02, OP_ATT_APP_HASH = 0x03, + OP_ATT_GET_ENVELOPE = 0x04, } op_code_attestation_t; // Error codes diff --git a/firmware/src/powhsm/src/mem.h b/firmware/src/powhsm/src/mem.h index ac610f20..58a42f68 100644 --- a/firmware/src/powhsm/src/mem.h +++ b/firmware/src/powhsm/src/mem.h @@ -34,6 +34,7 @@ #include "btctx.h" #include "btcscript.h" #include "auth.h" +#include "attestation.h" #include "heartbeat.h" // ----------------------------------------------------------------------- @@ -41,18 +42,6 @@ // heartbeat. // ----------------------------------------------------------------------- -// Maximum attestation message to sign size (prefix + public keys hash) -#define MAX_ATT_MESSAGE_SIZE 50 - -typedef struct att_s { - hash_sha256_ctx_t hash_ctx; // Attestation public keys hashing context - uint8_t msg[MAX_ATT_MESSAGE_SIZE]; // Attestation message - - uint32_t path[BIP32_PATH_NUMPARTS]; - uint8_t pubkey[PUBKEY_UNCMP_LENGTH]; - uint8_t pubkey_length; -} att_t; - typedef union { struct { block_t block; diff --git a/middleware/adm_ledger.py b/middleware/adm_ledger.py index da484038..758060e6 100644 --- a/middleware/adm_ledger.py +++ b/middleware/adm_ledger.py @@ -30,8 +30,8 @@ from admin.onboard import do_onboard from admin.pubkeys import do_get_pubkeys from admin.changepin import do_changepin -from admin.attestation import do_attestation -from admin.verify_attestation import do_verify_attestation +from admin.ledger_attestation import do_attestation +from admin.verify_ledger_attestation import do_verify_attestation from admin.authorize_signer import do_authorize_signer DEFAULT_ATT_UD_SOURCE = "https://public-node.rsk.co" diff --git a/middleware/admin/attestation.py b/middleware/admin/ledger_attestation.py similarity index 90% rename from middleware/admin/attestation.py rename to middleware/admin/ledger_attestation.py index 2328f1ab..a10fa2e0 100644 --- a/middleware/admin/attestation.py +++ b/middleware/admin/ledger_attestation.py @@ -64,7 +64,7 @@ def do_attestation(options): except RskClientError as e: raise AdminError(f"While fetching the best RSK block hash: {str(e)}") - info(f"Using {ud_value} as the user-defined UI attestation value") + info(f"Using {ud_value} as the user-defined attestation value") # Attempt to unlock the device without exiting the UI try: @@ -98,7 +98,10 @@ def do_attestation(options): # Signer attestation info("Gathering Signer attestation... ", options.verbose) try: - signer_attestation = hsm.get_signer_attestation() + powhsm_attestation = hsm.get_powhsm_attestation(ud_value) + # Health check: message and envelope must be the same + if powhsm_attestation["message"] != powhsm_attestation["envelope"]: + raise AdminError("Signer attestation message and envelope differ") except Exception as e: raise AdminError(f"Failed to gather Signer attestation: {str(e)}") info("Signer attestation gathered") @@ -117,10 +120,10 @@ def do_attestation(options): att_cert.add_element( HSMCertificateElement({ "name": "signer", - "message": signer_attestation["message"], - "signature": signer_attestation["signature"], + "message": powhsm_attestation["message"], + "signature": powhsm_attestation["signature"], "signed_by": "attestation", - "tweak": signer_attestation["app_hash"], + "tweak": powhsm_attestation["app_hash"], })) att_cert.clear_targets() att_cert.add_target("ui") diff --git a/middleware/admin/verify_attestation.py b/middleware/admin/verify_ledger_attestation.py similarity index 75% rename from middleware/admin/verify_attestation.py rename to middleware/admin/verify_ledger_attestation.py index 3d398267..f09f99c2 100644 --- a/middleware/admin/verify_attestation.py +++ b/middleware/admin/verify_ledger_attestation.py @@ -30,13 +30,22 @@ UI_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:UI:(5.[0-9])") -SIGNER_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:SIGNER:(5.[0-9])") +SIGNER_LEGACY_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:SIGNER:(5.[0-9])") UI_DERIVATION_PATH = "m/44'/0'/0'/0/0" UD_VALUE_LENGTH = 32 PUBKEY_COMPRESSED_LENGTH = 33 SIGNER_HASH_LENGTH = 32 SIGNER_ITERATION_LENGTH = 2 +# New signer message header with fields +SIGNER_MESSAGE_HEADER_REGEX = re.compile(b"^POWHSM:(5.[0-9])::") +SM_PLATFORM_LEN = 3 +SM_UD_LEN = 32 +SM_PKH_LEN = 32 +SM_BB_LEN = 32 +SM_TXN_LEN = 8 +SM_TMSTMP_LEN = 8 + # Ledger's root authority # (according to # https://github.com/LedgerHQ/blue-loader-python/blob/master/ledgerblue/ @@ -46,14 +55,6 @@ "dad609" -def match_ui_message_header(ui_message): - return UI_MESSAGE_HEADER_REGEX.match(ui_message) - - -def match_signer_message_header(signer_message): - return SIGNER_MESSAGE_HEADER_REGEX.match(signer_message) - - def do_verify_attestation(options): head("### -> Verify UI and Signer attestations", fill="#") @@ -130,7 +131,7 @@ def do_verify_attestation(options): ui_message = bytes.fromhex(ui_result[1]) ui_hash = bytes.fromhex(ui_result[2]) - mh_match = match_ui_message_header(ui_message) + mh_match = UI_MESSAGE_HEADER_REGEX.match(ui_message) if mh_match is None: raise AdminError( f"Invalid UI attestation message header: {ui_message.hex()}") @@ -174,26 +175,64 @@ def do_verify_attestation(options): signer_message = bytes.fromhex(signer_result[1]) signer_hash = bytes.fromhex(signer_result[2]) - mh_match = match_signer_message_header(signer_message) - if mh_match is None: + lmh_match = SIGNER_LEGACY_MESSAGE_HEADER_REGEX.match(signer_message) + mh_match = SIGNER_MESSAGE_HEADER_REGEX.match(signer_message) + if lmh_match is None and mh_match is None: raise AdminError( f"Invalid Signer attestation message header: {signer_message.hex()}") - mh_len = len(mh_match.group(0)) - if signer_message[mh_len:] != pubkeys_hash: - reported = signer_message[mh_len:].hex() + if lmh_match is not None: + # Legacy header + hlen = len(lmh_match.group(0)) + signer_version = lmh_match.group(1) + offset = hlen + reported_pubkeys_hash = signer_message[offset:] + offset += SM_PKH_LEN + else: + # New header + hlen = len(mh_match.group(0)) + signer_version = mh_match.group(1) + offset = hlen + reported_platform = signer_message[offset:offset+SM_PLATFORM_LEN] + offset += SM_PLATFORM_LEN + reported_ud_value = signer_message[offset:offset+SM_UD_LEN] + offset += SM_UD_LEN + reported_pubkeys_hash = signer_message[offset:offset+SM_PKH_LEN] + offset += SM_PKH_LEN + reported_best_block = signer_message[offset:offset+SM_BB_LEN] + offset += SM_BB_LEN + reported_txn_head = signer_message[offset:offset+SM_TXN_LEN] + offset += SM_TXN_LEN + reported_timestamp = signer_message[offset:offset+SM_TMSTMP_LEN] + offset += SM_TMSTMP_LEN + + if signer_message[offset:] != b'': + raise AdminError(f"Signer attestation message longer " + f"than expected: {signer_message.hex()}") + + if reported_pubkeys_hash != pubkeys_hash: raise AdminError( f"Signer attestation public keys hash mismatch: expected {pubkeys_hash.hex()}" - f" but attestation reports {reported}" + f" but attestation reports {reported_pubkeys_hash.hex()}" ) - signer_version = mh_match.group(1) + signer_info = [ + f"Hash: {pubkeys_hash.hex()}", + "", + f"Installed Signer hash: {signer_hash.hex()}", + f"Installed Signer version: {signer_version.decode()}", + ] + + if mh_match is not None: + signer_info += [ + f"Platform: {reported_platform.decode("ASCII")}", + f"UD value: {reported_ud_value.hex()}", + f"Best block: {reported_best_block.hex()}", + f"Last transaction signed: {reported_txn_head.hex()}", + f"Timestamp: {reported_timestamp.hex()}", + ] + head( - ["Signer verified with public keys:"] + pubkeys_output + [ - "", - f"Hash: {signer_message[mh_len:].hex()}", - f"Installed Signer hash: {signer_hash.hex()}", - f"Installed Signer version: {signer_version.decode()}", - ], + ["Signer verified with public keys:"] + pubkeys_output + signer_info, fill="-", ) diff --git a/middleware/ledger/hsm2dongle.py b/middleware/ledger/hsm2dongle.py index 91dbcb2a..e1154b95 100644 --- a/middleware/ledger/hsm2dongle.py +++ b/middleware/ledger/hsm2dongle.py @@ -28,7 +28,7 @@ from .signature import HSM2DongleSignature from .version import HSM2FirmwareVersion from .parameters import HSM2FirmwareParameters -from .hsm2dongle_cmds import HSM2SignerHeartbeat, HSM2UIHeartbeat +from .hsm2dongle_cmds import HSM2SignerHeartbeat, HSM2UIHeartbeat, PowHsmAttestation from .block_utils import ( rlp_mm_payload_size, remove_mm_fields_if_present, @@ -63,7 +63,6 @@ class _Command(IntEnum): SEED = 0x44 WIPE = 0x07 UI_ATT = 0x50 - SIGNER_ATT = 0x50 SIGNER_AUTH = 0x51 RETRIES = 0x45 @@ -118,13 +117,6 @@ class _UIAttestationOps(IntEnum): OP_APP_HASH = 0x04 -# Signer attestation OPs -class _SignerAttestationOps(IntEnum): - OP_GET = 0x01 - OP_GET_MESSAGE = 0x02 - OP_APP_HASH = 0x03 - - # Signer authorization OPs (and results) class _SignerAuthorizationOps(IntEnum): OP_SIGVER = 0x01 @@ -141,7 +133,6 @@ class _Ops: ADVANCE = _AdvanceOps UPD_ANCESTOR = _UpdateAncestorOps UI_ATT = _UIAttestationOps - SIGNER_ATT = _SignerAttestationOps SIGNER_AUTH = _SignerAuthorizationOps @@ -251,11 +242,6 @@ class _UIAttestationError(IntEnum): INTERNAL = 0x6A99 -class _SignerAttestationError(IntEnum): - PROT_INVALID = 0x6B00 - INTERNAL = 0x6B01 - - class _SignerAuthorizationError(IntEnum): PROT_INVALID = 0x6A01 INVALID_ITERATION = 0x6a03 @@ -271,7 +257,6 @@ class _Error: UPD_ANCESTOR = _AdvanceUpdateError UI = _UIError UI_ATT = _UIAttestationError - SIGNER_ATT = _SignerAttestationError SIGNER_AUTH = _SignerAuthorizationError # Whether a given code is in the @@ -1111,27 +1096,8 @@ def get_ui_attestation(self, ud_value_hex): "signature": attestation.hex(), } - def get_signer_attestation(self): - # Get signer hash - signer_hash = self._send_command( - self.CMD.SIGNER_ATT, bytes([self.OP.SIGNER_ATT.OP_APP_HASH]) - )[self.OFF.DATA:] - - # Retrieve attestation - attestation = self._send_command( - self.CMD.SIGNER_ATT, bytes([self.OP.SIGNER_ATT.OP_GET]) - )[self.OFF.DATA:] - - # Retrieve message - message = self._send_command( - self.CMD.SIGNER_ATT, bytes([self.OP.SIGNER_ATT.OP_GET_MESSAGE]) - )[self.OFF.DATA:] - - return { - "app_hash": signer_hash.hex(), - "message": message.hex(), - "signature": attestation.hex(), - } + def get_powhsm_attestation(self, ud_value_hex): + return PowHsmAttestation(self).run(ud_value_hex) def get_signer_heartbeat(self, ud_value): return HSM2SignerHeartbeat(self).run(ud_value) diff --git a/middleware/ledger/hsm2dongle_cmds/__init__.py b/middleware/ledger/hsm2dongle_cmds/__init__.py index 336f5b83..a6471ba5 100644 --- a/middleware/ledger/hsm2dongle_cmds/__init__.py +++ b/middleware/ledger/hsm2dongle_cmds/__init__.py @@ -22,3 +22,4 @@ from .signer_heartbeat import HSM2SignerHeartbeat from .ui_heartbeat import HSM2UIHeartbeat +from .powhsm_attestation import PowHsmAttestation diff --git a/middleware/ledger/hsm2dongle_cmds/command.py b/middleware/ledger/hsm2dongle_cmds/command.py index b1825a95..c33e2ae2 100644 --- a/middleware/ledger/hsm2dongle_cmds/command.py +++ b/middleware/ledger/hsm2dongle_cmds/command.py @@ -34,7 +34,7 @@ def __init__(self, hsm2dongle): self.Offset = hsm2dongle.OFF self.ErrorResult = hsm2dongle.ErrorResult - def send(self, op, data, timeout=None): + def send(self, op, data=b'', timeout=None): # Default timeout if timeout is None: timeout = self.dongle.DONGLE_TIMEOUT diff --git a/middleware/ledger/hsm2dongle_cmds/powhsm_attestation.py b/middleware/ledger/hsm2dongle_cmds/powhsm_attestation.py new file mode 100644 index 00000000..f5dff5b0 --- /dev/null +++ b/middleware/ledger/hsm2dongle_cmds/powhsm_attestation.py @@ -0,0 +1,81 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from enum import IntEnum +from .command import HSM2DongleCommand + + +class Op(IntEnum): + OP_GET = 0x01 + OP_GET_MESSAGE = 0x02 + OP_APP_HASH = 0x03 + OP_GET_ENVELOPE = 0x04 + + +LEGACY_HEADER = b"HSM:SIGNER:" + + +# Implements the powhsm attestation protocol against a +# running powhsm +class PowHsmAttestation(HSM2DongleCommand): + Command = 0x50 + + def run(self, ud_value_hex): + # Retrieve attestation signature + signature = self.send(Op.OP_GET, + bytes.fromhex(ud_value_hex))[self.Offset.DATA:] + + # Retrieve message and envelope + bufs = {} + brk = False + msgoffset = 1 # For legacy behavior handling + for (op, name) in \ + [(Op.OP_GET_MESSAGE, "message"), (Op.OP_GET_ENVELOPE, "envelope")]: + # Legacy behavior handling + if brk: + bufs["envelope"] = bufs["message"] + break + bufs[name] = b'' + more = True + page = 0 + while more: + result = self.send(op, bytes([page])) + more = result[self.Offset.DATA] == 1 + # Legacy behavior handling + if name == "message" and \ + result[self.Offset.DATA:self.Offset.DATA+len(LEGACY_HEADER)] == \ + LEGACY_HEADER: + msgoffset = 0 + more = False + brk = True + bufs[name] += result[self.Offset.DATA+msgoffset:] + page += 1 + + # Get signer hash + signer_hash = self.send(Op.OP_APP_HASH)[self.Offset.DATA:] + + return { + "app_hash": signer_hash.hex(), + "envelope": bufs["envelope"].hex(), + "message": bufs["message"].hex(), + "signature": signature.hex(), + } diff --git a/middleware/tests/admin/test_attestation.py b/middleware/tests/admin/test_ledger_attestation.py similarity index 89% rename from middleware/tests/admin/test_attestation.py rename to middleware/tests/admin/test_ledger_attestation.py index f2edfd59..935b1cc2 100644 --- a/middleware/tests/admin/test_attestation.py +++ b/middleware/tests/admin/test_ledger_attestation.py @@ -25,7 +25,7 @@ from types import SimpleNamespace from unittest import TestCase from unittest.mock import Mock, call, patch, mock_open -from admin.attestation import do_attestation +from admin.ledger_attestation import do_attestation from admin.certificate import HSMCertificate from admin.misc import AdminError from admin.rsk_client import RskClientError @@ -33,9 +33,9 @@ @patch("sys.stdout.write") @patch("time.sleep") -@patch("admin.attestation.do_unlock") -@patch("admin.attestation.get_hsm") -@patch("admin.attestation.HSMCertificate.from_jsonfile") +@patch("admin.ledger_attestation.do_unlock") +@patch("admin.ledger_attestation.get_hsm") +@patch("admin.ledger_attestation.HSMCertificate.from_jsonfile") class TestAttestation(TestCase): def setupMocks(self, from_jsonfile, get_hsm): from_jsonfile.return_value = HSMCertificate({ @@ -64,7 +64,8 @@ def setupMocks(self, from_jsonfile, get_hsm): }) hsm.exit_menu = Mock() hsm.disconnect = Mock() - hsm.get_signer_attestation = Mock(return_value={ + hsm.get_powhsm_attestation = Mock(return_value={ + 'envelope': 'dd' * 32, 'message': 'dd' * 32, 'signature': 'ee' * 32, 'app_hash': 'ff' * 32 @@ -78,7 +79,7 @@ def setupDefaultOptions(self): options.attestation_ud_source = 'aa' * 32 return options - @patch('admin.attestation.RskClient') + @patch('admin.ledger_attestation.RskClient') def test_attestation_ok_provided_ud_value(self, RskClient, from_jsonfile, @@ -134,7 +135,7 @@ def test_attestation_ok_provided_ud_value(self, }, indent=2))], file_mock.return_value.write.call_args_list) - @patch('admin.attestation.RskClient') + @patch('admin.ledger_attestation.RskClient') def test_attestation_ok_get_ud_value(self, RskClient, from_jsonfile, get_hsm, *_): self.setupMocks(from_jsonfile, get_hsm) RskClient.return_value = Mock() @@ -227,7 +228,7 @@ def test_attestation_invalid_jsonfile(self, from_jsonfile, get_hsm, *_): self.assertFalse(get_hsm.called) self.assertFalse(file_mock.return_value.write.called) - @patch('admin.attestation.RskClient') + @patch('admin.ledger_attestation.RskClient') def test_attestation_rsk_client_error(self, RskClient, from_jsonfile, get_hsm, *_): self.setupMocks(from_jsonfile, get_hsm) RskClient.side_effect = RskClientError('error-msg') @@ -274,10 +275,10 @@ def test_attestation_get_ui_attestation_error(self, from_jsonfile, get_hsm, *_): self.assertTrue(get_hsm.called) self.assertFalse(file_mock.return_value.write.called) - def test_attestation_get_signer_attestation_error(self, from_jsonfile, get_hsm, *_): + def test_attestation_get_powhsm_attestation_error(self, from_jsonfile, get_hsm, *_): self.setupMocks(from_jsonfile, get_hsm) hsm = get_hsm.return_value - hsm.get_signer_attestation.side_effect = Exception() + hsm.get_powhsm_attestation.side_effect = Exception() options = self.setupDefaultOptions() with patch('builtins.open', mock_open()) as file_mock: with self.assertRaises(AdminError): @@ -286,7 +287,21 @@ def test_attestation_get_signer_attestation_error(self, from_jsonfile, get_hsm, self.assertTrue(get_hsm.called) self.assertFalse(file_mock.return_value.write.called) - @patch("admin.attestation.HSMCertificate.add_element") + def test_attestation_get_powhsm_attestation_envelope_msg_differ(self, from_jsonfile, + get_hsm, *_): + self.setupMocks(from_jsonfile, get_hsm) + hsm = get_hsm.return_value + hsm.get_powhsm_attestation.return_value["envelope"] = "11"*32 + hsm.get_powhsm_attestation.return_value["message"] = "22"*32 + options = self.setupDefaultOptions() + with patch('builtins.open', mock_open()) as file_mock: + with self.assertRaises(AdminError): + do_attestation(options) + self.assertTrue(from_jsonfile.called) + self.assertTrue(get_hsm.called) + self.assertFalse(file_mock.return_value.write.called) + + @patch("admin.ledger_attestation.HSMCertificate.add_element") def test_attestation_add_element_error(self, add_element, from_jsonfile, get_hsm, *_): self.setupMocks(from_jsonfile, get_hsm) add_element.side_effect = Exception() @@ -298,7 +313,7 @@ def test_attestation_add_element_error(self, add_element, from_jsonfile, get_hsm self.assertTrue(get_hsm.called) self.assertFalse(file_mock.return_value.write.called) - @patch("admin.attestation.HSMCertificate.add_target") + @patch("admin.ledger_attestation.HSMCertificate.add_target") def test_attestation_add_target_error(self, add_target, from_jsonfile, get_hsm, *_): self.setupMocks(from_jsonfile, get_hsm) add_target.side_effect = ValueError() @@ -310,7 +325,7 @@ def test_attestation_add_target_error(self, add_target, from_jsonfile, get_hsm, self.assertTrue(get_hsm.called) self.assertFalse(file_mock.return_value.write.called) - @patch("admin.attestation.HSMCertificate.save_to_jsonfile") + @patch("admin.ledger_attestation.HSMCertificate.save_to_jsonfile") def test_attestation_save_to_jsonfile_error(self, save_to_jsonfile, from_jsonfile, diff --git a/middleware/tests/admin/test_verify_attestation.py b/middleware/tests/admin/test_verify_ledger_attestation.py similarity index 68% rename from middleware/tests/admin/test_verify_attestation.py rename to middleware/tests/admin/test_verify_ledger_attestation.py index 665e96db..40f510e2 100644 --- a/middleware/tests/admin/test_verify_attestation.py +++ b/middleware/tests/admin/test_verify_ledger_attestation.py @@ -25,11 +25,7 @@ from unittest.mock import Mock, call, patch, mock_open from admin.misc import AdminError from admin.pubkeys import PATHS -from admin.verify_attestation import ( - do_verify_attestation, - match_ui_message_header, - match_signer_message_header -) +from admin.verify_ledger_attestation import do_verify_attestation import ecdsa import hashlib import logging @@ -37,7 +33,8 @@ logging.disable(logging.CRITICAL) EXPECTED_UI_DERIVATION_PATH = "m/44'/0'/0'/0/0" -SIGNER_HEADER = b"HSM:SIGNER:5.3" +LEGACY_SIGNER_HEADER = b"HSM:SIGNER:5.3" +POWHSM_HEADER = b"POWHSM:5.4::" UI_HEADER = b"HSM:UI:5.3" @@ -78,16 +75,71 @@ def setUp(self): bytes.fromhex("0123") self.ui_hash = bytes.fromhex("ee" * 32) - self.signer_msg = SIGNER_HEADER + \ - bytes.fromhex(self.pubkeys_hash.hex()) + self.signer_msg = POWHSM_HEADER + \ + b'plf' + \ + bytes.fromhex('aa'*32) + \ + bytes.fromhex(self.pubkeys_hash.hex()) + \ + bytes.fromhex('bb'*32) + \ + bytes.fromhex('cc'*8) + \ + bytes.fromhex('dd'*8) + self.signer_hash = bytes.fromhex("ff" * 32) self.result = {} self.result['ui'] = (True, self.ui_msg.hex(), self.ui_hash.hex()) self.result['signer'] = (True, self.signer_msg.hex(), self.signer_hash.hex()) - @patch("admin.verify_attestation.head") - @patch("admin.verify_attestation.HSMCertificate") + @patch("admin.verify_ledger_attestation.head") + @patch("admin.verify_ledger_attestation.HSMCertificate") + @patch("json.loads") + def test_verify_attestation_legacy(self, + loads_mock, + certificate_mock, + head_mock, _): + self.signer_msg = LEGACY_SIGNER_HEADER + \ + bytes.fromhex(self.pubkeys_hash.hex()) + self.signer_hash = bytes.fromhex("ff" * 32) + self.result['signer'] = (True, self.signer_msg.hex(), self.signer_hash.hex()) + + loads_mock.return_value = self.public_keys + att_cert = Mock() + att_cert.validate_and_get_values = Mock(return_value=self.result) + certificate_mock.from_jsonfile = Mock(return_value=att_cert) + + with patch('builtins.open', mock_open(read_data='')) as file_mock: + do_verify_attestation(self.default_options) + + self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + self.assertEqual([call(self.certification_path)], + certificate_mock.from_jsonfile.call_args_list) + + expected_call_ui = call( + [ + "UI verified with:", + f"UD value: {'aa'*32}", + f"Derived public key ({EXPECTED_UI_DERIVATION_PATH}): {'bb'*33}", + f"Authorized signer hash: {'cc'*32}", + "Authorized signer iteration: 291", + f"Installed UI hash: {'ee'*32}", + "Installed UI version: 5.3", + ], + fill="-", + ) + self.assertEqual(expected_call_ui, head_mock.call_args_list[1]) + + expected_call_signer = call( + ["Signer verified with public keys:"] + self.expected_pubkeys_output + [ + f"Hash: {self.pubkeys_hash.hex()}", + "", + f"Installed Signer hash: {'ff'*32}", + "Installed Signer version: 5.3", + ], + fill="-", + ) + self.assertEqual(expected_call_signer, head_mock.call_args_list[2]) + + @patch("admin.verify_ledger_attestation.head") + @patch("admin.verify_ledger_attestation.HSMCertificate") @patch("json.loads") def test_verify_attestation(self, loads_mock, @@ -122,10 +174,18 @@ def test_verify_attestation(self, expected_call_signer = call( ["Signer verified with public keys:"] + self.expected_pubkeys_output + [ - "", f"Hash: {self.pubkeys_hash.hex()}", - f"Installed Signer hash: {'ff'*32}", - "Installed Signer version: 5.3", + "", + "Installed Signer hash: ffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffffffffffff", + "Installed Signer version: 5.4", + "Platform: plf", + "UD value: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaa", + "Best block: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + "bbbbb", + "Last transaction signed: cccccccccccccccc", + "Timestamp: dddddddddddddddd", ], fill="-", ) @@ -182,7 +242,7 @@ def test_verify_attestation_no_ui_derivation_key(self, loads_mock, _): 'not present in public key file'), str(e.exception)) - @patch("admin.verify_attestation.HSMCertificate") + @patch("admin.verify_ledger_attestation.HSMCertificate") @patch("json.loads") def test_verify_attestation_invalid_certificate(self, loads_mock, @@ -199,7 +259,7 @@ def test_verify_attestation_invalid_certificate(self, self.assertEqual('While loading the attestation certificate file: error-msg', str(e.exception)) - @patch("admin.verify_attestation.HSMCertificate") + @patch("admin.verify_ledger_attestation.HSMCertificate") @patch("json.loads") def test_verify_attestation_no_ui_att(self, loads_mock, @@ -221,7 +281,7 @@ def test_verify_attestation_no_ui_att(self, self.assertEqual('Certificate does not contain a UI attestation', str(e.exception)) - @patch("admin.verify_attestation.HSMCertificate") + @patch("admin.verify_ledger_attestation.HSMCertificate") @patch("json.loads") def test_verify_attestation_invalid_ui_att(self, loads_mock, @@ -242,7 +302,7 @@ def test_verify_attestation_invalid_ui_att(self, self.assertEqual("Invalid UI attestation: error validating 'ui'", str(e.exception)) - @patch("admin.verify_attestation.HSMCertificate") + @patch("admin.verify_ledger_attestation.HSMCertificate") @patch("json.loads") def test_verify_attestation_no_signer_att(self, loads_mock, @@ -264,7 +324,7 @@ def test_verify_attestation_no_signer_att(self, self.assertEqual('Certificate does not contain a Signer attestation', str(e.exception)) - @patch("admin.verify_attestation.HSMCertificate") + @patch("admin.verify_ledger_attestation.HSMCertificate") @patch("json.loads") def test_verify_attestation_invalid_signer_att(self, loads_mock, @@ -285,44 +345,43 @@ def test_verify_attestation_invalid_signer_att(self, self.assertEqual(("Invalid Signer attestation: error validating 'signer'"), str(e.exception)) - def test_match_ui_message_header_valid_header(self, _): - valid_headers = [ - UI_HEADER, - b"HSM:UI:5.0", - b"HSM:UI:5.5", - b"HSM:UI:5.9", - ] - for header in valid_headers: - ui_message = header + self.ui_msg[len(UI_HEADER):] - self.assertTrue(match_ui_message_header(ui_message)) - - def test_match_ui_message_header_invalid_header(self, _): - invalid_headers = [ - SIGNER_HEADER, - b"HSM:UI:4.0", - b"HSM:UI:5.X", - ] - for header in invalid_headers: - ui_message = header + self.ui_msg[len(UI_HEADER):] - self.assertFalse(match_ui_message_header(ui_message)) - - def test_match_signer_message_header_valid_header(self, _): - valid_headers = [ - SIGNER_HEADER, - b"HSM:SIGNER:5.0", - b"HSM:SIGNER:5.5", - b"HSM:SIGNER:5.9", - ] - for header in valid_headers: - signer_message = header + self.signer_msg[len(SIGNER_HEADER):] - self.assertTrue(match_signer_message_header(signer_message)) - - def test_match_signer_message_header_invalid_header(self, _): - invalid_headers = [ - UI_HEADER, - b"HSM:SIGNER:4.0", - b"HSM:SIGNER:5.X", - ] - for header in invalid_headers: - signer_message = header + self.signer_msg[len(SIGNER_HEADER):] - self.assertFalse(match_signer_message_header(signer_message)) + @patch("admin.verify_ledger_attestation.HSMCertificate") + @patch("json.loads") + def test_verify_attestation_invalid_signer_att_header(self, + loads_mock, + certificate_mock, _): + loads_mock.return_value = self.public_keys + signer_header = b"POWHSM:AAA::somerandomstuff".hex() + self.result["signer"] = (True, signer_header, self.signer_hash.hex()) + att_cert = Mock() + att_cert.validate_and_get_values = Mock(return_value=self.result) + certificate_mock.from_jsonfile = Mock(return_value=att_cert) + + with patch('builtins.open', mock_open(read_data='')) as file_mock: + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) + + self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + self.assertEqual((f"Invalid Signer attestation message header: {signer_header}"), + str(e.exception)) + + @patch("admin.verify_ledger_attestation.HSMCertificate") + @patch("json.loads") + def test_verify_attestation_invalid_signer_att_msg_too_long(self, + loads_mock, + certificate_mock, _): + loads_mock.return_value = self.public_keys + signer_header = (b"POWHSM:5.9::" + b"aa"*300).hex() + self.result["signer"] = (True, signer_header, self.signer_hash.hex()) + att_cert = Mock() + att_cert.validate_and_get_values = Mock(return_value=self.result) + certificate_mock.from_jsonfile = Mock(return_value=att_cert) + + with patch('builtins.open', mock_open(read_data='')) as file_mock: + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) + + self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + self.assertEqual(("Signer attestation message longer " + f"than expected: {signer_header}"), + str(e.exception)) diff --git a/middleware/tests/ledger/hsm2dongle_cmds/test_powhsm_attestation.py b/middleware/tests/ledger/hsm2dongle_cmds/test_powhsm_attestation.py new file mode 100644 index 00000000..2a280150 --- /dev/null +++ b/middleware/tests/ledger/hsm2dongle_cmds/test_powhsm_attestation.py @@ -0,0 +1,121 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from ..test_hsm2dongle import TestHSM2DongleBase +from ledger.hsm2dongle import HSM2DongleErrorResult, HSM2DongleError +from ledgerblue.commException import CommException + +import logging + +logging.disable(logging.CRITICAL) + + +class TestPowHsmAttestation(TestHSM2DongleBase): + SIG = "3046022100e4c30ef37a1228a2faf2a88c8fb52a1dfe006a222d0961" \ + "c43792018481d0d5e2022100b206abd9c8a46336f9684a84083613fb" \ + "e4d31c34f7c023e5716545a00a709318" + + def test_ok(self): + self.dongle.exchange.side_effect = [ + bytes.fromhex("aabbcc" + self.SIG), + bytes.fromhex("aabbcc01112233445566778899"), + bytes.fromhex("aabbcc00aabbccddeeff"), + bytes.fromhex("aabbcc0112345678"), + bytes.fromhex("aabbcc019abcdef0"), + bytes.fromhex("aabbcc001122334455"), + bytes.fromhex("aabbcc334455667788aabbccdd"), + ] + + self.assertEqual({ + "message": "112233445566778899aabbccddeeff", + "envelope": "123456789abcdef01122334455", + "app_hash": "334455667788aabbccdd", + "signature": self.SIG, + }, self.hsm2dongle.get_powhsm_attestation("aa" + "bb"*30 + "cc")) + + self.assert_exchange([ + bytes.fromhex("5001aa" + "bb"*30 + "cc"), + bytes.fromhex("500200"), + bytes.fromhex("500201"), + bytes.fromhex("500400"), + bytes.fromhex("500401"), + bytes.fromhex("500402"), + bytes.fromhex("5003"), + ]) + + def test_legacy_ok(self): + self.dongle.exchange.side_effect = [ + bytes.fromhex("aabbcc" + self.SIG), + bytes.fromhex("aabbcc") + b"HSM:SIGNER:5.0morestuff", + bytes.fromhex("aabbcc334455667788aabbccdd"), + ] + + self.assertEqual({ + "message": b"HSM:SIGNER:5.0morestuff".hex(), + "envelope": b"HSM:SIGNER:5.0morestuff".hex(), + "app_hash": "334455667788aabbccdd", + "signature": self.SIG, + }, self.hsm2dongle.get_powhsm_attestation("aa" + "bb"*30 + "cc")) + + self.assert_exchange([ + bytes.fromhex("5001aa" + "bb"*30 + "cc"), + bytes.fromhex("500200"), + bytes.fromhex("5003"), + ]) + + def test_error_result(self): + self.dongle.exchange.side_effect = [ + bytes.fromhex("aabbcc" + self.SIG), + bytes.fromhex("aabbcc01112233445566778899"), + bytes.fromhex("aabbcc00aabbccddeeff"), + CommException("an-error-result", 0x6b01) + ] + + with self.assertRaises(HSM2DongleErrorResult) as e: + self.hsm2dongle.get_powhsm_attestation("aa" + "bb"*30 + "cc") + self.assertEqual(e.exception.error_code, 0x6b01) + + self.assert_exchange([ + bytes.fromhex("5001aa" + "bb"*30 + "cc"), + bytes.fromhex("500200"), + bytes.fromhex("500201"), + bytes.fromhex("500400"), + ]) + + def test_exception(self): + self.dongle.exchange.side_effect = [ + bytes.fromhex("aabbcc" + self.SIG), + bytes.fromhex("aabbcc01112233445566778899"), + bytes.fromhex("aabbcc00aabbccddeeff"), + CommException("an-exception") + ] + + with self.assertRaises(HSM2DongleError) as e: + self.hsm2dongle.get_powhsm_attestation("aa" + "bb"*30 + "cc") + self.assertIn("an-exception", e.exception.message) + + self.assert_exchange([ + bytes.fromhex("5001aa" + "bb"*30 + "cc"), + bytes.fromhex("500200"), + bytes.fromhex("500201"), + bytes.fromhex("500400"), + ]) From fc5aab672b3ad238fd7f8dfde78cc20f6990ae53 Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:21:25 -0300 Subject: [PATCH 22/50] Fixes coverage report for feature/sgx branch (#224) - Triggers the coverage workflow for pushes to master and feature/sgx branches - Adds optional exec argument unit tests scripts - Some additional fixes to unit tests --- .github/workflows/coverage.yml | 2 +- firmware/coverage/gen-coverage | 16 +++++------ firmware/src/common/test/run-all.sh | 30 ++++++++++++-------- firmware/src/hal/common/test/run-all.sh | 30 ++++++++++++-------- firmware/src/hal/sgx/test/run-all.sh | 29 ++++++++++++------- firmware/src/hal/x86/test/run-all.sh | 29 ++++++++++++------- firmware/src/ledger/signer/test/run-all.sh | 30 ++++++++++++-------- firmware/src/ledger/ui/test/run-all.sh | 31 +++++++++++++-------- firmware/src/powhsm/test/btctx/test_btctx.c | 6 ++-- firmware/src/powhsm/test/run-all.sh | 30 ++++++++++++-------- firmware/src/powhsm/test/srlp/test_srlp.c | 5 +++- firmware/src/sgx/test/run-all.sh | 30 ++++++++++++-------- 12 files changed, 170 insertions(+), 98 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 8a688477..8169f121 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -2,7 +2,7 @@ name: "Code coverage" on: push: - branches: [ "master" ] + branches: [ "master", "feature/sgx" ] jobs: coverage: diff --git a/firmware/coverage/gen-coverage b/firmware/coverage/gen-coverage index e8d4e6cc..70859ef8 100755 --- a/firmware/coverage/gen-coverage +++ b/firmware/coverage/gen-coverage @@ -10,13 +10,13 @@ if [[ $1 == "exec" ]]; then find $REPOROOT/firmware -name "*.gcno" -o -name "*.gcda" | xargs rm -f # Run unit tests with coverage generation - COVERAGE=y $REPOROOT/firmware/src/common/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/powhsm/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/sgx/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/ledger/ui/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/ledger/signer/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/tcpsigner/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/hal/sgx/test/run-all.sh + # The `exec` argument is used for all scripts, since we are running them inside a docker container + COVERAGE=y $REPOROOT/firmware/src/common/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/powhsm/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/sgx/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/ledger/ui/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/ledger/signer/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/hal/sgx/test/run-all.sh exec # Run tcpsigner test suite pushd $REPOROOT/firmware/src/tcpsigner > /dev/null @@ -37,7 +37,7 @@ if [[ $1 == "exec" ]]; then # Remove unwanted coverage info (test files, tcpsigner, x86 HAL implementation, mock files) lcov --remove $BASEDIR/coverage.info "*/test_*.c" --output-file $BASEDIR/coverage.info lcov --remove $BASEDIR/coverage.info "*/tcpsigner/src/*" --output-file $BASEDIR/coverage.info - lcov --remove $BASEDIR/coverage.info "*/hal/src/x86/*" --output-file $BASEDIR/coverage.info + lcov --remove $BASEDIR/coverage.info "*/hal/x86/src/*" --output-file $BASEDIR/coverage.info lcov --remove $BASEDIR/coverage.info "*/mock_*.c" --output-file $BASEDIR/coverage.info # Generate report and summary genhtml $BASEDIR/coverage.info --output $BASEDIR/output -p $SRCDIR -t "powHSM firmware" diff --git a/firmware/src/common/test/run-all.sh b/firmware/src/common/test/run-all.sh index 0ac28ed5..f5efe428 100755 --- a/firmware/src/common/test/run-all.sh +++ b/firmware/src/common/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="bigdigits_helper ints memutil" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="bigdigits_helper ints memutil" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/hal/common/test/run-all.sh b/firmware/src/hal/common/test/run-all.sh index 4278c458..650caf44 100755 --- a/firmware/src/hal/common/test/run-all.sh +++ b/firmware/src/hal/common/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="sha256" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="sha256" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/hal/sgx/test/run-all.sh b/firmware/src/hal/sgx/test/run-all.sh index c7ce071e..d059b586 100755 --- a/firmware/src/hal/sgx/test/run-all.sh +++ b/firmware/src/hal/sgx/test/run-all.sh @@ -1,12 +1,21 @@ #!/bin/bash -ROOTDIR=$(dirname $0)/../../../../.. -TESTDIR=$(realpath $(dirname $0) --relative-to $ROOTDIR) -TESTDIRS="nvmem secret_store seed" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - $ROOTDIR/docker/mware/do-notty-nousb /hsm2/$TESTDIR/$d "make clean test" || exit $? -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="nvmem secret_store seed" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../..) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/hal/x86/test/run-all.sh b/firmware/src/hal/x86/test/run-all.sh index 54e1f7d0..0628d598 100755 --- a/firmware/src/hal/x86/test/run-all.sh +++ b/firmware/src/hal/x86/test/run-all.sh @@ -1,12 +1,21 @@ #!/bin/bash -ROOTDIR=$(dirname $0)/../../../../.. -TESTDIR=$(realpath $(dirname $0) --relative-to $ROOTDIR) -TESTDIRS="bip32 endian hmac_sha256 hmac_sha512 keccak256" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - $ROOTDIR/docker/mware/do-notty-nousb /hsm2/$TESTDIR/$d "make clean test" || exit $? -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="bip32 endian hmac_sha256 hmac_sha512 keccak256" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../..) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/ledger/signer/test/run-all.sh b/firmware/src/ledger/signer/test/run-all.sh index de927848..7631c557 100755 --- a/firmware/src/ledger/signer/test/run-all.sh +++ b/firmware/src/ledger/signer/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="signer_ux" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="signer_ux" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/ledger/ui/test/run-all.sh b/firmware/src/ledger/ui/test/run-all.sh index 2be0d676..f7fd121f 100755 --- a/firmware/src/ledger/ui/test/run-all.sh +++ b/firmware/src/ledger/ui/test/run-all.sh @@ -1,13 +1,22 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="attestation bootloader onboard pin signer_authorization ui_comm ui_heartbeat unlock ux_handlers" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="attestation bootloader onboard pin signer_authorization ui_comm ui_heartbeat unlock ux_handlers" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi + diff --git a/firmware/src/powhsm/test/btctx/test_btctx.c b/firmware/src/powhsm/test/btctx/test_btctx.c index 0bea267d..8b372376 100644 --- a/firmware/src/powhsm/test/btctx/test_btctx.c +++ b/firmware/src/powhsm/test/btctx/test_btctx.c @@ -54,12 +54,14 @@ int read_hex_file(const char* file_name, unsigned char** buffer, size_t* len) { fread(tmp, 2, 1, f); read_hex(tmp, 2, *buffer + off); } - fclose(f); - if (ferror(f)) { return -1; } + if (fclose(f)) { + return -1; + } + return 0; } diff --git a/firmware/src/powhsm/test/run-all.sh b/firmware/src/powhsm/test/run-all.sh index 3eb6b08e..dbe1dc1d 100755 --- a/firmware/src/powhsm/test/run-all.sh +++ b/firmware/src/powhsm/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="btcscript btctx difficulty srlp svarint trie" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="btcscript btctx difficulty srlp svarint trie" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/powhsm/test/srlp/test_srlp.c b/firmware/src/powhsm/test/srlp/test_srlp.c index b05a2b96..dba0d1ee 100644 --- a/firmware/src/powhsm/test/srlp/test_srlp.c +++ b/firmware/src/powhsm/test/srlp/test_srlp.c @@ -204,12 +204,15 @@ int read_block_file(const char* file_name, char** buffer, size_t* len) { *buffer = malloc(*len); fread(*buffer, *len, 1, f); - fclose(f); if (ferror(f)) { return -1; } + if (fclose(f)) { + return -1; + } + return 0; } diff --git a/firmware/src/sgx/test/run-all.sh b/firmware/src/sgx/test/run-all.sh index ea5c2acc..e69b07d7 100755 --- a/firmware/src/sgx/test/run-all.sh +++ b/firmware/src/sgx/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="system" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="system" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi From 54331a7e8a40a2bf624b747aac48d3bf0176e2cb Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:47:06 -0300 Subject: [PATCH 23/50] Install SGX powHSM as a systemd service (#226) --- dist/sgx/hsm/{run => start} | 7 +++- dist/sgx/hsm/stop | 4 ++ dist/sgx/scripts/hsmsgx.service | 19 +++++++++ dist/sgx/scripts/install_service | 67 ++++++++++++++++++++++++++++++++ dist/sgx/scripts/setup | 16 ++++++++ dist/sgx/setup-new-powhsm | 20 +++++++++- 6 files changed, 131 insertions(+), 2 deletions(-) rename dist/sgx/hsm/{run => start} (81%) create mode 100755 dist/sgx/hsm/stop create mode 100644 dist/sgx/scripts/hsmsgx.service create mode 100755 dist/sgx/scripts/install_service diff --git a/dist/sgx/hsm/run b/dist/sgx/hsm/start similarity index 81% rename from dist/sgx/hsm/run rename to dist/sgx/hsm/start index 44d972af..163454d0 100755 --- a/dist/sgx/hsm/run +++ b/dist/sgx/hsm/start @@ -4,6 +4,8 @@ BINDIR=$(realpath $(dirname $0)) WORKDIR=$(realpath $BINDIR/..) DOCKER_IMAGE=powhsmsgx:runner +source $BINDIR/.env + QUIET="" echo -e "\e[96mBuilding docker image $DOCKER_IMAGE (this will take a few minutes)..." if [[ "$2" != "-v" ]]; then @@ -16,10 +18,13 @@ echo DOCKER_CNT=powhsmsgx-runner DOCKER_USER="$(id -u):$(id -g)" +HOSTNAME="SGX" +NETWORK=${NETWORK:-net_sgx} PORT=7777 DOCKER_PORT="$PORT:$PORT" -docker run -ti --rm --name $DOCKER_CNT --user $DOCKER_USER -v $WORKDIR:/hsm \ +docker run --rm --name $DOCKER_CNT --user $DOCKER_USER -v $WORKDIR:/hsm \ + --hostname $HOSTNAME --network $NETWORK \ --device=/dev/sgx_enclave:/dev/sgx_enclave \ --device=/dev/sgx_provision:/dev/sgx_provision \ -w /hsm -p$DOCKER_PORT $DOCKER_IMAGE \ diff --git a/dist/sgx/hsm/stop b/dist/sgx/hsm/stop new file mode 100755 index 00000000..65d5355b --- /dev/null +++ b/dist/sgx/hsm/stop @@ -0,0 +1,4 @@ +#!/bin/bash + +DOCKER_CNT=powhsmsgx-runner +docker stop $DOCKER_CNT diff --git a/dist/sgx/scripts/hsmsgx.service b/dist/sgx/scripts/hsmsgx.service new file mode 100644 index 00000000..18c7f7e9 --- /dev/null +++ b/dist/sgx/scripts/hsmsgx.service @@ -0,0 +1,19 @@ +[Unit] +Description=SGX powHSM +Wants=network.target +After=syslog.target network-online.target docker.service +Requires=docker.service + +[Service] +Type=simple +WorkingDirectory=$HSM_INSTALL_DIR +User=hsm +Group=hsm +ExecStart=$HSM_INSTALL_DIR/bin/start +ExecStop=$HSM_INSTALL_DIR/bin/stop +Restart=on-failure +RestartSec=10 +KillMode=mixed + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/dist/sgx/scripts/install_service b/dist/sgx/scripts/install_service new file mode 100755 index 00000000..47bfb7db --- /dev/null +++ b/dist/sgx/scripts/install_service @@ -0,0 +1,67 @@ +#!/bin/bash + +# Require superuser +if ! [ "$(id -u)" == "0" ]; then + echo -e "\e[1;31mPlease run with sudo.\e[0m" + exit 1 +fi + +if [ -z "$1" ]; then + echo -e "\e[1;31mUsage: $0 \e[0m" + exit 1 +fi + +SERVICE_UNIT=$(realpath $1) +if [ ! -f "$SERVICE_UNIT" ]; then + echo "\e[1;31mService file not found: $SERVICE_UNIT\e[0m" + exit 1 +fi + +# Extract the installation directory from the service file +INSTALL_DIR=$(grep -oP 'WorkingDirectory=\K.*' $SERVICE_UNIT) +if [ -z "$INSTALL_DIR" ]; then + echo -e "\e[1;31mCould not extract installation directory from service file.\e[0m" + exit 1 +fi + +echo -e "\e[1;32mCreating hsm user and group...\e[0m" +if ! id -u hsm >/dev/null 2>&1; then + useradd -rm -s /bin/bash hsm || exit $? + usermod -aG docker hsm || exit $? +else + echo -e "\e[1;33mUser 'hsm' already exists. Skipping user creation.\e[0m" +fi + +DEFAULT_NETWORK="net_sgx" +while true; do + echo -e "\e[1;32mEnter the name of the docker network to be created: [$DEFAULT_NETWORK]\e[0m" + read -p "> " NETWORK + if [ -z "$NETWORK" ]; then + NETWORK=$DEFAULT_NETWORK + fi + echo -e "\e[1;33mThe docker network will be named '$NETWORK'. Proceed? [Y/n]\e[0m" + read -p "> " proceed + if [[ "Y" == "$proceed" ]] || [[ "y" == "$proceed" ]] || [ -z "$proceed" ]; then + break + fi +done + +echo -e "\e[1;32mCreating $NETWORK network...\e[0m" +docker network rm $NETWORK 2> /dev/null +docker network create $NETWORK &> /dev/null +echo "NETWORK=$NETWORK" >> $INSTALL_DIR/.env || exit $? + +echo -e "\e[1;32mSetting permisions...\e[0m" +chown -R root:hsm $INSTALL_DIR || exit $? +chmod 664 $INSTALL_DIR/*.dat $INSTALL_DIR/.env || exit $? + +echo -e "\e[1;32mCreating service...\e[0m" +cp $SERVICE_UNIT /etc/systemd/system/hsmsgx.service +systemctl daemon-reload || exit $? +echo -e "\e[1;32mEnabling service...\e[0m" +systemctl enable hsmsgx.service || exit $? +echo -e "\e[1;32mEStarting service...\e[0m" +systemctl start hsmsgx.service || exit $? +echo -e "\e[1;32mService started.\e[0m" +echo -e "\e[1;32mTo check the status of the service, run 'systemctl status hsmsgx.service'.\e[0m" +exit 0 diff --git a/dist/sgx/scripts/setup b/dist/sgx/scripts/setup index b118e26f..2170614d 100755 --- a/dist/sgx/scripts/setup +++ b/dist/sgx/scripts/setup @@ -35,6 +35,12 @@ EXPORT_DIR="$ROOT_DIR/export" PUBLIC_KEY_FILE="$EXPORT_DIR/public-keys.txt" PUBLIC_KEY_FILE_JSON="$EXPORT_DIR/public-keys.json" +# HSM scripts directory +SCRIPTS_DIR=$ROOT_DIR/scripts + +# Directory where the finalized systemd service unit will be saved +SERVICE_DIR=$ROOT_DIR/service + function checkHsmBinaries() { # Check for HSM binary files FILES="$HSMBIN_DIR/hsmsgx $HSMBIN_DIR/hsmsgx_enclave.signed" @@ -96,6 +102,15 @@ function selectInstallationDir() { done } +function createServiceUnit() { + rm -rf $SERVICE_DIR + mkdir $SERVICE_DIR + + cp $SCRIPTS_DIR/hsmsgx.service $SERVICE_DIR + # Replace the $HSM_INSTALL_DIR token in the script with the actual installation directory + sed -i "s|\$HSM_INSTALL_DIR|$INSTALL_DIR|g" $SERVICE_DIR/hsmsgx.service +} + function installPowHsm() { mkdir $REAL_INSTALL_DIR/bin cp -R $HSMBIN_DIR/* $REAL_INSTALL_DIR/bin @@ -134,6 +149,7 @@ checkForPinFile checkHsmBinaries expandBinaries selectInstallationDir +createServiceUnit echo echo -e "\e[1;32mInstalling the powHSM...\e[0m" installPowHsm diff --git a/dist/sgx/setup-new-powhsm b/dist/sgx/setup-new-powhsm index 1398782a..67dd81ba 100755 --- a/dist/sgx/setup-new-powhsm +++ b/dist/sgx/setup-new-powhsm @@ -1,3 +1,21 @@ #!/bin/bash -$(dirname $0)/scripts/run_with_docker ./scripts/setup $1 +# Require superuser, since we need to install a service in the host +if ! [ "$(id -u)" == "0" ]; then + echo -e "\e[1;32mPlease run with sudo.\e[0m" + exit 1 +fi + +ROOT_DIR=$(realpath $(dirname $0)) +$ROOT_DIR/scripts/run_with_docker ./scripts/setup $1 +if [ $? -ne 0 ]; then + echo -e "\e[1;31m Error during the powhsm setup, aborting \e[0m" + exit 1 +fi + +$ROOT_DIR/scripts/install_service $ROOT_DIR/service/hsmsgx.service +if [ $? -ne 0 ]; then + echo -e "\e[1;31m Error during the powhsm service installation, aborting \e[0m" + exit 1 +fi +echo -e "\e[1;32mHSM SGX setup done.\e[0m" From 344228a540ab3b1396849d8608872a880871be8c Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 3 Dec 2024 02:08:27 +1300 Subject: [PATCH 24/50] SGX endorsement and platform library (#225) - Added endorsement initialisation and finalisation functions for SGX - Added system finalisation ecall, used within the untrusted code's finalisation routine - Removed old stubs for SGX's HAL platform and endorsement - Added der_utils library to aid with endorsement signature encoding - Implemented SGX endorsement library - Implemented SGX platform library - Adjusting sync acquire lock's function to account for different return types - Removed now unused hmac_sha256 library from SGX's HAL - Added SGX's HAL der_utils and endorsement unit tests --- firmware/src/hal/include/hal/endorsement.h | 16 +- firmware/src/hal/sgx/src/trusted/der_utils.c | 62 +++ firmware/src/hal/sgx/src/trusted/der_utils.h | 28 + .../src/hal/sgx/src/trusted/endorsement.c | 352 +++++++++---- .../src/hal/sgx/src/trusted/hmac_sha256.c | 1 - .../src/hal/sgx/src/trusted/hmac_sha256.h | 1 - firmware/src/hal/sgx/src/trusted/platform.c | 49 +- firmware/src/hal/sgx/test/der_utils/Makefile | 39 ++ .../hal/sgx/test/der_utils/test_der_utils.c | 148 ++++++ .../src/hal/sgx/test/endorsement/Makefile | 39 ++ firmware/src/hal/sgx/test/endorsement/mocks.c | 137 +++++ firmware/src/hal/sgx/test/endorsement/mocks.h | 482 ++++++++++++++++++ .../sgx/test/endorsement/test_endorsement.c | 299 +++++++++++ .../mock/openenclave/attestation/attester.h | 1 + .../openenclave/attestation/sgx/evidence.h | 1 + .../mock/openenclave/attestation/verifier.h | 1 + .../test/mock/openenclave/bits/attestation.h | 1 + .../hal/sgx/test/mock/openenclave/bits/defs.h | 1 + .../test/mock/openenclave/bits/sgx/sgxtypes.h | 1 + .../hal/sgx/test/mock/openenclave/common.h | 211 +++++++- firmware/src/hal/sgx/test/run-all.sh | 2 +- firmware/src/sgx/src/hsm.edl | 2 + firmware/src/sgx/src/trusted/ecall.c | 10 +- firmware/src/sgx/src/trusted/ecall.h | 5 + firmware/src/sgx/src/trusted/sync.h | 4 +- firmware/src/sgx/src/trusted/system.c | 5 + firmware/src/sgx/src/trusted/system.h | 5 + .../src/sgx/src/untrusted/enclave_proxy.c | 15 + .../src/sgx/src/untrusted/enclave_proxy.h | 5 + firmware/src/sgx/src/untrusted/main.c | 2 +- firmware/src/sgx/test/system/test_system.c | 4 + 31 files changed, 1815 insertions(+), 114 deletions(-) create mode 100644 firmware/src/hal/sgx/src/trusted/der_utils.c create mode 100644 firmware/src/hal/sgx/src/trusted/der_utils.h delete mode 120000 firmware/src/hal/sgx/src/trusted/hmac_sha256.c delete mode 120000 firmware/src/hal/sgx/src/trusted/hmac_sha256.h mode change 120000 => 100644 firmware/src/hal/sgx/src/trusted/platform.c create mode 100644 firmware/src/hal/sgx/test/der_utils/Makefile create mode 100644 firmware/src/hal/sgx/test/der_utils/test_der_utils.c create mode 100644 firmware/src/hal/sgx/test/endorsement/Makefile create mode 100644 firmware/src/hal/sgx/test/endorsement/mocks.c create mode 100644 firmware/src/hal/sgx/test/endorsement/mocks.h create mode 100644 firmware/src/hal/sgx/test/endorsement/test_endorsement.c create mode 120000 firmware/src/hal/sgx/test/mock/openenclave/attestation/attester.h create mode 120000 firmware/src/hal/sgx/test/mock/openenclave/attestation/sgx/evidence.h create mode 120000 firmware/src/hal/sgx/test/mock/openenclave/attestation/verifier.h create mode 120000 firmware/src/hal/sgx/test/mock/openenclave/bits/attestation.h create mode 120000 firmware/src/hal/sgx/test/mock/openenclave/bits/defs.h create mode 120000 firmware/src/hal/sgx/test/mock/openenclave/bits/sgx/sgxtypes.h diff --git a/firmware/src/hal/include/hal/endorsement.h b/firmware/src/hal/include/hal/endorsement.h index 1e508e55..fbaa8adf 100644 --- a/firmware/src/hal/include/hal/endorsement.h +++ b/firmware/src/hal/include/hal/endorsement.h @@ -115,7 +115,7 @@ extern attestation_id_t attestation_id; */ bool endorsement_init(char* att_file_path); -#elif defined(HSM_PLATFORM_SGX) || defined(HSM_PLATFORM_LEDGER) +#elif defined(HSM_PLATFORM_LEDGER) /** * @brief Initializes the endorsement module @@ -124,6 +124,20 @@ bool endorsement_init(char* att_file_path); */ bool endorsement_init(); +#elif defined(HSM_PLATFORM_SGX) + +/** + * @brief Initializes the endorsement module + * + * @returns whether the initialisation succeeded + */ +bool endorsement_init(); + +/** + * @brief Finalises the endorsement module + */ +void endorsement_finalise(); + #endif // END of platform-dependent code diff --git a/firmware/src/hal/sgx/src/trusted/der_utils.c b/firmware/src/hal/sgx/src/trusted/der_utils.c new file mode 100644 index 00000000..f6841dfc --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/der_utils.c @@ -0,0 +1,62 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "der_utils.h" +#include +#include +#include + +// Helper function to encode a len-byte unsigned integer (R or S) in DER format +static size_t der_encode_uint(uint8_t* dest, uint8_t* src, size_t len) { + // Check if we need a leading zero byte + bool lz = src[0] & 0x80; + // Start of source: remove leading zeroes + size_t trim = 0; + while (!src[trim] && trim < (len - 1)) + trim++; + // Output + size_t off = 0; + dest[off++] = 0x02; // Integer tag + dest[off++] = len - trim + (lz ? 1 : 0); // Length byte + if (lz) + dest[off++] = 0x00; // Leading zero + memcpy(dest + off, src + trim, len - trim); // Actual integer + return (size_t)dest[1] + 2; +} + +uint8_t der_encode_signature(uint8_t* dest, sgx_ecdsa256_signature_t* sig) { + uint8_t r_encoded[sizeof(sig->r) + 2], + s_encoded[sizeof(sig->s) + 2]; // Temporary buffers for R and S + uint8_t r_len = (uint8_t)der_encode_uint(r_encoded, sig->r, sizeof(sig->r)); + uint8_t s_len = (uint8_t)der_encode_uint(s_encoded, sig->s, sizeof(sig->s)); + + // Start the sequence + dest[0] = 0x30; // Sequence tag + dest[1] = r_len + s_len; // Length of the sequence + memcpy(dest + 2, r_encoded, r_len); // Copy encoded R + memcpy(dest + 2 + r_len, s_encoded, s_len); // Copy encoded S + + // Return total length of DER encoded signature + return (uint8_t)(2 + r_len + s_len); +} diff --git a/firmware/src/hal/sgx/src/trusted/der_utils.h b/firmware/src/hal/sgx/src/trusted/der_utils.h new file mode 100644 index 00000000..9f30aaff --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/der_utils.h @@ -0,0 +1,28 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +uint8_t der_encode_signature(uint8_t* dest, sgx_ecdsa256_signature_t* sig); \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/endorsement.c b/firmware/src/hal/sgx/src/trusted/endorsement.c index 2fd21e99..c5f4dc45 100644 --- a/firmware/src/hal/sgx/src/trusted/endorsement.c +++ b/firmware/src/hal/sgx/src/trusted/endorsement.c @@ -22,169 +22,315 @@ * IN THE SOFTWARE. */ -#include -#include -#include -// TODO: remove usage of secp256k1 here upon final implementation -// (only needed here for mock implementation) -#include - #include "hal/constants.h" #include "hal/endorsement.h" -#include "hal/seed.h" #include "hal/exceptions.h" #include "hal/log.h" +#include "der_utils.h" -#include "random.h" - -// TODO: remove HMAC-SHA256 entirely upon final implementation, -// (only needed for mock implementation) -#include "hmac_sha256.h" - -static secp256k1_context* sp_ctx = NULL; - -// Test key for mock implementation -static const uint8_t attestation_key[] = { - 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, - 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, - 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, -}; -// Test code hash for mock implementation -static const uint8_t attestation_code_hash[] = { - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, -}; -static uint8_t attestation_pubkey[PUBKEY_UNCMP_LENGTH]; - -static size_t tweak_sign(const unsigned char* key, - const unsigned char* tweak, - const unsigned char* hash, - unsigned char* sig) { - unsigned char tweaked_key[PRIVATE_KEY_LENGTH]; - secp256k1_ecdsa_signature sp_sig; - size_t sig_serialized_size = MAX_SIGNATURE_LENGTH; - - // Tweak private key - memmove(tweaked_key, key, sizeof(tweaked_key)); - if (!secp256k1_ec_seckey_tweak_add(sp_ctx, tweaked_key, tweak)) - return 0; +#include - // Sign and serialize as DER - secp256k1_ecdsa_sign(sp_ctx, &sp_sig, hash, tweaked_key, NULL, NULL); - secp256k1_ecdsa_signature_serialize_der( - sp_ctx, sig, &sig_serialized_size, &sp_sig); +#include +#include +#include +#include +#include +#include + +#define RAW_ENVELOPE_BUFFER_SIZE (10 * 1024) + +static struct { + bool initialised; + // The format ID used for attestation. + // See openenclave/attestation/sgx/evidence.h for supported formats. + oe_uuid_t format_id; + // The format settings buffer for the selected format. + // This is returned by oe_verifier_get_format_settings. + uint8_t* format_settings; + // The size of the format settings buffer. + size_t format_settings_size; + // Current envelope + struct { + uint8_t raw[RAW_ENVELOPE_BUFFER_SIZE]; + size_t raw_size; + sgx_quote_t* quote; + sgx_quote_auth_data_t* quote_auth_data; + sgx_qe_auth_data_t qe_auth_data; + sgx_qe_cert_data_t qe_cert_data; + } envelope; +} G_endorsement_ctx; + +#define ENDORSEMENT_FORMAT OE_FORMAT_UUID_SGX_ECDSA + +#define ENDORSEMENT_CHECK(oe_result, error_msg) \ + { \ + if (OE_OK != oe_result) { \ + LOG(error_msg); \ + LOG(": result=%u (%s)\n", result, oe_result_str(oe_result)); \ + return false; \ + } \ + } - return (int)sig_serialized_size; +// Taken from OpenEnclave's common/sgx/quote.c +OE_INLINE uint16_t ReadUint16(const uint8_t* p) { + return (uint16_t)(p[0] | (p[1] << 8)); } -static uint8_t derive_pubkey_uncmp(const unsigned char* key, - unsigned char* dest) { - secp256k1_pubkey pubkey; - size_t dest_size = PUBKEY_UNCMP_LENGTH; +// Taken from OpenEnclave's common/sgx/quote.c +OE_INLINE uint32_t ReadUint32(const uint8_t* p) { + return (uint32_t)(p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); +} - // Calculate the public key and serialize it according to - // the compressed argument - if (!secp256k1_ec_pubkey_create(sp_ctx, &pubkey, key)) { - return 0; +// Generates an envelop with the provided message as a custom claim. +static bool generate_envelope(uint8_t* msg, size_t msg_size) { + if (!G_endorsement_ctx.initialised) { + LOG("Endorsement module has not been initialised\n"); + return false; } - secp256k1_ec_pubkey_serialize( - sp_ctx, dest, &dest_size, &pubkey, SECP256K1_EC_UNCOMPRESSED); + oe_result_t result = OE_FAILURE; + uint8_t* evidence_buffer = NULL; + size_t evidence_buffer_size = 0; + result = oe_get_evidence(&G_endorsement_ctx.format_id, + 0, + msg, + msg_size, + G_endorsement_ctx.format_settings, + G_endorsement_ctx.format_settings_size, + &evidence_buffer, + &evidence_buffer_size, + NULL, + NULL); + ENDORSEMENT_CHECK(result, "Envelope generation failed"); + if (evidence_buffer_size > sizeof(G_endorsement_ctx.envelope.raw)) { + LOG("Envelope generation failed: buffer needs %lu bytes but " + "only %ld available\n", + evidence_buffer_size, + sizeof(G_endorsement_ctx.envelope.raw)); + oe_free_evidence(evidence_buffer); + return false; + } - return (uint8_t)dest_size; + memcpy( + G_endorsement_ctx.envelope.raw, evidence_buffer, evidence_buffer_size); + G_endorsement_ctx.envelope.raw_size = evidence_buffer_size; + oe_free_evidence(evidence_buffer); + + return true; } -bool endorsement_init() { - // Init the secp256k1 context - if (!sp_ctx) - sp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - - // Compute attestation public key - if (derive_pubkey_uncmp(attestation_key, attestation_pubkey) != - PUBKEY_UNCMP_LENGTH) { - LOG("Error getting uncompressed public key for mock attestation key\n"); +// Based on OpenEnclave's common/sgx/quote.c::_parse_quote() +// No validation is performed. Left to the end user. +// Maybe we could do some minimal validation in the future. +static bool parse_envelope(uint8_t* msg, size_t msg_size) { + const uint8_t* p = G_endorsement_ctx.envelope.raw; + const uint8_t* const quote_end = p + G_endorsement_ctx.envelope.raw_size; + sgx_quote_t* _sgx_quote = (sgx_quote_t*)p; + G_endorsement_ctx.envelope.quote = _sgx_quote; + + if (quote_end < p) { + LOG("SGX quote parsing error. Pointer wrapper around\n"); + return false; + } + + p += sizeof(sgx_quote_t); + + if (p > quote_end) { + LOG("Parse error after parsing SGX quote, before signature\n"); + return false; + } + if (p + _sgx_quote->signature_len + msg_size != quote_end) { + LOG("Parse error after parsing SGX signature\n"); + return false; + } + + G_endorsement_ctx.envelope.quote_auth_data = (sgx_quote_auth_data_t*)p; + + p += sizeof(sgx_quote_auth_data_t); + + sgx_qe_auth_data_t* qe_auth_data = &G_endorsement_ctx.envelope.qe_auth_data; + qe_auth_data->size = ReadUint16(p); + p += 2; + qe_auth_data->data = (uint8_t*)p; + p += qe_auth_data->size; + + if (p > quote_end) { + LOG("Parse error after parsing QE authorization data\n"); + return false; + } + + sgx_qe_cert_data_t* qe_cert_data = &G_endorsement_ctx.envelope.qe_cert_data; + qe_cert_data->type = ReadUint16(p); + p += 2; + qe_cert_data->size = ReadUint32(p); + p += 4; + qe_cert_data->data = (uint8_t*)p; + p += qe_cert_data->size; + + if (memcmp(p, msg, msg_size)) { + LOG("Parse error: got inconsistent custom message\n"); + return false; + } + + p += msg_size; + + if (p != quote_end) { + LOG("Unexpected quote length while parsing\n"); return false; } - LOG("Loaded mock attestation key:\n"); - LOG_HEX("\tKey: ", attestation_key, sizeof(attestation_key)); - LOG_HEX("\tPublic key: ", attestation_pubkey, sizeof(attestation_pubkey)); return true; } -// TODO: Implement -uint8_t* endorsement_get_envelope() { - return NULL; +// ****************************************************** // +// ********** Public interface implemenetation ********** // +// ****************************************************** // + +bool endorsement_init() { + oe_result_t result = OE_FAILURE; + + explicit_bzero(&G_endorsement_ctx, sizeof(G_endorsement_ctx)); + + // Initialize modules + result = oe_attester_initialize(); + ENDORSEMENT_CHECK(result, "Failed to initialize attester"); + result = oe_verifier_initialize(); + ENDORSEMENT_CHECK(result, "Failed to initialize verifier"); + + // Make sure the desired format is supported and + // get the corresponding settings + const oe_uuid_t format_id = {ENDORSEMENT_FORMAT}; + result = + oe_attester_select_format(&format_id, 1, &G_endorsement_ctx.format_id); + ENDORSEMENT_CHECK(result, "Failed to select attestation format"); + + result = oe_verifier_get_format_settings( + &G_endorsement_ctx.format_id, + &G_endorsement_ctx.format_settings, + &G_endorsement_ctx.format_settings_size); + ENDORSEMENT_CHECK(result, "Format is not supported by verifier"); + + G_endorsement_ctx.initialised = true; + LOG("Attestation module initialized\n"); + return true; } -// TODO: Implement -size_t endorsement_get_envelope_length() { - return 0; +void endorsement_finalise() { + oe_verifier_shutdown(); + oe_attester_shutdown(); } bool endorsement_sign(uint8_t* msg, size_t msg_size, uint8_t* signature_out, uint8_t* signature_out_length) { - - uint8_t tweak[HMAC_SHA256_SIZE]; - uint8_t hash[HASH_LENGTH]; - if (*signature_out_length < MAX_SIGNATURE_LENGTH) { - return false; + LOG("Output buffer for signature too small: %u bytes\n", + *signature_out_length); + goto endorsement_sign_fail; } - sha256(msg, msg_size, hash, sizeof(hash)); - - if (hmac_sha256(attestation_code_hash, - sizeof(attestation_code_hash), - attestation_pubkey, - sizeof(attestation_pubkey), - tweak, - sizeof(tweak)) != sizeof(tweak)) { - LOG("Error computing tweak for endorsement\n"); - return false; + if (!generate_envelope(msg, msg_size)) { + LOG("Error generating envelope\n"); + goto endorsement_sign_fail; } - if (*signature_out_length < MAX_SIGNATURE_LENGTH) { - LOG("Output buffer for signature too small: %u bytes\n", - *signature_out_length); - return false; + if (!parse_envelope(msg, msg_size)) { + LOG("Error parsing envelope\n"); + goto endorsement_sign_fail; } - *signature_out_length = - tweak_sign(attestation_key, tweak, hash, signature_out); + // Output signature in DER format + sgx_ecdsa256_signature_t* sig = + &G_endorsement_ctx.envelope.quote_auth_data->signature; + *signature_out_length = der_encode_signature(signature_out, sig); return true; + +endorsement_sign_fail: + explicit_bzero(&G_endorsement_ctx.envelope, + sizeof(G_endorsement_ctx.envelope)); + return false; +} + +uint8_t* endorsement_get_envelope() { + if (G_endorsement_ctx.envelope.raw_size == 0) { + return 0; + } + return G_endorsement_ctx.envelope.raw; +} + +size_t endorsement_get_envelope_length() { + return G_endorsement_ctx.envelope.raw_size; } bool endorsement_get_code_hash(uint8_t* code_hash_out, uint8_t* code_hash_out_length) { + if (G_endorsement_ctx.envelope.raw_size == 0) { + LOG("No envelope available\n"); + return false; + } + + if (code_hash_out == NULL) { + LOG("Output buffer is NULL\n"); + return false; + } + if (*code_hash_out_length < HASH_LENGTH) { LOG("Output buffer for code hash too small: %u bytes\n", *code_hash_out_length); return false; } - memmove( - code_hash_out, attestation_code_hash, sizeof(attestation_code_hash)); - *code_hash_out_length = sizeof(attestation_code_hash); + memcpy(code_hash_out, + G_endorsement_ctx.envelope.quote->report_body.mrenclave, + sizeof(G_endorsement_ctx.envelope.quote->report_body.mrenclave)); + *code_hash_out_length = + sizeof(G_endorsement_ctx.envelope.quote->report_body.mrenclave); return true; } bool endorsement_get_public_key(uint8_t* public_key_out, uint8_t* public_key_out_length) { + if (G_endorsement_ctx.envelope.raw_size == 0) { + LOG("No envelope available\n"); + return false; + } + + if (public_key_out == NULL) { + LOG("Output buffer is NULL\n"); + return false; + } + if (*public_key_out_length < PUBKEY_UNCMP_LENGTH) { LOG("Output buffer for public key too small: %u bytes\n", *public_key_out_length); return false; } - memcpy(public_key_out, attestation_pubkey, sizeof(attestation_pubkey)); - *public_key_out_length = sizeof(attestation_pubkey); + size_t off = 0; + public_key_out[off++] = 0x04; + memcpy( + public_key_out + off, + G_endorsement_ctx.envelope.quote_auth_data->attestation_key.x, + sizeof(G_endorsement_ctx.envelope.quote_auth_data->attestation_key.x)); + off += + sizeof(G_endorsement_ctx.envelope.quote_auth_data->attestation_key.x); + memcpy( + public_key_out + off, + G_endorsement_ctx.envelope.quote_auth_data->attestation_key.y, + sizeof(G_endorsement_ctx.envelope.quote_auth_data->attestation_key.y)); + off += + sizeof(G_endorsement_ctx.envelope.quote_auth_data->attestation_key.y); + *public_key_out_length = off; + + // Sanity check + if (off != PUBKEY_UNCMP_LENGTH) { + LOG("Unexpected attestation public key length\n"); + return false; + } return true; -} \ No newline at end of file +} diff --git a/firmware/src/hal/sgx/src/trusted/hmac_sha256.c b/firmware/src/hal/sgx/src/trusted/hmac_sha256.c deleted file mode 120000 index f260ff64..00000000 --- a/firmware/src/hal/sgx/src/trusted/hmac_sha256.c +++ /dev/null @@ -1 +0,0 @@ -../../../x86/src/hmac_sha256.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/hmac_sha256.h b/firmware/src/hal/sgx/src/trusted/hmac_sha256.h deleted file mode 120000 index 9fd6de87..00000000 --- a/firmware/src/hal/sgx/src/trusted/hmac_sha256.h +++ /dev/null @@ -1 +0,0 @@ -../../../x86/src/hmac_sha256.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/platform.c b/firmware/src/hal/sgx/src/trusted/platform.c deleted file mode 120000 index ddeafb2f..00000000 --- a/firmware/src/hal/sgx/src/trusted/platform.c +++ /dev/null @@ -1 +0,0 @@ -../../../x86/src/platform.c \ No newline at end of file diff --git a/firmware/src/hal/sgx/src/trusted/platform.c b/firmware/src/hal/sgx/src/trusted/platform.c new file mode 100644 index 00000000..42f10dab --- /dev/null +++ b/firmware/src/hal/sgx/src/trusted/platform.c @@ -0,0 +1,48 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "hal/platform.h" +#include "hal/log.h" + +#include + +void platform_memmove(void *dst, const void *src, unsigned int length) { + memmove(dst, src, length); +} + +void platform_request_exit() { + // Currently unsupported, just log the call + LOG("platform_request_exit called\n"); +} + +const char *platform_get_id() { + return "sgx"; +} + +uint64_t platform_get_timestamp() { + // Trusted way of getting current timestamp + // currently unsupported in OE/SGX, return zero + // for the time being + return (uint64_t)0; +} \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/der_utils/Makefile b/firmware/src/hal/sgx/test/der_utils/Makefile new file mode 100644 index 00000000..d9557131 --- /dev/null +++ b/firmware/src/hal/sgx/test/der_utils/Makefile @@ -0,0 +1,39 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +PROG = test.out +OBJS = der_utils.o test_der_utils.o +CFLAGS += -I. + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) *.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/hal/sgx/test/der_utils/test_der_utils.c b/firmware/src/hal/sgx/test/der_utils/test_der_utils.c new file mode 100644 index 00000000..493314a0 --- /dev/null +++ b/firmware/src/hal/sgx/test/der_utils/test_der_utils.c @@ -0,0 +1,148 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include "der_utils.h" + +void test_der_encode(const sgx_ecdsa256_signature_t* sig, + const uint8_t* expected, + int expected_len) { + uint8_t dest[72]; // Buffer large enough for DER-encoded signature + int len = der_encode_signature(dest, (sgx_ecdsa256_signature_t*)sig); + + assert(len == expected_len); + assert(memcmp(dest, expected, expected_len) == 0); +} + +int main() { + printf("Test case 1: Standard values for R and S... "); + fflush(stdout); + sgx_ecdsa256_signature_t sig1 = { + .r = {0x1c, 0x1e, 0x24, 0xf5, 0x8d, 0x7b, 0xe5, 0xa0, 0xd3, 0x55, 0x4a, + 0x2f, 0x5f, 0x3e, 0x63, 0x3a, 0x8d, 0x78, 0xae, 0x92, 0xa0, 0xb4, + 0xa8, 0xc4, 0x95, 0xb1, 0xe3, 0x2d, 0x30, 0x1f, 0x14, 0xa5}, + .s = {0x6f, 0x2a, 0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, 0x32, + 0xe9, 0xfa, 0x28, 0xe7, 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, 0xf8, + 0xf9, 0x4c, 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8, 0x6c}}; + uint8_t expected1[] = { + 0x30, 0x44, 0x02, 0x20, 0x1c, 0x1e, 0x24, 0xf5, 0x8d, 0x7b, 0xe5, 0xa0, + 0xd3, 0x55, 0x4a, 0x2f, 0x5f, 0x3e, 0x63, 0x3a, 0x8d, 0x78, 0xae, 0x92, + 0xa0, 0xb4, 0xa8, 0xc4, 0x95, 0xb1, 0xe3, 0x2d, 0x30, 0x1f, 0x14, 0xa5, + 0x02, 0x20, 0x6f, 0x2a, 0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, + 0x32, 0xe9, 0xfa, 0x28, 0xe7, 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, 0xf8, + 0xf9, 0x4c, 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8, 0x6c}; + test_der_encode(&sig1, expected1, sizeof(expected1)); + printf("Passed.\n"); + + printf("Test case 2: High bit set in R... "); + fflush(stdout); + sgx_ecdsa256_signature_t sig2 = { + .r = {0x80, 0x00, 0x00, 0x01, 0x24, 0xf5, 0x8d, 0x7b, 0xe5, 0xa0, 0xd3, + 0x55, 0x4a, 0x2f, 0x5f, 0x3e, 0x63, 0x3a, 0x8d, 0x78, 0xae, 0x92, + 0xa0, 0xb4, 0xa8, 0xc4, 0x95, 0xb1, 0xe3, 0x2d, 0x30, 0x1f}, + .s = {0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, 0x32, 0xe9, 0xfa, + 0x28, 0xe7, 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, 0xf8, 0xf9, 0x4c, + 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8, 0x6c, 0x12, 0x34}}; + uint8_t expected2[] = { + 0x30, 0x45, 0x02, 0x21, 0x00, 0x80, 0x00, 0x00, 0x01, 0x24, 0xf5, 0x8d, + 0x7b, 0xe5, 0xa0, 0xd3, 0x55, 0x4a, 0x2f, 0x5f, 0x3e, 0x63, 0x3a, 0x8d, + 0x78, 0xae, 0x92, 0xa0, 0xb4, 0xa8, 0xc4, 0x95, 0xb1, 0xe3, 0x2d, 0x30, + 0x1f, 0x02, 0x20, 0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, 0x32, + 0xe9, 0xfa, 0x28, 0xe7, 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, 0xf8, 0xf9, + 0x4c, 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8, 0x6c, 0x12, 0x34}; + test_der_encode(&sig2, expected2, sizeof(expected2)); + printf("Passed.\n"); + + printf("Test case 3: Leading zeroes in R... "); + fflush(stdout); + sgx_ecdsa256_signature_t sig3 = { + .r = {0x00, 0x00, 0x00, 0x01, 0x24, 0xf5, 0x8d, 0x7b, 0xe5, 0xa0, 0xd3, + 0x55, 0x4a, 0x2f, 0x5f, 0x3e, 0x63, 0x3a, 0x8d, 0x78, 0xae, 0x92, + 0xa0, 0xb4, 0xa8, 0xc4, 0x95, 0xb1, 0xe3, 0x2d, 0x30, 0x1f}, + .s = {0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, 0x32, 0xe9, 0xfa, + 0x28, 0xe7, 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, 0xf8, 0xf9, 0x4c, + 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8, 0x6c, 0x12, 0x34}}; + uint8_t expected3[] = { + 0x30, 0x41, 0x02, 0x1d, 0x01, 0x24, 0xf5, 0x8d, 0x7b, 0xe5, 0xa0, 0xd3, + 0x55, 0x4a, 0x2f, 0x5f, 0x3e, 0x63, 0x3a, 0x8d, 0x78, 0xae, 0x92, 0xa0, + 0xb4, 0xa8, 0xc4, 0x95, 0xb1, 0xe3, 0x2d, 0x30, 0x1f, 0x02, 0x20, 0x0f, + 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, 0x32, 0xe9, 0xfa, 0x28, 0xe7, + 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, 0xf8, 0xf9, 0x4c, 0x77, 0xb2, 0xf1, + 0xab, 0xf8, 0xd9, 0xf8, 0x6c, 0x12, 0x34}; + test_der_encode(&sig3, expected3, sizeof(expected3)); + printf("Passed.\n"); + + printf("Test case 4: Leading zeroes in S... "); + fflush(stdout); + sgx_ecdsa256_signature_t sig4 = { + .r = {0x1c, 0x1e, 0x24, 0xf5, 0x8d, 0x7b, 0xe5, 0xa0, 0xd3, 0x55, 0x4a, + 0x2f, 0x5f, 0x3e, 0x63, 0x3a, 0x8d, 0x78, 0xae, 0x92, 0xa0, 0xb4, + 0xa8, 0xc4, 0x95, 0xb1, 0xe3, 0x2d, 0x30, 0x1f, 0x14, 0xa5}, + .s = {0x00, 0x00, 0x00, 0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, + 0x32, 0xe9, 0xfa, 0x28, 0xe7, 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, + 0xf8, 0xf9, 0x4c, 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8}}; + uint8_t expected4[] = { + 0x30, 0x41, 0x02, 0x20, 0x1c, 0x1e, 0x24, 0xf5, 0x8d, 0x7b, 0xe5, 0xa0, + 0xd3, 0x55, 0x4a, 0x2f, 0x5f, 0x3e, 0x63, 0x3a, 0x8d, 0x78, 0xae, 0x92, + 0xa0, 0xb4, 0xa8, 0xc4, 0x95, 0xb1, 0xe3, 0x2d, 0x30, 0x1f, 0x14, 0xa5, + 0x02, 0x1d, 0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, 0x32, 0xe9, + 0xfa, 0x28, 0xe7, 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, 0xf8, 0xf9, 0x4c, + 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8}; + test_der_encode(&sig4, expected4, sizeof(expected4)); + printf("Passed.\n"); + + printf("Test case 5: R is zero... "); + fflush(stdout); + sgx_ecdsa256_signature_t sig5 = { + .r = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .s = {0x12, 0x34, 0x56, 0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, 0x0c, 0x95, + 0x32, 0xe9, 0xfa, 0x28, 0xe7, 0xbd, 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, + 0xf8, 0xf9, 0x4c, 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8}}; + uint8_t expected5[] = {0x30, 0x25, 0x02, 0x01, 0x00, 0x02, 0x20, 0x12, + 0x34, 0x56, 0x0f, 0x8b, 0x46, 0xd1, 0x27, 0x5c, + 0x0c, 0x95, 0x32, 0xe9, 0xfa, 0x28, 0xe7, 0xbd, + 0xf9, 0xcc, 0x7e, 0xf0, 0x2e, 0xf8, 0xf9, 0x4c, + 0x77, 0xb2, 0xf1, 0xab, 0xf8, 0xd9, 0xf8}; + test_der_encode(&sig5, expected5, sizeof(expected5)); + printf("Passed.\n"); + + printf("Test case 6: R and S are zero... "); + fflush(stdout); + sgx_ecdsa256_signature_t sig6 = { + .r = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .s = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + uint8_t expected6[] = {0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00}; + test_der_encode(&sig6, expected6, sizeof(expected6)); + printf("Passed.\n"); + + return 0; +} \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/endorsement/Makefile b/firmware/src/hal/sgx/test/endorsement/Makefile new file mode 100644 index 00000000..86c19dd9 --- /dev/null +++ b/firmware/src/hal/sgx/test/endorsement/Makefile @@ -0,0 +1,39 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +PROG = test.out +OBJS = endorsement.o test_endorsement.o mocks.o +CFLAGS += -I. + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) *.o $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/hal/sgx/test/endorsement/mocks.c b/firmware/src/hal/sgx/test/endorsement/mocks.c new file mode 100644 index 00000000..98917046 --- /dev/null +++ b/firmware/src/hal/sgx/test/endorsement/mocks.c @@ -0,0 +1,137 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include "mocks.h" + +mock_config_t G_mock_config; + +#define MOCK_RESULT(fn) return G_mock_config.result_##fn ? OE_OK : OE_FAILURE + +uint8_t mock_format_id[] = {11, 22, 33}; +uint8_t mock_format_settings[] = {44, 55, 66, 77}; +uint8_t mock_evidence[] = MOCK_EVIDENCE; + +uint8_t der_encode_signature(uint8_t* dest, sgx_ecdsa256_signature_t* sig) { + memcpy(dest, sig->r, sizeof(sig->r)); + memcpy(dest + sizeof(sig->r), sig->s, sizeof(sig->s)); + return sizeof(sig->r) + sizeof(sig->s); +} + +oe_result_t oe_attester_initialize(void) { + MOCK_RESULT(oe_attester_initialize); +} + +oe_result_t oe_attester_select_format(const oe_uuid_t* format_ids, + size_t format_ids_length, + oe_uuid_t* selected_format_id) { + + const uint8_t expected_format_id[] = OE_FORMAT_UUID_SGX_ECDSA; + const oe_uuid_t assigned_format_id = {.b = {11, 22, 33}}; + + assert(format_ids_length == 1); + assert(!memcmp( + format_ids[0].b, expected_format_id, sizeof(expected_format_id))); + *selected_format_id = assigned_format_id; + MOCK_RESULT(oe_attester_select_format); +} + +oe_result_t oe_verifier_get_format_settings(const oe_uuid_t* format_id, + uint8_t** settings, + size_t* settings_size) { + + const uint8_t expected_format_id[] = {11, 22, 33}; + assert( + !memcmp(format_id->b, expected_format_id, sizeof(expected_format_id))); + assert(settings_size != NULL); + *settings = mock_format_settings; + *settings_size = sizeof(mock_format_settings); + + MOCK_RESULT(oe_verifier_get_format_settings); +} + +oe_result_t oe_get_evidence(const oe_uuid_t* format_id, + uint32_t flags, + const void* custom_claims_buffer, + size_t custom_claims_buffer_size, + const void* optional_parameters, + size_t optional_parameters_size, + uint8_t** evidence_buffer, + size_t* evidence_buffer_size, + uint8_t** endorsements_buffer, + size_t* endorsements_buffer_size) { + + // Test parameters + assert(flags == 0); + assert(!memcmp(format_id, mock_format_id, sizeof(mock_format_id))); + assert(!memcmp(optional_parameters, + mock_format_settings, + sizeof(mock_format_settings))); + assert(optional_parameters_size == sizeof(mock_format_settings)); + assert(endorsements_buffer == NULL); + assert(endorsements_buffer_size == NULL); + + // Mock evidence + size_t sz = G_mock_config.oe_get_evidence_buffer_size > 0 + ? G_mock_config.oe_get_evidence_buffer_size + : (sizeof(mock_evidence) + custom_claims_buffer_size); + G_mock_config.oe_get_evidence_buffer = malloc(sz); + if (G_mock_config.oe_get_evidence_buffer_size == 0) { + memcpy(G_mock_config.oe_get_evidence_buffer, + mock_evidence, + sizeof(mock_evidence)); + memcpy(G_mock_config.oe_get_evidence_buffer + sizeof(mock_evidence), + custom_claims_buffer, + custom_claims_buffer_size); + ((sgx_quote_t*)G_mock_config.oe_get_evidence_buffer)->signature_len = + sz - sizeof(sgx_quote_t) - custom_claims_buffer_size; + } + + // Result + *evidence_buffer = G_mock_config.oe_get_evidence_buffer; + *evidence_buffer_size = sz; + + MOCK_RESULT(oe_get_evidence); +} + +oe_result_t oe_free_evidence(uint8_t* evidence_buffer) { + G_mock_config.oe_get_evidence_buffer_freed |= + evidence_buffer == G_mock_config.oe_get_evidence_buffer; + MOCK_RESULT(oe_free_evidence); +} + +oe_result_t oe_attester_shutdown(void) { + MOCK_RESULT(oe_attester_shutdown); +} + +oe_result_t oe_verifier_initialize(void) { + MOCK_RESULT(oe_verifier_initialize); +} + +oe_result_t oe_verifier_shutdown(void) { + MOCK_RESULT(oe_verifier_shutdown); +} \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/endorsement/mocks.h b/firmware/src/hal/sgx/test/endorsement/mocks.h new file mode 100644 index 00000000..b1aa745f --- /dev/null +++ b/firmware/src/hal/sgx/test/endorsement/mocks.h @@ -0,0 +1,482 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __MOCKS_H +#define __MOCKS_H + +#include + +typedef struct { + bool result_oe_attester_initialize; + bool result_oe_attester_shutdown; + bool result_oe_verifier_initialize; + bool result_oe_verifier_shutdown; + bool result_oe_free_evidence; + bool result_oe_verifier_get_format_settings; + bool result_oe_get_evidence; + bool result_oe_attester_select_format; + + uint8_t* oe_get_evidence_buffer; + size_t oe_get_evidence_buffer_size; + bool oe_get_evidence_buffer_freed; +} mock_config_t; + +extern mock_config_t G_mock_config; + +#define MOCK_EVIDENCE \ + { \ + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0f, \ + 0x00, 0x93, 0x9a, 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, \ + 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07, 0xce, 0xae, 0x35, 0x49, 0xbc, \ + 0x72, 0x73, 0xeb, 0x34, 0xd5, 0x62, 0xf4, 0x56, 0x4f, 0xc1, 0x82, \ + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x0e, 0x10, 0x0f, 0xff, 0xff, 0x01, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0xd3, 0x26, 0x88, 0xd3, 0xc1, 0xf3, 0xdf, 0xcc, 0x8b, \ + 0x0b, 0x36, 0xea, 0xc7, 0xc8, 0x9d, 0x49, 0xaf, 0x33, 0x18, 0x00, \ + 0xbd, 0x56, 0x24, 0x80, 0x44, 0x16, 0x6f, 0xa6, 0x69, 0x94, 0x42, \ + 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x71, 0x8c, 0x2f, 0x1a, 0x0e, 0xfb, 0xd5, 0x13, 0xe0, 0x16, 0xfa, \ + 0xfd, 0x6c, 0xf6, 0x2a, 0x62, 0x44, 0x42, 0xf2, 0xd8, 0x37, 0x08, \ + 0xd4, 0xb3, 0x3a, 0xb5, 0xa8, 0xd8, 0xc1, 0xcd, 0x4d, 0xd0, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x01, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x95, 0xbb, 0x87, 0x5c, 0x1a, \ + 0x72, 0x80, 0x71, 0xf7, 0x0a, 0xd8, 0xc9, 0xd0, 0x3f, 0x17, 0x44, \ + 0xc1, 0x9a, 0xcb, 0x05, 0x80, 0x92, 0x1e, 0x61, 0x1a, 0xc9, 0x10, \ + 0x4f, 0x77, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x2b, 0x03, 0xa7, \ + 0xbd, 0x6b, 0x5d, 0xd9, 0xfe, 0xee, 0xb3, 0x75, 0xbd, 0x59, 0x77, \ + 0x30, 0xd2, 0x87, 0x26, 0x43, 0xb4, 0x7a, 0xff, 0x4d, 0xd6, 0x41, \ + 0xc5, 0xc3, 0xa2, 0xb8, 0x01, 0x6e, 0xbb, 0xd2, 0x27, 0xf6, 0x7e, \ + 0x7c, 0x23, 0xbb, 0xdd, 0xeb, 0x4f, 0x8f, 0xdd, 0xee, 0x03, 0x1a, \ + 0x2b, 0x96, 0x15, 0x01, 0xd1, 0xc2, 0x8d, 0xda, 0x08, 0x26, 0x69, \ + 0xd7, 0xac, 0x86, 0x1e, 0x6c, 0xa0, 0x24, 0xcb, 0x34, 0xc9, 0x0e, \ + 0xa6, 0xa8, 0xf9, 0xf2, 0x18, 0x1c, 0x90, 0x20, 0xcb, 0xcc, 0x7c, \ + 0x07, 0x3e, 0x69, 0x98, 0x17, 0x33, 0xc8, 0xde, 0xed, 0x6f, 0x6c, \ + 0x45, 0x18, 0x22, 0xaa, 0x08, 0x37, 0x63, 0x50, 0xff, 0x7d, 0xa0, \ + 0x1f, 0x84, 0x2b, 0xb4, 0x0c, 0x63, 0x1c, 0xbb, 0x71, 0x1f, 0x8b, \ + 0x6f, 0x7a, 0x4f, 0xae, 0x39, 0x83, 0x20, 0xa3, 0x88, 0x47, 0x74, \ + 0xd2, 0x50, 0xad, 0x0e, 0x0e, 0x10, 0x0f, 0xff, 0xff, 0x01, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x96, 0xb3, 0x47, 0xa6, 0x4e, 0x5a, 0x04, 0x5e, 0x27, 0x36, \ + 0x9c, 0x26, 0xe6, 0xdc, 0xda, 0x51, 0xfd, 0x7c, 0x85, 0x0e, 0x9b, \ + 0x3a, 0x3a, 0x79, 0xe7, 0x18, 0xf4, 0x32, 0x61, 0xde, 0xe1, 0xe4, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, \ + 0x4f, 0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, 0x96, 0x13, 0x7f, 0x77, \ + 0xc6, 0x8a, 0x82, 0x9a, 0x00, 0x56, 0xac, 0x8d, 0xed, 0x70, 0x14, \ + 0x0b, 0x08, 0x1b, 0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe7, 0x21, 0xd0, 0x32, 0x29, 0x54, \ + 0x82, 0x15, 0x89, 0x23, 0x7f, 0xd2, 0x7e, 0xfb, 0x8f, 0xef, 0x1a, \ + 0xcb, 0x3e, 0xcd, 0x6b, 0x03, 0x52, 0xc3, 0x12, 0x71, 0x55, 0x0f, \ + 0xc7, 0x0f, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x1f, 0x14, 0xd5, 0x32, 0x27, 0x4c, 0x43, 0x85, 0xfc, \ + 0x00, 0x19, 0xca, 0x2a, 0x21, 0xe5, 0x3e, 0x17, 0x14, 0x3c, 0xb6, \ + 0x23, 0x77, 0xca, 0x4f, 0xcd, 0xd9, 0x7f, 0xa9, 0xfe, 0xf8, 0xfb, \ + 0x25, 0x95, 0xd4, 0xee, 0x27, 0x2c, 0xf3, 0xc5, 0x12, 0xe3, 0x67, \ + 0x79, 0xde, 0x67, 0xdc, 0x78, 0x14, 0x98, 0x2f, 0x11, 0x60, 0xd9, \ + 0x81, 0xd1, 0x38, 0xa3, 0x2b, 0x26, 0x5e, 0x92, 0x8a, 0x05, 0x62, \ + 0x20, 0x00, 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, 0x05, 0x00, 0x62, 0x0e, 0x00, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, \ + 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, \ + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, \ + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x38, 0x7a, 0x43, 0x43, 0x42, \ + 0x4a, 0x69, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, \ + 0x66, 0x72, 0x32, 0x64, 0x6c, 0x77, 0x4e, 0x34, 0x32, 0x44, 0x42, \ + 0x55, 0x41, 0x39, 0x43, 0x58, 0x49, 0x6b, 0x42, 0x6c, 0x47, 0x50, \ + 0x32, 0x76, 0x56, 0x33, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, \ + 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, \ + 0x0a, 0x63, 0x44, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, \ + 0x55, 0x45, 0x41, 0x77, 0x77, 0x5a, 0x53, 0x57, 0x35, 0x30, 0x5a, \ + 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x42, 0x44, \ + 0x53, 0x79, 0x42, 0x51, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, \ + 0x79, 0x62, 0x53, 0x42, 0x44, 0x51, 0x54, 0x45, 0x61, 0x4d, 0x42, \ + 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x52, 0x0a, \ + 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x51, 0x32, 0x39, \ + 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, \ + 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, \ + 0x41, 0x63, 0x4d, 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, \ + 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, 0x4a, 0x68, 0x4d, 0x51, 0x73, \ + 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x0a, 0x44, \ + 0x41, 0x4a, 0x44, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, \ + 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, \ + 0x77, 0x48, 0x68, 0x63, 0x4e, 0x4d, 0x6a, 0x51, 0x77, 0x4d, 0x7a, \ + 0x49, 0x7a, 0x4d, 0x44, 0x51, 0x30, 0x4e, 0x6a, 0x49, 0x78, 0x57, \ + 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x45, 0x77, 0x4d, 0x7a, 0x49, 0x7a, \ + 0x4d, 0x44, 0x51, 0x30, 0x4e, 0x6a, 0x49, 0x78, 0x0a, 0x57, 0x6a, \ + 0x42, 0x77, 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, \ + 0x51, 0x51, 0x44, 0x44, 0x42, 0x6c, 0x4a, 0x62, 0x6e, 0x52, 0x6c, \ + 0x62, 0x43, 0x42, 0x54, 0x52, 0x31, 0x67, 0x67, 0x55, 0x45, 0x4e, \ + 0x4c, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, \ + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x52, 0x6f, 0x77, 0x47, \ + 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x0a, 0x44, 0x42, 0x46, \ + 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x43, 0x42, 0x44, 0x62, 0x33, \ + 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, \ + 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, \ + 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, \ + 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, \ + 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x67, 0x4d, \ + 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, \ + 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, \ + 0x42, 0x5a, 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, \ + 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x43, 0x43, 0x71, 0x47, \ + 0x53, 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, 0x41, 0x30, 0x49, \ + 0x41, 0x42, 0x4b, 0x6c, 0x37, 0x0a, 0x52, 0x44, 0x4e, 0x6c, 0x73, \ + 0x5a, 0x4b, 0x6b, 0x45, 0x74, 0x41, 0x63, 0x57, 0x37, 0x53, 0x66, \ + 0x43, 0x58, 0x31, 0x4a, 0x65, 0x67, 0x62, 0x76, 0x47, 0x71, 0x34, \ + 0x4f, 0x30, 0x72, 0x52, 0x55, 0x74, 0x30, 0x7a, 0x2f, 0x47, 0x36, \ + 0x66, 0x5a, 0x4a, 0x73, 0x4e, 0x6c, 0x70, 0x6d, 0x52, 0x77, 0x54, \ + 0x42, 0x34, 0x44, 0x59, 0x6b, 0x72, 0x67, 0x6b, 0x6d, 0x31, 0x74, \ + 0x2b, 0x39, 0x52, 0x70, 0x0a, 0x4c, 0x77, 0x78, 0x46, 0x58, 0x39, \ + 0x2f, 0x6b, 0x67, 0x68, 0x78, 0x69, 0x44, 0x51, 0x6d, 0x30, 0x6a, \ + 0x71, 0x6d, 0x6a, 0x67, 0x67, 0x4d, 0x4f, 0x4d, 0x49, 0x49, 0x44, \ + 0x43, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, \ + 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x53, 0x56, 0x62, 0x31, \ + 0x33, 0x4e, 0x76, 0x52, 0x76, 0x68, 0x36, 0x55, 0x42, 0x4a, 0x79, \ + 0x64, 0x54, 0x30, 0x0a, 0x4d, 0x38, 0x34, 0x42, 0x56, 0x77, 0x76, \ + 0x65, 0x56, 0x44, 0x42, 0x72, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, \ + 0x38, 0x45, 0x5a, 0x44, 0x42, 0x69, 0x4d, 0x47, 0x43, 0x67, 0x58, \ + 0x71, 0x42, 0x63, 0x68, 0x6c, 0x70, 0x6f, 0x64, 0x48, 0x52, 0x77, \ + 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x46, 0x77, 0x61, 0x53, 0x35, \ + 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x63, 0x32, \ + 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, \ + 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, \ + 0x74, 0x4c, 0x33, 0x4e, 0x6e, 0x65, 0x43, 0x39, 0x6a, 0x5a, 0x58, \ + 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, \ + 0x57, 0x39, 0x75, 0x4c, 0x33, 0x59, 0x30, 0x4c, 0x33, 0x42, 0x6a, \ + 0x61, 0x32, 0x4e, 0x79, 0x62, 0x44, 0x39, 0x6a, 0x59, 0x54, 0x31, \ + 0x77, 0x0a, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, \ + 0x53, 0x5a, 0x6c, 0x62, 0x6d, 0x4e, 0x76, 0x5a, 0x47, 0x6c, 0x75, \ + 0x5a, 0x7a, 0x31, 0x6b, 0x5a, 0x58, 0x49, 0x77, 0x48, 0x51, 0x59, \ + 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x41, \ + 0x4c, 0x4b, 0x56, 0x35, 0x44, 0x46, 0x31, 0x36, 0x4b, 0x6e, 0x45, \ + 0x62, 0x53, 0x57, 0x35, 0x51, 0x4d, 0x39, 0x65, 0x63, 0x44, 0x71, \ + 0x0a, 0x42, 0x5a, 0x61, 0x48, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, \ + 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x45, 0x41, \ + 0x77, 0x49, 0x47, 0x77, 0x44, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, \ + 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x41, 0x6a, 0x41, \ + 0x41, 0x4d, 0x49, 0x49, 0x43, 0x4f, 0x77, 0x59, 0x4a, 0x4b, 0x6f, \ + 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x0a, \ + 0x42, 0x49, 0x49, 0x43, 0x4c, 0x44, 0x43, 0x43, 0x41, 0x69, 0x67, \ + 0x77, 0x48, 0x67, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, \ + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x51, 0x51, 0x51, 0x74, \ + 0x74, 0x4a, 0x58, 0x75, 0x69, 0x51, 0x56, 0x77, 0x71, 0x4d, 0x34, \ + 0x73, 0x37, 0x34, 0x67, 0x2b, 0x48, 0x78, 0x66, 0x4b, 0x54, 0x43, \ + 0x43, 0x41, 0x57, 0x55, 0x47, 0x43, 0x69, 0x71, 0x47, 0x0a, 0x53, \ + 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x77, \ + 0x67, 0x67, 0x46, 0x56, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, \ + 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, \ + 0x49, 0x42, 0x41, 0x67, 0x45, 0x4f, 0x4d, 0x42, 0x41, 0x47, 0x43, \ + 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, \ + 0x41, 0x51, 0x49, 0x43, 0x41, 0x67, 0x45, 0x4f, 0x0a, 0x4d, 0x42, \ + 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, \ + 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x44, 0x41, 0x67, 0x45, 0x44, \ + 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, \ + 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x45, 0x41, 0x67, \ + 0x45, 0x44, 0x4d, 0x42, 0x45, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, \ + 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x0a, 0x41, 0x51, 0x49, \ + 0x46, 0x41, 0x67, 0x49, 0x41, 0x2f, 0x7a, 0x41, 0x52, 0x42, 0x67, \ + 0x73, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x44, \ + 0x51, 0x45, 0x43, 0x42, 0x67, 0x49, 0x43, 0x41, 0x50, 0x38, 0x77, \ + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, \ + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x63, 0x43, 0x41, 0x51, \ + 0x45, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, \ + 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x67, \ + 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, \ + 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, \ + 0x67, 0x6b, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, \ + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, \ + 0x42, 0x41, 0x67, 0x6f, 0x43, 0x0a, 0x41, 0x51, 0x41, 0x77, 0x45, \ + 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, \ + 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x73, 0x43, 0x41, 0x51, 0x41, \ + 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, \ + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x77, 0x43, 0x41, \ + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, \ + 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, \ + 0x30, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, \ + 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, \ + 0x41, 0x67, 0x34, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, \ + 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, \ + 0x30, 0x42, 0x41, 0x67, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, \ + 0x41, 0x59, 0x4c, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, \ + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x41, 0x43, 0x41, 0x51, \ + 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, \ + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x45, 0x43, \ + 0x41, 0x51, 0x30, 0x77, 0x48, 0x77, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, \ + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, \ + 0x49, 0x45, 0x0a, 0x45, 0x41, 0x34, 0x4f, 0x41, 0x77, 0x50, 0x2f, \ + 0x2f, 0x77, 0x45, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, \ + 0x41, 0x41, 0x41, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4b, 0x4b, 0x6f, \ + 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, \ + 0x77, 0x51, 0x43, 0x41, 0x41, 0x41, 0x77, 0x46, 0x41, 0x59, 0x4b, \ + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, \ + 0x42, 0x0a, 0x42, 0x41, 0x51, 0x47, 0x41, 0x47, 0x42, 0x71, 0x41, \ + 0x41, 0x41, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x43, 0x69, 0x71, 0x47, \ + 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x55, \ + 0x4b, 0x41, 0x51, 0x45, 0x77, 0x48, 0x67, 0x59, 0x4b, 0x4b, 0x6f, \ + 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, \ + 0x67, 0x51, 0x51, 0x44, 0x56, 0x65, 0x2f, 0x44, 0x58, 0x55, 0x56, \ + 0x0a, 0x45, 0x34, 0x67, 0x65, 0x6d, 0x74, 0x67, 0x4f, 0x35, 0x75, \ + 0x42, 0x70, 0x76, 0x44, 0x42, 0x45, 0x42, 0x67, 0x6f, 0x71, 0x68, \ + 0x6b, 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x44, 0x51, 0x45, 0x48, \ + 0x4d, 0x44, 0x59, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, \ + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, \ + 0x45, 0x42, 0x41, 0x66, 0x38, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, \ + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, \ + 0x42, 0x42, 0x77, 0x49, 0x42, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, \ + 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, \ + 0x51, 0x30, 0x42, 0x42, 0x77, 0x4d, 0x42, 0x41, 0x51, 0x41, 0x77, \ + 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, \ + 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x51, 0x41, 0x77, 0x0a, 0x52, \ + 0x67, 0x49, 0x68, 0x41, 0x4a, 0x46, 0x67, 0x66, 0x37, 0x38, 0x48, \ + 0x67, 0x67, 0x54, 0x42, 0x74, 0x76, 0x51, 0x50, 0x58, 0x5a, 0x4a, \ + 0x78, 0x2f, 0x33, 0x46, 0x6d, 0x37, 0x31, 0x76, 0x43, 0x4f, 0x6d, \ + 0x74, 0x38, 0x32, 0x70, 0x63, 0x65, 0x39, 0x31, 0x4d, 0x32, 0x5a, \ + 0x41, 0x49, 0x30, 0x41, 0x69, 0x45, 0x41, 0x69, 0x5a, 0x4d, 0x50, \ + 0x42, 0x62, 0x5a, 0x5a, 0x6d, 0x76, 0x52, 0x32, 0x0a, 0x76, 0x2b, \ + 0x31, 0x6d, 0x72, 0x73, 0x37, 0x36, 0x4a, 0x65, 0x67, 0x6c, 0x44, \ + 0x51, 0x2b, 0x70, 0x4b, 0x2f, 0x53, 0x4c, 0x4e, 0x39, 0x34, 0x6c, \ + 0x34, 0x2b, 0x6a, 0x4d, 0x35, 0x44, 0x41, 0x3d, 0x0a, 0x2d, 0x2d, \ + 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, \ + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, \ + 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, \ + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, \ + 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, \ + 0x43, 0x6c, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x32, 0x67, 0x41, 0x77, \ + 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4a, 0x56, 0x76, 0x58, \ + 0x63, 0x32, 0x39, 0x47, 0x2b, 0x48, 0x70, 0x51, 0x45, 0x6e, 0x4a, \ + 0x31, 0x50, 0x51, 0x7a, 0x7a, 0x67, 0x46, 0x58, 0x43, 0x39, 0x35, \ + 0x55, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, \ + 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x4d, 0x47, 0x67, 0x78, \ + 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, \ + 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, \ + 0x4e, 0x48, 0x57, 0x43, 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, \ + 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, \ + 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, \ + 0x6c, 0x62, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x33, 0x4a, 0x77, 0x62, \ + 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, \ + 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, \ + 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, \ + 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, \ + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, \ + 0x4d, 0x51, 0x73, 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, \ + 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x41, 0x65, 0x46, \ + 0x77, 0x30, 0x78, 0x4f, 0x44, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, \ + 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, \ + 0x7a, 0x4d, 0x7a, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x44, \ + 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x4d, 0x48, 0x41, 0x78, 0x49, \ + 0x6a, 0x41, 0x67, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, \ + 0x4d, 0x47, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, \ + 0x4e, 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, \ + 0x47, 0x78, 0x68, 0x64, 0x47, 0x5a, 0x76, 0x63, 0x6d, 0x30, 0x67, \ + 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, \ + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, \ + 0x56, 0x73, 0x0a, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, \ + 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, \ + 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, \ + 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, \ + 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, \ + 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, \ + 0x78, 0x0a, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, \ + 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, \ + 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, \ + 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, \ + 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x4e, \ + 0x53, 0x42, 0x2f, 0x37, 0x74, 0x32, 0x31, 0x6c, 0x58, 0x53, 0x4f, \ + 0x0a, 0x32, 0x43, 0x75, 0x7a, 0x70, 0x78, 0x77, 0x37, 0x34, 0x65, \ + 0x4a, 0x42, 0x37, 0x32, 0x45, 0x79, 0x44, 0x47, 0x67, 0x57, 0x35, \ + 0x72, 0x58, 0x43, 0x74, 0x78, 0x32, 0x74, 0x56, 0x54, 0x4c, 0x71, \ + 0x36, 0x68, 0x4b, 0x6b, 0x36, 0x7a, 0x2b, 0x55, 0x69, 0x52, 0x5a, \ + 0x43, 0x6e, 0x71, 0x52, 0x37, 0x70, 0x73, 0x4f, 0x76, 0x67, 0x71, \ + 0x46, 0x65, 0x53, 0x78, 0x6c, 0x6d, 0x54, 0x6c, 0x4a, 0x6c, 0x0a, \ + 0x65, 0x54, 0x6d, 0x69, 0x32, 0x57, 0x59, 0x7a, 0x33, 0x71, 0x4f, \ + 0x42, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, \ + 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, \ + 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, \ + 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, \ + 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x0a, 0x42, \ + 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, \ + 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, \ + 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, \ + 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, \ + 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, \ + 0x64, 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, \ + 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, \ + 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, \ + 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, \ + 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, \ + 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, \ + 0x67, 0x51, 0x55, 0x6c, 0x57, 0x39, 0x64, 0x0a, 0x7a, 0x62, 0x30, \ + 0x62, 0x34, 0x65, 0x6c, 0x41, 0x53, 0x63, 0x6e, 0x55, 0x39, 0x44, \ + 0x50, 0x4f, 0x41, 0x56, 0x63, 0x4c, 0x33, 0x6c, 0x51, 0x77, 0x44, \ + 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, \ + 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, \ + 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, \ + 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x0a, 0x41, 0x66, 0x38, 0x43, \ + 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, \ + 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x52, 0x77, \ + 0x41, 0x77, 0x52, 0x41, 0x49, 0x67, 0x58, 0x73, 0x56, 0x6b, 0x69, \ + 0x30, 0x77, 0x2b, 0x69, 0x36, 0x56, 0x59, 0x47, 0x57, 0x33, 0x55, \ + 0x46, 0x2f, 0x32, 0x32, 0x75, 0x61, 0x58, 0x65, 0x30, 0x59, 0x4a, \ + 0x44, 0x6a, 0x31, 0x55, 0x65, 0x0a, 0x6e, 0x41, 0x2b, 0x54, 0x6a, \ + 0x44, 0x31, 0x61, 0x69, 0x35, 0x63, 0x43, 0x49, 0x43, 0x59, 0x62, \ + 0x31, 0x53, 0x41, 0x6d, 0x44, 0x35, 0x78, 0x6b, 0x66, 0x54, 0x56, \ + 0x70, 0x76, 0x6f, 0x34, 0x55, 0x6f, 0x79, 0x69, 0x53, 0x59, 0x78, \ + 0x72, 0x44, 0x57, 0x4c, 0x6d, 0x55, 0x52, 0x34, 0x43, 0x49, 0x39, \ + 0x4e, 0x4b, 0x79, 0x66, 0x50, 0x4e, 0x2b, 0x0a, 0x2d, 0x2d, 0x2d, \ + 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, \ + 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, \ + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, \ + 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, \ + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, \ + 0x6a, 0x7a, 0x43, 0x43, 0x41, 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, \ + 0x42, 0x41, 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, \ + 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, \ + 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, \ + 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, \ + 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x61, 0x44, 0x45, 0x61, 0x4d, \ + 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, \ + 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, \ + 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, \ + 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, \ + 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, \ + 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, \ + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, \ + 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, \ + 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, \ + 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, \ + 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, \ + 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, \ + 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, \ + 0x45, 0x34, 0x4d, 0x44, 0x55, 0x79, 0x4d, 0x54, 0x45, 0x77, 0x4e, \ + 0x44, 0x55, 0x78, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x35, \ + 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, \ + 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, \ + 0x67, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, \ + 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, \ + 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, \ + 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, \ + 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, \ + 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, \ + 0x30, 0x0a, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, \ + 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, \ + 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, \ + 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, \ + 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, \ + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, \ + 0x0a, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, \ + 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, \ + 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, \ + 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x43, 0x36, 0x6e, \ + 0x45, 0x77, 0x4d, 0x44, 0x49, 0x59, 0x5a, 0x4f, 0x6a, 0x2f, 0x69, \ + 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, 0x4b, 0x69, 0x37, 0x0a, \ + 0x31, 0x4f, 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, 0x47, \ + 0x6a, 0x62, 0x6e, 0x42, 0x56, 0x4a, 0x66, 0x56, 0x6e, 0x6b, 0x59, \ + 0x34, 0x75, 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, 0x59, 0x4c, 0x30, \ + 0x4d, 0x78, 0x4f, 0x34, 0x6d, 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, \ + 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, 0x46, 0x50, 0x32, 0x73, \ + 0x4a, 0x42, 0x4b, 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, \ + 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, \ + 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, \ + 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, \ + 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4f, \ + 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, \ + 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x0a, 0x4d, 0x45, \ + 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, \ + 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, \ + 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, \ + 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, \ + 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, \ + 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x0a, 0x5a, 0x57, 0x77, \ + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, \ + 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, \ + 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, \ + 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, \ + 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, \ + 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x0a, 0x55, 0x72, 0x39, 0x51, \ + 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, \ + 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, \ + 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, \ + 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, \ + 0x4d, 0x41, 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, \ + 0x77, 0x43, 0x67, 0x59, 0x49, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, \ + 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x51, 0x41, 0x77, \ + 0x52, 0x67, 0x49, 0x68, 0x41, 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, \ + 0x52, 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4e, 0x6f, \ + 0x6f, 0x77, 0x4c, 0x75, 0x50, 0x52, 0x4c, 0x73, 0x57, 0x47, 0x66, \ + 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, 0x58, 0x39, 0x34, 0x42, 0x67, \ + 0x77, 0x54, 0x77, 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, 0x34, 0x4a, \ + 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, 0x73, 0x2b, 0x58, 0x6f, 0x35, \ + 0x6f, 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, 0x78, 0x48, \ + 0x52, 0x41, 0x76, 0x5a, 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, \ + 0x63, 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, 0x49, 0x3d, 0x0a, 0x2d, \ + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, \ + 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, \ + 0x2d, 0x2d, 0x0a, 0x00 \ + } + +#endif // __MOCKS_H diff --git a/firmware/src/hal/sgx/test/endorsement/test_endorsement.c b/firmware/src/hal/sgx/test/endorsement/test_endorsement.c new file mode 100644 index 00000000..ce73f2a1 --- /dev/null +++ b/firmware/src/hal/sgx/test/endorsement/test_endorsement.c @@ -0,0 +1,299 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "hal/endorsement.h" +#include "hal/constants.h" + +#include +#include "mocks.h" + +uint8_t msg[] = "this is a message"; +uint8_t signature[MAX_SIGNATURE_LENGTH]; +uint8_t signature_length; +extern uint8_t mock_evidence[]; + +void setup_no_init() { + // This has the side effect of clearing the initialized state of the + // endorsement module + G_mock_config.result_oe_attester_initialize = false; + endorsement_init(); + + G_mock_config.result_oe_attester_initialize = true; + G_mock_config.result_oe_verifier_initialize = true; + G_mock_config.result_oe_attester_select_format = true; + G_mock_config.result_oe_verifier_get_format_settings = true; + G_mock_config.result_oe_get_evidence = true; + G_mock_config.oe_get_evidence_buffer_freed = false; + + signature_length = sizeof(signature); + if (G_mock_config.oe_get_evidence_buffer != NULL) { + free(G_mock_config.oe_get_evidence_buffer); + G_mock_config.oe_get_evidence_buffer = NULL; + } + G_mock_config.oe_get_evidence_buffer_size = 0; +} + +void setup() { + setup_no_init(); + assert(endorsement_init()); +} + +void setup_and_sign() { + setup(); + assert(endorsement_sign(msg, sizeof(msg), signature, &signature_length)); + assert(G_mock_config.oe_get_evidence_buffer_freed); +} + +void test_endorsement_init_ok() { + setup_no_init(); + assert(endorsement_init() == true); +} + +void test_endorsement_init_err_attinit() { + setup_no_init(); + G_mock_config.result_oe_attester_initialize = false; + assert(endorsement_init() == false); +} + +void test_endorsement_init_err_verinit() { + setup_no_init(); + G_mock_config.result_oe_verifier_initialize = false; + assert(endorsement_init() == false); +} + +void test_endorsement_init_err_selfmt() { + setup_no_init(); + G_mock_config.result_oe_attester_select_format = false; + assert(endorsement_init() == false); +} + +void test_endorsement_init_err_getfmt() { + setup_no_init(); + G_mock_config.result_oe_verifier_get_format_settings = false; + assert(endorsement_init() == false); +} + +void test_signature_ok() { + setup(); + + assert(endorsement_sign(msg, sizeof(msg), signature, &signature_length)); + + sgx_ecdsa256_signature_t* sig = + &((sgx_quote_auth_data_t*)(mock_evidence + sizeof(sgx_quote_t))) + ->signature; + assert(!memcmp(signature, sig->r, sizeof(sig->r))); + assert(!memcmp(signature + sizeof(sig->r), sig->s, sizeof(sig->s))); + assert(signature_length == sizeof(sig->r) + sizeof(sig->s)); + + assert(G_mock_config.oe_get_evidence_buffer_freed); +} + +void test_signature_err_notinit() { + setup_no_init(); + + assert(!endorsement_sign(msg, sizeof(msg), signature, &signature_length)); +} + +void test_signature_err_sigbuftoosmall() { + setup(); + + signature_length = 10; + assert(!endorsement_sign(msg, sizeof(msg), signature, &signature_length)); + + assert(!G_mock_config.oe_get_evidence_buffer_freed); +} + +void test_signature_err_evibuftoobig() { + setup(); + + G_mock_config.oe_get_evidence_buffer_size = 100000; + assert(!endorsement_sign(msg, sizeof(msg), signature, &signature_length)); + + assert(G_mock_config.oe_get_evidence_buffer_freed); +} + +void test_signature_err_evidencebroken() { + setup(); + + G_mock_config.oe_get_evidence_buffer_size = 1000; + assert(!endorsement_sign(msg, sizeof(msg), signature, &signature_length)); + + assert(G_mock_config.oe_get_evidence_buffer_freed); +} + +void test_get_envelope_ok() { + setup_and_sign(); + assert(!memcmp(endorsement_get_envelope(), + mock_evidence, + sizeof(sgx_quote_t) - sizeof(uint32_t))); + assert(!memcmp(endorsement_get_envelope() + sizeof(sgx_quote_t), + mock_evidence + sizeof(sgx_quote_t), + endorsement_get_envelope_length() - sizeof(sgx_quote_t) - + sizeof(msg))); + assert(!memcmp(endorsement_get_envelope() + + endorsement_get_envelope_length() - sizeof(msg), + msg, + sizeof(msg))); +} + +void test_get_envelope_nosignature() { + setup(); + assert(endorsement_get_envelope() == NULL); + assert(endorsement_get_envelope_length() == 0); +} + +void test_get_code_hash_ok() { + setup_and_sign(); + + uint8_t expected_code_hash[] = { + 0xd3, 0x26, 0x88, 0xd3, 0xc1, 0xf3, 0xdf, 0xcc, 0x8b, 0x0b, 0x36, + 0xea, 0xc7, 0xc8, 0x9d, 0x49, 0xaf, 0x33, 0x18, 0x00, 0xbd, 0x56, + 0x24, 0x80, 0x44, 0x16, 0x6f, 0xa6, 0x69, 0x94, 0x42, 0xc1}; + + uint8_t code_hash[sizeof(expected_code_hash) + 10]; + uint8_t code_hash_length = sizeof(code_hash); + + assert(endorsement_get_code_hash(code_hash, &code_hash_length)); + assert(code_hash_length == sizeof(expected_code_hash)); + assert(!memcmp(code_hash, expected_code_hash, sizeof(expected_code_hash))); +} + +void test_get_code_hash_err_nullbuf() { + setup_and_sign(); + + uint8_t* code_hash = NULL; + uint8_t code_hash_length = 100; + + assert(!endorsement_get_code_hash(code_hash, &code_hash_length)); + assert(code_hash_length == 100); +} + +void test_get_code_hash_err_nosignature() { + setup(); + + uint8_t code_hash[123]; + uint8_t code_hash_length = sizeof(code_hash); + + assert(!endorsement_get_code_hash(code_hash, &code_hash_length)); + assert(code_hash_length == sizeof(code_hash)); +} + +void test_get_code_hash_err_buftoosmall() { + setup_and_sign(); + + uint8_t code_hash[10]; + uint8_t code_hash_length = sizeof(code_hash); + + assert(!endorsement_get_code_hash(code_hash, &code_hash_length)); + assert(code_hash_length == sizeof(code_hash)); +} + +void test_get_public_key_ok() { + setup_and_sign(); + + uint8_t expected_public_key[] = { + 0x04, 0xa0, 0x24, 0xcb, 0x34, 0xc9, 0x0e, 0xa6, 0xa8, 0xf9, 0xf2, + 0x18, 0x1c, 0x90, 0x20, 0xcb, 0xcc, 0x7c, 0x07, 0x3e, 0x69, 0x98, + 0x17, 0x33, 0xc8, 0xde, 0xed, 0x6f, 0x6c, 0x45, 0x18, 0x22, 0xaa, + 0x08, 0x37, 0x63, 0x50, 0xff, 0x7d, 0xa0, 0x1f, 0x84, 0x2b, 0xb4, + 0x0c, 0x63, 0x1c, 0xbb, 0x71, 0x1f, 0x8b, 0x6f, 0x7a, 0x4f, 0xae, + 0x39, 0x83, 0x20, 0xa3, 0x88, 0x47, 0x74, 0xd2, 0x50, 0xad}; + + uint8_t public_key[sizeof(expected_public_key) + 10]; + uint8_t public_key_length = sizeof(public_key); + + assert(endorsement_get_public_key(public_key, &public_key_length)); + assert(public_key_length == sizeof(expected_public_key)); + assert( + !memcmp(public_key, expected_public_key, sizeof(expected_public_key))); +} + +void test_get_public_key_err_nullbuf() { + setup_and_sign(); + + uint8_t* public_key = NULL; + uint8_t public_key_length = 100; + + assert(!endorsement_get_public_key(public_key, &public_key_length)); + assert(public_key_length == 100); +} + +void test_get_public_key_err_nosignature() { + setup(); + + uint8_t public_key[123]; + uint8_t public_key_length = sizeof(public_key); + + assert(!endorsement_get_public_key(public_key, &public_key_length)); + assert(public_key_length == sizeof(public_key)); +} + +void test_get_public_key_err_buftoosmall() { + setup_and_sign(); + + uint8_t public_key[10]; + uint8_t public_key_length = sizeof(public_key); + + assert(!endorsement_get_public_key(public_key, &public_key_length)); + assert(public_key_length == sizeof(public_key)); +} + +int main() { + printf("Testing endorsement_init()...\n"); + test_endorsement_init_ok(); + test_endorsement_init_err_attinit(); + test_endorsement_init_err_verinit(); + test_endorsement_init_err_selfmt(); + test_endorsement_init_err_getfmt(); + + printf("Testing endorsement_sign()...\n"); + test_signature_ok(); + test_signature_err_notinit(); + test_signature_err_sigbuftoosmall(); + test_signature_err_evibuftoobig(); + test_signature_err_evidencebroken(); + + printf("Testing endorsement_get_envelope()...\n"); + test_get_envelope_ok(); + test_get_envelope_nosignature(); + + printf("Testing endorsement_get_code_hash()...\n"); + test_get_code_hash_ok(); + test_get_code_hash_err_nullbuf(); + test_get_code_hash_err_nosignature(); + test_get_code_hash_err_buftoosmall(); + + printf("Testing endorsement_get_public_key()...\n"); + test_get_public_key_ok(); + test_get_public_key_err_nullbuf(); + test_get_public_key_err_nosignature(); + test_get_public_key_err_buftoosmall(); +} diff --git a/firmware/src/hal/sgx/test/mock/openenclave/attestation/attester.h b/firmware/src/hal/sgx/test/mock/openenclave/attestation/attester.h new file mode 120000 index 00000000..98e8e7ca --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/attestation/attester.h @@ -0,0 +1 @@ +../common.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/openenclave/attestation/sgx/evidence.h b/firmware/src/hal/sgx/test/mock/openenclave/attestation/sgx/evidence.h new file mode 120000 index 00000000..b84129c3 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/attestation/sgx/evidence.h @@ -0,0 +1 @@ +../../common.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/openenclave/attestation/verifier.h b/firmware/src/hal/sgx/test/mock/openenclave/attestation/verifier.h new file mode 120000 index 00000000..98e8e7ca --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/attestation/verifier.h @@ -0,0 +1 @@ +../common.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/openenclave/bits/attestation.h b/firmware/src/hal/sgx/test/mock/openenclave/bits/attestation.h new file mode 120000 index 00000000..98e8e7ca --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/bits/attestation.h @@ -0,0 +1 @@ +../common.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/openenclave/bits/defs.h b/firmware/src/hal/sgx/test/mock/openenclave/bits/defs.h new file mode 120000 index 00000000..98e8e7ca --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/bits/defs.h @@ -0,0 +1 @@ +../common.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/openenclave/bits/sgx/sgxtypes.h b/firmware/src/hal/sgx/test/mock/openenclave/bits/sgx/sgxtypes.h new file mode 120000 index 00000000..b84129c3 --- /dev/null +++ b/firmware/src/hal/sgx/test/mock/openenclave/bits/sgx/sgxtypes.h @@ -0,0 +1 @@ +../../common.h \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/mock/openenclave/common.h b/firmware/src/hal/sgx/test/mock/openenclave/common.h index 54a3fc35..6d04665d 100644 --- a/firmware/src/hal/sgx/test/mock/openenclave/common.h +++ b/firmware/src/hal/sgx/test/mock/openenclave/common.h @@ -25,11 +25,220 @@ #ifndef __MOCK_OE_COMMON_H #define __MOCK_OE_COMMON_H -typedef enum oe_result { +#include +#include + +// Taken from OpenEnclave's include/openenclave/bits/defs.h + +#define OE_PACK_BEGIN _Pragma("pack(push, 1)") +#define OE_PACK_END _Pragma("pack(pop)") + +// Taken from OpenEnclave's include/openenclave/bits/result.h + +typedef enum _oe_result { OE_OK, OE_FAILURE, } oe_result_t; #define oe_result_str(result) ((result) == OE_OK ? "OE_OK" : "OE_FAILURE") +// Taken from OpenEnclave's include/openenclave/bits/sgx/sgxtypes.h + +#define SGX_USERDATA_SIZE 20 +#define OE_ZERO_SIZED_ARRAY +#define OE_SHA256_SIZE 32 +#define SGX_CPUSVN_SIZE 16 +#define OE_INLINE + +OE_PACK_BEGIN +typedef struct _sgx_report_data { + unsigned char field[64]; +} sgx_report_data_t; +OE_PACK_END + +OE_PACK_BEGIN +typedef struct _sgx_qe_auth_data { + uint16_t size; + uint8_t* data; +} sgx_qe_auth_data_t; +OE_PACK_END + +OE_PACK_BEGIN +typedef struct _sgx_qe_cert_data { + uint16_t type; + uint32_t size; + uint8_t* data; +} sgx_qe_cert_data_t; +OE_PACK_END + +OE_PACK_BEGIN +typedef struct _sgx_attributes { + uint64_t flags; + uint64_t xfrm; +} sgx_attributes_t; +OE_PACK_END + +OE_PACK_BEGIN +typedef struct _sgx_report_body { + /* (0) CPU security version */ + uint8_t cpusvn[SGX_CPUSVN_SIZE]; + + /* (16) Selector for which fields are defined in SSA.MISC */ + uint32_t miscselect; + + /* (20) Reserved */ + uint8_t reserved1[12]; + + /* (32) Enclave extended product ID */ + uint8_t isvextprodid[16]; + + /* (48) Enclave attributes */ + sgx_attributes_t attributes; + + /* (64) Enclave measurement */ + uint8_t mrenclave[OE_SHA256_SIZE]; + + /* (96) Reserved */ + uint8_t reserved2[32]; + + /* (128) The value of the enclave's SIGNER measurement */ + uint8_t mrsigner[OE_SHA256_SIZE]; + + /* (160) Reserved */ + uint8_t reserved3[32]; + + /* (192) Enclave Configuration ID*/ + uint8_t configid[64]; + + /* (256) Enclave product ID */ + uint16_t isvprodid; + + /* (258) Enclave security version */ + uint16_t isvsvn; + + /* (260) Enclave Configuration Security Version*/ + uint16_t configsvn; + + /* (262) Reserved */ + uint8_t reserved4[42]; + + /* (304) Enclave family ID */ + uint8_t isvfamilyid[16]; + + /* (320) User report data */ + sgx_report_data_t report_data; +} sgx_report_body_t; +OE_PACK_END + +OE_PACK_BEGIN +typedef struct _sgx_quote { + /* (0) */ + uint16_t version; + + /* (2) */ + uint16_t sign_type; + + /* (4) */ + uint32_t tee_type; + + /* (8) */ + uint16_t qe_svn; + + /* (10) */ + uint16_t pce_svn; + + /* (12) */ + uint8_t uuid[16]; + + /* (28) */ + uint8_t user_data[SGX_USERDATA_SIZE]; + + /* (48) */ + sgx_report_body_t report_body; + + /* (432) */ + uint32_t signature_len; + + /* (436) signature array (varying length) */ + OE_ZERO_SIZED_ARRAY uint8_t signature[]; +} sgx_quote_t; +OE_PACK_END + +OE_PACK_BEGIN +typedef struct _sgx_ecdsa256_signature { + uint8_t r[32]; + uint8_t s[32]; +} sgx_ecdsa256_signature_t; +OE_PACK_END + +OE_PACK_BEGIN +typedef struct _sgx_ecdsa256_key { + uint8_t x[32]; + uint8_t y[32]; +} sgx_ecdsa256_key_t; +OE_PACK_END + +OE_PACK_BEGIN +typedef struct _sgx_quote_auth_data { + /* (0) Pair of 256 bit ECDSA Signature. */ + sgx_ecdsa256_signature_t signature; + + /* (64) Pair of 256 bit ECDSA Key. */ + sgx_ecdsa256_key_t attestation_key; + + /* (128) Quoting Enclave Report Body */ + sgx_report_body_t qe_report_body; + + /* (512) Quoting Enclave Report Body Signature */ + sgx_ecdsa256_signature_t qe_report_body_signature; +} sgx_quote_auth_data_t; +OE_PACK_END + +// Taken from OpenEnclave's include/openenclave/bits/evidence.h + +#define OE_FORMAT_UUID_SGX_ECDSA \ + { \ + 0xa3, 0xa2, 0x1e, 0x87, 0x1b, 0x4d, 0x40, 0x14, 0xb7, 0x0a, 0xa1, \ + 0x25, 0xd2, 0xfb, 0xcd, 0x8c \ + } + +#define OE_UUID_SIZE 16 + +typedef struct _oe_uuid_t { + uint8_t b[OE_UUID_SIZE]; +} oe_uuid_t; + +// Taken from OpenEnclave's include/openenclave/attestation/attester.h + +oe_result_t oe_attester_initialize(void); + +oe_result_t oe_attester_select_format(const oe_uuid_t* format_ids, + size_t format_ids_length, + oe_uuid_t* selected_format_id); + +oe_result_t oe_get_evidence(const oe_uuid_t* format_id, + uint32_t flags, + const void* custom_claims_buffer, + size_t custom_claims_buffer_size, + const void* optional_parameters, + size_t optional_parameters_size, + uint8_t** evidence_buffer, + size_t* evidence_buffer_size, + uint8_t** endorsements_buffer, + size_t* endorsements_buffer_size); + +oe_result_t oe_free_evidence(uint8_t* evidence_buffer); + +oe_result_t oe_attester_shutdown(void); + +// Taken from OpenEnclave's include/openenclave/attestation/verifier.h + +oe_result_t oe_verifier_initialize(void); + +oe_result_t oe_verifier_get_format_settings(const oe_uuid_t* format_id, + uint8_t** settings, + size_t* settings_size); + +oe_result_t oe_verifier_shutdown(void); + #endif // #ifndef __MOCK_OE_COMMON_H \ No newline at end of file diff --git a/firmware/src/hal/sgx/test/run-all.sh b/firmware/src/hal/sgx/test/run-all.sh index d059b586..1016ef1b 100755 --- a/firmware/src/hal/sgx/test/run-all.sh +++ b/firmware/src/hal/sgx/test/run-all.sh @@ -2,7 +2,7 @@ if [[ $1 == "exec" ]]; then BASEDIR=$(realpath $(dirname $0)) - TESTDIRS="nvmem secret_store seed" + TESTDIRS="der_utils endorsement nvmem secret_store seed" for d in $TESTDIRS; do echo "******************************" echo "Testing $d..." diff --git a/firmware/src/sgx/src/hsm.edl b/firmware/src/sgx/src/hsm.edl index 9f62a8ba..6411e48a 100644 --- a/firmware/src/sgx/src/hsm.edl +++ b/firmware/src/sgx/src/hsm.edl @@ -9,6 +9,8 @@ enclave { trusted { public bool ecall_system_init(unsigned char *msg_buffer, size_t msg_buffer_size); + public void ecall_system_finalise(); + public unsigned int ecall_system_process_apdu(unsigned int rx); }; diff --git a/firmware/src/sgx/src/trusted/ecall.c b/firmware/src/sgx/src/trusted/ecall.c index cf5c89d4..97f66a76 100644 --- a/firmware/src/sgx/src/trusted/ecall.c +++ b/firmware/src/sgx/src/trusted/ecall.c @@ -32,14 +32,20 @@ #include "hal/log.h" bool ecall_system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { - SYNC_AQUIRE_LOCK(); + SYNC_AQUIRE_LOCK(false); bool success = system_init(msg_buffer, msg_buffer_size); SYNC_RELEASE_LOCK(); return success; } -unsigned int ecall_system_process_apdu(unsigned int rx) { +void ecall_system_finalise() { SYNC_AQUIRE_LOCK(); + system_finalise(); + SYNC_RELEASE_LOCK(); +} + +unsigned int ecall_system_process_apdu(unsigned int rx) { + SYNC_AQUIRE_LOCK(0); unsigned int result = system_process_apdu(rx); SYNC_RELEASE_LOCK(); return result; diff --git a/firmware/src/sgx/src/trusted/ecall.h b/firmware/src/sgx/src/trusted/ecall.h index f5373272..c25910f1 100644 --- a/firmware/src/sgx/src/trusted/ecall.h +++ b/firmware/src/sgx/src/trusted/ecall.h @@ -37,6 +37,11 @@ */ bool ecall_system_init(unsigned char *msg_buffer, size_t msg_buffer_size); +/** + * @brief See system_finalise in system.h + */ +void ecall_system_finalise(); + /** * @brief See system_process_apdu in system.h */ diff --git a/firmware/src/sgx/src/trusted/sync.h b/firmware/src/sgx/src/trusted/sync.h index 853925ff..b079d280 100644 --- a/firmware/src/sgx/src/trusted/sync.h +++ b/firmware/src/sgx/src/trusted/sync.h @@ -28,10 +28,10 @@ #include #include "hal/log.h" -#define SYNC_AQUIRE_LOCK() \ +#define SYNC_AQUIRE_LOCK(err_res) \ if (!sync_try_aqcuire_lock()) { \ LOG("Failed to acquire lock, ecall %s was not executed!\n", __func__); \ - return false; \ + return err_res; \ } #define SYNC_RELEASE_LOCK() sync_release_lock() diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c index 0f5d4a1b..09fe938c 100644 --- a/firmware/src/sgx/src/trusted/system.c +++ b/firmware/src/sgx/src/trusted/system.c @@ -233,3 +233,8 @@ bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { return true; } + +void system_finalise() { + // Finalise modules + endorsement_finalise(); +} diff --git a/firmware/src/sgx/src/trusted/system.h b/firmware/src/sgx/src/trusted/system.h index e571e136..d07a1fd4 100644 --- a/firmware/src/sgx/src/trusted/system.h +++ b/firmware/src/sgx/src/trusted/system.h @@ -35,6 +35,11 @@ */ bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size); +/** + * @brief Finalises the system module + */ +void system_finalise(); + /** * @brief Process an APDU message * diff --git a/firmware/src/sgx/src/untrusted/enclave_proxy.c b/firmware/src/sgx/src/untrusted/enclave_proxy.c index 6e402b56..ee901026 100644 --- a/firmware/src/sgx/src/untrusted/enclave_proxy.c +++ b/firmware/src/sgx/src/untrusted/enclave_proxy.c @@ -37,6 +37,21 @@ bool eprx_system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { return result; } +void eprx_system_finalise() { + oe_enclave_t *enclave = epro_get_enclave(); + if (enclave == NULL) { + LOG("Failed to retrieve the enclave. " + "Unable to call system_finalise().\n"); + return; + } + + oe_result_t oe_result = ecall_system_finalise(enclave); + if (OE_OK != oe_result) { + LOG("Failed to call system_finalise(): oe_result=%u (%s)\n", + oe_result, oe_result_str(oe_result)); + } +} + unsigned int eprx_system_process_apdu(unsigned int rx) { oe_enclave_t *enclave = epro_get_enclave(); if (enclave == NULL) { diff --git a/firmware/src/sgx/src/untrusted/enclave_proxy.h b/firmware/src/sgx/src/untrusted/enclave_proxy.h index 4565ab12..43e59cd5 100644 --- a/firmware/src/sgx/src/untrusted/enclave_proxy.h +++ b/firmware/src/sgx/src/untrusted/enclave_proxy.h @@ -8,6 +8,11 @@ */ bool eprx_system_init(unsigned char *msg_buffer, size_t msg_buffer_size); +/** + * @brief See system_finalise in system.h within the trusted sources + */ +void eprx_system_finalise(); + /** * @brief See system_process_apdu in system.h within the trusted sources */ diff --git a/firmware/src/sgx/src/untrusted/main.c b/firmware/src/sgx/src/untrusted/main.c index 56dfc1fd..9251ef1a 100644 --- a/firmware/src/sgx/src/untrusted/main.c +++ b/firmware/src/sgx/src/untrusted/main.c @@ -96,8 +96,8 @@ static struct argp argp = { static void finalise_with(int exit_code) { printf("Terminating...\n"); + eprx_system_finalise(); io_finalise(); - // TODO: finalize enclave, i/o printf("Done. Bye.\n"); exit(exit_code); } diff --git a/firmware/src/sgx/test/system/test_system.c b/firmware/src/sgx/test/system/test_system.c index b0c0b760..d49fdf3d 100644 --- a/firmware/src/sgx/test/system/test_system.c +++ b/firmware/src/sgx/test/system/test_system.c @@ -276,6 +276,10 @@ bool endorsement_init() { return true; } +void endorsement_finalise() { + // Nothing to do here +} + void nvmem_init() { NUM_CALLS(nvmem_init)++; } From c93d70d7d4aab422f800715ef2d82c4a7f7cba6c Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:21:25 -0300 Subject: [PATCH 25/50] Fixes coverage report for feature/sgx branch (#224) - Triggers the coverage workflow for pushes to master and feature/sgx branches - Adds optional exec argument unit tests scripts - Some additional fixes to unit tests --- .github/workflows/coverage.yml | 2 +- firmware/coverage/gen-coverage | 16 +++++------ firmware/src/common/test/run-all.sh | 30 ++++++++++++-------- firmware/src/hal/common/test/run-all.sh | 30 ++++++++++++-------- firmware/src/hal/sgx/test/run-all.sh | 29 ++++++++++++------- firmware/src/hal/x86/test/run-all.sh | 29 ++++++++++++------- firmware/src/ledger/signer/test/run-all.sh | 30 ++++++++++++-------- firmware/src/ledger/ui/test/run-all.sh | 31 +++++++++++++-------- firmware/src/powhsm/test/btctx/test_btctx.c | 6 ++-- firmware/src/powhsm/test/run-all.sh | 30 ++++++++++++-------- firmware/src/powhsm/test/srlp/test_srlp.c | 5 +++- firmware/src/sgx/test/run-all.sh | 30 ++++++++++++-------- 12 files changed, 170 insertions(+), 98 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 8a688477..8169f121 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -2,7 +2,7 @@ name: "Code coverage" on: push: - branches: [ "master" ] + branches: [ "master", "feature/sgx" ] jobs: coverage: diff --git a/firmware/coverage/gen-coverage b/firmware/coverage/gen-coverage index e8d4e6cc..70859ef8 100755 --- a/firmware/coverage/gen-coverage +++ b/firmware/coverage/gen-coverage @@ -10,13 +10,13 @@ if [[ $1 == "exec" ]]; then find $REPOROOT/firmware -name "*.gcno" -o -name "*.gcda" | xargs rm -f # Run unit tests with coverage generation - COVERAGE=y $REPOROOT/firmware/src/common/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/powhsm/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/sgx/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/ledger/ui/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/ledger/signer/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/tcpsigner/test/run-all.sh - COVERAGE=y $REPOROOT/firmware/src/hal/sgx/test/run-all.sh + # The `exec` argument is used for all scripts, since we are running them inside a docker container + COVERAGE=y $REPOROOT/firmware/src/common/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/powhsm/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/sgx/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/ledger/ui/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/ledger/signer/test/run-all.sh exec + COVERAGE=y $REPOROOT/firmware/src/hal/sgx/test/run-all.sh exec # Run tcpsigner test suite pushd $REPOROOT/firmware/src/tcpsigner > /dev/null @@ -37,7 +37,7 @@ if [[ $1 == "exec" ]]; then # Remove unwanted coverage info (test files, tcpsigner, x86 HAL implementation, mock files) lcov --remove $BASEDIR/coverage.info "*/test_*.c" --output-file $BASEDIR/coverage.info lcov --remove $BASEDIR/coverage.info "*/tcpsigner/src/*" --output-file $BASEDIR/coverage.info - lcov --remove $BASEDIR/coverage.info "*/hal/src/x86/*" --output-file $BASEDIR/coverage.info + lcov --remove $BASEDIR/coverage.info "*/hal/x86/src/*" --output-file $BASEDIR/coverage.info lcov --remove $BASEDIR/coverage.info "*/mock_*.c" --output-file $BASEDIR/coverage.info # Generate report and summary genhtml $BASEDIR/coverage.info --output $BASEDIR/output -p $SRCDIR -t "powHSM firmware" diff --git a/firmware/src/common/test/run-all.sh b/firmware/src/common/test/run-all.sh index 0ac28ed5..f5efe428 100755 --- a/firmware/src/common/test/run-all.sh +++ b/firmware/src/common/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="bigdigits_helper ints memutil" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="bigdigits_helper ints memutil" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/hal/common/test/run-all.sh b/firmware/src/hal/common/test/run-all.sh index 4278c458..650caf44 100755 --- a/firmware/src/hal/common/test/run-all.sh +++ b/firmware/src/hal/common/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="sha256" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="sha256" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/hal/sgx/test/run-all.sh b/firmware/src/hal/sgx/test/run-all.sh index c7ce071e..d059b586 100755 --- a/firmware/src/hal/sgx/test/run-all.sh +++ b/firmware/src/hal/sgx/test/run-all.sh @@ -1,12 +1,21 @@ #!/bin/bash -ROOTDIR=$(dirname $0)/../../../../.. -TESTDIR=$(realpath $(dirname $0) --relative-to $ROOTDIR) -TESTDIRS="nvmem secret_store seed" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - $ROOTDIR/docker/mware/do-notty-nousb /hsm2/$TESTDIR/$d "make clean test" || exit $? -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="nvmem secret_store seed" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../..) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/hal/x86/test/run-all.sh b/firmware/src/hal/x86/test/run-all.sh index 54e1f7d0..0628d598 100755 --- a/firmware/src/hal/x86/test/run-all.sh +++ b/firmware/src/hal/x86/test/run-all.sh @@ -1,12 +1,21 @@ #!/bin/bash -ROOTDIR=$(dirname $0)/../../../../.. -TESTDIR=$(realpath $(dirname $0) --relative-to $ROOTDIR) -TESTDIRS="bip32 endian hmac_sha256 hmac_sha512 keccak256" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - $ROOTDIR/docker/mware/do-notty-nousb /hsm2/$TESTDIR/$d "make clean test" || exit $? -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="bip32 endian hmac_sha256 hmac_sha512 keccak256" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../..) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/ledger/signer/test/run-all.sh b/firmware/src/ledger/signer/test/run-all.sh index de927848..7631c557 100755 --- a/firmware/src/ledger/signer/test/run-all.sh +++ b/firmware/src/ledger/signer/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="signer_ux" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="signer_ux" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/ledger/ui/test/run-all.sh b/firmware/src/ledger/ui/test/run-all.sh index 2be0d676..f7fd121f 100755 --- a/firmware/src/ledger/ui/test/run-all.sh +++ b/firmware/src/ledger/ui/test/run-all.sh @@ -1,13 +1,22 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="attestation bootloader onboard pin signer_authorization ui_comm ui_heartbeat unlock ux_handlers" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="attestation bootloader onboard pin signer_authorization ui_comm ui_heartbeat unlock ux_handlers" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi + diff --git a/firmware/src/powhsm/test/btctx/test_btctx.c b/firmware/src/powhsm/test/btctx/test_btctx.c index 0bea267d..8b372376 100644 --- a/firmware/src/powhsm/test/btctx/test_btctx.c +++ b/firmware/src/powhsm/test/btctx/test_btctx.c @@ -54,12 +54,14 @@ int read_hex_file(const char* file_name, unsigned char** buffer, size_t* len) { fread(tmp, 2, 1, f); read_hex(tmp, 2, *buffer + off); } - fclose(f); - if (ferror(f)) { return -1; } + if (fclose(f)) { + return -1; + } + return 0; } diff --git a/firmware/src/powhsm/test/run-all.sh b/firmware/src/powhsm/test/run-all.sh index 3eb6b08e..dbe1dc1d 100755 --- a/firmware/src/powhsm/test/run-all.sh +++ b/firmware/src/powhsm/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="btcscript btctx difficulty srlp svarint trie" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="btcscript btctx difficulty srlp svarint trie" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi diff --git a/firmware/src/powhsm/test/srlp/test_srlp.c b/firmware/src/powhsm/test/srlp/test_srlp.c index b05a2b96..dba0d1ee 100644 --- a/firmware/src/powhsm/test/srlp/test_srlp.c +++ b/firmware/src/powhsm/test/srlp/test_srlp.c @@ -204,12 +204,15 @@ int read_block_file(const char* file_name, char** buffer, size_t* len) { *buffer = malloc(*len); fread(*buffer, *len, 1, f); - fclose(f); if (ferror(f)) { return -1; } + if (fclose(f)) { + return -1; + } + return 0; } diff --git a/firmware/src/sgx/test/run-all.sh b/firmware/src/sgx/test/run-all.sh index ea5c2acc..e69b07d7 100755 --- a/firmware/src/sgx/test/run-all.sh +++ b/firmware/src/sgx/test/run-all.sh @@ -1,13 +1,21 @@ #!/bin/bash -BASEDIR=$(dirname $0) -TESTDIRS="system" -TESTDIRS=${1:-"$TESTDIRS"} -for d in $TESTDIRS; do - echo "******************************" - echo "Testing $d..." - echo "******************************" - cd "$BASEDIR/$d" - make clean test || exit $? - cd - > /dev/null -done +if [[ $1 == "exec" ]]; then + BASEDIR=$(realpath $(dirname $0)) + TESTDIRS="system" + for d in $TESTDIRS; do + echo "******************************" + echo "Testing $d..." + echo "******************************" + cd "$BASEDIR/$d" + make clean test || exit $? + cd - > /dev/null + done + exit 0 +else + # Script directory + REPOROOT=$(realpath $(dirname $0)/../../../../) + SCRIPT=$(realpath $0 --relative-to=$REPOROOT) + + $REPOROOT/docker/mware/do-notty-nousb /hsm2 "./$SCRIPT exec" +fi From f45141f85f5f2ad2415b8bede34a416a6687c30d Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:47:06 -0300 Subject: [PATCH 26/50] Install SGX powHSM as a systemd service (#226) --- dist/sgx/hsm/{run => start} | 7 +++- dist/sgx/hsm/stop | 4 ++ dist/sgx/scripts/hsmsgx.service | 19 +++++++++ dist/sgx/scripts/install_service | 67 ++++++++++++++++++++++++++++++++ dist/sgx/scripts/setup | 16 ++++++++ dist/sgx/setup-new-powhsm | 20 +++++++++- 6 files changed, 131 insertions(+), 2 deletions(-) rename dist/sgx/hsm/{run => start} (81%) create mode 100755 dist/sgx/hsm/stop create mode 100644 dist/sgx/scripts/hsmsgx.service create mode 100755 dist/sgx/scripts/install_service diff --git a/dist/sgx/hsm/run b/dist/sgx/hsm/start similarity index 81% rename from dist/sgx/hsm/run rename to dist/sgx/hsm/start index 44d972af..163454d0 100755 --- a/dist/sgx/hsm/run +++ b/dist/sgx/hsm/start @@ -4,6 +4,8 @@ BINDIR=$(realpath $(dirname $0)) WORKDIR=$(realpath $BINDIR/..) DOCKER_IMAGE=powhsmsgx:runner +source $BINDIR/.env + QUIET="" echo -e "\e[96mBuilding docker image $DOCKER_IMAGE (this will take a few minutes)..." if [[ "$2" != "-v" ]]; then @@ -16,10 +18,13 @@ echo DOCKER_CNT=powhsmsgx-runner DOCKER_USER="$(id -u):$(id -g)" +HOSTNAME="SGX" +NETWORK=${NETWORK:-net_sgx} PORT=7777 DOCKER_PORT="$PORT:$PORT" -docker run -ti --rm --name $DOCKER_CNT --user $DOCKER_USER -v $WORKDIR:/hsm \ +docker run --rm --name $DOCKER_CNT --user $DOCKER_USER -v $WORKDIR:/hsm \ + --hostname $HOSTNAME --network $NETWORK \ --device=/dev/sgx_enclave:/dev/sgx_enclave \ --device=/dev/sgx_provision:/dev/sgx_provision \ -w /hsm -p$DOCKER_PORT $DOCKER_IMAGE \ diff --git a/dist/sgx/hsm/stop b/dist/sgx/hsm/stop new file mode 100755 index 00000000..65d5355b --- /dev/null +++ b/dist/sgx/hsm/stop @@ -0,0 +1,4 @@ +#!/bin/bash + +DOCKER_CNT=powhsmsgx-runner +docker stop $DOCKER_CNT diff --git a/dist/sgx/scripts/hsmsgx.service b/dist/sgx/scripts/hsmsgx.service new file mode 100644 index 00000000..18c7f7e9 --- /dev/null +++ b/dist/sgx/scripts/hsmsgx.service @@ -0,0 +1,19 @@ +[Unit] +Description=SGX powHSM +Wants=network.target +After=syslog.target network-online.target docker.service +Requires=docker.service + +[Service] +Type=simple +WorkingDirectory=$HSM_INSTALL_DIR +User=hsm +Group=hsm +ExecStart=$HSM_INSTALL_DIR/bin/start +ExecStop=$HSM_INSTALL_DIR/bin/stop +Restart=on-failure +RestartSec=10 +KillMode=mixed + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/dist/sgx/scripts/install_service b/dist/sgx/scripts/install_service new file mode 100755 index 00000000..47bfb7db --- /dev/null +++ b/dist/sgx/scripts/install_service @@ -0,0 +1,67 @@ +#!/bin/bash + +# Require superuser +if ! [ "$(id -u)" == "0" ]; then + echo -e "\e[1;31mPlease run with sudo.\e[0m" + exit 1 +fi + +if [ -z "$1" ]; then + echo -e "\e[1;31mUsage: $0 \e[0m" + exit 1 +fi + +SERVICE_UNIT=$(realpath $1) +if [ ! -f "$SERVICE_UNIT" ]; then + echo "\e[1;31mService file not found: $SERVICE_UNIT\e[0m" + exit 1 +fi + +# Extract the installation directory from the service file +INSTALL_DIR=$(grep -oP 'WorkingDirectory=\K.*' $SERVICE_UNIT) +if [ -z "$INSTALL_DIR" ]; then + echo -e "\e[1;31mCould not extract installation directory from service file.\e[0m" + exit 1 +fi + +echo -e "\e[1;32mCreating hsm user and group...\e[0m" +if ! id -u hsm >/dev/null 2>&1; then + useradd -rm -s /bin/bash hsm || exit $? + usermod -aG docker hsm || exit $? +else + echo -e "\e[1;33mUser 'hsm' already exists. Skipping user creation.\e[0m" +fi + +DEFAULT_NETWORK="net_sgx" +while true; do + echo -e "\e[1;32mEnter the name of the docker network to be created: [$DEFAULT_NETWORK]\e[0m" + read -p "> " NETWORK + if [ -z "$NETWORK" ]; then + NETWORK=$DEFAULT_NETWORK + fi + echo -e "\e[1;33mThe docker network will be named '$NETWORK'. Proceed? [Y/n]\e[0m" + read -p "> " proceed + if [[ "Y" == "$proceed" ]] || [[ "y" == "$proceed" ]] || [ -z "$proceed" ]; then + break + fi +done + +echo -e "\e[1;32mCreating $NETWORK network...\e[0m" +docker network rm $NETWORK 2> /dev/null +docker network create $NETWORK &> /dev/null +echo "NETWORK=$NETWORK" >> $INSTALL_DIR/.env || exit $? + +echo -e "\e[1;32mSetting permisions...\e[0m" +chown -R root:hsm $INSTALL_DIR || exit $? +chmod 664 $INSTALL_DIR/*.dat $INSTALL_DIR/.env || exit $? + +echo -e "\e[1;32mCreating service...\e[0m" +cp $SERVICE_UNIT /etc/systemd/system/hsmsgx.service +systemctl daemon-reload || exit $? +echo -e "\e[1;32mEnabling service...\e[0m" +systemctl enable hsmsgx.service || exit $? +echo -e "\e[1;32mEStarting service...\e[0m" +systemctl start hsmsgx.service || exit $? +echo -e "\e[1;32mService started.\e[0m" +echo -e "\e[1;32mTo check the status of the service, run 'systemctl status hsmsgx.service'.\e[0m" +exit 0 diff --git a/dist/sgx/scripts/setup b/dist/sgx/scripts/setup index b118e26f..2170614d 100755 --- a/dist/sgx/scripts/setup +++ b/dist/sgx/scripts/setup @@ -35,6 +35,12 @@ EXPORT_DIR="$ROOT_DIR/export" PUBLIC_KEY_FILE="$EXPORT_DIR/public-keys.txt" PUBLIC_KEY_FILE_JSON="$EXPORT_DIR/public-keys.json" +# HSM scripts directory +SCRIPTS_DIR=$ROOT_DIR/scripts + +# Directory where the finalized systemd service unit will be saved +SERVICE_DIR=$ROOT_DIR/service + function checkHsmBinaries() { # Check for HSM binary files FILES="$HSMBIN_DIR/hsmsgx $HSMBIN_DIR/hsmsgx_enclave.signed" @@ -96,6 +102,15 @@ function selectInstallationDir() { done } +function createServiceUnit() { + rm -rf $SERVICE_DIR + mkdir $SERVICE_DIR + + cp $SCRIPTS_DIR/hsmsgx.service $SERVICE_DIR + # Replace the $HSM_INSTALL_DIR token in the script with the actual installation directory + sed -i "s|\$HSM_INSTALL_DIR|$INSTALL_DIR|g" $SERVICE_DIR/hsmsgx.service +} + function installPowHsm() { mkdir $REAL_INSTALL_DIR/bin cp -R $HSMBIN_DIR/* $REAL_INSTALL_DIR/bin @@ -134,6 +149,7 @@ checkForPinFile checkHsmBinaries expandBinaries selectInstallationDir +createServiceUnit echo echo -e "\e[1;32mInstalling the powHSM...\e[0m" installPowHsm diff --git a/dist/sgx/setup-new-powhsm b/dist/sgx/setup-new-powhsm index 1398782a..67dd81ba 100755 --- a/dist/sgx/setup-new-powhsm +++ b/dist/sgx/setup-new-powhsm @@ -1,3 +1,21 @@ #!/bin/bash -$(dirname $0)/scripts/run_with_docker ./scripts/setup $1 +# Require superuser, since we need to install a service in the host +if ! [ "$(id -u)" == "0" ]; then + echo -e "\e[1;32mPlease run with sudo.\e[0m" + exit 1 +fi + +ROOT_DIR=$(realpath $(dirname $0)) +$ROOT_DIR/scripts/run_with_docker ./scripts/setup $1 +if [ $? -ne 0 ]; then + echo -e "\e[1;31m Error during the powhsm setup, aborting \e[0m" + exit 1 +fi + +$ROOT_DIR/scripts/install_service $ROOT_DIR/service/hsmsgx.service +if [ $? -ne 0 ]; then + echo -e "\e[1;31m Error during the powhsm service installation, aborting \e[0m" + exit 1 +fi +echo -e "\e[1;32mHSM SGX setup done.\e[0m" From 5de65aab2bbc00ad22d88e3d1a4fb9cba6ba80d1 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 4 Dec 2024 06:34:35 +1300 Subject: [PATCH 27/50] Version 5.3.2 ALPHA release (#227) - Bumped version to 5.3.2 - Updated version references in firmware, middleware and unit tests - Updated CHANGELOG --- CHANGELOG.md | 10 ++++++++++ firmware/src/ledger/ui/src/defs.h | 2 +- firmware/src/ledger/ui/test/onboard/test_onboard.c | 4 ++-- firmware/src/powhsm/src/defs.h | 2 +- middleware/ledger/protocol.py | 4 ++-- middleware/tests/ledger/test_protocol.py | 2 +- middleware/tests/ledger/test_protocol_v1.py | 2 +- 7 files changed, 18 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32e2bdcc..a74724b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [5.3.2 ALPHA] - 04/12/2024 + +### Features/enhancements + +- SGX distribution: installing powHSM as a system service + +### Fixes + +- Fixed code coverage report + ## [5.3.1 ALPHA] - 14/11/2024 ### Fixes diff --git a/firmware/src/ledger/ui/src/defs.h b/firmware/src/ledger/ui/src/defs.h index b4577ec9..9f7ab309 100644 --- a/firmware/src/ledger/ui/src/defs.h +++ b/firmware/src/ledger/ui/src/defs.h @@ -31,6 +31,6 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 #define VERSION_MINOR 0x03 -#define VERSION_PATCH 0x01 +#define VERSION_PATCH 0x02 #endif // __DEFS_H diff --git a/firmware/src/ledger/ui/test/onboard/test_onboard.c b/firmware/src/ledger/ui/test/onboard/test_onboard.c index 933e13b2..bcc8e555 100644 --- a/firmware/src/ledger/ui/test/onboard/test_onboard.c +++ b/firmware/src/ledger/ui/test/onboard/test_onboard.c @@ -313,11 +313,11 @@ void test_is_onboarded() { G_device_onboarded = true; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x01\x05\x03\x01"); + ASSERT_APDU("\x80\x01\x05\x03\x02"); G_device_onboarded = false; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x00\x05\x03\x01"); + ASSERT_APDU("\x80\x00\x05\x03\x02"); } int main() { diff --git a/firmware/src/powhsm/src/defs.h b/firmware/src/powhsm/src/defs.h index ac150a22..9465f26a 100644 --- a/firmware/src/powhsm/src/defs.h +++ b/firmware/src/powhsm/src/defs.h @@ -30,6 +30,6 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 #define VERSION_MINOR 0x03 -#define VERSION_PATCH 0x01 +#define VERSION_PATCH 0x02 #endif // __DEFS_H diff --git a/middleware/ledger/protocol.py b/middleware/ledger/protocol.py index 3b683345..4141cda5 100644 --- a/middleware/ledger/protocol.py +++ b/middleware/ledger/protocol.py @@ -38,8 +38,8 @@ class HSM2ProtocolLedger(HSM2Protocol): # Current manager supported versions for HSM UI and HSM SIGNER (<=) - UI_VERSION = HSM2FirmwareVersion(5, 3, 1) - APP_VERSION = HSM2FirmwareVersion(5, 3, 1) + UI_VERSION = HSM2FirmwareVersion(5, 3, 2) + APP_VERSION = HSM2FirmwareVersion(5, 3, 2) # Amount of time to wait to make sure the app is opened OPEN_APP_WAIT = 1 # second diff --git a/middleware/tests/ledger/test_protocol.py b/middleware/tests/ledger/test_protocol.py index 25a076e2..08079d58 100644 --- a/middleware/tests/ledger/test_protocol.py +++ b/middleware/tests/ledger/test_protocol.py @@ -49,7 +49,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 1)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 2)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM2ProtocolLedger(self.pin, self.dongle) diff --git a/middleware/tests/ledger/test_protocol_v1.py b/middleware/tests/ledger/test_protocol_v1.py index 91978469..b0a4d0d1 100644 --- a/middleware/tests/ledger/test_protocol_v1.py +++ b/middleware/tests/ledger/test_protocol_v1.py @@ -47,7 +47,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 1)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 2)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM1ProtocolLedger(self.pin, self.dongle) From 0663ff7c132200fddf7065270d1597daf50a97dd Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Sat, 7 Dec 2024 02:42:04 +1300 Subject: [PATCH 28/50] SGX attestation gathering (#228) - Unified certificates in certificate module - Moved existing HSMCertificate and HSMCertificateElement to certificate_v1 - Added new HSMCertificateV2 and HSMCertificateV2Element (and subclasses) - Added new attestation gathering operation for adm_sgx - Added new attestation gathering module used within adm_sgx - Factored out user-defined value gathering into admin/misc module - Current SGX attestation saving to file is directly translated from value grabbed with HSM2Dongle - Added and updated unit tests --- middleware/adm_ledger.py | 4 +- middleware/adm_sgx.py | 15 +- middleware/admin/certificate.py | 230 +--------------- middleware/admin/certificate_v1.py | 251 ++++++++++++++++++ middleware/admin/certificate_v2.py | 49 ++++ middleware/admin/ledger_attestation.py | 28 +- middleware/admin/misc.py | 28 ++ middleware/admin/sgx_attestation.py | 71 +++++ middleware/tests/admin/test_adm_sgx.py | 40 ++- ..._certificate.py => test_certificate_v1.py} | 4 +- ...ment.py => test_certificate_v1_element.py} | 2 +- .../tests/admin/test_ledger_attestation.py | 81 +----- middleware/tests/admin/test_misc.py | 63 +++++ .../tests/admin/test_sgx_attestation.py | 113 ++++++++ setup.cfg | 4 +- 15 files changed, 654 insertions(+), 329 deletions(-) create mode 100644 middleware/admin/certificate_v1.py create mode 100644 middleware/admin/certificate_v2.py create mode 100644 middleware/admin/sgx_attestation.py rename middleware/tests/admin/{test_certificate.py => test_certificate_v1.py} (99%) rename middleware/tests/admin/{test_certificate_element.py => test_certificate_v1_element.py} (99%) create mode 100644 middleware/tests/admin/test_misc.py create mode 100644 middleware/tests/admin/test_sgx_attestation.py diff --git a/middleware/adm_ledger.py b/middleware/adm_ledger.py index 758060e6..6ba72dce 100644 --- a/middleware/adm_ledger.py +++ b/middleware/adm_ledger.py @@ -25,7 +25,7 @@ import logging from ledger.hsm2dongle import HSM2DongleError from comm.platform import Platform -from admin.misc import not_implemented, info, AdminError +from admin.misc import not_implemented, info, AdminError, DEFAULT_ATT_UD_SOURCE from admin.unlock import do_unlock from admin.onboard import do_onboard from admin.pubkeys import do_get_pubkeys @@ -34,8 +34,6 @@ from admin.verify_ledger_attestation import do_verify_attestation from admin.authorize_signer import do_authorize_signer -DEFAULT_ATT_UD_SOURCE = "https://public-node.rsk.co" - def main(): logging.disable(logging.CRITICAL) diff --git a/middleware/adm_sgx.py b/middleware/adm_sgx.py index 6a4dcf0c..d6a8f289 100644 --- a/middleware/adm_sgx.py +++ b/middleware/adm_sgx.py @@ -25,11 +25,12 @@ import logging from ledger.hsm2dongle import HSM2DongleError from comm.platform import Platform -from admin.misc import not_implemented, info, AdminError +from admin.misc import not_implemented, info, AdminError, DEFAULT_ATT_UD_SOURCE from admin.unlock import do_unlock from admin.onboard import do_onboard from admin.pubkeys import do_get_pubkeys from admin.changepin import do_changepin +from admin.sgx_attestation import do_attestation def main(): @@ -40,6 +41,7 @@ def main(): "onboard": do_onboard, "pubkeys": do_get_pubkeys, "changepin": do_changepin, + "attestation": do_attestation, } parser = ArgumentParser(description="SGX powHSM Administrative tool") @@ -79,7 +81,7 @@ def main(): "-o", "--output", dest="output_file_path", - help="Output file (only valid for 'onboard' and 'pubkeys' " + help="Output file (only valid for 'onboard', 'pubkeys' and 'attestation' " "operations).", ) parser.add_argument( @@ -92,6 +94,15 @@ def main(): default=False, const=True, ) + parser.add_argument( + "--attudsource", + dest="attestation_ud_source", + default=DEFAULT_ATT_UD_SOURCE, + help="JSON-RPC endpoint used to retrieve the latest RSK block hash used " + "as the user defined value for the attestation (defaults to " + f"{DEFAULT_ATT_UD_SOURCE}). Can also specify a 32-byte hex string to use as" + " the value.", + ) parser.add_argument( "-v", "--verbose", diff --git a/middleware/admin/certificate.py b/middleware/admin/certificate.py index 29ce300a..64b3bb6b 100644 --- a/middleware/admin/certificate.py +++ b/middleware/admin/certificate.py @@ -20,231 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import json -import hmac -import secp256k1 as ec -import hashlib -from .utils import is_nonempty_hex_string - - -class HSMCertificate: - VERSION = 1 # Only supported version - ROOT_ELEMENT = "root" - - @staticmethod - def from_jsonfile(path): - try: - with open(path, "r") as file: - certificate_map = json.loads(file.read()) - - if type(certificate_map) != dict: - raise ValueError( - "JSON file must contain an object as a top level element") - - return HSMCertificate(certificate_map) - except (ValueError, json.JSONDecodeError) as e: - raise ValueError('Unable to read HSM certificate from "%s": %s' % - (path, str(e))) - - def __init__(self, certificate_map=None): - self._targets = [] - self._elements = {} - - if certificate_map is not None: - self._parse(certificate_map) - - def validate_and_get_values(self, raw_root_pubkey_hex): - # Parse the root public key - try: - root_pubkey = ec.PublicKey(bytes.fromhex(raw_root_pubkey_hex), raw=True) - except Exception: - return dict([(target, (False, self.ROOT_ELEMENT)) - for target in self._targets]) - - result = {} - for target in self._targets: - # Build the chain from the target to the root - chain = [] - current = self._elements[target] - while True: - if current.signed_by == self.ROOT_ELEMENT: - break - chain.append(current) - current = self._elements[current.signed_by] - - # Validate the chain from root to leaf - # If valid, return True and the value of the leaf - # If not valid, return False and the name of the element that - # failed the validation - current_pubkey = root_pubkey - while True: - # Validate this element - if not current.is_valid(current_pubkey): - result[target] = (False, current.name) - break - # Reached the leaf? => valid! - if len(chain) == 0: - result[target] = (True, current.get_value(), current.tweak) - break - - current_pubkey = ec.PublicKey(bytes.fromhex(current.get_value()), - raw=True) - current = chain.pop() - - return result - - def add_element(self, element): - if type(element) != HSMCertificateElement: - raise ValueError( - f"Expected an HSMCertificateElement but got a {type(element)}") - self._elements[element.name] = element - - def clear_targets(self): - self._targets = [] - - def add_target(self, target): - if target not in self._elements: - raise ValueError(f"Target {target} not in elements") - self._targets.append(target) - - def to_dict(self): - return { - "version": self.VERSION, - "targets": self._targets, - "elements": list(map(lambda e: e.to_dict(), self._elements.values())), - } - - def save_to_jsonfile(self, path): - with open(path, "w") as file: - file.write("%s\n" % json.dumps(self.to_dict(), indent=2)) - - def _parse(self, certificate_map): - if "version" not in certificate_map or certificate_map["version"] != self.VERSION: - raise ValueError( - "Invalid or unsupported HSM certificate version " - f"(current version is {self.VERSION})" - ) - - if "targets" not in certificate_map or type(certificate_map["targets"]) != list: - raise ValueError("Missing or invalid targets") - - self._targets = certificate_map["targets"] - - if "elements" not in certificate_map: - raise ValueError("Missing elements") - - for item in certificate_map["elements"]: - element = HSMCertificateElement(item) - self._elements[item["name"]] = element - - # Sanity: check each target has a path to the root authority - for target in self._targets: - if target not in self._elements: - raise ValueError(f"Target {target} not in elements") - - visited = [] - current = self._elements[target] - while True: - if current.name in visited: - raise ValueError( - f"Target {target} has not got a path to the root authority") - if current.signed_by == self.ROOT_ELEMENT: - break - if current.signed_by not in self._elements: - raise ValueError(f"Signer {current.signed_by} not in elements") - visited.append(current.name) - current = self._elements[current.signed_by] - - -class HSMCertificateElement: - VALID_NAMES = ["device", "attestation", "ui", "signer"] - EXTRACTORS = { - "device": lambda b: b[-65:], - "attestation": lambda b: b[1:], - "ui": lambda b: b[:], - "signer": lambda b: b[:], - } - - def __init__(self, element_map): - if ("name" not in element_map - or element_map["name"] not in self.VALID_NAMES): - raise ValueError("Missing or invalid name for HSM certificate element") - self._name = element_map["name"] - - if "signed_by" not in element_map: - raise ValueError("Missing certifier for HSM certificate element") - self._signed_by = element_map["signed_by"] - - self._tweak = None - if "tweak" in element_map: - if not is_nonempty_hex_string(element_map["tweak"]): - raise ValueError( - f"Invalid signer tweak for HSM certificate element {self.name}") - self._tweak = element_map["tweak"] - - if "message" not in element_map or not is_nonempty_hex_string( - element_map["message"]): - raise ValueError( - f"Missing or invalid message for HSM certificate element {self.name}") - self._message = element_map["message"] - - if "signature" not in element_map or not is_nonempty_hex_string( - element_map["signature"]): - raise ValueError( - f"Missing or invalid signature for HSM certificate element {self.name}") - self._signature = element_map["signature"] - - @property - def name(self): - return self._name - - @property - def signed_by(self): - return self._signed_by - - @property - def tweak(self): - return self._tweak - - @property - def message(self): - return self._message - - @property - def signature(self): - return self._signature - - def to_dict(self): - result = { - "name": self.name, - "message": self.message, - "signature": self.signature, - "signed_by": self.signed_by, - } - - if self.tweak is not None: - result["tweak"] = self.tweak - - return result - - def is_valid(self, certifier_pubkey): - try: - message = bytes.fromhex(self.message) - - verifier_pubkey = certifier_pubkey - if self.tweak is not None: - tweak = hmac.new( - bytes.fromhex(self.tweak), - certifier_pubkey.serialize(compressed=False), - hashlib.sha256, - ).digest() - - verifier_pubkey = verifier_pubkey.tweak_add(tweak) - - return verifier_pubkey.ecdsa_verify( - message, verifier_pubkey.ecdsa_deserialize(bytes.fromhex(self.signature))) - except Exception: - return False - - def get_value(self): - return self.EXTRACTORS[self.name](bytes.fromhex(self.message)).hex() +from .certificate_v1 import HSMCertificate, HSMCertificateElement +from .certificate_v2 import HSMCertificateV2, HSMCertificateV2Element diff --git a/middleware/admin/certificate_v1.py b/middleware/admin/certificate_v1.py new file mode 100644 index 00000000..a37802ed --- /dev/null +++ b/middleware/admin/certificate_v1.py @@ -0,0 +1,251 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import json +import hmac +import secp256k1 as ec +import hashlib +from .utils import is_nonempty_hex_string + + +class HSMCertificateElement: + VALID_NAMES = ["device", "attestation", "ui", "signer"] + EXTRACTORS = { + "device": lambda b: b[-65:], + "attestation": lambda b: b[1:], + "ui": lambda b: b[:], + "signer": lambda b: b[:], + } + + def __init__(self, element_map): + if ("name" not in element_map + or element_map["name"] not in self.VALID_NAMES): + raise ValueError("Missing or invalid name for HSM certificate element") + self._name = element_map["name"] + + if "signed_by" not in element_map: + raise ValueError("Missing certifier for HSM certificate element") + self._signed_by = element_map["signed_by"] + + self._tweak = None + if "tweak" in element_map: + if not is_nonempty_hex_string(element_map["tweak"]): + raise ValueError( + f"Invalid signer tweak for HSM certificate element {self.name}") + self._tweak = element_map["tweak"] + + if "message" not in element_map or not is_nonempty_hex_string( + element_map["message"]): + raise ValueError( + f"Missing or invalid message for HSM certificate element {self.name}") + self._message = element_map["message"] + + if "signature" not in element_map or not is_nonempty_hex_string( + element_map["signature"]): + raise ValueError( + f"Missing or invalid signature for HSM certificate element {self.name}") + self._signature = element_map["signature"] + + @property + def name(self): + return self._name + + @property + def signed_by(self): + return self._signed_by + + @property + def tweak(self): + return self._tweak + + @property + def message(self): + return self._message + + @property + def signature(self): + return self._signature + + def to_dict(self): + result = { + "name": self.name, + "message": self.message, + "signature": self.signature, + "signed_by": self.signed_by, + } + + if self.tweak is not None: + result["tweak"] = self.tweak + + return result + + def is_valid(self, certifier_pubkey): + try: + message = bytes.fromhex(self.message) + + verifier_pubkey = certifier_pubkey + if self.tweak is not None: + tweak = hmac.new( + bytes.fromhex(self.tweak), + certifier_pubkey.serialize(compressed=False), + hashlib.sha256, + ).digest() + + verifier_pubkey = verifier_pubkey.tweak_add(tweak) + + return verifier_pubkey.ecdsa_verify( + message, verifier_pubkey.ecdsa_deserialize(bytes.fromhex(self.signature))) + except Exception: + return False + + def get_value(self): + return self.EXTRACTORS[self.name](bytes.fromhex(self.message)).hex() + + +class HSMCertificate: + VERSION = 1 # Only supported version + ROOT_ELEMENT = "root" + ELEMENT_BASE_CLASS = HSMCertificateElement + + @staticmethod + def from_jsonfile(path): + try: + with open(path, "r") as file: + certificate_map = json.loads(file.read()) + + if type(certificate_map) != dict: + raise ValueError( + "JSON file must contain an object as a top level element") + + return HSMCertificate(certificate_map) + except (ValueError, json.JSONDecodeError) as e: + raise ValueError('Unable to read HSM certificate from "%s": %s' % + (path, str(e))) + + def __init__(self, certificate_map=None): + self._targets = [] + self._elements = {} + + if certificate_map is not None: + self._parse(certificate_map) + + def validate_and_get_values(self, raw_root_pubkey_hex): + # Parse the root public key + try: + root_pubkey = ec.PublicKey(bytes.fromhex(raw_root_pubkey_hex), raw=True) + except Exception: + return dict([(target, (False, self.ROOT_ELEMENT)) + for target in self._targets]) + + result = {} + for target in self._targets: + # Build the chain from the target to the root + chain = [] + current = self._elements[target] + while True: + if current.signed_by == self.ROOT_ELEMENT: + break + chain.append(current) + current = self._elements[current.signed_by] + + # Validate the chain from root to leaf + # If valid, return True and the value of the leaf + # If not valid, return False and the name of the element that + # failed the validation + current_pubkey = root_pubkey + while True: + # Validate this element + if not current.is_valid(current_pubkey): + result[target] = (False, current.name) + break + # Reached the leaf? => valid! + if len(chain) == 0: + result[target] = (True, current.get_value(), current.tweak) + break + + current_pubkey = ec.PublicKey(bytes.fromhex(current.get_value()), + raw=True) + current = chain.pop() + + return result + + def add_element(self, element): + if not isinstance(element, self.ELEMENT_BASE_CLASS): + raise ValueError( + f"Expected an HSMCertificateElement but got a {type(element)}") + self._elements[element.name] = element + + def clear_targets(self): + self._targets = [] + + def add_target(self, target): + if target not in self._elements: + raise ValueError(f"Target {target} not in elements") + self._targets.append(target) + + def to_dict(self): + return { + "version": self.VERSION, + "targets": self._targets, + "elements": list(map(lambda e: e.to_dict(), self._elements.values())), + } + + def save_to_jsonfile(self, path): + with open(path, "w") as file: + file.write("%s\n" % json.dumps(self.to_dict(), indent=2)) + + def _parse(self, certificate_map): + if "version" not in certificate_map or certificate_map["version"] != self.VERSION: + raise ValueError( + "Invalid or unsupported HSM certificate version " + f"(current version is {self.VERSION})" + ) + + if "targets" not in certificate_map or type(certificate_map["targets"]) != list: + raise ValueError("Missing or invalid targets") + + self._targets = certificate_map["targets"] + + if "elements" not in certificate_map: + raise ValueError("Missing elements") + + for item in certificate_map["elements"]: + element = HSMCertificateElement(item) + self._elements[item["name"]] = element + + # Sanity: check each target has a path to the root authority + for target in self._targets: + if target not in self._elements: + raise ValueError(f"Target {target} not in elements") + + visited = [] + current = self._elements[target] + while True: + if current.name in visited: + raise ValueError( + f"Target {target} has not got a path to the root authority") + if current.signed_by == self.ROOT_ELEMENT: + break + if current.signed_by not in self._elements: + raise ValueError(f"Signer {current.signed_by} not in elements") + visited.append(current.name) + current = self._elements[current.signed_by] diff --git a/middleware/admin/certificate_v2.py b/middleware/admin/certificate_v2.py new file mode 100644 index 00000000..61e74ce5 --- /dev/null +++ b/middleware/admin/certificate_v2.py @@ -0,0 +1,49 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from .certificate_v1 import HSMCertificate + + +class HSMCertificateV2Element: + # TODO: actual logic and subclasses + def __init__(self, element_map): + self.element_map = element_map + + # Stub + def name(self): + return "attestation" + + def to_dict(self): + return self.element_map + + +class HSMCertificateV2(HSMCertificate): + VERSION = 2 + ELEMENT_BASE_CLASS = HSMCertificateV2Element + + def validate_and_get_values(self, raw_root_pubkey_hex): + # TODO + pass + + def _parse(self, certificate_map): + # TODO + pass diff --git a/middleware/admin/ledger_attestation.py b/middleware/admin/ledger_attestation.py index a10fa2e0..9242d08e 100644 --- a/middleware/admin/ledger_attestation.py +++ b/middleware/admin/ledger_attestation.py @@ -20,13 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from .misc import info, head, get_hsm, dispose_hsm, AdminError, wait_for_reconnection -from .utils import is_hex_string_of_length, normalize_hex_string +from .misc import info, head, get_hsm, dispose_hsm, AdminError, wait_for_reconnection, \ + get_ud_value_for_attestation from .unlock import do_unlock from .certificate import HSMCertificate, HSMCertificateElement -from .rsk_client import RskClient, RskClientError - -UD_VALUE_LENGTH = 32 def do_attestation(options): @@ -46,24 +43,9 @@ def do_attestation(options): except Exception as e: raise AdminError(f"While loading the attestation certificate file: {str(e)}") - # Get the UD value for the UI attestation - info("Gathering user-defined UI attestation value... ", options.verbose) - - if is_hex_string_of_length(options.attestation_ud_source, - UD_VALUE_LENGTH, - allow_prefix=True): - ud_value = normalize_hex_string(options.attestation_ud_source) - else: - try: - rsk_client = RskClient(options.attestation_ud_source) - best_block = rsk_client.get_block_by_number( - rsk_client.get_best_block_number()) - ud_value = best_block["hash"][2:] - if not is_hex_string_of_length(ud_value, UD_VALUE_LENGTH): - raise ValueError(f"Got invalid best block from RSK server: {ud_value}") - except RskClientError as e: - raise AdminError(f"While fetching the best RSK block hash: {str(e)}") - + # Get the UD value for the attestations + info("Gathering user-defined attestation value... ", options.verbose) + ud_value = get_ud_value_for_attestation(options.attestation_ud_source) info(f"Using {ud_value} as the user-defined attestation value") # Attempt to unlock the device without exiting the UI diff --git a/middleware/admin/misc.py b/middleware/admin/misc.py index c8dcd59b..e72e46f7 100644 --- a/middleware/admin/misc.py +++ b/middleware/admin/misc.py @@ -29,6 +29,9 @@ from .dongle_admin import DongleAdmin from .dongle_eth import DongleEth from comm.platform import Platform +from .utils import is_hex_string_of_length, normalize_hex_string +from .rsk_client import RskClient, RskClientError + PIN_ERROR_MESSAGE = ("Invalid pin given. It must be exactly 8 alphanumeric " "characters with at least one alphabetic character.") @@ -37,6 +40,9 @@ SIGNER_WAIT_TIME = 3 # seconds +ATTESTATION_UD_VALUE_LENGTH = 32 # bytes +DEFAULT_ATT_UD_SOURCE = "https://public-node.rsk.co" + class AdminError(RuntimeError): pass @@ -127,3 +133,25 @@ def ask_for_pin(any_pin): def wait_for_reconnection(): time.sleep(SIGNER_WAIT_TIME) + + +def get_ud_value_for_attestation(user_provided_ud_source): + if is_hex_string_of_length(user_provided_ud_source, + ATTESTATION_UD_VALUE_LENGTH, + allow_prefix=True): + # Final value provided by user + ud_value = normalize_hex_string(user_provided_ud_source) + else: + # Final value taken from a specific Rootstock node + try: + rsk_client = RskClient(user_provided_ud_source) + best_block = rsk_client.get_block_by_number( + rsk_client.get_best_block_number()) + ud_value = best_block["hash"][2:] + if not is_hex_string_of_length(ud_value, ATTESTATION_UD_VALUE_LENGTH): + raise ValueError("Got invalid best block from " + f"Rootstock server: {ud_value}") + except RskClientError as e: + raise AdminError(f"While fetching the best Rootstock block hash: {str(e)}") + + return ud_value diff --git a/middleware/admin/sgx_attestation.py b/middleware/admin/sgx_attestation.py new file mode 100644 index 00000000..c261f0ba --- /dev/null +++ b/middleware/admin/sgx_attestation.py @@ -0,0 +1,71 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from .misc import info, head, get_hsm, AdminError, get_ud_value_for_attestation +from .unlock import do_unlock +from .certificate import HSMCertificateV2, HSMCertificateV2Element + + +def do_attestation(options): + head("### -> Get powHSM attestation", fill="#") + hsm = None + + # Require an output file + if options.output_file_path is None: + raise AdminError("No output file path given") + + # Get the UD value for the attestation + info("Gathering user-defined attestation value... ", options.verbose) + ud_value = get_ud_value_for_attestation(options.attestation_ud_source) + info(f"Using {ud_value} as the user-defined attestation value") + + # Attempt to unlock the device + if not options.no_unlock: + try: + do_unlock(options, label=False) + except Exception as e: + raise AdminError(f"Failed to unlock device: {str(e)}") + + # Connection + hsm = get_hsm(options.verbose) + + # powHSM attestation + info("Gathering powHSM attestation... ", options.verbose) + try: + powhsm_attestation = hsm.get_powhsm_attestation(ud_value) + except Exception as e: + raise AdminError(f"Failed to gather powHSM attestation: {str(e)}") + info("powHSM attestation gathered") + + hsm.disconnect() + + # Generate and save the attestation certificate + info("Generating the attestation certificate... ", options.verbose) + + att_cert = HSMCertificateV2() + # TODO: + # 1. Parse envelope + # 2. Add actual elements of the certificate + att_cert.add_element(HSMCertificateV2Element(powhsm_attestation)) + att_cert.save_to_jsonfile(options.output_file_path) + + info(f"Attestation certificate saved to {options.output_file_path}") diff --git a/middleware/tests/admin/test_adm_sgx.py b/middleware/tests/admin/test_adm_sgx.py index d5a5f5cb..53c139cd 100644 --- a/middleware/tests/admin/test_adm_sgx.py +++ b/middleware/tests/admin/test_adm_sgx.py @@ -30,7 +30,7 @@ logging.disable(logging.CRITICAL) -class TestAdmLedger(TestCase): +class TestAdmSgx(TestCase): def setUp(self): self.old_stdout = sys.stdout self.DEFAULT_OPTIONS = { @@ -39,6 +39,7 @@ def setUp(self): "any_pin": False, "new_pin": None, "no_unlock": False, + "attestation_ud_source": "https://public-node.rsk.co", "operation": None, "output_file_path": None, "pin": None, @@ -169,3 +170,40 @@ def test_changepin(self, do_changepin): self.assertTrue(do_changepin.called) self.assertEqual(do_changepin.call_count, 2) self.assertEqual(expected_call_args_list, do_changepin.call_args_list) + + @patch("adm_sgx.do_attestation") + def test_attestation(self, do_attestation): + expected_options = { + **self.DEFAULT_OPTIONS, + 'attestation_ud_source': 'user-defined-source', + 'operation': 'attestation', + 'output_file_path': 'out-path', + 'pin': 'a-pin', + } + expected_call_args_list = [ + call(Namespace(**expected_options)), + call(Namespace(**{**expected_options, "no_unlock": True})) + ] + + with patch('sys.argv', ['adm_sgx.py', + '-p', 'a-pin', + '-o', 'out-path', + '--attudsource', 'user-defined-source', + 'attestation']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + with patch('sys.argv', ['adm_sgx.py', + '--pin', 'a-pin', + '--output', 'out-path', + '--attudsource', 'user-defined-source', + '--nounlock', + 'attestation']): + with self.assertRaises(SystemExit) as e: + main() + self.assertEqual(e.exception.code, 0) + + self.assertTrue(do_attestation.called) + self.assertEqual(do_attestation.call_count, 2) + self.assertEqual(expected_call_args_list, do_attestation.call_args_list) diff --git a/middleware/tests/admin/test_certificate.py b/middleware/tests/admin/test_certificate_v1.py similarity index 99% rename from middleware/tests/admin/test_certificate.py rename to middleware/tests/admin/test_certificate_v1.py index 856e414e..591cfc91 100644 --- a/middleware/tests/admin/test_certificate.py +++ b/middleware/tests/admin/test_certificate_v1.py @@ -29,7 +29,7 @@ from admin.certificate import HSMCertificate, HSMCertificateElement -class TestCertificate(TestCase): +class TestHSMCertificate(TestCase): def test_create_valid_certificate_ok(self): cert = HSMCertificate({ "version": 1, @@ -155,7 +155,7 @@ def test_create_certificate_missing_elements(self): "targets": ["attestation", "device"] }) - @patch('admin.certificate.HSMCertificateElement') + @patch('admin.certificate_v1.HSMCertificateElement') def test_create_certificate_invalid_element(self, certElementMock): certElementMock.side_effect = ValueError() with self.assertRaises(ValueError): diff --git a/middleware/tests/admin/test_certificate_element.py b/middleware/tests/admin/test_certificate_v1_element.py similarity index 99% rename from middleware/tests/admin/test_certificate_element.py rename to middleware/tests/admin/test_certificate_v1_element.py index 74087f1d..ff2f206c 100644 --- a/middleware/tests/admin/test_certificate_element.py +++ b/middleware/tests/admin/test_certificate_v1_element.py @@ -30,7 +30,7 @@ from admin.certificate import HSMCertificateElement -class TestCertificateElement(TestCase): +class TestHSMCertificateElement(TestCase): def test_create_certificate_element_ok(self): element = HSMCertificateElement({ "name": "device", diff --git a/middleware/tests/admin/test_ledger_attestation.py b/middleware/tests/admin/test_ledger_attestation.py index 935b1cc2..27ab2672 100644 --- a/middleware/tests/admin/test_ledger_attestation.py +++ b/middleware/tests/admin/test_ledger_attestation.py @@ -28,7 +28,6 @@ from admin.ledger_attestation import do_attestation from admin.certificate import HSMCertificate from admin.misc import AdminError -from admin.rsk_client import RskClientError @patch("sys.stdout.write") @@ -79,68 +78,11 @@ def setupDefaultOptions(self): options.attestation_ud_source = 'aa' * 32 return options - @patch('admin.ledger_attestation.RskClient') - def test_attestation_ok_provided_ud_value(self, - RskClient, - from_jsonfile, - get_hsm, - *_): + @patch('admin.ledger_attestation.get_ud_value_for_attestation') + def test_attestation_ok(self, get_ud_value_for_attestation, + from_jsonfile, get_hsm, *_): self.setupMocks(from_jsonfile, get_hsm) - options = self.setupDefaultOptions() - with patch('builtins.open', mock_open()) as file_mock: - do_attestation(options) - - self.assertEqual([call(options.attestation_ud_source)], - get_hsm.return_value.get_ui_attestation.call_args_list) - self.assertEqual([], RskClient.call_args_list) - self.assertEqual([call(options.attestation_certificate_file_path)], - from_jsonfile.call_args_list) - self.assertEqual([call(options.verbose), call(options.verbose)], - get_hsm.call_args_list) - self.assertEqual([call(options.output_file_path, 'w')], file_mock.call_args_list) - self.assertEqual([call("%s\n" % json.dumps({ - 'version': 1, - 'targets': [ - 'ui', - 'signer' - ], - 'elements': [ - { - "name": "attestation", - "message": '11' * 32, - "signature": '22' * 32, - "signed_by": "device" - }, - { - "name": "device", - "message": '33' * 32, - "signature": '44' * 32, - "signed_by": "root" - }, - { - 'name': 'ui', - 'message': 'aa' * 32, - 'signature': 'bb' * 32, - 'signed_by': 'attestation', - 'tweak': 'cc' * 32 - }, - { - 'name': 'signer', - 'message': 'dd' * 32, - 'signature': 'ee' * 32, - 'signed_by': 'attestation', - 'tweak': 'ff' * 32 - } - ] - }, indent=2))], - file_mock.return_value.write.call_args_list) - - @patch('admin.ledger_attestation.RskClient') - def test_attestation_ok_get_ud_value(self, RskClient, from_jsonfile, get_hsm, *_): - self.setupMocks(from_jsonfile, get_hsm) - RskClient.return_value = Mock() - rsk_client = RskClient.return_value - rsk_client.get_block_by_number = Mock(return_value={'hash': '0x' + 'bb' * 32}) + get_ud_value_for_attestation.return_value = 'bb'*32 options = self.setupDefaultOptions() options.attestation_ud_source = 'an-url' @@ -149,8 +91,7 @@ def test_attestation_ok_get_ud_value(self, RskClient, from_jsonfile, get_hsm, *_ self.assertEqual([call(options.attestation_certificate_file_path)], from_jsonfile.call_args_list) - self.assertEqual([call('an-url')], RskClient.call_args_list) - self.assertTrue(rsk_client.get_block_by_number.called) + self.assertEqual([call('an-url')], get_ud_value_for_attestation.call_args_list) self.assertNotEqual([call(options.attestation_ud_source)], get_hsm.return_value.get_ui_attestation.call_args_list) self.assertEqual([call('bb' * 32)], @@ -228,15 +169,19 @@ def test_attestation_invalid_jsonfile(self, from_jsonfile, get_hsm, *_): self.assertFalse(get_hsm.called) self.assertFalse(file_mock.return_value.write.called) - @patch('admin.ledger_attestation.RskClient') - def test_attestation_rsk_client_error(self, RskClient, from_jsonfile, get_hsm, *_): + @patch('admin.ledger_attestation.get_ud_value_for_attestation') + def test_attestation_get_ud_value_for_attestation_error(self, + get_ud_value_for_attestation, + from_jsonfile, get_hsm, *_): self.setupMocks(from_jsonfile, get_hsm) - RskClient.side_effect = RskClientError('error-msg') + get_ud_value_for_attestation.side_effect = AdminError('error-msg') options = self.setupDefaultOptions() - options.attestation_ud_source = 'an-url' + options.attestation_ud_source = 'another-url' with patch('builtins.open', mock_open()) as file_mock: with self.assertRaises(AdminError): do_attestation(options) + self.assertEqual([call('another-url')], + get_ud_value_for_attestation.call_args_list) self.assertTrue(from_jsonfile.called) self.assertFalse(get_hsm.called) self.assertFalse(file_mock.return_value.write.called) diff --git a/middleware/tests/admin/test_misc.py b/middleware/tests/admin/test_misc.py new file mode 100644 index 00000000..d6ac6279 --- /dev/null +++ b/middleware/tests/admin/test_misc.py @@ -0,0 +1,63 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from unittest import TestCase +from unittest.mock import Mock, patch +from admin.misc import get_ud_value_for_attestation, RskClientError, AdminError + +import logging + +logging.disable(logging.CRITICAL) + + +class TestGetUdValueForAttestation(TestCase): + def test_hex_string(self): + self.assertEqual("aa"*32, get_ud_value_for_attestation("aa"*32)) + self.assertEqual("aa"*32, get_ud_value_for_attestation("0x"+"aa"*32)) + + @patch("admin.misc.RskClient") + def test_ud_source_ok(self, RskClient): + rsk_client = Mock() + RskClient.return_value = rsk_client + rsk_client.get_best_block_number.return_value = "the-best-block-number" + rsk_client.get_block_by_number.return_value = {"hash": "0x" + "bb"*32} + + self.assertEqual("bb"*32, get_ud_value_for_attestation("a-ud-source")) + + RskClient.assert_called_with("a-ud-source") + rsk_client.get_best_block_number.assert_called() + rsk_client.get_block_by_number.assert_called_with("the-best-block-number") + + @patch("admin.misc.RskClient") + def test_ud_source_client_error(self, RskClient): + rsk_client = Mock() + RskClient.return_value = rsk_client + rsk_client.get_best_block_number.return_value = "the-best-block-number" + rsk_client.get_block_by_number.side_effect = RskClientError("an-error") + + with self.assertRaises(AdminError) as e: + get_ud_value_for_attestation("a-ud-source") + self.assertIn("an-error", str(e.exception)) + + RskClient.assert_called_with("a-ud-source") + rsk_client.get_best_block_number.assert_called() + rsk_client.get_block_by_number.assert_called_with("the-best-block-number") diff --git a/middleware/tests/admin/test_sgx_attestation.py b/middleware/tests/admin/test_sgx_attestation.py new file mode 100644 index 00000000..2f05f2da --- /dev/null +++ b/middleware/tests/admin/test_sgx_attestation.py @@ -0,0 +1,113 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from types import SimpleNamespace +from unittest import TestCase +from unittest.mock import Mock, patch +from parameterized import parameterized +from admin.sgx_attestation import do_attestation +from admin.misc import AdminError + + +@patch("sys.stdout") +@patch("admin.sgx_attestation.HSMCertificateV2Element") +@patch("admin.sgx_attestation.HSMCertificateV2") +@patch("admin.sgx_attestation.do_unlock") +@patch("admin.sgx_attestation.get_ud_value_for_attestation") +@patch("admin.sgx_attestation.get_hsm") +class TestSgxAttestation(TestCase): + def setUp(self): + options = SimpleNamespace() + options.output_file_path = "an-output-file" + options.no_unlock = False + options.verbose = "is-verbose" + options.attestation_ud_source = "an-ud-source" + self.options = options + + def setupMocks(self, get_hsm, get_ud_value_for_attestation, do_unlock, + HSMCertificateV2, HSMCertificateV2Element): + self.get_hsm = get_hsm + self.get_ud_value_for_attestation = get_ud_value_for_attestation + self.do_unlock = do_unlock + self.HSMCertificateV2 = HSMCertificateV2 + self.HSMCertificateV2Element = HSMCertificateV2Element + + self.hsm = Mock() + self.hsm.get_powhsm_attestation.return_value = "the-attestation" + get_hsm.return_value = self.hsm + get_ud_value_for_attestation.return_value = "some-random-value" + + @parameterized.expand([ + ("unlock", False), + ("no_unlock", True), + ]) + def test_ok(self, *args): + self.setupMocks(*args[:-3]) + self.options.no_unlock = args[-1] + + do_attestation(self.options) + + self.get_ud_value_for_attestation.assert_called_with("an-ud-source") + if self.options.no_unlock: + self.do_unlock.assert_not_called() + else: + self.do_unlock.assert_called_with(self.options, label=False) + self.get_hsm.assert_called_with("is-verbose") + self.hsm.get_powhsm_attestation.assert_called_with("some-random-value") + self.hsm.disconnect.assert_called() + self.HSMCertificateV2Element.assert_called_with("the-attestation") + elem = self.HSMCertificateV2Element.return_value + cert = self.HSMCertificateV2.return_value + cert.add_element.assert_called_with(elem) + cert.save_to_jsonfile.assert_called_with("an-output-file") + + def test_no_output_path(self, *args): + self.setupMocks(*args[:-1]) + self.options.output_file_path = None + + with self.assertRaises(AdminError) as e: + do_attestation(self.options) + self.assertIn("output file", str(e.exception)) + + self.get_ud_value_for_attestation.assert_not_called() + self.get_hsm.assert_not_called() + self.hsm.get_powhsm_attestation.assert_not_called() + self.do_unlock.assert_not_called() + self.HSMCertificateV2.assert_not_called() + self.HSMCertificateV2Element.assert_not_called() + + def test_adm_err(self, *args): + self.setupMocks(*args[:-1]) + + self.hsm.get_powhsm_attestation.side_effect = RuntimeError("an error") + + with self.assertRaises(RuntimeError) as e: + do_attestation(self.options) + self.assertIn("an error", str(e.exception)) + + self.get_ud_value_for_attestation.assert_called_with("an-ud-source") + self.do_unlock.assert_called_with(self.options, label=False) + self.get_hsm.assert_called_with("is-verbose") + self.hsm.get_powhsm_attestation.assert_called_with("some-random-value") + self.hsm.disconnect.assert_not_called() + self.HSMCertificateV2.assert_not_called() + self.HSMCertificateV2Element.assert_not_called() diff --git a/setup.cfg b/setup.cfg index bd38e3cf..b11ff18e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,7 +22,9 @@ max-line-length = 90 indent-size = 4 # Ignore unused imports in __init__.py files -per-file-ignores = __init__.py:F401 +per-file-ignores = + __init__.py:F401, + middleware/admin/certificate.py:F401, show-source = False statistics = True From 5c5396711f53ace7448616ac811a90bb9a3c5fd8 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 17 Dec 2024 02:29:32 +1300 Subject: [PATCH 29/50] Certificate V2 generator (#229) - Added individual certificate v2 element types with serialization logic: SgxQuote, SgxAttestationKey and X509 - Added CStruct abstraction to simplify representing C structs - Added struct definitions as CStruct subtypes based on OpenEnclave's endorsement type definitions - Updated SGX attestation gathering logic to parse the envelope and generate the actual certificate elements - Added and updated unit tests - Ignoring long line linting in envelope unit tests --- middleware/admin/certificate.py | 4 +- middleware/admin/certificate_v2.py | 60 ++++- middleware/admin/sgx_attestation.py | 74 +++++- middleware/comm/cstruct.py | 163 +++++++++++++ middleware/sgx/envelope.py | 192 +++++++++++++++ middleware/tests/admin/test_certificate_v1.py | 2 +- middleware/tests/admin/test_certificate_v2.py | 91 +++++++ .../tests/admin/test_sgx_attestation.py | 130 +++++++++- middleware/tests/comm/test_cstruct.py | 223 ++++++++++++++++++ middleware/tests/sgx/test_envelope.py | 112 +++++++++ setup.cfg | 1 + 11 files changed, 1026 insertions(+), 26 deletions(-) create mode 100644 middleware/comm/cstruct.py create mode 100644 middleware/sgx/envelope.py create mode 100644 middleware/tests/admin/test_certificate_v2.py create mode 100644 middleware/tests/comm/test_cstruct.py create mode 100644 middleware/tests/sgx/test_envelope.py diff --git a/middleware/admin/certificate.py b/middleware/admin/certificate.py index 64b3bb6b..1b86f791 100644 --- a/middleware/admin/certificate.py +++ b/middleware/admin/certificate.py @@ -21,4 +21,6 @@ # SOFTWARE. from .certificate_v1 import HSMCertificate, HSMCertificateElement -from .certificate_v2 import HSMCertificateV2, HSMCertificateV2Element +from .certificate_v2 import HSMCertificateV2, HSMCertificateV2ElementSGXQuote, \ + HSMCertificateV2ElementSGXAttestationKey, \ + HSMCertificateV2ElementX509 diff --git a/middleware/admin/certificate_v2.py b/middleware/admin/certificate_v2.py index 61e74ce5..962fa3a0 100644 --- a/middleware/admin/certificate_v2.py +++ b/middleware/admin/certificate_v2.py @@ -24,16 +24,62 @@ class HSMCertificateV2Element: - # TODO: actual logic and subclasses - def __init__(self, element_map): - self.element_map = element_map + pass - # Stub - def name(self): - return "attestation" + +class HSMCertificateV2ElementSGXQuote(HSMCertificateV2Element): + def __init__(self, name, message, custom_data, signature, signed_by): + self.name = name + self.message = message + self.custom_data = custom_data + self.signature = signature + self.signed_by = signed_by + + def to_dict(self): + return { + "name": self.name, + "type": "sgx_quote", + "message": self.message.hex(), + "custom_data": self.custom_data.hex(), + "signature": self.signature.hex(), + "signed_by": self.signed_by, + } + + +class HSMCertificateV2ElementSGXAttestationKey(HSMCertificateV2Element): + def __init__(self, name, message, key, auth_data, signature, signed_by): + self.name = name + self.message = message + self.key = key + self.auth_data = auth_data + self.signature = signature + self.signed_by = signed_by + + def to_dict(self): + return { + "name": self.name, + "type": "sgx_attestation_key", + "message": self.message.hex(), + "key": self.key.hex(), + "auth_data": self.auth_data.hex(), + "signature": self.signature.hex(), + "signed_by": self.signed_by, + } + + +class HSMCertificateV2ElementX509(HSMCertificateV2Element): + def __init__(self, name, message, signed_by): + self.name = name + self.message = message + self.signed_by = signed_by def to_dict(self): - return self.element_map + return { + "name": self.name, + "type": "x509_pem", + "message": self.message.decode('ASCII'), + "signed_by": self.signed_by, + } class HSMCertificateV2(HSMCertificate): diff --git a/middleware/admin/sgx_attestation.py b/middleware/admin/sgx_attestation.py index c261f0ba..364df5b2 100644 --- a/middleware/admin/sgx_attestation.py +++ b/middleware/admin/sgx_attestation.py @@ -20,9 +20,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import ecdsa from .misc import info, head, get_hsm, AdminError, get_ud_value_for_attestation from .unlock import do_unlock -from .certificate import HSMCertificateV2, HSMCertificateV2Element +from sgx.envelope import SgxEnvelope +from .certificate import HSMCertificateV2, HSMCertificateV2ElementSGXQuote, \ + HSMCertificateV2ElementSGXAttestationKey, \ + HSMCertificateV2ElementX509 def do_attestation(options): @@ -58,14 +62,72 @@ def do_attestation(options): hsm.disconnect() + # Parse envelope + info("Parsing the powHSM attestation envelope...") + try: + envelope = SgxEnvelope( + bytes.fromhex(powhsm_attestation["envelope"]), + bytes.fromhex(powhsm_attestation["message"])) + except Exception as e: + raise AdminError(f"SGX envelope parse error: {str(e)}") + + # Conversions + quote_signature = ecdsa.util.sigdecode_string( + envelope.quote_auth_data.signature.r + + envelope.quote_auth_data.signature.s, + ecdsa.NIST256p.order) + quote_signature = ecdsa.util.sigencode_der( + quote_signature[0], + quote_signature[1], + ecdsa.NIST256p.order) + att_key = ecdsa.VerifyingKey.from_string( + envelope.quote_auth_data.attestation_key.x + + envelope.quote_auth_data.attestation_key.y, + ecdsa.NIST256p) + qe_rb_signature = ecdsa.util.sigdecode_string( + envelope.quote_auth_data.qe_report_body_signature.r + + envelope.quote_auth_data.qe_report_body_signature.s, + ecdsa.NIST256p.order) + qe_rb_signature = ecdsa.util.sigencode_der( + qe_rb_signature[0], + qe_rb_signature[1], + ecdsa.NIST256p.order) + # Generate and save the attestation certificate info("Generating the attestation certificate... ", options.verbose) - att_cert = HSMCertificateV2() - # TODO: - # 1. Parse envelope - # 2. Add actual elements of the certificate - att_cert.add_element(HSMCertificateV2Element(powhsm_attestation)) + + att_cert.add_element( + HSMCertificateV2ElementSGXQuote( + name="quote", + message=envelope.quote.get_raw_data(), + custom_data=envelope.custom_message, + signature=quote_signature, + signed_by="attestation", + )) + att_cert.add_element( + HSMCertificateV2ElementSGXAttestationKey( + name="attestation", + message=envelope.quote_auth_data.qe_report_body.get_raw_data(), + key=att_key.to_string("uncompressed"), + auth_data=envelope.qe_auth_data.data, + signature=qe_rb_signature, + signed_by="quoting_enclave", + )) + att_cert.add_element( + HSMCertificateV2ElementX509( + name="quoting_enclave", + message=envelope.qe_cert_data.certs[0], + signed_by="platform_ca", + )) + att_cert.add_element( + HSMCertificateV2ElementX509( + name="platform_ca", + message=envelope.qe_cert_data.certs[1], + signed_by="sgx_root", + )) + + att_cert.add_target("quote") att_cert.save_to_jsonfile(options.output_file_path) info(f"Attestation certificate saved to {options.output_file_path}") diff --git a/middleware/comm/cstruct.py b/middleware/comm/cstruct.py new file mode 100644 index 00000000..77203988 --- /dev/null +++ b/middleware/comm/cstruct.py @@ -0,0 +1,163 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +import struct +import re + + +class CStruct: + MAP = { + "uint8_t": ["B", "s"], + "uint16_t": "H", + "uint32_t": "I", + "uint64_t": "Q", + } + SPEC = None + TYPENAME = None + + @classmethod + def _spec(cls, little=True): + if cls.SPEC is None or little not in cls.SPEC: + fmt = "<" if little else ">" + atrmap = {} + names = [] + types = [] + index = 0 + typename = None + for line in cls.__doc__.split("\n")[1:]: + line = re.sub(r"\s+", " ", line.strip()) + if line == "": + continue + if typename is None: + typename = line + continue + tspec = line.split(" ") + + length = "" if len(tspec) < 3 else str(int(tspec[2].strip(), 10)) + + typ = tspec[0].strip() + actual_type = None + derived_type = None + if typ not in cls.MAP.keys(): + for kls in cls.__base__.__subclasses__(): + if cls != kls: + if typ == kls._typename(): + actual_type = kls + derived_type = kls + if derived_type is None: + raise ValueError(f"Invalid type: {typ}") + else: + actual_type = cls.MAP[typ] + + if length != "" and not isinstance(actual_type, list): + raise ValueError(f"Invalid type spec: {line}") + + name = tspec[1].strip() + + if isinstance(actual_type, list): + actual_type = actual_type[0] if length == "" else actual_type[1] + elif not isinstance(actual_type, str) and \ + issubclass(actual_type, cls.__base__): + actual_type = str(actual_type.get_bytelength(little)) + "s" + + fmt += length + actual_type + names.append(name) + types.append(derived_type) + atrmap[name] = index + index += 1 + if cls.SPEC is None: + cls.SPEC = {} + cls.SPEC[little] = (struct.Struct(fmt), atrmap, names, types, typename) + + return cls.SPEC[little] + + @classmethod + def _struct(cls, little=True): + return cls._spec(little)[0] + + @classmethod + def _atrmap(cls, little=True): + return cls._spec(little)[1] + + @classmethod + def _names(cls, little=True): + return cls._spec(little)[2] + + @classmethod + def _types(cls, little=True): + return cls._spec(little)[3] + + @classmethod + def _typename(cls): + if cls.TYPENAME is None: + for line in cls.__doc__.split("\n"): + line = re.sub(r"\s+", " ", line.strip()) + if line == "": + continue + cls.TYPENAME = line + break + + return cls.TYPENAME + + @classmethod + def get_bytelength(cls, little=True): + return cls._struct(little).size + + def __init__(self, value, offset=0, little=True): + self._offset = offset + self._little = little + self._raw_value = value + + try: + self._parsed = list(self._struct(little).unpack_from(value, offset)) + except Exception as e: + raise ValueError(f"While parsing: {e}") + + for index, derived_type in enumerate(self._types(little)): + if derived_type is not None: + self._parsed[index] = derived_type(self._parsed[index], little=little) + + def _value(self, name): + amap = self._atrmap(self._little) + if name in amap: + return self._parsed[amap[name]] + raise NameError(f"Property {name} does not exist") + + def __getattr__(self, name): + return self._value(name) + + def get_raw_data(self): + return self._raw_value[ + self._offset:self._offset+self.get_bytelength(self._little)] + + def to_dict(self): + result = {} + for name in self._names(self._little): + value = self._value(name) + if isinstance(value, bytes): + value = value.hex() + result[name] = value.to_dict() if isinstance(value, CStruct) else value + return result + + def __repr__(self): + return f"<{self.__class__.__name__}: {self.to_dict()}>" diff --git a/middleware/sgx/envelope.py b/middleware/sgx/envelope.py new file mode 100644 index 00000000..39f86aab --- /dev/null +++ b/middleware/sgx/envelope.py @@ -0,0 +1,192 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from comm.cstruct import CStruct + + +class SgxEnvelope(CStruct): + """ + sgx_envelope_t + + sgx_quote_t quote + sgx_quote_tail_t quote_tail + sgx_quote_auth_data_t quote_auth_data + """ + + def __init__(self, envelope_bytes, custom_message_bytes, offset=0, little=True): + super().__init__(envelope_bytes, offset, little) + offset += self.get_bytelength() + + qead = SgxQeAuthData(envelope_bytes, offset, little) + offset += qead.get_total_bytelength() + self.qe_auth_data = qead + + qecd = SgxQeCertData(envelope_bytes, offset, little) + offset += qecd.get_total_bytelength() + self.qe_cert_data = qecd + + if envelope_bytes[offset:] != custom_message_bytes: + raise ValueError("Unexpected custom message in envelope tail") + self.custom_message = custom_message_bytes + +############################################################################## +# Types below taken from OpenEnclave's include/openenclave/bits/sgx/sgxtypes.h +############################################################################## + + +class SgxAttributes(CStruct): + """ + sgx_attributes_t + + uint64_t flags + uint64_t xfrm + """ + + +class SgxReportData(CStruct): + """ + sgx_report_data_t + + uint8_t field 64 + """ + + +class SgxReportBody(CStruct): + """ + sgx_report_body_t + + uint8_t cpusvn 16 + uint32_t miscselect + uint8_t reserved1 12 + uint8_t isvextprodid 16 + sgx_attributes_t attributes + uint8_t mrenclave 32 + uint8_t reserved2 32 + uint8_t mrsigner 32 + uint8_t reserved3 32 + uint8_t configid 64 + uint16_t isvprodid + uint16_t isvsvn + uint16_t configsvn + uint8_t reserved4 42 + uint8_t isvfamilyid 16 + sgx_report_data_t report_data + """ + + +class SgxEcdsa256Signature(CStruct): + """ + sgx_ecdsa256_signature_t + + uint8_t r 32 + uint8_t s 32 + """ + + +class SgxEcdsa256Key(CStruct): + """ + sgx_ecdsa256_key_t + + uint8_t x 32 + uint8_t y 32 + """ + + +class SgxQuote(CStruct): + """ + sgx_quote_t + + uint16_t version + uint16_t sign_type + uint32_t tee_type + uint16_t qe_svn + uint16_t pce_svn + uint8_t uuid 16 + uint8_t user_data 20 + sgx_report_body_t report_body + """ + + +# This is actually part of sgx_quote_t, separated +# for pratical reasons since the signature doesn't include +# this field +class SgxQuoteTail(CStruct): + """ + sgx_quote_tail_t + + uint32_t signature_len + """ + + +class SgxQuoteAuthData(CStruct): + """ + sgx_quote_auth_data_t + + sgx_ecdsa256_signature_t signature + sgx_ecdsa256_key_t attestation_key + sgx_report_body_t qe_report_body + sgx_ecdsa256_signature_t qe_report_body_signature + """ + +#################################################################### +# The following two structs are augmented with content parsing logic +#################################################################### + + +class SgxQeAuthData(CStruct): + """ + sgx_qe_auth_data_t + + uint16_t size + """ + + def __init__(self, value, offset=0, little=True): + super().__init__(value, offset, little) + os = offset + self.get_bytelength() + data = value[os:os+self.size] + if len(data) != self.size: + raise ValueError(f"Expected {self.size} data bytes but only got {len(data)}") + self.data = data + + def get_total_bytelength(self): + return self.get_bytelength() + len(self.data) + + +class SgxQeCertData(SgxQeAuthData): + """ + sgx_qe_cert_data_t + + uint16_t type + uint32_t size + """ + SPEC = None + TYPENAME = None + + X509_START_MARKER = b"-----BEGIN CERTIFICATE-----\n" + X509_END_MARKER = b"\n-----END CERTIFICATE-----\n" + + def __init__(self, value, offset=0, little=True): + super().__init__(value, offset, little) + self.certs = list(map(lambda c: c.replace(self.X509_START_MARKER, b""), + filter(lambda c: + c.strip().startswith(self.X509_START_MARKER), + self.data.split(self.X509_END_MARKER)))) diff --git a/middleware/tests/admin/test_certificate_v1.py b/middleware/tests/admin/test_certificate_v1.py index 591cfc91..f7503bba 100644 --- a/middleware/tests/admin/test_certificate_v1.py +++ b/middleware/tests/admin/test_certificate_v1.py @@ -26,7 +26,7 @@ from unittest import TestCase from unittest.mock import call, patch, mock_open -from admin.certificate import HSMCertificate, HSMCertificateElement +from admin.certificate_v1 import HSMCertificate, HSMCertificateElement class TestHSMCertificate(TestCase): diff --git a/middleware/tests/admin/test_certificate_v2.py b/middleware/tests/admin/test_certificate_v2.py new file mode 100644 index 00000000..f4a16da6 --- /dev/null +++ b/middleware/tests/admin/test_certificate_v2.py @@ -0,0 +1,91 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from unittest import TestCase +from admin.certificate_v1 import HSMCertificate +from admin.certificate_v2 import HSMCertificateV2, HSMCertificateV2ElementSGXQuote, \ + HSMCertificateV2ElementSGXAttestationKey, \ + HSMCertificateV2ElementX509 + + +class TestHSMCertificateV2(TestCase): + def test_behavior_inherited(self): + self.assertTrue(issubclass(HSMCertificateV2, HSMCertificate)) + + def test_create_empty_certificate_ok(self): + cert = HSMCertificateV2() + self.assertEqual({'version': 2, 'targets': [], 'elements': []}, cert.to_dict()) + + +class TestHSMCertificateV2ElementSGXQuote(TestCase): + def test_dict_ok(self): + elem = HSMCertificateV2ElementSGXQuote( + "thename", + bytes.fromhex("aabbcc"), + bytes.fromhex("ddeeff"), + bytes.fromhex("112233"), + "whosigned" + ) + self.assertEqual({ + "name": "thename", + "type": "sgx_quote", + "message": "aabbcc", + "custom_data": "ddeeff", + "signature": "112233", + "signed_by": "whosigned", + }, elem.to_dict()) + + +class TestHSMCertificateV2ElementSGXAttestationKey(TestCase): + def test_dict_ok(self): + elem = HSMCertificateV2ElementSGXAttestationKey( + "thename", + bytes.fromhex("aabbcc"), + bytes.fromhex("ddeeff"), + bytes.fromhex("112233"), + bytes.fromhex("44556677"), + "whosigned" + ) + self.assertEqual({ + "name": "thename", + "type": "sgx_attestation_key", + "message": "aabbcc", + "key": "ddeeff", + "auth_data": "112233", + "signature": "44556677", + "signed_by": "whosigned", + }, elem.to_dict()) + + +class TestHSMCertificateV2ElementX509(TestCase): + def test_dict_ok(self): + elem = HSMCertificateV2ElementX509( + "thename", + b"this is an ascii message", + "whosigned" + ) + self.assertEqual({ + "name": "thename", + "type": "x509_pem", + "message": "this is an ascii message", + "signed_by": "whosigned", + }, elem.to_dict()) diff --git a/middleware/tests/admin/test_sgx_attestation.py b/middleware/tests/admin/test_sgx_attestation.py index 2f05f2da..4b60fadb 100644 --- a/middleware/tests/admin/test_sgx_attestation.py +++ b/middleware/tests/admin/test_sgx_attestation.py @@ -20,17 +20,21 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import ecdsa from types import SimpleNamespace from unittest import TestCase -from unittest.mock import Mock, patch +from unittest.mock import Mock, patch, call from parameterized import parameterized from admin.sgx_attestation import do_attestation from admin.misc import AdminError @patch("sys.stdout") -@patch("admin.sgx_attestation.HSMCertificateV2Element") +@patch("admin.sgx_attestation.HSMCertificateV2ElementX509") +@patch("admin.sgx_attestation.HSMCertificateV2ElementSGXAttestationKey") +@patch("admin.sgx_attestation.HSMCertificateV2ElementSGXQuote") @patch("admin.sgx_attestation.HSMCertificateV2") +@patch("admin.sgx_attestation.SgxEnvelope") @patch("admin.sgx_attestation.do_unlock") @patch("admin.sgx_attestation.get_ud_value_for_attestation") @patch("admin.sgx_attestation.get_hsm") @@ -44,15 +48,56 @@ def setUp(self): self.options = options def setupMocks(self, get_hsm, get_ud_value_for_attestation, do_unlock, - HSMCertificateV2, HSMCertificateV2Element): + SgxEnvelope, HSMCertificateV2, HSMCertificateV2ElementSGXQuote, + HSMCertificateV2ElementSGXAttestationKey, HSMCertificateV2ElementX509): self.get_hsm = get_hsm self.get_ud_value_for_attestation = get_ud_value_for_attestation self.do_unlock = do_unlock + self.SgxEnvelope = SgxEnvelope self.HSMCertificateV2 = HSMCertificateV2 - self.HSMCertificateV2Element = HSMCertificateV2Element + self.HSMCertificateV2ElementSGXQuote = HSMCertificateV2ElementSGXQuote + self.HSMCertificateV2ElementSGXAttestationKey = \ + HSMCertificateV2ElementSGXAttestationKey + self.HSMCertificateV2ElementX509 = HSMCertificateV2ElementX509 self.hsm = Mock() - self.hsm.get_powhsm_attestation.return_value = "the-attestation" + self.hsm.get_powhsm_attestation.return_value = { + "envelope": "11"*32, + "message": "22"*32, + } + quote = SimpleNamespace(**{"get_raw_data": lambda: "quote-raw-data"}) + sig = SimpleNamespace(**{"r": b"a"*32, "s": b"a"*32}) + self.att_key = ecdsa.SigningKey.generate(curve=ecdsa.NIST256p).\ + get_verifying_key() + att_key_str = self.att_key.to_string() + attkey = SimpleNamespace(**{"x": att_key_str[:32], "y": att_key_str[32:]}) + qesig = SimpleNamespace(**{"r": b"c"*32, "s": b"c"*32}) + qad = SimpleNamespace(**{ + "signature": sig, + "attestation_key": attkey, + "qe_report_body": SimpleNamespace(**{ + "get_raw_data": lambda: "qerb-raw-data"}), + "qe_report_body_signature": qesig, + }) + qead = SimpleNamespace(**{ + "data": "qead-data", + }) + qecd = SimpleNamespace(**{ + "certs": ["qecd-cert-0", "qecd-cert-1"], + }) + envelope = SimpleNamespace(**{ + "quote": quote, + "quote_auth_data": qad, + "qe_auth_data": qead, + "qe_cert_data": qecd, + "custom_message": "a-custom-message", + }) + self.SgxEnvelope.return_value = envelope + + self.HSMCertificateV2ElementSGXQuote.return_value = "quote_elem" + self.HSMCertificateV2ElementSGXAttestationKey.return_value = "attkey_elem" + self.HSMCertificateV2ElementX509.side_effect = ["cert0_elem", "cert1_elem"] + get_hsm.return_value = self.hsm get_ud_value_for_attestation.return_value = "some-random-value" @@ -74,10 +119,44 @@ def test_ok(self, *args): self.get_hsm.assert_called_with("is-verbose") self.hsm.get_powhsm_attestation.assert_called_with("some-random-value") self.hsm.disconnect.assert_called() - self.HSMCertificateV2Element.assert_called_with("the-attestation") - elem = self.HSMCertificateV2Element.return_value + self.SgxEnvelope.assert_called_with( + bytes.fromhex("11"*32), + bytes.fromhex("22"*32), + ) + self.HSMCertificateV2ElementSGXQuote.assert_called_with( + name="quote", + message="quote-raw-data", + custom_data="a-custom-message", + signature=bytes.fromhex("30440220"+"61"*32+"0220"+"61"*32), + signed_by="attestation", + ) + self.HSMCertificateV2ElementSGXAttestationKey.assert_called_with( + name="attestation", + message="qerb-raw-data", + key=self.att_key.to_string("uncompressed"), + auth_data="qead-data", + signature=bytes.fromhex("30440220"+"63"*32+"0220"+"63"*32), + signed_by="quoting_enclave", + ) + self.HSMCertificateV2ElementX509.assert_has_calls([ + call( + name="quoting_enclave", + message="qecd-cert-0", + signed_by="platform_ca", + ), + call( + name="platform_ca", + message="qecd-cert-1", + signed_by="sgx_root", + ) + ]) cert = self.HSMCertificateV2.return_value - cert.add_element.assert_called_with(elem) + cert.add_element.assert_has_calls([ + call("quote_elem"), + call("attkey_elem"), + call("cert0_elem"), + call("cert1_elem") + ]) cert.save_to_jsonfile.assert_called_with("an-output-file") def test_no_output_path(self, *args): @@ -92,10 +171,13 @@ def test_no_output_path(self, *args): self.get_hsm.assert_not_called() self.hsm.get_powhsm_attestation.assert_not_called() self.do_unlock.assert_not_called() + self.SgxEnvelope.assert_not_called() self.HSMCertificateV2.assert_not_called() - self.HSMCertificateV2Element.assert_not_called() + self.HSMCertificateV2ElementSGXQuote.assert_not_called() + self.HSMCertificateV2ElementSGXAttestationKey.assert_not_called() + self.HSMCertificateV2ElementX509.assert_not_called() - def test_adm_err(self, *args): + def test_adm_err_get_attestation(self, *args): self.setupMocks(*args[:-1]) self.hsm.get_powhsm_attestation.side_effect = RuntimeError("an error") @@ -109,5 +191,31 @@ def test_adm_err(self, *args): self.get_hsm.assert_called_with("is-verbose") self.hsm.get_powhsm_attestation.assert_called_with("some-random-value") self.hsm.disconnect.assert_not_called() + self.SgxEnvelope.assert_not_called() + self.HSMCertificateV2.assert_not_called() + self.HSMCertificateV2ElementSGXQuote.assert_not_called() + self.HSMCertificateV2ElementSGXAttestationKey.assert_not_called() + self.HSMCertificateV2ElementX509.assert_not_called() + + def test_adm_err_envelope_parsing(self, *args): + self.setupMocks(*args[:-1]) + + self.SgxEnvelope.side_effect = ValueError("an error") + + with self.assertRaises(AdminError) as e: + do_attestation(self.options) + self.assertIn("envelope parse error", str(e.exception)) + + self.get_ud_value_for_attestation.assert_called_with("an-ud-source") + self.do_unlock.assert_called_with(self.options, label=False) + self.get_hsm.assert_called_with("is-verbose") + self.hsm.get_powhsm_attestation.assert_called_with("some-random-value") + self.hsm.disconnect.assert_called() + self.SgxEnvelope.assert_called_with( + bytes.fromhex("11"*32), + bytes.fromhex("22"*32), + ) self.HSMCertificateV2.assert_not_called() - self.HSMCertificateV2Element.assert_not_called() + self.HSMCertificateV2ElementSGXQuote.assert_not_called() + self.HSMCertificateV2ElementSGXAttestationKey.assert_not_called() + self.HSMCertificateV2ElementX509.assert_not_called() diff --git a/middleware/tests/comm/test_cstruct.py b/middleware/tests/comm/test_cstruct.py new file mode 100644 index 00000000..8c04d47d --- /dev/null +++ b/middleware/tests/comm/test_cstruct.py @@ -0,0 +1,223 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from unittest import TestCase +from parameterized import parameterized +from comm.cstruct import CStruct + +import logging + +logging.disable(logging.CRITICAL) + + +class RandomBisStruct(CStruct): + """ + random_bis_t + + uint16_t another_double + uint8_t single_arr 10 + uint32_t another_quad + """ + + +class RandomTrisStruct(CStruct): + """ + random_tris_t + + uint8_t arr_one 2 + uint8_t arr_two 3 + """ + + +class RandomStruct(CStruct): + """ + random_t + + uint8_t single_val + uint16_t double_val + uint32_t quad_val + uint64_t oct_val + + random_bis_t other_random + random_tris_t yet_other_random + """ + + +class Invalid1(CStruct): + """ + invalid_1 + + nonexistent_type something + """ + + +class Invalid2(CStruct): + """ + invalid_2 + + uint32_t withlength 5 + """ + + +class ValidWithInvalid(CStruct): + """ + valid_with_invalid + + uint8_t a_number + uint16_t another_number + invalid_2 something_invalid + """ + + +class TestCStruct(TestCase): + def setUp(self): + self.packed = bytes.fromhex( + "99" # single_val + "0102" # double_val + "03040506" # quad_val + "0708090a0b0c0d0e" # oct_val + "8899" # another_double + "00112233445566778899" # single_arr + "d1d2d3d4" # another_quad + "aabb" # arr_one + "ccddee" # arr_two + ) + + def test_expected_sizes(self): + self.assertEqual(16, RandomBisStruct.get_bytelength()) + self.assertEqual(5, RandomTrisStruct.get_bytelength()) + self.assertEqual(15 + + RandomBisStruct.get_bytelength() + + RandomTrisStruct.get_bytelength(), + RandomStruct.get_bytelength()) + + def test_parsing_default(self): + parsed = RandomStruct(self.packed) + + self.assertEqual(0x99, parsed.single_val) + self.assertEqual(0x0201, parsed.double_val) + self.assertEqual(0x06050403, parsed.quad_val) + self.assertEqual(0x0e0d0c0b0a090807, parsed.oct_val) + + self.assertEqual(0x9988, parsed.other_random.another_double) + self.assertEqual(bytes.fromhex("00112233445566778899"), + parsed.other_random.single_arr) + self.assertEqual(0xd4d3d2d1, parsed.other_random.another_quad) + + self.assertEqual(bytes.fromhex("aabb"), parsed.yet_other_random.arr_one) + self.assertEqual(bytes.fromhex("ccddee"), parsed.yet_other_random.arr_two) + + self.assertEqual({ + "single_val": 0x99, + "double_val": 0x0201, + "quad_val": 0x06050403, + "oct_val": 0x0e0d0c0b0a090807, + "other_random": { + "another_double": 0x9988, + "single_arr": "00112233445566778899", + "another_quad": 0xd4d3d2d1, + }, + "yet_other_random": { + "arr_one": "aabb", + "arr_two": "ccddee", + } + }, parsed.to_dict()) + + def test_parsing_little_offset(self): + parsed = RandomStruct(b"thisisrandom" + self.packed, offset=12, little=True) + + self.assertEqual(0x99, parsed.single_val) + self.assertEqual(0x0201, parsed.double_val) + self.assertEqual(0x06050403, parsed.quad_val) + self.assertEqual(0x0e0d0c0b0a090807, parsed.oct_val) + + self.assertEqual(0x9988, parsed.other_random.another_double) + self.assertEqual(bytes.fromhex("00112233445566778899"), + parsed.other_random.single_arr) + self.assertEqual(0xd4d3d2d1, parsed.other_random.another_quad) + + self.assertEqual(bytes.fromhex("aabb"), parsed.yet_other_random.arr_one) + self.assertEqual(bytes.fromhex("ccddee"), parsed.yet_other_random.arr_two) + + self.assertEqual({ + "single_val": 0x99, + "double_val": 0x0201, + "quad_val": 0x06050403, + "oct_val": 0x0e0d0c0b0a090807, + "other_random": { + "another_double": 0x9988, + "single_arr": "00112233445566778899", + "another_quad": 0xd4d3d2d1, + }, + "yet_other_random": { + "arr_one": "aabb", + "arr_two": "ccddee", + } + }, parsed.to_dict()) + + def test_parsing_big(self): + parsed = RandomStruct(self.packed, little=False) + + self.assertEqual(0x99, parsed.single_val) + self.assertEqual(0x0102, parsed.double_val) + self.assertEqual(0x03040506, parsed.quad_val) + self.assertEqual(0x0708090a0b0c0d0e, parsed.oct_val) + + self.assertEqual(0x8899, parsed.other_random.another_double) + self.assertEqual(bytes.fromhex("00112233445566778899"), + parsed.other_random.single_arr) + self.assertEqual(0xd1d2d3d4, parsed.other_random.another_quad) + + self.assertEqual(bytes.fromhex("aabb"), parsed.yet_other_random.arr_one) + self.assertEqual(bytes.fromhex("ccddee"), parsed.yet_other_random.arr_two) + + self.assertEqual({ + "single_val": 0x99, + "double_val": 0x0102, + "quad_val": 0x03040506, + "oct_val": 0x0708090a0b0c0d0e, + "other_random": { + "another_double": 0x8899, + "single_arr": "00112233445566778899", + "another_quad": 0xd1d2d3d4, + }, + "yet_other_random": { + "arr_one": "aabb", + "arr_two": "ccddee", + } + }, parsed.to_dict()) + + def test_parsing_toosmall(self): + with self.assertRaises(ValueError): + RandomStruct(b"thisistoosmall") + + @parameterized.expand([ + ("invalid_one", Invalid1), + ("invalid_two", Invalid2), + ("valid_with_invalid", ValidWithInvalid) + ]) + def test_invalid_spec(self, _, kls): + with self.assertRaises(ValueError): + kls.get_bytelength() + + with self.assertRaises(ValueError): + kls(b'somethingtoparse') diff --git a/middleware/tests/sgx/test_envelope.py b/middleware/tests/sgx/test_envelope.py new file mode 100644 index 00000000..132a2861 --- /dev/null +++ b/middleware/tests/sgx/test_envelope.py @@ -0,0 +1,112 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from unittest import TestCase +from parameterized import parameterized +from sgx.envelope import SgxAttributes, \ + SgxReportData, \ + SgxReportBody, \ + SgxEcdsa256Signature, \ + SgxEcdsa256Key, \ + SgxQuote, \ + SgxQuoteTail, \ + SgxQuoteAuthData, \ + SgxQeCertData, \ + SgxQeAuthData, \ + SgxEnvelope + +import logging + +logging.disable(logging.CRITICAL) + +TEST_ENVELOPE = """ +03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ceae3549bc7273eb34d562f4564fc182000000000e0e100fffff01000000000000000000010000000000000000000000000000000000000000000000000000000000000005000000000000000700000000000000d32688d3c1f3dfcc8b0b36eac7c89d49af331800bd56248044166fa6699442c10000000000000000000000000000000000000000000000000000000000000000718c2f1a0efbd513e016fafd6cf62a624442f2d83708d4b33ab5a8d8c1cd4dd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000640001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009e95bb875c1a728071f70ad8c9d03f1744c19acb0580921e611ac9104f7701d00000000000000000000000000000000000000000000000000000000000000000ca100000e52b03a7bd6b5dd9feeeb375bd597730d2872643b47aff4dd641c5c3a2b8016ebbd227f67e7c23bbddeb4f8fddee031a2b961501d1c28dda082669d7ac861e6ca024cb34c90ea6a8f9f2181c9020cbcc7c073e69981733c8deed6f6c451822aa08376350ff7da01f842bb40c631cbb711f8b6f7a4fae398320a3884774d250ad0e0e100fffff0100000000000000000000000000000000000000000000000000000000000000000000000000000000001500000000000000e70000000000000096b347a64e5a045e27369c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e400000000000000000000000000000000000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8ded70140b081b094490c57bff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fe721d0322954821589237fd27efb8fef1acb3ecd6b0352c31271550fc70f9400000000000000000000000000000000000000000000000000000000000000001f14d532274c4385fc0019ca2a21e53e17143cb62377ca4fcdd97fa9fef8fb2595d4ee272cf3c512e36779de67dc7814982f1160d981d138a32b265e928a05622000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f0500620e00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d494945387a4343424a69674177494241674955667232646c774e343244425541394358496b426c4750327656334177436759494b6f5a497a6a3045417749770a634445694d434147413155454177775a535735305a577767553064594946424453794251624746305a6d397962534244515445614d42674741315545436777520a535735305a577767513239796347397959585270623234784644415342674e564241634d43314e68626e526849454e7359584a684d51737743515944565151490a44414a445154454c4d416b474131554542684d4356564d774868634e4d6a51774d7a497a4d4451304e6a49785768634e4d7a45774d7a497a4d4451304e6a49780a576a42774d534977494159445651514444426c4a626e526c624342545231676755454e4c49454e6c636e52705a6d6c6a5958526c4d526f77474159445651514b0a4442464a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424b6c370a52444e6c735a4b6b45744163573753664358314a656762764771344f3072525574307a2f4736665a4a734e6c706d527754423444596b72676b6d31742b3952700a4c77784658392f6b6768786944516d306a716d6a67674d4f4d494944436a416642674e5648534d4547444157674253566231334e765276683655424a796454300a4d383442567776655644427242674e56485238455a4442694d47436758714263686c706f64485277637a6f764c32467761533530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c334e6e6543396a5a584a3061575a7059324630615739754c3359304c33426a61324e796244396a595431770a624746305a6d397962535a6c626d4e765a476c755a7a316b5a584977485159445652304f4242594546414c4b5635444631364b6e4562535735514d39656344710a425a61484d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d4949434f77594a4b6f5a496876684e415130420a424949434c444343416967774867594b4b6f5a496876684e415130424151515174744a587569515677714d34733734672b4878664b54434341575547436971470a534962345451454e41514977676746564d42414743797147534962345451454e415149424167454f4d42414743797147534962345451454e415149434167454f0a4d42414743797147534962345451454e41514944416745444d42414743797147534962345451454e41514945416745444d42454743797147534962345451454e0a41514946416749412f7a415242677371686b69472b4530424451454342674943415038774541594c4b6f5a496876684e4151304241676343415145774541594c0a4b6f5a496876684e4151304241676743415141774541594c4b6f5a496876684e4151304241676b43415141774541594c4b6f5a496876684e4151304241676f430a415141774541594c4b6f5a496876684e4151304241677343415141774541594c4b6f5a496876684e4151304241677743415141774541594c4b6f5a496876684e0a4151304241673043415141774541594c4b6f5a496876684e4151304241673443415141774541594c4b6f5a496876684e4151304241673843415141774541594c0a4b6f5a496876684e4151304241684143415141774541594c4b6f5a496876684e4151304241684543415130774877594c4b6f5a496876684e41513042416849450a4541344f4177502f2f7745414141414141414141414141774541594b4b6f5a496876684e4151304241775143414141774641594b4b6f5a496876684e415130420a4241514741474271414141414d41384743697147534962345451454e4151554b415145774867594b4b6f5a496876684e41513042426751514456652f445855560a453467656d74674f357542707644424542676f71686b69472b453042445145484d4459774541594c4b6f5a496876684e4151304242774542416638774541594c0a4b6f5a496876684e4151304242774942415141774541594c4b6f5a496876684e4151304242774d4241514177436759494b6f5a497a6a304541774944535141770a52674968414a4667663738486767544274765150585a4a782f33466d373176434f6d74383270636539314d325a41493041694541695a4d5042625a5a6d7652320a762b316d727337364a65676c44512b704b2f534c4e39346c342b6a4d3544413d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436c6a4343416a32674177494241674956414a567658633239472b487051456e4a3150517a7a674658433935554d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484178496a41670a42674e5642414d4d47556c756447567349464e4857434251513073675547786864475a76636d306751304578476a415942674e5642416f4d45556c75644756730a49454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b474131554543417743513045780a437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741454e53422f377432316c58534f0a3243757a7078773734654a423732457944476757357258437478327456544c7136684b6b367a2b5569525a436e71523770734f766771466553786c6d546c4a6c0a65546d693257597a33714f42757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f536347724442530a42674e5648523845537a424a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e5648513445466751556c5739640a7a62306234656c4153636e553944504f4156634c336c517744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159420a4166384341514177436759494b6f5a497a6a30454177494452774177524149675873566b6930772b6936565947573355462f32327561586530594a446a3155650a6e412b546a44316169356343494359623153416d4435786b66545670766f34556f79695359787244574c6d5552344349394e4b7966504e2b0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a00746869732069732061206d657373616765 +""" + +TEST_MESSAGE = "746869732069732061206d657373616765" + + +class TestSgxQeAuthData(TestCase): + def test_parses_ok(self): + parsed = SgxQeAuthData(bytes.fromhex("0a00112233445566778899aa")) + self.assertEqual(10, parsed.size) + self.assertEqual(bytes.fromhex("112233445566778899aa"), parsed.data) + + def test_parses_error_tooshort(self): + with self.assertRaises(ValueError): + SgxQeAuthData(bytes.fromhex("0a0baabbcc")) + + +class TestSgxQeCertData(TestCase): + def test_parses_ok(self): + certs = \ +b""" +-----BEGIN CERTIFICATE----- +this is certificate one +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +this is certificate two +-----END CERTIFICATE----- +""" + parsed = SgxQeCertData( + bytes.fromhex("1122") + + len(certs).to_bytes(4, byteorder="little", signed=False) + + certs + ) + self.assertEqual(0x2211, parsed.type) + self.assertEqual(certs, parsed.data) + self.assertEqual(2, len(parsed.certs)) + + def test_parses_error_tooshort(self): + with self.assertRaises(ValueError): + SgxQeAuthData(bytes.fromhex("0a0baabbcc")) + + +class TestSgxEnvelope(TestCase): + def test_parses_ok(self): + envelope = SgxEnvelope( + bytes.fromhex(TEST_ENVELOPE), + bytes.fromhex(TEST_MESSAGE) + ) + + self.assertEqual(TEST_MESSAGE, envelope.custom_message.hex()) + + def test_parsing_fails_if_message_mismatch(self): + with self.assertRaises(ValueError): + SgxEnvelope(bytes.fromhex(TEST_ENVELOPE), b"some-other-message") + + +class TestSgxStructs(TestCase): + # Sizes taken from OpenEnclave's include/openenclave/bits/sgx/sgxtypes.h + # sgx_quote_t is smaller due to not including the last field (signature_len) + @parameterized.expand([ + ("sgx_attributes_t", SgxAttributes, 16), + ("sgx_report_data_t", SgxReportData, 64), + ("sgx_report_body_t", SgxReportBody, 384), + ("sgx_ecdsa256_signature_t", SgxEcdsa256Signature, 64), + ("sgx_ecdsa256_key_t", SgxEcdsa256Key, 64), + ("sgx_quote_t", SgxQuote, 432), + ("sgx_quote_tail_t", SgxQuoteTail, 4), + ("sgx_quote_auth_data_t", SgxQuoteAuthData, 576), + ]) + def test_sizes_ok(self, _, kls, exp_len): + self.assertEqual(exp_len, kls.get_bytelength()) diff --git a/setup.cfg b/setup.cfg index b11ff18e..da90c29b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,6 +25,7 @@ indent-size = 4 per-file-ignores = __init__.py:F401, middleware/admin/certificate.py:F401, + middleware/tests/sgx/test_envelope.py:E122, show-source = False statistics = True From 76b46833f2e6e81fa81136d7b536e3f1824f1646 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Thu, 19 Dec 2024 03:21:09 +1300 Subject: [PATCH 30/50] Certificate V2 parser (#230) - Added version mapping and parsing logic to certificate version 1 - Added dict based initialisation functions to HSMCertificateV2Element and its subclasses - Updated sgx attestation gathering certificate generation - Added and updated unit tests - Ignoring long line linting in certificate v2 resources file --- middleware/admin/certificate.py | 7 + middleware/admin/certificate_v1.py | 30 ++- middleware/admin/certificate_v2.py | 160 +++++++++--- middleware/admin/sgx_attestation.py | 50 ++-- middleware/tests/admin/test_certificate_v1.py | 4 +- middleware/tests/admin/test_certificate_v2.py | 230 ++++++++++++++++-- .../admin/test_certificate_v2_resources.py | 63 +++++ .../tests/admin/test_sgx_attestation.py | 58 ++--- setup.cfg | 1 + 9 files changed, 480 insertions(+), 123 deletions(-) create mode 100644 middleware/tests/admin/test_certificate_v2_resources.py diff --git a/middleware/admin/certificate.py b/middleware/admin/certificate.py index 1b86f791..1321a0b2 100644 --- a/middleware/admin/certificate.py +++ b/middleware/admin/certificate.py @@ -24,3 +24,10 @@ from .certificate_v2 import HSMCertificateV2, HSMCertificateV2ElementSGXQuote, \ HSMCertificateV2ElementSGXAttestationKey, \ HSMCertificateV2ElementX509 + + +# Assign version mapping to the parent class +HSMCertificate.VERSION_MAPPING = { + 1: HSMCertificate, + 2: HSMCertificateV2, +} diff --git a/middleware/admin/certificate_v1.py b/middleware/admin/certificate_v1.py index a37802ed..414fe8f3 100644 --- a/middleware/admin/certificate_v1.py +++ b/middleware/admin/certificate_v1.py @@ -125,18 +125,25 @@ class HSMCertificate: VERSION = 1 # Only supported version ROOT_ELEMENT = "root" ELEMENT_BASE_CLASS = HSMCertificateElement + ELEMENT_FACTORY = HSMCertificateElement - @staticmethod - def from_jsonfile(path): + @classmethod + def from_jsonfile(kls, path): try: with open(path, "r") as file: certificate_map = json.loads(file.read()) if type(certificate_map) != dict: raise ValueError( - "JSON file must contain an object as a top level element") + "Certificate file must contain an object as a top level element") - return HSMCertificate(certificate_map) + version = certificate_map.get("version") + if version not in kls.VERSION_MAPPING: + raise ValueError("Invalid or unsupported HSM certificate " + f"version {version} (supported versions are " + f"{", ".join(kls.VERSION_MAPPING.keys())})") + + return kls.VERSION_MAPPING[version](certificate_map) except (ValueError, json.JSONDecodeError) as e: raise ValueError('Unable to read HSM certificate from "%s": %s' % (path, str(e))) @@ -190,8 +197,8 @@ def validate_and_get_values(self, raw_root_pubkey_hex): def add_element(self, element): if not isinstance(element, self.ELEMENT_BASE_CLASS): - raise ValueError( - f"Expected an HSMCertificateElement but got a {type(element)}") + raise ValueError(f"Expected an {self.ELEMENT_BASE_CLASS.__name__} " + "but got a {type(element)}") self._elements[element.name] = element def clear_targets(self): @@ -214,11 +221,10 @@ def save_to_jsonfile(self, path): file.write("%s\n" % json.dumps(self.to_dict(), indent=2)) def _parse(self, certificate_map): - if "version" not in certificate_map or certificate_map["version"] != self.VERSION: - raise ValueError( - "Invalid or unsupported HSM certificate version " - f"(current version is {self.VERSION})" - ) + version = certificate_map.get("version") + if version != self.VERSION: + raise ValueError("Invalid or unexpected HSM certificate version " + f"{version} (expected {self.VERSION})") if "targets" not in certificate_map or type(certificate_map["targets"]) != list: raise ValueError("Missing or invalid targets") @@ -229,7 +235,7 @@ def _parse(self, certificate_map): raise ValueError("Missing elements") for item in certificate_map["elements"]: - element = HSMCertificateElement(item) + element = self.ELEMENT_FACTORY(item) self._elements[item["name"]] = element # Sanity: check each target has a path to the root authority diff --git a/middleware/admin/certificate_v2.py b/middleware/admin/certificate_v2.py index 962fa3a0..a7b58f7c 100644 --- a/middleware/admin/certificate_v2.py +++ b/middleware/admin/certificate_v2.py @@ -20,76 +20,176 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import base64 from .certificate_v1 import HSMCertificate +from .utils import is_nonempty_hex_string class HSMCertificateV2Element: - pass + def __init__(self): + raise RuntimeError("Cannot instantiate an " + "abstract HSMCertificateV2Element") + + @classmethod + def from_dict(kls, element_map): + if element_map.get("type") not in kls.TYPE_MAPPING: + raise ValueError("Invalid or missing element type for " + f"element {element_map.get("name")}") + + return kls.TYPE_MAPPING[element_map["type"]](element_map) + + def _init_with_map(self, element_map): + if "name" not in element_map: + raise ValueError("Missing name for HSM certificate element") + + self._name = element_map["name"] + + if "signed_by" not in element_map: + raise ValueError("Missing certifier for HSM certificate element") + self._signed_by = element_map["signed_by"] + + @property + def name(self): + return self._name + + @property + def signed_by(self): + return self._signed_by class HSMCertificateV2ElementSGXQuote(HSMCertificateV2Element): - def __init__(self, name, message, custom_data, signature, signed_by): - self.name = name - self.message = message - self.custom_data = custom_data - self.signature = signature - self.signed_by = signed_by + def __init__(self, element_map): + self._init_with_map(element_map) + + def _init_with_map(self, element_map): + super()._init_with_map(element_map) + + if not is_nonempty_hex_string(element_map.get("message")): + raise ValueError(f"Invalid message for HSM certificate element {self.name}") + self._message = bytes.fromhex(element_map["message"]) + + if not is_nonempty_hex_string(element_map.get("custom_data")): + raise ValueError("Invalid custom data for HSM certificate " + f"element {self.name}") + self._custom_data = bytes.fromhex(element_map["custom_data"]) + + if not is_nonempty_hex_string(element_map.get("signature")): + raise ValueError("Invalid signature for HSM certificate element {self.name}") + self._signature = bytes.fromhex(element_map["signature"]) + + @property + def message(self): + return self._message.hex() + + @property + def custom_data(self): + return self._custom_data.hex() + + @property + def signature(self): + return self._signature.hex() def to_dict(self): return { "name": self.name, "type": "sgx_quote", - "message": self.message.hex(), - "custom_data": self.custom_data.hex(), - "signature": self.signature.hex(), + "message": self.message, + "custom_data": self.custom_data, + "signature": self.signature, "signed_by": self.signed_by, } class HSMCertificateV2ElementSGXAttestationKey(HSMCertificateV2Element): - def __init__(self, name, message, key, auth_data, signature, signed_by): - self.name = name - self.message = message - self.key = key - self.auth_data = auth_data - self.signature = signature - self.signed_by = signed_by + def __init__(self, element_map): + self._init_with_map(element_map) + + def _init_with_map(self, element_map): + super()._init_with_map(element_map) + + if not is_nonempty_hex_string(element_map.get("message")): + raise ValueError(f"Invalid message for HSM certificate element {self.name}") + self._message = bytes.fromhex(element_map["message"]) + + if not is_nonempty_hex_string(element_map.get("key")): + raise ValueError(f"Invalid key for HSM certificate element {self.name}") + self._key = bytes.fromhex(element_map["key"]) + + if not is_nonempty_hex_string(element_map.get("auth_data")): + raise ValueError(f"Invalid auth data for HSM certificate element {self.name}") + self._auth_data = bytes.fromhex(element_map["auth_data"]) + + if not is_nonempty_hex_string(element_map.get("signature")): + raise ValueError(f"Invalid signature for HSM certificate element {self.name}") + self._signature = bytes.fromhex(element_map["signature"]) + + @property + def message(self): + return self._message.hex() + + @property + def key(self): + return self._key.hex() + + @property + def auth_data(self): + return self._auth_data.hex() + + @property + def signature(self): + return self._signature.hex() def to_dict(self): return { "name": self.name, "type": "sgx_attestation_key", - "message": self.message.hex(), - "key": self.key.hex(), - "auth_data": self.auth_data.hex(), - "signature": self.signature.hex(), + "message": self.message, + "key": self.key, + "auth_data": self.auth_data, + "signature": self.signature, "signed_by": self.signed_by, } class HSMCertificateV2ElementX509(HSMCertificateV2Element): - def __init__(self, name, message, signed_by): - self.name = name - self.message = message - self.signed_by = signed_by + def __init__(self, element_map): + self._init_with_map(element_map) + + def _init_with_map(self, element_map): + super()._init_with_map(element_map) + + try: + self._message = base64.b64decode(element_map.get("message")) + except Exception: + raise ValueError(f"Invalid message for HSM certificate element {self.name}") + + @property + def message(self): + return base64.b64encode(self._message).decode("ASCII") def to_dict(self): return { "name": self.name, "type": "x509_pem", - "message": self.message.decode('ASCII'), + "message": self.message, "signed_by": self.signed_by, } +# Element type mappings +HSMCertificateV2Element.TYPE_MAPPING = { + "sgx_quote": HSMCertificateV2ElementSGXQuote, + "sgx_attestation_key": HSMCertificateV2ElementSGXAttestationKey, + "x509_pem": HSMCertificateV2ElementX509, +} + + class HSMCertificateV2(HSMCertificate): VERSION = 2 + ROOT_ELEMENT = "sgx_root" ELEMENT_BASE_CLASS = HSMCertificateV2Element + ELEMENT_FACTORY = HSMCertificateV2Element.from_dict def validate_and_get_values(self, raw_root_pubkey_hex): # TODO pass - - def _parse(self, certificate_map): - # TODO - pass diff --git a/middleware/admin/sgx_attestation.py b/middleware/admin/sgx_attestation.py index 364df5b2..8267e678 100644 --- a/middleware/admin/sgx_attestation.py +++ b/middleware/admin/sgx_attestation.py @@ -98,34 +98,34 @@ def do_attestation(options): att_cert = HSMCertificateV2() att_cert.add_element( - HSMCertificateV2ElementSGXQuote( - name="quote", - message=envelope.quote.get_raw_data(), - custom_data=envelope.custom_message, - signature=quote_signature, - signed_by="attestation", - )) + HSMCertificateV2ElementSGXQuote({ + "name": "quote", + "message": envelope.quote.get_raw_data().hex(), + "custom_data": envelope.custom_message.hex(), + "signature": quote_signature.hex(), + "signed_by": "attestation", + })) att_cert.add_element( - HSMCertificateV2ElementSGXAttestationKey( - name="attestation", - message=envelope.quote_auth_data.qe_report_body.get_raw_data(), - key=att_key.to_string("uncompressed"), - auth_data=envelope.qe_auth_data.data, - signature=qe_rb_signature, - signed_by="quoting_enclave", - )) + HSMCertificateV2ElementSGXAttestationKey({ + "name": "attestation", + "message": envelope.quote_auth_data.qe_report_body.get_raw_data().hex(), + "key": att_key.to_string("uncompressed").hex(), + "auth_data": envelope.qe_auth_data.data.hex(), + "signature": qe_rb_signature.hex(), + "signed_by": "quoting_enclave", + })) att_cert.add_element( - HSMCertificateV2ElementX509( - name="quoting_enclave", - message=envelope.qe_cert_data.certs[0], - signed_by="platform_ca", - )) + HSMCertificateV2ElementX509({ + "name": "quoting_enclave", + "message": envelope.qe_cert_data.certs[0], + "signed_by": "platform_ca", + })) att_cert.add_element( - HSMCertificateV2ElementX509( - name="platform_ca", - message=envelope.qe_cert_data.certs[1], - signed_by="sgx_root", - )) + HSMCertificateV2ElementX509({ + "name": "platform_ca", + "message": envelope.qe_cert_data.certs[1], + "signed_by": "sgx_root", + })) att_cert.add_target("quote") att_cert.save_to_jsonfile(options.output_file_path) diff --git a/middleware/tests/admin/test_certificate_v1.py b/middleware/tests/admin/test_certificate_v1.py index f7503bba..8235850a 100644 --- a/middleware/tests/admin/test_certificate_v1.py +++ b/middleware/tests/admin/test_certificate_v1.py @@ -26,7 +26,7 @@ from unittest import TestCase from unittest.mock import call, patch, mock_open -from admin.certificate_v1 import HSMCertificate, HSMCertificateElement +from admin.certificate import HSMCertificate, HSMCertificateElement class TestHSMCertificate(TestCase): @@ -155,7 +155,7 @@ def test_create_certificate_missing_elements(self): "targets": ["attestation", "device"] }) - @patch('admin.certificate_v1.HSMCertificateElement') + @patch('admin.certificate_v1.HSMCertificate.ELEMENT_FACTORY') def test_create_certificate_invalid_element(self, certElementMock): certElementMock.side_effect = ValueError() with self.assertRaises(ValueError): diff --git a/middleware/tests/admin/test_certificate_v2.py b/middleware/tests/admin/test_certificate_v2.py index f4a16da6..ada5c485 100644 --- a/middleware/tests/admin/test_certificate_v2.py +++ b/middleware/tests/admin/test_certificate_v2.py @@ -22,9 +22,11 @@ from unittest import TestCase from admin.certificate_v1 import HSMCertificate -from admin.certificate_v2 import HSMCertificateV2, HSMCertificateV2ElementSGXQuote, \ +from admin.certificate_v2 import HSMCertificateV2, HSMCertificateV2Element, \ + HSMCertificateV2ElementSGXQuote, \ HSMCertificateV2ElementSGXAttestationKey, \ HSMCertificateV2ElementX509 +from .test_certificate_v2_resources import TEST_CERTIFICATE class TestHSMCertificateV2(TestCase): @@ -35,16 +37,61 @@ def test_create_empty_certificate_ok(self): cert = HSMCertificateV2() self.assertEqual({'version': 2, 'targets': [], 'elements': []}, cert.to_dict()) + def test_parse_identity(self): + cert = HSMCertificateV2(TEST_CERTIFICATE) + self.assertEqual(TEST_CERTIFICATE, cert.to_dict()) + + +class TestHSMCertificateV2Element(TestCase): + def test_from_dict_unknown_type(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "a-strange-name", + "type": "an-unknown-type", + "some": "other", + "random": "attributes", + }) + self.assertIn("a-strange-name", str(e.exception)) + + def test_from_dict_no_name(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "type": "sgx_quote", + "signed_by": "a-signer", + "some": "other", + "random": "attributes", + }) + self.assertIn("Missing name", str(e.exception)) + + def test_from_dict_no_signed_by(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "a name", + "type": "sgx_quote", + "some": "other", + "random": "attributes", + }) + self.assertIn("Missing certifier", str(e.exception)) + class TestHSMCertificateV2ElementSGXQuote(TestCase): + def setUp(self): + self.elem = HSMCertificateV2ElementSGXQuote({ + "name": "thename", + "message": "aabbcc", + "custom_data": "ddeeff", + "signature": "112233", + "signed_by": "whosigned", + }) + + def test_props(self): + self.assertEqual("thename", self.elem.name) + self.assertEqual("whosigned", self.elem.signed_by) + self.assertEqual("aabbcc", self.elem.message) + self.assertEqual("ddeeff", self.elem.custom_data) + self.assertEqual("112233", self.elem.signature) + def test_dict_ok(self): - elem = HSMCertificateV2ElementSGXQuote( - "thename", - bytes.fromhex("aabbcc"), - bytes.fromhex("ddeeff"), - bytes.fromhex("112233"), - "whosigned" - ) self.assertEqual({ "name": "thename", "type": "sgx_quote", @@ -52,19 +99,71 @@ def test_dict_ok(self): "custom_data": "ddeeff", "signature": "112233", "signed_by": "whosigned", - }, elem.to_dict()) + }, self.elem.to_dict()) + + def test_parse_identity(self): + source = TEST_CERTIFICATE["elements"][0] + elem = HSMCertificateV2Element.from_dict(source) + self.assertTrue(isinstance(elem, HSMCertificateV2ElementSGXQuote)) + self.assertEqual(source, elem.to_dict()) + + def test_from_dict_invalid_message(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "quote", + "type": "sgx_quote", + "message": "not-hex", + "custom_data": "112233", + "signature": "445566778899", + "signed_by": "attestation" + }) + self.assertIn("Invalid message", str(e.exception)) + + def test_from_dict_invalid_custom_data(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "quote", + "type": "sgx_quote", + "message": "aabbccdd", + "custom_data": "not-hex", + "signature": "445566778899", + "signed_by": "attestation" + }) + self.assertIn("Invalid custom data", str(e.exception)) + + def test_from_dict_invalid_signature(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "quote", + "type": "sgx_quote", + "message": "aabbccdd", + "custom_data": "112233", + "signature": "not-hex", + "signed_by": "attestation" + }) + self.assertIn("Invalid signature", str(e.exception)) class TestHSMCertificateV2ElementSGXAttestationKey(TestCase): + def setUp(self): + self.elem = HSMCertificateV2ElementSGXAttestationKey({ + "name": "thename", + "message": "aabbcc", + "key": "ddeeff", + "auth_data": "112233", + "signature": "44556677", + "signed_by": "whosigned", + }) + + def test_props(self): + self.assertEqual("thename", self.elem.name) + self.assertEqual("whosigned", self.elem.signed_by) + self.assertEqual("aabbcc", self.elem.message) + self.assertEqual("ddeeff", self.elem.key) + self.assertEqual("112233", self.elem.auth_data) + self.assertEqual("44556677", self.elem.signature) + def test_dict_ok(self): - elem = HSMCertificateV2ElementSGXAttestationKey( - "thename", - bytes.fromhex("aabbcc"), - bytes.fromhex("ddeeff"), - bytes.fromhex("112233"), - bytes.fromhex("44556677"), - "whosigned" - ) self.assertEqual({ "name": "thename", "type": "sgx_attestation_key", @@ -73,19 +172,100 @@ def test_dict_ok(self): "auth_data": "112233", "signature": "44556677", "signed_by": "whosigned", - }, elem.to_dict()) + }, self.elem.to_dict()) + + def test_parse_identity(self): + source = TEST_CERTIFICATE["elements"][1] + elem = HSMCertificateV2Element.from_dict(source) + self.assertTrue(isinstance(elem, HSMCertificateV2ElementSGXAttestationKey)) + self.assertEqual(source, elem.to_dict()) + + def test_from_dict_invalid_message(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "attestation", + "type": "sgx_attestation_key", + "message": "not-hex", + "key": "eeff", + "auth_data": "112233", + "signature": "44556677", + "signed_by": "quoting_enclave" + }) + self.assertIn("Invalid message", str(e.exception)) + + def test_from_dict_invalid_key(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "attestation", + "type": "sgx_attestation_key", + "message": "aabbccdd", + "key": "not-hex", + "auth_data": "112233", + "signature": "44556677", + "signed_by": "quoting_enclave" + }) + self.assertIn("Invalid key", str(e.exception)) + + def test_from_dict_invalid_auth_data(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "attestation", + "type": "sgx_attestation_key", + "message": "aabbccdd", + "key": "eeff", + "auth_data": "not-hex", + "signature": "44556677", + "signed_by": "quoting_enclave" + }) + self.assertIn("Invalid auth data", str(e.exception)) + + def test_from_dict_invalid_signature(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "attestation", + "type": "sgx_attestation_key", + "message": "aabbccdd", + "key": "eeff", + "auth_data": "112233", + "signature": "not-hex", + "signed_by": "quoting_enclave" + }) + self.assertIn("Invalid signature", str(e.exception)) class TestHSMCertificateV2ElementX509(TestCase): + def setUp(self): + self.elem = HSMCertificateV2ElementX509({ + "name": "thename", + "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", + "signed_by": "whosigned", + }) + + def test_props(self): + self.assertEqual("thename", self.elem.name) + self.assertEqual("whosigned", self.elem.signed_by) + self.assertEqual("dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", self.elem.message) + def test_dict_ok(self): - elem = HSMCertificateV2ElementX509( - "thename", - b"this is an ascii message", - "whosigned" - ) self.assertEqual({ "name": "thename", "type": "x509_pem", - "message": "this is an ascii message", + "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", "signed_by": "whosigned", - }, elem.to_dict()) + }, self.elem.to_dict()) + + def test_parse_identity(self): + source = TEST_CERTIFICATE["elements"][3] + elem = HSMCertificateV2Element.from_dict(source) + self.assertTrue(isinstance(elem, HSMCertificateV2ElementX509)) + self.assertEqual(source, elem.to_dict()) + + def test_from_dict_invalid_message(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "quoting_enclave", + "type": "x509_pem", + "message": "not-base-64", + "signed_by": "platform_ca" + }) + self.assertIn("Invalid message", str(e.exception)) diff --git a/middleware/tests/admin/test_certificate_v2_resources.py b/middleware/tests/admin/test_certificate_v2_resources.py new file mode 100644 index 00000000..4717248a --- /dev/null +++ b/middleware/tests/admin/test_certificate_v2_resources.py @@ -0,0 +1,63 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import json + +TEST_CERTIFICATE = json.loads(""" +{ + "version": 2, + "targets": [ + "quote" + ], + "elements": [ + { + "name": "quote", + "type": "sgx_quote", + "message": "03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ceae3549bc7273eb34d562f4564fc182000000000e0e100fffff01000000000000000000010000000000000000000000000000000000000000000000000000000000000005000000000000000700000000000000d32688d3c1f3dfcc8b0b36eac7c89d49af331800bd56248044166fa6699442c10000000000000000000000000000000000000000000000000000000000000000718c2f1a0efbd513e016fafd6cf62a624442f2d83708d4b33ab5a8d8c1cd4dd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000640001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009e95bb875c1a728071f70ad8c9d03f1744c19acb0580921e611ac9104f7701d00000000000000000000000000000000000000000000000000000000000000000", + "custom_data": "504f5748534d3a352e343a3a736778f36f7bc09aab50c0886a442b2d04b18186720bda7a753643066cd0bc0a4191800c4d091913d39750dc8975adbdd261bd10c1c2e110faa47cfbe30e740895552bbdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b00000000000000000000000000000000", + "signature": "3046022100e52b03a7bd6b5dd9feeeb375bd597730d2872643b47aff4dd641c5c3a2b8016e022100bbd227f67e7c23bbddeb4f8fddee031a2b961501d1c28dda082669d7ac861e6c", + "signed_by": "attestation" + }, + { + "name": "attestation", + "type": "sgx_attestation_key", + "message": "0e0e100fffff0100000000000000000000000000000000000000000000000000000000000000000000000000000000001500000000000000e70000000000000096b347a64e5a045e27369c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e400000000000000000000000000000000000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8ded70140b081b094490c57bff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fe721d0322954821589237fd27efb8fef1acb3ecd6b0352c31271550fc70f940000000000000000000000000000000000000000000000000000000000000000", + "key": "04a024cb34c90ea6a8f9f2181c9020cbcc7c073e69981733c8deed6f6c451822aa08376350ff7da01f842bb40c631cbb711f8b6f7a4fae398320a3884774d250ad", + "auth_data": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "signature": "304502201f14d532274c4385fc0019ca2a21e53e17143cb62377ca4fcdd97fa9fef8fb2502210095d4ee272cf3c512e36779de67dc7814982f1160d981d138a32b265e928a0562", + "signed_by": "quoting_enclave" + }, + { + "name": "quoting_enclave", + "type": "x509_pem", + "message": "MIIE8zCCBJigAwIBAgIUfr2dlwN42DBUA9CXIkBlGP2vV3AwCgYIKoZIzj0EAwIwcDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBDSyBQbGF0Zm9ybSBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMwHhcNMjQwMzIzMDQ0NjIxWhcNMzEwMzIzMDQ0NjIxWjBwMSIwIAYDVQQDDBlJbnRlbCBTR1ggUENLIENlcnRpZmljYXRlMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKl7RDNlsZKkEtAcW7SfCX1JegbvGq4O0rRUt0z/G6fZJsNlpmRwTB4DYkrgkm1t+9RpLwxFX9/kghxiDQm0jqmjggMOMIIDCjAfBgNVHSMEGDAWgBSVb13NvRvh6UBJydT0M84BVwveVDBrBgNVHR8EZDBiMGCgXqBchlpodHRwczovL2FwaS50cnVzdGVkc2VydmljZXMuaW50ZWwuY29tL3NneC9jZXJ0aWZpY2F0aW9uL3Y0L3Bja2NybD9jYT1wbGF0Zm9ybSZlbmNvZGluZz1kZXIwHQYDVR0OBBYEFALKV5DF16KnEbSW5QM9ecDqBZaHMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMIICOwYJKoZIhvhNAQ0BBIICLDCCAigwHgYKKoZIhvhNAQ0BAQQQttJXuiQVwqM4s74g+HxfKTCCAWUGCiqGSIb4TQENAQIwggFVMBAGCyqGSIb4TQENAQIBAgEOMBAGCyqGSIb4TQENAQICAgEOMBAGCyqGSIb4TQENAQIDAgEDMBAGCyqGSIb4TQENAQIEAgEDMBEGCyqGSIb4TQENAQIFAgIA/zARBgsqhkiG+E0BDQECBgICAP8wEAYLKoZIhvhNAQ0BAgcCAQEwEAYLKoZIhvhNAQ0BAggCAQAwEAYLKoZIhvhNAQ0BAgkCAQAwEAYLKoZIhvhNAQ0BAgoCAQAwEAYLKoZIhvhNAQ0BAgsCAQAwEAYLKoZIhvhNAQ0BAgwCAQAwEAYLKoZIhvhNAQ0BAg0CAQAwEAYLKoZIhvhNAQ0BAg4CAQAwEAYLKoZIhvhNAQ0BAg8CAQAwEAYLKoZIhvhNAQ0BAhACAQAwEAYLKoZIhvhNAQ0BAhECAQ0wHwYLKoZIhvhNAQ0BAhIEEA4OAwP//wEAAAAAAAAAAAAwEAYKKoZIhvhNAQ0BAwQCAAAwFAYKKoZIhvhNAQ0BBAQGAGBqAAAAMA8GCiqGSIb4TQENAQUKAQEwHgYKKoZIhvhNAQ0BBgQQDVe/DXUVE4gemtgO5uBpvDBEBgoqhkiG+E0BDQEHMDYwEAYLKoZIhvhNAQ0BBwEBAf8wEAYLKoZIhvhNAQ0BBwIBAQAwEAYLKoZIhvhNAQ0BBwMBAQAwCgYIKoZIzj0EAwIDSQAwRgIhAJFgf78HggTBtvQPXZJx/3Fm71vCOmt82pce91M2ZAI0AiEAiZMPBbZZmvR2v+1mrs76JeglDQ+pK/SLN94l4+jM5DA=", + "signed_by": "platform_ca" + }, + { + "name": "platform_ca", + "type": "x509_pem", + "message": "MIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMCMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAgBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJleTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9dzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1UenA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+", + "signed_by": "sgx_root" + } + ] +} +""") diff --git a/middleware/tests/admin/test_sgx_attestation.py b/middleware/tests/admin/test_sgx_attestation.py index 4b60fadb..78d1e8de 100644 --- a/middleware/tests/admin/test_sgx_attestation.py +++ b/middleware/tests/admin/test_sgx_attestation.py @@ -65,7 +65,7 @@ def setupMocks(self, get_hsm, get_ud_value_for_attestation, do_unlock, "envelope": "11"*32, "message": "22"*32, } - quote = SimpleNamespace(**{"get_raw_data": lambda: "quote-raw-data"}) + quote = SimpleNamespace(**{"get_raw_data": lambda: b"quote-raw-data"}) sig = SimpleNamespace(**{"r": b"a"*32, "s": b"a"*32}) self.att_key = ecdsa.SigningKey.generate(curve=ecdsa.NIST256p).\ get_verifying_key() @@ -76,11 +76,11 @@ def setupMocks(self, get_hsm, get_ud_value_for_attestation, do_unlock, "signature": sig, "attestation_key": attkey, "qe_report_body": SimpleNamespace(**{ - "get_raw_data": lambda: "qerb-raw-data"}), + "get_raw_data": lambda: b"qerb-raw-data"}), "qe_report_body_signature": qesig, }) qead = SimpleNamespace(**{ - "data": "qead-data", + "data": b"qead-data", }) qecd = SimpleNamespace(**{ "certs": ["qecd-cert-0", "qecd-cert-1"], @@ -90,7 +90,7 @@ def setupMocks(self, get_hsm, get_ud_value_for_attestation, do_unlock, "quote_auth_data": qad, "qe_auth_data": qead, "qe_cert_data": qecd, - "custom_message": "a-custom-message", + "custom_message": b"a-custom-message", }) self.SgxEnvelope.return_value = envelope @@ -123,32 +123,32 @@ def test_ok(self, *args): bytes.fromhex("11"*32), bytes.fromhex("22"*32), ) - self.HSMCertificateV2ElementSGXQuote.assert_called_with( - name="quote", - message="quote-raw-data", - custom_data="a-custom-message", - signature=bytes.fromhex("30440220"+"61"*32+"0220"+"61"*32), - signed_by="attestation", - ) - self.HSMCertificateV2ElementSGXAttestationKey.assert_called_with( - name="attestation", - message="qerb-raw-data", - key=self.att_key.to_string("uncompressed"), - auth_data="qead-data", - signature=bytes.fromhex("30440220"+"63"*32+"0220"+"63"*32), - signed_by="quoting_enclave", - ) + self.HSMCertificateV2ElementSGXQuote.assert_called_with({ + "name": "quote", + "message": b"quote-raw-data".hex(), + "custom_data": b"a-custom-message".hex(), + "signature": "30440220"+"61"*32+"0220"+"61"*32, + "signed_by": "attestation", + }) + self.HSMCertificateV2ElementSGXAttestationKey.assert_called_with({ + "name": "attestation", + "message": b"qerb-raw-data".hex(), + "key": self.att_key.to_string("uncompressed").hex(), + "auth_data": b"qead-data".hex(), + "signature": "30440220"+"63"*32+"0220"+"63"*32, + "signed_by": "quoting_enclave", + }) self.HSMCertificateV2ElementX509.assert_has_calls([ - call( - name="quoting_enclave", - message="qecd-cert-0", - signed_by="platform_ca", - ), - call( - name="platform_ca", - message="qecd-cert-1", - signed_by="sgx_root", - ) + call({ + "name": "quoting_enclave", + "message": "qecd-cert-0", + "signed_by": "platform_ca", + }), + call({ + "name": "platform_ca", + "message": "qecd-cert-1", + "signed_by": "sgx_root", + }) ]) cert = self.HSMCertificateV2.return_value cert.add_element.assert_has_calls([ diff --git a/setup.cfg b/setup.cfg index da90c29b..36a420ae 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,6 +26,7 @@ per-file-ignores = __init__.py:F401, middleware/admin/certificate.py:F401, middleware/tests/sgx/test_envelope.py:E122, + middleware/tests/admin/test_certificate_v2_resources.py:E501, show-source = False statistics = True From 6f54ca3c0a851362fa5b425809131732cc3deed9 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 24 Dec 2024 00:30:50 +1300 Subject: [PATCH 31/50] Certificate v2 validator (#231) - Replacing plain public key in validate_and_get_values method for a root of trust object with get_pubkey method - Using inherited validate_and_get_values in HSMCertificateV2 - Added HSMCertificateRoot to certificate version 1 to act as root of trust in existing validations - Updated verify ledger attestation accordingly - Added and updated unit tests --- middleware/admin/certificate.py | 2 +- middleware/admin/certificate_v1.py | 42 +++++++++++------ middleware/admin/certificate_v2.py | 26 ++++++++--- middleware/admin/verify_ledger_attestation.py | 6 ++- middleware/tests/admin/test_certificate_v1.py | 45 +++---------------- .../admin/test_certificate_v1_element.py | 22 +++++++-- middleware/tests/admin/test_certificate_v2.py | 12 +++++ 7 files changed, 90 insertions(+), 65 deletions(-) diff --git a/middleware/admin/certificate.py b/middleware/admin/certificate.py index 1321a0b2..ad14cbd6 100644 --- a/middleware/admin/certificate.py +++ b/middleware/admin/certificate.py @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from .certificate_v1 import HSMCertificate, HSMCertificateElement +from .certificate_v1 import HSMCertificate, HSMCertificateRoot, HSMCertificateElement from .certificate_v2 import HSMCertificateV2, HSMCertificateV2ElementSGXQuote, \ HSMCertificateV2ElementSGXAttestationKey, \ HSMCertificateV2ElementX509 diff --git a/middleware/admin/certificate_v1.py b/middleware/admin/certificate_v1.py index 414fe8f3..842793a0 100644 --- a/middleware/admin/certificate_v1.py +++ b/middleware/admin/certificate_v1.py @@ -27,6 +27,21 @@ from .utils import is_nonempty_hex_string +class HSMCertificateRoot: + def __init__(self, raw_pubkey_hex): + # Parse the public key + try: + self.pubkey = ec.PublicKey(bytes.fromhex(raw_pubkey_hex), raw=True) + except Exception: + raise ValueError("Error parsing certificate root public key") + + def __repr__(self): + return self.pubkey.serialize(compressed=False).hex() + + def get_pubkey(self): + return self.pubkey + + class HSMCertificateElement: VALID_NAMES = ["device", "attestation", "ui", "signer"] EXTRACTORS = { @@ -98,10 +113,11 @@ def to_dict(self): return result - def is_valid(self, certifier_pubkey): + def is_valid(self, certifier): try: message = bytes.fromhex(self.message) + certifier_pubkey = certifier.get_pubkey() verifier_pubkey = certifier_pubkey if self.tweak is not None: tweak = hmac.new( @@ -120,6 +136,12 @@ def is_valid(self, certifier_pubkey): def get_value(self): return self.EXTRACTORS[self.name](bytes.fromhex(self.message)).hex() + def get_pubkey(self): + return ec.PublicKey(bytes.fromhex(self.get_value()), raw=True) + + def get_tweak(self): + return self.tweak + class HSMCertificate: VERSION = 1 # Only supported version @@ -155,14 +177,7 @@ def __init__(self, certificate_map=None): if certificate_map is not None: self._parse(certificate_map) - def validate_and_get_values(self, raw_root_pubkey_hex): - # Parse the root public key - try: - root_pubkey = ec.PublicKey(bytes.fromhex(raw_root_pubkey_hex), raw=True) - except Exception: - return dict([(target, (False, self.ROOT_ELEMENT)) - for target in self._targets]) - + def validate_and_get_values(self, root_of_trust): result = {} for target in self._targets: # Build the chain from the target to the root @@ -178,19 +193,18 @@ def validate_and_get_values(self, raw_root_pubkey_hex): # If valid, return True and the value of the leaf # If not valid, return False and the name of the element that # failed the validation - current_pubkey = root_pubkey + current_certifier = root_of_trust while True: # Validate this element - if not current.is_valid(current_pubkey): + if not current.is_valid(current_certifier): result[target] = (False, current.name) break # Reached the leaf? => valid! if len(chain) == 0: - result[target] = (True, current.get_value(), current.tweak) + result[target] = (True, current.get_value(), current.get_tweak()) break - current_pubkey = ec.PublicKey(bytes.fromhex(current.get_value()), - raw=True) + current_certifier = current current = chain.pop() return result diff --git a/middleware/admin/certificate_v2.py b/middleware/admin/certificate_v2.py index a7b58f7c..ca343025 100644 --- a/middleware/admin/certificate_v2.py +++ b/middleware/admin/certificate_v2.py @@ -27,8 +27,7 @@ class HSMCertificateV2Element: def __init__(self): - raise RuntimeError("Cannot instantiate an " - "abstract HSMCertificateV2Element") + raise NotImplementedError("Cannot instantiate a HSMCertificateV2Element") @classmethod def from_dict(kls, element_map): @@ -56,6 +55,22 @@ def name(self): def signed_by(self): return self._signed_by + def get_value(self): + raise NotImplementedError(f"{type(self).__name__} can't provide a value") + + def get_pubkey(self): + # TODO: this should yield not implemented + # TODO: implementation should be down to each specific subclass + return None + + def is_valid(self, certifier): + # TODO: this should yield not implemented + # TODO: implementation should be down to each specific subclass + return True + + def get_tweak(self): + return None + class HSMCertificateV2ElementSGXQuote(HSMCertificateV2Element): def __init__(self, element_map): @@ -89,6 +104,9 @@ def custom_data(self): def signature(self): return self._signature.hex() + def get_value(self): + return self.custom_data + def to_dict(self): return { "name": self.name, @@ -189,7 +207,3 @@ class HSMCertificateV2(HSMCertificate): ROOT_ELEMENT = "sgx_root" ELEMENT_BASE_CLASS = HSMCertificateV2Element ELEMENT_FACTORY = HSMCertificateV2Element.from_dict - - def validate_and_get_values(self, raw_root_pubkey_hex): - # TODO - pass diff --git a/middleware/admin/verify_ledger_attestation.py b/middleware/admin/verify_ledger_attestation.py index f09f99c2..d9f7ffd0 100644 --- a/middleware/admin/verify_ledger_attestation.py +++ b/middleware/admin/verify_ledger_attestation.py @@ -26,7 +26,7 @@ import re from .misc import info, head, AdminError from .utils import is_nonempty_hex_string -from .certificate import HSMCertificate +from .certificate import HSMCertificate, HSMCertificateRoot UI_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:UI:(5.[0-9])") @@ -69,6 +69,10 @@ def do_verify_attestation(options): if not is_nonempty_hex_string(options.root_authority): raise AdminError("Invalid root authority") root_authority = options.root_authority + try: + root_authority = HSMCertificateRoot(root_authority) + except ValueError: + raise AdminError("Invalid root authority") info(f"Using {root_authority} as root authority") # Load the given public keys and compute diff --git a/middleware/tests/admin/test_certificate_v1.py b/middleware/tests/admin/test_certificate_v1.py index 8235850a..c6ab1ea0 100644 --- a/middleware/tests/admin/test_certificate_v1.py +++ b/middleware/tests/admin/test_certificate_v1.py @@ -26,7 +26,7 @@ from unittest import TestCase from unittest.mock import call, patch, mock_open -from admin.certificate import HSMCertificate, HSMCertificateElement +from admin.certificate import HSMCertificate, HSMCertificateRoot, HSMCertificateElement class TestHSMCertificate(TestCase): @@ -240,6 +240,7 @@ def test_create_certificate_signer_not_in_elements(self): def test_validate_and_get_values_ok(self): root_privkey = ec.PrivateKey() root_pubkey = root_privkey.pubkey.serialize(compressed=False).hex() + root_of_trust = HSMCertificateRoot(root_pubkey) device_privkey = ec.PrivateKey() device_pubkey = device_privkey.pubkey.serialize(compressed=False).hex() att_pubkey = ec.PrivateKey().pubkey.serialize(compressed=False).hex() @@ -273,48 +274,12 @@ def test_validate_and_get_values_ok(self): self.assertEqual({ 'attestation': (True, att_pubkey, None), 'device': (True, device_pubkey, None) - }, cert.validate_and_get_values(root_pubkey)) - - def test_create_and_get_values_invalid_pubkey(self): - root_privkey = ec.PrivateKey() - device_privkey = ec.PrivateKey() - device_pubkey = device_privkey.pubkey.serialize(compressed=False).hex() - att_pubkey = ec.PrivateKey().pubkey.serialize(compressed=False).hex() - - att_msg = 'ff' + att_pubkey - att_sig = device_privkey.ecdsa_serialize( - device_privkey.ecdsa_sign(bytes.fromhex(att_msg))).hex() - - device_msg = os.urandom(16).hex() + device_pubkey - device_sig = root_privkey.ecdsa_serialize( - root_privkey.ecdsa_sign(bytes.fromhex(device_msg))).hex() - - cert = HSMCertificate({ - "version": 1, - "targets": ["attestation", "device"], - "elements": [ - { - "name": "attestation", - "message": att_msg, - "signature": att_sig, - "signed_by": "device" - }, - { - "name": "device", - "message": device_msg, - "signature": device_sig, - "signed_by": "root" - }] - }) - - self.assertEqual({ - 'attestation': (False, 'root'), - 'device': (False, 'root') - }, cert.validate_and_get_values('invalid-pubkey')) + }, cert.validate_and_get_values(root_of_trust)) def test_validate_and_get_values_invalid_element(self): root_privkey = ec.PrivateKey() root_pubkey = root_privkey.pubkey.serialize(compressed=False).hex() + root_of_trust = HSMCertificateRoot(root_pubkey) device_privkey = ec.PrivateKey() device_pubkey = device_privkey.pubkey.serialize(compressed=False).hex() att_pubkey = ec.PrivateKey().pubkey.serialize(compressed=False).hex() @@ -347,7 +312,7 @@ def test_validate_and_get_values_invalid_element(self): self.assertEqual({ 'attestation': (False, 'attestation'), 'device': (True, device_pubkey, None) - }, cert.validate_and_get_values(root_pubkey)) + }, cert.validate_and_get_values(root_of_trust)) def test_validate_and_get_values_invalid_elements(self): att_privkey = ec.PrivateKey() diff --git a/middleware/tests/admin/test_certificate_v1_element.py b/middleware/tests/admin/test_certificate_v1_element.py index ff2f206c..716f0dfb 100644 --- a/middleware/tests/admin/test_certificate_v1_element.py +++ b/middleware/tests/admin/test_certificate_v1_element.py @@ -27,7 +27,21 @@ import secp256k1 as ec from unittest import TestCase -from admin.certificate import HSMCertificateElement +from unittest.mock import Mock +from admin.certificate import HSMCertificateRoot, HSMCertificateElement + + +class TestHSMCertificateRoot(TestCase): + def test_ok(self): + pubkey = ec.PrivateKey().pubkey + root = HSMCertificateRoot(pubkey.serialize(compressed=False).hex()) + self.assertEqual( + pubkey.serialize(compressed=True), + root.get_pubkey().serialize(compressed=True)) + + def test_invalid_pubkey(self): + with self.assertRaises(ValueError): + HSMCertificateRoot("invalid-pubkey") class TestHSMCertificateElement(TestCase): @@ -100,6 +114,7 @@ def test_certificate_element_is_valid_ok(self): privkey = ec.PrivateKey() msg = 'aa' * 65 signature = privkey.ecdsa_serialize(privkey.ecdsa_sign(bytes.fromhex(msg))).hex() + mock_certifier = Mock(get_pubkey=lambda: privkey.pubkey) element = HSMCertificateElement({ "name": "device", @@ -113,7 +128,7 @@ def test_certificate_element_is_valid_ok(self): "signature": signature, "signed_by": "root" }, element.to_dict()) - self.assertTrue(element.is_valid(privkey.pubkey)) + self.assertTrue(element.is_valid(mock_certifier)) def test_certificate_element_is_valid_with_tweak_ok(self): privkey = ec.PrivateKey() @@ -124,6 +139,7 @@ def test_certificate_element_is_valid_with_tweak_ok(self): pubkey.serialize(compressed=False), hashlib.sha256, ).digest() + mock_certifier = Mock(get_pubkey=lambda: pubkey) tweak_privkey = ec.PrivateKey(privkey.tweak_add(tweak), raw=True) msg = os.urandom(66).hex() @@ -144,7 +160,7 @@ def test_certificate_element_is_valid_with_tweak_ok(self): "signed_by": "root", "tweak": raw_tweak }, element.to_dict()) - self.assertTrue(element.is_valid(pubkey)) + self.assertTrue(element.is_valid(mock_certifier)) def test_certificate_element_is_valid_wrong_signature(self): privkey = ec.PrivateKey() diff --git a/middleware/tests/admin/test_certificate_v2.py b/middleware/tests/admin/test_certificate_v2.py index ada5c485..ed7c0c8d 100644 --- a/middleware/tests/admin/test_certificate_v2.py +++ b/middleware/tests/admin/test_certificate_v2.py @@ -41,6 +41,18 @@ def test_parse_identity(self): cert = HSMCertificateV2(TEST_CERTIFICATE) self.assertEqual(TEST_CERTIFICATE, cert.to_dict()) + def test_validate_and_get_values_value(self): + cert = HSMCertificateV2(TEST_CERTIFICATE) + self.assertEqual({ + "quote": ( + True, + "504f5748534d3a352e343a3a736778f36f7bc09aab50c0886a442b2d04b18186720bd" + "a7a753643066cd0bc0a4191800c4d091913d39750dc8975adbdd261bd10c1c2e110fa" + "a47cfbe30e740895552bbdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6" + "e7191f67ea4209b00000000000000000000000000000000", + None) + }, cert.validate_and_get_values('a-root-of-trust')) + class TestHSMCertificateV2Element(TestCase): def test_from_dict_unknown_type(self): From 304212707c6bc64b171928a5cf50c50b7b2b4e8f Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Sat, 28 Dec 2024 02:06:33 +1300 Subject: [PATCH 32/50] SGX attestation validation (#232) - Added message parsing capabilities to HSMCertificateV2ElementSGXQuote - Added file certificate loading capabilities to HSMCertificateV2ElementX509 - Factored out common behavior between ledger and SGX attestation verification into helper library functions - Added helper library for assorted attestation utils, including a v5+ attestation message parsing class - Added SGX do_verify_attestation function with its corresponding module - Added verify_attestation operation to adm_sgx tool - Added and updated unit tests - Ignoring long line warnings for test attestation utils resources module --- middleware/adm_sgx.py | 26 +- middleware/admin/attestation_utils.py | 143 ++++++++++ middleware/admin/certificate_v2.py | 23 +- middleware/admin/verify_ledger_attestation.py | 119 +++----- middleware/admin/verify_sgx_attestation.py | 125 ++++++++ middleware/tests/admin/test_adm_sgx.py | 15 +- .../tests/admin/test_attestation_utils.py | 269 ++++++++++++++++++ .../admin/test_attestation_utils_resources.py | 36 +++ middleware/tests/admin/test_certificate_v2.py | 58 +++- .../admin/test_verify_ledger_attestation.py | 177 +++++------- .../admin/test_verify_sgx_attestation.py | 241 ++++++++++++++++ setup.cfg | 1 + 12 files changed, 1034 insertions(+), 199 deletions(-) create mode 100644 middleware/admin/attestation_utils.py create mode 100644 middleware/admin/verify_sgx_attestation.py create mode 100644 middleware/tests/admin/test_attestation_utils.py create mode 100644 middleware/tests/admin/test_attestation_utils_resources.py create mode 100644 middleware/tests/admin/test_verify_sgx_attestation.py diff --git a/middleware/adm_sgx.py b/middleware/adm_sgx.py index d6a8f289..7090c5c8 100644 --- a/middleware/adm_sgx.py +++ b/middleware/adm_sgx.py @@ -31,6 +31,7 @@ from admin.pubkeys import do_get_pubkeys from admin.changepin import do_changepin from admin.sgx_attestation import do_attestation +from admin.verify_sgx_attestation import do_verify_attestation def main(): @@ -42,12 +43,13 @@ def main(): "pubkeys": do_get_pubkeys, "changepin": do_changepin, "attestation": do_attestation, + "verify_attestation": do_verify_attestation, } parser = ArgumentParser(description="SGX powHSM Administrative tool") parser.add_argument("operation", choices=list(actions.keys())) parser.add_argument( - "-r", + "-p", "--port", dest="sgx_port", help="SGX powHSM listening port (default 7777)", @@ -61,7 +63,7 @@ def main(): help="SGX powHSM host. (default 'localhost')", default="localhost", ) - parser.add_argument("-p", "--pin", dest="pin", help="PIN.") + parser.add_argument("-P", "--pin", dest="pin", help="PIN.") parser.add_argument( "-n", "--newpin", @@ -103,6 +105,26 @@ def main(): f"{DEFAULT_ATT_UD_SOURCE}). Can also specify a 32-byte hex string to use as" " the value.", ) + parser.add_argument( + "-t", + "--attcert", + dest="attestation_certificate_file_path", + help="Attestation key certificate file (only valid for " + "'verify_attestation' operation).", + ) + parser.add_argument( + "-r", + "--root", + dest="root_authority", + help="Root attestation authority (only valid for 'verify_attestation' " + "operation). Defaults to Intel SGX's root authority.", + ) + parser.add_argument( + "-b", + "--pubkeys", + dest="pubkeys_file_path", + help="Public keys file (only valid for 'verify_attestation' operation).", + ) parser.add_argument( "-v", "--verbose", diff --git a/middleware/admin/attestation_utils.py b/middleware/admin/attestation_utils.py new file mode 100644 index 00000000..d9d31387 --- /dev/null +++ b/middleware/admin/attestation_utils.py @@ -0,0 +1,143 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import hashlib +import json +import re +import secp256k1 as ec +import requests +from pathlib import Path +from comm.cstruct import CStruct +from .misc import AdminError +from .certificate_v2 import HSMCertificateV2, HSMCertificateV2ElementX509 + + +class PowHsmAttestationMessage(CStruct): + """ + pow_hsm_message_header + + uint8_t platform 3 + uint8_t ud_value 32 + uint8_t public_keys_hash 32 + uint8_t best_block 32 + uint8_t last_signed_tx 8 + uint8_t timestamp 8 + """ + + HEADER_REGEX = re.compile(b"^POWHSM:(5.[0-9])::") + + @classmethod + def is_header(kls, value): + return kls.HEADER_REGEX.match(value) is not None + + def __init__(self, value, offset=0, little=True, name="powHSM"): + self.name = name + # Parse header + match = self.HEADER_REGEX.match(value) + if match is None: + raise ValueError( + f"Invalid {self.name} attestation message header: {value.hex()}") + + # Validate total length + header_length = len(match.group(0)) + expected_length = header_length + self.get_bytelength() + if len(value[offset:]) != expected_length: + raise ValueError(f"{self.name} attestation message length " + f"mismatch: {value[offset:].hex()}") + + # Grab version + self.version = match.group(1).decode("ASCII") + + # Parse the rest + super().__init__(value, offset+header_length, little) + + # Conversions + self.platform = self.platform.decode("ASCII") + self.timestamp = int.from_bytes(self.timestamp, byteorder="big", signed=False) + + +def load_pubkeys(pubkeys_file_path): + # Load the given public keys file into a map + try: + with open(pubkeys_file_path, "r") as file: + pubkeys_map = json.loads(file.read()) + + if type(pubkeys_map) != dict: + raise AdminError( + "Public keys file must contain an object as a top level element") + + result = {} + for path in pubkeys_map.keys(): + pubkey = pubkeys_map[path] + try: + pubkey = ec.PublicKey(bytes.fromhex(pubkey), raw=True) + except Exception: + raise AdminError(f"Invalid public key for path {path}: {pubkey}") + result[path] = pubkey + return result + except (FileNotFoundError, ValueError, json.JSONDecodeError) as e: + raise AdminError('Unable to read public keys from "%s": %s' % + (pubkeys_file_path, str(e))) + + +def compute_pubkeys_hash(pubkeys_map): + # Compute the given public keys hash + # (sha256sum of the uncompressed public keys in + # lexicographical path order) + if len(pubkeys_map) == 0: + raise AdminError("Can't compute the hash of an empty public keys map") + + pubkeys_hash = hashlib.sha256() + for path in sorted(pubkeys_map.keys()): + pubkey = pubkeys_map[path] + pubkeys_hash.update(pubkey.serialize(compressed=False)) + return pubkeys_hash.digest() + + +def compute_pubkeys_output(pubkeys_map): + pubkeys_output = [] + path_name_padding = max(map(len, pubkeys_map.keys())) + for path in sorted(pubkeys_map.keys()): + pubkey = pubkeys_map[path] + pubkeys_output.append( + f"{(path + ':').ljust(path_name_padding+1)} " + f"{pubkey.serialize(compressed=True).hex()}" + ) + return pubkeys_output + + +def get_root_of_trust(path): + # From file + if Path(path).is_file(): + return HSMCertificateV2ElementX509.from_pemfile( + path, + HSMCertificateV2.ROOT_ELEMENT, + HSMCertificateV2.ROOT_ELEMENT) + + # Assume URL and try to grab it + ra_res = requests.get(path) + if ra_res.status_code != 200: + raise RuntimeError(f"Error fetching root of trust from {path}") + return HSMCertificateV2ElementX509.from_pem( + ra_res.content.decode(), + HSMCertificateV2.ROOT_ELEMENT, + HSMCertificateV2.ROOT_ELEMENT) diff --git a/middleware/admin/certificate_v2.py b/middleware/admin/certificate_v2.py index ca343025..e84591d2 100644 --- a/middleware/admin/certificate_v2.py +++ b/middleware/admin/certificate_v2.py @@ -20,9 +20,12 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import re +from pathlib import Path import base64 from .certificate_v1 import HSMCertificate from .utils import is_nonempty_hex_string +from sgx.envelope import SgxQuote class HSMCertificateV2Element: @@ -105,7 +108,10 @@ def signature(self): return self._signature.hex() def get_value(self): - return self.custom_data + return { + "sgx_quote": SgxQuote(self._message), + "message": self.custom_data, + } def to_dict(self): return { @@ -170,6 +176,21 @@ def to_dict(self): class HSMCertificateV2ElementX509(HSMCertificateV2Element): + @classmethod + def from_pemfile(kls, pem_path, name, signed_by): + return kls.from_pem(Path(pem_path).read_text(), name, signed_by) + + @classmethod + def from_pem(kls, pem_str, name, signed_by): + return kls({ + "name": name, + "message": re.sub(r"[\s\n\r]+", " ", pem_str) + .replace("-----END CERTIFICATE-----", "") + .replace("-----BEGIN CERTIFICATE-----", "") + .strip().encode(), + "signed_by": signed_by, + }) + def __init__(self, element_map): self._init_with_map(element_map) diff --git a/middleware/admin/verify_ledger_attestation.py b/middleware/admin/verify_ledger_attestation.py index d9f7ffd0..475a1ef5 100644 --- a/middleware/admin/verify_ledger_attestation.py +++ b/middleware/admin/verify_ledger_attestation.py @@ -20,32 +20,23 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import json -import hashlib -import secp256k1 as ec import re from .misc import info, head, AdminError +from .attestation_utils import PowHsmAttestationMessage, load_pubkeys, \ + compute_pubkeys_hash, compute_pubkeys_output from .utils import is_nonempty_hex_string from .certificate import HSMCertificate, HSMCertificateRoot -UI_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:UI:(5.[0-9])") -SIGNER_LEGACY_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:SIGNER:(5.[0-9])") +UI_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:UI:([2,3,4,5].[0-9])") +SIGNER_LEGACY_MESSAGE_HEADER_REGEX = re.compile(b"^HSM:SIGNER:([2,3,4,5].[0-9])") UI_DERIVATION_PATH = "m/44'/0'/0'/0/0" UD_VALUE_LENGTH = 32 +PUBLIC_KEYS_HASH_LENGTH = 32 PUBKEY_COMPRESSED_LENGTH = 33 SIGNER_HASH_LENGTH = 32 SIGNER_ITERATION_LENGTH = 2 -# New signer message header with fields -SIGNER_MESSAGE_HEADER_REGEX = re.compile(b"^POWHSM:(5.[0-9])::") -SM_PLATFORM_LEN = 3 -SM_UD_LEN = 32 -SM_PKH_LEN = 32 -SM_BB_LEN = 32 -SM_TXN_LEN = 8 -SM_TMSTMP_LEN = 8 - # Ledger's root authority # (according to # https://github.com/LedgerHQ/blue-loader-python/blob/master/ledgerblue/ @@ -75,45 +66,18 @@ def do_verify_attestation(options): raise AdminError("Invalid root authority") info(f"Using {root_authority} as root authority") - # Load the given public keys and compute - # their hash (sha256sum of the uncompressed - # public keys in lexicographical path order) - # Also find and save the public key corresponding - # to the expected derivation path for the UI - # attestation - expected_ui_public_key = None - try: - with open(options.pubkeys_file_path, "r") as file: - pubkeys_map = json.loads(file.read()) - - if type(pubkeys_map) != dict: - raise ValueError( - "Public keys file must contain an object as a top level element") - - pubkeys_hash = hashlib.sha256() - pubkeys_output = [] - path_name_padding = max(map(len, pubkeys_map.keys())) - for path in sorted(pubkeys_map.keys()): - pubkey = pubkeys_map[path] - if not is_nonempty_hex_string(pubkey): - raise AdminError(f"Invalid public key for path {path}: {pubkey}") - pubkey = ec.PublicKey(bytes.fromhex(pubkey), raw=True) - pubkeys_hash.update(pubkey.serialize(compressed=False)) - pubkeys_output.append( - f"{(path + ':').ljust(path_name_padding+1)} " - f"{pubkey.serialize(compressed=True).hex()}" - ) - if path == UI_DERIVATION_PATH: - expected_ui_public_key = pubkey.serialize(compressed=True).hex() - pubkeys_hash = pubkeys_hash.digest() - - except (ValueError, json.JSONDecodeError) as e: - raise ValueError('Unable to read public keys from "%s": %s' % - (options.pubkeys_file_path, str(e))) + # Load public keys, compute their hash and format them for output + pubkeys_map = load_pubkeys(options.pubkeys_file_path) + pubkeys_hash = compute_pubkeys_hash(pubkeys_map) + pubkeys_output = compute_pubkeys_output(pubkeys_map) + # Find the expected UI public key + expected_ui_public_key = next(filter( + lambda pair: pair[0] == UI_DERIVATION_PATH, pubkeys_map.items()), (None, None))[1] if expected_ui_public_key is None: raise AdminError( f"Public key with path {UI_DERIVATION_PATH} not present in public key file") + expected_ui_public_key = expected_ui_public_key.serialize(compressed=True).hex() # Load the given attestation key certificate try: @@ -155,6 +119,10 @@ def do_verify_attestation(options): SIGNER_HASH_LENGTH + SIGNER_ITERATION_LENGTH] signer_iteration = int.from_bytes(signer_iteration, byteorder='big', signed=False) + if ui_public_key != expected_ui_public_key: + raise AdminError("Invalid UI attestation: unexpected public key reported. " + f"Expected {expected_ui_public_key} but got {ui_public_key}") + head( [ "UI verified with:", @@ -180,40 +148,31 @@ def do_verify_attestation(options): signer_message = bytes.fromhex(signer_result[1]) signer_hash = bytes.fromhex(signer_result[2]) lmh_match = SIGNER_LEGACY_MESSAGE_HEADER_REGEX.match(signer_message) - mh_match = SIGNER_MESSAGE_HEADER_REGEX.match(signer_message) - if lmh_match is None and mh_match is None: + if lmh_match is None and not PowHsmAttestationMessage.is_header(signer_message): raise AdminError( f"Invalid Signer attestation message header: {signer_message.hex()}") if lmh_match is not None: # Legacy header + powhsm_message = None hlen = len(lmh_match.group(0)) - signer_version = lmh_match.group(1) + signer_version = lmh_match.group(1).decode() offset = hlen reported_pubkeys_hash = signer_message[offset:] - offset += SM_PKH_LEN + offset += PUBLIC_KEYS_HASH_LENGTH + if signer_message[offset:] != b'': + raise AdminError(f"Signer attestation message longer " + f"than expected: {signer_message.hex()}") else: # New header - hlen = len(mh_match.group(0)) - signer_version = mh_match.group(1) - offset = hlen - reported_platform = signer_message[offset:offset+SM_PLATFORM_LEN] - offset += SM_PLATFORM_LEN - reported_ud_value = signer_message[offset:offset+SM_UD_LEN] - offset += SM_UD_LEN - reported_pubkeys_hash = signer_message[offset:offset+SM_PKH_LEN] - offset += SM_PKH_LEN - reported_best_block = signer_message[offset:offset+SM_BB_LEN] - offset += SM_BB_LEN - reported_txn_head = signer_message[offset:offset+SM_TXN_LEN] - offset += SM_TXN_LEN - reported_timestamp = signer_message[offset:offset+SM_TMSTMP_LEN] - offset += SM_TMSTMP_LEN - - if signer_message[offset:] != b'': - raise AdminError(f"Signer attestation message longer " - f"than expected: {signer_message.hex()}") - + try: + powhsm_message = PowHsmAttestationMessage(signer_message, name="Signer") + except ValueError as e: + raise AdminError(str(e)) + signer_version = powhsm_message.version + reported_pubkeys_hash = powhsm_message.public_keys_hash + + # Validations on extracted values if reported_pubkeys_hash != pubkeys_hash: raise AdminError( f"Signer attestation public keys hash mismatch: expected {pubkeys_hash.hex()}" @@ -224,16 +183,16 @@ def do_verify_attestation(options): f"Hash: {pubkeys_hash.hex()}", "", f"Installed Signer hash: {signer_hash.hex()}", - f"Installed Signer version: {signer_version.decode()}", + f"Installed Signer version: {signer_version}", ] - if mh_match is not None: + if powhsm_message is not None: signer_info += [ - f"Platform: {reported_platform.decode("ASCII")}", - f"UD value: {reported_ud_value.hex()}", - f"Best block: {reported_best_block.hex()}", - f"Last transaction signed: {reported_txn_head.hex()}", - f"Timestamp: {reported_timestamp.hex()}", + f"Platform: {powhsm_message.platform}", + f"UD value: {powhsm_message.ud_value.hex()}", + f"Best block: {powhsm_message.best_block.hex()}", + f"Last transaction signed: {powhsm_message.last_signed_tx.hex()}", + f"Timestamp: {powhsm_message.timestamp}", ] head( diff --git a/middleware/admin/verify_sgx_attestation.py b/middleware/admin/verify_sgx_attestation.py new file mode 100644 index 00000000..1e8672fb --- /dev/null +++ b/middleware/admin/verify_sgx_attestation.py @@ -0,0 +1,125 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from .misc import info, head, AdminError +from .attestation_utils import PowHsmAttestationMessage, load_pubkeys, \ + compute_pubkeys_hash, compute_pubkeys_output, \ + get_root_of_trust +from .certificate import HSMCertificate + + +# ################################################################################### +# As default root authority, we use the Provisioning Certification Root CA from Intel +# The Provisioning Certification Root CA is available for download +# from Intel, as described here: +# https://api.portal.trustedservices.intel.com/content/documentation.html + +DEFAULT_ROOT_AUTHORITY = "https://certificates.trustedservices.intel.com/"\ + "Intel_SGX_Provisioning_Certification_RootCA.pem" + +# ################################################################################### + + +def do_verify_attestation(options): + head("### -> Verify powHSM attestation", fill="#") + + if options.attestation_certificate_file_path is None: + raise AdminError("No attestation certificate file given") + + if options.pubkeys_file_path is None: + raise AdminError("No public keys file given") + + # Load root authority + root_authority = options.root_authority or DEFAULT_ROOT_AUTHORITY + info(f"Attempting to gather root authority from {root_authority}...") + try: + root_of_trust = get_root_of_trust(root_authority) + except Exception as e: + raise AdminError(f"Invalid root authority {root_authority}: {e}") + info(f"Using {root_authority} as root authority") + + # Load public keys, compute their hash and format them for output + try: + pubkeys_map = load_pubkeys(options.pubkeys_file_path) + pubkeys_hash = compute_pubkeys_hash(pubkeys_map) + pubkeys_output = compute_pubkeys_output(pubkeys_map) + except Exception as e: + raise AdminError(str(e)) + + # Load the given attestation key certificate + try: + att_cert = HSMCertificate.from_jsonfile(options.attestation_certificate_file_path) + except Exception as e: + raise AdminError(f"While loading the attestation certificate file: {str(e)}") + + # Validate the certificate using the given root authority + # (this should be *one of* Ledger's public keys) + result = att_cert.validate_and_get_values(root_of_trust) + + # powHSM specific validations + if "quote" not in result: + raise AdminError("Certificate does not contain a powHSM attestation") + + powhsm_result = result["quote"] + if not powhsm_result[0]: + raise AdminError( + f"Invalid powHSM attestation: error validating '{powhsm_result[1]}'") + powhsm_result = powhsm_result[1] + + sgx_quote = powhsm_result["sgx_quote"] + powhsm_message = bytes.fromhex(powhsm_result["message"]) + if not PowHsmAttestationMessage.is_header(powhsm_message): + raise AdminError( + f"Invalid powHSM attestation message header: {powhsm_message.hex()}") + + try: + powhsm_message = PowHsmAttestationMessage(powhsm_message) + except Exception as e: + raise AdminError(f"Error parsing powHSM attestation message: {str(e)}") + reported_pubkeys_hash = powhsm_message.public_keys_hash + + if reported_pubkeys_hash != pubkeys_hash: + raise AdminError( + f"powHSM attestation public keys hash mismatch: expected {pubkeys_hash.hex()}" + f" but attestation reports {reported_pubkeys_hash.hex()}" + ) + + signer_info = [ + f"Hash: {pubkeys_hash.hex()}", + "", + f"Installed powHSM MRENCLAVE: {sgx_quote.report_body.mrenclave.hex()}", + f"Installed powHSM MRSIGNER: {sgx_quote.report_body.mrsigner.hex()}", + f"Installed powHSM version: {powhsm_message.version}", + ] + + signer_info += [ + f"Platform: {powhsm_message.platform}", + f"UD value: {powhsm_message.ud_value.hex()}", + f"Best block: {powhsm_message.best_block.hex()}", + f"Last transaction signed: {powhsm_message.last_signed_tx.hex()}", + f"Timestamp: {powhsm_message.timestamp}", + ] + + head( + ["powHSM verified with public keys:"] + pubkeys_output + signer_info, + fill="-", + ) diff --git a/middleware/tests/admin/test_adm_sgx.py b/middleware/tests/admin/test_adm_sgx.py index 53c139cd..ca8427b6 100644 --- a/middleware/tests/admin/test_adm_sgx.py +++ b/middleware/tests/admin/test_adm_sgx.py @@ -40,6 +40,9 @@ def setUp(self): "new_pin": None, "no_unlock": False, "attestation_ud_source": "https://public-node.rsk.co", + "attestation_certificate_file_path": None, + "root_authority": None, + "pubkeys_file_path": None, "operation": None, "output_file_path": None, "pin": None, @@ -61,7 +64,7 @@ def test_unlock(self, do_unlock): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm_sgx.py', '-p', 'a-pin', 'unlock']): + with patch('sys.argv', ['adm_sgx.py', '-P', 'a-pin', 'unlock']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) @@ -89,7 +92,7 @@ def test_onboard(self, do_onboard): ] with patch('sys.argv', - ['adm_sgx.py', '-p', 'a-pin', 'onboard']): + ['adm_sgx.py', '-P', 'a-pin', 'onboard']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) @@ -119,7 +122,7 @@ def test_pubkeys(self, do_get_pubkeys): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm_sgx.py', '-p', 'a-pin', '-o', 'a-path', '-u', + with patch('sys.argv', ['adm_sgx.py', '-P', 'a-pin', '-o', 'a-path', '-u', '-s', '1.2.3.4', 'pubkeys']): with self.assertRaises(SystemExit) as e: main() @@ -154,8 +157,8 @@ def test_changepin(self, do_changepin): call(Namespace(**expected_options)) ] - with patch('sys.argv', ['adm_sgx.py', '-p', 'old-pin', '-n', 'new-pin', - '-r', '4567', '-a', 'changepin']): + with patch('sys.argv', ['adm_sgx.py', '-P', 'old-pin', '-n', 'new-pin', + '-p', '4567', '-a', 'changepin']): with self.assertRaises(SystemExit) as e: main() self.assertEqual(e.exception.code, 0) @@ -186,7 +189,7 @@ def test_attestation(self, do_attestation): ] with patch('sys.argv', ['adm_sgx.py', - '-p', 'a-pin', + '-P', 'a-pin', '-o', 'out-path', '--attudsource', 'user-defined-source', 'attestation']): diff --git a/middleware/tests/admin/test_attestation_utils.py b/middleware/tests/admin/test_attestation_utils.py new file mode 100644 index 00000000..790fa505 --- /dev/null +++ b/middleware/tests/admin/test_attestation_utils.py @@ -0,0 +1,269 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from types import SimpleNamespace +import secp256k1 as ec +from unittest import TestCase +from unittest.mock import patch, mock_open +from parameterized import parameterized +from admin.attestation_utils import AdminError, PowHsmAttestationMessage, load_pubkeys, \ + compute_pubkeys_hash, compute_pubkeys_output, \ + get_root_of_trust +from .test_attestation_utils_resources import TEST_PUBKEYS_JSON, \ + TEST_PUBKEYS_JSON_INVALID +import logging + +logging.disable(logging.CRITICAL) + + +class TestPowHsmAttestationMessage(TestCase): + @parameterized.expand([ + ("ok_exact", True, b"POWHSM:5.6::"), + ("ok_longer", True, b"POWHSM:5.3::whatcomesafterwards"), + ("version_mismatch", False, b"POWHSM:4.3::"), + ("shorter", False, b"POWHSM:5.3:"), + ("invalid", False, b"something invalid"), + ]) + def test_is_header(self, _, expected, header): + self.assertEqual(expected, PowHsmAttestationMessage.is_header(header)) + + def test_parse_ok(self): + msg = PowHsmAttestationMessage( + b"POWHSM:5.7::" + + b"abc" + + bytes.fromhex("aa"*32) + + bytes.fromhex("bb"*32) + + bytes.fromhex("cc"*32) + + bytes.fromhex("dd"*8) + + bytes.fromhex("00"*7 + "83") + ) + + self.assertEqual("abc", msg.platform) + self.assertEqual(bytes.fromhex("aa"*32), msg.ud_value) + self.assertEqual(bytes.fromhex("bb"*32), msg.public_keys_hash) + self.assertEqual(bytes.fromhex("cc"*32), msg.best_block) + self.assertEqual(bytes.fromhex("dd"*8), msg.last_signed_tx) + self.assertEqual(0x83, msg.timestamp) + + def test_parse_header_mismatch(self): + with self.assertRaises(ValueError) as e: + PowHsmAttestationMessage( + b"POWHSM:3.0::" + + b"abc" + + bytes.fromhex("aa"*32) + + bytes.fromhex("bb"*32) + + bytes.fromhex("cc"*32) + + bytes.fromhex("dd"*8) + + bytes.fromhex("00"*7 + "83") + + b"0" + ) + self.assertIn("header", str(e.exception)) + + def test_parse_shorter(self): + with self.assertRaises(ValueError) as e: + PowHsmAttestationMessage( + b"POWHSM:5.7::" + + b"abc" + + bytes.fromhex("aa"*32) + + bytes.fromhex("bb"*32) + + bytes.fromhex("cc"*32) + + bytes.fromhex("dd"*8) + + bytes.fromhex("00"*6 + "83") + ) + self.assertIn("length mismatch", str(e.exception)) + + def test_parse_longer(self): + with self.assertRaises(ValueError) as e: + PowHsmAttestationMessage( + b"POWHSM:5.7::" + + b"abc" + + bytes.fromhex("aa"*32) + + bytes.fromhex("bb"*32) + + bytes.fromhex("cc"*32) + + bytes.fromhex("dd"*8) + + bytes.fromhex("00"*7 + "83") + + b"0" + ) + self.assertIn("length mismatch", str(e.exception)) + + +class TestLoadPubKeys(TestCase): + def test_load_pubkeys_ok(self): + with patch("builtins.open", mock_open()) as file_mock: + file_mock.return_value.read.return_value = TEST_PUBKEYS_JSON + pubkeys = load_pubkeys("a-path") + + file_mock.assert_called_with("a-path", "r") + self.assertEqual([ + "m/44'/1'/0'/0/0", + "m/44'/1'/1'/0/0", + "m/44'/1'/2'/0/0", + ], list(pubkeys.keys())) + self.assertEqual(bytes.fromhex( + "03abe31ee7c91976f7a56d8e196d82d5ce75a0fcc2935723bf25610d22bd81e50f"), + pubkeys["m/44'/1'/0'/0/0"].serialize(compressed=True)) + self.assertEqual(bytes.fromhex( + "03d44eac557a58be6cd4a40cbdaa9ed22cf4f0322e8c7bb84f6421d5bdda3b99ff"), + pubkeys["m/44'/1'/1'/0/0"].serialize(compressed=True)) + self.assertEqual(bytes.fromhex( + "02877a756d2b82ddff342fa327b065326001b204b2f86a24ac36638b5162330141"), + pubkeys["m/44'/1'/2'/0/0"].serialize(compressed=True)) + + def test_load_pubkeys_file_doesnotexist(self): + with patch("builtins.open", mock_open()) as file_mock: + file_mock.side_effect = FileNotFoundError("another error") + with self.assertRaises(AdminError) as e: + load_pubkeys("a-path") + file_mock.assert_called_with("a-path", "r") + self.assertIn("another error", str(e.exception)) + + def test_load_pubkeys_invalid_json(self): + with patch("builtins.open", mock_open()) as file_mock: + file_mock.return_value.read.return_value = "not json" + with self.assertRaises(AdminError) as e: + load_pubkeys("a-path") + file_mock.assert_called_with("a-path", "r") + self.assertIn("Unable to read", str(e.exception)) + + def test_load_pubkeys_notamap(self): + with patch("builtins.open", mock_open()) as file_mock: + file_mock.return_value.read.return_value = "[1,2,3]" + with self.assertRaises(AdminError) as e: + load_pubkeys("a-path") + file_mock.assert_called_with("a-path", "r") + self.assertIn("top level", str(e.exception)) + + def test_load_pubkeys_invalid_pubkey(self): + with patch("builtins.open", mock_open()) as file_mock: + file_mock.return_value.read.return_value = TEST_PUBKEYS_JSON_INVALID + with self.assertRaises(AdminError) as e: + load_pubkeys("a-path") + file_mock.assert_called_with("a-path", "r") + self.assertIn("public key", str(e.exception)) + + +class TestComputePubkeysHash(TestCase): + def test_ok(self): + expected_hash = bytes.fromhex( + "ad33c8be1af2520e2c533d883a2021654102917969816cd1b9dacfcccf4e139e") + + def to_pub(h): + return ec.PrivateKey(bytes.fromhex(h), raw=True).pubkey + + keys = { + "1first": to_pub("11"*32), + "3third": to_pub("33"*32), + "2second": to_pub("22"*32), + } + + self.assertEqual(expected_hash, compute_pubkeys_hash(keys)) + + def test_empty_errors(self): + with self.assertRaises(AdminError) as e: + compute_pubkeys_hash({}) + self.assertIn("empty", str(e.exception)) + + +class TestComputePubkeysOutput(TestCase): + def test_sample_output(self): + class PubKey: + def __init__(self, h): + self.h = h + + def serialize(self, compressed): + return bytes.fromhex(self.h) if compressed else "" + + keys = { + "name": PubKey("11223344"), + "longer_name": PubKey("aabbcc"), + "very_very_long_name": PubKey("6677889900"), + } + + self.assertEqual([ + "longer_name: aabbcc", + "name: 11223344", + "very_very_long_name: 6677889900", + ], compute_pubkeys_output(keys)) + + +class TestGetRootOfTrust(TestCase): + @patch("admin.attestation_utils.HSMCertificateV2ElementX509") + @patch("admin.attestation_utils.Path") + def test_file_ok(self, path, HSMCertificateV2ElementX509): + path.return_value.is_file.return_value = True + HSMCertificateV2ElementX509.from_pemfile.return_value = "the-result" + + self.assertEqual("the-result", get_root_of_trust("a-file-path")) + + path.assert_called_with("a-file-path") + HSMCertificateV2ElementX509.from_pemfile.assert_called_with( + "a-file-path", "sgx_root", "sgx_root") + + @patch("admin.attestation_utils.HSMCertificateV2ElementX509") + @patch("admin.attestation_utils.Path") + def test_file_invalid(self, path, HSMCertificateV2ElementX509): + path.return_value.is_file.return_value = True + err = ValueError("something wrong") + HSMCertificateV2ElementX509.from_pemfile.side_effect = err + + with self.assertRaises(ValueError) as e: + get_root_of_trust("a-file-path") + self.assertEqual(err, e.exception) + + path.assert_called_with("a-file-path") + HSMCertificateV2ElementX509.from_pemfile.assert_called_with( + "a-file-path", "sgx_root", "sgx_root") + + @patch("admin.attestation_utils.requests") + @patch("admin.attestation_utils.HSMCertificateV2ElementX509") + @patch("admin.attestation_utils.Path") + def test_url_ok(self, path, HSMCertificateV2ElementX509, requests): + path.return_value.is_file.return_value = False + requests.get.return_value = SimpleNamespace(**{ + "status_code": 200, + "content": b"some-pem", + }) + HSMCertificateV2ElementX509.from_pem.return_value = "the-result" + + self.assertEqual("the-result", get_root_of_trust("a-url")) + + path.assert_called_with("a-url") + requests.get.assert_called_with("a-url") + HSMCertificateV2ElementX509.from_pem.assert_called_with( + "some-pem", "sgx_root", "sgx_root") + + @patch("admin.attestation_utils.requests") + @patch("admin.attestation_utils.HSMCertificateV2ElementX509") + @patch("admin.attestation_utils.Path") + def test_url_error_get(self, path, HSMCertificateV2ElementX509, requests): + path.return_value.is_file.return_value = False + requests.get.return_value = SimpleNamespace(**{ + "status_code": 123, + }) + + with self.assertRaises(RuntimeError) as e: + get_root_of_trust("a-url") + self.assertIn("fetching root of trust", str(e.exception)) + + path.assert_called_with("a-url") + requests.get.assert_called_with("a-url") + HSMCertificateV2ElementX509.from_pem.assert_not_called() diff --git a/middleware/tests/admin/test_attestation_utils_resources.py b/middleware/tests/admin/test_attestation_utils_resources.py new file mode 100644 index 00000000..6da5092d --- /dev/null +++ b/middleware/tests/admin/test_attestation_utils_resources.py @@ -0,0 +1,36 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +TEST_PUBKEYS_JSON = """ +{ + "m/44'/1'/0'/0/0": "04abe31ee7c91976f7a56d8e196d82d5ce75a0fcc2935723bf25610d22bd81e50fb4def0b3f99ae2054868ea2133e5b88145220ac492f86b942bd40f574d9117e1", + "m/44'/1'/1'/0/0": "04d44eac557a58be6cd4a40cbdaa9ed22cf4f0322e8c7bb84f6421d5bdda3b99ff73982e67c4550faad3f67de7615a0a32cfcf3322f5eca5cbaa6792131600ca17", + "m/44'/1'/2'/0/0": "04877a756d2b82ddff342fa327b065326001b204b2f86a24ac36638b51623301416076d2eb1a048c2efa3934d5673bdf3db8d0f1e8ade406c6a478f0910cdb8c4c" +} +""" + +TEST_PUBKEYS_JSON_INVALID = """ +{ + "path_1": "02877a756d2b82ddff342fa327b065326001b204b2f86a24ac36638b5162330141", + "path_2": "11223344" +} +""" diff --git a/middleware/tests/admin/test_certificate_v2.py b/middleware/tests/admin/test_certificate_v2.py index ed7c0c8d..99a82099 100644 --- a/middleware/tests/admin/test_certificate_v2.py +++ b/middleware/tests/admin/test_certificate_v2.py @@ -21,6 +21,7 @@ # SOFTWARE. from unittest import TestCase +from unittest.mock import patch from admin.certificate_v1 import HSMCertificate from admin.certificate_v2 import HSMCertificateV2, HSMCertificateV2Element, \ HSMCertificateV2ElementSGXQuote, \ @@ -41,17 +42,34 @@ def test_parse_identity(self): cert = HSMCertificateV2(TEST_CERTIFICATE) self.assertEqual(TEST_CERTIFICATE, cert.to_dict()) - def test_validate_and_get_values_value(self): + @patch("admin.certificate_v2.SgxQuote") + def test_validate_and_get_values_value(self, SgxQuoteMock): + SgxQuoteMock.return_value = "an-sgx-quote" cert = HSMCertificateV2(TEST_CERTIFICATE) self.assertEqual({ "quote": ( - True, - "504f5748534d3a352e343a3a736778f36f7bc09aab50c0886a442b2d04b18186720bd" - "a7a753643066cd0bc0a4191800c4d091913d39750dc8975adbdd261bd10c1c2e110fa" - "a47cfbe30e740895552bbdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6" - "e7191f67ea4209b00000000000000000000000000000000", - None) + True, { + "sgx_quote": "an-sgx-quote", + "message": "504f5748534d3a352e343a3a736778f36f7bc09aab50c0886a442b2" + "d04b18186720bda7a753643066cd0bc0a4191800c4d091913d39750" + "dc8975adbdd261bd10c1c2e110faa47cfbe30e740895552bbdcb3c1" + "7c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea420" + "9b00000000000000000000000000000000", + }, None) }, cert.validate_and_get_values('a-root-of-trust')) + SgxQuoteMock.assert_called_with(bytes.fromhex( + "03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ceae3549bc7273eb34" + "d562f4564fc182000000000e0e100fffff0100000000000000000001000000000000000000" + "00000000000000000000000000000000000000000000050000000000000007000000000000" + "00d32688d3c1f3dfcc8b0b36eac7c89d49af331800bd56248044166fa6699442c100000000" + "00000000000000000000000000000000000000000000000000000000718c2f1a0efbd513e0" + "16fafd6cf62a624442f2d83708d4b33ab5a8d8c1cd4dd00000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000006400010000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000009e95" + "bb875c1a728071f70ad8c9d03f1744c19acb0580921e611ac9104f7701d000000000000000" + "00000000000000000000000000000000000000000000000000")) class TestHSMCertificateV2Element(TestCase): @@ -281,3 +299,29 @@ def test_from_dict_invalid_message(self): "signed_by": "platform_ca" }) self.assertIn("Invalid message", str(e.exception)) + + def test_from_pem(self): + self.assertEqual({ + "name": "thename", + "type": "x509_pem", + "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", + "signed_by": "whosigned", + }, HSMCertificateV2ElementX509.from_pem(""" + -----BEGIN CERTIFICATE----- + dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl + -----END CERTIFICATE----- + """, "thename", "whosigned").to_dict()) + + @patch("admin.certificate_v2.Path") + @patch("admin.certificate_v2.HSMCertificateV2ElementX509.from_pem") + def test_from_pemfile(self, from_pem, Path): + Path.return_value.read_text.return_value = "the pem contents" + from_pem.return_value = "the instance" + self.assertEqual("the instance", + HSMCertificateV2ElementX509.from_pemfile("a-file.pem", + "the name", + "who signed")) + Path.assert_called_with("a-file.pem") + from_pem.assert_called_with("the pem contents", + "the name", + "who signed") diff --git a/middleware/tests/admin/test_verify_ledger_attestation.py b/middleware/tests/admin/test_verify_ledger_attestation.py index 40f510e2..ba5638cc 100644 --- a/middleware/tests/admin/test_verify_ledger_attestation.py +++ b/middleware/tests/admin/test_verify_ledger_attestation.py @@ -22,11 +22,12 @@ from types import SimpleNamespace from unittest import TestCase -from unittest.mock import Mock, call, patch, mock_open +from unittest.mock import Mock, call, patch from admin.misc import AdminError from admin.pubkeys import PATHS from admin.verify_ledger_attestation import do_verify_attestation import ecdsa +import secp256k1 as ec import hashlib import logging @@ -39,7 +40,7 @@ @patch("sys.stdout.write") -class TestVerifyAttestation(TestCase): +class TestVerifyLedgerAttestation(TestCase): def setUp(self): self.certification_path = 'certification-path' self.pubkeys_path = 'pubkeys-path' @@ -60,17 +61,20 @@ def setUp(self): path_name_padding = max(map(len, paths)) for path in sorted(paths): pubkey = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1).get_verifying_key() - self.public_keys[path] = pubkey.to_string('compressed').hex() + self.public_keys[path] = ec.PublicKey( + pubkey.to_string('compressed'), raw=True) pubkeys_hash.update(pubkey.to_string('uncompressed')) self.expected_pubkeys_output.append( f"{(path + ':').ljust(path_name_padding+1)} " f"{pubkey.to_string('compressed').hex()}" ) self.pubkeys_hash = pubkeys_hash.digest() + self.expected_ui_pubkey = self.public_keys[EXPECTED_UI_DERIVATION_PATH]\ + .serialize(compressed=True).hex() self.ui_msg = UI_HEADER + \ bytes.fromhex("aa"*32) + \ - bytes.fromhex("bb"*33) + \ + bytes.fromhex(self.expected_ui_pubkey) + \ bytes.fromhex("cc"*32) + \ bytes.fromhex("0123") self.ui_hash = bytes.fromhex("ee" * 32) @@ -81,7 +85,7 @@ def setUp(self): bytes.fromhex(self.pubkeys_hash.hex()) + \ bytes.fromhex('bb'*32) + \ bytes.fromhex('cc'*8) + \ - bytes.fromhex('dd'*8) + bytes.fromhex('00'*7 + 'ab') self.signer_hash = bytes.fromhex("ff" * 32) @@ -91,9 +95,9 @@ def setUp(self): @patch("admin.verify_ledger_attestation.head") @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation_legacy(self, - loads_mock, + load_pubkeys_mock, certificate_mock, head_mock, _): self.signer_msg = LEGACY_SIGNER_HEADER + \ @@ -101,15 +105,14 @@ def test_verify_attestation_legacy(self, self.signer_hash = bytes.fromhex("ff" * 32) self.result['signer'] = (True, self.signer_msg.hex(), self.signer_hash.hex()) - loads_mock.return_value = self.public_keys + load_pubkeys_mock.return_value = self.public_keys att_cert = Mock() att_cert.validate_and_get_values = Mock(return_value=self.result) certificate_mock.from_jsonfile = Mock(return_value=att_cert) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - do_verify_attestation(self.default_options) + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual([call(self.certification_path)], certificate_mock.from_jsonfile.call_args_list) @@ -117,7 +120,8 @@ def test_verify_attestation_legacy(self, [ "UI verified with:", f"UD value: {'aa'*32}", - f"Derived public key ({EXPECTED_UI_DERIVATION_PATH}): {'bb'*33}", + f"Derived public key ({EXPECTED_UI_DERIVATION_PATH}): " + f"{self.expected_ui_pubkey}", f"Authorized signer hash: {'cc'*32}", "Authorized signer iteration: 291", f"Installed UI hash: {'ee'*32}", @@ -140,21 +144,19 @@ def test_verify_attestation_legacy(self, @patch("admin.verify_ledger_attestation.head") @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation(self, - loads_mock, + load_pubkeys_mock, certificate_mock, - head_mock, - _): - loads_mock.return_value = self.public_keys + head_mock, _): + load_pubkeys_mock.return_value = self.public_keys att_cert = Mock() att_cert.validate_and_get_values = Mock(return_value=self.result) certificate_mock.from_jsonfile = Mock(return_value=att_cert) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - do_verify_attestation(self.default_options) + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual([call(self.certification_path)], certificate_mock.from_jsonfile.call_args_list) @@ -162,7 +164,8 @@ def test_verify_attestation(self, [ "UI verified with:", f"UD value: {'aa'*32}", - f"Derived public key ({EXPECTED_UI_DERIVATION_PATH}): {'bb'*33}", + f"Derived public key ({EXPECTED_UI_DERIVATION_PATH}): " + f"{self.expected_ui_pubkey}", f"Authorized signer hash: {'cc'*32}", "Authorized signer iteration: 291", f"Installed UI hash: {'ee'*32}", @@ -185,7 +188,7 @@ def test_verify_attestation(self, "Best block: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" "bbbbb", "Last transaction signed: cccccccccccccccc", - "Timestamp: dddddddddddddddd", + "Timestamp: 171", ], fill="-", ) @@ -206,66 +209,43 @@ def test_verify_attestation_no_pubkey(self, _): do_verify_attestation(options) self.assertEqual('No public keys file given', str(e.exception)) - @patch("json.loads") - def test_verify_attestation_invalid_pubkeys_map(self, loads_mock, _): - loads_mock.return_value = 'invalid-json' - with patch('builtins.open', mock_open(read_data='')): - with self.assertRaises(ValueError) as e: - do_verify_attestation(self.default_options) - - self.assertEqual(('Unable to read public keys from "pubkeys-path": Public keys ' - 'file must contain an object as a top level element'), - str(e.exception)) - - @patch("json.loads") - def test_verify_attestation_invalid_pubkey(self, loads_mock, _): - loads_mock.return_value = {'invalid-path': 'invalid-key'} - with patch('builtins.open', mock_open(read_data='')): - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) - - self.assertEqual('Invalid public key for path invalid-path: invalid-key', - str(e.exception)) - - @patch("json.loads") - def test_verify_attestation_no_ui_derivation_key(self, loads_mock, _): + @patch("admin.verify_ledger_attestation.load_pubkeys") + def test_verify_attestation_no_ui_derivation_key(self, load_pubkeys_mock, _): incomplete_pubkeys = self.public_keys incomplete_pubkeys.pop(EXPECTED_UI_DERIVATION_PATH, None) - loads_mock.return_value = incomplete_pubkeys + load_pubkeys_mock.return_value = incomplete_pubkeys - with patch('builtins.open', mock_open(read_data='')) as file_mock: - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual((f'Public key with path {EXPECTED_UI_DERIVATION_PATH} ' 'not present in public key file'), str(e.exception)) @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation_invalid_certificate(self, - loads_mock, + load_pubkeys_mock, certificate_mock, _): - loads_mock.return_value = self.public_keys + load_pubkeys_mock.return_value = self.public_keys certificate_mock.from_jsonfile = Mock(side_effect=Exception('error-msg')) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual('While loading the attestation certificate file: error-msg', str(e.exception)) @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation_no_ui_att(self, - loads_mock, + load_pubkeys_mock, certificate_mock, _): - loads_mock.return_value = self.public_keys + load_pubkeys_mock.return_value = self.public_keys result = self.result result.pop('ui', None) @@ -273,115 +253,106 @@ def test_verify_attestation_no_ui_att(self, att_cert.validate_and_get_values = Mock(return_value=self.result) certificate_mock.from_jsonfile = Mock(return_value=att_cert) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual('Certificate does not contain a UI attestation', str(e.exception)) @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation_invalid_ui_att(self, - loads_mock, + load_pubkeys_mock, certificate_mock, _): - loads_mock.return_value = self.public_keys + load_pubkeys_mock.return_value = self.public_keys result = self.result result['ui'] = (False, 'ui') att_cert = Mock() att_cert.validate_and_get_values = Mock(return_value=result) certificate_mock.from_jsonfile = Mock(return_value=att_cert) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual("Invalid UI attestation: error validating 'ui'", str(e.exception)) @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation_no_signer_att(self, - loads_mock, + load_pubkeys_mock, certificate_mock, _): - loads_mock.return_value = self.public_keys - + load_pubkeys_mock.return_value = self.public_keys result = self.result result.pop('signer', None) att_cert = Mock() att_cert.validate_and_get_values = Mock(return_value=self.result) certificate_mock.from_jsonfile = Mock(return_value=att_cert) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual('Certificate does not contain a Signer attestation', str(e.exception)) @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation_invalid_signer_att(self, - loads_mock, + load_pubkeys_mock, certificate_mock, _): - loads_mock.return_value = self.public_keys + load_pubkeys_mock.return_value = self.public_keys result = self.result result['signer'] = (False, 'signer') att_cert = Mock() att_cert.validate_and_get_values = Mock(return_value=result) certificate_mock.from_jsonfile = Mock(return_value=att_cert) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual(("Invalid Signer attestation: error validating 'signer'"), str(e.exception)) @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation_invalid_signer_att_header(self, - loads_mock, + load_pubkeys_mock, certificate_mock, _): - loads_mock.return_value = self.public_keys + load_pubkeys_mock.return_value = self.public_keys signer_header = b"POWHSM:AAA::somerandomstuff".hex() self.result["signer"] = (True, signer_header, self.signer_hash.hex()) att_cert = Mock() att_cert.validate_and_get_values = Mock(return_value=self.result) certificate_mock.from_jsonfile = Mock(return_value=att_cert) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) self.assertEqual((f"Invalid Signer attestation message header: {signer_header}"), str(e.exception)) @patch("admin.verify_ledger_attestation.HSMCertificate") - @patch("json.loads") + @patch("admin.verify_ledger_attestation.load_pubkeys") def test_verify_attestation_invalid_signer_att_msg_too_long(self, - loads_mock, + load_pubkeys_mock, certificate_mock, _): - loads_mock.return_value = self.public_keys + load_pubkeys_mock.return_value = self.public_keys signer_header = (b"POWHSM:5.9::" + b"aa"*300).hex() self.result["signer"] = (True, signer_header, self.signer_hash.hex()) att_cert = Mock() att_cert.validate_and_get_values = Mock(return_value=self.result) certificate_mock.from_jsonfile = Mock(return_value=att_cert) - with patch('builtins.open', mock_open(read_data='')) as file_mock: - with self.assertRaises(AdminError) as e: - do_verify_attestation(self.default_options) + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.default_options) - self.assertEqual([call(self.pubkeys_path, 'r')], file_mock.call_args_list) - self.assertEqual(("Signer attestation message longer " - f"than expected: {signer_header}"), - str(e.exception)) + load_pubkeys_mock.assert_called_with(self.pubkeys_path) + self.assertIn("Signer attestation message length mismatch", str(e.exception)) diff --git a/middleware/tests/admin/test_verify_sgx_attestation.py b/middleware/tests/admin/test_verify_sgx_attestation.py new file mode 100644 index 00000000..5bacadf5 --- /dev/null +++ b/middleware/tests/admin/test_verify_sgx_attestation.py @@ -0,0 +1,241 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from types import SimpleNamespace +from unittest import TestCase +from unittest.mock import Mock, patch +from parameterized import parameterized +from admin.misc import AdminError +from admin.pubkeys import PATHS +from admin.verify_sgx_attestation import do_verify_attestation, DEFAULT_ROOT_AUTHORITY +import ecdsa +import secp256k1 as ec +import hashlib +import logging + +logging.disable(logging.CRITICAL) + + +@patch("sys.stdout.write") +@patch("admin.verify_sgx_attestation.head") +@patch("admin.verify_sgx_attestation.HSMCertificate") +@patch("admin.verify_sgx_attestation.load_pubkeys") +@patch("admin.verify_sgx_attestation.get_root_of_trust") +class TestVerifySgxAttestation(TestCase): + def setUp(self): + self.certification_path = 'certification-path' + self.pubkeys_path = 'pubkeys-path' + self.options = SimpleNamespace(**{ + 'attestation_certificate_file_path': self.certification_path, + 'pubkeys_file_path': self.pubkeys_path, + 'root_authority': None + }) + + paths = [] + for path in PATHS.values(): + paths.append(str(path)) + + self.public_keys = {} + self.expected_pubkeys_output = [] + pubkeys_hash = hashlib.sha256() + path_name_padding = max(map(len, paths)) + for path in sorted(paths): + pubkey = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1).get_verifying_key() + self.public_keys[path] = ec.PublicKey( + pubkey.to_string('compressed'), raw=True) + pubkeys_hash.update(pubkey.to_string('uncompressed')) + self.expected_pubkeys_output.append( + f"{(path + ':').ljust(path_name_padding+1)} " + f"{pubkey.to_string('compressed').hex()}" + ) + self.expected_pubkeys_hash = pubkeys_hash.digest().hex() + + self.powhsm_msg = \ + b"POWHSM:5.4::" + \ + b'plf' + \ + bytes.fromhex('aa'*32) + \ + bytes.fromhex(self.expected_pubkeys_hash) + \ + bytes.fromhex('bb'*32) + \ + bytes.fromhex('cc'*8) + \ + bytes.fromhex('00'*7 + 'cd') + + self.mock_sgx_quote = SimpleNamespace(**{ + "report_body": SimpleNamespace(**{ + "mrenclave": bytes.fromhex("aabbccdd"), + "mrsigner": bytes.fromhex("1122334455"), + }) + }) + + self.validate_result = {"quote": ( + True, { + "sgx_quote": self.mock_sgx_quote, + "message": self.powhsm_msg.hex() + }, None) + } + + def configure_mocks(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head): + get_root_of_trust.return_value = "the-root-of-trust" + load_pubkeys.return_value = self.public_keys + self.mock_certificate = Mock() + self.mock_certificate.validate_and_get_values.return_value = self.validate_result + HSMCertificate.from_jsonfile.return_value = self.mock_certificate + + @parameterized.expand([ + ("default_root", None), + ("custom_root", "a-custom-root") + ]) + def test_verify_attestation(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _, __, custom_root): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + if custom_root: + self.options.root_authority = custom_root + + do_verify_attestation(self.options) + + if custom_root: + get_root_of_trust.assert_called_with(custom_root) + else: + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + load_pubkeys.assert_called_with(self.pubkeys_path) + HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) + self.mock_certificate.validate_and_get_values \ + .assert_called_with("the-root-of-trust") + head.assert_called_with([ + "powHSM verified with public keys:" + ] + self.expected_pubkeys_output + [ + f"Hash: {self.expected_pubkeys_hash}", + "", + "Installed powHSM MRENCLAVE: aabbccdd", + "Installed powHSM MRSIGNER: 1122334455", + "Installed powHSM version: 5.4", + "Platform: plf", + f"UD value: {"aa"*32}", + f"Best block: {"bb"*32}", + f"Last transaction signed: {"cc"*8}", + "Timestamp: 205", + ], fill="-") + + def test_verify_attestation_err_load_pubkeys(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + load_pubkeys.side_effect = ValueError("pubkeys error") + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("pubkeys error", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + load_pubkeys.assert_called_with(self.pubkeys_path) + HSMCertificate.from_jsonfile.assert_not_called() + self.mock_certificate.validate_and_get_values.assert_not_called() + + def test_verify_attestation_err_load_cert(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + HSMCertificate.from_jsonfile.side_effect = ValueError("load cert error") + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("load cert error", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + load_pubkeys.assert_called_with(self.pubkeys_path) + HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) + self.mock_certificate.validate_and_get_values.assert_not_called() + + def test_verify_attestation_validation_noquote(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + self.mock_certificate.validate_and_get_values.return_value = {"something": "else"} + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("does not contain", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + load_pubkeys.assert_called_with(self.pubkeys_path) + HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) + self.mock_certificate.validate_and_get_values \ + .assert_called_with("the-root-of-trust") + + def test_verify_attestation_validation_failed(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + self.mock_certificate.validate_and_get_values.return_value = { + "quote": (False, "a validation error") + } + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("validation error", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + load_pubkeys.assert_called_with(self.pubkeys_path) + HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) + self.mock_certificate.validate_and_get_values \ + .assert_called_with("the-root-of-trust") + + def test_verify_attestation_invalid_header(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + self.validate_result["quote"][1]["message"] = "aabbccdd" + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("message header", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + load_pubkeys.assert_called_with(self.pubkeys_path) + HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) + self.mock_certificate.validate_and_get_values \ + .assert_called_with("the-root-of-trust") + + def test_verify_attestation_invalid_message(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + self.validate_result["quote"][1]["message"] = b"POWHSM:5.4::plf".hex() + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("parsing", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + load_pubkeys.assert_called_with(self.pubkeys_path) + HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) + self.mock_certificate.validate_and_get_values \ + .assert_called_with("the-root-of-trust") + + def test_verify_attestation_pkh_mismatch(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + self.public_keys.popitem() + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("hash mismatch", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + load_pubkeys.assert_called_with(self.pubkeys_path) + HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) + self.mock_certificate.validate_and_get_values \ + .assert_called_with("the-root-of-trust") diff --git a/setup.cfg b/setup.cfg index 36a420ae..1dbd51f0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,6 +27,7 @@ per-file-ignores = middleware/admin/certificate.py:F401, middleware/tests/sgx/test_envelope.py:E122, middleware/tests/admin/test_certificate_v2_resources.py:E501, + middleware/tests/admin/test_attestation_utils_resources.py:E501, show-source = False statistics = True From 0b62d17a614f5840a4d136dcc98c748f57d48f56 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 1 Jan 2025 00:32:30 +1300 Subject: [PATCH 33/50] Certificate V2 sgx_quote type element validation (#234) - HSMCertificateV2Element base class now raises not implemented errors for is_valid and get_pubkey - Implemented is_valid in HSMCertificateV2ElementSGXQuote - HSMCertificateV2ElementSGXQuote's message method now returns an SgxQuote - Mocking is_valid and get_pubkey in the rest of HSMCertificateV2Element's subclasses - Added and updated unit tests --- middleware/admin/certificate_v2.py | 44 ++++- middleware/tests/admin/test_certificate_v2.py | 183 ++++++++++++++---- 2 files changed, 185 insertions(+), 42 deletions(-) diff --git a/middleware/admin/certificate_v2.py b/middleware/admin/certificate_v2.py index e84591d2..f5bf6a2e 100644 --- a/middleware/admin/certificate_v2.py +++ b/middleware/admin/certificate_v2.py @@ -23,6 +23,8 @@ import re from pathlib import Path import base64 +import ecdsa +import hashlib from .certificate_v1 import HSMCertificate from .utils import is_nonempty_hex_string from sgx.envelope import SgxQuote @@ -62,14 +64,10 @@ def get_value(self): raise NotImplementedError(f"{type(self).__name__} can't provide a value") def get_pubkey(self): - # TODO: this should yield not implemented - # TODO: implementation should be down to each specific subclass - return None + raise NotImplementedError(f"{type(self).__name__} can't provide a public key") def is_valid(self, certifier): - # TODO: this should yield not implemented - # TODO: implementation should be down to each specific subclass - return True + raise NotImplementedError(f"{type(self).__name__} can't be queried for validity") def get_tweak(self): return None @@ -97,7 +95,7 @@ def _init_with_map(self, element_map): @property def message(self): - return self._message.hex() + return SgxQuote(self._message) @property def custom_data(self): @@ -107,9 +105,25 @@ def custom_data(self): def signature(self): return self._signature.hex() + def is_valid(self, certifier): + try: + # Validate custom data + expected = hashlib.sha256(self._custom_data).digest() + if expected != self.message.report_body.report_data.field[:len(expected)]: + return False + + # Verify signature against the certifier + return certifier.get_pubkey().verify_digest( + self._signature, + hashlib.sha256(self._message).digest(), + ecdsa.util.sigdecode_der, + ) + except Exception: + return False + def get_value(self): return { - "sgx_quote": SgxQuote(self._message), + "sgx_quote": self.message, "message": self.custom_data, } @@ -117,7 +131,7 @@ def to_dict(self): return { "name": self.name, "type": "sgx_quote", - "message": self.message, + "message": self._message.hex(), "custom_data": self.custom_data, "signature": self.signature, "signed_by": self.signed_by, @@ -163,6 +177,12 @@ def auth_data(self): def signature(self): return self._signature.hex() + def is_valid(self, certifier): + return True + + def get_pubkey(self): + return ecdsa.VerifyingKey.from_string(self._key, ecdsa.NIST256p) + def to_dict(self): return { "name": self.name, @@ -206,6 +226,12 @@ def _init_with_map(self, element_map): def message(self): return base64.b64encode(self._message).decode("ASCII") + def is_valid(self, certifier): + return True + + def get_pubkey(self): + return None + def to_dict(self): return { "name": self.name, diff --git a/middleware/tests/admin/test_certificate_v2.py b/middleware/tests/admin/test_certificate_v2.py index 99a82099..ae292645 100644 --- a/middleware/tests/admin/test_certificate_v2.py +++ b/middleware/tests/admin/test_certificate_v2.py @@ -20,9 +20,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import ecdsa +import hashlib from unittest import TestCase -from unittest.mock import patch +from unittest.mock import Mock, patch +from parameterized import parameterized from admin.certificate_v1 import HSMCertificate +from sgx.envelope import SgxQuote from admin.certificate_v2 import HSMCertificateV2, HSMCertificateV2Element, \ HSMCertificateV2ElementSGXQuote, \ HSMCertificateV2ElementSGXAttestationKey, \ @@ -36,43 +40,62 @@ def test_behavior_inherited(self): def test_create_empty_certificate_ok(self): cert = HSMCertificateV2() - self.assertEqual({'version': 2, 'targets': [], 'elements': []}, cert.to_dict()) + self.assertEqual({"version": 2, "targets": [], "elements": []}, cert.to_dict()) def test_parse_identity(self): cert = HSMCertificateV2(TEST_CERTIFICATE) self.assertEqual(TEST_CERTIFICATE, cert.to_dict()) - @patch("admin.certificate_v2.SgxQuote") - def test_validate_and_get_values_value(self, SgxQuoteMock): - SgxQuoteMock.return_value = "an-sgx-quote" + def mock_element(self, which_one_invalid): + class MockElement: + def __init__(self, d): + self.d = d + self.name = d["name"] + self.signed_by = d["signed_by"] + + def is_valid(self, c): + return self.name != which_one_invalid + + def get_value(self): + return f"the value for {self.name}" + + def get_tweak(self): + return None + + def mock_element_factory(k, d): + return MockElement(d) + + HSMCertificateV2.ELEMENT_FACTORY = mock_element_factory + + def test_validate_and_get_values_value(self): + self.mock_element(True) + cert = HSMCertificateV2(TEST_CERTIFICATE) + self.assertEqual({ + "quote": (True, "the value for quote", None), + }, cert.validate_and_get_values("a-root-of-trust")) + + @parameterized.expand([ + ("invalid_quote", "quote"), + ("invalid_attestation", "attestation"), + ("invalid_qe", "quoting_enclave"), + ("invalid_plf", "platform_ca"), + ]) + def test_validate_and_get_values_invalid(self, _, invalid_name): + self.mock_element(invalid_name) cert = HSMCertificateV2(TEST_CERTIFICATE) self.assertEqual({ - "quote": ( - True, { - "sgx_quote": "an-sgx-quote", - "message": "504f5748534d3a352e343a3a736778f36f7bc09aab50c0886a442b2" - "d04b18186720bda7a753643066cd0bc0a4191800c4d091913d39750" - "dc8975adbdd261bd10c1c2e110faa47cfbe30e740895552bbdcb3c1" - "7c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea420" - "9b00000000000000000000000000000000", - }, None) - }, cert.validate_and_get_values('a-root-of-trust')) - SgxQuoteMock.assert_called_with(bytes.fromhex( - "03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ceae3549bc7273eb34" - "d562f4564fc182000000000e0e100fffff0100000000000000000001000000000000000000" - "00000000000000000000000000000000000000000000050000000000000007000000000000" - "00d32688d3c1f3dfcc8b0b36eac7c89d49af331800bd56248044166fa6699442c100000000" - "00000000000000000000000000000000000000000000000000000000718c2f1a0efbd513e0" - "16fafd6cf62a624442f2d83708d4b33ab5a8d8c1cd4dd00000000000000000000000000000" - "00000000000000000000000000000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000000000000000000000000000" - "00000000000000006400010000000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000000000000000000000009e95" - "bb875c1a728071f70ad8c9d03f1744c19acb0580921e611ac9104f7701d000000000000000" - "00000000000000000000000000000000000000000000000000")) + "quote": (False, invalid_name), + }, cert.validate_and_get_values("a-root-of-trust")) class TestHSMCertificateV2Element(TestCase): + def setUp(self): + class TestElement(HSMCertificateV2Element): + def __init__(self): + pass + + self.instance = TestElement() + def test_from_dict_unknown_type(self): with self.assertRaises(ValueError) as e: HSMCertificateV2Element.from_dict({ @@ -103,12 +126,41 @@ def test_from_dict_no_signed_by(self): }) self.assertIn("Missing certifier", str(e.exception)) + def test_cant_instantiate(self): + with self.assertRaises(NotImplementedError): + HSMCertificateV2Element() + + def test_get_pubkey_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.instance.get_pubkey() + + def test_get_value_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.instance.get_value() + + def test_is_valid_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.instance.is_valid("a-certifier") + class TestHSMCertificateV2ElementSGXQuote(TestCase): + TEST_MESSAGE = \ + "03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ceae3549bc7273eb34d562f"\ + "4564fc182000000000e0e100fffff01000000000000000000010000000000000000000000000000"\ + "000000000000000000000000000000000005000000000000000700000000000000d32688d3c1f3d"\ + "fcc8b0b36eac7c89d49af331800bd56248044166fa6699442c10000000000000000000000000000"\ + "000000000000000000000000000000000000718c2f1a0efbd513e016fafd6cf62a624442f2d8370"\ + "8d4b33ab5a8d8c1cd4dd00000000000000000000000000000000000000000000000000000000000"\ + "0000000000000000000000000000000000000000000000000000000000000000000000000000000"\ + "0000000000000000000000000000000000000000000000000000000640001000000000000000000"\ + "0000000000000000000000000000000000000000000000000000000000000000000000000000000"\ + "00000000000000000000000005d53b30e22f66979d36721e10ab7722557257a9ef8ba77ec7fe430"\ + "493c3542f90000000000000000000000000000000000000000000000000000000000000000" + def setUp(self): self.elem = HSMCertificateV2ElementSGXQuote({ "name": "thename", - "message": "aabbcc", + "message": self.TEST_MESSAGE, "custom_data": "ddeeff", "signature": "112233", "signed_by": "whosigned", @@ -117,7 +169,9 @@ def setUp(self): def test_props(self): self.assertEqual("thename", self.elem.name) self.assertEqual("whosigned", self.elem.signed_by) - self.assertEqual("aabbcc", self.elem.message) + self.assertIsInstance(self.elem.message, SgxQuote) + self.assertEqual(bytes.fromhex(self.TEST_MESSAGE), + self.elem.message.get_raw_data()) self.assertEqual("ddeeff", self.elem.custom_data) self.assertEqual("112233", self.elem.signature) @@ -125,7 +179,7 @@ def test_dict_ok(self): self.assertEqual({ "name": "thename", "type": "sgx_quote", - "message": "aabbcc", + "message": self.TEST_MESSAGE, "custom_data": "ddeeff", "signature": "112233", "signed_by": "whosigned", @@ -154,7 +208,7 @@ def test_from_dict_invalid_custom_data(self): HSMCertificateV2Element.from_dict({ "name": "quote", "type": "sgx_quote", - "message": "aabbccdd", + "message": self.TEST_MESSAGE, "custom_data": "not-hex", "signature": "445566778899", "signed_by": "attestation" @@ -166,13 +220,68 @@ def test_from_dict_invalid_signature(self): HSMCertificateV2Element.from_dict({ "name": "quote", "type": "sgx_quote", - "message": "aabbccdd", + "message": self.TEST_MESSAGE, "custom_data": "112233", "signature": "not-hex", "signed_by": "attestation" }) self.assertIn("Invalid signature", str(e.exception)) + def test_get_pubkey_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.elem.get_pubkey() + + def test_is_valid_ok(self): + pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) + certifier = Mock() + certifier.get_pubkey.return_value = pk.verifying_key + + valid_elem = HSMCertificateV2ElementSGXQuote({ + "name": "thename", + "message": self.TEST_MESSAGE, + "custom_data": "10061982", + "signature": pk.sign_digest( + hashlib.sha256(bytes.fromhex(self.TEST_MESSAGE)).digest(), + sigencode=ecdsa.util.sigencode_der + ).hex(), + "signed_by": "whosigned", + }) + self.assertTrue(valid_elem.is_valid(certifier)) + + def test_is_valid_custom_data_mismatch(self): + pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) + certifier = Mock() + certifier.get_pubkey.return_value = pk.verifying_key + + valid_elem = HSMCertificateV2ElementSGXQuote({ + "name": "thename", + "message": self.TEST_MESSAGE, + "custom_data": "11061982", + "signature": pk.sign_digest( + hashlib.sha256(bytes.fromhex(self.TEST_MESSAGE)).digest(), + sigencode=ecdsa.util.sigencode_der + ).hex(), + "signed_by": "whosigned", + }) + self.assertFalse(valid_elem.is_valid(certifier)) + + def test_is_valid_signature_mismatch(self): + pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) + certifier = Mock() + certifier.get_pubkey.return_value = pk.verifying_key + + valid_elem = HSMCertificateV2ElementSGXQuote({ + "name": "thename", + "message": self.TEST_MESSAGE, + "custom_data": "10061982", + "signature": pk.sign_digest( + hashlib.sha256(b"something else").digest(), + sigencode=ecdsa.util.sigencode_der + ).hex(), + "signed_by": "whosigned", + }) + self.assertFalse(valid_elem.is_valid(certifier)) + class TestHSMCertificateV2ElementSGXAttestationKey(TestCase): def setUp(self): @@ -262,6 +371,10 @@ def test_from_dict_invalid_signature(self): }) self.assertIn("Invalid signature", str(e.exception)) + def test_get_value_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.elem.get_value() + class TestHSMCertificateV2ElementX509(TestCase): def setUp(self): @@ -300,6 +413,10 @@ def test_from_dict_invalid_message(self): }) self.assertIn("Invalid message", str(e.exception)) + def test_get_value_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.elem.get_value() + def test_from_pem(self): self.assertEqual({ "name": "thename", From baacb37576a3baad72831aa2740519f59c85d88b Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Sat, 4 Jan 2025 01:50:25 +1300 Subject: [PATCH 34/50] Certificate V2 sgx_attestation_key type element validation (#235) - Implemented HSMCertificateV2ElementSGXAttestationKey's key and is_valid methods - HSMCertificateV2ElementSGXAttestationKey's message now returns an instance of SgxReportBody - HSMCertificateV2ElementX509 now parses the raw certificate into an cryptography x509 certificate object - Implemented HSMCertificateV2ElementX509's get_pubkey method - Added cryptography dependency to middleware docker image - Added and updated unit tests - Incidentally removing some garbage --- docker/mware/requirements.txt | 30 ++ middleware/admin/certificate_v2.py | 56 ++- middleware/da.json | 20 - middleware/tests/admin/test_certificate_v2.py | 365 +----------------- .../admin/test_certificate_v2_element.py | 79 ++++ ...tificate_v2_element_sgx_attestation_key.py | 168 ++++++++ .../test_certificate_v2_element_sgx_quote.py | 170 ++++++++ .../admin/test_certificate_v2_element_x509.py | 200 ++++++++++ 8 files changed, 695 insertions(+), 393 deletions(-) delete mode 100644 middleware/da.json create mode 100644 middleware/tests/admin/test_certificate_v2_element.py create mode 100644 middleware/tests/admin/test_certificate_v2_element_sgx_attestation_key.py create mode 100644 middleware/tests/admin/test_certificate_v2_element_sgx_quote.py create mode 100644 middleware/tests/admin/test_certificate_v2_element_x509.py diff --git a/docker/mware/requirements.txt b/docker/mware/requirements.txt index df27073a..eff05dbf 100644 --- a/docker/mware/requirements.txt +++ b/docker/mware/requirements.txt @@ -810,3 +810,33 @@ yapf==0.40.2 \ zipp==3.19.2 \ --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c +cryptography==44.0.0 \ + --hash=sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7 \ + --hash=sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731 \ + --hash=sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b \ + --hash=sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc \ + --hash=sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543 \ + --hash=sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385 \ + --hash=sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c \ + --hash=sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591 \ + --hash=sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede \ + --hash=sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb \ + --hash=sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f \ + --hash=sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123 \ + --hash=sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c \ + --hash=sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba \ + --hash=sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c \ + --hash=sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285 \ + --hash=sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd \ + --hash=sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092 \ + --hash=sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa \ + --hash=sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289 \ + --hash=sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02 \ + --hash=sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64 \ + --hash=sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053 \ + --hash=sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417 \ + --hash=sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e \ + --hash=sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e \ + --hash=sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7 \ + --hash=sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756 \ + --hash=sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4 diff --git a/middleware/admin/certificate_v2.py b/middleware/admin/certificate_v2.py index f5bf6a2e..c61faa3c 100644 --- a/middleware/admin/certificate_v2.py +++ b/middleware/admin/certificate_v2.py @@ -25,9 +25,12 @@ import base64 import ecdsa import hashlib +from cryptography import x509 +from cryptography.hazmat.primitives.serialization import PublicFormat, Encoding +from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1 from .certificate_v1 import HSMCertificate from .utils import is_nonempty_hex_string -from sgx.envelope import SgxQuote +from sgx.envelope import SgxQuote, SgxReportBody class HSMCertificateV2Element: @@ -163,11 +166,11 @@ def _init_with_map(self, element_map): @property def message(self): - return self._message.hex() + return SgxReportBody(self._message) @property def key(self): - return self._key.hex() + return ecdsa.VerifyingKey.from_string(self._key, ecdsa.NIST256p) @property def auth_data(self): @@ -178,7 +181,20 @@ def signature(self): return self._signature.hex() def is_valid(self, certifier): - return True + try: + # Validate report data + expected = hashlib.sha256(self.key.to_string() + self._auth_data).digest() + if expected != self.message.report_data.field[:len(expected)]: + return False + + # Verify signature against the certifier + return certifier.get_pubkey().verify_digest( + self._signature, + hashlib.sha256(self._message).digest(), + ecdsa.util.sigdecode_der, + ) + except Exception: + return False def get_pubkey(self): return ecdsa.VerifyingKey.from_string(self._key, ecdsa.NIST256p) @@ -187,8 +203,8 @@ def to_dict(self): return { "name": self.name, "type": "sgx_attestation_key", - "message": self.message, - "key": self.key, + "message": self.message.get_raw_data().hex(), + "key": self.key.to_string("uncompressed").hex(), "auth_data": self.auth_data, "signature": self.signature, "signed_by": self.signed_by, @@ -196,6 +212,9 @@ def to_dict(self): class HSMCertificateV2ElementX509(HSMCertificateV2Element): + HEADER_BEGIN = "-----BEGIN CERTIFICATE-----" + HEADER_END = "-----END CERTIFICATE-----" + @classmethod def from_pemfile(kls, pem_path, name, signed_by): return kls.from_pem(Path(pem_path).read_text(), name, signed_by) @@ -205,14 +224,15 @@ def from_pem(kls, pem_str, name, signed_by): return kls({ "name": name, "message": re.sub(r"[\s\n\r]+", " ", pem_str) - .replace("-----END CERTIFICATE-----", "") - .replace("-----BEGIN CERTIFICATE-----", "") + .replace(kls.HEADER_END, "") + .replace(kls.HEADER_BEGIN, "") .strip().encode(), "signed_by": signed_by, }) def __init__(self, element_map): self._init_with_map(element_map) + self._certificate = None def _init_with_map(self, element_map): super()._init_with_map(element_map) @@ -226,11 +246,29 @@ def _init_with_map(self, element_map): def message(self): return base64.b64encode(self._message).decode("ASCII") + @property + def certificate(self): + if self._certificate is None: + self._certificate = x509.load_pem_x509_certificate(( + self.HEADER_BEGIN + self.message + self.HEADER_END).encode()) + return self._certificate + def is_valid(self, certifier): return True def get_pubkey(self): - return None + try: + public_key = self.certificate.public_key() + + if not isinstance(public_key.curve, SECP256R1): + raise ValueError("Certificate does not have a NIST P-256 public key") + + public_bytes = public_key.public_bytes( + Encoding.X962, PublicFormat.CompressedPoint) + + return ecdsa.VerifyingKey.from_string(public_bytes, ecdsa.NIST256p) + except Exception as e: + raise ValueError(f"Error gathering public key from certificate: {str(e)}") def to_dict(self): return { diff --git a/middleware/da.json b/middleware/da.json deleted file mode 100644 index 104f9c32..00000000 --- a/middleware/da.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": 1, - "targets": [ - "attestation" - ], - "elements": [ - { - "name": "attestation", - "message": "ff044e11fa744fcb5c5a22f71558982272f4fe7ca38219c32c4c790f98f7981b1bc63f84b966ffa0188a8ea74b2831cbf258673bce3e4f76dec3c57e2d790aa437e8", - "signature": "304402205d2084fd806f2f1f043225289cd543f48a87d41d5fc446e44f83971efe584c6c0220769573a7e8348ccc1c9ef68b6b4ec9562f305869fb87f211116a71417e45441d", - "signed_by": "device" - }, - { - "name": "device", - "message": "0210b48081be20280434a28e4185e735964a36b5cd8817cbdde534f2839f04c5f998927a36f08343726de175327fa5272e3929b9c357f36f2128c92e14af359ce0e00734d2c93f4c07", - "signature": "30440220181d61b12165b0dd0548cb574577d9f9419a894da56e5b1323375c3b9435622a0220290a29b2a06bbd481b0d0587abadddee39c002ed7f269ac11b23917e7c5c615e", - "signed_by": "root" - } - ] -} diff --git a/middleware/tests/admin/test_certificate_v2.py b/middleware/tests/admin/test_certificate_v2.py index ae292645..3ac67838 100644 --- a/middleware/tests/admin/test_certificate_v2.py +++ b/middleware/tests/admin/test_certificate_v2.py @@ -20,17 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import ecdsa -import hashlib from unittest import TestCase -from unittest.mock import Mock, patch from parameterized import parameterized from admin.certificate_v1 import HSMCertificate -from sgx.envelope import SgxQuote -from admin.certificate_v2 import HSMCertificateV2, HSMCertificateV2Element, \ - HSMCertificateV2ElementSGXQuote, \ - HSMCertificateV2ElementSGXAttestationKey, \ - HSMCertificateV2ElementX509 +from admin.certificate_v2 import HSMCertificateV2 from .test_certificate_v2_resources import TEST_CERTIFICATE @@ -86,359 +79,3 @@ def test_validate_and_get_values_invalid(self, _, invalid_name): self.assertEqual({ "quote": (False, invalid_name), }, cert.validate_and_get_values("a-root-of-trust")) - - -class TestHSMCertificateV2Element(TestCase): - def setUp(self): - class TestElement(HSMCertificateV2Element): - def __init__(self): - pass - - self.instance = TestElement() - - def test_from_dict_unknown_type(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "a-strange-name", - "type": "an-unknown-type", - "some": "other", - "random": "attributes", - }) - self.assertIn("a-strange-name", str(e.exception)) - - def test_from_dict_no_name(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "type": "sgx_quote", - "signed_by": "a-signer", - "some": "other", - "random": "attributes", - }) - self.assertIn("Missing name", str(e.exception)) - - def test_from_dict_no_signed_by(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "a name", - "type": "sgx_quote", - "some": "other", - "random": "attributes", - }) - self.assertIn("Missing certifier", str(e.exception)) - - def test_cant_instantiate(self): - with self.assertRaises(NotImplementedError): - HSMCertificateV2Element() - - def test_get_pubkey_notimplemented(self): - with self.assertRaises(NotImplementedError): - self.instance.get_pubkey() - - def test_get_value_notimplemented(self): - with self.assertRaises(NotImplementedError): - self.instance.get_value() - - def test_is_valid_notimplemented(self): - with self.assertRaises(NotImplementedError): - self.instance.is_valid("a-certifier") - - -class TestHSMCertificateV2ElementSGXQuote(TestCase): - TEST_MESSAGE = \ - "03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ceae3549bc7273eb34d562f"\ - "4564fc182000000000e0e100fffff01000000000000000000010000000000000000000000000000"\ - "000000000000000000000000000000000005000000000000000700000000000000d32688d3c1f3d"\ - "fcc8b0b36eac7c89d49af331800bd56248044166fa6699442c10000000000000000000000000000"\ - "000000000000000000000000000000000000718c2f1a0efbd513e016fafd6cf62a624442f2d8370"\ - "8d4b33ab5a8d8c1cd4dd00000000000000000000000000000000000000000000000000000000000"\ - "0000000000000000000000000000000000000000000000000000000000000000000000000000000"\ - "0000000000000000000000000000000000000000000000000000000640001000000000000000000"\ - "0000000000000000000000000000000000000000000000000000000000000000000000000000000"\ - "00000000000000000000000005d53b30e22f66979d36721e10ab7722557257a9ef8ba77ec7fe430"\ - "493c3542f90000000000000000000000000000000000000000000000000000000000000000" - - def setUp(self): - self.elem = HSMCertificateV2ElementSGXQuote({ - "name": "thename", - "message": self.TEST_MESSAGE, - "custom_data": "ddeeff", - "signature": "112233", - "signed_by": "whosigned", - }) - - def test_props(self): - self.assertEqual("thename", self.elem.name) - self.assertEqual("whosigned", self.elem.signed_by) - self.assertIsInstance(self.elem.message, SgxQuote) - self.assertEqual(bytes.fromhex(self.TEST_MESSAGE), - self.elem.message.get_raw_data()) - self.assertEqual("ddeeff", self.elem.custom_data) - self.assertEqual("112233", self.elem.signature) - - def test_dict_ok(self): - self.assertEqual({ - "name": "thename", - "type": "sgx_quote", - "message": self.TEST_MESSAGE, - "custom_data": "ddeeff", - "signature": "112233", - "signed_by": "whosigned", - }, self.elem.to_dict()) - - def test_parse_identity(self): - source = TEST_CERTIFICATE["elements"][0] - elem = HSMCertificateV2Element.from_dict(source) - self.assertTrue(isinstance(elem, HSMCertificateV2ElementSGXQuote)) - self.assertEqual(source, elem.to_dict()) - - def test_from_dict_invalid_message(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "quote", - "type": "sgx_quote", - "message": "not-hex", - "custom_data": "112233", - "signature": "445566778899", - "signed_by": "attestation" - }) - self.assertIn("Invalid message", str(e.exception)) - - def test_from_dict_invalid_custom_data(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "quote", - "type": "sgx_quote", - "message": self.TEST_MESSAGE, - "custom_data": "not-hex", - "signature": "445566778899", - "signed_by": "attestation" - }) - self.assertIn("Invalid custom data", str(e.exception)) - - def test_from_dict_invalid_signature(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "quote", - "type": "sgx_quote", - "message": self.TEST_MESSAGE, - "custom_data": "112233", - "signature": "not-hex", - "signed_by": "attestation" - }) - self.assertIn("Invalid signature", str(e.exception)) - - def test_get_pubkey_notimplemented(self): - with self.assertRaises(NotImplementedError): - self.elem.get_pubkey() - - def test_is_valid_ok(self): - pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) - certifier = Mock() - certifier.get_pubkey.return_value = pk.verifying_key - - valid_elem = HSMCertificateV2ElementSGXQuote({ - "name": "thename", - "message": self.TEST_MESSAGE, - "custom_data": "10061982", - "signature": pk.sign_digest( - hashlib.sha256(bytes.fromhex(self.TEST_MESSAGE)).digest(), - sigencode=ecdsa.util.sigencode_der - ).hex(), - "signed_by": "whosigned", - }) - self.assertTrue(valid_elem.is_valid(certifier)) - - def test_is_valid_custom_data_mismatch(self): - pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) - certifier = Mock() - certifier.get_pubkey.return_value = pk.verifying_key - - valid_elem = HSMCertificateV2ElementSGXQuote({ - "name": "thename", - "message": self.TEST_MESSAGE, - "custom_data": "11061982", - "signature": pk.sign_digest( - hashlib.sha256(bytes.fromhex(self.TEST_MESSAGE)).digest(), - sigencode=ecdsa.util.sigencode_der - ).hex(), - "signed_by": "whosigned", - }) - self.assertFalse(valid_elem.is_valid(certifier)) - - def test_is_valid_signature_mismatch(self): - pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) - certifier = Mock() - certifier.get_pubkey.return_value = pk.verifying_key - - valid_elem = HSMCertificateV2ElementSGXQuote({ - "name": "thename", - "message": self.TEST_MESSAGE, - "custom_data": "10061982", - "signature": pk.sign_digest( - hashlib.sha256(b"something else").digest(), - sigencode=ecdsa.util.sigencode_der - ).hex(), - "signed_by": "whosigned", - }) - self.assertFalse(valid_elem.is_valid(certifier)) - - -class TestHSMCertificateV2ElementSGXAttestationKey(TestCase): - def setUp(self): - self.elem = HSMCertificateV2ElementSGXAttestationKey({ - "name": "thename", - "message": "aabbcc", - "key": "ddeeff", - "auth_data": "112233", - "signature": "44556677", - "signed_by": "whosigned", - }) - - def test_props(self): - self.assertEqual("thename", self.elem.name) - self.assertEqual("whosigned", self.elem.signed_by) - self.assertEqual("aabbcc", self.elem.message) - self.assertEqual("ddeeff", self.elem.key) - self.assertEqual("112233", self.elem.auth_data) - self.assertEqual("44556677", self.elem.signature) - - def test_dict_ok(self): - self.assertEqual({ - "name": "thename", - "type": "sgx_attestation_key", - "message": "aabbcc", - "key": "ddeeff", - "auth_data": "112233", - "signature": "44556677", - "signed_by": "whosigned", - }, self.elem.to_dict()) - - def test_parse_identity(self): - source = TEST_CERTIFICATE["elements"][1] - elem = HSMCertificateV2Element.from_dict(source) - self.assertTrue(isinstance(elem, HSMCertificateV2ElementSGXAttestationKey)) - self.assertEqual(source, elem.to_dict()) - - def test_from_dict_invalid_message(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "attestation", - "type": "sgx_attestation_key", - "message": "not-hex", - "key": "eeff", - "auth_data": "112233", - "signature": "44556677", - "signed_by": "quoting_enclave" - }) - self.assertIn("Invalid message", str(e.exception)) - - def test_from_dict_invalid_key(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "attestation", - "type": "sgx_attestation_key", - "message": "aabbccdd", - "key": "not-hex", - "auth_data": "112233", - "signature": "44556677", - "signed_by": "quoting_enclave" - }) - self.assertIn("Invalid key", str(e.exception)) - - def test_from_dict_invalid_auth_data(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "attestation", - "type": "sgx_attestation_key", - "message": "aabbccdd", - "key": "eeff", - "auth_data": "not-hex", - "signature": "44556677", - "signed_by": "quoting_enclave" - }) - self.assertIn("Invalid auth data", str(e.exception)) - - def test_from_dict_invalid_signature(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "attestation", - "type": "sgx_attestation_key", - "message": "aabbccdd", - "key": "eeff", - "auth_data": "112233", - "signature": "not-hex", - "signed_by": "quoting_enclave" - }) - self.assertIn("Invalid signature", str(e.exception)) - - def test_get_value_notimplemented(self): - with self.assertRaises(NotImplementedError): - self.elem.get_value() - - -class TestHSMCertificateV2ElementX509(TestCase): - def setUp(self): - self.elem = HSMCertificateV2ElementX509({ - "name": "thename", - "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", - "signed_by": "whosigned", - }) - - def test_props(self): - self.assertEqual("thename", self.elem.name) - self.assertEqual("whosigned", self.elem.signed_by) - self.assertEqual("dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", self.elem.message) - - def test_dict_ok(self): - self.assertEqual({ - "name": "thename", - "type": "x509_pem", - "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", - "signed_by": "whosigned", - }, self.elem.to_dict()) - - def test_parse_identity(self): - source = TEST_CERTIFICATE["elements"][3] - elem = HSMCertificateV2Element.from_dict(source) - self.assertTrue(isinstance(elem, HSMCertificateV2ElementX509)) - self.assertEqual(source, elem.to_dict()) - - def test_from_dict_invalid_message(self): - with self.assertRaises(ValueError) as e: - HSMCertificateV2Element.from_dict({ - "name": "quoting_enclave", - "type": "x509_pem", - "message": "not-base-64", - "signed_by": "platform_ca" - }) - self.assertIn("Invalid message", str(e.exception)) - - def test_get_value_notimplemented(self): - with self.assertRaises(NotImplementedError): - self.elem.get_value() - - def test_from_pem(self): - self.assertEqual({ - "name": "thename", - "type": "x509_pem", - "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", - "signed_by": "whosigned", - }, HSMCertificateV2ElementX509.from_pem(""" - -----BEGIN CERTIFICATE----- - dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl - -----END CERTIFICATE----- - """, "thename", "whosigned").to_dict()) - - @patch("admin.certificate_v2.Path") - @patch("admin.certificate_v2.HSMCertificateV2ElementX509.from_pem") - def test_from_pemfile(self, from_pem, Path): - Path.return_value.read_text.return_value = "the pem contents" - from_pem.return_value = "the instance" - self.assertEqual("the instance", - HSMCertificateV2ElementX509.from_pemfile("a-file.pem", - "the name", - "who signed")) - Path.assert_called_with("a-file.pem") - from_pem.assert_called_with("the pem contents", - "the name", - "who signed") diff --git a/middleware/tests/admin/test_certificate_v2_element.py b/middleware/tests/admin/test_certificate_v2_element.py new file mode 100644 index 00000000..dcd717b5 --- /dev/null +++ b/middleware/tests/admin/test_certificate_v2_element.py @@ -0,0 +1,79 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from unittest import TestCase +from admin.certificate_v2 import HSMCertificateV2Element + + +class TestHSMCertificateV2Element(TestCase): + def setUp(self): + class TestElement(HSMCertificateV2Element): + def __init__(self): + pass + + self.instance = TestElement() + + def test_from_dict_unknown_type(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "a-strange-name", + "type": "an-unknown-type", + "some": "other", + "random": "attributes", + }) + self.assertIn("a-strange-name", str(e.exception)) + + def test_from_dict_no_name(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "type": "sgx_quote", + "signed_by": "a-signer", + "some": "other", + "random": "attributes", + }) + self.assertIn("Missing name", str(e.exception)) + + def test_from_dict_no_signed_by(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "a name", + "type": "sgx_quote", + "some": "other", + "random": "attributes", + }) + self.assertIn("Missing certifier", str(e.exception)) + + def test_cant_instantiate(self): + with self.assertRaises(NotImplementedError): + HSMCertificateV2Element() + + def test_get_pubkey_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.instance.get_pubkey() + + def test_get_value_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.instance.get_value() + + def test_is_valid_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.instance.is_valid("a-certifier") diff --git a/middleware/tests/admin/test_certificate_v2_element_sgx_attestation_key.py b/middleware/tests/admin/test_certificate_v2_element_sgx_attestation_key.py new file mode 100644 index 00000000..e739cb9c --- /dev/null +++ b/middleware/tests/admin/test_certificate_v2_element_sgx_attestation_key.py @@ -0,0 +1,168 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import ecdsa +from unittest import TestCase +from unittest.mock import Mock +from admin.certificate_v2 import HSMCertificateV2Element, \ + HSMCertificateV2ElementSGXAttestationKey +from .test_certificate_v2_resources import TEST_CERTIFICATE + + +class TestHSMCertificateV2ElementSGXAttestationKey(TestCase): + def setUp(self): + self.source = TEST_CERTIFICATE["elements"][1] + self.elem = HSMCertificateV2ElementSGXAttestationKey(self.source) + valid_key = ecdsa.VerifyingKey.from_string( + bytes.fromhex("03a97b443365b192a412d01c5bb49f097d497a06ef1aae0ed2b454b74c" + "ff1ba7d9"), + ecdsa.NIST256p) + self.valid_certifier = Mock() + self.valid_certifier.get_pubkey.return_value = valid_key + + def test_props(self): + self.assertEqual("attestation", self.elem.name) + self.assertEqual("quoting_enclave", self.elem.signed_by) + self.assertEqual(bytes.fromhex( + "0e0e100fffff01000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000001500000000000000e70000000000000096b347a64e5a045e2736" + "9c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e4000000000000000000000000000000" + "00000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8d" + "ed70140b081b094490c57bff00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000001000a" + "00000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000001fe721d0322954821589237fd2" + "7efb8fef1acb3ecd6b0352c31271550fc70f94000000000000000000000000000000000000" + "0000000000000000000000000000"), self.elem.message.get_raw_data()) + self.assertEqual(bytes.fromhex( + "03a024cb34c90ea6a8f9f2181c9020cbcc7c073e69981733c8deed6f6c451822aa"), + self.elem.key.to_string("compressed")) + self.assertEqual( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + self.elem.auth_data) + self.assertEqual( + "304502201f14d532274c4385fc0019ca2a21e53e17143cb62377ca4fcdd97fa9fef8fb25022" + "10095d4ee272cf3c512e36779de67dc7814982f1160d981d138a32b265e928a0562", + self.elem.signature) + + def test_to_dict(self): + self.assertEqual(self.source, self.elem.to_dict()) + + def test_parse_identity(self): + elem = HSMCertificateV2Element.from_dict(self.source) + self.assertTrue(isinstance(elem, HSMCertificateV2ElementSGXAttestationKey)) + self.assertEqual(self.source, elem.to_dict()) + + def test_from_dict_invalid_message(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "message": "not-hex", + }) + self.assertIn("Invalid message", str(e.exception)) + + def test_from_dict_invalid_key(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "key": "not-hex", + }) + self.assertIn("Invalid key", str(e.exception)) + + def test_from_dict_invalid_auth_data(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "auth_data": "not-hex", + }) + self.assertIn("Invalid auth data", str(e.exception)) + + def test_from_dict_invalid_signature(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "signature": "not-hex", + }) + self.assertIn("Invalid signature", str(e.exception)) + + def test_get_value_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.elem.get_value() + + def test_is_valid_ok(self): + self.assertTrue(self.elem.is_valid(self.valid_certifier)) + + def test_is_valid_err_notthekey(self): + invalid_key = ecdsa.VerifyingKey.from_string( + bytes.fromhex("03986284e40eafc53a650547216176d4a227e1fa3a4473b76e48cfc442" + "efa004c4"), + ecdsa.NIST256p) + certifier = Mock() + certifier.get_pubkey.return_value = invalid_key + self.assertFalse(self.elem.is_valid(certifier)) + + def test_is_valid_err_message(self): + self.elem = HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "message": "1e0e100fffff010000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000001500000000000000e70000000000000096b" + "347a64e5a045e27369c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e40000000000" + "0000000000000000000000000000000000000000000000000000008c4f5775d796503e9" + "6137f77c68a829a0056ac8ded70140b081b094490c57bff000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000001000a000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000001fe721d0322954821589237fd27efb8fef1acb3ecd6b0352c31271550fc" + "70f940000000000000000000000000000000000000000000000000000000000000000", + }) + self.assertFalse(self.elem.is_valid(self.valid_certifier)) + + def test_is_valid_err_message_invalid(self): + self.elem = HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "message": "aabbccdd", + }) + self.assertFalse(self.elem.is_valid(self.valid_certifier)) + + def test_is_valid_err_auth_data(self): + self.elem = HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "auth_data": "aabbccdd", + }) + self.assertFalse(self.elem.is_valid(self.valid_certifier)) + + def test_is_valid_err_key(self): + self.elem = HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "key": "03e2005bbf9db399bcba0b40d181b691f0d81287dbc1b6280bebd9247b" + "c0933f38", + }) + self.assertFalse(self.elem.is_valid(self.valid_certifier)) + + def test_is_valid_err_key_invalid(self): + self.elem = HSMCertificateV2ElementSGXAttestationKey({ + **self.source, + "key": "aabbccdd", + }) + self.assertFalse(self.elem.is_valid(self.valid_certifier)) diff --git a/middleware/tests/admin/test_certificate_v2_element_sgx_quote.py b/middleware/tests/admin/test_certificate_v2_element_sgx_quote.py new file mode 100644 index 00000000..5d7554ea --- /dev/null +++ b/middleware/tests/admin/test_certificate_v2_element_sgx_quote.py @@ -0,0 +1,170 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import ecdsa +import hashlib +from unittest import TestCase +from unittest.mock import Mock +from sgx.envelope import SgxQuote +from admin.certificate_v2 import HSMCertificateV2Element, \ + HSMCertificateV2ElementSGXQuote +from .test_certificate_v2_resources import TEST_CERTIFICATE + + +class TestHSMCertificateV2ElementSGXQuote(TestCase): + TEST_MESSAGE = \ + "03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ceae3549bc7273eb34d562f"\ + "4564fc182000000000e0e100fffff01000000000000000000010000000000000000000000000000"\ + "000000000000000000000000000000000005000000000000000700000000000000d32688d3c1f3d"\ + "fcc8b0b36eac7c89d49af331800bd56248044166fa6699442c10000000000000000000000000000"\ + "000000000000000000000000000000000000718c2f1a0efbd513e016fafd6cf62a624442f2d8370"\ + "8d4b33ab5a8d8c1cd4dd00000000000000000000000000000000000000000000000000000000000"\ + "0000000000000000000000000000000000000000000000000000000000000000000000000000000"\ + "0000000000000000000000000000000000000000000000000000000640001000000000000000000"\ + "0000000000000000000000000000000000000000000000000000000000000000000000000000000"\ + "00000000000000000000000005d53b30e22f66979d36721e10ab7722557257a9ef8ba77ec7fe430"\ + "493c3542f90000000000000000000000000000000000000000000000000000000000000000" + + def setUp(self): + self.elem = HSMCertificateV2ElementSGXQuote({ + "name": "thename", + "message": self.TEST_MESSAGE, + "custom_data": "ddeeff", + "signature": "112233", + "signed_by": "whosigned", + }) + + def test_props(self): + self.assertEqual("thename", self.elem.name) + self.assertEqual("whosigned", self.elem.signed_by) + self.assertIsInstance(self.elem.message, SgxQuote) + self.assertEqual(bytes.fromhex(self.TEST_MESSAGE), + self.elem.message.get_raw_data()) + self.assertEqual("ddeeff", self.elem.custom_data) + self.assertEqual("112233", self.elem.signature) + + def test_dict_ok(self): + self.assertEqual({ + "name": "thename", + "type": "sgx_quote", + "message": self.TEST_MESSAGE, + "custom_data": "ddeeff", + "signature": "112233", + "signed_by": "whosigned", + }, self.elem.to_dict()) + + def test_parse_identity(self): + source = TEST_CERTIFICATE["elements"][0] + elem = HSMCertificateV2Element.from_dict(source) + self.assertTrue(isinstance(elem, HSMCertificateV2ElementSGXQuote)) + self.assertEqual(source, elem.to_dict()) + + def test_from_dict_invalid_message(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "quote", + "type": "sgx_quote", + "message": "not-hex", + "custom_data": "112233", + "signature": "445566778899", + "signed_by": "attestation" + }) + self.assertIn("Invalid message", str(e.exception)) + + def test_from_dict_invalid_custom_data(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "quote", + "type": "sgx_quote", + "message": self.TEST_MESSAGE, + "custom_data": "not-hex", + "signature": "445566778899", + "signed_by": "attestation" + }) + self.assertIn("Invalid custom data", str(e.exception)) + + def test_from_dict_invalid_signature(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "quote", + "type": "sgx_quote", + "message": self.TEST_MESSAGE, + "custom_data": "112233", + "signature": "not-hex", + "signed_by": "attestation" + }) + self.assertIn("Invalid signature", str(e.exception)) + + def test_get_pubkey_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.elem.get_pubkey() + + def test_is_valid_ok(self): + pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) + certifier = Mock() + certifier.get_pubkey.return_value = pk.verifying_key + + valid_elem = HSMCertificateV2ElementSGXQuote({ + "name": "thename", + "message": self.TEST_MESSAGE, + "custom_data": "10061982", + "signature": pk.sign_digest( + hashlib.sha256(bytes.fromhex(self.TEST_MESSAGE)).digest(), + sigencode=ecdsa.util.sigencode_der + ).hex(), + "signed_by": "whosigned", + }) + self.assertTrue(valid_elem.is_valid(certifier)) + + def test_is_valid_custom_data_mismatch(self): + pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) + certifier = Mock() + certifier.get_pubkey.return_value = pk.verifying_key + + valid_elem = HSMCertificateV2ElementSGXQuote({ + "name": "thename", + "message": self.TEST_MESSAGE, + "custom_data": "11061982", + "signature": pk.sign_digest( + hashlib.sha256(bytes.fromhex(self.TEST_MESSAGE)).digest(), + sigencode=ecdsa.util.sigencode_der + ).hex(), + "signed_by": "whosigned", + }) + self.assertFalse(valid_elem.is_valid(certifier)) + + def test_is_valid_signature_mismatch(self): + pk = ecdsa.SigningKey.generate(ecdsa.NIST256p) + certifier = Mock() + certifier.get_pubkey.return_value = pk.verifying_key + + valid_elem = HSMCertificateV2ElementSGXQuote({ + "name": "thename", + "message": self.TEST_MESSAGE, + "custom_data": "10061982", + "signature": pk.sign_digest( + hashlib.sha256(b"something else").digest(), + sigencode=ecdsa.util.sigencode_der + ).hex(), + "signed_by": "whosigned", + }) + self.assertFalse(valid_elem.is_valid(certifier)) diff --git a/middleware/tests/admin/test_certificate_v2_element_x509.py b/middleware/tests/admin/test_certificate_v2_element_x509.py new file mode 100644 index 00000000..b5fd0c17 --- /dev/null +++ b/middleware/tests/admin/test_certificate_v2_element_x509.py @@ -0,0 +1,200 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from unittest import TestCase +from unittest.mock import Mock, patch +from ecdsa import NIST256p +from cryptography.hazmat.primitives.serialization import PublicFormat, Encoding +from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1 +from admin.certificate_v2 import HSMCertificateV2Element, \ + HSMCertificateV2ElementX509 +from .test_certificate_v2_resources import TEST_CERTIFICATE + + +class TestHSMCertificateV2ElementX509(TestCase): + def setUp(self): + self.elem = HSMCertificateV2ElementX509({ + "name": "thename", + "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", + "signed_by": "whosigned", + }) + + def test_props(self): + self.assertEqual("thename", self.elem.name) + self.assertEqual("whosigned", self.elem.signed_by) + self.assertEqual("dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", self.elem.message) + + def test_dict_ok(self): + self.assertEqual({ + "name": "thename", + "type": "x509_pem", + "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", + "signed_by": "whosigned", + }, self.elem.to_dict()) + + def test_parse_identity(self): + source = TEST_CERTIFICATE["elements"][3] + elem = HSMCertificateV2Element.from_dict(source) + self.assertTrue(isinstance(elem, HSMCertificateV2ElementX509)) + self.assertEqual(source, elem.to_dict()) + + def test_from_dict_invalid_message(self): + with self.assertRaises(ValueError) as e: + HSMCertificateV2Element.from_dict({ + "name": "quoting_enclave", + "type": "x509_pem", + "message": "not-base-64", + "signed_by": "platform_ca" + }) + self.assertIn("Invalid message", str(e.exception)) + + def test_get_value_notimplemented(self): + with self.assertRaises(NotImplementedError): + self.elem.get_value() + + def test_from_pem(self): + self.assertEqual({ + "name": "thename", + "type": "x509_pem", + "message": "dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl", + "signed_by": "whosigned", + }, HSMCertificateV2ElementX509.from_pem(""" + -----BEGIN CERTIFICATE----- + dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl + -----END CERTIFICATE----- + """, "thename", "whosigned").to_dict()) + + @patch("admin.certificate_v2.Path") + @patch("admin.certificate_v2.HSMCertificateV2ElementX509.from_pem") + def test_from_pemfile(self, from_pem, Path): + Path.return_value.read_text.return_value = "the pem contents" + from_pem.return_value = "the instance" + self.assertEqual("the instance", + HSMCertificateV2ElementX509.from_pemfile("a-file.pem", + "the name", + "who signed")) + Path.assert_called_with("a-file.pem") + from_pem.assert_called_with("the pem contents", + "the name", + "who signed") + + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_certificate(self, load_pem_x509_certificate): + load_pem_x509_certificate.return_value = "mock-certificate" + + self.assertEqual("mock-certificate", self.elem.certificate) + self.assertEqual("mock-certificate", self.elem.certificate) + + load_pem_x509_certificate.assert_called_with( + b"-----BEGIN CERTIFICATE-----" + b"dGhpcyBpcyBhbiBhc2NpaSBtZXNzYWdl" + b"-----END CERTIFICATE-----" + ) + self.assertEqual(1, load_pem_x509_certificate.call_count) + + def setup_is_valid_mocks(self, load_pem_x509_certificate, VerifyingKey): + self.pubkey = Mock() + self.pubkey.curve = SECP256R1() + self.pubkey.public_bytes.return_value = "the-public-bytes" + self.cert = Mock() + self.cert.public_key.return_value = self.pubkey + load_pem_x509_certificate.return_value = self.cert + VerifyingKey.from_string.return_value = "the-expected-pubkey" + + @patch("admin.certificate_v2.ecdsa.VerifyingKey") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_get_pubkey_ok(self, load_pem_x509_certificate, VerifyingKey): + self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + + self.assertEqual("the-expected-pubkey", self.elem.get_pubkey()) + self.pubkey.public_bytes.assert_called_with( + Encoding.X962, PublicFormat.CompressedPoint) + VerifyingKey.from_string.assert_called_with("the-public-bytes", NIST256p) + + @patch("admin.certificate_v2.ecdsa.VerifyingKey") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_get_pubkey_err_load_cert(self, load_pem_x509_certificate, VerifyingKey): + self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + load_pem_x509_certificate.side_effect = Exception("blah blah") + + with self.assertRaises(ValueError) as e: + self.elem.get_pubkey() + self.assertIn("gathering public key", str(e.exception)) + self.assertIn("blah blah", str(e.exception)) + self.pubkey.public_bytes.assert_not_called() + VerifyingKey.from_string.assert_not_called() + + @patch("admin.certificate_v2.ecdsa.VerifyingKey") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_get_pubkey_err_get_pub(self, load_pem_x509_certificate, VerifyingKey): + self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.cert.public_key.side_effect = Exception("blah blah") + + with self.assertRaises(ValueError) as e: + self.elem.get_pubkey() + self.assertIn("gathering public key", str(e.exception)) + self.assertIn("blah blah", str(e.exception)) + self.pubkey.public_bytes.assert_not_called() + VerifyingKey.from_string.assert_not_called() + + @patch("admin.certificate_v2.ecdsa.VerifyingKey") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_get_pubkey_err_pub_notnistp256(self, load_pem_x509_certificate, + VerifyingKey): + self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.pubkey.curve = "somethingelse" + + with self.assertRaises(ValueError) as e: + self.elem.get_pubkey() + self.assertIn("gathering public key", str(e.exception)) + self.assertIn("NIST P-256", str(e.exception)) + self.pubkey.public_bytes.assert_not_called() + VerifyingKey.from_string.assert_not_called() + + @patch("admin.certificate_v2.ecdsa.VerifyingKey") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_get_pubkey_err_public_bytes(self, load_pem_x509_certificate, VerifyingKey): + self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.pubkey.public_bytes.side_effect = Exception("blah blah") + + with self.assertRaises(ValueError) as e: + self.elem.get_pubkey() + self.assertIn("gathering public key", str(e.exception)) + self.assertIn("blah blah", str(e.exception)) + self.pubkey.public_bytes.assert_called_with( + Encoding.X962, PublicFormat.CompressedPoint) + VerifyingKey.from_string.assert_not_called() + + @patch("admin.certificate_v2.ecdsa.VerifyingKey") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_get_pubkey_err_ecdsafromstring(self, load_pem_x509_certificate, + VerifyingKey): + self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + VerifyingKey.from_string.side_effect = Exception("blah blah") + + with self.assertRaises(ValueError) as e: + self.elem.get_pubkey() + self.assertIn("gathering public key", str(e.exception)) + self.assertIn("blah blah", str(e.exception)) + self.pubkey.public_bytes.assert_called_with( + Encoding.X962, PublicFormat.CompressedPoint) + VerifyingKey.from_string.assert_called_with("the-public-bytes", NIST256p) From 92445fd6ab8b592a4feedba93d7f4ff0b3830957 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 8 Jan 2025 06:07:34 +1300 Subject: [PATCH 35/50] Certificate V2 x509_pem type element validation (#240) * Certificate V2 x509_pem type element validation - Implemented HSMCertificateV2ElementX509's is_valid method - Added root of trust element validation in SGX attestation verification - Added and updated unit tests * Changes as per PR review --- middleware/admin/certificate_v2.py | 36 +++++- middleware/admin/verify_sgx_attestation.py | 3 + .../admin/test_certificate_v2_element_x509.py | 107 ++++++++++++++++-- .../admin/test_verify_sgx_attestation.py | 54 +++++++-- 4 files changed, 182 insertions(+), 18 deletions(-) diff --git a/middleware/admin/certificate_v2.py b/middleware/admin/certificate_v2.py index c61faa3c..e0488d54 100644 --- a/middleware/admin/certificate_v2.py +++ b/middleware/admin/certificate_v2.py @@ -21,13 +21,14 @@ # SOFTWARE. import re -from pathlib import Path import base64 import ecdsa import hashlib +from datetime import datetime, UTC +from pathlib import Path from cryptography import x509 from cryptography.hazmat.primitives.serialization import PublicFormat, Encoding -from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1 +from cryptography.hazmat.primitives.asymmetric import ec from .certificate_v1 import HSMCertificate from .utils import is_nonempty_hex_string from sgx.envelope import SgxQuote, SgxReportBody @@ -254,13 +255,40 @@ def certificate(self): return self._certificate def is_valid(self, certifier): - return True + try: + # IMPORTANT: for now, we only allow verifying the validity of an + # HSMCertificateV2ElementX509 using another HSMCertificateV2ElementX509 + # instance as certifier. That way, we simplify the validation procedure + # and ensure maximum use of the underlying library's capabilities + # (cryptography) + if not isinstance(certifier, type(self)): + return False + + subject = self.certificate + issuer = certifier.certificate + now = datetime.now(UTC) + + # 1. Check validity period + if subject.not_valid_before_utc > now or subject.not_valid_after_utc < now: + return False + + # 2. Verify the signature + issuer.public_key().verify( + subject.signature, + subject.tbs_certificate_bytes, + ec.ECDSA(subject.signature_hash_algorithm) + ) + + return True + + except Exception: + return False def get_pubkey(self): try: public_key = self.certificate.public_key() - if not isinstance(public_key.curve, SECP256R1): + if not isinstance(public_key.curve, ec.SECP256R1): raise ValueError("Certificate does not have a NIST P-256 public key") public_bytes = public_key.public_bytes( diff --git a/middleware/admin/verify_sgx_attestation.py b/middleware/admin/verify_sgx_attestation.py index 1e8672fb..bb0f2903 100644 --- a/middleware/admin/verify_sgx_attestation.py +++ b/middleware/admin/verify_sgx_attestation.py @@ -53,6 +53,9 @@ def do_verify_attestation(options): info(f"Attempting to gather root authority from {root_authority}...") try: root_of_trust = get_root_of_trust(root_authority) + info("Attempting to validate self-signed root authority...") + if not root_of_trust.is_valid(root_of_trust): + raise ValueError("Failed to validate self-signed root of trust") except Exception as e: raise AdminError(f"Invalid root authority {root_authority}: {e}") info(f"Using {root_authority} as root authority") diff --git a/middleware/tests/admin/test_certificate_v2_element_x509.py b/middleware/tests/admin/test_certificate_v2_element_x509.py index b5fd0c17..f4f8f4dc 100644 --- a/middleware/tests/admin/test_certificate_v2_element_x509.py +++ b/middleware/tests/admin/test_certificate_v2_element_x509.py @@ -20,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from datetime import datetime, timedelta, UTC from unittest import TestCase from unittest.mock import Mock, patch from ecdsa import NIST256p @@ -111,7 +112,7 @@ def test_certificate(self, load_pem_x509_certificate): ) self.assertEqual(1, load_pem_x509_certificate.call_count) - def setup_is_valid_mocks(self, load_pem_x509_certificate, VerifyingKey): + def setup_pubkey_mocks(self, load_pem_x509_certificate, VerifyingKey): self.pubkey = Mock() self.pubkey.curve = SECP256R1() self.pubkey.public_bytes.return_value = "the-public-bytes" @@ -123,7 +124,7 @@ def setup_is_valid_mocks(self, load_pem_x509_certificate, VerifyingKey): @patch("admin.certificate_v2.ecdsa.VerifyingKey") @patch("admin.certificate_v2.x509.load_pem_x509_certificate") def test_get_pubkey_ok(self, load_pem_x509_certificate, VerifyingKey): - self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.setup_pubkey_mocks(load_pem_x509_certificate, VerifyingKey) self.assertEqual("the-expected-pubkey", self.elem.get_pubkey()) self.pubkey.public_bytes.assert_called_with( @@ -133,7 +134,7 @@ def test_get_pubkey_ok(self, load_pem_x509_certificate, VerifyingKey): @patch("admin.certificate_v2.ecdsa.VerifyingKey") @patch("admin.certificate_v2.x509.load_pem_x509_certificate") def test_get_pubkey_err_load_cert(self, load_pem_x509_certificate, VerifyingKey): - self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.setup_pubkey_mocks(load_pem_x509_certificate, VerifyingKey) load_pem_x509_certificate.side_effect = Exception("blah blah") with self.assertRaises(ValueError) as e: @@ -146,7 +147,7 @@ def test_get_pubkey_err_load_cert(self, load_pem_x509_certificate, VerifyingKey) @patch("admin.certificate_v2.ecdsa.VerifyingKey") @patch("admin.certificate_v2.x509.load_pem_x509_certificate") def test_get_pubkey_err_get_pub(self, load_pem_x509_certificate, VerifyingKey): - self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.setup_pubkey_mocks(load_pem_x509_certificate, VerifyingKey) self.cert.public_key.side_effect = Exception("blah blah") with self.assertRaises(ValueError) as e: @@ -160,7 +161,7 @@ def test_get_pubkey_err_get_pub(self, load_pem_x509_certificate, VerifyingKey): @patch("admin.certificate_v2.x509.load_pem_x509_certificate") def test_get_pubkey_err_pub_notnistp256(self, load_pem_x509_certificate, VerifyingKey): - self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.setup_pubkey_mocks(load_pem_x509_certificate, VerifyingKey) self.pubkey.curve = "somethingelse" with self.assertRaises(ValueError) as e: @@ -173,7 +174,7 @@ def test_get_pubkey_err_pub_notnistp256(self, load_pem_x509_certificate, @patch("admin.certificate_v2.ecdsa.VerifyingKey") @patch("admin.certificate_v2.x509.load_pem_x509_certificate") def test_get_pubkey_err_public_bytes(self, load_pem_x509_certificate, VerifyingKey): - self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.setup_pubkey_mocks(load_pem_x509_certificate, VerifyingKey) self.pubkey.public_bytes.side_effect = Exception("blah blah") with self.assertRaises(ValueError) as e: @@ -188,7 +189,7 @@ def test_get_pubkey_err_public_bytes(self, load_pem_x509_certificate, VerifyingK @patch("admin.certificate_v2.x509.load_pem_x509_certificate") def test_get_pubkey_err_ecdsafromstring(self, load_pem_x509_certificate, VerifyingKey): - self.setup_is_valid_mocks(load_pem_x509_certificate, VerifyingKey) + self.setup_pubkey_mocks(load_pem_x509_certificate, VerifyingKey) VerifyingKey.from_string.side_effect = Exception("blah blah") with self.assertRaises(ValueError) as e: @@ -198,3 +199,95 @@ def test_get_pubkey_err_ecdsafromstring(self, load_pem_x509_certificate, self.pubkey.public_bytes.assert_called_with( Encoding.X962, PublicFormat.CompressedPoint) VerifyingKey.from_string.assert_called_with("the-public-bytes", NIST256p) + + def setup_is_valid_mocks(self, load_pem_x509_certificate, ec): + self.certifier = HSMCertificateV2ElementX509({ + "name": "mock-certifier", + "signed_by": "someone-else", + "message": "Y2VydGlmaWVy" + }) + + self.mock_certifier = Mock() + self.mock_elem = Mock() + + def load_mock(data): + if b"Y2VydGlmaWVy" in data: + return self.mock_certifier + return self.mock_elem + + load_pem_x509_certificate.side_effect = load_mock + + self.now = datetime.now(UTC) + one_week = timedelta(weeks=1) + self.mock_elem.not_valid_before_utc = self.now - one_week + self.mock_elem.not_valid_after_utc = self.now + one_week + self.mock_certifier_pk = Mock() + self.mock_certifier.public_key.return_value = self.mock_certifier_pk + self.mock_elem.signature = "the-signature" + self.mock_elem.tbs_certificate_bytes = "the-fingerprint" + self.mock_elem.signature_hash_algorithm = "the-signature-hash-algo" + ec.ECDSA.return_value = "the-ecdsa-algo" + + @patch("admin.certificate_v2.ec") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_is_valid_ok(self, load_pem_x509_certificate, ec): + self.setup_is_valid_mocks(load_pem_x509_certificate, ec) + + self.assertTrue(self.elem.is_valid(self.certifier)) + + self.mock_certifier_pk.verify.assert_called_with( + "the-signature", + "the-fingerprint", + "the-ecdsa-algo" + ) + ec.ECDSA.assert_called_with("the-signature-hash-algo") + + @patch("admin.certificate_v2.ec") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_is_valid_before_in_future(self, load_pem_x509_certificate, ec): + self.setup_is_valid_mocks(load_pem_x509_certificate, ec) + self.mock_elem.not_valid_before_utc = self.now + \ + timedelta(minutes=1) + + self.assertFalse(self.elem.is_valid(self.certifier)) + + self.mock_certifier_pk.verify.assert_not_called() + ec.ECDSA.assert_not_called() + + @patch("admin.certificate_v2.ec") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_is_valid_after_in_past(self, load_pem_x509_certificate, ec): + self.setup_is_valid_mocks(load_pem_x509_certificate, ec) + self.mock_elem.not_valid_after_utc = self.now - \ + timedelta(minutes=1) + + self.assertFalse(self.elem.is_valid(self.certifier)) + + self.mock_certifier_pk.verify.assert_not_called() + ec.ECDSA.assert_not_called() + + @patch("admin.certificate_v2.ec") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_is_valid_signature_invalid(self, load_pem_x509_certificate, ec): + self.setup_is_valid_mocks(load_pem_x509_certificate, ec) + self.mock_certifier_pk.verify.side_effect = RuntimeError("wrong signature") + + self.assertFalse(self.elem.is_valid(self.certifier)) + + self.mock_certifier_pk.verify.assert_called_with( + "the-signature", + "the-fingerprint", + "the-ecdsa-algo" + ) + ec.ECDSA.assert_called_with("the-signature-hash-algo") + + @patch("admin.certificate_v2.ec") + @patch("admin.certificate_v2.x509.load_pem_x509_certificate") + def test_is_valid_x509_error(self, load_pem_x509_certificate, ec): + self.setup_is_valid_mocks(load_pem_x509_certificate, ec) + load_pem_x509_certificate.side_effect = ValueError("a random error") + + self.assertFalse(self.elem.is_valid(self.certifier)) + + self.mock_certifier_pk.verify.assert_not_called() + ec.ECDSA.assert_not_called() diff --git a/middleware/tests/admin/test_verify_sgx_attestation.py b/middleware/tests/admin/test_verify_sgx_attestation.py index 5bacadf5..cf980d9b 100644 --- a/middleware/tests/admin/test_verify_sgx_attestation.py +++ b/middleware/tests/admin/test_verify_sgx_attestation.py @@ -94,7 +94,9 @@ def setUp(self): def configure_mocks(self, get_root_of_trust, load_pubkeys, HSMCertificate, head): - get_root_of_trust.return_value = "the-root-of-trust" + self.root_of_trust = Mock() + self.root_of_trust.is_valid.return_value = True + get_root_of_trust.return_value = self.root_of_trust load_pubkeys.return_value = self.public_keys self.mock_certificate = Mock() self.mock_certificate.validate_and_get_values.return_value = self.validate_result @@ -116,10 +118,11 @@ def test_verify_attestation(self, get_root_of_trust, load_pubkeys, get_root_of_trust.assert_called_with(custom_root) else: get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) load_pubkeys.assert_called_with(self.pubkeys_path) HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) self.mock_certificate.validate_and_get_values \ - .assert_called_with("the-root-of-trust") + .assert_called_with(self.root_of_trust) head.assert_called_with([ "powHSM verified with public keys:" ] + self.expected_pubkeys_output + [ @@ -135,6 +138,36 @@ def test_verify_attestation(self, get_root_of_trust, load_pubkeys, "Timestamp: 205", ], fill="-") + def test_verify_attestation_err_get_root(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + get_root_of_trust.side_effect = ValueError("root of trust error") + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("root of trust error", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_not_called() + load_pubkeys.assert_not_called() + HSMCertificate.from_jsonfile.assert_not_called() + self.mock_certificate.validate_and_get_values.assert_not_called() + + def test_verify_attestation_err_root_invalid(self, get_root_of_trust, load_pubkeys, + HSMCertificate, head, _): + self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) + self.root_of_trust.is_valid.return_value = False + + with self.assertRaises(AdminError) as e: + do_verify_attestation(self.options) + self.assertIn("self-signed root of trust", str(e.exception)) + + get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) + load_pubkeys.assert_not_called() + HSMCertificate.from_jsonfile.assert_not_called() + self.mock_certificate.validate_and_get_values.assert_not_called() + def test_verify_attestation_err_load_pubkeys(self, get_root_of_trust, load_pubkeys, HSMCertificate, head, _): self.configure_mocks(get_root_of_trust, load_pubkeys, HSMCertificate, head) @@ -145,6 +178,7 @@ def test_verify_attestation_err_load_pubkeys(self, get_root_of_trust, load_pubke self.assertIn("pubkeys error", str(e.exception)) get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) load_pubkeys.assert_called_with(self.pubkeys_path) HSMCertificate.from_jsonfile.assert_not_called() self.mock_certificate.validate_and_get_values.assert_not_called() @@ -159,6 +193,7 @@ def test_verify_attestation_err_load_cert(self, get_root_of_trust, load_pubkeys, self.assertIn("load cert error", str(e.exception)) get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) load_pubkeys.assert_called_with(self.pubkeys_path) HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) self.mock_certificate.validate_and_get_values.assert_not_called() @@ -173,10 +208,11 @@ def test_verify_attestation_validation_noquote(self, get_root_of_trust, load_pub self.assertIn("does not contain", str(e.exception)) get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) load_pubkeys.assert_called_with(self.pubkeys_path) HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) self.mock_certificate.validate_and_get_values \ - .assert_called_with("the-root-of-trust") + .assert_called_with(self.root_of_trust) def test_verify_attestation_validation_failed(self, get_root_of_trust, load_pubkeys, HSMCertificate, head, _): @@ -190,10 +226,11 @@ def test_verify_attestation_validation_failed(self, get_root_of_trust, load_pubk self.assertIn("validation error", str(e.exception)) get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) load_pubkeys.assert_called_with(self.pubkeys_path) HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) self.mock_certificate.validate_and_get_values \ - .assert_called_with("the-root-of-trust") + .assert_called_with(self.root_of_trust) def test_verify_attestation_invalid_header(self, get_root_of_trust, load_pubkeys, HSMCertificate, head, _): @@ -205,10 +242,11 @@ def test_verify_attestation_invalid_header(self, get_root_of_trust, load_pubkeys self.assertIn("message header", str(e.exception)) get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) load_pubkeys.assert_called_with(self.pubkeys_path) HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) self.mock_certificate.validate_and_get_values \ - .assert_called_with("the-root-of-trust") + .assert_called_with(self.root_of_trust) def test_verify_attestation_invalid_message(self, get_root_of_trust, load_pubkeys, HSMCertificate, head, _): @@ -220,10 +258,11 @@ def test_verify_attestation_invalid_message(self, get_root_of_trust, load_pubkey self.assertIn("parsing", str(e.exception)) get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) load_pubkeys.assert_called_with(self.pubkeys_path) HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) self.mock_certificate.validate_and_get_values \ - .assert_called_with("the-root-of-trust") + .assert_called_with(self.root_of_trust) def test_verify_attestation_pkh_mismatch(self, get_root_of_trust, load_pubkeys, HSMCertificate, head, _): @@ -235,7 +274,8 @@ def test_verify_attestation_pkh_mismatch(self, get_root_of_trust, load_pubkeys, self.assertIn("hash mismatch", str(e.exception)) get_root_of_trust.assert_called_with(DEFAULT_ROOT_AUTHORITY) + self.root_of_trust.is_valid.assert_called_with(self.root_of_trust) load_pubkeys.assert_called_with(self.pubkeys_path) HSMCertificate.from_jsonfile.assert_called_with(self.certification_path) self.mock_certificate.validate_and_get_values \ - .assert_called_with("the-root-of-trust") + .assert_called_with(self.root_of_trust) From ccb345a288197159ce397d21c5ef34b10c50975c Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 8 Jan 2025 10:18:28 +1300 Subject: [PATCH 36/50] SGX onboarding attestation gathering and verification (#242) - Updated setup script to gather and verify attestation after onboarding is completed - Added runtime attestation dependencies to the SGX distribution Dockerfile --- dist/sgx/Dockerfile | 8 +++++++- dist/sgx/scripts/setup | 21 +++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/dist/sgx/Dockerfile b/dist/sgx/Dockerfile index 1805e567..dbb318ce 100644 --- a/dist/sgx/Dockerfile +++ b/dist/sgx/Dockerfile @@ -12,6 +12,12 @@ RUN curl -L -o libssl1.1.deb https://ftp.debian.org/debian/pool/main/o/openssl/ # Install SGX runtime dependencies RUN echo 'deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main' | tee /etc/apt/sources.list.d/intel-sgx.list && \ + echo 'deb [arch=amd64] http://azure.archive.ubuntu.com/ubuntu/ focal main restricted' | tee -a /etc/apt/sources.list.d/intel-sgx.list && \ + echo 'deb [arch=amd64] https://packages.microsoft.com/ubuntu/20.04/prod focal main' | tee -a /etc/apt/sources.list.d/intel-sgx.list && \ + gpg --keyserver keyserver.ubuntu.com --recv-keys 871920D1991BC93C 3B4FE6ACC0B21F32 EB3E94ADBE1229CF && \ + gpg --export --armor 871920D1991BC93C | apt-key add - && \ + gpg --export --armor 3B4FE6ACC0B21F32 | apt-key add - && \ + gpg --export --armor EB3E94ADBE1229CF | apt-key add - && \ curl -fsSL https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | apt-key add - && \ apt-get update && \ - apt-get install -y libsgx-enclave-common + apt-get install -y libsgx-enclave-common libsgx-quote-ex libsgx-dcap-ql az-dcap-client diff --git a/dist/sgx/scripts/setup b/dist/sgx/scripts/setup index 2170614d..3e816f0b 100755 --- a/dist/sgx/scripts/setup +++ b/dist/sgx/scripts/setup @@ -34,6 +34,7 @@ PIN_FILE="$ROOT_DIR/pin.txt" EXPORT_DIR="$ROOT_DIR/export" PUBLIC_KEY_FILE="$EXPORT_DIR/public-keys.txt" PUBLIC_KEY_FILE_JSON="$EXPORT_DIR/public-keys.json" +ATTESTATION_FILE="$EXPORT_DIR/attestation.json" # HSM scripts directory SCRIPTS_DIR=$ROOT_DIR/scripts @@ -139,7 +140,17 @@ function onboard() { } function keys() { - $ADMIN pubkeys -o $PUBLIC_KEY_FILE + $ADMIN pubkeys -uo $PUBLIC_KEY_FILE + error +} + +function attestation() { + $ADMIN attestation -o $ATTESTATION_FILE + error +} + +function verify_attestation() { + $ADMIN verify_attestation -t $ATTESTATION_FILE -b $PUBLIC_KEY_FILE_JSON error } @@ -161,10 +172,16 @@ echo -e "\e[1;33mOnboarding the powHSM... \e[0m" onboard echo -e "\e[1;33mOnboarding complete.\e[0m" echo -echo -e "\e[1;32mGathering public keys\e[0m" +echo -e "\e[1;32mGathering attestation\e[0m" createOutputDir +attestation +echo +echo -e "\e[1;32mGathering public keys\e[0m" keys echo +echo -e "\e[1;32mVerifying attestation\e[0m" +verify_attestation +echo echo -e "\e[1;32mStopping the powHSM...\e[0m" stopPowHsm cleanBinaries From 69f1a5023b8b10fce09cf31626939376487af4aa Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Thu, 9 Jan 2025 04:31:18 +1300 Subject: [PATCH 37/50] SGX heartbeat disabling (#243) - Throwing ERR_INS_NOT_SUPPORTED for the heartbeat operation in SGX only - Added test case to system module unit tests --- firmware/src/sgx/src/trusted/system.c | 4 +++ firmware/src/sgx/test/system/test_system.c | 29 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c index 09fe938c..02545dc6 100644 --- a/firmware/src/sgx/src/trusted/system.c +++ b/firmware/src/sgx/src/trusted/system.c @@ -147,6 +147,10 @@ static external_processor_result_t system_do_process_apdu(unsigned int rx) { REQUIRE_UNLOCKED(); result.tx = do_change_password(rx); break; + case INS_HEARTBEAT: + // For now, we don't support heartbeat in SGX + THROW(ERR_INS_NOT_SUPPORTED); + break; default: result.handled = false; } diff --git a/firmware/src/sgx/test/system/test_system.c b/firmware/src/sgx/test/system/test_system.c index d49fdf3d..8ee70584 100644 --- a/firmware/src/sgx/test/system/test_system.c +++ b/firmware/src/sgx/test/system/test_system.c @@ -31,6 +31,7 @@ #include "hal/communication.h" #include "hal/exceptions.h" #include "hal/log.h" +#include "apdu.h" #include "hsm.h" #include "system.h" @@ -944,6 +945,33 @@ void test_retries_cmd_handled() { ASSERT_APDU("\x80\xA2\x03"); } +void test_heartbeat_cmd_throws_unsupported() { + setup(); + printf("Test heartbeat command throws unsupported instruction...\n"); + + system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); + unsigned int rx = 0; + SEED_SET_AVAILABLE(true); + ACCESS_UNLOCK(); + SET_APDU("\x80\x60\x00", rx); // SGX_ONBOARD + BEGIN_TRY { + TRY { + system_process_apdu(rx); + // system_process_apdu should throw ERR_INS_NOT_SUPPORTED + ASSERT_FAIL(); + } + CATCH_OTHER(e) { + assert(e == ERR_INS_NOT_SUPPORTED); + } + FINALLY { + ASSERT_NOT_HANDLED(); + teardown(); + return; + } + } + END_TRY; +} + void test_invalid_cmd_not_handled() { setup(); printf("Test invalid command is ignored...\n"); @@ -986,6 +1014,7 @@ int main() { test_echo_cmd_handled(); test_is_locked_cmd_handled(); test_retries_cmd_handled(); + test_heartbeat_cmd_throws_unsupported(); test_invalid_cmd_not_handled(); return 0; From 53e25077c67701d033186012da3c05917fd88a5f Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 14 Jan 2025 07:54:16 +1300 Subject: [PATCH 38/50] Fix middleware docker image build (#252) --- docker/mware/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/mware/Dockerfile b/docker/mware/Dockerfile index b9bad088..8c7055a2 100644 --- a/docker/mware/Dockerfile +++ b/docker/mware/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update && \ # Python package prerequisites RUN apt-get install -y \ libsecp256k1-dev=0.2.0-2 \ - libudev-dev=252.31-1~deb12u1 \ + libudev-dev=252.33-1~deb12u1 \ libusb-1.0-0-dev=2:1.0.26-1 \ libffi-dev=3.4.4-1 \ libjpeg-dev=1:2.1.5-2 From 2b181c9e949c488b47bb281705586d40a3402640 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Tue, 14 Jan 2025 07:54:27 +1300 Subject: [PATCH 39/50] Fix middleware docker image build (#253) --- docker/mware/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/mware/Dockerfile b/docker/mware/Dockerfile index b9bad088..8c7055a2 100644 --- a/docker/mware/Dockerfile +++ b/docker/mware/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update && \ # Python package prerequisites RUN apt-get install -y \ libsecp256k1-dev=0.2.0-2 \ - libudev-dev=252.31-1~deb12u1 \ + libudev-dev=252.33-1~deb12u1 \ libusb-1.0-0-dev=2:1.0.26-1 \ libffi-dev=3.4.4-1 \ libjpeg-dev=1:2.1.5-2 From 3a186bb719ccf1ad2bdcf7bd51e128fec510ead5 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 15 Jan 2025 01:50:58 +1300 Subject: [PATCH 40/50] SGX attestation documentation (#254) - Updated main README - Added SGX stuff to attestation documentation - Added reproducible builds information to build README --- README.md | 2 +- docs/attestation.md | 188 +++++++++++++++++++++++++++++++++------ firmware/build/README.md | 4 + 3 files changed, 168 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 7c54a95f..9f19d322 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ powHSM is a solution designed specifically for the [RSK network](https://www.rsk 1. The first implementation consists of a pair of applications for the [Ledger Nano S](https://shop.ledger.com/products/ledger-nano-s), namely a UI and a Signer, and it strongly depends on the device's security features to implement the aforementioned safekeeping. This implementation requires a physical Ledger Nano S device and a self-managed physical standalone server. 2. The second implementation consists of both a host and an enclave binary targetting the Intel SGX architecture. Just as the Ledger Nano S implementation, it strongly depends on the Intel SGX security features in order to keep the private keys safe. This implementation can run both on standalone SGX-enabled servers as well as on SGX-enabled cloud computing providers (e.g., Microsoft Azure). -Each powPeg member runs an individual physical device or SGX enclave on which a transparent installation and onboarding process is carried. Amongst other things, this process safely generates the root key, that either never leaves the device (Ledger) or can only ever be decrypted by the enclave (SGX). There is an [attestation process](./docs/attestation.md) that serves the purpose of testifying and guaranteeing this key generation process, and ultimately the fact that the key is only ever known to the device (attestation is currently only supported on the Ledger implementation). +Each powPeg member runs an individual physical device or SGX enclave on which a transparent installation and onboarding process is carried. Amongst other things, this process safely generates the root key, that either never leaves the device (Ledger) or can only ever be decrypted by the enclave (SGX). There is an [attestation process](./docs/attestation.md) that serves the purpose of testifying and guaranteeing this key generation process, and ultimately the fact that the key is only ever known to the physical device or SGX enclave. After onboarding, each powHSM runs either on its host (SGX) or is physically connected to it (Ledger), and interacts with its corresponding powPeg node by means of a middleware layer that exposes a [high-level protocol](./docs/protocol.md) for its operation. diff --git a/docs/attestation.md b/docs/attestation.md index 530aa713..0ff97a8e 100644 --- a/docs/attestation.md +++ b/docs/attestation.md @@ -1,18 +1,19 @@ # powHSM attestation -## Foreword +## Abstract -Currently, attestation is a feature supported only in the Ledger version of powHSM. An attestation implementation for the SGX version of powHSM is currently under development. Therefore, all the information contained herein must be interpreted as applying exclusively to the Ledger version of powHSM. +This document describes the mechanisms through which a powHSM installation can prove to an end user that either: -## Abstract +- It is actually installed an authentic physical Ledger Nano S device with specific UI and Signer versions, along with its currently authorized signer version and generated public keys; or +- It is running in an authentic Intel SGX environment, within an SGX enclave with a specific codebase, along with its safely generated and stored public keys. -This document describes the mechanisms through which a powHSM installation can prove to an end user that it is actually installed on an authentic physical Ledger device with specific UI and Signer versions, along with its currently authorized signer version and generated public keys. +## Attestation for the Ledger-based powHSM -## Preliminaries, native support and assumptions +### Preliminaries, native support and assumptions Each Ledger device currently used to run powHSM on, namely Ledger Nano S, ships with a mechanism to prove its authenticity and that also enables and leverages some basic additional support for user application attestation. For powHSM attestation we make extensive use of these mechanisms, assuming it is robust enough for our purpose. -## Device key and authenticity +### Device key and authenticity The mechanism used by Ledger Nano S devices to prove their authenticity can be better understood from [the ledger documentation](https://developers.ledger.com/docs/nano-app/bolos-features/#attestation): @@ -20,7 +21,7 @@ _"When all Ledger devices are provisioned in the factory, they first generate a We use the device public key and issuer certificate as the basis for the powHSM attestation mechanism. -## Application attestation and powHSM +### Application attestation and powHSM Ledger Nano S user applications can make indirect use of the aforementioned device keypair to provide attestation mechanisms. This can be better understood from [the ledger documentation](https://developers.ledger.com/docs/nano-app/bolos-features/#attestation): @@ -32,19 +33,19 @@ _"The attestation keys are not accessible to apps directly, instead BOLOS provid For powHSM, we use Endorsement Scheme Two, which provides a primitive to _"Sign a message using a private key derived from the attestation private key and the hash of the running application"_. In this way, installed applications can endorse specific messages, and that endorsement constitutes _proof_ of those messages being generated on that specific running code on an authentic Ledger Nano S. This is the basis for the powHSM attestation. -## Attestation goal +### Attestation goal -The main goal of the powHSM attestation mechanism is enabling the end user(s) to have proof of a specific powHSM with a given UI and Signer running on an authentic Ledger Nano S with a specific authorized signer version and having control over a given set of generated public keys. Given the constraints specifically implemented on the powHSM UI (more on this later), proof of the aforementioned would also guarantee that the holder of the powHSM device will not ever be able to alter the installed UI; and that upgrades for the Signer application will need the explicit authorization of a minimum number of predefined authorizers (currently hardcoded within the UI, and decided at compile time). Attempts to bypass these restrictions would result in the keypairs being lost forever. +The main goal of the Ledger-based powHSM attestation mechanism is enabling the end user(s) to have proof of a specific powHSM with a given UI and Signer running on an authentic Ledger Nano S with a specific authorized signer version and having control over a given set of generated public keys. Given the constraints specifically implemented on the powHSM UI (more on this later), proof of the aforementioned would also guarantee that the holder of the powHSM device will not ever be able to alter the installed UI; and that upgrades for the Signer application will need the explicit authorization of a minimum number of predefined authorizers (currently hardcoded within the UI, and decided at compile time). Attempts to bypass these restrictions would result in the keypairs being lost forever. -## Attestation gathering +### Attestation gathering -The attestation gathering process is actually a three step process: first, the attestation keypair is setup; second, the UI provides attestation for itself; last, the Signer provides an attestation for itself. Together, these three pieces form the powHSM attestation. +The attestation gathering process is actually a three step process: first, the attestation keypair is setup; second, the UI provides attestation for itself; last, the Signer provides an attestation for itself. Together, these three pieces form the powHSM attestation. Intermediate software layers unify these pieces into a user-friendly format that can be used for transmission and verification. -### Attestation keypair setup +#### Attestation keypair setup The attestation keypair setup takes place right after the onboarding is complete (any attestation keypairs generated before that are wiped). In this part of the process, also known as endorsement setup, the device generates a new keypair, which will be known as the attestation keypair. Then, it signs its public key with its device key, and then outputs the attestation public key, the aforementioned signature and the issuer's certificate of the device's keypair. This two-step certification chain can be used to prove that the generated attestation keypair was generated in an authentic ledger device and is under its control. It is important to mention that the _endorsement scheme number two_ is used for the attestation setup. This then implies that applications using the attestation key to sign messages actually use a derived key obtained from this key plus the running application hash. Therefore, a valid signature under this scheme is also proof of it being generated from a specific application. -### UI Attestation +#### UI Attestation Before diving into the UI attestation, it is important to recall a few relevant UI features: @@ -64,23 +65,52 @@ To generate the attestation, the UI uses the configured attestation scheme to si As a consequence of the aforementioned features, this message guarantees that the device is running a specific version of the UI with a specific seed and authorized signer version, and also that this cannot be changed without wiping the device, therefore losing the keys forever. The RSK best block hash also consitutes proof of a minimum date/time on which the attestation was generated. -### Signer attestation +#### Signer attestation + +To generate the attestation, the Signer uses the configured attestation scheme to sign a message that guarantees that the device is running a specific version of the Signer and that those keys are in control of the Ledger device. Additional fields aid in auditing a device's state at the time the attestation is gathered (e.g., for firmware updates). For details on the specific message signed, refer to the [powHSM attestation contents](#powhsm-attestation-contents) section. + +## Attestation for the Intel SGX-based powHSM + +### Preliminaries, native support and assumptions + +The Intel Software Guard Extensions (SGX) architecture features an advanced mechanism that allows a combination of hardware and software to gain a remote party's trust. This mechanism, known as remote attestation, gives the relying party the ability to check that the intended software is +securely running within an enclave on a system with Intel SGX enabled. For the Intel SGX-based powHSM attestation we make use of remote attestation, assuming it is robust enough for our purpose. In particular, we use ECDSA-based attestation using Intel SGX Data Center Attestation Primitives (DCAP), explained below. + +### Local and remote attestation + +Local attestation is a native Intel SGX process that can be by used by an enclave to verify the integrity and authenticity of another enclave running on the same physical platform. It enables the "verifier" enclave to confirm the identity, code, and state of the target enclave by exchanging a secure report, natively and securely generated using Intel SGX primitives. This report can additionally include arbitrary information generated by the target enclave, whose source the verifier enclave can deem trustworthy. + +Remote attestation extends local attestation to enable trust verification between an SGX enclave and a verifier outside the platform. In Intel SGX DCAP remote attestation, the target enclave generates a local attestation report, which is then sent to a specialized system enclave that transforms the local report into a "quote" by signing it with a platform-specific attestation key. This quote, along with a certificate that chains back to Intel's root of trust, is sent to the remote verifier. The verifier uses the certificate chain to validate the quote and, by extension, the enclave’s identity and platform security, enabling the remote party to trust the enclave. + +### Attestation goal + +The main goal of the SGX-based powHSM attestation mechanism is enabling the end user(s) to have proof of a powHSM with a given trusted codebase running within an authentic Intel SGX enclave and having control over a given set of generated public keys. Given the constraints specifically implemented on the powHSM enclave business layer alongside the specific primitives leveraged to encrypt/decrypt secrets within the SGX enclave (namely, the use of the enclave identity for the encryption key derivation functions), it is guaranteed that all enclave secrets (and, in particular, the master seed) will only ever be known to the powHSM enclave. Any attempts to modify the code (even having access to the enclave signer private key) will result in a different enclave identity and, thus, in an invalid set of derived keys that will make it impossible for the modified enclave to access the original enclave's secrets. + +### Attestation gathering + +As opposed to what happens with the Ledger-based powHSM, the attestation gathering process for the SGX-based powHSM is straightforward: upon request, the powHSM enclave produces a quote. This quote is, in itself, the entire attestation, but is then transformed by intermediate software layers into a user-friendly format that can be used for transmission and verification. + +## powHSM attestation contents -To generate the attestation, the Signer uses the configured attestation scheme to sign a message generated by the concatenation of: +Under both Ledger and SGX, the powHSM business layer includes an arbitrary message that is part of the final attestation produced, and that can also be verified and trusted by the interested parties. This message is generated by the concatenation of: - A predefined header (`POWHSM:5.4::`). -- A 3-byte platform identifier, which for Ledger is exactly the ASCII characters `led`. -- A 32 byte user-defined value. By default, the attestation generation client supplies the latest RSK block hash as this value, so it can then be used as a minimum timestamp reference for the attestation generation. +- A 3-byte platform identifier, which for Ledger and SGX are exactly the ASCII characters `led` or `sgx`, respectively. +- A 32 byte user-defined value, given by the requesting party. By default, the attestation generation client supplies the latest RSK block hash as this value, so it can then be used as a minimum timestamp reference for the attestation generation. - A 32 byte value that is generated by computing the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path. -- A 32 byte value denoting the device's current known best block hash for the Rootstock network. +- A 32 byte value denoting the powHSM's current known best block hash for the Rootstock network. - An 8 byte value denoting the leading bytes of the latest authorised signed Bitcoin transaction hash. -- An 8 byte value denoting a big-endian unix timestamp. For Ledger, this is always zero. +- An 8 byte value denoting a big-endian unix timestamp. For both Ledger and SGX, this is currently always zero. + +This message guarantees that the device is running a specific powHSM version and that the keys are in control of the Ledger device or SGX enclave. The additional fields aid in auditing a powHSM's state at the time the attestation is gathered. -This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device. The additional fields aid in auditing a device's state at the time the attestation is gathered (e.g., for firmware updates). +## Attestation file formats -## Attestation file format +The output of the attestation process is a JSON file with a proprietary structure that allows for the validation of each of the attestation components all the way to the root of trust (Ledger or Intel, depending on the platform used). Currently, there's two versions of the attestation file used: version one is used in the Ledger-based implementation, and version two is used for the Intel SGX-based implementation. In the future, the idea is unifying everything into a single version in order to simplify the generation and verification process both from a software implementation and end-user perspective. -The output of the attestation process is a JSON file with a proprietary structure that allows for the validation of each of the attestation components (UI and Signer) all the way to the issuer's public key (Ledger), and also validating the generated attestation keypair as a byproduct. A sample attestation file is shown below: +### Attestation version one + +A sample attestation version one file is shown below: ```json { @@ -151,9 +181,77 @@ def extract(element): The validation process _for each of the targets_ is fairly straightforward, and can even be done manually with the aid of basic ECDSA and hashing tools: walk the element chain "upwards" until the element signed by `root` is found. Then start by validating that element's signature against the root public key and extracting that element's public key. Repeat the process walking the chain "downwards" until the target is reached. Fail if at any point an element's signature is invalid. Otherwise the target is valid and its value can be extracted from its `message` field and interpreted accordingly (in the case of the `ui` element, the user-defined value, public key and custom certification authority; in the case of the `signer`, the hash of the authorized public keys). +### Attestation version two + +A sample attestation version two file is shown below: + +```json +{ + "version": 2, + "targets": [ + "quote" + ], + "elements": [ + { + "name": "quote", + "type": "sgx_quote", + "message": "03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ceae3549bc7273eb34d562f4564fc182000000000e0e100fffff01000000000000000000010000000000000000000000000000000000000000000000000000000000000005000000000000000700000000000000d32688d3c1f3dfcc8b0b36eac7c89d49af331800bd56248044166fa6699442c10000000000000000000000000000000000000000000000000000000000000000718c2f1a0efbd513e016fafd6cf62a624442f2d83708d4b33ab5a8d8c1cd4dd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1fcb9087762c10418e2a0e9e0791f9fdfe1e123b00416a477cf0875f98e44070000000000000000000000000000000000000000000000000000000000000000", + "custom_data": "504f5748534d3a352e343a3a7367788d5dbf3ca886a9d849228e154693cdbab15d109f6327a71b5ef5860a9b828bef0c4d091913d39750dc8975adbdd261bd10c1c2e110faa47cfbe30e740895552bbdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b00000000000000000000000000000000", + "signature": "3046022100a4ec02ec2714b7c5c23cf6ff85ea45a4cff357199ed093212488ec4efead26d602210094d383e55f079ad3a66dcbfc2962b006b8d98c7a872721a4d54644096dc21bd3", + "signed_by": "attestation" + }, + { + "name": "attestation", + "type": "sgx_attestation_key", + "message": "0e0e100fffff0100000000000000000000000000000000000000000000000000000000000000000000000000000000001500000000000000e70000000000000096b347a64e5a045e27369c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e400000000000000000000000000000000000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8ded70140b081b094490c57bff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fe721d0322954821589237fd27efb8fef1acb3ecd6b0352c31271550fc70f940000000000000000000000000000000000000000000000000000000000000000", + "key": "04a024cb34c90ea6a8f9f2181c9020cbcc7c073e69981733c8deed6f6c451822aa08376350ff7da01f842bb40c631cbb711f8b6f7a4fae398320a3884774d250ad", + "auth_data": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "signature": "304502201f14d532274c4385fc0019ca2a21e53e17143cb62377ca4fcdd97fa9fef8fb2502210095d4ee272cf3c512e36779de67dc7814982f1160d981d138a32b265e928a0562", + "signed_by": "quoting_enclave" + }, + { + "name": "quoting_enclave", + "type": "x509_pem", + "message": "MIIE8zCCBJigAwIBAgIUfr2dlwN42DBUA9CXIkBlGP2vV3AwCgYIKoZIzj0EAwIw\ncDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBDSyBQbGF0Zm9ybSBDQTEaMBgGA1UECgwR\nSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQI\nDAJDQTELMAkGA1UEBhMCVVMwHhcNMjQwMzIzMDQ0NjIxWhcNMzEwMzIzMDQ0NjIx\nWjBwMSIwIAYDVQQDDBlJbnRlbCBTR1ggUENLIENlcnRpZmljYXRlMRowGAYDVQQK\nDBFJbnRlbCBDb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNV\nBAgMAkNBMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKl7\nRDNlsZKkEtAcW7SfCX1JegbvGq4O0rRUt0z/G6fZJsNlpmRwTB4DYkrgkm1t+9Rp\nLwxFX9/kghxiDQm0jqmjggMOMIIDCjAfBgNVHSMEGDAWgBSVb13NvRvh6UBJydT0\nM84BVwveVDBrBgNVHR8EZDBiMGCgXqBchlpodHRwczovL2FwaS50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL3NneC9jZXJ0aWZpY2F0aW9uL3Y0L3Bja2NybD9jYT1w\nbGF0Zm9ybSZlbmNvZGluZz1kZXIwHQYDVR0OBBYEFALKV5DF16KnEbSW5QM9ecDq\nBZaHMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMIICOwYJKoZIhvhNAQ0B\nBIICLDCCAigwHgYKKoZIhvhNAQ0BAQQQttJXuiQVwqM4s74g+HxfKTCCAWUGCiqG\nSIb4TQENAQIwggFVMBAGCyqGSIb4TQENAQIBAgEOMBAGCyqGSIb4TQENAQICAgEO\nMBAGCyqGSIb4TQENAQIDAgEDMBAGCyqGSIb4TQENAQIEAgEDMBEGCyqGSIb4TQEN\nAQIFAgIA/zARBgsqhkiG+E0BDQECBgICAP8wEAYLKoZIhvhNAQ0BAgcCAQEwEAYL\nKoZIhvhNAQ0BAggCAQAwEAYLKoZIhvhNAQ0BAgkCAQAwEAYLKoZIhvhNAQ0BAgoC\nAQAwEAYLKoZIhvhNAQ0BAgsCAQAwEAYLKoZIhvhNAQ0BAgwCAQAwEAYLKoZIhvhN\nAQ0BAg0CAQAwEAYLKoZIhvhNAQ0BAg4CAQAwEAYLKoZIhvhNAQ0BAg8CAQAwEAYL\nKoZIhvhNAQ0BAhACAQAwEAYLKoZIhvhNAQ0BAhECAQ0wHwYLKoZIhvhNAQ0BAhIE\nEA4OAwP//wEAAAAAAAAAAAAwEAYKKoZIhvhNAQ0BAwQCAAAwFAYKKoZIhvhNAQ0B\nBAQGAGBqAAAAMA8GCiqGSIb4TQENAQUKAQEwHgYKKoZIhvhNAQ0BBgQQDVe/DXUV\nE4gemtgO5uBpvDBEBgoqhkiG+E0BDQEHMDYwEAYLKoZIhvhNAQ0BBwEBAf8wEAYL\nKoZIhvhNAQ0BBwIBAQAwEAYLKoZIhvhNAQ0BBwMBAQAwCgYIKoZIzj0EAwIDSQAw\nRgIhAJFgf78HggTBtvQPXZJx/3Fm71vCOmt82pce91M2ZAI0AiEAiZMPBbZZmvR2\nv+1mrs76JeglDQ+pK/SLN94l4+jM5DA=", + "signed_by": "platform_ca" + }, + { + "name": "platform_ca", + "type": "x509_pem", + "message": "MIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+", + "signed_by": "sgx_root" + } + ] +} +``` + +Following is an explanation of the different components in the example: + +- The `version` field just indicates the version of the format (`2`), which determines the semantics of the rest of the file. +- The `targets` field is a string array indicating which elements are to be validated. In this case, only the `quote` element is to be validated. +- The `elements` is an array containing each of the elements of the certificate. The role of each of the elements' mandatory fields is explained below: + - The `name` field is a unique identifier for the element throughout the file. It allows for referencing from the `targets` and `elements.signed_by` fields. As opposed to what happens in version 1, arbitrary names are allowed here. + - The `type` field indicates the type of element being described, and dictates which other attributes should also be present. Currently, there are three element types allowed: `sgx_quote`, `sgx_attestation_key` and `x509_pem`. + - The `signed_by` contains either the name of another element within the file (e.g., `platform_ca` for the `quoting_enclave` element), or the value `sgx_root`. It is used to find the certifier for the element at hand. In the case of referencing an element, that element's public key is used for validation of the current element. In the case of `sgx_root`, the root of trust certificate (normally Intel) is to be used for validation. This certificate can be fed manually through e.g. tooling. + - The `message` contains: + - For the `sgx_quote` type, the hex-encoded message signed in that element, that corresponds to a `sgx_quote_t` struct, without the `signature_len` component (see [the source](https://github.com/openenclave/openenclave/blob/master/include/openenclave/bits/sgx/sgxtypes.h) for details). + - For the `sgx_attestation_key` type, the hex-encoded message signed in that element, that corresponds to a `sgx_report_body_t` struct (see [the source](https://github.com/openenclave/openenclave/blob/master/include/openenclave/bits/sgx/sgxtypes.h) for details). + - For the `x509_pem` type, the base64-encoded x509 certificate (same as what a `.pem` file would contain, without the begin and end markers). + - For the `sgx_quote` and `sgx_attestation_key` types, the `signature` contains the hex-encoded DER signature for that element's `message`. + - Additionally, for the `sgx_quote` type, the `custom_data` field contains the hex-encoded custom message given by the powHSM enclave. Its hash is contained within the `message` field. + - Additionally, for the `sgx_attestation_key` type: + - The `key` field contains the hex-encoded uncompressed NIST P-256 attestation public key that is used to validate other elements. + - The `auth_data` field contains hex-encoded additional data that, SHA-256 hashed alongside the aforementioned public key, is contained within the signed `message`. + +The validation process _for each of the targets_ is fairly straightforward, and very similar in spirit to that of the version one certificate shown before. It can also be done manually with the aid of basic ECDSA, hashing and x509 tools: walk the element chain "upwards" until the element signed by `sgx_root` is found. Then, if the element is of `x509_type`, validate it using an x509 parser and validator, retrieving the root of trust accordingly. Otherwise, validate that element's `signature` and `message` against the public key of the `signed_by` element. Additionally, validate that all remaining attributes are contained within the `message` according to its type. Repeat the process walking the chain "downwards" until the target is reached. Fail if at any point an element is deemed invalid. Otherwise the target is valid. Normally the target should be of `sgx_quote` type, and the custom message signed by the powHSM enclave is exactly the `custom_data` field. The individual fields contained within can now be extracted, analysed and validated accordingly. + ## Tooling -For completion's sake, a validation tool is provided within the administration toolset. So, for example, if the file depicted above was at `/a/path/to/the/attestation.json`, the JSON-formatted public keys generated at onboarding time were at `/a/path/to/the/public-keys.json` and we knew the issuer public key was `0490f5c9d15a0134bb019d2afd0bf297149738459706e7ac5be4abc350a1f818057224fce12ec9a65de18ec34d6e8c24db927835ea1692b14c32e9836a75dad609` (the actual ledger issuer public key, found in [ledger's endorsement setup tooling](https://github.com/LedgerHQ/blue-loader-python/blob/0.1.31/ledgerblue/endorsementSetup.py#L138)), we could issue: +For completion's sake, validation tools are provided within the administration toolset. So, for example, if the JSON attestation file was at `/a/path/to/the/attestation.json`, the JSON-formatted public keys generated at onboarding time were at `/a/path/to/the/public-keys.json`, then we could issue the following commands depending on the platform. + +### Ledger + +Assuming we knew the issuer public key was `0490f5c9d15a0134bb019d2afd0bf297149738459706e7ac5be4abc350a1f818057224fce12ec9a65de18ec34d6e8c24db927835ea1692b14c32e9836a75dad609` (the actual ledger issuer public key, found in [ledger's endorsement setup tooling](https://github.com/LedgerHQ/blue-loader-python/blob/0.1.31/ledgerblue/endorsementSetup.py#L138)), we could issue: ```bash middleware/term> python adm_ledger.py verify_attestation -t /a/path/to/the/attestation.json -r 0490f5c9d15a0134bb019d2afd0bf297149738459706e7ac5be4abc350a1f818057224fce12ec9a65de18ec34d6e8c24db927835ea1692b14c32e9836a75dad609 -b /a/path/to/the/public-keys.json @@ -191,8 +289,48 @@ Platform: led UD value: 13c3581aa97c8169d3994e9369c11ebd63bcf123d0671634f21b568983d32916 Best block: bdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b Last transaction signed: 659a04529d6811dd -Timestamp: 0000000000000000 +Timestamp: 0 --------------------------------------------------------------------------------------- ``` -and verify that the reported UI and Signer application hashes match the expected value. Additionally, the user should check that each additional reported value corresponds with an expected or reasonable value (e.g., verify that the UD value corresponds to an RSK block header hash that was mined on or after the time of setup/update; or that in the case of an update, the public keys correspond to those of the powPeg member and have not been altered from the values obtained at setup). \ No newline at end of file +and verify that the reported UI and Signer application hashes match the expected value. The user should also check that each additional reported value corresponds with an expected or reasonable value (e.g., verify that the UD value corresponds to an RSK block header hash that was mined on or after the time of setup/update; or that in the case of an update, the public keys correspond to those of the PowPeg member and have not been altered from the values obtained at setup). + +### SGX + +Assuming we knew Intel SGX Root CA certificate could be downloaded from `https://certificates.trustedservices.intel.com/Intel_SGX_Provisioning_Certification_RootCA.pem` (the actual certificate, that can be found [in Intel's API documentation](https://api.portal.trustedservices.intel.com/content/documentation.html#pcs)), we could issue: + +```bash +middleware/term> python adm_sgx.py verify_attestation -t /a/path/to/the/attestation.json -r https://certificates.trustedservices.intel.com/Intel_SGX_Provisioning_Certification_RootCA.pem -b /a/path/to/the/public-keys.json +``` + +to then obtain the following sample output: + +``` +################################ +### -> Verify powHSM attestation +################################ +Attempting to gather root authority from https://certificates.trustedservices.intel.com/Intel_SGX_Provisioning_Certification_RootCA.pem... +Attempting to validate self-signed root authority... +Using https://certificates.trustedservices.intel.com/Intel_SGX_Provisioning_Certification_RootCA.pem as root authority +-------------------------------------------------------------------------------------------- +powHSM verified with public keys: +m/44'/0'/0'/0/0: 03d2c1ab7245b1676e7aa66ef7588c3925ff972cce19756e6c030ad8ad22634fa4 +m/44'/1'/0'/0/0: 03c9b0dac136c1651e75456f768c6ed3a424500af139905710882f7821c5810ffe +m/44'/1'/1'/0/0: 03b70f79eb845c76bb3c51e0b6c6b58a67ec84bb1fb48871127960f0cfe41dc359 +m/44'/1'/2'/0/0: 031df2601f232cbf1fd8bb5e3dd1fe0bc5c4952b41716546f7c48823dffaa055dc +m/44'/137'/0'/0/0: 0238ad6df3f4023502860c46fab39a64e4ff76225782321eb19be87008606175c4 +m/44'/137'/1'/0/0: 03d4b5cef399724fa0bb27f3e46d83b4f7c3ce69abfebd6afa25f8aa3078a3ac72 +Hash: 0c4d091913d39750dc8975adbdd261bd10c1c2e110faa47cfbe30e740895552b + +Installed powHSM MRENCLAVE: d32688d3c1f3dfcc8b0b36eac7c89d49af331800bd56248044166fa6699442c1 +Installed powHSM MRSIGNER: 718c2f1a0efbd513e016fafd6cf62a624442f2d83708d4b33ab5a8d8c1cd4dd0 +Installed powHSM version: 5.4 +Platform: sgx +UD value: 13c3581aa97c8169d3994e9369c11ebd63bcf123d0671634f21b568983d32916 +Best block: bdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b +Last transaction signed: 659a04529d6811dd +Timestamp: 0 +-------------------------------------------------------------------------------------------- +``` + +and verify that the reported MRENCLAVE and MRSIGNER application hashes match the expected values (for completion, this can be obtained from the Rootstocklabs publicly available enclave binary for the corresponding version, and then its digest verified against a local build). The user should also check that each additional reported value corresponds with an expected or reasonable value (e.g., verify that the UD value corresponds to an RSK block header hash that was mined on or after the time of setup and that the public keys correspond to those that will be used to define the PowPeg member and have not been altered). \ No newline at end of file diff --git a/firmware/build/README.md b/firmware/build/README.md index 267f8ab5..4db0db1c 100644 --- a/firmware/build/README.md +++ b/firmware/build/README.md @@ -72,6 +72,10 @@ For example, to build host and enclave with checkpoint `0x00f06dcff26ec8b4d373fb Once the build is complete, the binaries will be placed under `/firmware/src/sgx/bin` with the names `hsmsgx` for the host and `hsmsgx_enclave.signed` for the signed enclave. +### Reproducible builds + +It is *very important* to mention that both the host and enclave builds are bitwise reproducible. That is, two independent builds of the same code will yield the exact same binary files (and thus, the same `sha256sum`s and `oesign` digests). As a consequence, two independent builds of the same enclave sources signed with the same private key and enclave configuration will also yield two enclave binaries with identical `MRENCLAVE` values. This is paramount for the [attestation process](../../docs/attestation.md). + ### Simulation and debug builds There are also debug and simulation builds available for development and testing purposes. Just replace the use of the `build-sgx` script with either `build-sgx-debug` or `build-sgx-sim` to obtain a debug or simulation version. The debug version has got a slightly different OpenEnclave configuration file and logging settings, and the simulation version can be ran on non-SGX environments (this latter version extremely useful for local development and testing). From 2652b3dee9c97d27b3a2461c09f91c8d3e3a9f92 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 15 Jan 2025 06:39:31 +1300 Subject: [PATCH 41/50] SGX heartbeat documentation (#259) - Added note to heartbeat documentation stating that it is currently unsupported for SGX - Added corresponding unsupported notes in protocol operations within the protocol documentation --- docs/heartbeat.md | 2 +- docs/protocol.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/heartbeat.md b/docs/heartbeat.md index 58ec43ba..bb41ea6a 100644 --- a/docs/heartbeat.md +++ b/docs/heartbeat.md @@ -2,7 +2,7 @@ ## Foreword -Currently, just like what happens in the case of [attestation](./attestation.md), heartbeat is a feature supported only in the Ledger version of powHSM. A heartbeat implementation for the SGX version of powHSM is currently under development. Therefore, all the information contained herein must be interpreted as applying exclusively to the Ledger version of powHSM. +Currently, heartbeat is a feature supported only in the Ledger version of powHSM. A heartbeat implementation for the SGX version of powHSM is currently under development. Therefore, all the information contained herein must be interpreted as applying exclusively to the Ledger version of powHSM. ## Abstract diff --git a/docs/protocol.md b/docs/protocol.md index 9a7bf889..f3544967 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -356,6 +356,8 @@ This operation can return `0` and generic errors. See the error codes section fo **Error codes:** This operation can return `0`, `-301` and generic errors. See the error codes section for details. +**Important:** +Currently, this operation is unsupported for the SGX version of powHSM, returning error `-905` upon an otherwise correct invocation. ### UI heartbeat @@ -390,6 +392,8 @@ This operation can return `0`, `-301` and generic errors. See the error codes se **Error codes:** This operation can return `0`, `-301` and generic errors. See the error codes section for details. +**Important:** +Currently, this operation is unsupported for the SGX version of powHSM, returning error `-905` upon an otherwise correct invocation. ### Error and success codes From 37ddeea38f9404bb835cc55f6f06b764806c85f9 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Thu, 16 Jan 2025 05:53:08 +1300 Subject: [PATCH 42/50] Fixed C linting to include sgx code (#261) - Including sgx code in lint-c/format-c scripts - Fixed reported sgx linting errors --- firmware/src/sgx/src/trusted/ecall.c | 1 - firmware/src/sgx/src/trusted/sync.c | 3 ++- firmware/src/sgx/src/trusted/system.c | 18 +++++++-------- firmware/src/sgx/src/trusted/system.h | 7 +++--- .../src/sgx/src/untrusted/enclave_provider.c | 15 ++++++++---- .../src/sgx/src/untrusted/enclave_provider.h | 8 +++---- .../src/sgx/src/untrusted/enclave_proxy.c | 14 +++++------ firmware/src/sgx/src/untrusted/io.h | 6 ++--- .../src/sgx/src/untrusted/keyvalue_store.c | 23 ++++++++----------- .../src/sgx/src/untrusted/keyvalue_store.h | 16 ++++++------- firmware/src/sgx/src/untrusted/log.c | 8 +++---- firmware/src/sgx/src/untrusted/log.h | 4 ++-- firmware/src/sgx/src/untrusted/main.c | 7 +++--- lint-c | 3 ++- 14 files changed, 67 insertions(+), 66 deletions(-) diff --git a/firmware/src/sgx/src/trusted/ecall.c b/firmware/src/sgx/src/trusted/ecall.c index cf5c89d4..9d6bb2b0 100644 --- a/firmware/src/sgx/src/trusted/ecall.c +++ b/firmware/src/sgx/src/trusted/ecall.c @@ -44,4 +44,3 @@ unsigned int ecall_system_process_apdu(unsigned int rx) { SYNC_RELEASE_LOCK(); return result; } - diff --git a/firmware/src/sgx/src/trusted/sync.c b/firmware/src/sgx/src/trusted/sync.c index 078c9eee..179dd58b 100644 --- a/firmware/src/sgx/src/trusted/sync.c +++ b/firmware/src/sgx/src/trusted/sync.c @@ -28,7 +28,8 @@ static bool G_locked = false; bool sync_try_aqcuire_lock() { - if (G_locked) return false; + if (G_locked) + return false; G_locked = true; return true; } diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c index 0f5d4a1b..9bb65808 100644 --- a/firmware/src/sgx/src/trusted/system.c +++ b/firmware/src/sgx/src/trusted/system.c @@ -90,13 +90,13 @@ static unsigned int do_unlock(unsigned int rx) { SET_APDU_OP(1); return TX_NO_DATA(); } - + if (APDU_DATA_SIZE(rx) == 0) { THROW(ERR_INVALID_DATA_SIZE); } - SET_APDU_OP( - access_unlock((char*)APDU_DATA_PTR, APDU_DATA_SIZE(rx)) ? 1 : 0); + SET_APDU_OP(access_unlock((char*)APDU_DATA_PTR, APDU_DATA_SIZE(rx)) ? 1 + : 0); return TX_NO_DATA(); } @@ -158,16 +158,17 @@ unsigned int system_process_apdu(unsigned int rx) { return hsm_process_apdu(rx); } -bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { +bool system_init(unsigned char* msg_buffer, size_t msg_buffer_size) { // Setup the shared APDU buffer if (msg_buffer_size != EXPECTED_APDU_BUFFER_SIZE) { LOG("Expected APDU buffer size to be %u but got %lu\n", - EXPECTED_APDU_BUFFER_SIZE, msg_buffer_size); + EXPECTED_APDU_BUFFER_SIZE, + msg_buffer_size); return false; } apdu_buffer = msg_buffer; apdu_buffer_size = msg_buffer_size; - + // Initialize modules LOG("Initializing modules...\n"); if (!sest_init()) { @@ -206,9 +207,8 @@ bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { } nvmem_init(); - if (!nvmem_register_block("bcstate", - &N_bc_state_var, - sizeof(N_bc_state_var))) { + if (!nvmem_register_block( + "bcstate", &N_bc_state_var, sizeof(N_bc_state_var))) { LOG("Error registering bcstate block\n"); return false; } diff --git a/firmware/src/sgx/src/trusted/system.h b/firmware/src/sgx/src/trusted/system.h index e571e136..8d922a9b 100644 --- a/firmware/src/sgx/src/trusted/system.h +++ b/firmware/src/sgx/src/trusted/system.h @@ -27,7 +27,7 @@ /** * @brief Initializes the system module - * + * * @param msg_buffer the APDU buffer to use * @param msg_buffer_size the size of the APDU buffer in bytes * @@ -37,12 +37,11 @@ bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size); /** * @brief Process an APDU message - * + * * @param rx number of received bytes - * + * * @returns number of bytes to transmit */ unsigned int system_process_apdu(unsigned int rx); - #endif // __TRUSTED_SYSTEM_H diff --git a/firmware/src/sgx/src/untrusted/enclave_provider.c b/firmware/src/sgx/src/untrusted/enclave_provider.c index 20ac295c..5866ee94 100644 --- a/firmware/src/sgx/src/untrusted/enclave_provider.c +++ b/firmware/src/sgx/src/untrusted/enclave_provider.c @@ -22,7 +22,6 @@ * IN THE SOFTWARE. */ - #include #include "hsm_u.h" @@ -36,7 +35,8 @@ #define CREATE_ENCLAVE_FLAGS OE_ENCLAVE_FLAG_SIMULATE #endif -// Global pointer to the enclave. This should be the only global pointer to the enclave +// Global pointer to the enclave. This should be the only global pointer to the +// enclave static char* G_enclave_path = NULL; static oe_enclave_t* G_enclave = NULL; @@ -51,13 +51,18 @@ bool epro_init(char* enclave_path) { oe_enclave_t* epro_get_enclave() { if (NULL == G_enclave) { - oe_enclave_t *enclave = NULL; + oe_enclave_t* enclave = NULL; LOG("Creating HSM enclave...\n"); oe_result_t result = oe_create_hsm_enclave(G_enclave_path, OE_ENCLAVE_TYPE_AUTO, - CREATE_ENCLAVE_FLAGS, NULL, 0, &enclave); + CREATE_ENCLAVE_FLAGS, + NULL, + 0, + &enclave); if (OE_OK != result) { - LOG("Failed to create enclave: oe_result=%u (%s)\n", result, oe_result_str(result)); + LOG("Failed to create enclave: oe_result=%u (%s)\n", + result, + oe_result_str(result)); return NULL; } diff --git a/firmware/src/sgx/src/untrusted/enclave_provider.h b/firmware/src/sgx/src/untrusted/enclave_provider.h index 37a31f91..3adf6f17 100644 --- a/firmware/src/sgx/src/untrusted/enclave_provider.h +++ b/firmware/src/sgx/src/untrusted/enclave_provider.h @@ -29,16 +29,16 @@ /** * @brief Initializes the enclave provider with the given enclave binary path - * + * * @returns Whether initialization succeeded */ bool epro_init(char* enclave_path); /** - * @brief Returns a pointer to the HSM enclave. This function should always - * return a valid pointer to the enclave, which can be used to perform + * @brief Returns a pointer to the HSM enclave. This function should always + * return a valid pointer to the enclave, which can be used to perform * ecall operations. - * + * * @returns A valid pointer to the HSM enclave, or NULL if an error occurred */ oe_enclave_t* epro_get_enclave(); diff --git a/firmware/src/sgx/src/untrusted/enclave_proxy.c b/firmware/src/sgx/src/untrusted/enclave_proxy.c index 6e402b56..53bb4c44 100644 --- a/firmware/src/sgx/src/untrusted/enclave_proxy.c +++ b/firmware/src/sgx/src/untrusted/enclave_proxy.c @@ -22,8 +22,8 @@ * ECALLS */ -bool eprx_system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { - oe_enclave_t *enclave = epro_get_enclave(); +bool eprx_system_init(unsigned char* msg_buffer, size_t msg_buffer_size) { + oe_enclave_t* enclave = epro_get_enclave(); if (enclave == NULL) { LOG("Failed to retrieve the enclave. " "Unable to call system_init().\n"); @@ -31,14 +31,14 @@ bool eprx_system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { } bool result; - oe_result_t oe_result = ecall_system_init(enclave, &result, - msg_buffer, msg_buffer_size); + oe_result_t oe_result = + ecall_system_init(enclave, &result, msg_buffer, msg_buffer_size); CHECK_ECALL_RESULT(oe_result, "Failed to call system_init()", false); return result; } unsigned int eprx_system_process_apdu(unsigned int rx) { - oe_enclave_t *enclave = epro_get_enclave(); + oe_enclave_t* enclave = epro_get_enclave(); if (enclave == NULL) { LOG("Failed to retrieve the enclave. " "Unable to call system_process_command().\n"); @@ -48,7 +48,8 @@ unsigned int eprx_system_process_apdu(unsigned int rx) { unsigned int result; oe_result_t oe_result = ecall_system_process_apdu(enclave, &result, rx); - CHECK_ECALL_RESULT(oe_result, "Failed to call ecall_system_process_apdu()", false); + CHECK_ECALL_RESULT( + oe_result, "Failed to call ecall_system_process_apdu()", false); return result; } @@ -85,4 +86,3 @@ bool ocall_kvstore_remove(char* key) { log_clear_prefix(); return retval; } - diff --git a/firmware/src/sgx/src/untrusted/io.h b/firmware/src/sgx/src/untrusted/io.h index 405fe86a..cc2d0394 100644 --- a/firmware/src/sgx/src/untrusted/io.h +++ b/firmware/src/sgx/src/untrusted/io.h @@ -34,12 +34,12 @@ extern unsigned char io_apdu_buffer[APDU_BUFFER_SIZE]; /** - * @brief Initializes the I/O module. Starts a TCP server at the given host and + * @brief Initializes the I/O module. Starts a TCP server at the given host and * port. - * + * * @param port the port on which to listen for connections * @param host the interface to bind to - * + * */ bool io_init(int port, const char *host); diff --git a/firmware/src/sgx/src/untrusted/keyvalue_store.c b/firmware/src/sgx/src/untrusted/keyvalue_store.c index b743a7ec..a1058253 100644 --- a/firmware/src/sgx/src/untrusted/keyvalue_store.c +++ b/firmware/src/sgx/src/untrusted/keyvalue_store.c @@ -30,10 +30,9 @@ #define KVSTORE_SUFFIX ".dat" static char* filename_for(char* key) { - size_t filename_size = strlen(KVSTORE_PREFIX) + - strlen(KVSTORE_SUFFIX) + - strlen(key); - char* filename = malloc(filename_size+1); + size_t filename_size = + strlen(KVSTORE_PREFIX) + strlen(KVSTORE_SUFFIX) + strlen(key); + char* filename = malloc(filename_size + 1); strcpy(filename, ""); strcat(filename, KVSTORE_PREFIX); strcat(filename, key); @@ -45,7 +44,8 @@ static FILE* open_file_for(char* key, char* mode, size_t* file_size) { char* filename = filename_for(key); struct stat fst; stat(filename, &fst); - if (file_size) *file_size = fst.st_size; + if (file_size) + *file_size = fst.st_size; FILE* file = fopen(filename, mode); free(filename); return file; @@ -64,10 +64,7 @@ bool kvstore_save(char* key, uint8_t* data, size_t data_size) { return false; } - if (fwrite(data, - sizeof(data[0]), - data_size, - file) != data_size) { + if (fwrite(data, sizeof(data[0]), data_size, file) != data_size) { LOG("Error writing secret payload for key <%s>\n", key); fclose(file); return false; @@ -109,10 +106,7 @@ size_t kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size) { return 0; } - if (fread(data_buf, - sizeof(data_buf[0]), - file_size, - file) != file_size) { + if (fread(data_buf, sizeof(data_buf[0]), file_size, file) != file_size) { LOG("Could not read payload for key <%s>\n", key); fclose(file); return 0; @@ -125,7 +119,8 @@ size_t kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size) { bool kvstore_remove(char* key) { char* filename = filename_for(key); int result = remove(filename); - if (result) LOG("Error removing file for key <%s>\n", key); + if (result) + LOG("Error removing file for key <%s>\n", key); free(filename); return !result; } diff --git a/firmware/src/sgx/src/untrusted/keyvalue_store.h b/firmware/src/sgx/src/untrusted/keyvalue_store.h index 359d8010..872a60a5 100644 --- a/firmware/src/sgx/src/untrusted/keyvalue_store.h +++ b/firmware/src/sgx/src/untrusted/keyvalue_store.h @@ -27,40 +27,40 @@ /** * @brief Tell whether a given key currently exists - * + * * @param key the key to check for - * + * * @returns whether the key exists */ bool kvstore_exists(char* key); /** * @brief Save the given data to the given key - * + * * @param key the key to save the data to * @param data the buffer containing the data to write * @param data_size the data size in bytes - * + * * @returns whether saving succeeded */ bool kvstore_save(char* key, uint8_t* data, size_t data_size); /** * @brief Read the given key into the given buffer - * + * * @param key the key to read from * @param data_buf the buffer to read the data to * @param buffer_size the buffer size in bytes - * + * * @returns the number of bytes read, or ZERO upon error */ size_t kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size); /** * @brief Remove any data associated with the given key - * + * * @param key the key to remove - * + * * @returns whether key removal was successful */ bool kvstore_remove(char* key); diff --git a/firmware/src/sgx/src/untrusted/log.c b/firmware/src/sgx/src/untrusted/log.c index f8aa9e47..0d4ea99c 100644 --- a/firmware/src/sgx/src/untrusted/log.c +++ b/firmware/src/sgx/src/untrusted/log.c @@ -27,7 +27,7 @@ #include "log.h" -static char* log_prefix = (char*)NULL; +static char *log_prefix = (char *)NULL; void LOG(const char *format, ...) { va_list args; @@ -57,10 +57,10 @@ void LOG_HEX(const char *prefix, const void *buffer, const size_t size) { printf("\n"); } -void log_set_prefix(const char* prefix) { - log_prefix = (char*)prefix; +void log_set_prefix(const char *prefix) { + log_prefix = (char *)prefix; } void log_clear_prefix() { - log_prefix = (char*)NULL; + log_prefix = (char *)NULL; } \ No newline at end of file diff --git a/firmware/src/sgx/src/untrusted/log.h b/firmware/src/sgx/src/untrusted/log.h index 99f16a1d..14850e33 100644 --- a/firmware/src/sgx/src/untrusted/log.h +++ b/firmware/src/sgx/src/untrusted/log.h @@ -43,10 +43,10 @@ void LOG_HEX(const char *prefix, const void *buffer, const size_t size); /** * @brief Set a prefix for all logs - * + * * @param prefix the prefix to use for logs */ -void log_set_prefix(const char* prefix); +void log_set_prefix(const char *prefix); /** * @brief Clear any prefix set for logs diff --git a/firmware/src/sgx/src/untrusted/main.c b/firmware/src/sgx/src/untrusted/main.c index 56dfc1fd..d5b36adc 100644 --- a/firmware/src/sgx/src/untrusted/main.c +++ b/firmware/src/sgx/src/untrusted/main.c @@ -45,8 +45,7 @@ static struct argp_option options[] = { {"bind", 'b', "ADDRESS", 0, "Address to bind to", 0}, {"port", 'p', "PORT", 0, "Port to listen on", 0}, - {0} -}; + {0}}; // Argument definitions for argp struct arguments { @@ -91,7 +90,9 @@ static struct argp argp = { parse_opt, "ENCLAVE_PATH", "SGX powHSM", - NULL, NULL, NULL, + NULL, + NULL, + NULL, }; static void finalise_with(int exit_code) { diff --git a/lint-c b/lint-c index 65270971..6f35653f 100755 --- a/lint-c +++ b/lint-c @@ -12,11 +12,12 @@ if [[ $1 == "exec" ]]; then fi SRC_DIR="firmware/src" - SEARCH_DIRS="$SRC_DIR/ledger/signer $SRC_DIR/ledger/ui $SRC_DIR/tcpsigner $SRC_DIR/common $SRC_DIR/hal" + SEARCH_DIRS="$SRC_DIR/ledger/signer $SRC_DIR/ledger/ui $SRC_DIR/tcpsigner $SRC_DIR/common $SRC_DIR/hal $SRC_DIR/sgx" find $SEARCH_DIRS -name "*.[ch]" | \ egrep -v "(bigdigits|bigdtypes|keccak256)\.[ch]$" | \ egrep -v "firmware/src/ledger/ui/src/glyphs.[ch]" | \ + egrep -v "firmware/src/sgx/src/(trusted|untrusted)/hsm_([tu]|args).[ch]" | \ xargs clang-format-10 --style=file $CLANG_ARGS else # Script directory From 607394975d94493df355a417331ec13340332f15 Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:20:21 -0300 Subject: [PATCH 43/50] Sets uninitialized socket file descriptors to -1 (#248) Sets the value of uninitialized file descriptors on io.c to -1 instead of 0. --- firmware/src/sgx/src/untrusted/io.c | 45 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/firmware/src/sgx/src/untrusted/io.c b/firmware/src/sgx/src/untrusted/io.c index b5dd84b4..deb02a78 100644 --- a/firmware/src/sgx/src/untrusted/io.c +++ b/firmware/src/sgx/src/untrusted/io.c @@ -43,6 +43,13 @@ int serverfd; int connfd; struct sockaddr_in servaddr, cliaddr; +static void close_and_reset_fd(int *fd) { + if (fd && (*fd != -1)) { + close(*fd); + *fd = -1; + } +} + static int start_server(int port, const char *host) { int sockfd; struct hostent *hostinfo; @@ -50,14 +57,14 @@ static int start_server(int port, const char *host) { if (hostinfo == NULL) { LOG("Host not found.\n"); - return 0; + return -1; } // socket create and verification sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { LOG("Socket creation failed...\n"); - return 0; + return -1; } explicit_bzero(&servaddr, sizeof(servaddr)); @@ -65,12 +72,12 @@ static int start_server(int port, const char *host) { if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) { LOG("Socket option setting failed failed\n"); - return 0; + return -1; } if (setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &(int){1}, sizeof(int)) < 0) { LOG("Socket option setting failed failed\n"); - return 0; + return -1; } // Set address and port @@ -81,13 +88,13 @@ static int start_server(int port, const char *host) { // Binding newly created socket to given IP and verification if ((bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) != 0) { LOG("Socket bind failed...\n"); - return 0; + return -1; } // Now server is ready to listen and verification if ((listen(sockfd, 5)) != 0) { LOG("Listen failed...\n"); - return 0; + return -1; } LOG("Server listening...\n"); @@ -107,20 +114,14 @@ static bool accept_connection() { } bool io_init(int port, const char *host) { - connfd = 0; + connfd = -1; serverfd = start_server(port, host); - return serverfd; + return (serverfd != -1); } void io_finalise() { - if (connfd) { - close(connfd); - connfd = 0; - } - if (serverfd) { - close(serverfd); - serverfd = 0; - } + close_and_reset_fd(&connfd); + close_and_reset_fd(&serverfd); } unsigned short io_exchange(unsigned short tx) { @@ -129,7 +130,7 @@ unsigned short io_exchange(unsigned short tx) { int readlen; while (true) { - if (!connfd) { + if (connfd == -1) { if (!accept_connection()) { LOG("Error accepting client connection\n"); return 0; @@ -146,13 +147,13 @@ unsigned short io_exchange(unsigned short tx) { tx_net = htonl(tx_net); if (send(connfd, &tx_net, sizeof(tx_net), MSG_NOSIGNAL) == -1) { LOG("Connection closed by the client\n"); - connfd = 0; + close_and_reset_fd(&connfd); continue; } // Write APDU if (send(connfd, io_apdu_buffer, tx, MSG_NOSIGNAL) == -1) { LOG("Connection closed by the client\n"); - connfd = 0; + close_and_reset_fd(&connfd); continue; } LOG_HEX("I/O =>", io_apdu_buffer, tx); @@ -172,8 +173,7 @@ unsigned short io_exchange(unsigned short tx) { "Disconnected\n", readlen, rx); - close(connfd); - connfd = 0; + close_and_reset_fd(&connfd); continue; } LOG_HEX("I/O <=", io_apdu_buffer, rx); @@ -196,7 +196,6 @@ unsigned short io_exchange(unsigned short tx) { readlen, sizeof(rx_net)); } - close(connfd); - connfd = 0; + close_and_reset_fd(&connfd); } } From bebff196a51fb87e5a3284105bd7572ce367561d Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:06:24 -0300 Subject: [PATCH 44/50] Removes .gitignore from distribution builds (#264) --- build-dist-ledger | 1 + build-dist-sgx | 1 + 2 files changed, 2 insertions(+) diff --git a/build-dist-ledger b/build-dist-ledger index c62d0297..22959902 100755 --- a/build-dist-ledger +++ b/build-dist-ledger @@ -35,6 +35,7 @@ echo -e "\e[32mBuilding into \e[93m$DEST_DIR\e[32m with checkpoint \e[93m$CHECKP echo -e "\e[33mCopying files and creating directories...\e[0m" rm -rf $DEST_DIR cp -Rf $ROOT_DIR/dist/ledger $DEST_DIR +rm $DEST_DIR/.gitignore rm -rf $FIRMWARE_DIR mkdir -p $FIRMWARE_DIR diff --git a/build-dist-sgx b/build-dist-sgx index 31052197..61f347a2 100755 --- a/build-dist-sgx +++ b/build-dist-sgx @@ -33,6 +33,7 @@ echo -e "\e[32mBuilding into \e[93m$DEST_DIR\e[32m with checkpoint \e[93m$CHECKP echo -e "\e[33mCopying files and creating directories...\e[0m" rm -rf $DEST_DIR cp -Rf $ROOT_DIR/dist/sgx $DEST_DIR +rm $DEST_DIR/.gitignore rm -rf $BIN_DIR mkdir -p $BIN_DIR From 21f3b80d219c1de46bdaf38e2e034a02e3bf7944 Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Mon, 20 Jan 2025 10:00:32 -0300 Subject: [PATCH 45/50] Fixes signature for finalise function (#249) Fixes the signature of finalise function so that it conforms with the expected signal handler function signature --- firmware/src/sgx/src/untrusted/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/src/sgx/src/untrusted/main.c b/firmware/src/sgx/src/untrusted/main.c index d5b36adc..a2d2c1af 100644 --- a/firmware/src/sgx/src/untrusted/main.c +++ b/firmware/src/sgx/src/untrusted/main.c @@ -103,7 +103,9 @@ static void finalise_with(int exit_code) { exit(exit_code); } -static void finalise() { +static void finalise(int signum) { + (void) signum; // Suppress unused parameter warning + finalise_with(0); } From 6359eed20745b7e4f403e50deecf106952d6689b Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Mon, 20 Jan 2025 11:46:39 -0300 Subject: [PATCH 46/50] Fixes formatting error identified by C linter (#266) --- firmware/src/sgx/src/untrusted/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/src/sgx/src/untrusted/main.c b/firmware/src/sgx/src/untrusted/main.c index a2d2c1af..222c7add 100644 --- a/firmware/src/sgx/src/untrusted/main.c +++ b/firmware/src/sgx/src/untrusted/main.c @@ -104,7 +104,7 @@ static void finalise_with(int exit_code) { } static void finalise(int signum) { - (void) signum; // Suppress unused parameter warning + (void)signum; // Suppress unused parameter warning finalise_with(0); } From ed9b51b12c915256588439f8f4d9173a0a6b28f2 Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:35:54 -0300 Subject: [PATCH 47/50] Sanitizes key for kvstore (#247) - Sanitizes the key before using it for file operations. - Added unit tests for keyvalue_store module --- .../src/sgx/src/untrusted/keyvalue_store.c | 39 ++- .../src/sgx/src/untrusted/keyvalue_store.h | 3 + firmware/src/sgx/test/common/common.mk | 4 +- firmware/src/sgx/test/keyvalue_store/Makefile | 38 +++ .../test/keyvalue_store/test_keyvalue_store.c | 282 ++++++++++++++++++ firmware/src/sgx/test/run-all.sh | 2 +- 6 files changed, 363 insertions(+), 5 deletions(-) create mode 100644 firmware/src/sgx/test/keyvalue_store/Makefile create mode 100644 firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c diff --git a/firmware/src/sgx/src/untrusted/keyvalue_store.c b/firmware/src/sgx/src/untrusted/keyvalue_store.c index a1058253..b68d6ce2 100644 --- a/firmware/src/sgx/src/untrusted/keyvalue_store.c +++ b/firmware/src/sgx/src/untrusted/keyvalue_store.c @@ -23,19 +23,52 @@ */ #include -#include "hsm_u.h" +#include +#include +#include #include "log.h" +#include "keyvalue_store.h" #define KVSTORE_PREFIX "./kvstore-" #define KVSTORE_SUFFIX ".dat" +#define KVSTORE_MAX_KEY_LEN 150 + +// Sanitizes a key by allowing only [a-zA-Z0-9]. If one or more invalid +// characters are found, Replace them with a single hyphen. +static void sanitize_key(char* key, char* sanitized_key) { + if (!key || !sanitized_key) + return; + + size_t key_len = strlen(key); + + // Truncate key if it's too long + if (key_len > KVSTORE_MAX_KEY_LEN) { + key_len = KVSTORE_MAX_KEY_LEN; + } + + bool prev_char_valid = false; + size_t sanitized_key_len = 0; + for (size_t i = 0; i < key_len; i++) { + if (isalnum(key[i])) { + sanitized_key[sanitized_key_len++] = key[i]; + prev_char_valid = true; + } else if (prev_char_valid) { + sanitized_key[sanitized_key_len++] = '-'; + prev_char_valid = false; + } + } + sanitized_key[sanitized_key_len] = '\0'; +} static char* filename_for(char* key) { + char sanitized_key[KVSTORE_MAX_KEY_LEN + 1]; + sanitize_key(key, sanitized_key); size_t filename_size = - strlen(KVSTORE_PREFIX) + strlen(KVSTORE_SUFFIX) + strlen(key); + strlen(KVSTORE_PREFIX) + strlen(KVSTORE_SUFFIX) + strlen(sanitized_key); char* filename = malloc(filename_size + 1); strcpy(filename, ""); strcat(filename, KVSTORE_PREFIX); - strcat(filename, key); + strcat(filename, sanitized_key); strcat(filename, KVSTORE_SUFFIX); return filename; } diff --git a/firmware/src/sgx/src/untrusted/keyvalue_store.h b/firmware/src/sgx/src/untrusted/keyvalue_store.h index 872a60a5..f54de20b 100644 --- a/firmware/src/sgx/src/untrusted/keyvalue_store.h +++ b/firmware/src/sgx/src/untrusted/keyvalue_store.h @@ -25,6 +25,9 @@ #ifndef __KEYVALUE_STORE_H #define __KEYVALUE_STORE_H +#include +#include + /** * @brief Tell whether a given key currently exists * diff --git a/firmware/src/sgx/test/common/common.mk b/firmware/src/sgx/test/common/common.mk index fbf7a6b1..7d43cd52 100644 --- a/firmware/src/sgx/test/common/common.mk +++ b/firmware/src/sgx/test/common/common.mk @@ -1,5 +1,6 @@ TESTCOMMONDIR = ../common SGXTRUSTEDDIR = ../../src/trusted +SGXUNTRUSTEDDIR = ../../src/untrusted HALINCDIR = ../../../hal/include HALSGXSRCDIR = ../../../hal/sgx/src/trusted POWHSMSRCDIR = ../../../powhsm/src @@ -7,13 +8,14 @@ COMMONDIR = ../../../common/src CFLAGS = -iquote $(TESTCOMMONDIR) CFLAGS += -iquote $(SGXTRUSTEDDIR) +CFLAGS += -iquote $(SGXUNTRUSTEDDIR) CFLAGS += -iquote $(HALINCDIR) CFLAGS += -iquote $(HALSGXSRCDIR) CFLAGS += -iquote $(POWHSMSRCDIR) CFLAGS += -iquote $(COMMONDIR) CFLAGS += -DHSM_PLATFORM_SGX -VPATH += $(SGXTRUSTEDDIR):$(COMMONDIR) +VPATH += $(SGXTRUSTEDDIR):$(SGXUNTRUSTEDDIR):$(COMMONDIR) include ../../../../coverage/coverage.mk diff --git a/firmware/src/sgx/test/keyvalue_store/Makefile b/firmware/src/sgx/test/keyvalue_store/Makefile new file mode 100644 index 00000000..705a9078 --- /dev/null +++ b/firmware/src/sgx/test/keyvalue_store/Makefile @@ -0,0 +1,38 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +PROG = test.out +OBJS = keyvalue_store.o test_keyvalue_store.o log.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) *.o *.dat $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c b/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c new file mode 100644 index 00000000..483d5ed3 --- /dev/null +++ b/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c @@ -0,0 +1,282 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include "keyvalue_store.h" + +// Test helpers +void setup() { + system("rm -f ./kvstore-*.dat"); +} + +void assert_key_exists(char* key, bool exists) { + assert(kvstore_exists(key) == exists); +} + +void assert_key_value(char* key, uint8_t* data, size_t data_size) { + uint8_t retrieved_data[BUFSIZ]; + size_t retrieved_size = + kvstore_get(key, retrieved_data, sizeof(retrieved_data)); + assert(retrieved_size == data_size); + assert(memcmp(retrieved_data, data, retrieved_size) == 0); +} + +void save_and_assert_success(char* key, uint8_t* data, size_t data_size) { + assert(kvstore_save(key, data, data_size)); + assert_key_exists(key, true); +} + +void remove_and_assert_success(char* key) { + assert(kvstore_remove(key)); + assert_key_exists(key, false); +} + +void assert_file_exists(char* filename, bool exists) { + FILE* file = fopen(filename, "rb"); + if (exists) { + assert(file != NULL); + } else { + assert(file == NULL); + } + if (file) { + fclose(file); + } +} + +void assert_file_contents(char* filename, uint8_t* data, size_t data_size) { + FILE* file = fopen(filename, "rb"); + assert(file != NULL); + + uint8_t file_data[BUFSIZ]; + size_t file_size = + fread(file_data, sizeof(file_data[0]), sizeof(file_data), file); + assert(file_size == data_size); + assert(memcmp(file_data, data, data_size) == 0); + + fclose(file); +} + +// Test cases +void test_save_retrieve() { + printf("Test save and retrieve...\n"); + setup(); + + struct { + char* key; + uint8_t* data; + } input_data[] = { + {"a-key", (uint8_t*)"some piece of data"}, + {"another-key", (uint8_t*)"another piece of data"}, + {"yet-another-key", (uint8_t*)"yet another piece of data"}, + {"the-last-key", (uint8_t*)"the last piece of data"}}; + size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); + + for (size_t i = 0; i < num_inputs; i++) { + save_and_assert_success(input_data[i].key, + input_data[i].data, + strlen((char*)input_data[i].data)); + } + + for (size_t i = 0; i < num_inputs; i++) { + assert_key_value(input_data[i].key, + input_data[i].data, + strlen((char*)input_data[i].data)); + } +} + +void test_kvstore_exists() { + printf("Test kvstore_exists...\n"); + setup(); + + struct { + char* key; + uint8_t* data; + } existing_keys[] = { + {"first-key", (uint8_t*)"some piece of data"}, + {"second-key", (uint8_t*)"another piece of data"}, + {"third-key", (uint8_t*)"yet another piece of data"}, + }; + size_t num_existing_keys = sizeof(existing_keys) / sizeof(existing_keys[0]); + + char* non_existing_keys[] = { + "non-existing-key-1", + "non-existing-key-2", + "non-existing-key-3", + }; + size_t num_non_existing_keys = + sizeof(non_existing_keys) / sizeof(non_existing_keys[0]); + + for (size_t i = 0; i < num_existing_keys; i++) { + save_and_assert_success(existing_keys[i].key, + existing_keys[i].data, + strlen((char*)existing_keys[i].data)); + } + + for (size_t i = 0; i < num_existing_keys; i++) { + assert_key_exists(existing_keys[i].key, true); + } + + for (size_t i = 0; i < num_non_existing_keys; i++) { + assert_key_exists(non_existing_keys[i], false); + } +} + +void test_save_remove() { + printf("Test save and remove...\n"); + setup(); + + struct { + char* key; + uint8_t* data; + bool remove; + } input_data[] = { + {"first-key", (uint8_t*)"some piece of data", false}, + {"second-key", (uint8_t*)"another piece of data", true}, + {"third-key", (uint8_t*)"yet another piece of data", true}, + {"fourth-key", (uint8_t*)"the last piece of data", false}, + }; + size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); + + for (size_t i = 0; i < num_inputs; i++) { + save_and_assert_success(input_data[i].key, + input_data[i].data, + strlen((char*)input_data[i].data)); + assert_key_value(input_data[i].key, + input_data[i].data, + strlen((char*)input_data[i].data)); + } + + // Remove selected keys + for (size_t i = 0; i < num_inputs; i++) { + if (input_data[i].remove) { + remove_and_assert_success(input_data[i].key); + } + } + + // Assert that the selected keys were removed and the others still exist + for (size_t i = 0; i < num_inputs; i++) { + if (input_data[i].remove) { + assert_key_exists(input_data[i].key, false); + } else { + assert_key_value(input_data[i].key, + input_data[i].data, + strlen((char*)input_data[i].data)); + } + } +} + +void test_filename() { + printf("Test filename for key...\n"); + setup(); + + struct { + char* key; + uint8_t* data; + char* filename; + } input_data[] = { + {"first-key", "data for the first key", "kvstore-first-key.dat"}, + {"second-key", "data for the second key", "kvstore-second-key.dat"}, + {"third-key", "data for the third key", "kvstore-third-key.dat"}, + {"fourth-key", "data for the fourth key", "kvstore-fourth-key.dat"}, + }; + size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); + + // Make sure none of the files exist + for (size_t i = 0; i < num_inputs; i++) { + assert_file_exists(input_data[i].filename, false); + } + + // Save data to each key and assert that the file name and contents are + // correct + for (size_t i = 0; i < num_inputs; i++) { + save_and_assert_success(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + assert_file_exists(input_data[i].filename, true); + assert_file_contents(input_data[i].filename, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + } +} + +void test_sanitize_key() { + printf("Test sanitize key...\n"); + setup(); + + struct { + char* key; + char* filename; + uint8_t* data; + } input_data[] = { + {"onlyletters", "kvstore-onlyletters.dat", "data1"}, + {"123456", "kvstore-123456.dat", "data2"}, + {"lettersandnumbers123", "kvstore-lettersandnumbers123.dat", "data3"}, + {"letters-and-numbers-with-hyphen-123", + "kvstore-letters-and-numbers-with-hyphen-123.dat", + "data4"}, + {"key containing spaces", "kvstore-key-containing-spaces.dat", "data5"}, + {"key containing special characters!@#$%^&*()", + "kvstore-key-containing-special-characters-.dat", + "data6"}, + {"../../../../../etc/passwd", "kvstore-etc-passwd.dat", "data7"}, + {"some@#£_&-(_./file#£+-:;name", "kvstore-some-file-name.dat", "data8"}, + }; + size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); + + // Make sure none of the files exist + for (size_t i = 0; i < num_inputs; i++) { + assert_file_exists(input_data[i].filename, false); + } + + // Save data to each key and assert that the file name and contents are + // correct + for (size_t i = 0; i < num_inputs; i++) { + save_and_assert_success( + input_data[i].key, input_data[i].data, strlen(input_data[i].data)); + assert_file_exists(input_data[i].filename, true); + assert_file_contents(input_data[i].filename, + input_data[i].data, + strlen(input_data[i].data)); + } + + // Ensure data can be retrieved with the original key + for (size_t i = 0; i < num_inputs; i++) { + assert_key_value( + input_data[i].key, input_data[i].data, strlen(input_data[i].data)); + } +} + +int main() { + test_save_retrieve(); + test_kvstore_exists(); + test_save_remove(); + test_filename(); + test_sanitize_key(); + return 0; +} \ No newline at end of file diff --git a/firmware/src/sgx/test/run-all.sh b/firmware/src/sgx/test/run-all.sh index e69b07d7..e54a9360 100755 --- a/firmware/src/sgx/test/run-all.sh +++ b/firmware/src/sgx/test/run-all.sh @@ -2,7 +2,7 @@ if [[ $1 == "exec" ]]; then BASEDIR=$(realpath $(dirname $0)) - TESTDIRS="system" + TESTDIRS="system keyvalue_store" for d in $TESTDIRS; do echo "******************************" echo "Testing $d..." From 353c4cf1962d7802847dab835f0fab75cc60feb3 Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 22 Jan 2025 01:19:03 +1300 Subject: [PATCH 48/50] Added APDU buffer pointer validation to SGX enclave init sequence (#267) - Using oe_is_outside_enclave to validate the APDU buffer in system_init - Added and updated unit tests cases --- firmware/src/sgx/src/trusted/system.c | 9 +++ firmware/src/sgx/test/common/common.mk | 3 +- .../src/sgx/test/common/openenclave/enclave.h | 27 ++++++++ .../test/keyvalue_store/test_keyvalue_store.c | 69 ++++++++++--------- firmware/src/sgx/test/system/test_system.c | 36 +++++++++- 5 files changed, 108 insertions(+), 36 deletions(-) create mode 100644 firmware/src/sgx/test/common/openenclave/enclave.h diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c index 9bb65808..114ee4bd 100644 --- a/firmware/src/sgx/src/trusted/system.c +++ b/firmware/src/sgx/src/trusted/system.c @@ -1,4 +1,5 @@ #include +#include #include "hal/constants.h" #include "hal/communication.h" @@ -166,6 +167,14 @@ bool system_init(unsigned char* msg_buffer, size_t msg_buffer_size) { msg_buffer_size); return false; } + + // Validate that the APDU buffer is entirely outside the enclave + // memory space + if (!oe_is_outside_enclave(msg_buffer, msg_buffer_size)) { + LOG("APDU buffer memory area not outside the enclave\n"); + return false; + } + apdu_buffer = msg_buffer; apdu_buffer_size = msg_buffer_size; diff --git a/firmware/src/sgx/test/common/common.mk b/firmware/src/sgx/test/common/common.mk index 7d43cd52..3b10a292 100644 --- a/firmware/src/sgx/test/common/common.mk +++ b/firmware/src/sgx/test/common/common.mk @@ -6,7 +6,8 @@ HALSGXSRCDIR = ../../../hal/sgx/src/trusted POWHSMSRCDIR = ../../../powhsm/src COMMONDIR = ../../../common/src -CFLAGS = -iquote $(TESTCOMMONDIR) +CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function +CFLAGS += -I $(TESTCOMMONDIR) CFLAGS += -iquote $(SGXTRUSTEDDIR) CFLAGS += -iquote $(SGXUNTRUSTEDDIR) CFLAGS += -iquote $(HALINCDIR) diff --git a/firmware/src/sgx/test/common/openenclave/enclave.h b/firmware/src/sgx/test/common/openenclave/enclave.h new file mode 100644 index 00000000..87b7f344 --- /dev/null +++ b/firmware/src/sgx/test/common/openenclave/enclave.h @@ -0,0 +1,27 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +bool oe_is_outside_enclave(const void *ptr, size_t size); diff --git a/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c b/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c index 483d5ed3..87ff9ae6 100644 --- a/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c +++ b/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c @@ -89,24 +89,23 @@ void test_save_retrieve() { struct { char* key; - uint8_t* data; - } input_data[] = { - {"a-key", (uint8_t*)"some piece of data"}, - {"another-key", (uint8_t*)"another piece of data"}, - {"yet-another-key", (uint8_t*)"yet another piece of data"}, - {"the-last-key", (uint8_t*)"the last piece of data"}}; + char* data; + } input_data[] = {{"a-key", "some piece of data"}, + {"another-key", "another piece of data"}, + {"yet-another-key", "yet another piece of data"}, + {"the-last-key", "the last piece of data"}}; size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); for (size_t i = 0; i < num_inputs; i++) { save_and_assert_success(input_data[i].key, - input_data[i].data, - strlen((char*)input_data[i].data)); + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); } for (size_t i = 0; i < num_inputs; i++) { assert_key_value(input_data[i].key, - input_data[i].data, - strlen((char*)input_data[i].data)); + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); } } @@ -116,11 +115,11 @@ void test_kvstore_exists() { struct { char* key; - uint8_t* data; + char* data; } existing_keys[] = { - {"first-key", (uint8_t*)"some piece of data"}, - {"second-key", (uint8_t*)"another piece of data"}, - {"third-key", (uint8_t*)"yet another piece of data"}, + {"first-key", "some piece of data"}, + {"second-key", "another piece of data"}, + {"third-key", "yet another piece of data"}, }; size_t num_existing_keys = sizeof(existing_keys) / sizeof(existing_keys[0]); @@ -134,8 +133,8 @@ void test_kvstore_exists() { for (size_t i = 0; i < num_existing_keys; i++) { save_and_assert_success(existing_keys[i].key, - existing_keys[i].data, - strlen((char*)existing_keys[i].data)); + (uint8_t*)existing_keys[i].data, + strlen(existing_keys[i].data)); } for (size_t i = 0; i < num_existing_keys; i++) { @@ -153,23 +152,23 @@ void test_save_remove() { struct { char* key; - uint8_t* data; + char* data; bool remove; } input_data[] = { - {"first-key", (uint8_t*)"some piece of data", false}, - {"second-key", (uint8_t*)"another piece of data", true}, - {"third-key", (uint8_t*)"yet another piece of data", true}, - {"fourth-key", (uint8_t*)"the last piece of data", false}, + {"first-key", "some piece of data", false}, + {"second-key", "another piece of data", true}, + {"third-key", "yet another piece of data", true}, + {"fourth-key", "the last piece of data", false}, }; size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); for (size_t i = 0; i < num_inputs; i++) { save_and_assert_success(input_data[i].key, - input_data[i].data, - strlen((char*)input_data[i].data)); + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); assert_key_value(input_data[i].key, - input_data[i].data, - strlen((char*)input_data[i].data)); + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); } // Remove selected keys @@ -185,8 +184,8 @@ void test_save_remove() { assert_key_exists(input_data[i].key, false); } else { assert_key_value(input_data[i].key, - input_data[i].data, - strlen((char*)input_data[i].data)); + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); } } } @@ -197,7 +196,7 @@ void test_filename() { struct { char* key; - uint8_t* data; + char* data; char* filename; } input_data[] = { {"first-key", "data for the first key", "kvstore-first-key.dat"}, @@ -232,7 +231,7 @@ void test_sanitize_key() { struct { char* key; char* filename; - uint8_t* data; + char* data; } input_data[] = { {"onlyletters", "kvstore-onlyletters.dat", "data1"}, {"123456", "kvstore-123456.dat", "data2"}, @@ -257,18 +256,20 @@ void test_sanitize_key() { // Save data to each key and assert that the file name and contents are // correct for (size_t i = 0; i < num_inputs; i++) { - save_and_assert_success( - input_data[i].key, input_data[i].data, strlen(input_data[i].data)); + save_and_assert_success(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); assert_file_exists(input_data[i].filename, true); assert_file_contents(input_data[i].filename, - input_data[i].data, + (uint8_t*)input_data[i].data, strlen(input_data[i].data)); } // Ensure data can be retrieved with the original key for (size_t i = 0; i < num_inputs; i++) { - assert_key_value( - input_data[i].key, input_data[i].data, strlen(input_data[i].data)); + assert_key_value(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); } } diff --git a/firmware/src/sgx/test/system/test_system.c b/firmware/src/sgx/test/system/test_system.c index b0c0b760..aec1b7c3 100644 --- a/firmware/src/sgx/test/system/test_system.c +++ b/firmware/src/sgx/test/system/test_system.c @@ -64,6 +64,7 @@ typedef struct mock_calls_counter { int nvmem_init_count; int nvmem_register_block_count; int sest_init_count; + int oe_is_outside_enclave_count; } mock_calls_counter_t; typedef struct nvmem_register_block_args { @@ -106,6 +107,7 @@ typedef struct mock_force_fail { bool endorsement_init; bool nvmem_register_block; bool sest_init; + bool oe_is_outside_enclave; } mock_force_fail_t; typedef struct mock_data { @@ -166,6 +168,11 @@ try_context_t* G_try_last_open_context = &G_try_last_open_context_var; unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; // Mock implementation of dependencies +bool oe_is_outside_enclave(const void* ptr, size_t size) { + MOCK_CALL(oe_is_outside_enclave); + return true; +} + void hsm_init() { NUM_CALLS(hsm_init)++; } @@ -351,6 +358,7 @@ void test_init_success() { printf("Test system_init success...\n"); assert(system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -381,6 +389,23 @@ void test_init_fails_invalid_buf_size() { printf("Test system_init fails with invalid buffer size...\n"); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer) - 1)); + ASSERT_NOT_CALLED(oe_is_outside_enclave); + ASSERT_NOT_CALLED(sest_init); + ASSERT_NOT_CALLED(access_init); + ASSERT_NOT_CALLED(seed_init); + ASSERT_NOT_CALLED(communication_init); + ASSERT_NOT_CALLED(endorsement_init); + ASSERT_NOT_CALLED(nvmem_init); + teardown(); +} + +void test_init_fails_invalid_buf_memarea() { + setup(); + printf("Test system_init fails with invalid buffer memory area...\n"); + + FORCE_FAIL(oe_is_outside_enclave, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); ASSERT_NOT_CALLED(sest_init); ASSERT_NOT_CALLED(access_init); ASSERT_NOT_CALLED(seed_init); @@ -396,6 +421,7 @@ void test_init_fails_when_sest_init_fails() { FORCE_FAIL(sest_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); ASSERT_NOT_CALLED(access_init); ASSERT_NOT_CALLED(seed_init); @@ -411,6 +437,7 @@ void test_init_fails_when_access_init_fails() { FORCE_FAIL(access_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); ASSERT_NOT_CALLED(seed_init); @@ -426,6 +453,7 @@ void test_init_fails_when_seed_init_fails() { FORCE_FAIL(seed_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -441,6 +469,7 @@ void test_init_fails_when_communication_init_fails() { FORCE_FAIL(communication_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -456,6 +485,7 @@ void test_init_fails_when_endorsement_init_fails() { FORCE_FAIL(endorsement_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -471,7 +501,7 @@ void test_init_fails_when_nvmem_register_block_fails() { FORCE_NVMEM_FAIL_ON_KEY("bcstate"); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); - assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -487,6 +517,8 @@ void test_init_fails_when_nvmem_register_block_fails() { FORCE_NVMEM_FAIL_ON_KEY("bcstate_updating"); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 2); + assert(NUM_CALLS(sest_init) == 2); assert(NUM_CALLS(access_init) == 2); assert(NUM_CALLS(seed_init) == 2); assert(NUM_CALLS(communication_init) == 2); @@ -513,6 +545,7 @@ void test_init_fails_when_nvmem_load_fails() { FORCE_FAIL(nvmem_load, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -958,6 +991,7 @@ void test_invalid_cmd_not_handled() { int main() { test_init_success(); test_init_fails_invalid_buf_size(); + test_init_fails_invalid_buf_memarea(); test_init_fails_when_sest_init_fails(); test_init_fails_when_access_init_fails(); test_init_fails_when_seed_init_fails(); From 5e63f11fab2dd3c59f100ced8d65c494ca7e6f57 Mon Sep 17 00:00:00 2001 From: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> Date: Tue, 21 Jan 2025 10:25:52 -0300 Subject: [PATCH 49/50] Moves finalise logic out of signal handler (#268) Signal handler now only sets a flag that is checked in main --- firmware/src/sgx/src/untrusted/main.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/firmware/src/sgx/src/untrusted/main.c b/firmware/src/sgx/src/untrusted/main.c index 222c7add..25a0e4df 100644 --- a/firmware/src/sgx/src/untrusted/main.c +++ b/firmware/src/sgx/src/untrusted/main.c @@ -54,6 +54,9 @@ struct arguments { char *enclave_path; }; +// Global flag to indicate that the application should stop +static sig_atomic_t G_stop_requested = 0; + // Argp individual option parsing function static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; @@ -106,7 +109,9 @@ static void finalise_with(int exit_code) { static void finalise(int signum) { (void)signum; // Suppress unused parameter warning - finalise_with(0); + // Note: Do not add any finalise logic directly here, just set the flag + // and let the main loop handle it + G_stop_requested = 1; } static void set_signal_handlers() { @@ -157,6 +162,10 @@ int main(int argc, char **argv) { unsigned int tx = 0; while (true) { + if (G_stop_requested) { + break; + } + rx = io_exchange(tx); if (rx) { @@ -164,9 +173,11 @@ int main(int argc, char **argv) { } } - LOG("Exited main loop unexpectedly\n"); + finalise_with(0); + return 0; main_error: + LOG("Exited main loop unexpectedly\n"); finalise_with(1); return 1; } From e713a729e53e8a23723300a51dfa5f93d84a66ac Mon Sep 17 00:00:00 2001 From: Ariel Mendelzon Date: Wed, 22 Jan 2025 09:39:55 +1300 Subject: [PATCH 50/50] Merge latest sgx changes (#271) * Fixes coverage report for feature/sgx branch (#224) - Triggers the coverage workflow for pushes to master and feature/sgx branches - Adds optional exec argument unit tests scripts - Some additional fixes to unit tests * Install SGX powHSM as a systemd service (#226) * Version 5.3.2 ALPHA release (#227) - Bumped version to 5.3.2 - Updated version references in firmware, middleware and unit tests - Updated CHANGELOG * Fix middleware docker image build (#252) * Fixed C linting to include sgx code (#261) - Including sgx code in lint-c/format-c scripts - Fixed reported sgx linting errors * Sets uninitialized socket file descriptors to -1 (#248) Sets the value of uninitialized file descriptors on io.c to -1 instead of 0. * Removes .gitignore from distribution builds (#264) * Fixes signature for finalise function (#249) Fixes the signature of finalise function so that it conforms with the expected signal handler function signature * Fixes formatting error identified by C linter (#266) * Sanitizes key for kvstore (#247) - Sanitizes the key before using it for file operations. - Added unit tests for keyvalue_store module * Added APDU buffer pointer validation to SGX enclave init sequence (#267) - Using oe_is_outside_enclave to validate the APDU buffer in system_init - Added and updated unit tests cases * Moves finalise logic out of signal handler (#268) Signal handler now only sets a flag that is checked in main * Fixed C linting errors --------- Co-authored-by: Italo Sampaio <100376888+italo-sampaio@users.noreply.github.com> --- CHANGELOG.md | 10 + build-dist-ledger | 1 + build-dist-sgx | 1 + dist/sgx/scripts/setup | 6 + firmware/src/ledger/ui/src/defs.h | 2 +- .../src/ledger/ui/test/onboard/test_onboard.c | 4 +- firmware/src/powhsm/src/defs.h | 2 +- firmware/src/sgx/src/trusted/ecall.c | 1 - firmware/src/sgx/src/trusted/sync.c | 3 +- firmware/src/sgx/src/trusted/system.c | 27 +- firmware/src/sgx/src/trusted/system.h | 7 +- .../src/sgx/src/untrusted/enclave_provider.c | 15 +- .../src/sgx/src/untrusted/enclave_provider.h | 8 +- .../src/sgx/src/untrusted/enclave_proxy.c | 19 +- firmware/src/sgx/src/untrusted/io.c | 45 ++- firmware/src/sgx/src/untrusted/io.h | 6 +- .../src/sgx/src/untrusted/keyvalue_store.c | 60 +++- .../src/sgx/src/untrusted/keyvalue_store.h | 19 +- firmware/src/sgx/src/untrusted/log.c | 8 +- firmware/src/sgx/src/untrusted/log.h | 4 +- firmware/src/sgx/src/untrusted/main.c | 26 +- firmware/src/sgx/test/common/common.mk | 7 +- .../src/sgx/test/common/openenclave/enclave.h | 27 ++ firmware/src/sgx/test/keyvalue_store/Makefile | 38 +++ .../test/keyvalue_store/test_keyvalue_store.c | 283 ++++++++++++++++++ firmware/src/sgx/test/run-all.sh | 2 +- firmware/src/sgx/test/system/test_system.c | 36 ++- lint-c | 3 +- middleware/ledger/protocol.py | 4 +- middleware/tests/ledger/test_protocol.py | 2 +- middleware/tests/ledger/test_protocol_v1.py | 2 +- 31 files changed, 570 insertions(+), 108 deletions(-) create mode 100644 firmware/src/sgx/test/common/openenclave/enclave.h create mode 100644 firmware/src/sgx/test/keyvalue_store/Makefile create mode 100644 firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 32e2bdcc..a74724b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [5.3.2 ALPHA] - 04/12/2024 + +### Features/enhancements + +- SGX distribution: installing powHSM as a system service + +### Fixes + +- Fixed code coverage report + ## [5.3.1 ALPHA] - 14/11/2024 ### Fixes diff --git a/build-dist-ledger b/build-dist-ledger index c62d0297..22959902 100755 --- a/build-dist-ledger +++ b/build-dist-ledger @@ -35,6 +35,7 @@ echo -e "\e[32mBuilding into \e[93m$DEST_DIR\e[32m with checkpoint \e[93m$CHECKP echo -e "\e[33mCopying files and creating directories...\e[0m" rm -rf $DEST_DIR cp -Rf $ROOT_DIR/dist/ledger $DEST_DIR +rm $DEST_DIR/.gitignore rm -rf $FIRMWARE_DIR mkdir -p $FIRMWARE_DIR diff --git a/build-dist-sgx b/build-dist-sgx index a450cbe6..406206fd 100755 --- a/build-dist-sgx +++ b/build-dist-sgx @@ -33,6 +33,7 @@ echo -e "\e[32mBuilding into \e[93m$DEST_DIR\e[32m with checkpoint \e[93m$CHECKP echo -e "\e[33mCopying files and creating directories...\e[0m" rm -rf $DEST_DIR cp -Rf $ROOT_DIR/dist/sgx $DEST_DIR +rm $DEST_DIR/.gitignore rm -rf $BIN_DIR mkdir -p $BIN_DIR diff --git a/dist/sgx/scripts/setup b/dist/sgx/scripts/setup index 3e816f0b..8c7d8eb6 100755 --- a/dist/sgx/scripts/setup +++ b/dist/sgx/scripts/setup @@ -42,6 +42,12 @@ SCRIPTS_DIR=$ROOT_DIR/scripts # Directory where the finalized systemd service unit will be saved SERVICE_DIR=$ROOT_DIR/service +# HSM scripts directory +SCRIPTS_DIR=$ROOT_DIR/scripts + +# Directory where the finalized systemd service unit will be saved +SERVICE_DIR=$ROOT_DIR/service + function checkHsmBinaries() { # Check for HSM binary files FILES="$HSMBIN_DIR/hsmsgx $HSMBIN_DIR/hsmsgx_enclave.signed" diff --git a/firmware/src/ledger/ui/src/defs.h b/firmware/src/ledger/ui/src/defs.h index b4577ec9..9f7ab309 100644 --- a/firmware/src/ledger/ui/src/defs.h +++ b/firmware/src/ledger/ui/src/defs.h @@ -31,6 +31,6 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 #define VERSION_MINOR 0x03 -#define VERSION_PATCH 0x01 +#define VERSION_PATCH 0x02 #endif // __DEFS_H diff --git a/firmware/src/ledger/ui/test/onboard/test_onboard.c b/firmware/src/ledger/ui/test/onboard/test_onboard.c index 933e13b2..bcc8e555 100644 --- a/firmware/src/ledger/ui/test/onboard/test_onboard.c +++ b/firmware/src/ledger/ui/test/onboard/test_onboard.c @@ -313,11 +313,11 @@ void test_is_onboarded() { G_device_onboarded = true; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x01\x05\x03\x01"); + ASSERT_APDU("\x80\x01\x05\x03\x02"); G_device_onboarded = false; assert(5 == is_onboarded()); - ASSERT_APDU("\x80\x00\x05\x03\x01"); + ASSERT_APDU("\x80\x00\x05\x03\x02"); } int main() { diff --git a/firmware/src/powhsm/src/defs.h b/firmware/src/powhsm/src/defs.h index ac150a22..9465f26a 100644 --- a/firmware/src/powhsm/src/defs.h +++ b/firmware/src/powhsm/src/defs.h @@ -30,6 +30,6 @@ // Version and patchlevel #define VERSION_MAJOR 0x05 #define VERSION_MINOR 0x03 -#define VERSION_PATCH 0x01 +#define VERSION_PATCH 0x02 #endif // __DEFS_H diff --git a/firmware/src/sgx/src/trusted/ecall.c b/firmware/src/sgx/src/trusted/ecall.c index 97f66a76..cdc973bf 100644 --- a/firmware/src/sgx/src/trusted/ecall.c +++ b/firmware/src/sgx/src/trusted/ecall.c @@ -50,4 +50,3 @@ unsigned int ecall_system_process_apdu(unsigned int rx) { SYNC_RELEASE_LOCK(); return result; } - diff --git a/firmware/src/sgx/src/trusted/sync.c b/firmware/src/sgx/src/trusted/sync.c index 078c9eee..179dd58b 100644 --- a/firmware/src/sgx/src/trusted/sync.c +++ b/firmware/src/sgx/src/trusted/sync.c @@ -28,7 +28,8 @@ static bool G_locked = false; bool sync_try_aqcuire_lock() { - if (G_locked) return false; + if (G_locked) + return false; G_locked = true; return true; } diff --git a/firmware/src/sgx/src/trusted/system.c b/firmware/src/sgx/src/trusted/system.c index 02545dc6..51395ea5 100644 --- a/firmware/src/sgx/src/trusted/system.c +++ b/firmware/src/sgx/src/trusted/system.c @@ -1,4 +1,5 @@ #include +#include #include "hal/constants.h" #include "hal/communication.h" @@ -90,13 +91,13 @@ static unsigned int do_unlock(unsigned int rx) { SET_APDU_OP(1); return TX_NO_DATA(); } - + if (APDU_DATA_SIZE(rx) == 0) { THROW(ERR_INVALID_DATA_SIZE); } - SET_APDU_OP( - access_unlock((char*)APDU_DATA_PTR, APDU_DATA_SIZE(rx)) ? 1 : 0); + SET_APDU_OP(access_unlock((char*)APDU_DATA_PTR, APDU_DATA_SIZE(rx)) ? 1 + : 0); return TX_NO_DATA(); } @@ -162,16 +163,25 @@ unsigned int system_process_apdu(unsigned int rx) { return hsm_process_apdu(rx); } -bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { +bool system_init(unsigned char* msg_buffer, size_t msg_buffer_size) { // Setup the shared APDU buffer if (msg_buffer_size != EXPECTED_APDU_BUFFER_SIZE) { LOG("Expected APDU buffer size to be %u but got %lu\n", - EXPECTED_APDU_BUFFER_SIZE, msg_buffer_size); + EXPECTED_APDU_BUFFER_SIZE, + msg_buffer_size); + return false; + } + + // Validate that the APDU buffer is entirely outside the enclave + // memory space + if (!oe_is_outside_enclave(msg_buffer, msg_buffer_size)) { + LOG("APDU buffer memory area not outside the enclave\n"); return false; } + apdu_buffer = msg_buffer; apdu_buffer_size = msg_buffer_size; - + // Initialize modules LOG("Initializing modules...\n"); if (!sest_init()) { @@ -210,9 +220,8 @@ bool system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { } nvmem_init(); - if (!nvmem_register_block("bcstate", - &N_bc_state_var, - sizeof(N_bc_state_var))) { + if (!nvmem_register_block( + "bcstate", &N_bc_state_var, sizeof(N_bc_state_var))) { LOG("Error registering bcstate block\n"); return false; } diff --git a/firmware/src/sgx/src/trusted/system.h b/firmware/src/sgx/src/trusted/system.h index d07a1fd4..3928d9c5 100644 --- a/firmware/src/sgx/src/trusted/system.h +++ b/firmware/src/sgx/src/trusted/system.h @@ -27,7 +27,7 @@ /** * @brief Initializes the system module - * + * * @param msg_buffer the APDU buffer to use * @param msg_buffer_size the size of the APDU buffer in bytes * @@ -42,12 +42,11 @@ void system_finalise(); /** * @brief Process an APDU message - * + * * @param rx number of received bytes - * + * * @returns number of bytes to transmit */ unsigned int system_process_apdu(unsigned int rx); - #endif // __TRUSTED_SYSTEM_H diff --git a/firmware/src/sgx/src/untrusted/enclave_provider.c b/firmware/src/sgx/src/untrusted/enclave_provider.c index 20ac295c..5866ee94 100644 --- a/firmware/src/sgx/src/untrusted/enclave_provider.c +++ b/firmware/src/sgx/src/untrusted/enclave_provider.c @@ -22,7 +22,6 @@ * IN THE SOFTWARE. */ - #include #include "hsm_u.h" @@ -36,7 +35,8 @@ #define CREATE_ENCLAVE_FLAGS OE_ENCLAVE_FLAG_SIMULATE #endif -// Global pointer to the enclave. This should be the only global pointer to the enclave +// Global pointer to the enclave. This should be the only global pointer to the +// enclave static char* G_enclave_path = NULL; static oe_enclave_t* G_enclave = NULL; @@ -51,13 +51,18 @@ bool epro_init(char* enclave_path) { oe_enclave_t* epro_get_enclave() { if (NULL == G_enclave) { - oe_enclave_t *enclave = NULL; + oe_enclave_t* enclave = NULL; LOG("Creating HSM enclave...\n"); oe_result_t result = oe_create_hsm_enclave(G_enclave_path, OE_ENCLAVE_TYPE_AUTO, - CREATE_ENCLAVE_FLAGS, NULL, 0, &enclave); + CREATE_ENCLAVE_FLAGS, + NULL, + 0, + &enclave); if (OE_OK != result) { - LOG("Failed to create enclave: oe_result=%u (%s)\n", result, oe_result_str(result)); + LOG("Failed to create enclave: oe_result=%u (%s)\n", + result, + oe_result_str(result)); return NULL; } diff --git a/firmware/src/sgx/src/untrusted/enclave_provider.h b/firmware/src/sgx/src/untrusted/enclave_provider.h index 37a31f91..3adf6f17 100644 --- a/firmware/src/sgx/src/untrusted/enclave_provider.h +++ b/firmware/src/sgx/src/untrusted/enclave_provider.h @@ -29,16 +29,16 @@ /** * @brief Initializes the enclave provider with the given enclave binary path - * + * * @returns Whether initialization succeeded */ bool epro_init(char* enclave_path); /** - * @brief Returns a pointer to the HSM enclave. This function should always - * return a valid pointer to the enclave, which can be used to perform + * @brief Returns a pointer to the HSM enclave. This function should always + * return a valid pointer to the enclave, which can be used to perform * ecall operations. - * + * * @returns A valid pointer to the HSM enclave, or NULL if an error occurred */ oe_enclave_t* epro_get_enclave(); diff --git a/firmware/src/sgx/src/untrusted/enclave_proxy.c b/firmware/src/sgx/src/untrusted/enclave_proxy.c index ee901026..8dad423c 100644 --- a/firmware/src/sgx/src/untrusted/enclave_proxy.c +++ b/firmware/src/sgx/src/untrusted/enclave_proxy.c @@ -22,8 +22,8 @@ * ECALLS */ -bool eprx_system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { - oe_enclave_t *enclave = epro_get_enclave(); +bool eprx_system_init(unsigned char* msg_buffer, size_t msg_buffer_size) { + oe_enclave_t* enclave = epro_get_enclave(); if (enclave == NULL) { LOG("Failed to retrieve the enclave. " "Unable to call system_init().\n"); @@ -31,14 +31,14 @@ bool eprx_system_init(unsigned char *msg_buffer, size_t msg_buffer_size) { } bool result; - oe_result_t oe_result = ecall_system_init(enclave, &result, - msg_buffer, msg_buffer_size); + oe_result_t oe_result = + ecall_system_init(enclave, &result, msg_buffer, msg_buffer_size); CHECK_ECALL_RESULT(oe_result, "Failed to call system_init()", false); return result; } void eprx_system_finalise() { - oe_enclave_t *enclave = epro_get_enclave(); + oe_enclave_t* enclave = epro_get_enclave(); if (enclave == NULL) { LOG("Failed to retrieve the enclave. " "Unable to call system_finalise().\n"); @@ -48,12 +48,13 @@ void eprx_system_finalise() { oe_result_t oe_result = ecall_system_finalise(enclave); if (OE_OK != oe_result) { LOG("Failed to call system_finalise(): oe_result=%u (%s)\n", - oe_result, oe_result_str(oe_result)); + oe_result, + oe_result_str(oe_result)); } } unsigned int eprx_system_process_apdu(unsigned int rx) { - oe_enclave_t *enclave = epro_get_enclave(); + oe_enclave_t* enclave = epro_get_enclave(); if (enclave == NULL) { LOG("Failed to retrieve the enclave. " "Unable to call system_process_command().\n"); @@ -63,7 +64,8 @@ unsigned int eprx_system_process_apdu(unsigned int rx) { unsigned int result; oe_result_t oe_result = ecall_system_process_apdu(enclave, &result, rx); - CHECK_ECALL_RESULT(oe_result, "Failed to call ecall_system_process_apdu()", false); + CHECK_ECALL_RESULT( + oe_result, "Failed to call ecall_system_process_apdu()", false); return result; } @@ -100,4 +102,3 @@ bool ocall_kvstore_remove(char* key) { log_clear_prefix(); return retval; } - diff --git a/firmware/src/sgx/src/untrusted/io.c b/firmware/src/sgx/src/untrusted/io.c index b5dd84b4..deb02a78 100644 --- a/firmware/src/sgx/src/untrusted/io.c +++ b/firmware/src/sgx/src/untrusted/io.c @@ -43,6 +43,13 @@ int serverfd; int connfd; struct sockaddr_in servaddr, cliaddr; +static void close_and_reset_fd(int *fd) { + if (fd && (*fd != -1)) { + close(*fd); + *fd = -1; + } +} + static int start_server(int port, const char *host) { int sockfd; struct hostent *hostinfo; @@ -50,14 +57,14 @@ static int start_server(int port, const char *host) { if (hostinfo == NULL) { LOG("Host not found.\n"); - return 0; + return -1; } // socket create and verification sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { LOG("Socket creation failed...\n"); - return 0; + return -1; } explicit_bzero(&servaddr, sizeof(servaddr)); @@ -65,12 +72,12 @@ static int start_server(int port, const char *host) { if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) { LOG("Socket option setting failed failed\n"); - return 0; + return -1; } if (setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &(int){1}, sizeof(int)) < 0) { LOG("Socket option setting failed failed\n"); - return 0; + return -1; } // Set address and port @@ -81,13 +88,13 @@ static int start_server(int port, const char *host) { // Binding newly created socket to given IP and verification if ((bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) != 0) { LOG("Socket bind failed...\n"); - return 0; + return -1; } // Now server is ready to listen and verification if ((listen(sockfd, 5)) != 0) { LOG("Listen failed...\n"); - return 0; + return -1; } LOG("Server listening...\n"); @@ -107,20 +114,14 @@ static bool accept_connection() { } bool io_init(int port, const char *host) { - connfd = 0; + connfd = -1; serverfd = start_server(port, host); - return serverfd; + return (serverfd != -1); } void io_finalise() { - if (connfd) { - close(connfd); - connfd = 0; - } - if (serverfd) { - close(serverfd); - serverfd = 0; - } + close_and_reset_fd(&connfd); + close_and_reset_fd(&serverfd); } unsigned short io_exchange(unsigned short tx) { @@ -129,7 +130,7 @@ unsigned short io_exchange(unsigned short tx) { int readlen; while (true) { - if (!connfd) { + if (connfd == -1) { if (!accept_connection()) { LOG("Error accepting client connection\n"); return 0; @@ -146,13 +147,13 @@ unsigned short io_exchange(unsigned short tx) { tx_net = htonl(tx_net); if (send(connfd, &tx_net, sizeof(tx_net), MSG_NOSIGNAL) == -1) { LOG("Connection closed by the client\n"); - connfd = 0; + close_and_reset_fd(&connfd); continue; } // Write APDU if (send(connfd, io_apdu_buffer, tx, MSG_NOSIGNAL) == -1) { LOG("Connection closed by the client\n"); - connfd = 0; + close_and_reset_fd(&connfd); continue; } LOG_HEX("I/O =>", io_apdu_buffer, tx); @@ -172,8 +173,7 @@ unsigned short io_exchange(unsigned short tx) { "Disconnected\n", readlen, rx); - close(connfd); - connfd = 0; + close_and_reset_fd(&connfd); continue; } LOG_HEX("I/O <=", io_apdu_buffer, rx); @@ -196,7 +196,6 @@ unsigned short io_exchange(unsigned short tx) { readlen, sizeof(rx_net)); } - close(connfd); - connfd = 0; + close_and_reset_fd(&connfd); } } diff --git a/firmware/src/sgx/src/untrusted/io.h b/firmware/src/sgx/src/untrusted/io.h index 405fe86a..cc2d0394 100644 --- a/firmware/src/sgx/src/untrusted/io.h +++ b/firmware/src/sgx/src/untrusted/io.h @@ -34,12 +34,12 @@ extern unsigned char io_apdu_buffer[APDU_BUFFER_SIZE]; /** - * @brief Initializes the I/O module. Starts a TCP server at the given host and + * @brief Initializes the I/O module. Starts a TCP server at the given host and * port. - * + * * @param port the port on which to listen for connections * @param host the interface to bind to - * + * */ bool io_init(int port, const char *host); diff --git a/firmware/src/sgx/src/untrusted/keyvalue_store.c b/firmware/src/sgx/src/untrusted/keyvalue_store.c index b743a7ec..b68d6ce2 100644 --- a/firmware/src/sgx/src/untrusted/keyvalue_store.c +++ b/firmware/src/sgx/src/untrusted/keyvalue_store.c @@ -23,20 +23,52 @@ */ #include -#include "hsm_u.h" +#include +#include +#include #include "log.h" +#include "keyvalue_store.h" #define KVSTORE_PREFIX "./kvstore-" #define KVSTORE_SUFFIX ".dat" +#define KVSTORE_MAX_KEY_LEN 150 + +// Sanitizes a key by allowing only [a-zA-Z0-9]. If one or more invalid +// characters are found, Replace them with a single hyphen. +static void sanitize_key(char* key, char* sanitized_key) { + if (!key || !sanitized_key) + return; + + size_t key_len = strlen(key); + + // Truncate key if it's too long + if (key_len > KVSTORE_MAX_KEY_LEN) { + key_len = KVSTORE_MAX_KEY_LEN; + } + + bool prev_char_valid = false; + size_t sanitized_key_len = 0; + for (size_t i = 0; i < key_len; i++) { + if (isalnum(key[i])) { + sanitized_key[sanitized_key_len++] = key[i]; + prev_char_valid = true; + } else if (prev_char_valid) { + sanitized_key[sanitized_key_len++] = '-'; + prev_char_valid = false; + } + } + sanitized_key[sanitized_key_len] = '\0'; +} static char* filename_for(char* key) { - size_t filename_size = strlen(KVSTORE_PREFIX) + - strlen(KVSTORE_SUFFIX) + - strlen(key); - char* filename = malloc(filename_size+1); + char sanitized_key[KVSTORE_MAX_KEY_LEN + 1]; + sanitize_key(key, sanitized_key); + size_t filename_size = + strlen(KVSTORE_PREFIX) + strlen(KVSTORE_SUFFIX) + strlen(sanitized_key); + char* filename = malloc(filename_size + 1); strcpy(filename, ""); strcat(filename, KVSTORE_PREFIX); - strcat(filename, key); + strcat(filename, sanitized_key); strcat(filename, KVSTORE_SUFFIX); return filename; } @@ -45,7 +77,8 @@ static FILE* open_file_for(char* key, char* mode, size_t* file_size) { char* filename = filename_for(key); struct stat fst; stat(filename, &fst); - if (file_size) *file_size = fst.st_size; + if (file_size) + *file_size = fst.st_size; FILE* file = fopen(filename, mode); free(filename); return file; @@ -64,10 +97,7 @@ bool kvstore_save(char* key, uint8_t* data, size_t data_size) { return false; } - if (fwrite(data, - sizeof(data[0]), - data_size, - file) != data_size) { + if (fwrite(data, sizeof(data[0]), data_size, file) != data_size) { LOG("Error writing secret payload for key <%s>\n", key); fclose(file); return false; @@ -109,10 +139,7 @@ size_t kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size) { return 0; } - if (fread(data_buf, - sizeof(data_buf[0]), - file_size, - file) != file_size) { + if (fread(data_buf, sizeof(data_buf[0]), file_size, file) != file_size) { LOG("Could not read payload for key <%s>\n", key); fclose(file); return 0; @@ -125,7 +152,8 @@ size_t kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size) { bool kvstore_remove(char* key) { char* filename = filename_for(key); int result = remove(filename); - if (result) LOG("Error removing file for key <%s>\n", key); + if (result) + LOG("Error removing file for key <%s>\n", key); free(filename); return !result; } diff --git a/firmware/src/sgx/src/untrusted/keyvalue_store.h b/firmware/src/sgx/src/untrusted/keyvalue_store.h index 359d8010..f54de20b 100644 --- a/firmware/src/sgx/src/untrusted/keyvalue_store.h +++ b/firmware/src/sgx/src/untrusted/keyvalue_store.h @@ -25,42 +25,45 @@ #ifndef __KEYVALUE_STORE_H #define __KEYVALUE_STORE_H +#include +#include + /** * @brief Tell whether a given key currently exists - * + * * @param key the key to check for - * + * * @returns whether the key exists */ bool kvstore_exists(char* key); /** * @brief Save the given data to the given key - * + * * @param key the key to save the data to * @param data the buffer containing the data to write * @param data_size the data size in bytes - * + * * @returns whether saving succeeded */ bool kvstore_save(char* key, uint8_t* data, size_t data_size); /** * @brief Read the given key into the given buffer - * + * * @param key the key to read from * @param data_buf the buffer to read the data to * @param buffer_size the buffer size in bytes - * + * * @returns the number of bytes read, or ZERO upon error */ size_t kvstore_get(char* key, uint8_t* data_buf, size_t buffer_size); /** * @brief Remove any data associated with the given key - * + * * @param key the key to remove - * + * * @returns whether key removal was successful */ bool kvstore_remove(char* key); diff --git a/firmware/src/sgx/src/untrusted/log.c b/firmware/src/sgx/src/untrusted/log.c index f8aa9e47..0d4ea99c 100644 --- a/firmware/src/sgx/src/untrusted/log.c +++ b/firmware/src/sgx/src/untrusted/log.c @@ -27,7 +27,7 @@ #include "log.h" -static char* log_prefix = (char*)NULL; +static char *log_prefix = (char *)NULL; void LOG(const char *format, ...) { va_list args; @@ -57,10 +57,10 @@ void LOG_HEX(const char *prefix, const void *buffer, const size_t size) { printf("\n"); } -void log_set_prefix(const char* prefix) { - log_prefix = (char*)prefix; +void log_set_prefix(const char *prefix) { + log_prefix = (char *)prefix; } void log_clear_prefix() { - log_prefix = (char*)NULL; + log_prefix = (char *)NULL; } \ No newline at end of file diff --git a/firmware/src/sgx/src/untrusted/log.h b/firmware/src/sgx/src/untrusted/log.h index 99f16a1d..14850e33 100644 --- a/firmware/src/sgx/src/untrusted/log.h +++ b/firmware/src/sgx/src/untrusted/log.h @@ -43,10 +43,10 @@ void LOG_HEX(const char *prefix, const void *buffer, const size_t size); /** * @brief Set a prefix for all logs - * + * * @param prefix the prefix to use for logs */ -void log_set_prefix(const char* prefix); +void log_set_prefix(const char *prefix); /** * @brief Clear any prefix set for logs diff --git a/firmware/src/sgx/src/untrusted/main.c b/firmware/src/sgx/src/untrusted/main.c index 9251ef1a..fc07d17e 100644 --- a/firmware/src/sgx/src/untrusted/main.c +++ b/firmware/src/sgx/src/untrusted/main.c @@ -45,8 +45,7 @@ static struct argp_option options[] = { {"bind", 'b', "ADDRESS", 0, "Address to bind to", 0}, {"port", 'p', "PORT", 0, "Port to listen on", 0}, - {0} -}; + {0}}; // Argument definitions for argp struct arguments { @@ -55,6 +54,9 @@ struct arguments { char *enclave_path; }; +// Global flag to indicate that the application should stop +static sig_atomic_t G_stop_requested = 0; + // Argp individual option parsing function static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; @@ -91,7 +93,9 @@ static struct argp argp = { parse_opt, "ENCLAVE_PATH", "SGX powHSM", - NULL, NULL, NULL, + NULL, + NULL, + NULL, }; static void finalise_with(int exit_code) { @@ -102,8 +106,12 @@ static void finalise_with(int exit_code) { exit(exit_code); } -static void finalise() { - finalise_with(0); +static void finalise(int signum) { + (void)signum; // Suppress unused parameter warning + + // Note: Do not add any finalise logic directly here, just set the flag + // and let the main loop handle it + G_stop_requested = 1; } static void set_signal_handlers() { @@ -154,6 +162,10 @@ int main(int argc, char **argv) { unsigned int tx = 0; while (true) { + if (G_stop_requested) { + break; + } + rx = io_exchange(tx); if (rx) { @@ -161,9 +173,11 @@ int main(int argc, char **argv) { } } - LOG("Exited main loop unexpectedly\n"); + finalise_with(0); + return 0; main_error: + LOG("Exited main loop unexpectedly\n"); finalise_with(1); return 1; } diff --git a/firmware/src/sgx/test/common/common.mk b/firmware/src/sgx/test/common/common.mk index fbf7a6b1..3b10a292 100644 --- a/firmware/src/sgx/test/common/common.mk +++ b/firmware/src/sgx/test/common/common.mk @@ -1,19 +1,22 @@ TESTCOMMONDIR = ../common SGXTRUSTEDDIR = ../../src/trusted +SGXUNTRUSTEDDIR = ../../src/untrusted HALINCDIR = ../../../hal/include HALSGXSRCDIR = ../../../hal/sgx/src/trusted POWHSMSRCDIR = ../../../powhsm/src COMMONDIR = ../../../common/src -CFLAGS = -iquote $(TESTCOMMONDIR) +CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function +CFLAGS += -I $(TESTCOMMONDIR) CFLAGS += -iquote $(SGXTRUSTEDDIR) +CFLAGS += -iquote $(SGXUNTRUSTEDDIR) CFLAGS += -iquote $(HALINCDIR) CFLAGS += -iquote $(HALSGXSRCDIR) CFLAGS += -iquote $(POWHSMSRCDIR) CFLAGS += -iquote $(COMMONDIR) CFLAGS += -DHSM_PLATFORM_SGX -VPATH += $(SGXTRUSTEDDIR):$(COMMONDIR) +VPATH += $(SGXTRUSTEDDIR):$(SGXUNTRUSTEDDIR):$(COMMONDIR) include ../../../../coverage/coverage.mk diff --git a/firmware/src/sgx/test/common/openenclave/enclave.h b/firmware/src/sgx/test/common/openenclave/enclave.h new file mode 100644 index 00000000..87b7f344 --- /dev/null +++ b/firmware/src/sgx/test/common/openenclave/enclave.h @@ -0,0 +1,27 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +bool oe_is_outside_enclave(const void *ptr, size_t size); diff --git a/firmware/src/sgx/test/keyvalue_store/Makefile b/firmware/src/sgx/test/keyvalue_store/Makefile new file mode 100644 index 00000000..705a9078 --- /dev/null +++ b/firmware/src/sgx/test/keyvalue_store/Makefile @@ -0,0 +1,38 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include ../common/common.mk + +PROG = test.out +OBJS = keyvalue_store.o test_keyvalue_store.o log.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) $(COVFLAGS) -o $@ $^ + +.PHONY: clean test +clean: + rm -f $(PROG) *.o *.dat $(COVFILES) + +test: all + ./$(PROG) diff --git a/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c b/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c new file mode 100644 index 00000000..87ff9ae6 --- /dev/null +++ b/firmware/src/sgx/test/keyvalue_store/test_keyvalue_store.c @@ -0,0 +1,283 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include "keyvalue_store.h" + +// Test helpers +void setup() { + system("rm -f ./kvstore-*.dat"); +} + +void assert_key_exists(char* key, bool exists) { + assert(kvstore_exists(key) == exists); +} + +void assert_key_value(char* key, uint8_t* data, size_t data_size) { + uint8_t retrieved_data[BUFSIZ]; + size_t retrieved_size = + kvstore_get(key, retrieved_data, sizeof(retrieved_data)); + assert(retrieved_size == data_size); + assert(memcmp(retrieved_data, data, retrieved_size) == 0); +} + +void save_and_assert_success(char* key, uint8_t* data, size_t data_size) { + assert(kvstore_save(key, data, data_size)); + assert_key_exists(key, true); +} + +void remove_and_assert_success(char* key) { + assert(kvstore_remove(key)); + assert_key_exists(key, false); +} + +void assert_file_exists(char* filename, bool exists) { + FILE* file = fopen(filename, "rb"); + if (exists) { + assert(file != NULL); + } else { + assert(file == NULL); + } + if (file) { + fclose(file); + } +} + +void assert_file_contents(char* filename, uint8_t* data, size_t data_size) { + FILE* file = fopen(filename, "rb"); + assert(file != NULL); + + uint8_t file_data[BUFSIZ]; + size_t file_size = + fread(file_data, sizeof(file_data[0]), sizeof(file_data), file); + assert(file_size == data_size); + assert(memcmp(file_data, data, data_size) == 0); + + fclose(file); +} + +// Test cases +void test_save_retrieve() { + printf("Test save and retrieve...\n"); + setup(); + + struct { + char* key; + char* data; + } input_data[] = {{"a-key", "some piece of data"}, + {"another-key", "another piece of data"}, + {"yet-another-key", "yet another piece of data"}, + {"the-last-key", "the last piece of data"}}; + size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); + + for (size_t i = 0; i < num_inputs; i++) { + save_and_assert_success(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + } + + for (size_t i = 0; i < num_inputs; i++) { + assert_key_value(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + } +} + +void test_kvstore_exists() { + printf("Test kvstore_exists...\n"); + setup(); + + struct { + char* key; + char* data; + } existing_keys[] = { + {"first-key", "some piece of data"}, + {"second-key", "another piece of data"}, + {"third-key", "yet another piece of data"}, + }; + size_t num_existing_keys = sizeof(existing_keys) / sizeof(existing_keys[0]); + + char* non_existing_keys[] = { + "non-existing-key-1", + "non-existing-key-2", + "non-existing-key-3", + }; + size_t num_non_existing_keys = + sizeof(non_existing_keys) / sizeof(non_existing_keys[0]); + + for (size_t i = 0; i < num_existing_keys; i++) { + save_and_assert_success(existing_keys[i].key, + (uint8_t*)existing_keys[i].data, + strlen(existing_keys[i].data)); + } + + for (size_t i = 0; i < num_existing_keys; i++) { + assert_key_exists(existing_keys[i].key, true); + } + + for (size_t i = 0; i < num_non_existing_keys; i++) { + assert_key_exists(non_existing_keys[i], false); + } +} + +void test_save_remove() { + printf("Test save and remove...\n"); + setup(); + + struct { + char* key; + char* data; + bool remove; + } input_data[] = { + {"first-key", "some piece of data", false}, + {"second-key", "another piece of data", true}, + {"third-key", "yet another piece of data", true}, + {"fourth-key", "the last piece of data", false}, + }; + size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); + + for (size_t i = 0; i < num_inputs; i++) { + save_and_assert_success(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + assert_key_value(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + } + + // Remove selected keys + for (size_t i = 0; i < num_inputs; i++) { + if (input_data[i].remove) { + remove_and_assert_success(input_data[i].key); + } + } + + // Assert that the selected keys were removed and the others still exist + for (size_t i = 0; i < num_inputs; i++) { + if (input_data[i].remove) { + assert_key_exists(input_data[i].key, false); + } else { + assert_key_value(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + } + } +} + +void test_filename() { + printf("Test filename for key...\n"); + setup(); + + struct { + char* key; + char* data; + char* filename; + } input_data[] = { + {"first-key", "data for the first key", "kvstore-first-key.dat"}, + {"second-key", "data for the second key", "kvstore-second-key.dat"}, + {"third-key", "data for the third key", "kvstore-third-key.dat"}, + {"fourth-key", "data for the fourth key", "kvstore-fourth-key.dat"}, + }; + size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); + + // Make sure none of the files exist + for (size_t i = 0; i < num_inputs; i++) { + assert_file_exists(input_data[i].filename, false); + } + + // Save data to each key and assert that the file name and contents are + // correct + for (size_t i = 0; i < num_inputs; i++) { + save_and_assert_success(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + assert_file_exists(input_data[i].filename, true); + assert_file_contents(input_data[i].filename, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + } +} + +void test_sanitize_key() { + printf("Test sanitize key...\n"); + setup(); + + struct { + char* key; + char* filename; + char* data; + } input_data[] = { + {"onlyletters", "kvstore-onlyletters.dat", "data1"}, + {"123456", "kvstore-123456.dat", "data2"}, + {"lettersandnumbers123", "kvstore-lettersandnumbers123.dat", "data3"}, + {"letters-and-numbers-with-hyphen-123", + "kvstore-letters-and-numbers-with-hyphen-123.dat", + "data4"}, + {"key containing spaces", "kvstore-key-containing-spaces.dat", "data5"}, + {"key containing special characters!@#$%^&*()", + "kvstore-key-containing-special-characters-.dat", + "data6"}, + {"../../../../../etc/passwd", "kvstore-etc-passwd.dat", "data7"}, + {"some@#£_&-(_./file#£+-:;name", "kvstore-some-file-name.dat", "data8"}, + }; + size_t num_inputs = sizeof(input_data) / sizeof(input_data[0]); + + // Make sure none of the files exist + for (size_t i = 0; i < num_inputs; i++) { + assert_file_exists(input_data[i].filename, false); + } + + // Save data to each key and assert that the file name and contents are + // correct + for (size_t i = 0; i < num_inputs; i++) { + save_and_assert_success(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + assert_file_exists(input_data[i].filename, true); + assert_file_contents(input_data[i].filename, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + } + + // Ensure data can be retrieved with the original key + for (size_t i = 0; i < num_inputs; i++) { + assert_key_value(input_data[i].key, + (uint8_t*)input_data[i].data, + strlen(input_data[i].data)); + } +} + +int main() { + test_save_retrieve(); + test_kvstore_exists(); + test_save_remove(); + test_filename(); + test_sanitize_key(); + return 0; +} \ No newline at end of file diff --git a/firmware/src/sgx/test/run-all.sh b/firmware/src/sgx/test/run-all.sh index e69b07d7..e54a9360 100755 --- a/firmware/src/sgx/test/run-all.sh +++ b/firmware/src/sgx/test/run-all.sh @@ -2,7 +2,7 @@ if [[ $1 == "exec" ]]; then BASEDIR=$(realpath $(dirname $0)) - TESTDIRS="system" + TESTDIRS="system keyvalue_store" for d in $TESTDIRS; do echo "******************************" echo "Testing $d..." diff --git a/firmware/src/sgx/test/system/test_system.c b/firmware/src/sgx/test/system/test_system.c index 8ee70584..29761631 100644 --- a/firmware/src/sgx/test/system/test_system.c +++ b/firmware/src/sgx/test/system/test_system.c @@ -65,6 +65,7 @@ typedef struct mock_calls_counter { int nvmem_init_count; int nvmem_register_block_count; int sest_init_count; + int oe_is_outside_enclave_count; } mock_calls_counter_t; typedef struct nvmem_register_block_args { @@ -107,6 +108,7 @@ typedef struct mock_force_fail { bool endorsement_init; bool nvmem_register_block; bool sest_init; + bool oe_is_outside_enclave; } mock_force_fail_t; typedef struct mock_data { @@ -167,6 +169,11 @@ try_context_t* G_try_last_open_context = &G_try_last_open_context_var; unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; // Mock implementation of dependencies +bool oe_is_outside_enclave(const void* ptr, size_t size) { + MOCK_CALL(oe_is_outside_enclave); + return true; +} + void hsm_init() { NUM_CALLS(hsm_init)++; } @@ -356,6 +363,7 @@ void test_init_success() { printf("Test system_init success...\n"); assert(system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -386,6 +394,23 @@ void test_init_fails_invalid_buf_size() { printf("Test system_init fails with invalid buffer size...\n"); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer) - 1)); + ASSERT_NOT_CALLED(oe_is_outside_enclave); + ASSERT_NOT_CALLED(sest_init); + ASSERT_NOT_CALLED(access_init); + ASSERT_NOT_CALLED(seed_init); + ASSERT_NOT_CALLED(communication_init); + ASSERT_NOT_CALLED(endorsement_init); + ASSERT_NOT_CALLED(nvmem_init); + teardown(); +} + +void test_init_fails_invalid_buf_memarea() { + setup(); + printf("Test system_init fails with invalid buffer memory area...\n"); + + FORCE_FAIL(oe_is_outside_enclave, true); + assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); ASSERT_NOT_CALLED(sest_init); ASSERT_NOT_CALLED(access_init); ASSERT_NOT_CALLED(seed_init); @@ -401,6 +426,7 @@ void test_init_fails_when_sest_init_fails() { FORCE_FAIL(sest_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); ASSERT_NOT_CALLED(access_init); ASSERT_NOT_CALLED(seed_init); @@ -416,6 +442,7 @@ void test_init_fails_when_access_init_fails() { FORCE_FAIL(access_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); ASSERT_NOT_CALLED(seed_init); @@ -431,6 +458,7 @@ void test_init_fails_when_seed_init_fails() { FORCE_FAIL(seed_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -446,6 +474,7 @@ void test_init_fails_when_communication_init_fails() { FORCE_FAIL(communication_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -461,6 +490,7 @@ void test_init_fails_when_endorsement_init_fails() { FORCE_FAIL(endorsement_init, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -476,7 +506,7 @@ void test_init_fails_when_nvmem_register_block_fails() { FORCE_NVMEM_FAIL_ON_KEY("bcstate"); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); - assert(NUM_CALLS(sest_init) == 1); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -492,6 +522,8 @@ void test_init_fails_when_nvmem_register_block_fails() { FORCE_NVMEM_FAIL_ON_KEY("bcstate_updating"); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 2); + assert(NUM_CALLS(sest_init) == 2); assert(NUM_CALLS(access_init) == 2); assert(NUM_CALLS(seed_init) == 2); assert(NUM_CALLS(communication_init) == 2); @@ -518,6 +550,7 @@ void test_init_fails_when_nvmem_load_fails() { FORCE_FAIL(nvmem_load, true); assert(!system_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer))); + assert(NUM_CALLS(oe_is_outside_enclave) == 1); assert(NUM_CALLS(sest_init) == 1); assert(NUM_CALLS(access_init) == 1); assert(NUM_CALLS(seed_init) == 1); @@ -990,6 +1023,7 @@ void test_invalid_cmd_not_handled() { int main() { test_init_success(); test_init_fails_invalid_buf_size(); + test_init_fails_invalid_buf_memarea(); test_init_fails_when_sest_init_fails(); test_init_fails_when_access_init_fails(); test_init_fails_when_seed_init_fails(); diff --git a/lint-c b/lint-c index 65270971..6f35653f 100755 --- a/lint-c +++ b/lint-c @@ -12,11 +12,12 @@ if [[ $1 == "exec" ]]; then fi SRC_DIR="firmware/src" - SEARCH_DIRS="$SRC_DIR/ledger/signer $SRC_DIR/ledger/ui $SRC_DIR/tcpsigner $SRC_DIR/common $SRC_DIR/hal" + SEARCH_DIRS="$SRC_DIR/ledger/signer $SRC_DIR/ledger/ui $SRC_DIR/tcpsigner $SRC_DIR/common $SRC_DIR/hal $SRC_DIR/sgx" find $SEARCH_DIRS -name "*.[ch]" | \ egrep -v "(bigdigits|bigdtypes|keccak256)\.[ch]$" | \ egrep -v "firmware/src/ledger/ui/src/glyphs.[ch]" | \ + egrep -v "firmware/src/sgx/src/(trusted|untrusted)/hsm_([tu]|args).[ch]" | \ xargs clang-format-10 --style=file $CLANG_ARGS else # Script directory diff --git a/middleware/ledger/protocol.py b/middleware/ledger/protocol.py index 3b683345..4141cda5 100644 --- a/middleware/ledger/protocol.py +++ b/middleware/ledger/protocol.py @@ -38,8 +38,8 @@ class HSM2ProtocolLedger(HSM2Protocol): # Current manager supported versions for HSM UI and HSM SIGNER (<=) - UI_VERSION = HSM2FirmwareVersion(5, 3, 1) - APP_VERSION = HSM2FirmwareVersion(5, 3, 1) + UI_VERSION = HSM2FirmwareVersion(5, 3, 2) + APP_VERSION = HSM2FirmwareVersion(5, 3, 2) # Amount of time to wait to make sure the app is opened OPEN_APP_WAIT = 1 # second diff --git a/middleware/tests/ledger/test_protocol.py b/middleware/tests/ledger/test_protocol.py index 25a076e2..08079d58 100644 --- a/middleware/tests/ledger/test_protocol.py +++ b/middleware/tests/ledger/test_protocol.py @@ -49,7 +49,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 1)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 2)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM2ProtocolLedger(self.pin, self.dongle) diff --git a/middleware/tests/ledger/test_protocol_v1.py b/middleware/tests/ledger/test_protocol_v1.py index 91978469..b0a4d0d1 100644 --- a/middleware/tests/ledger/test_protocol_v1.py +++ b/middleware/tests/ledger/test_protocol_v1.py @@ -47,7 +47,7 @@ def setUp(self): self.dongle.disconnect = Mock() self.dongle.is_onboarded = Mock(return_value=True) self.dongle.get_current_mode = Mock(return_value=HSM2Dongle.MODE.SIGNER) - self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 1)) + self.dongle.get_version = Mock(return_value=HSM2FirmwareVersion(5, 3, 2)) self.dongle.get_signer_parameters = Mock(return_value=Mock( min_required_difficulty=123)) self.protocol = HSM1ProtocolLedger(self.pin, self.dongle)