From 27f4804c185ae24b3b6367bb2fdb898d6692d0f6 Mon Sep 17 00:00:00 2001 From: bg Date: Wed, 20 Jun 2012 21:58:55 +0000 Subject: [PATCH] new skipjack test --- Makefile_en21_conf.inc | 2 + bigint/bigint.c | 282 ++++++++++++++++++---------- bigint/bigint.h | 9 +- hmac-sha1/hmac-sha1.c | 10 +- host/bigint_test.rb | 3 +- host/get_test.rb | 5 +- host/nessie_check.rb | 6 +- rsa/rsa_basic.c | 10 +- rsa/rsa_basic.h | 4 +- sha1/sha1.c | 4 +- sha1/sha1.h | 6 +- shacal1/shacal1_enc.c | 2 +- test_src/circularbytebuffer-asm.S | 22 ++- test_src/circularbytebuffer.h | 44 ++++- test_src/cli-hexdump.S | 18 +- test_src/main-aes-test.c | 25 +-- test_src/main-arcfour-test.c | 28 ++- test_src/main-des-test.c | 57 +++--- test_src/main-present-test.c | 28 +-- test_src/main-rsaes_oaep-test.c | 5 +- test_src/main-rsaes_pkcs1v15-test.c | 4 +- test_src/main-skipjack-test.c | 50 +++++ test_src/uart_i-asm.S | 78 ++++---- testvectors/skipjack_tv.pdf | Bin 0 -> 33927 bytes 24 files changed, 433 insertions(+), 269 deletions(-) create mode 100644 testvectors/skipjack_tv.pdf diff --git a/Makefile_en21_conf.inc b/Makefile_en21_conf.inc index 66f3ef9..bbdeeb2 100644 --- a/Makefile_en21_conf.inc +++ b/Makefile_en21_conf.inc @@ -5,6 +5,8 @@ OPTIMIZE = -Os # -Os EXTRALINK = xram.o DEFS = -D$(call uc, $(MCU_TARGET)) -DF_CPU=$(F_CPU) BOARD_NAME = ethernut2.1 +FLASHCMD = /bin/bash openocd_flash.sh # +RESETCMD = override CFLAGS_A = -MMD -MF$(DEP_DIR)$(patsubst %.o,%.d,$(notdir $(1))) $(DEBUG) $(WARNING) -std=$(CSTD) $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) override CFLAGS = -MMD -MF$(DEP_DIR)$(patsubst %.o,%.d,$(notdir $@)) $(DEBUG) $(WARNING) -std=$(CSTD) $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) diff --git a/bigint/bigint.c b/bigint/bigint.c index c69d42e..3c0bb53 100644 --- a/bigint/bigint.c +++ b/bigint/bigint.c @@ -53,9 +53,9 @@ #define SET_NEG(a) (a)->info |= BIGINT_NEG_MASK #define SET_POS(a) (a)->info &= ~BIGINT_NEG_MASK #define XCHG(a,b) do{(a)^=(b); (b)^=(a); (a)^=(b);}while(0) -#define XCHG_PTR(a,b) do{ a = (void*)(((bigint_ptr_int_t)(a)) ^ ((bigint_ptr_int_t)(b))); \ - b = (void*)(((bigint_ptr_int_t)(a)) ^ ((bigint_ptr_int_t)(b))); \ - a = (void*)(((bigint_ptr_int_t)(a)) ^ ((bigint_ptr_int_t)(b)));}while(0) +#define XCHG_PTR(a,b) do{ a = (void*)(((intptr_t)(a)) ^ ((intptr_t)(b))); \ + b = (void*)(((intptr_t)(a)) ^ ((intptr_t)(b))); \ + a = (void*)(((intptr_t)(a)) ^ ((intptr_t)(b)));}while(0) #define GET_SIGN(a) ((a)->info&BIGINT_NEG_MASK) @@ -80,7 +80,7 @@ void bigint_adjust(bigint_t* a){ /******************************************************************************/ -uint16_t bigint_length_b(bigint_t* a){ +uint16_t bigint_length_b(const bigint_t* a){ if(!a->length_B || a->length_B==0){ return 0; } @@ -89,13 +89,13 @@ uint16_t bigint_length_b(bigint_t* a){ /******************************************************************************/ -uint16_t bigint_length_B(bigint_t* a){ +uint16_t bigint_length_B(const bigint_t* a){ return a->length_B * sizeof(bigint_word_t); } /******************************************************************************/ -uint32_t bigint_get_first_set_bit(bigint_t* a){ +uint32_t bigint_get_first_set_bit(const bigint_t* a){ if(a->length_B==0){ return (uint32_t)(-1); } @@ -105,7 +105,7 @@ uint32_t bigint_get_first_set_bit(bigint_t* a){ /******************************************************************************/ -uint32_t bigint_get_last_set_bit(bigint_t* a){ +uint32_t bigint_get_last_set_bit(const bigint_t* a){ uint32_t r=0; uint8_t b=0; bigint_word_t x=1; @@ -138,23 +138,24 @@ void bigint_copy(bigint_t* dest, const bigint_t* src){ /* this should be implemented in assembly */ void bigint_add_u(bigint_t* dest, const bigint_t* a, const bigint_t* b){ uint16_t i; - bigint_wordplus_t t=0LL; + bigint_wordplus_t t = 0LL; if(a->length_B < b->length_B){ XCHG_PTR(a,b); } - for(i=0; ilength_B; ++i){ -// t = (bigint_wordplus_t)(a->wordv[i]) + (bigint_wordplus_t)(b->wordv[i]) + t; + for(i = 0; i < b->length_B; ++i){ t += a->wordv[i]; t += b->wordv[i]; dest->wordv[i] = (bigint_word_t)t; - t>>=BIGINT_WORD_SIZE; + t >>= BIGINT_WORD_SIZE; } - for(; ilength_B; ++i){ + for(; i < a->length_B; ++i){ t += a->wordv[i]; dest->wordv[i] = (bigint_word_t)t; - t>>=BIGINT_WORD_SIZE; + t >>= BIGINT_WORD_SIZE; + } + if(t){ + dest->wordv[i++] = (bigint_word_t)t; } - dest->wordv[i++] = (bigint_word_t)t; dest->length_B = i; bigint_adjust(dest); } @@ -163,20 +164,66 @@ void bigint_add_u(bigint_t* dest, const bigint_t* a, const bigint_t* b){ /* this should be implemented in assembly */ void bigint_add_scale_u(bigint_t* dest, const bigint_t* a, uint16_t scale){ - bigint_t x; + if(a->length_B == 0){ + return; + } + if(scale == 0){ + bigint_add_u(dest, dest, a); + return; + } +#if DEBUG_ADD_SCALE + cli_putstr_P(PSTR("\r\nDBG: bigint_add_scale(")); + bigint_print_hex(dest); + cli_putc(','); + bigint_print_hex(dest); + cli_putc(','); + cli_hexdump_rev(&scale, 2); + cli_putc(')'); +#endif #if BIGINT_WORD_SIZE == 8 - memset(dest->wordv + dest->length_B, 0, MAX(dest->length_B, a->length_B + scale) - dest->length_B); - x.wordv = dest->wordv + scale; + if(scale >= dest->length_B){ +#if DEBUG_ADD_SCALE + cli_putstr_P(PSTR("\r\n\tpath one")); +#endif + memset(dest->wordv + dest->length_B, 0, scale - dest->length_B); + memcpy(dest->wordv + scale, a->wordv, a->length_B); + dest->info = a->info; + dest->length_B = a->length_B + scale; + return; + } + bigint_t x; +#if DEBUG_ADD_SCALE + cli_putstr_P(PSTR("\r\n\tpath two")); +#endif x.length_B = dest->length_B - scale; - if((int16_t)x.length_B < 0) - x.length_B = 0; x.info = dest->info; + x.wordv = dest->wordv + scale; bigint_add_u(&x, &x, a); dest->length_B = x.length_B + scale; dest->info = 0; bigint_adjust(dest); #else -#error unimplemented! + bigint_t s; + uint16_t word_shift = scale / sizeof(bigint_word_t), byte_shift = scale % sizeof(bigint_word_t); + bigint_word_t bv[a->length_B + 1]; + s.wordv = bv; + bv[0] = bv[a->length_B] = 0; + memcpy((uint8_t*)bv + byte_shift, a->wordv, a->length_B * sizeof(bigint_word_t)); + s.length_B = a->length_B + 1; + bigint_adjust(&s); + memset(dest->wordv + dest->length_B, 0, (MAX(dest->length_B, s.length_B + word_shift) - dest->length_B) * sizeof(bigint_word_t)); + x.wordv = dest->wordv + word_shift; + x.length_B = dest->length_B - word_shift; + if((int16_t)x.length_B < 0){ + x.length_B = 0; + x.info = 0; + }else{ + x.info = dest->info; + } + bigint_add_u(&x, &x, &s); + dest->length_B = x.length_B + word_shift; + dest->info = 0; + bigint_adjust(dest); #endif @@ -220,9 +267,7 @@ void bigint_sub_u(bigint_t* dest, const bigint_t* a, const bigint_t* b){ int8_t borrow=0; int8_t r; bigint_wordplus_signed_t t=0LL; - uint16_t i, min, max; - min = MIN(a->length_B, b->length_B); - max = MAX(a->length_B, b->length_B); + uint16_t i; r = bigint_cmp_u(a,b); if(r==0){ bigint_set_zero(dest); @@ -243,9 +288,9 @@ void bigint_sub_u(bigint_t* dest, const bigint_t* a, const bigint_t* b){ SET_NEG(dest); return; } - for(i=0; ilength_B; ++i){ t = a->wordv[i]; - if(ilength_B){ t -= b->wordv[i]; } t -= borrow; @@ -291,34 +336,26 @@ int8_t bigint_cmp_u(const bigint_t* a, const bigint_t* b){ void bigint_add_s(bigint_t* dest, const bigint_t* a, const bigint_t* b){ uint8_t s; - int8_t d = 0; s = GET_SIGN(a)?2:0; s |= GET_SIGN(b)?1:0; switch(s){ case 0: /* both positive */ - d = 1; bigint_add_u(dest, a,b); + SET_POS(dest); break; case 1: /* a positive, b negative */ - d = bigint_cmp_u(a,b); bigint_sub_u(dest, a, b); break; case 2: /* a negative, b positive */ - d = bigint_cmp_u(b,a); bigint_sub_u(dest, b, a); break; case 3: /* both negative */ - d = -1; bigint_add_u(dest, a, b); + SET_NEG(dest); break; default: /* how can this happen?*/ break; } - if(d<0){ - SET_NEG(dest); - }else{ - SET_POS(dest); - } } /******************************************************************************/ @@ -379,35 +416,33 @@ int8_t bigint_cmp_s(const bigint_t* a, const bigint_t* b){ /******************************************************************************/ void bigint_shiftleft(bigint_t* a, uint16_t shift){ - uint16_t byteshift, word_alloc; + uint16_t byteshift, words_to_shift; int16_t i; uint8_t bitshift; bigint_word_t *p; bigint_wordplus_t t=0; - if(shift==0){ + if(shift == 0){ return; } - byteshift = shift/8; - bitshift = shift&7; - for(i=0;i<=byteshift/sizeof(bigint_word_t); ++i){ - a->wordv[a->length_B+i] = 0; - } + byteshift = shift / 8; + bitshift = shift & 7; + memset(&a->wordv[a->length_B], 0x00, byteshift); if(byteshift){ - memmove(((uint8_t*)a->wordv)+byteshift, a->wordv, a->length_B*sizeof(bigint_word_t)); + memmove(((uint8_t*)a->wordv)+byteshift, a->wordv, a->length_B * sizeof(bigint_word_t)); memset(a->wordv, 0, byteshift); } - p = (bigint_word_t*)(((uint8_t*)a->wordv)+byteshift); - word_alloc = a->length_B+(byteshift+sizeof(bigint_word_t)-1)/sizeof(bigint_word_t)+1; - a->wordv[word_alloc-1]=0; - if(bitshift!=0){ - for(i=0; ilength_B; ++i){ - t |= ((bigint_wordplus_t)p[i])<wordv + byteshift / sizeof(bigint_word_t)); + words_to_shift = a->length_B + ((byteshift % sizeof(bigint_word_t))?1:0); + /* XXX */ + for(i = 0; i < words_to_shift; ++i){ + t |= ((bigint_wordplus_t)p[i]) << bitshift; p[i] = (bigint_word_t)t; t >>= BIGINT_WORD_SIZE; } p[i] = (bigint_word_t)t; } - a->length_B = word_alloc; + a->length_B += (shift + BIGINT_WORD_SIZE - 1) / BIGINT_WORD_SIZE; bigint_adjust(a); } @@ -420,30 +455,29 @@ void bigint_shiftright(bigint_t* a, uint16_t shift){ bigint_wordplus_t t=0; byteshift = shift/8; bitshift = shift&7; - if(byteshift >= a->length_B*sizeof(bigint_word_t)){ /* we would shift out more than we have */ + if(byteshift >= a->length_B * sizeof(bigint_word_t)){ /* we would shift out more than we have */ bigint_set_zero(a); return; } - if(byteshift == a->length_B*sizeof(bigint_word_t)-1 && bitshift>GET_FBS(a)){ + if(byteshift == a->length_B * sizeof(bigint_word_t) - 1 && bitshift > GET_FBS(a)){ bigint_set_zero(a); return; } if(byteshift){ - memmove(a->wordv, (uint8_t*)a->wordv+byteshift, a->length_B-byteshift); - memset((uint8_t*)a->wordv+a->length_B-byteshift, 0, byteshift); + memmove(a->wordv, (uint8_t*)a->wordv + byteshift, a->length_B * sizeof(bigint_word_t) - byteshift); + memset((uint8_t*)a->wordv + a->length_B * sizeof(bigint_word_t) - byteshift, 0, byteshift); } byteshift /= sizeof(bigint_word_t); - if(bitshift!=0){ + a->length_B -= (byteshift + sizeof(bigint_word_t) - 1) / sizeof(bigint_word_t); + if(bitshift != 0 && a->length_B){ /* shift to the right */ - for(i=a->length_B-byteshift-1; i>0; --i){ - t |= ((bigint_wordplus_t)(a->wordv[i]))<<(BIGINT_WORD_SIZE-bitshift); - a->wordv[i] = (bigint_word_t)(t>>BIGINT_WORD_SIZE); + i = a->length_B - 1; + do{ + t |= ((bigint_wordplus_t)(a->wordv[i])) << (BIGINT_WORD_SIZE - bitshift); + a->wordv[i] = (bigint_word_t)(t >> BIGINT_WORD_SIZE); t <<= BIGINT_WORD_SIZE; - } - t |= ((bigint_wordplus_t)(a->wordv[0]))<<(BIGINT_WORD_SIZE-bitshift); - a->wordv[0] = (bigint_word_t)(t>>BIGINT_WORD_SIZE); + }while(i--); } - a->length_B -= ((shift/8)+sizeof(bigint_word_t)-1)/sizeof(bigint_word_t); bigint_adjust(a); } @@ -474,21 +508,21 @@ void bigint_mul_u(bigint_t* dest, const bigint_t* a, const bigint_t* b){ } if(dest==a || dest==b){ bigint_t d; - bigint_word_t d_b[a->length_B+b->length_B]; + bigint_word_t d_b[a->length_B + b->length_B]; d.wordv = d_b; bigint_mul_u(&d, a, b); bigint_copy(dest, &d); return; } if(a->length_B==1 || b->length_B==1){ - if(a->length_B!=1){ + if(a->length_B != 1){ XCHG_PTR(a,b); } bigint_wordplus_t t=0; uint16_t i; bigint_word_t x = a->wordv[0]; for(i=0; i < b->length_B; ++i){ - t += ((bigint_wordplus_t)b->wordv[i])*((bigint_wordplus_t)x); + t += ((bigint_wordplus_t)b->wordv[i]) * ((bigint_wordplus_t)x); dest->wordv[i] = (bigint_word_t)t; t>>=BIGINT_WORD_SIZE; } @@ -508,30 +542,57 @@ void bigint_mul_u(bigint_t* dest, const bigint_t* a, const bigint_t* b){ bigint_adjust(dest); return; } - bigint_set_zero(dest); +#if BIGINT_WORD_SIZE == 8 + if(a->length_B <= 4 || b->length_B <= 4){ + if(a->length_B > 4){ + XCHG_PTR(a,b); + } + uint32_t x = 0, y = 0; + uint16_t j = b->length_B / 4, idx = 0; + uint64_t r = 0; + memcpy(&x, a->wordv, a->length_B); + while(j){ + r += (uint64_t)((uint32_t*)b->wordv)[idx] * (uint64_t)x; + ((uint32_t*)dest->wordv)[idx] = (uint32_t)r; + r >>= 32; + ++idx; + --j; + } + idx *= 4; + memcpy(&y, b->wordv + idx, b->length_B - idx); + r += (uint64_t)y * (uint64_t)x; + while(r){ + dest->wordv[idx++] = (uint8_t)r; + r >>= 8; + } + dest->length_B = idx; + bigint_adjust(dest); + return; + } +#endif /* split a in xh & xl; split b in yh & yl */ const uint16_t n = (MAX(a->length_B, b->length_B)+1)/2; bigint_t xl, xh, yl, yh; xl.wordv = a->wordv; yl.wordv = b->wordv; - if(a->length_B<=n){ + if(a->length_B <= n){ bigint_set_zero(&xh); xl.length_B = a->length_B; xl.info = a->info; }else{ - xl.length_B=n; + xl.length_B = n; xl.info = 0; bigint_adjust(&xl); xh.wordv = &(a->wordv[n]); xh.length_B = a->length_B-n; xh.info = a->info; } - if(b->length_B<=n){ + if(b->length_B <= n){ bigint_set_zero(&yh); yl.length_B = b->length_B; yl.info = b->info; }else{ - yl.length_B=n; + yl.length_B = n; yl.info = 0; bigint_adjust(&yl); yh.wordv = &(b->wordv[n]); @@ -540,24 +601,39 @@ void bigint_mul_u(bigint_t* dest, const bigint_t* a, const bigint_t* b){ } /* now we have split up a and b */ /* remember we want to do: - * x*y = (xh*yh)*b**2n + ((xh+xl)*(yh+yl) - xh*yh - xl*yl)*b**n + yh*yl + * x*y = (xh * b ** n + xl) * (yh * b ** n + yl) + * x*y = (xh*yh)*b**2n + ((xh+xl)*(yh+yl) - xh*yh - xl*yl)*b**n + xl*yl * 5 9 2 4 3 7 5 6 1 8 1 */ - bigint_word_t tmp_b[2*n+2], m_b[2*(n+1)]; - bigint_t tmp, tmp2, m; - tmp.wordv = tmp_b; - tmp2.wordv = &(tmp_b[n+1]); - m.wordv = m_b; - - bigint_mul_u(dest, &xl, &yl); /* 1: dest <= xl*yl */ - bigint_add_u(&tmp2, &xh, &xl); /* 2: tmp2 <= xh+xl */ - bigint_add_u(&tmp, &yh, &yl); /* 3: tmp <= yh+yl */ - bigint_mul_u(&m, &tmp2, &tmp); /* 4: m <= tmp2*tmp */ - bigint_mul_u(&tmp, &xh, &yh); /* 5: h <= xh*yh */ - bigint_sub_u(&m, &m, dest); /* 6: m <= m-dest */ - bigint_sub_u(&m, &m, &tmp); /* 7: m <= m-h */ - bigint_add_scale_u(dest, &m, n*sizeof(bigint_word_t)); /* 8: dest <= dest+m**n*/ - bigint_add_scale_u(dest, &tmp, 2*n*sizeof(bigint_word_t)); /* 9: dest <= dest+tmp**(2*n) */ + bigint_word_t tmp1_b[n*2+2]; + bigint_t tmp1, tmp2; + tmp1.wordv = tmp1_b; + tmp2.wordv = &tmp1_b[n+1]; + + bigint_add_u(&tmp2, &xh, &xl); /* 2: tmp2 <= xh + xl */ + bigint_add_u(&tmp1, &yh, &yl); /* 3: tmp1 <= yh + yl */ + bigint_mul_u(dest, &tmp2, &tmp1); /* 4: dest <= tmp2 * tmp1 */ + bigint_mul_u(&tmp1, &xh, &yh); /* 5: tmp1 <= xh * yh */ + bigint_sub_u(dest, dest, &tmp1); /* 7: dest <= dest - tmp1 */ + bigint_word_t tmp3_b[2*n]; + tmp2.wordv = tmp3_b; + bigint_mul_u(&tmp2, &xl, &yl); /* 1: tmp3 <= xl * yl */ + bigint_sub_u(dest, dest, &tmp2); /* 6: dest <= dest - tmp3 */ + bigint_shiftleft(dest, n * sizeof(bigint_word_t) * 8); + bigint_add_u(dest, dest, &tmp2); /* 8: dest <= tmp3 + dest ** n */ + bigint_add_scale_u(dest, &tmp1, 2*n*sizeof(bigint_word_t)); /* 9: dest <= dest + tmp1 ** (2 * n) */ + +#if 0 + bigint_mul_u(dest, &xl, &yl); /* 1: dest <= xl * yl */ + bigint_add_u(&tmp2, &xh, &xl); /* 2: tmp2 <= xh + xl */ + bigint_add_u(&tmp1, &yh, &yl); /* 3: tmp1 <= yh + yl */ + bigint_mul_u(&tmp3, &tmp2, &tmp1); /* 4: tmp3 <= tmp2 * tmp1 */ + bigint_mul_u(&tmp1, &xh, &yh); /* 5: h <= xh * yh */ + bigint_sub_u(&tmp3, &tmp3, dest); /* 6: tmp3 <= tmp3 - dest */ + bigint_sub_u(&tmp3, &tmp3, &tmp1); /* 7: tmp3 <= tmp3 - h */ + bigint_add_scale_u(dest, &tmp3, n*sizeof(bigint_word_t)); /* 8: dest <= dest + tmp3 ** n */ + bigint_add_scale_u(dest, &tmp1, 2*n*sizeof(bigint_word_t)); /* 9: dest <= dest + tmp1 ** (2 * n) */ +#endif } /******************************************************************************/ @@ -593,36 +669,35 @@ void bigint_mul_s(bigint_t* dest, const bigint_t* a, const bigint_t* b){ /* square */ /* (xh*b^n+xl)^2 = xh^2*b^2n + 2*xh*xl*b^n + xl^2 */ void bigint_square(bigint_t* dest, const bigint_t* a){ - if(a->length_B*sizeof(bigint_word_t)<=4){ - uint64_t r=0; - memcpy(&r, a->wordv, a->length_B*sizeof(bigint_word_t)); - r = r*r; - memcpy(dest->wordv, &r, 2*a->length_B*sizeof(bigint_word_t)); + if(a->length_B * sizeof(bigint_word_t) <= 4){ + uint64_t r = 0; + memcpy(&r, a->wordv, a->length_B * sizeof(bigint_word_t)); + r = r * r; + memcpy(dest->wordv, &r, 2 * a->length_B*sizeof(bigint_word_t)); SET_POS(dest); - dest->length_B=2*a->length_B; + dest->length_B = 2 * a->length_B; bigint_adjust(dest); return; } if(dest==a){ bigint_t d; - bigint_word_t d_b[a->length_B*2]; + bigint_word_t d_b[a->length_B * 2]; d.wordv = d_b; bigint_square(&d, a); bigint_copy(dest, &d); return; } uint16_t n; - n=(a->length_B+1)/2; + n = (a->length_B + 1) / 2; bigint_t xh, xl, tmp; /* x-high, x-low, temp */ - bigint_word_t buffer[2*n+1]; + bigint_word_t buffer[2 * n + 1]; xl.wordv = a->wordv; xl.length_B = n; xl.info = 0; xh.wordv = &(a->wordv[n]); - xh.length_B = a->length_B-n; - xh.info = 0; + xh.length_B = a->length_B - n; + xh.info = a->info; bigint_adjust(&xl); - bigint_adjust(&xh); tmp.wordv = buffer; /* (xh * b**n + xl)**2 = xh**2 * b**2n + 2 * xh * xl * b**n + xl**2 */ @@ -632,7 +707,7 @@ void bigint_square(bigint_t* dest, const bigint_t* a){ // cli_putstr("\r\nDBG (1): xl**2: "); bigint_print_hex(dest); bigint_square(&tmp, &xh); // cli_putstr("\r\nDBG (2): xh**2: "); bigint_print_hex(&tmp); - bigint_add_scale_u(dest, &tmp, 2*n*sizeof(bigint_word_t)); + bigint_add_scale_u(dest, &tmp, 2 * n * sizeof(bigint_word_t)); // cli_putstr("\r\nDBG (3): xl**2 + xh**2*n**2: "); bigint_print_hex(dest); bigint_mul_u(&tmp, &xl, &xh); // cli_putstr("\r\nDBG (4): xl*xh: "); bigint_print_hex(&tmp); @@ -660,11 +735,14 @@ void bigint_sub_u_bitscale(bigint_t* a, const bigint_t* b, uint16_t bitscale){ bigint_copy(&tmp, b); bigint_shiftleft(&tmp, bitscale % BIGINT_WORD_SIZE); +// cli_putstr_P(PSTR("\r\nDBG: shifted value: ")); bigint_print_hex(&tmp); + x.info = a->info; x.wordv = &(a->wordv[word_shift]); x.length_B = a->length_B - word_shift; bigint_sub_u(&x, &x, &tmp); + a->length_B = x.length_B + word_shift; bigint_adjust(a); return; } @@ -712,14 +790,16 @@ void bigint_reduce(bigint_t* a, const bigint_t* r){ } while((GET_FBS(a) > rfbs) && (a->length_B == r->length_B)){ shift = GET_FBS(a)-rfbs-1; +// cli_putstr("\r\nDBG: (2a) = "); bigint_print_hex(a); // cli_putstr("\r\nDBG: (q) shift = "); cli_hexdump_rev(&shift, 2); bigint_sub_u_bitscale(a, r, shift); -// cli_putstr("\r\nDBG: (2) = "); bigint_print_hex(a); +// cli_putstr("\r\nDBG: (2b) = "); bigint_print_hex(a); } while(bigint_cmp_u(a,r)>=0){ bigint_sub_u(a,a,r); // cli_putstr("\r\nDBG: (3) = "); bigint_print_hex(a); } +// cli_putc(' '); bigint_adjust(a); // cli_putstr("\r\nDBG: (a) = "); bigint_print_hex(a); // cli_putstr("\r\n"); @@ -932,7 +1012,7 @@ void bigint_inverse(bigint_t* dest, const bigint_t* a, const bigint_t* m){ void bigint_changeendianess(bigint_t* a){ uint8_t t, *p, *q; p = (uint8_t*)(a->wordv); - q = ((uint8_t*)p)+a->length_B*sizeof(bigint_word_t)-1; + q = p + a->length_B * sizeof(bigint_word_t) - 1; while(p=SHA1_BLOCK_BITS){ - sha1_nextBlock(&(s->a), block); + sha1_nextBlock(&s->a, block); block = (uint8_t*)block + SHA1_BLOCK_BYTES; length_b -= SHA1_BLOCK_BITS; } - sha1_lastBlock(&(s->a), block, length_b); + sha1_lastBlock(&s->a, block, length_b); } void hmac_sha1_final(void* dest, hmac_sha1_ctx_t *s){ - sha1_ctx2hash((sha1_hash_t*)dest, &(s->a)); - sha1_lastBlock(&(s->b), dest, SHA1_HASH_BITS); - sha1_ctx2hash((sha1_hash_t*)dest, &(s->b)); + sha1_ctx2hash(dest, &s->a); + sha1_lastBlock(&s->b, dest, SHA1_HASH_BITS); + sha1_ctx2hash(dest, &(s->b)); } #endif diff --git a/host/bigint_test.rb b/host/bigint_test.rb index d942b37..25a9f0c 100644 --- a/host/bigint_test.rb +++ b/host/bigint_test.rb @@ -412,6 +412,7 @@ end def expmod_test(a,b,c) begin + printf("[testing] expmod(%#x, %#x, %#x)\n",a,b,c) if $debug line = $sp.gets() line = "" if line==nil puts("DBG got: "+line) if $debug @@ -848,7 +849,7 @@ if File.exists?(logfilename) end $logfile = File.open(logfilename, 'w') printf("logfile: %s\n", logfilename) - +$logfile.sync = true $logfile.printf("bigint test from: %s\n", Time.now.to_s) $logfile.printf("skip = %s\n", opts['s']) if opts['s'] $logfile.printf("seed = 0x%X\n", 0xdeadbeef) diff --git a/host/get_test.rb b/host/get_test.rb index df16955..3c88cfd 100644 --- a/host/get_test.rb +++ b/host/get_test.rb @@ -22,6 +22,7 @@ require 'rubygems' require 'serialport' $debug = false +$progress_dots = false def read_line(error_msg=true) begin @@ -34,7 +35,7 @@ def read_line(error_msg=true) puts("ERROR: read timeout!\n") if error_msg return nil end - putc('.') if s.include?(6.chr) + putc('.') if s.include?(6.chr) && $progress_dots puts(s.inspect) if $debug end while s == 6.chr s.gsub(/\006/, '') @@ -124,7 +125,7 @@ puts("\nPort: "+ARGV[0]+ "@"+ARGV[1]+" "+ARGV[2]+"N"+ARGV[3]+"\n"); $linewidth = 16 $sp = SerialPort.new(ARGV[0], ARGV[1].to_i, ARGV[2].to_i, ARGV[3].to_i, SerialPort::NONE); $sp.read_timeout=1000; # 1 second -$extended_wait=10; +$extended_wait=100000; $sp.write(command); if(readTestVector(param)==false) diff --git a/host/nessie_check.rb b/host/nessie_check.rb index d2ed46a..cea8925 100644 --- a/host/nessie_check.rb +++ b/host/nessie_check.rb @@ -18,6 +18,8 @@ along with this program. If not, see . =end +$debug = true + def skip_header(file) begin l = file.gets().strip @@ -89,8 +91,8 @@ def compare(fname1, fname2) end if(a!=b and a!=nil and b!=nil) $error += 1 -# puts("a key: "+a[0]+" value: "+a[1]) -# puts("b key: "+b[0]+" value: "+b[1]) + puts("a key: "+a[0]+" value: "+a[1]) if $debug + puts("b key: "+b[0]+" value: "+b[1]) if $debug end end until a==nil or b==nil end diff --git a/rsa/rsa_basic.c b/rsa/rsa_basic.c index 0c69753..49e0919 100644 --- a/rsa/rsa_basic.c +++ b/rsa/rsa_basic.c @@ -30,7 +30,7 @@ #include "cli.h" #endif -void rsa_enc(bigint_t* data, rsa_publickey_t* key){ +void rsa_enc(bigint_t* data, const rsa_publickey_t* key){ /* cli_putstr_P(PSTR("\r\n -->rsa_enc()\r\n m = ")); bigint_print_hex(data); @@ -50,10 +50,10 @@ h = (m1 - m2) * qinv % p m = m2 + q * h */ -uint8_t rsa_dec_crt_mono(bigint_t* data, rsa_privatekey_t* key){ +uint8_t rsa_dec_crt_mono(bigint_t* data, const rsa_privatekey_t* key){ bigint_t m1, m2; - m1.wordv = malloc((key->components[0].length_B + 1) * sizeof(bigint_word_t)); - m2.wordv = malloc((key->components[1].length_B + 1) * sizeof(bigint_word_t)); + m1.wordv = malloc((key->components[0].length_B /* + 1 */) * sizeof(bigint_word_t)); + m2.wordv = malloc((key->components[1].length_B /* + 1 */) * sizeof(bigint_word_t)); if(!m1.wordv || !m2.wordv){ #if DEBUG cli_putstr_P(PSTR("\r\nERROR: OOM!")); @@ -160,7 +160,7 @@ uint8_t rsa_dec_crt_mono(bigint_t* data, rsa_privatekey_t* key){ return 0; } -uint8_t rsa_dec(bigint_t* data, rsa_privatekey_t* key){ +uint8_t rsa_dec(bigint_t* data, const rsa_privatekey_t* key){ if(key->n == 1){ bigint_expmod_u(data, data, &(key->components[0]), &key->modulus); return 0; diff --git a/rsa/rsa_basic.h b/rsa/rsa_basic.h index 54854a6..3146540 100644 --- a/rsa/rsa_basic.h +++ b/rsa/rsa_basic.h @@ -40,8 +40,8 @@ typedef struct { } rsa_fullkey_t; -void rsa_enc(bigint_t* data, rsa_publickey_t* key); -uint8_t rsa_dec(bigint_t* data, rsa_privatekey_t* key); +void rsa_enc(bigint_t* data, const rsa_publickey_t* key); +uint8_t rsa_dec(bigint_t* data, const rsa_privatekey_t* key); void rsa_os2ip(bigint_t* dest, const void* data, uint32_t length_B); void rsa_i2osp(void* dest, bigint_t* src, uint16_t* out_length_B); diff --git a/sha1/sha1.c b/sha1/sha1.c index df448d1..2e22b8e 100644 --- a/sha1/sha1.c +++ b/sha1/sha1.c @@ -207,7 +207,7 @@ void sha1_lastBlock(sha1_ctx_t *state, const void* block, uint16_t length){ /********************************************************************************************************/ -void sha1_ctx2hash (sha1_hash_t *dest, sha1_ctx_t *state){ +void sha1_ctx2hash (void *dest, sha1_ctx_t *state){ #if defined LITTLE_ENDIAN uint8_t i; for(i=0; i<5; ++i){ @@ -226,7 +226,7 @@ void sha1_ctx2hash (sha1_hash_t *dest, sha1_ctx_t *state){ * * */ -void sha1 (sha1_hash_t *dest, const void* msg, uint32_t length){ +void sha1 (void *dest, const void* msg, uint32_t length){ sha1_ctx_t s; DEBUG_S("\r\nBLA BLUB"); sha1_init(&s); diff --git a/sha1/sha1.h b/sha1/sha1.h index 6675d20..1966786 100644 --- a/sha1/sha1.h +++ b/sha1/sha1.h @@ -65,7 +65,9 @@ typedef struct { * \brief hash value type * A variable of this type may hold a SHA-1 hash value */ +/* typedef uint8_t sha1_hash_t[SHA1_HASH_BITS/8]; +*/ /** \fn sha1_init(sha1_ctx_t *state) * \brief initializes a SHA-1 context @@ -100,7 +102,7 @@ void sha1_lastBlock (sha1_ctx_t *state, const void* block, uint16_t length_b); * \param dest pointer to the hash value destination * \param state pointer to the hash context */ -void sha1_ctx2hash (sha1_hash_t *dest, sha1_ctx_t *state); +void sha1_ctx2hash (void *dest, sha1_ctx_t *state); /** \fn sha1(sha1_hash_t *dest, const void* msg, uint32_t length_b) * \brief hashing a message which in located entirely in RAM @@ -110,7 +112,7 @@ void sha1_ctx2hash (sha1_hash_t *dest, sha1_ctx_t *state); * \param msg pointer to the message which should be hashed * \param length_b length of the message in bits */ -void sha1(sha1_hash_t *dest, const void* msg, uint32_t length_b); +void sha1(void *dest, const void* msg, uint32_t length_b); diff --git a/shacal1/shacal1_enc.c b/shacal1/shacal1_enc.c index 634f18d..87e5d45 100644 --- a/shacal1/shacal1_enc.c +++ b/shacal1/shacal1_enc.c @@ -43,7 +43,7 @@ void shacal1_enc(void* buffer, void* key, uint16_t keysize_b){ memcpy(keybuffer, key, (keysize_b+7)/8); memcpy(t_ctx.h, buffer, SHA1_HASH_BITS/8); - sha1_ctx2hash((sha1_hash_t*)(&(ctx.h[0])), &t_ctx); + sha1_ctx2hash(&ctx.h[0], &t_ctx); memcpy(t_ctx.h, ctx.h, SHA1_HASH_BITS/8); sha1_nextBlock(&ctx, keybuffer); for(i=0; i<5; ++i) diff --git a/test_src/circularbytebuffer-asm.S b/test_src/circularbytebuffer-asm.S index f76cebe..199c86a 100644 --- a/test_src/circularbytebuffer-asm.S +++ b/test_src/circularbytebuffer-asm.S @@ -287,6 +287,7 @@ circularbytebuffer_append: ldd r23, Z+BUFFER_SIZE_OFFSET cp r22, r23 brne 10f +5: ldi r24, 1 ret 10: @@ -343,14 +344,15 @@ circularbytebuffer_push: ldd r22, Z+FILLCOUNT_OFFSET ldd r23, Z+BUFFER_SIZE_OFFSET cp r22, r23 - brne 10f - ldi r24, 1 - ret + brlo 10f + rjmp 5b +; ldi r24, 1 +; ret 10: - clt - tst r22 - brne 11f - set +; clt +; tst r22 +; brne 11f +; set 11: inc r22 std Z+FILLCOUNT_OFFSET, r22 @@ -368,7 +370,7 @@ circularbytebuffer_push: 20: std Z+HEAD_OFFSET, r26 std Z+HEAD_OFFSET+1, r27 - brtc 30b - std Z+TAIL_OFFSET, r26 - std Z+TAIL_OFFSET+1, r27 +; brtc 30b +; std Z+TAIL_OFFSET, r26 +; std Z+TAIL_OFFSET+1, r27 rjmp 30b diff --git a/test_src/circularbytebuffer.h b/test_src/circularbytebuffer.h index d1e40e4..9f29003 100644 --- a/test_src/circularbytebuffer.h +++ b/test_src/circularbytebuffer.h @@ -19,36 +19,59 @@ /** * \file circularbytebuffer.h * \email daniel.otte@rub.de - * \author Daniel Otte + * \author Daniel Otte * \date 2009-07-24 * \license GPLv3 or later - * \ingroup circularbytebuffer + * \addtogroup circularbytebuffer * \brief declaration for circular byte buffer */ - +/*@{*/ #ifndef CIRCULARBYTEBUFFER_H_ #define CIRCULARBYTEBUFFER_H_ #include #include #include "config.h" - + /** + * \brief type holding the managment information for the buffer + * + * A variable of this type may hold all the information to control the buffer + */ typedef struct { - uint8_t buffer_size; - uint8_t fillcount; - uint8_t* buffer; - uint8_t* head; - uint8_t* tail; - uint8_t* top; + uint8_t buffer_size; /**< holds the amount of bytes which may be stored in the buffer */ + uint8_t fillcount; /**< holds the amount of bytes actually stored in the buffer */ + uint8_t* buffer; /**< pointer to the actual buffer */ + uint8_t* head; /**< pointer to the head of the buffer */ + uint8_t* tail; /**< pointer to the tail of the buffer */ + uint8_t* top; /**< pointer to the last free address in the buffer */ } circularbytebuffer_t; #if CIRCULARBYTEBUFFER_NO_MALLOC==0 +/** \brief buffer initialisation with automatic allocation + * + * This function initializes the given buffer context and allocates memory for + * it by calling malloc. + * \param buffersize size of the buffer to allocate + * \param cb buffer context to be initialized + */ uint8_t circularbytebuffer_init(uint8_t buffersize, circularbytebuffer_t* cb); #endif #if CIRCULARBYTEBUFFER_NO_INIT2==0 +/** \brief buffer initialisation without automatic allocation + * + * This function initializes the given buffer context and uses the given buffer + * for storage, so no malloc is needed. + * \param buffersize size of the buffer + * \param cb buffer context to be initialized + * \param buffer buffer for the storage of data (you are responisble for allocation and freeing) + */ void circularbytebuffer_init2(uint8_t buffersize, circularbytebuffer_t* cb, void* buffer); #endif +/** \brief + * + * + */ uint16_t circularbytebuffer_get_lifo(circularbytebuffer_t* cb); uint16_t circularbytebuffer_get_fifo(circularbytebuffer_t* cb); uint8_t circularbytebuffer_append(uint8_t, circularbytebuffer_t* cb); @@ -56,4 +79,5 @@ uint8_t circularbytebuffer_push(uint8_t, circularbytebuffer_t* cb); uint8_t circularbytebuffer_cnt(circularbytebuffer_t* cb); void circularbytebuffer_free(circularbytebuffer_t* cb); +/*@}*/ #endif /* CIRCULARBYTEBUFFER_H_ */ diff --git a/test_src/cli-hexdump.S b/test_src/cli-hexdump.S index ce151b9..032f59b 100644 --- a/test_src/cli-hexdump.S +++ b/test_src/cli-hexdump.S @@ -142,11 +142,9 @@ LENG_1 = 17 .global cli_hexdump_block cli_hexdump_block: - tst r22 - brne 1f - tst r23 - brne 1f - ret + movw r26, r22 + adiw r26, 0 + breq simple_ret 1: push WIDTH push INDENT @@ -160,16 +158,16 @@ cli_hexdump_block: movw DATA_0, r24 movw LENG_0, r22 2: - clr r25 +; clr r25 ldi r24, '\r' rcall cli_putc - clr r25 +; clr r25 ldi r24, '\n' rcall cli_putc mov r4, INDENT tst r4 breq 4f -3: clr r25 +3:; clr r25 ldi r24, ' ' rcall cli_putc dec r4 @@ -181,8 +179,7 @@ cli_hexdump_block: tst LENG_1 brne 7f cp WIDTH, LENG_0 - breq 6f - brcs 7f + brlo 7f mov r22, LENG_0 6: inc r4 7: @@ -200,6 +197,7 @@ cli_hexdump_block: pop DATA_0 pop INDENT pop WIDTH +simple_ret: ret diff --git a/test_src/main-aes-test.c b/test_src/main-aes-test.c index e7b2071..71d7bef 100644 --- a/test_src/main-aes-test.c +++ b/test_src/main-aes-test.c @@ -20,15 +20,9 @@ * AES test-suit * */ - -#include "config.h" - -#include "uart_i.h" -#include "debug.h" - +#include "main-test-common.h" #include "aes.h" -#include "cli.h" #include "performance_test.h" #include "dump.h" @@ -46,11 +40,6 @@ #include "bcal-performance.h" #include "bcal-nessie.h" -#include -#include -#include -#include - const char* algo_name = "AES"; const bcdesc_t* const const algolist[] PROGMEM = { @@ -718,4 +707,16 @@ int main (void){ cmd_interface(cmdlist); } } +int main(void) { + main_setup(); + + cmacvs_algolist=(bcdesc_t**)algolist; + cmacvs_algo=(bcdesc_t*)&aes128_desc; + + for(;;){ + welcome_msg(algo_name); + cmd_interface(cmdlist); + } + +} diff --git a/test_src/main-arcfour-test.c b/test_src/main-arcfour-test.c index 9228188..30801f8 100644 --- a/test_src/main-arcfour-test.c +++ b/test_src/main-arcfour-test.c @@ -21,23 +21,16 @@ * */ -#include "config.h" -#include "uart_i.h" -#include "debug.h" +#include "main-test-common.h" #include -#include "cli.h" #include "performance_test.h" #include "scal_arcfour.h" #include "scal-basic.h" #include "scal-nessie.h" -#include -#include -#include - char* algo_name = "Arcfour"; /***************************************************************************** @@ -97,16 +90,17 @@ const cmdlist_entry_t cmdlist[] PROGMEM = { { NULL, NULL, NULL} }; -int main (void){ - DEBUG_INIT(); - - cli_rx = (cli_rx_fpt)uart0_getc; - cli_tx = (cli_tx_fpt)uart0_putc; +int main(void) { + main_setup(); + + shavs_algolist=(hfdesc_t**)algolist; + shavs_algo=(hfdesc_t*)&sha256_desc; + for(;;){ - cli_putstr_P(PSTR("\r\n\r\nCrypto-VS (")); - cli_putstr(algo_name); - cli_putstr_P(PSTR(")\r\nloaded and running\r\n")); + welcome_msg(algo_name); cmd_interface(cmdlist); - } + } + } + diff --git a/test_src/main-des-test.c b/test_src/main-des-test.c index c1ef54f..d85a830 100644 --- a/test_src/main-des-test.c +++ b/test_src/main-des-test.c @@ -21,13 +21,9 @@ * */ -#include "config.h" - -#include "uart_i.h" -#include "debug.h" +#include "main-test-common.h" #include "des.h" -#include "cli.h" #include "performance_test.h" #include "bcal-performance.h" #include "bcal-nessie.h" @@ -35,10 +31,6 @@ #include "bcal_tdes.h" #include "bcal_tdes2.h" -#include -#include -#include - char* algo_name = "DES"; const bcdesc_t* const algolist[] PROGMEM = { @@ -51,8 +43,31 @@ const bcdesc_t* const algolist[] PROGMEM = { * additional validation-functions * *****************************************************************************/ -void testrun_nessie_des(void){ - bcal_nessie_multiple(algolist); +void testrun_nessie_des(const char* param){ + if(!param){ + bcal_nessie_multiple(algolist); + }else{ + uint8_t i=0; + bcdesc_t* ptr; + for(;;){ + ptr = (bcdesc_t*)pgm_read_word(&algolist[i++]); + if(ptr == NULL){ + cli_putstr_P(PSTR("\r\nunknown algorithm: ")); + cli_putstr(param); + cli_putstr_P(PSTR("\r\navailable algorithms are:")); + i = 0; + while((ptr = (bcdesc_t*)pgm_read_word(&algolist[i++]))){ + cli_putstr_P(PSTR("\r\n\t")); + cli_putstr_P((const char*)pgm_read_word(&ptr->name)); + } + return; + } + if(!strcmp_P(param, (const char*)pgm_read_word(&ptr->name))){ + bcal_nessie(ptr); + return; + } + } + } } void testrun_performance_des(void){ @@ -68,22 +83,20 @@ const char performance_str[] PROGMEM = "performance"; const char echo_str[] PROGMEM = "echo"; const cmdlist_entry_t cmdlist[] PROGMEM = { - { nessie_str, NULL, testrun_nessie_des }, - { test_str, NULL, testrun_nessie_des }, + { nessie_str, (void*)1, (void_fpt)testrun_nessie_des }, + { test_str, (void*)1, (void_fpt)testrun_nessie_des }, { performance_str, NULL, testrun_performance_des}, { echo_str, (void*)1, (void_fpt)echo_ctrl}, { NULL, NULL, NULL} }; -int main (void){ - DEBUG_INIT(); - - cli_rx = (cli_rx_fpt)uart0_getc; - cli_tx = (cli_tx_fpt)uart0_putc; +int main(void) { + main_setup(); + for(;;){ - cli_putstr_P(PSTR("\r\n\r\nCrypto-VS (")); - cli_putstr(algo_name); - cli_putstr_P(PSTR(")\r\nloaded and running\r\n")); + welcome_msg(algo_name); cmd_interface(cmdlist); - } + } + } + diff --git a/test_src/main-present-test.c b/test_src/main-present-test.c index 442e142..3a08c12 100644 --- a/test_src/main-present-test.c +++ b/test_src/main-present-test.c @@ -21,24 +21,16 @@ * */ -#include "config.h" - -#include "uart_i.h" -#include "debug.h" +#include "main-test-common.h" #include #include -#include "cli.h" #include "performance_test.h" #include "bcal-performance.h" #include "bcal-nessie.h" #include "bcal_present80.h" #include "bcal_present128.h" -#include -#include -#include - char* algo_name = "Present"; const bcdesc_t* const algolist[] PROGMEM = { @@ -146,15 +138,15 @@ const cmdlist_entry_t cmdlist[] PROGMEM = { { NULL, NULL, NULL} }; -int main (void){ - DEBUG_INIT(); - - cli_rx = (cli_rx_fpt)uart0_getc; - cli_tx = (cli_tx_fpt)uart0_putc; +int main(void) { + main_setup(); + + shavs_algolist=(hfdesc_t**)algolist; + shavs_algo=(hfdesc_t*)&sha256_desc; + for(;;){ - cli_putstr_P(PSTR("\r\n\r\nCrypto-VS (")); - cli_putstr(algo_name); - cli_putstr_P(PSTR(")\r\nloaded and running\r\n")); + welcome_msg(algo_name); cmd_interface(cmdlist); - } + } + } diff --git a/test_src/main-rsaes_oaep-test.c b/test_src/main-rsaes_oaep-test.c index 26cb449..53a6c22 100644 --- a/test_src/main-rsaes_oaep-test.c +++ b/test_src/main-rsaes_oaep-test.c @@ -531,12 +531,15 @@ void quick_test(void){ uint8_t *ciphertext, *plaintext, rc; uint8_t seed[sizeof(SEED)]; uint16_t clen, plen; + if(!keys_allocated){ + load_fix_rsa(); + } ciphertext = malloc(clen = pub_key.modulus.length_B * sizeof(bigint_word_t)); plaintext = malloc(pub_key.modulus.length_B * sizeof(bigint_word_t)); memcpy_P(plaintext, MSG, sizeof(MSG)); memcpy_P(seed, SEED, sizeof(SEED)); cli_putstr_P(PSTR("\r\nplaintext:")); - cli_hexdump_block(plaintext, sizeof(MSG), 4, 8); + cli_hexdump_block(plaintext, sizeof(MSG), 4, 16); cli_putstr_P(PSTR("\r\nencrypting: ...")); rc = rsa_encrypt_oaep(ciphertext, &clen, plaintext, sizeof(MSG), &pub_key, NULL, NULL, seed); if(rc){ diff --git a/test_src/main-rsaes_pkcs1v15-test.c b/test_src/main-rsaes_pkcs1v15-test.c index a5a3a88..00f12ed 100644 --- a/test_src/main-rsaes_pkcs1v15-test.c +++ b/test_src/main-rsaes_pkcs1v15-test.c @@ -32,7 +32,7 @@ #include "performance_test.h" -#define DEBUG 0 +#define DEBUG 1 const char* algo_name = "RSAES-PKCS1V15"; @@ -663,7 +663,7 @@ void run_seed_test(void){ cli_putstr_P(PSTR("\r\nERROR: OOM!")); return; } - msg_ = malloc(bigint_length_B(&pub_key.modulus) + sizeof(bigint_word_t)); + msg_ = malloc(bigint_length_B(&pub_key.modulus) /* + sizeof(bigint_word_t) */ ); #if DEBUG cli_putstr_P(PSTR("\r\nDBG: @msg_: 0x")); cli_hexdump_rev(&msg_, 2); diff --git a/test_src/main-skipjack-test.c b/test_src/main-skipjack-test.c index e3f68f5..48de3cf 100644 --- a/test_src/main-skipjack-test.c +++ b/test_src/main-skipjack-test.c @@ -61,6 +61,54 @@ void testrun_performance_skipjack(void){ bcal_performance_multiple(algolist); } +int test_enc(const void* buffer, void* key){ + uint8_t data[8]; + int r; + memcpy(data, buffer, 8); + skipjack_enc(data, key); + cli_putstr_P(PSTR(" key = ")); + cli_hexdump(key, 10); + cli_putstr_P(PSTR(" plaintext = ")); + cli_hexdump(buffer, 8); + cli_putstr_P(PSTR(" ciphertext = ")); + cli_hexdump(data, 8); + skipjack_dec(data, key); + r = memcmp(data, buffer, 8); + cli_putstr_P(PSTR(" decrypt: ")); + if(r){ + cli_putstr_P(PSTR("fail")); + }else{ + cli_putstr_P(PSTR("ok")); + } + return r; +} + +void testrun_nist_vectors(void){ + uint8_t key[10]; + uint8_t data[8]; + uint8_t i; + + cli_putstr_P(PSTR("\r\n\r\n=== NIST vectors run 1 ===")); + memset(key, 0, 10); + for(i=0; i<64; ++i){ + memset(data, 0, 8); + data[i>>3] |= 0x80 >> (i & 7); + cli_putstr_P(PSTR("\r\n round: 0x")); + cli_hexdump_byte(i); + test_enc(data, key); + } + + cli_putstr_P(PSTR("\r\n\r\n=== NIST vectors run 2 ===")); + memset(data, 0, 8); + for(i=0; i<80; ++i){ + memset(key, 0, 10); + key[i>>3] |= 0x80 >> (i & 7); + cli_putstr_P(PSTR("\r\n round: 0x")); + cli_hexdump_byte(i); + test_enc(data, key); + } +} + /***************************************************************************** * self tests * *****************************************************************************/ @@ -113,12 +161,14 @@ void testrun_skipjack(void){ const char nessie_str[] PROGMEM = "nessie"; const char test_str[] PROGMEM = "test"; +const char nist_str[] PROGMEM = "nist"; const char performance_str[] PROGMEM = "performance"; const char echo_str[] PROGMEM = "echo"; const cmdlist_entry_t cmdlist[] PROGMEM = { { nessie_str, NULL, testrun_nessie_skipjack}, { test_str, NULL, testrun_skipjack}, + { nist_str, NULL, testrun_nist_vectors}, { performance_str, NULL, testrun_performance_skipjack}, { echo_str, (void*)1, (void_fpt)echo_ctrl}, { NULL, NULL, NULL} diff --git a/test_src/uart_i-asm.S b/test_src/uart_i-asm.S index ebd9663..be0aee6 100644 --- a/test_src/uart_i-asm.S +++ b/test_src/uart_i-asm.S @@ -294,10 +294,7 @@ uart0_putc: ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET) ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET) 20: -; sei movw r24, r26 -; nop -; nop cli rcall circularbytebuffer_cnt sei @@ -308,9 +305,8 @@ uart0_putc: clr r25 cli rcall circularbytebuffer_append - sei SET_BIT_IO UCSR0B, UDRIE0, r24 - ret + reti /******************************************************************************/ /* @@ -364,19 +360,48 @@ uart0_putc: clr r1 LOAD_IO r24, UDR0 #if UART0_SWFLOWCTRL - ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET) + ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET) ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET) cpi r24, XON_VALUE - brne 10f - ldi r24, 1 - st X, r24 - rjmp 99f -10: + breq 11f cpi r24, XOFF_VALUE - brne 20f + brne 12f clr r24 - st X, r24 +11: st X, r24 rjmp 99f +12: + push r24 +/* now the "sending" part*/ + ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET) + ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET) + rcall circularbytebuffer_cnt + ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET) + ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET) + ld r18, Z + tst r18 + breq 15f/* branch if rxon inactive -> we had send an XOFF earlier */ + /* ok, we did not have send an XOFF, should we? */ + cpi r24, UART0_THRESH_HIGH + brlo 90f /* ok, nothing critical, go on */ + st Z, r1 + ldi r24, XOFF_VALUE +; sbi _SFR_IO_ADDR(PORTD), 5 + rjmp 16f +15: + cpi r24, UART0_THRESH_LOW + brsh 90f /* nothing has changed */ + /* if we get here, we had send an XOFF and are now below threshold */ + /* so we sen an XON */ + ldi r24, XON_VALUE + cbi _SFR_IO_ADDR(PORTD), 5 + st Z, r24 +16: + ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET) + ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET) + rcall circularbytebuffer_push + SET_BIT_IO UCSR0B, UDRIE0, r24 +90: + pop r24 #endif /* UART0_SWFLOWCTRL */ 20: #if UART0_HOOK @@ -409,33 +434,8 @@ uart0_putc: ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET) ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET) clr r25 +; sbi _SFR_IO_ADDR(PORTD), 6 rcall circularbytebuffer_append -#if UART0_SWFLOWCTRL - ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET) - ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET) - rcall circularbytebuffer_cnt - ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET) - ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET) - ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET) - ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET) - ld r18, Z - tst r18 - breq 60f - cpi r24, UART0_THRESH_HIGH+1 - brlo 99f - clr r25 - ldi r24, XOFF_VALUE - rcall circularbytebuffer_push - SET_BIT_IO UCSR0B, UDRIE0, r24 - rjmp 99f -60: - cpi r24, UART0_THRESH_LOW - brge 99f - clr r25 - ldi r24, XON_VALUE - rcall circularbytebuffer_push - SET_BIT_IO UCSR0B, UDRIE0, r24 -#endif /* UART0_SWFLOWCTRL */ 99: out _SFR_IO_ADDR(SREG), r16 pop_range 16, 31 diff --git a/testvectors/skipjack_tv.pdf b/testvectors/skipjack_tv.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8457c4191c684d440b4c7497352ce27b75f0d6f6 GIT binary patch literal 33927 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

kZ1S2bO^k1tzSlbF0xyN=I~ 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 literal 0 HcmV?d00001 -- 2.39.2