TI C2000 example: init the software AES context, honour ENTROPY_NUM_SRC, report per-window raw entropy
parent
104cab75a0
commit
def00ad02d
|
|
@ -0,0 +1,30 @@
|
|||
/* entropy_probe.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ENTROPY_PROBE_H
|
||||
#define ENTROPY_PROBE_H
|
||||
|
||||
/* Raw entropy-source characterization image (make ENTROPY_PROBE=1).
|
||||
* Dumps unconditioned samples over SCI; never returns. */
|
||||
void entropy_probe_run(void);
|
||||
|
||||
#endif /* ENTROPY_PROBE_H */
|
||||
|
|
@ -310,6 +310,13 @@ endif
|
|||
# can estimate min-entropy. Measurement only - no crypto runs.
|
||||
ENTROPY_PROBE ?= 0
|
||||
ifeq ($(ENTROPY_PROBE),1)
|
||||
ifneq ($(SIGN)$(MLDSA)$(BENCH),000)
|
||||
$(error ENTROPY_PROBE=1 is a standalone measurement image - build it on its own)
|
||||
endif
|
||||
# Nothing after entropy_probe_run() executes, so linking wolfcrypt_test and
|
||||
# benchmark would only bloat the image.
|
||||
CFLAGS += --define=NO_CRYPT_TEST --define=NO_CRYPT_BENCHMARK
|
||||
HARNESS_SRCS :=
|
||||
CFLAGS += --define=WOLF_ENTROPY_PROBE --define=NO_CRYPT_TEST \
|
||||
--define=NO_CRYPT_BENCHMARK
|
||||
HARNESS_EXTRA += $(CURDIR)/Source/entropy_probe.c
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ ML-DSA-87 (asymmetric, @150 MHz): verify ~225 ms/op; keygen and signing also run
|
|||
|
||||
The F28P550SJ has an on-chip AES accelerator ("AESA", a TI EIP-120t at `0x00042000`) that C2000Ware exposes through `driverlib/f28p55x/driverlib/aes.h`. `HWAES=1` offloads AES-ECB/CBC/CTR to it via the wolfCrypt crypto-callback framework (`wolfcrypt/src/port/ti/ti-c2000-aes.c` in the wolfSSL tree, gated on `WOLFSSL_C2000_AES`). `driverlib.lib` is already linked by this example, so no extra build plumbing is needed.
|
||||
|
||||
Software AES stays compiled in. A context opts into hardware with `wc_AesInit(&aes, NULL, WOLFSSL_C2000_DEVID)`; one initialised with `INVALID_DEVID` runs pure software. `wolf_aes_hw_test()` uses both and compares them, which is the point: on a 16-bit-byte target the octet marshalling into the accelerator's 32-bit registers is the highest-risk part of the port, and a mismatch is exactly what you want to see. The harness prints 13 lines covering ECB/CBC/CTR at 128/192/256 bits, multi-block, split calls, in-place decrypt and a non-block-aligned CTR split, each checked against software and (for the first block of each mode) against the published NIST SP800-38A vector.
|
||||
Software AES stays compiled in. A context opts into hardware with `wc_AesInit(&aes, NULL, WOLFSSL_C2000_DEVID)`; one initialised with `INVALID_DEVID` runs pure software. `wolf_aes_hw_test()` uses both and compares them, which is the point: on a 16-bit-byte target the octet marshalling into the accelerator's 32-bit registers is the highest-risk part of the port, and a mismatch is exactly what you want to see. The harness prints 18 lines covering ECB/CBC/CTR at 128/192/256 bits, multi-block, split calls, in-place decrypt and a non-block-aligned CTR split, each checked against software and (for the first block of each mode) against the published NIST SP800-38A vector.
|
||||
|
||||
`HWAES=1` also defines `WC_USE_DEVID=0x2000` so `wolfcrypt_test` and `benchmark` exercise the device too -- without it they init every context with `INVALID_DEVID` and silently measure software.
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,13 @@
|
|||
/* Counter1 counts down from 0xFFFFF, capping the window near 34,900 INTOSC
|
||||
* cycles at 300 MHz PLL / 10 MHz INTOSC; keep well under that. */
|
||||
#define PROBE_CNT1_SEED 0xFFFFFUL
|
||||
|
||||
/* A sample taken after a DCC ERROR flag or a guard-loop timeout is not noise,
|
||||
* it is a misconfigured clock mux or a stalled counter. Count both so a
|
||||
* capture with any nonzero total can be rejected rather than analysed. */
|
||||
static uint32_t probeDccErrors;
|
||||
static uint32_t probeDccTimeouts;
|
||||
static uint32_t probeAdcTimeouts;
|
||||
#define PROBE_SAMPLES 1024
|
||||
/* printf over SCI dominates; keep the ADC set smaller. */
|
||||
#define PROBE_ADC_SAMPLES 1024
|
||||
|
|
@ -87,12 +94,19 @@ static uint32_t probe_dccSample(uint32_t base, DCC_Count0ClockSource src0,
|
|||
|
||||
DCC_enableModule(base);
|
||||
|
||||
/* Bounded wait, scaled to the window, so a bad mux cannot hang. */
|
||||
/* Bounded wait, scaled to the window, so a bad mux cannot hang. Record
|
||||
* why we stopped: only a clean done-signal yields a usable sample. */
|
||||
for (guard = 0; guard < (window * 256UL) + 100000UL; guard++) {
|
||||
if (DCC_getSingleShotStatus(base) || DCC_getErrorStatus(base)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (DCC_getErrorStatus(base)) {
|
||||
probeDccErrors++;
|
||||
}
|
||||
else if (!DCC_getSingleShotStatus(base)) {
|
||||
probeDccTimeouts++;
|
||||
}
|
||||
|
||||
return (PROBE_CNT1_SEED - (DCC_getCounter1Value(base) & PROBE_CNT1_SEED));
|
||||
}
|
||||
|
|
@ -140,6 +154,9 @@ static uint16_t probe_adcSample(void)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (guard >= 1000000UL) {
|
||||
probeAdcTimeouts++;
|
||||
}
|
||||
|
||||
return ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER0);
|
||||
}
|
||||
|
|
@ -191,7 +208,7 @@ static void probe_dumpPackedDcc(const char* tag, uint32_t base,
|
|||
}
|
||||
|
||||
|
||||
static void probe_dumpPackedAdc(uint32_t nbytes)
|
||||
static void probe_dumpPackedAdc(const char* tag, uint32_t nbytes)
|
||||
{
|
||||
uint32_t i;
|
||||
int b;
|
||||
|
|
@ -199,7 +216,7 @@ static void probe_dumpPackedAdc(uint32_t nbytes)
|
|||
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
if ((i % 32U) == 0U) {
|
||||
printf("\r\nE6 0 ");
|
||||
printf("\r\n%s 0 ", tag);
|
||||
}
|
||||
acc = 0U;
|
||||
for (b = 0; b < 8; b++) {
|
||||
|
|
@ -218,8 +235,10 @@ void entropy_probe_run(void)
|
|||
uint32_t i;
|
||||
|
||||
printf("\r\n=== ENTROPY PROBE ===\r\n");
|
||||
printf("SYSCLK %lu Hz, samples/config %d\r\n",
|
||||
(unsigned long)DEVICE_SYSCLK_FREQ, (int)PROBE_SAMPLES);
|
||||
/* %lu, not %d: int is 16 bits here and PROBE_PACKED_BYTES is 32768. */
|
||||
printf("SYSCLK %lu Hz, samples/config %lu, packed stream %lu octets\r\n",
|
||||
(unsigned long)DEVICE_SYSCLK_FREQ, (unsigned long)PROBE_SAMPLES,
|
||||
(unsigned long)PROBE_PACKED_BYTES);
|
||||
|
||||
probe_dccInit();
|
||||
probe_adcInit();
|
||||
|
|
@ -244,8 +263,11 @@ void entropy_probe_run(void)
|
|||
DCC_COUNT1SRC_PLL, 256UL, PROBE_PACKED_BYTES);
|
||||
probe_dumpPackedDcc("E5", DCC0_BASE, DCC_COUNT0SRC_INTOSC2,
|
||||
DCC_COUNT1SRC_PLL, 256UL, PROBE_PACKED_BYTES);
|
||||
probe_dumpPackedAdc(PROBE_PACKED_BYTES);
|
||||
probe_dumpPackedAdc("E6", PROBE_PACKED_BYTES);
|
||||
|
||||
printf("\r\nDCC errors %lu, DCC timeouts %lu, ADC timeouts %lu\r\n",
|
||||
(unsigned long)probeDccErrors, (unsigned long)probeDccTimeouts,
|
||||
(unsigned long)probeAdcTimeouts);
|
||||
printf("\r\nPROBE DONE\r\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@
|
|||
#endif
|
||||
#ifdef WOLF_ENTROPY
|
||||
#include <wolfssl/wolfcrypt/port/ti/ti-c2000-entropy.h>
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
#endif
|
||||
#ifdef WOLF_ENTROPY_PROBE
|
||||
#include "entropy_probe.h"
|
||||
#endif
|
||||
#ifdef WOLF_25519
|
||||
#include <wolfssl/wolfcrypt/curve25519.h>
|
||||
|
|
@ -978,7 +980,7 @@ static void wolf_mldsa87_verify_test(void)
|
|||
* signature that arrive PACKED verify once wc_UnpackOctets() expands them.
|
||||
* One key struct is shared - WOLFSSL_MLDSA_VERIFY_NO_MALLOC pins the verify
|
||||
* workspace inside it, far too big for the 16 KW C28x stack. */
|
||||
/* Static: an ML-DSA-65 signature is 3309 cells = 6618 octets of C28x RAM. */
|
||||
/* Static: an ML-DSA-65 signature is 3309 octets = 3309 cells = 6618 bytes. */
|
||||
static byte mo_pub[WC_MLDSA_65_PUB_KEY_SIZE];
|
||||
static byte mo_sig[WC_MLDSA_65_SIG_SIZE];
|
||||
static wc_MlDsaKey mo_key;
|
||||
|
|
@ -1030,12 +1032,23 @@ static void mo_pack_roundtrip(void)
|
|||
src[i] = (byte)((i * 7 + 1) & 0xFF);
|
||||
}
|
||||
ret = wc_PackOctets(packed, (word32)sizeof(packed), src,
|
||||
(word32)sizeof(src));
|
||||
(word32)sizeof(src), (word32)sizeof(src));
|
||||
if (ret == 0) {
|
||||
ret = wc_UnpackOctets(back, (word32)sizeof(back), packed,
|
||||
(word32)sizeof(src));
|
||||
(word32)sizeof(packed), (word32)sizeof(src));
|
||||
}
|
||||
/* Round-trip alone would also pass for an identity implementation, so
|
||||
* check the packed layout itself: cell 0 must carry the first
|
||||
* WC_OCTETS_PER_BYTE octets, low octet first. */
|
||||
ok = (ret == 0) && (XMEMCMP(src, back, sizeof(src)) == 0);
|
||||
if (ok) {
|
||||
word32 expect = 0;
|
||||
word32 e;
|
||||
for (e = 0; e < WC_OCTETS_PER_BYTE; e++) {
|
||||
expect |= (word32)src[e] << (8 * e);
|
||||
}
|
||||
ok = ((word32)packed[0] == expect);
|
||||
}
|
||||
printf("wc_Pack/UnpackOctets round-trip: %s (ret=%d)\r\n",
|
||||
ok ? "PASS" : "FAIL", ret);
|
||||
}
|
||||
|
|
@ -1047,10 +1060,16 @@ static void mo_packed_verify(void)
|
|||
int ret;
|
||||
|
||||
ret = wc_UnpackOctets(mo_pub, (word32)sizeof(mo_pub),
|
||||
(const byte*)kat_mldsa65_pub_packed, (word32)sizeof(mo_pub));
|
||||
(const byte*)kat_mldsa65_pub_packed,
|
||||
(word32)(sizeof(kat_mldsa65_pub_packed) /
|
||||
sizeof(kat_mldsa65_pub_packed[0])),
|
||||
(word32)sizeof(mo_pub));
|
||||
if (ret == 0) {
|
||||
ret = wc_UnpackOctets(mo_sig, (word32)sizeof(mo_sig),
|
||||
(const byte*)kat_mldsa65_sig_packed, (word32)sizeof(mo_sig));
|
||||
(const byte*)kat_mldsa65_sig_packed,
|
||||
(word32)(sizeof(kat_mldsa65_sig_packed) /
|
||||
sizeof(kat_mldsa65_sig_packed[0])),
|
||||
(word32)sizeof(mo_sig));
|
||||
}
|
||||
/* Expanded buffers must match the plain arrays octet for octet. */
|
||||
if (ret == 0) {
|
||||
|
|
@ -1098,8 +1117,9 @@ static void wolf_mldsa_octet_test(void)
|
|||
return;
|
||||
}
|
||||
|
||||
printf("octet model: CHAR_BIT=%d, %lu octet(s) per byte cell; "
|
||||
"ML-DSA-65 sig = %lu octets = %lu cells = %lu bytes of RAM\r\n",
|
||||
printf("octet model: CHAR_BIT=%d, one octet per byte cell, %lu octet(s) "
|
||||
"per cell when packed; ML-DSA-65 sig = %lu octets = %lu cells = "
|
||||
"%lu bytes of RAM\r\n",
|
||||
(int)CHAR_BIT, (unsigned long)WC_OCTETS_PER_BYTE,
|
||||
(unsigned long)WC_MLDSA_65_SIG_SIZE,
|
||||
(unsigned long)WC_MLDSA_65_SIG_SIZE,
|
||||
|
|
@ -1134,6 +1154,36 @@ static void wolf_mldsa_octet_test(void)
|
|||
kat_mldsa87_sig_ph512, (word32)sizeof(kat_mldsa87_sig_ph512),
|
||||
WC_HASH_TYPE_SHA512, sha512, (word32)sizeof(sha512));
|
||||
|
||||
/* Negative case: every check above is positive, so a verify that returned
|
||||
* success unconditionally - or a w1 encoder that collapsed distinct
|
||||
* commitments - would pass them all. Flip one octet of the level-44
|
||||
* signature and require a clean rejection. */
|
||||
{
|
||||
static byte bad[WC_MLDSA_44_SIG_SIZE];
|
||||
int bres = 1;
|
||||
int bret;
|
||||
|
||||
XMEMCPY(bad, kat_mldsa44_sig, sizeof(bad));
|
||||
bad[sizeof(bad) / 2] ^= 0x01;
|
||||
|
||||
bret = wc_MlDsaKey_Init(&mo_key, NULL, INVALID_DEVID);
|
||||
if (bret == 0) {
|
||||
bret = wc_MlDsaKey_SetParams(&mo_key, WC_ML_DSA_44);
|
||||
}
|
||||
if (bret == 0) {
|
||||
bret = wc_MlDsaKey_ImportPubRaw(&mo_key, kat_mldsa44_pub,
|
||||
(word32)sizeof(kat_mldsa44_pub));
|
||||
}
|
||||
if (bret == 0) {
|
||||
bret = wc_MlDsaKey_VerifyCtx(&mo_key, bad, (word32)sizeof(bad),
|
||||
NULL, 0, mo_msg, (word32)sizeof(mo_msg), &bres);
|
||||
}
|
||||
/* A corrupt signature must be rejected, not error out. */
|
||||
printf("ML-DSA-44 corrupted-signature reject: %s (ret=%d res=%d)\r\n",
|
||||
((bret == 0) && (bres == 0)) ? "PASS" : "FAIL", bret, bres);
|
||||
wc_MlDsaKey_Free(&mo_key);
|
||||
}
|
||||
|
||||
mo_packed_verify();
|
||||
}
|
||||
#endif /* WOLF_MLDSA_OCTETS */
|
||||
|
|
@ -1305,9 +1355,18 @@ static void wolf_entropy_test(void)
|
|||
printf("Entropy liveness self-test (raw): %s (ret=%d)\r\n",
|
||||
(ret == 0) ? "PASS" : "FAIL", ret);
|
||||
|
||||
/* Raw noise sanity per source: population count should sit near half. */
|
||||
for (src = 0; src < 2; src++) {
|
||||
/* Raw noise sanity per source: population count should sit near half.
|
||||
* Source 1 is optional - a build that needs DCC0 elsewhere sets
|
||||
* WOLFSSL_C2000_ENTROPY_NUM_SRC to 1. */
|
||||
for (src = 0; src < WOLFSSL_C2000_ENTROPY_NUM_SRC; src++) {
|
||||
ret = wc_c2000_Entropy_GetRaw(raw, (word32)sizeof(raw), src);
|
||||
if (ret != 0) {
|
||||
/* raw[] holds stale data on failure, so counting it would report a
|
||||
* meaningless balance. Report the read error instead. */
|
||||
printf("Entropy raw src%d bit balance: FAIL (read error %d)\r\n",
|
||||
src, ret);
|
||||
continue;
|
||||
}
|
||||
ones = 0;
|
||||
for (i = 0; i < (word32)sizeof(raw); i++) {
|
||||
for (b = 0; b < 8; b++) {
|
||||
|
|
@ -1319,7 +1378,7 @@ static void wolf_entropy_test(void)
|
|||
/* 2048 bits; accept 40%..60% ones, i.e. counts 820..1228. */
|
||||
printf("Entropy raw src%d bit balance: %s (%lu/2048 ones)\r\n",
|
||||
src,
|
||||
(ret == 0 && ones > 819UL && ones < 1229UL) ? "PASS" : "FAIL",
|
||||
(ones > 819UL && ones < 1229UL) ? "PASS" : "FAIL",
|
||||
(unsigned long)ones);
|
||||
}
|
||||
|
||||
|
|
@ -1378,6 +1437,17 @@ static void wolf_aes_test(void)
|
|||
static byte o[16], o2[16], tag[16];
|
||||
int r;
|
||||
|
||||
/* Must be initialised, and explicitly with INVALID_DEVID: a static Aes
|
||||
* zero-fills devId to 0, which is a valid device id, so with WOLF_CRYPTO_CB
|
||||
* built in (HWAES=1) every aes.c hook would attempt callback dispatch
|
||||
* instead of skipping. This is the software reference for the HW-vs-SW
|
||||
* cross-checks, so it must stay unambiguously software. */
|
||||
r = wc_AesInit(&aes, NULL, INVALID_DEVID);
|
||||
if (r != 0) {
|
||||
printf("AES software test: FAIL (init ret=%d)\r\n", r);
|
||||
return;
|
||||
}
|
||||
|
||||
/* CBC */
|
||||
r = wc_AesSetKey(&aes, k, 16, iv, AES_ENCRYPTION);
|
||||
if (r == 0) r = wc_AesCbcEncrypt(&aes, o, pt, 16);
|
||||
|
|
@ -1432,11 +1502,17 @@ static void wolf_aes_test(void)
|
|||
* NIST SP800-38A vectors are asserted where we have them; multi-block,
|
||||
* split-call and in-place cases are checked hardware-against-software, since
|
||||
* software AES is already covered by wolfcrypt_test. */
|
||||
/* Set only when the AESA device actually registered. Without it the 'hw'
|
||||
* context silently falls back to software and every cross-check would compare
|
||||
* software against software and report PASS. */
|
||||
static int g_aesaReady = 0;
|
||||
|
||||
static void hw_report(const char* name, int r, const byte* a, const byte* b,
|
||||
word32 len)
|
||||
{
|
||||
printf("HW %s: %s\r\n", name,
|
||||
(r == 0 && XMEMCMP(a, b, len) == 0) ? "PASS" : "FAIL");
|
||||
int cmp = XMEMCMP(a, b, len);
|
||||
printf("HW %s: %s (ret=%d cmp=%d)\r\n", name,
|
||||
(r == 0 && cmp == 0) ? "PASS" : "FAIL", r, cmp);
|
||||
}
|
||||
|
||||
static void wolf_aes_hw_test(void)
|
||||
|
|
@ -1494,9 +1570,20 @@ static void wolf_aes_hw_test(void)
|
|||
static byte oh[64], os[64], dh[64];
|
||||
int rh, rs;
|
||||
|
||||
if (wc_AesInit(&hw, NULL, WOLFSSL_C2000_DEVID) != 0 ||
|
||||
wc_AesInit(&sw, NULL, INVALID_DEVID) != 0) {
|
||||
printf("HW AES init: FAIL\r\n");
|
||||
if (!g_aesaReady) {
|
||||
printf("HW AES cross-checks: SKIP (AESA not registered)\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
rh = wc_AesInit(&hw, NULL, WOLFSSL_C2000_DEVID);
|
||||
if (rh != 0) {
|
||||
printf("HW AES init (hw ctx): FAIL (ret=%d)\r\n", rh);
|
||||
return;
|
||||
}
|
||||
rs = wc_AesInit(&sw, NULL, INVALID_DEVID);
|
||||
if (rs != 0) {
|
||||
printf("HW AES init (sw ctx): FAIL (ret=%d)\r\n", rs);
|
||||
wc_AesFree(&hw);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1506,7 +1593,7 @@ static void wolf_aes_hw_test(void)
|
|||
if (rh == 0) rh = wc_AesEcbEncrypt(&hw, oh, pt, 64);
|
||||
if (rs == 0) rs = wc_AesEcbEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-128-ECB encrypt vs NIST", rh, oh, ecb_ct1, 16);
|
||||
hw_report("AES-128-ECB encrypt vs SW", (rh | rs), oh, os, 64);
|
||||
hw_report("AES-128-ECB encrypt vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
rh = wc_AesSetKey(&hw, k128, 16, NULL, AES_DECRYPTION);
|
||||
if (rh == 0) rh = wc_AesEcbDecrypt(&hw, dh, oh, 64);
|
||||
|
|
@ -1518,7 +1605,7 @@ static void wolf_aes_hw_test(void)
|
|||
if (rh == 0) rh = wc_AesCbcEncrypt(&hw, oh, pt, 64);
|
||||
if (rs == 0) rs = wc_AesCbcEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-128-CBC encrypt vs NIST", rh, oh, cbc_ct1, 16);
|
||||
hw_report("AES-128-CBC encrypt vs SW", (rh | rs), oh, os, 64);
|
||||
hw_report("AES-128-CBC encrypt vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
rh = wc_AesSetKey(&hw, k128, 16, iv, AES_DECRYPTION);
|
||||
if (rh == 0) rh = wc_AesCbcDecrypt(&hw, dh, oh, 64);
|
||||
|
|
@ -1528,7 +1615,7 @@ static void wolf_aes_hw_test(void)
|
|||
rh = wc_AesSetKey(&hw, k128, 16, iv, AES_ENCRYPTION);
|
||||
if (rh == 0) rh = wc_AesCbcEncrypt(&hw, oh, pt, 16);
|
||||
if (rh == 0) rh = wc_AesCbcEncrypt(&hw, oh + 16, pt + 16, 48);
|
||||
hw_report("AES-128-CBC split-call chain", (rh | rs), oh, os, 64);
|
||||
hw_report("AES-128-CBC split-call chain", rh, oh, os, 64);
|
||||
|
||||
/* ---- CBC in-place decrypt: proves the last-block save ---- */
|
||||
XMEMCPY(dh, os, 64);
|
||||
|
|
@ -1543,26 +1630,53 @@ static void wolf_aes_hw_test(void)
|
|||
if (rs == 0) rs = wc_AesCtrEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-128-CTR vs NIST (64B)", rh, oh, ctr_ct, 64);
|
||||
hw_report("AES-128-CTR SW vs NIST (64B)", rs, os, ctr_ct, 64);
|
||||
hw_report("AES-128-CTR vs SW", (rh | rs), oh, os, 64);
|
||||
hw_report("AES-128-CTR vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
/* ---- CTR split at a non-block boundary: proves aes->left/aes->tmp ---- */
|
||||
rh = wc_AesSetKey(&hw, k128, 16, ctr_iv, AES_ENCRYPTION);
|
||||
if (rh == 0) rh = wc_AesCtrEncrypt(&hw, oh, pt, 10);
|
||||
if (rh == 0) rh = wc_AesCtrEncrypt(&hw, oh + 10, pt + 10, 54);
|
||||
hw_report("AES-128-CTR partial split", (rh | rs), oh, os, 64);
|
||||
hw_report("AES-128-CTR partial split", rh, oh, os, 64);
|
||||
|
||||
/* ---- 192- and 256-bit keys: the 6- and 8-word AES_setKey1 paths ---- */
|
||||
rh = wc_AesSetKey(&hw, k192, 24, iv, AES_ENCRYPTION);
|
||||
rs = wc_AesSetKey(&sw, k192, 24, iv, AES_ENCRYPTION);
|
||||
if (rh == 0) rh = wc_AesCbcEncrypt(&hw, oh, pt, 64);
|
||||
if (rs == 0) rs = wc_AesCbcEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-192-CBC encrypt vs SW", (rh | rs), oh, os, 64);
|
||||
hw_report("AES-192-CBC encrypt vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
rh = wc_AesSetKey(&hw, k256, 32, iv, AES_ENCRYPTION);
|
||||
rs = wc_AesSetKey(&sw, k256, 32, iv, AES_ENCRYPTION);
|
||||
if (rh == 0) rh = wc_AesCbcEncrypt(&hw, oh, pt, 64);
|
||||
if (rs == 0) rs = wc_AesCbcEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-256-CBC encrypt vs SW", (rh | rs), oh, os, 64);
|
||||
hw_report("AES-256-CBC encrypt vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
/* ECB and CTR at 192/256 too: the accelerator's key schedule differs per
|
||||
* key size, and marshalling the longer schedule into its 32-bit registers
|
||||
* is exactly the octet handling this port is validating. */
|
||||
rh = wc_AesSetKey(&hw, k192, 24, NULL, AES_ENCRYPTION);
|
||||
rs = wc_AesSetKey(&sw, k192, 24, NULL, AES_ENCRYPTION);
|
||||
if (rh == 0) rh = wc_AesEcbEncrypt(&hw, oh, pt, 64);
|
||||
if (rs == 0) rs = wc_AesEcbEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-192-ECB encrypt vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
rh = wc_AesSetKey(&hw, k256, 32, NULL, AES_ENCRYPTION);
|
||||
rs = wc_AesSetKey(&sw, k256, 32, NULL, AES_ENCRYPTION);
|
||||
if (rh == 0) rh = wc_AesEcbEncrypt(&hw, oh, pt, 64);
|
||||
if (rs == 0) rs = wc_AesEcbEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-256-ECB encrypt vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
rh = wc_AesSetKey(&hw, k192, 24, ctr_iv, AES_ENCRYPTION);
|
||||
rs = wc_AesSetKey(&sw, k192, 24, ctr_iv, AES_ENCRYPTION);
|
||||
if (rh == 0) rh = wc_AesCtrEncrypt(&hw, oh, pt, 64);
|
||||
if (rs == 0) rs = wc_AesCtrEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-192-CTR encrypt vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
rh = wc_AesSetKey(&hw, k256, 32, ctr_iv, AES_ENCRYPTION);
|
||||
rs = wc_AesSetKey(&sw, k256, 32, ctr_iv, AES_ENCRYPTION);
|
||||
if (rh == 0) rh = wc_AesCtrEncrypt(&hw, oh, pt, 64);
|
||||
if (rs == 0) rs = wc_AesCtrEncrypt(&sw, os, pt, 64);
|
||||
hw_report("AES-256-CTR encrypt vs SW", ((rh != 0) ? rh : rs), oh, os, 64);
|
||||
|
||||
wc_AesFree(&hw);
|
||||
wc_AesFree(&sw);
|
||||
|
|
@ -1964,12 +2078,13 @@ static void wolf_aes_modes_test(void)
|
|||
#ifdef WOLFSSL_AES_OFB
|
||||
{
|
||||
static Aes oaes;
|
||||
r = wc_AesSetKey(&oaes, mk, 16, miv, AES_ENCRYPTION);
|
||||
r = wc_AesInit(&oaes, NULL, INVALID_DEVID);
|
||||
if (r == 0) r = wc_AesSetKey(&oaes, mk, 16, miv, AES_ENCRYPTION);
|
||||
if (r == 0) r = wc_AesOfbEncrypt(&oaes, mct, mpt, 32);
|
||||
if (r == 0) r = wc_AesSetKey(&oaes, mk, 16, miv, AES_ENCRYPTION);
|
||||
if (r == 0) r = wc_AesOfbDecrypt(&oaes, mdec, mct, 32);
|
||||
printf("AES-128-OFB round-trip: %s\r\n",
|
||||
(r == 0 && XMEMCMP(mdec, mpt, 32) == 0) ? "PASS":"FAIL");
|
||||
printf("AES-128-OFB round-trip: %s (ret=%d)\r\n",
|
||||
(r == 0 && XMEMCMP(mdec, mpt, 32) == 0) ? "PASS":"FAIL", r);
|
||||
wc_AesFree(&oaes);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -2147,12 +2262,12 @@ int main(void)
|
|||
printf("=== wolfSSL wolfCrypt on TI C2000 LAUNCHXL-F28P55X ===\r\n");
|
||||
|
||||
#ifdef WOLF_ENTROPY_PROBE
|
||||
/* Measurement-only image: dump raw entropy samples and stop. */
|
||||
{
|
||||
extern void entropy_probe_run(void);
|
||||
entropy_probe_run();
|
||||
}
|
||||
while (1) {
|
||||
/* Measurement-only image: dump raw entropy samples and stop. Nothing
|
||||
* after this runs, which is why the Makefile rejects combining
|
||||
* ENTROPY_PROBE=1 with the other image toggles. */
|
||||
entropy_probe_run();
|
||||
for (;;) {
|
||||
/* spin */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -2173,6 +2288,7 @@ int main(void)
|
|||
}
|
||||
else {
|
||||
printf("C2000 AESA init: PASS\r\n");
|
||||
g_aesaReady = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ an upper bound, and low measured correlation is what makes it a reasonable one.
|
|||
Usage:
|
||||
python3 tools/entropy_analyze.py capture.log
|
||||
python3 tools/entropy_analyze.py --selftest
|
||||
tail -f /tmp/uart-monitor/latest/ttyACMx.log | python3 tools/entropy_analyze.py -
|
||||
"""
|
||||
|
||||
import math
|
||||
|
|
@ -56,15 +55,22 @@ RAW = OrderedDict((
|
|||
))
|
||||
|
||||
BANNER = "=== ENTROPY PROBE ==="
|
||||
# The probe reports how many samples were taken after a DCC ERROR flag or a
|
||||
# guard-loop timeout. Any nonzero count means the capture is not pure noise.
|
||||
HEALTH_RE = re.compile(r"DCC errors (\d+), DCC timeouts (\d+), "
|
||||
r"ADC timeouts (\d+)")
|
||||
DONE = "PROBE DONE"
|
||||
MAX_LAG = 64
|
||||
# Below this the MCV bound is too wide to be worth reporting.
|
||||
MIN_PACKED_OCTETS = 256
|
||||
Z_99 = 2.5758293035489004 # two-sided 99% normal quantile
|
||||
|
||||
|
||||
def first_pass(text):
|
||||
"""The board loops main(), so the probe output repeats. Return just the
|
||||
first complete pass, so a long capture does not silently concatenate
|
||||
several runs into one sample set."""
|
||||
"""Return just the first complete probe pass. The probe image runs once
|
||||
and then spins, so a normal capture holds one pass - but a capture that
|
||||
spans a reset or a re-flash would otherwise concatenate several runs into
|
||||
one sample set."""
|
||||
start = text.find(BANNER)
|
||||
if start < 0:
|
||||
return text
|
||||
|
|
@ -77,21 +83,41 @@ def first_pass(text):
|
|||
|
||||
|
||||
def parse(text):
|
||||
"""tag -> list of ints, in emission order."""
|
||||
"""Returns (out, per_window).
|
||||
|
||||
out tag -> list of ints, in emission order (all windows merged).
|
||||
per_window tag -> {window: [ints]}.
|
||||
|
||||
The raw DCC tags are emitted once per sweep window (256/1024/4096), and a
|
||||
count scales with the window, so merging them would mix populations of
|
||||
different magnitude. The packed streams the min-entropy estimate uses are
|
||||
emitted once, at a single window, so out[] is correct for those."""
|
||||
out = {}
|
||||
per_window = {}
|
||||
# A console line is "<tag> <window> <hex> <hex> ...". Match per line, and
|
||||
# never across a newline: the tags and window counts are themselves valid
|
||||
# hex, so a multi-line match would swallow the next line's header as data.
|
||||
# Tolerate any timestamp or prefix a log wrapper put ahead of the tag.
|
||||
line_re = re.compile(r"\b(E[0-9])[^\S\n]+(\d+)[^\S\n]+"
|
||||
r"((?:[0-9a-fA-F]+[^\S\n]*)+)$")
|
||||
skipped = 0
|
||||
for line in text.splitlines():
|
||||
m = line_re.search(line.rstrip())
|
||||
line = line.rstrip()
|
||||
m = line_re.search(line)
|
||||
if m is None:
|
||||
# A line that starts with a probe tag but does not parse means a
|
||||
# corrupted capture, not unrelated console output - say so.
|
||||
if re.match(r"\s*E[0-9]\b", line):
|
||||
skipped += 1
|
||||
continue
|
||||
out.setdefault(m.group(1), []).extend(
|
||||
int(t, 16) for t in m.group(3).split())
|
||||
return out
|
||||
vals = [int(t, 16) for t in m.group(3).split()]
|
||||
out.setdefault(m.group(1), []).extend(vals)
|
||||
per_window.setdefault(m.group(1), {}).setdefault(
|
||||
int(m.group(2)), []).extend(vals)
|
||||
if skipped:
|
||||
sys.stderr.write("warning: %d probe line(s) did not parse - capture may "
|
||||
"be corrupted or truncated\n" % skipped)
|
||||
return out, per_window
|
||||
|
||||
|
||||
def unpack_bits(octets):
|
||||
|
|
@ -266,7 +292,16 @@ def main():
|
|||
with open(path, errors="replace") as f:
|
||||
text = f.read()
|
||||
|
||||
data = parse(first_pass(text))
|
||||
health = HEALTH_RE.search(text)
|
||||
if health is None:
|
||||
sys.stderr.write("warning: no probe health line - old probe image, or "
|
||||
"the capture is truncated\n")
|
||||
elif any(int(g) for g in health.groups()):
|
||||
sys.exit("probe reported %s DCC errors, %s DCC timeouts, %s ADC "
|
||||
"timeouts - these samples are not noise, reject the capture"
|
||||
% health.groups())
|
||||
|
||||
data, per_window = parse(first_pass(text))
|
||||
if not data:
|
||||
sys.exit("no probe tags found - is this an ENTROPY_PROBE=1 capture?")
|
||||
|
||||
|
|
@ -276,6 +311,10 @@ def main():
|
|||
if not octets:
|
||||
sys.stderr.write("warning: no %s samples (%s)\n" % (tag, label))
|
||||
continue
|
||||
if len(octets) < MIN_PACKED_OCTETS:
|
||||
sys.stderr.write("warning: %s has only %d octets (< %d) - the "
|
||||
"min-entropy estimate will be unreliable\n"
|
||||
% (tag, len(octets), MIN_PACKED_OCTETS))
|
||||
bad = [v for v in octets if v > 0xFF]
|
||||
if bad:
|
||||
sys.exit("%s: %d values exceed one octet - capture is corrupt"
|
||||
|
|
@ -283,11 +322,15 @@ def main():
|
|||
rows.append(report(tag, label, octets))
|
||||
|
||||
for tag, label in RAW.items():
|
||||
vals = data.get(tag)
|
||||
if vals:
|
||||
a = np.asarray(vals, dtype=np.int64)
|
||||
print("%s %s: %d samples, min %d max %d mean %.1f, "
|
||||
"%d distinct" % (tag, label, len(a), a.min(), a.max(),
|
||||
wins = per_window.get(tag)
|
||||
if not wins:
|
||||
continue
|
||||
# Per window: a raw count scales with the window, so pooling them
|
||||
# would report a spread that is an artifact of the sweep.
|
||||
for win in sorted(wins):
|
||||
a = np.asarray(wins[win], dtype=np.int64)
|
||||
print("%s %s [window %d]: %d samples, min %d max %d mean %.1f, "
|
||||
"%d distinct" % (tag, label, win, len(a), a.min(), a.max(),
|
||||
a.mean(), len(np.unique(a))))
|
||||
print()
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include <wolfssl/wolfcrypt/sha512.h>
|
||||
#include <wolfssl/wolfcrypt/hash.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MSG_SZ 512
|
||||
#define OUT_NAME "mldsa_octet_kat.h"
|
||||
|
|
@ -167,17 +166,25 @@ int main(void)
|
|||
for (i = 0; i < MSG_SZ; i++)
|
||||
msg[i] = (byte)(i & 0xFF);
|
||||
|
||||
ret = wolfCrypt_Init();
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "wolfCrypt_Init failed: %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = wc_Sha256Hash(msg, MSG_SZ, sha256);
|
||||
if (ret == 0)
|
||||
ret = wc_Sha512Hash(msg, MSG_SZ, sha512);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "hash failed: %d\n", ret);
|
||||
wolfCrypt_Cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
out = fopen(OUT_NAME, "w");
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "cannot open output\n");
|
||||
wolfCrypt_Cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +212,9 @@ int main(void)
|
|||
if (ret != 0) {
|
||||
/* Do not leave a truncated header behind for the build to pick up. */
|
||||
remove(OUT_NAME);
|
||||
wolfCrypt_Cleanup();
|
||||
return 1;
|
||||
}
|
||||
wolfCrypt_Cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue