hmac-sha256 bugfix + hmac-sha256 test suit
This commit is contained in:
parent
b74ffe54a4
commit
cc0d247149
6
Makefile
6
Makefile
|
@ -34,9 +34,9 @@ LIBS =
|
|||
|
||||
define BLA_TEMPLATE2
|
||||
$(2): $(3)
|
||||
echo $$@
|
||||
echo $$^
|
||||
$(CC) $(CFLAGS) $(LDFLAGS)$(patsubst %.elf,%.map,$(2)) -o \
|
||||
@echo "[gcc]: $$@"
|
||||
# echo $$^
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS)$(patsubst %.elf,%.map,$(2)) -o \
|
||||
$(2) \
|
||||
$(3) \
|
||||
$(LIBS)
|
||||
|
|
|
@ -26,6 +26,7 @@ void hmac_sha256_init(hmac_sha256_ctx_t *s, void* key, uint16_t kl){
|
|||
uint8_t buffer[SHA256_BLOCK_BITS/8];
|
||||
uint8_t i;
|
||||
|
||||
memset(buffer, 0, SHA256_BLOCK_BITS/8);
|
||||
if (kl > SHA256_BLOCK_BITS){
|
||||
sha256((void*)buffer, key, kl);
|
||||
} else {
|
||||
|
@ -48,6 +49,7 @@ void hmac_sha256_final(hmac_sha256_ctx_t *s, void* key, uint16_t kl){
|
|||
uint8_t i;
|
||||
sha256_ctx_t a;
|
||||
|
||||
memset(buffer, 0, SHA256_BLOCK_BITS/8);
|
||||
if (kl > SHA256_BLOCK_BITS){
|
||||
sha256((void*)buffer, key, kl);
|
||||
} else {
|
||||
|
@ -61,7 +63,8 @@ void hmac_sha256_final(hmac_sha256_ctx_t *s, void* key, uint16_t kl){
|
|||
sha256_init(&a);
|
||||
sha256_nextBlock(&a, buffer); /* hash key ^ opad */
|
||||
sha256_ctx2hash((void*)buffer, s); /* copy hash(key ^ ipad, msg) to buffer */
|
||||
sha256_lastBlock(s, buffer, SHA256_HASH_BITS);
|
||||
sha256_lastBlock(&a, buffer, SHA256_HASH_BITS);
|
||||
memcpy(s, &a, sizeof(sha256_ctx_t));
|
||||
#if defined SECURE_WIPE_BUFFER
|
||||
memset(buffer, 0, SHA256_BLOCK_BITS/8);
|
||||
memset(a.h, 0, 8*4);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "sha256.h"
|
||||
|
||||
#define HMAC_BITS SHA256_HASH_BITS
|
||||
#define HMAC_BYTES (HMAC_BITS/8)
|
||||
#define HMAC_BYTES ((HMAC_BITS+7)/8)
|
||||
|
||||
typedef sha256_ctx_t hmac_sha256_ctx_t;
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ ALGO_NAME := HMAC-SHA256
|
|||
# comment out the following line for removement of HMAC-SHA256 from the build process
|
||||
MACS += $(ALGO_NAME)
|
||||
|
||||
$(ALGO_NAME)_OBJ := hmac-sha256.o
|
||||
$(ALGO_NAME)_TEST_BIN := main.o debug.o uart.o serial-tools.o sha256-asm.o \
|
||||
xtea-asm.o arcfour-asm.o prng.o cast5.o
|
||||
$(ALGO_NAME)_OBJ := hmac-sha256.o sha256-asm.o
|
||||
$(ALGO_NAME)_TEST_BIN := main-hmac-sha256-test.o debug.o uart.o serial-tools.o \
|
||||
hmac-sha256.o sha256-asm.o nessie_mac_test.o
|
||||
$(ALGO_NAME)_NESSIE_TEST := "nessie"
|
||||
$(ALGO_NAME)_PEROFRMANCE_TEST := "performance"
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* HMAC-SHA256 test-suit
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "serial-tools.h"
|
||||
#include "uart.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "sha256.h"
|
||||
#include "hmac-sha256.h"
|
||||
|
||||
#include "nessie_mac_test.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
char* algo_name = "HMAC-SHA256";
|
||||
|
||||
/*****************************************************************************
|
||||
* additional validation-functions *
|
||||
*****************************************************************************/
|
||||
void hmacsha256_next_dummy(void* buffer, void* ctx){
|
||||
sha256_nextBlock(ctx, buffer);
|
||||
}
|
||||
|
||||
void hmacsha256_init_dummy(void* key, uint16_t keysize_b, void* ctx){
|
||||
hmac_sha256_init(ctx, key, keysize_b);
|
||||
}
|
||||
|
||||
void hmacsha256_last_dummy(void* buffer, uint16_t size_b, void* key, uint16_t keysize_b, void* ctx){
|
||||
sha256_lastBlock(ctx, buffer, size_b);
|
||||
hmac_sha256_final(ctx, key, keysize_b);
|
||||
}
|
||||
|
||||
void testrun_nessie_hmacsha256(void){
|
||||
nessie_mac_ctx.macsize_b = 256;
|
||||
nessie_mac_ctx.keysize_b = 512;
|
||||
nessie_mac_ctx.blocksize_B = 512/8;
|
||||
nessie_mac_ctx.ctx_size_B = sizeof(hmac_sha256_ctx_t);
|
||||
nessie_mac_ctx.name = algo_name;
|
||||
nessie_mac_ctx.mac_init = (nessie_mac_init_fpt)hmacsha256_init_dummy;
|
||||
nessie_mac_ctx.mac_next = (nessie_mac_next_fpt)hmacsha256_next_dummy;
|
||||
nessie_mac_ctx.mac_last = (nessie_mac_last_fpt)hmacsha256_last_dummy;
|
||||
nessie_mac_ctx.mac_conv = (nessie_mac_conv_fpt)sha256_ctx2hash;
|
||||
|
||||
nessie_mac_run();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* main *
|
||||
*****************************************************************************/
|
||||
|
||||
int main (void){
|
||||
char str[20];
|
||||
DEBUG_INIT();
|
||||
uart_putstr("\r\n");
|
||||
|
||||
uart_putstr_P(PSTR("\r\n\r\nCrypto-VS ("));
|
||||
uart_putstr(algo_name);
|
||||
uart_putstr_P(PSTR(")\r\nloaded and running\r\n"));
|
||||
|
||||
restart:
|
||||
while(1){
|
||||
if (!getnextwordn(str,20)) {DEBUG_S("DBG: W1\r\n"); goto error;}
|
||||
if (strcmp(str, "nessie")) {DEBUG_S("DBG: 1b\r\n"); goto error;}
|
||||
testrun_nessie_hmacsha256();
|
||||
goto restart;
|
||||
continue;
|
||||
error:
|
||||
uart_putstr("ERROR\r\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,22 +24,21 @@ void serpent_genctx_dummy(uint8_t* key, uint16_t keysize, void* ctx){
|
|||
}
|
||||
|
||||
void testrun_nessie_serpent(void){
|
||||
nessie_ctx.blocksize_B = 16;
|
||||
nessie_ctx.keysize = 128;
|
||||
nessie_ctx.name = cipher_name;
|
||||
nessie_ctx.ctx_size_B = sizeof(serpent_ctx_t);
|
||||
nessie_ctx.cipher_enc = (nessie_enc_fpt)serpent_enc;
|
||||
nessie_ctx.cipher_dec = (nessie_dec_fpt)serpent_dec;
|
||||
nessie_ctx.cipher_genctx = (nessie_gen_fpt)serpent_genctx_dummy;
|
||||
nessie_bc_ctx.blocksize_B = 16;
|
||||
nessie_bc_ctx.keysize_b = 128;
|
||||
nessie_bc_ctx.name = cipher_name;
|
||||
nessie_bc_ctx.ctx_size_B = sizeof(serpent_ctx_t);
|
||||
nessie_bc_ctx.cipher_enc = (nessie_bc_enc_fpt)serpent_enc;
|
||||
nessie_bc_ctx.cipher_dec = (nessie_bc_dec_fpt)serpent_dec;
|
||||
nessie_bc_ctx.cipher_genctx = (nessie_bc_gen_fpt)serpent_genctx_dummy;
|
||||
|
||||
nessie_run();
|
||||
nessie_bc_run();
|
||||
|
||||
nessie_ctx.keysize = 192;
|
||||
nessie_run();
|
||||
|
||||
nessie_ctx.keysize = 256;
|
||||
nessie_run();
|
||||
nessie_bc_ctx.keysize_b = 192;
|
||||
nessie_bc_run();
|
||||
|
||||
nessie_bc_ctx.keysize_b = 256;
|
||||
nessie_bc_run();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,16 +28,16 @@ void xtea_dec_dummy(uint8_t* buffer, void* ctx){
|
|||
xtea_dec((uint32_t*)buffer, (uint32_t*)buffer, ctx);
|
||||
}
|
||||
|
||||
void testrun_xtea(void){
|
||||
nessie_ctx.blocksize_B = 8;
|
||||
nessie_ctx.keysize = 128;
|
||||
nessie_ctx.name = cipher_name;
|
||||
nessie_ctx.ctx_size_B = 128/8;
|
||||
nessie_ctx.cipher_enc = (nessie_enc_fpt)xtea_enc_dummy;
|
||||
nessie_ctx.cipher_dec = (nessie_dec_fpt)xtea_dec_dummy;
|
||||
nessie_ctx.cipher_genctx = (nessie_gen_fpt)xtea_genctx_dummy;
|
||||
void testrun_nessie_xtea(void){
|
||||
nessie_bc_ctx.blocksize_B = 8;
|
||||
nessie_bc_ctx.keysize_b = 128;
|
||||
nessie_bc_ctx.name = cipher_name;
|
||||
nessie_bc_ctx.ctx_size_B = 128/8;
|
||||
nessie_bc_ctx.cipher_enc = (nessie_bc_enc_fpt)xtea_enc_dummy;
|
||||
nessie_bc_ctx.cipher_dec = (nessie_bc_dec_fpt)xtea_dec_dummy;
|
||||
nessie_bc_ctx.cipher_genctx = (nessie_bc_gen_fpt)xtea_genctx_dummy;
|
||||
|
||||
nessie_run();
|
||||
nessie_bc_run();
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,7 +59,7 @@ restart:
|
|||
while(1){
|
||||
if (!getnextwordn(str,20)) {DEBUG_S("DBG: W1\r\n"); goto error;}
|
||||
if (strcmp(str, "nessie")) {DEBUG_S("DBG: 1b\r\n"); goto error;}
|
||||
testrun_xtea();
|
||||
testrun_nessie_xtea();
|
||||
goto restart;
|
||||
continue;
|
||||
error:
|
||||
|
|
150
nessie_bc_test.c
150
nessie_bc_test.c
|
@ -14,7 +14,7 @@
|
|||
|
||||
|
||||
|
||||
nessie_ctx_t nessie_ctx;
|
||||
nessie_bc_ctx_t nessie_bc_ctx;
|
||||
|
||||
static void printblock(uint8_t* block, uint16_t blocksize_bit){
|
||||
char tab [] = {'0', '1', '2', '3',
|
||||
|
@ -66,49 +66,49 @@ static void printitem(char* name, uint8_t* buffer, uint16_t size_B){
|
|||
}
|
||||
}
|
||||
|
||||
void nessie_enc(uint8_t* key, uint8_t* pt){
|
||||
uint8_t ctx[nessie_ctx.ctx_size_B];
|
||||
uint8_t buffer[nessie_ctx.blocksize_B];
|
||||
void nessie_bc_enc(uint8_t* key, uint8_t* pt){
|
||||
uint8_t ctx[nessie_bc_ctx.ctx_size_B];
|
||||
uint8_t buffer[nessie_bc_ctx.blocksize_B];
|
||||
uint16_t i;
|
||||
|
||||
/* single test */
|
||||
printitem("key", key, (nessie_ctx.keysize+7)/8);
|
||||
nessie_ctx.cipher_genctx(key, nessie_ctx.keysize, ctx);
|
||||
memcpy(buffer, pt, nessie_ctx.blocksize_B);
|
||||
printitem("plain", buffer, nessie_ctx.blocksize_B);
|
||||
nessie_ctx.cipher_enc(buffer, ctx);
|
||||
printitem("cipher", buffer, nessie_ctx.blocksize_B);
|
||||
nessie_ctx.cipher_dec(buffer, ctx);
|
||||
printitem("decrypted", buffer, nessie_ctx.blocksize_B);
|
||||
printitem("key", key, (nessie_bc_ctx.keysize_b+7)/8);
|
||||
nessie_bc_ctx.cipher_genctx(key, nessie_bc_ctx.keysize_b, ctx);
|
||||
memcpy(buffer, pt, nessie_bc_ctx.blocksize_B);
|
||||
printitem("plain", buffer, nessie_bc_ctx.blocksize_B);
|
||||
nessie_bc_ctx.cipher_enc(buffer, ctx);
|
||||
printitem("cipher", buffer, nessie_bc_ctx.blocksize_B);
|
||||
nessie_bc_ctx.cipher_dec(buffer, ctx);
|
||||
printitem("decrypted", buffer, nessie_bc_ctx.blocksize_B);
|
||||
|
||||
/* 100 times test */
|
||||
memcpy(buffer, pt, nessie_ctx.blocksize_B);
|
||||
memcpy(buffer, pt, nessie_bc_ctx.blocksize_B);
|
||||
for(i=0; i<100; ++i){
|
||||
nessie_ctx.cipher_enc(buffer, ctx);
|
||||
nessie_bc_ctx.cipher_enc(buffer, ctx);
|
||||
}
|
||||
printitem("Iterated 100 times", buffer, nessie_ctx.blocksize_B);
|
||||
printitem("Iterated 100 times", buffer, nessie_bc_ctx.blocksize_B);
|
||||
#ifndef NESSIE_NO1KTEST
|
||||
/* 1000 times test, we use the 100 precedig steps to fasten things a bit */
|
||||
for(; i<1000; ++i){
|
||||
nessie_ctx.cipher_enc(buffer, ctx);
|
||||
nessie_bc_ctx.cipher_enc(buffer, ctx);
|
||||
}
|
||||
printitem("Iterated 1000 times", buffer, nessie_ctx.blocksize_B);
|
||||
printitem("Iterated 1000 times", buffer, nessie_bc_ctx.blocksize_B);
|
||||
#endif
|
||||
}
|
||||
|
||||
void nessie_dec(uint8_t* key, uint8_t* ct){
|
||||
uint8_t ctx[nessie_ctx.ctx_size_B];
|
||||
uint8_t buffer[nessie_ctx.blocksize_B];
|
||||
void nessie_bc_dec(uint8_t* key, uint8_t* ct){
|
||||
uint8_t ctx[nessie_bc_ctx.ctx_size_B];
|
||||
uint8_t buffer[nessie_bc_ctx.blocksize_B];
|
||||
|
||||
/* single test */
|
||||
printitem("key", key, (nessie_ctx.keysize+7)/8);
|
||||
nessie_ctx.cipher_genctx(key, nessie_ctx.keysize, ctx);
|
||||
memcpy(buffer, ct, nessie_ctx.blocksize_B);
|
||||
printitem("cipher", buffer, nessie_ctx.blocksize_B);
|
||||
nessie_ctx.cipher_dec(buffer, ctx);
|
||||
printitem("plain", buffer, nessie_ctx.blocksize_B);
|
||||
nessie_ctx.cipher_enc(buffer, ctx);
|
||||
printitem("encrypted", buffer, nessie_ctx.blocksize_B);
|
||||
printitem("key", key, (nessie_bc_ctx.keysize_b+7)/8);
|
||||
nessie_bc_ctx.cipher_genctx(key, nessie_bc_ctx.keysize_b, ctx);
|
||||
memcpy(buffer, ct, nessie_bc_ctx.blocksize_B);
|
||||
printitem("cipher", buffer, nessie_bc_ctx.blocksize_B);
|
||||
nessie_bc_ctx.cipher_dec(buffer, ctx);
|
||||
printitem("plain", buffer, nessie_bc_ctx.blocksize_B);
|
||||
nessie_bc_ctx.cipher_enc(buffer, ctx);
|
||||
printitem("encrypted", buffer, nessie_bc_ctx.blocksize_B);
|
||||
|
||||
}
|
||||
|
||||
|
@ -151,27 +151,27 @@ static void print_header(void){
|
|||
"********************************************************************************\r\n"
|
||||
"\r\n"));
|
||||
uart_putstr_P(PSTR("Primitive Name: "));
|
||||
uart_putstr(nessie_ctx.name);
|
||||
uart_putstr(nessie_bc_ctx.name);
|
||||
uart_putstr_P(PSTR("\r\n"));
|
||||
for(i=0; i<16+strlen(nessie_ctx.name); ++i){
|
||||
for(i=0; i<16+strlen(nessie_bc_ctx.name); ++i){
|
||||
uart_putc('=');
|
||||
}
|
||||
uart_putstr_P(PSTR("\r\nKey size: "));
|
||||
if(nessie_ctx.keysize>100){
|
||||
uart_putc('0'+nessie_ctx.keysize/100);
|
||||
if(nessie_bc_ctx.keysize_b>100){
|
||||
uart_putc('0'+nessie_bc_ctx.keysize_b/100);
|
||||
}
|
||||
if(nessie_ctx.keysize>10){
|
||||
uart_putc('0'+(nessie_ctx.keysize/10)%10);
|
||||
if(nessie_bc_ctx.keysize_b>10){
|
||||
uart_putc('0'+(nessie_bc_ctx.keysize_b/10)%10);
|
||||
}
|
||||
uart_putc('0'+nessie_ctx.keysize%10);
|
||||
uart_putc('0'+nessie_bc_ctx.keysize_b%10);
|
||||
uart_putstr_P(PSTR(" bits\r\nBlock size: "));
|
||||
if(nessie_ctx.blocksize_B*8>100){
|
||||
uart_putc('0'+(nessie_ctx.blocksize_B*8)/100);
|
||||
if(nessie_bc_ctx.blocksize_B*8>100){
|
||||
uart_putc('0'+(nessie_bc_ctx.blocksize_B*8)/100);
|
||||
}
|
||||
if(nessie_ctx.blocksize_B*8>10){
|
||||
uart_putc('0'+((nessie_ctx.blocksize_B*8)/10)%10);
|
||||
if(nessie_bc_ctx.blocksize_B*8>10){
|
||||
uart_putc('0'+((nessie_bc_ctx.blocksize_B*8)/10)%10);
|
||||
}
|
||||
uart_putc('0'+(nessie_ctx.blocksize_B*8)%10);
|
||||
uart_putc('0'+(nessie_bc_ctx.blocksize_B*8)%10);
|
||||
uart_putstr_P(PSTR(" bits"));
|
||||
}
|
||||
|
||||
|
@ -179,54 +179,54 @@ static void print_footer(void){
|
|||
uart_putstr_P(PSTR("\r\n\r\n\r\n\r\nEnd of test vectors\r\n\r\n"));
|
||||
}
|
||||
|
||||
void nessie_run(void){
|
||||
void nessie_bc_run(void){
|
||||
uint16_t i;
|
||||
uint8_t set;
|
||||
uint8_t key[(nessie_ctx.keysize+7)/8];
|
||||
uint8_t buffer[nessie_ctx.blocksize_B];
|
||||
uint8_t key[(nessie_bc_ctx.keysize_b+7)/8];
|
||||
uint8_t buffer[nessie_bc_ctx.blocksize_B];
|
||||
|
||||
print_header();
|
||||
/* test set 1 */
|
||||
set=1;
|
||||
print_setheader(set);
|
||||
for(i=0; i<nessie_ctx.keysize; ++i){
|
||||
for(i=0; i<nessie_bc_ctx.keysize_b; ++i){
|
||||
print_set_vector(set, i);
|
||||
memset(key, 0, (nessie_ctx.keysize+7)/8);
|
||||
memset(key, 0, (nessie_bc_ctx.keysize_b+7)/8);
|
||||
key[i/8] |= 0x80>>(i%8);
|
||||
memset(buffer, 0, nessie_ctx.blocksize_B);
|
||||
nessie_enc(key, buffer);
|
||||
memset(buffer, 0, nessie_bc_ctx.blocksize_B);
|
||||
nessie_bc_enc(key, buffer);
|
||||
}
|
||||
/* test set 2 */
|
||||
set=2;
|
||||
print_setheader(set);
|
||||
for(i=0; i<nessie_ctx.blocksize_B*8; ++i){
|
||||
for(i=0; i<nessie_bc_ctx.blocksize_B*8; ++i){
|
||||
print_set_vector(set, i);
|
||||
memset(key, 0, (nessie_ctx.keysize+7)/8);
|
||||
memset(buffer, 0, nessie_ctx.blocksize_B);
|
||||
memset(key, 0, (nessie_bc_ctx.keysize_b+7)/8);
|
||||
memset(buffer, 0, nessie_bc_ctx.blocksize_B);
|
||||
buffer[i/8] |= 0x80>>(i%8);
|
||||
nessie_enc(key, buffer);
|
||||
nessie_bc_enc(key, buffer);
|
||||
}
|
||||
/* test set 3 */
|
||||
set=3;
|
||||
print_setheader(set);
|
||||
for(i=0; i<256; ++i){
|
||||
print_set_vector(set, i);
|
||||
memset(key, i, (nessie_ctx.keysize+7)/8);
|
||||
memset(buffer, i, nessie_ctx.blocksize_B);
|
||||
nessie_enc(key, buffer);
|
||||
memset(key, i, (nessie_bc_ctx.keysize_b+7)/8);
|
||||
memset(buffer, i, nessie_bc_ctx.blocksize_B);
|
||||
nessie_bc_enc(key, buffer);
|
||||
}
|
||||
/* test set 4 */
|
||||
set=4;
|
||||
print_setheader(set);
|
||||
/* 4 - 0*/
|
||||
print_set_vector(set, 0);
|
||||
for(i=0; i<(nessie_ctx.keysize+7)/8; ++i){
|
||||
for(i=0; i<(nessie_bc_ctx.keysize_b+7)/8; ++i){
|
||||
key[i]=i;
|
||||
}
|
||||
for(i=0; i<nessie_ctx.blocksize_B; ++i){
|
||||
for(i=0; i<nessie_bc_ctx.blocksize_B; ++i){
|
||||
buffer[i]=i*0x11;
|
||||
}
|
||||
nessie_enc(key, buffer);
|
||||
nessie_bc_enc(key, buffer);
|
||||
/* 4 - 1 */
|
||||
print_set_vector(set, 1);
|
||||
/* This is the test vectors in Kasumi */
|
||||
|
@ -235,60 +235,60 @@ void nessie_run(void){
|
|||
0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 };
|
||||
static uint8_t kasumi_plain[]={
|
||||
0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84 };
|
||||
for(i=0; i<(nessie_ctx.keysize+7)/8; ++i){
|
||||
for(i=0; i<(nessie_bc_ctx.keysize_b+7)/8; ++i){
|
||||
key[i]=kasumi_key[i%sizeof(kasumi_key)];
|
||||
}
|
||||
for(i=0; i<nessie_ctx.blocksize_B; ++i){
|
||||
for(i=0; i<nessie_bc_ctx.blocksize_B; ++i){
|
||||
buffer[i]=kasumi_plain[i%sizeof(kasumi_plain)];
|
||||
}
|
||||
/* half done ;-) */
|
||||
/* test set 5 */
|
||||
set=1;
|
||||
print_setheader(set);
|
||||
for(i=0; i<nessie_ctx.keysize; ++i){
|
||||
for(i=0; i<nessie_bc_ctx.keysize_b; ++i){
|
||||
print_set_vector(set, i);
|
||||
memset(key, 0, (nessie_ctx.keysize+7)/8);
|
||||
memset(key, 0, (nessie_bc_ctx.keysize_b+7)/8);
|
||||
key[i/8] |= 0x80>>(i%8);
|
||||
memset(buffer, 0, nessie_ctx.blocksize_B);
|
||||
nessie_dec(key, buffer);
|
||||
memset(buffer, 0, nessie_bc_ctx.blocksize_B);
|
||||
nessie_bc_dec(key, buffer);
|
||||
}
|
||||
/* test set 6 */
|
||||
set=6;
|
||||
print_setheader(set);
|
||||
for(i=0; i<nessie_ctx.blocksize_B*8; ++i){
|
||||
for(i=0; i<nessie_bc_ctx.blocksize_B*8; ++i){
|
||||
print_set_vector(set, i);
|
||||
memset(key, 0, (nessie_ctx.keysize+7)/8);
|
||||
memset(buffer, 0, nessie_ctx.blocksize_B);
|
||||
memset(key, 0, (nessie_bc_ctx.keysize_b+7)/8);
|
||||
memset(buffer, 0, nessie_bc_ctx.blocksize_B);
|
||||
buffer[i/8] |= 0x80>>(i%8);
|
||||
nessie_dec(key, buffer);
|
||||
nessie_bc_dec(key, buffer);
|
||||
}
|
||||
/* test set 7 */
|
||||
set=7;
|
||||
print_setheader(set);
|
||||
for(i=0; i<256; ++i){
|
||||
print_set_vector(set, i);
|
||||
memset(key, i, (nessie_ctx.keysize+7)/8);
|
||||
memset(buffer, i, nessie_ctx.blocksize_B);
|
||||
nessie_dec(key, buffer);
|
||||
memset(key, i, (nessie_bc_ctx.keysize_b+7)/8);
|
||||
memset(buffer, i, nessie_bc_ctx.blocksize_B);
|
||||
nessie_bc_dec(key, buffer);
|
||||
}
|
||||
/* test set 8 */
|
||||
set=8;
|
||||
print_setheader(set);
|
||||
/* 8 - 0*/
|
||||
print_set_vector(set, 0);
|
||||
for(i=0; i<(nessie_ctx.keysize+7)/8; ++i){
|
||||
for(i=0; i<(nessie_bc_ctx.keysize_b+7)/8; ++i){
|
||||
key[i]=i;
|
||||
}
|
||||
for(i=0; i<nessie_ctx.blocksize_B; ++i){
|
||||
for(i=0; i<nessie_bc_ctx.blocksize_B; ++i){
|
||||
buffer[i]=i*0x11;
|
||||
}
|
||||
nessie_dec(key, buffer);
|
||||
nessie_bc_dec(key, buffer);
|
||||
/* 8 - 1 */
|
||||
print_set_vector(set, 1);
|
||||
for(i=0; i<(nessie_ctx.keysize+7)/8; ++i){
|
||||
for(i=0; i<(nessie_bc_ctx.keysize_b+7)/8; ++i){
|
||||
key[i]=kasumi_key[i%sizeof(kasumi_key)];
|
||||
}
|
||||
for(i=0; i<nessie_ctx.blocksize_B; ++i){
|
||||
for(i=0; i<nessie_bc_ctx.blocksize_B; ++i){
|
||||
buffer[i]=kasumi_plain[i%sizeof(kasumi_plain)];
|
||||
}
|
||||
print_footer();
|
||||
|
|
|
@ -3,25 +3,23 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*nessie_gen_fpt)(uint8_t*, uint16_t, void*);
|
||||
typedef void (*nessie_enc_fpt)(void*, void*);
|
||||
typedef void (*nessie_dec_fpt)(void*, void*);
|
||||
typedef void (*nessie_bc_gen_fpt)(uint8_t* key, uint16_t keysize_b, void* ctx);
|
||||
typedef void (*nessie_bc_enc_fpt)(void* buffer, void* ctx);
|
||||
typedef void (*nessie_bc_dec_fpt)(void* buffer, void* ctx);
|
||||
|
||||
typedef struct nessie_ctx_st{
|
||||
uint16_t keysize;
|
||||
typedef struct nessie_bc_ctx_st{
|
||||
uint16_t keysize_b;
|
||||
uint16_t blocksize_B;
|
||||
uint16_t ctx_size_B;
|
||||
char* name;
|
||||
void (*cipher_genctx)(uint8_t* key, uint16_t keysize, void* ctx);
|
||||
void (*cipher_enc)(void* buffer, void* ctx);
|
||||
void (*cipher_dec)(void* buffer, void* ctx);
|
||||
} nessie_ctx_t;
|
||||
nessie_bc_gen_fpt cipher_genctx;
|
||||
nessie_bc_enc_fpt cipher_enc;
|
||||
nessie_bc_dec_fpt cipher_dec;
|
||||
} nessie_bc_ctx_t;
|
||||
|
||||
|
||||
extern nessie_ctx_t nessie_ctx;
|
||||
extern nessie_bc_ctx_t nessie_bc_ctx;
|
||||
|
||||
void nessie_enc(uint8_t* key, uint8_t* pt);
|
||||
void nessie_dec(uint8_t* key, uint8_t* ct);
|
||||
void nessie_run(void);
|
||||
void nessie_bc_run(void);
|
||||
|
||||
#endif /*NESSIE_BC_TEST_H_*/
|
||||
|
|
|
@ -0,0 +1,359 @@
|
|||
/**
|
||||
*
|
||||
* author: Daniel Otte
|
||||
* email: daniel.otte@rub.de
|
||||
* license: GPLv3
|
||||
*
|
||||
* a suit for running the nessie-tests for MACs
|
||||
*
|
||||
* */
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "nessie_mac_test.h"
|
||||
#include "uart.h"
|
||||
|
||||
nessie_mac_ctx_t nessie_mac_ctx;
|
||||
|
||||
#define KEYSIZE_B ((nessie_mac_ctx.keysize_b+7)/8)
|
||||
#define MACSIZE_B ((nessie_mac_ctx.macsize_b+7)/8)
|
||||
|
||||
#define PRINTKEY printitem("key", key, KEYSIZE_B)
|
||||
#define PRINTMAC printitem("MAC", mac, MACSIZE_B)
|
||||
|
||||
static void printblock(uint8_t* block, uint16_t blocksize_bit){
|
||||
char tab [] = {'0', '1', '2', '3',
|
||||
'4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F'};
|
||||
uint16_t i;
|
||||
for(i=0; i<(blocksize_bit+7)/8; ++i){
|
||||
uart_putc(tab[(block[i])>>4]);
|
||||
uart_putc(tab[(block[i])&0xf]);
|
||||
}
|
||||
}
|
||||
|
||||
#define SPACES 31
|
||||
#define BYTESPERLINE 16
|
||||
|
||||
static void printitem(char* name, uint8_t* buffer, uint16_t size_B){
|
||||
uint8_t name_len;
|
||||
uint8_t i;
|
||||
name_len=strlen(name);
|
||||
if(name_len>SPACES-1){
|
||||
uart_putstr_P(PSTR("\r\n!!! formatting error !!!\r\n"));
|
||||
return;
|
||||
}
|
||||
uart_putstr_P(PSTR("\r\n"));
|
||||
for(i=0; i<SPACES-name_len-1; ++i){
|
||||
uart_putc(' ');
|
||||
}
|
||||
uart_putstr(name);
|
||||
uart_putc('=');
|
||||
/* now the data printing begins */
|
||||
if(size_B<=BYTESPERLINE){
|
||||
/* one line seems sufficient */
|
||||
printblock(buffer, size_B*8);
|
||||
} else {
|
||||
/* we need more lines */
|
||||
printblock(buffer, BYTESPERLINE*8); /* first line */
|
||||
int16_t toprint = size_B - BYTESPERLINE;
|
||||
buffer += BYTESPERLINE;
|
||||
while(toprint > 0){
|
||||
uart_putstr_P(PSTR("\r\n"));
|
||||
for(i=0; i<SPACES; ++i){
|
||||
uart_putc(' ');
|
||||
}
|
||||
printblock(buffer, ((toprint>BYTESPERLINE)?BYTESPERLINE:toprint)*8);
|
||||
buffer += BYTESPERLINE;
|
||||
toprint -= BYTESPERLINE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_set_vector(uint8_t set, uint16_t vector){
|
||||
uart_putstr_P(PSTR("\r\n\r\nSet "));
|
||||
uart_putc('0'+set%10);
|
||||
uart_putstr_P(PSTR(", vector#"));
|
||||
uart_putc((vector<100)?' ':'0'+vector/100);
|
||||
uart_putc((vector<10 )?' ':'0'+(vector/10)%10);
|
||||
uart_putc('0'+vector%10);
|
||||
uart_putc(':');
|
||||
}
|
||||
|
||||
/* example:
|
||||
Test vectors -- set 3
|
||||
=====================
|
||||
*/
|
||||
static void print_setheader(uint8_t set){
|
||||
uart_putstr_P(PSTR("\r\n\r\nTest vectors -- set "));
|
||||
uart_putc('0'+set%10);
|
||||
uart_putstr_P(PSTR("\r\n====================="));
|
||||
}
|
||||
|
||||
/* example:
|
||||
********************************************************************************
|
||||
*Project NESSIE - New European Schemes for Signature, Integrity, and Encryption*
|
||||
********************************************************************************
|
||||
|
||||
Primitive Name: Serpent
|
||||
=======================
|
||||
Key size: 256 bits
|
||||
Block size: 128 bits
|
||||
*/
|
||||
|
||||
static void print_header(void){
|
||||
uint16_t i;
|
||||
uart_putstr_P(PSTR("\r\n\r\n"
|
||||
"********************************************************************************\r\n"
|
||||
"* micro-cryt - crypto primitives for microcontrolles by Daniel Otte *\r\n"
|
||||
"********************************************************************************\r\n"
|
||||
"\r\n"));
|
||||
uart_putstr_P(PSTR("Primitive Name: "));
|
||||
uart_putstr(nessie_mac_ctx.name);
|
||||
uart_putstr_P(PSTR("\r\n"));
|
||||
for(i=0; i<16+strlen(nessie_mac_ctx.name); ++i){
|
||||
uart_putc('=');
|
||||
}
|
||||
uart_putstr_P(PSTR("\r\nHash size: "));
|
||||
if(nessie_mac_ctx.macsize_b >100){
|
||||
uart_putc('0'+nessie_mac_ctx.macsize_b/100);
|
||||
}
|
||||
if(nessie_mac_ctx.macsize_b>10){
|
||||
uart_putc('0'+(nessie_mac_ctx.macsize_b/10)%10);
|
||||
}
|
||||
uart_putc('0'+nessie_mac_ctx.macsize_b%10);
|
||||
uart_putstr_P(PSTR(" bits\r\n"));
|
||||
}
|
||||
|
||||
static void print_footer(void){
|
||||
uart_putstr_P(PSTR("\r\n\r\n\r\n\r\nEnd of test vectors\r\n\r\n"));
|
||||
}
|
||||
|
||||
static
|
||||
void ascii_mac(char* data, char* desc, uint8_t* key){
|
||||
uint8_t ctx[nessie_mac_ctx.ctx_size_B];
|
||||
uint8_t mac[MACSIZE_B];
|
||||
uint16_t sl;
|
||||
|
||||
uart_putstr_P(PSTR("\r\n message="));
|
||||
uart_putstr(desc);
|
||||
PRINTKEY;
|
||||
nessie_mac_ctx.mac_init(key, nessie_mac_ctx.keysize_b, ctx);
|
||||
sl = strlen(data);
|
||||
while(sl>=nessie_mac_ctx.blocksize_B){
|
||||
nessie_mac_ctx.mac_next(data, ctx);
|
||||
data += nessie_mac_ctx.blocksize_B;
|
||||
sl -= nessie_mac_ctx.blocksize_B;
|
||||
}
|
||||
nessie_mac_ctx.mac_last(data, sl*8, key, nessie_mac_ctx.keysize_b, ctx);
|
||||
nessie_mac_ctx.mac_conv(mac, ctx);
|
||||
PRINTMAC;
|
||||
}
|
||||
|
||||
// message=1 million times "a"
|
||||
|
||||
static
|
||||
void amillion_mac(uint8_t* key){
|
||||
uint8_t ctx[nessie_mac_ctx.ctx_size_B];
|
||||
uint8_t mac[MACSIZE_B];
|
||||
uint8_t block[nessie_mac_ctx.blocksize_B];
|
||||
uint32_t n=1000000LL;
|
||||
|
||||
uart_putstr_P(PSTR("\r\n message="));
|
||||
uart_putstr_P(PSTR("1 million times \"a\""));
|
||||
PRINTKEY;
|
||||
|
||||
memset(block, 'a', nessie_mac_ctx.blocksize_B);
|
||||
nessie_mac_ctx.mac_init(key, nessie_mac_ctx.keysize_b, ctx);
|
||||
while(n>=nessie_mac_ctx.blocksize_B){
|
||||
nessie_mac_ctx.mac_next(block, ctx);
|
||||
n -= nessie_mac_ctx.blocksize_B;
|
||||
}
|
||||
nessie_mac_ctx.mac_last(block, n*8, key, nessie_mac_ctx.keysize_b, ctx);
|
||||
nessie_mac_ctx.mac_conv(mac, ctx);
|
||||
PRINTMAC;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void zero_mac(uint16_t n, uint8_t* key){
|
||||
uint8_t ctx[nessie_mac_ctx.ctx_size_B];
|
||||
uint8_t mac[MACSIZE_B];
|
||||
uint8_t block[nessie_mac_ctx.blocksize_B];
|
||||
|
||||
uart_putstr_P(PSTR("\r\n message="));
|
||||
if(n>=10000)
|
||||
uart_putc('0'+n/10000);
|
||||
if(n>=1000)
|
||||
uart_putc('0'+(n/1000)%10);
|
||||
if(n>=100)
|
||||
uart_putc('0'+(n/100)%10);
|
||||
if(n>=10)
|
||||
uart_putc('0'+(n/10)%10);
|
||||
uart_putc('0'+n%10);
|
||||
uart_putstr_P(PSTR(" zero bits"));
|
||||
PRINTKEY;
|
||||
|
||||
memset(block, 0, nessie_mac_ctx.blocksize_B);
|
||||
nessie_mac_ctx.mac_init(key, nessie_mac_ctx.keysize_b,ctx);;
|
||||
while(n>=nessie_mac_ctx.blocksize_B*8){
|
||||
nessie_mac_ctx.mac_next(block, ctx);
|
||||
n -= nessie_mac_ctx.blocksize_B*8;
|
||||
}
|
||||
nessie_mac_ctx.mac_last(block, n, key, nessie_mac_ctx.keysize_b, ctx);
|
||||
nessie_mac_ctx.mac_conv(mac, ctx);
|
||||
PRINTMAC;
|
||||
}
|
||||
|
||||
static
|
||||
void one_in512_mac(uint16_t pos, uint8_t* key){
|
||||
uint8_t ctx[nessie_mac_ctx.ctx_size_B];
|
||||
uint8_t mac[MACSIZE_B];
|
||||
uint8_t block[nessie_mac_ctx.blocksize_B];
|
||||
uint16_t n=512;
|
||||
char* tab[8]={"80", "40", "20", "10",
|
||||
"08", "04", "02", "01" };
|
||||
|
||||
pos&=511;
|
||||
uart_putstr_P(PSTR("\r\n message="));
|
||||
uart_putstr_P(PSTR("512-bit string: "));
|
||||
if((pos/8) >=10){
|
||||
uart_putc('0'+(pos/8/10)%10);
|
||||
} else {
|
||||
uart_putc(' ');
|
||||
}
|
||||
uart_putc('0'+(pos/8)%10);
|
||||
uart_putstr_P(PSTR("*00,"));
|
||||
uart_putstr(tab[pos&7]);
|
||||
uart_putc(',');
|
||||
if(63-(pos/8) >=10){
|
||||
uart_putc('0'+((63-pos/8)/10)%10);
|
||||
} else {
|
||||
uart_putc(' ');
|
||||
}
|
||||
uart_putc('0'+(63-pos/8)%10);
|
||||
uart_putstr_P(PSTR("*00"));
|
||||
PRINTKEY;
|
||||
|
||||
/* now the real stuff */
|
||||
memset(block, 0, 512/8);
|
||||
block[pos>>3] = 0x80>>(pos&0x7);
|
||||
nessie_mac_ctx.mac_init(key, nessie_mac_ctx.keysize_b, ctx);;
|
||||
while(n>=nessie_mac_ctx.blocksize_B*8){
|
||||
nessie_mac_ctx.mac_next(block, ctx);
|
||||
n -= nessie_mac_ctx.blocksize_B*8;
|
||||
}
|
||||
nessie_mac_ctx.mac_last(block, n, key, nessie_mac_ctx.keysize_b, ctx);
|
||||
nessie_mac_ctx.mac_conv(mac, ctx);
|
||||
PRINTMAC;
|
||||
}
|
||||
|
||||
static
|
||||
void tv4_mac(uint8_t* key){
|
||||
uint8_t ctx[nessie_mac_ctx.ctx_size_B];
|
||||
uint8_t mac[MACSIZE_B];
|
||||
uint8_t block[256/8];
|
||||
uint16_t n=256;
|
||||
uint32_t i;
|
||||
|
||||
uart_putstr_P(PSTR("\r\n message="));
|
||||
uart_putstr(PSTR("256 zero bits"));
|
||||
memset(block, 0, 256/8);
|
||||
|
||||
nessie_mac_ctx.mac_init(key, nessie_mac_ctx.keysize_b, ctx);;
|
||||
while(n>=nessie_mac_ctx.blocksize_B*8){
|
||||
nessie_mac_ctx.mac_next(block, ctx);
|
||||
n -= nessie_mac_ctx.blocksize_B*8;
|
||||
}
|
||||
nessie_mac_ctx.mac_last(block, n, key, nessie_mac_ctx.keysize_b, ctx);
|
||||
nessie_mac_ctx.mac_conv(mac, ctx);
|
||||
PRINTMAC;
|
||||
for(i=1; i<100000L; ++i){ /* this assumes BLOCKSIZE >= HASHSIZE */
|
||||
nessie_mac_ctx.mac_init(key, nessie_mac_ctx.keysize_b, ctx);;
|
||||
nessie_mac_ctx.mac_last(mac, nessie_mac_ctx.macsize_b, key, nessie_mac_ctx.keysize_b, ctx);
|
||||
nessie_mac_ctx.mac_conv(mac, ctx);
|
||||
}
|
||||
printitem("iterated 100000 times", mac, MACSIZE_B);
|
||||
}
|
||||
|
||||
|
||||
void nessie_mac_run(void){
|
||||
uint16_t i;
|
||||
uint8_t set;
|
||||
uint8_t keyproto[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
|
||||
uint8_t key[KEYSIZE_B];
|
||||
|
||||
print_header();
|
||||
/* test set 1 */
|
||||
char* challange[10][2]= {
|
||||
{"", "\"\" (empty string)"},
|
||||
{"a", "\"a\""},
|
||||
{"abc", "\"abc\""},
|
||||
{"message digest", "\"message digest\""},
|
||||
{"abcdefghijklmnopqrstuvwxyz","\"abcdefghijklmnopqrstuvwxyz\""},
|
||||
{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||
"\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\""},
|
||||
{"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789" , "\"A...Za...z0...9\""},
|
||||
{"1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890",
|
||||
"8 times \"1234567890\""},
|
||||
{"Now is the time for all ", "\"Now is the time for all \""},
|
||||
{"Now is the time for it", "\"Now is the time for it\""}
|
||||
};
|
||||
set=1;
|
||||
print_setheader(set);
|
||||
for(i=0; i<KEYSIZE_B; ++i){
|
||||
key[i] = keyproto[i%sizeof(keyproto)];
|
||||
}
|
||||
for(i=0; i<10; ++i){
|
||||
print_set_vector(set, i);
|
||||
ascii_mac(challange[i][0], challange[i][1], key);
|
||||
}
|
||||
print_set_vector(set, i);
|
||||
amillion_mac(key);
|
||||
for(i=0; i<KEYSIZE_B; ++i){
|
||||
key[i] = keyproto[16+i%8];
|
||||
}
|
||||
for(i=0; i<10; ++i){
|
||||
print_set_vector(set, 11+i);
|
||||
ascii_mac(challange[i][0], challange[i][1], key);
|
||||
}
|
||||
print_set_vector(set, 11+i);
|
||||
amillion_mac(key);
|
||||
/* test set 2 */
|
||||
set=2;
|
||||
for(i=0; i<KEYSIZE_B; ++i){
|
||||
key[i] = keyproto[i%sizeof(keyproto)];
|
||||
}
|
||||
print_setheader(set);
|
||||
for(i=0; i<1024; ++i){
|
||||
print_set_vector(set, i);
|
||||
zero_mac(i, key);
|
||||
}
|
||||
/* test set 3 */
|
||||
set=3;
|
||||
print_setheader(set);
|
||||
/* we use the same key as above */
|
||||
for(i=0; i<512; ++i){
|
||||
print_set_vector(set, i);
|
||||
one_in512_mac(i, key);
|
||||
}
|
||||
/* test set 4 */
|
||||
set=4;
|
||||
print_setheader(set);
|
||||
/* we use the same key as above */
|
||||
print_set_vector(set, 0);
|
||||
tv4_mac(key);
|
||||
/* test set 5 */
|
||||
for(i=0; i<nessie_mac_ctx.keysize_b; ++i){
|
||||
print_set_vector(set, i);
|
||||
memset(key, 0, KEYSIZE_B);
|
||||
key[i>>3]=0x80>>(i&0x7);
|
||||
ascii_mac("ABC", "\"ABC\"", key);
|
||||
}
|
||||
print_footer();
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef NESSIE_MAC_TEST_H_
|
||||
#define NESSIE_MAC_TEST_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*nessie_mac_init_fpt)(void* key, uint16_t keysize_b, void* ctx);
|
||||
typedef void (*nessie_mac_next_fpt)(void* buffer, void* ctx);
|
||||
typedef void (*nessie_mac_last_fpt)(void* buffer, uint16_t size_b, void* key, uint16_t keysize_b, void* ctx);
|
||||
typedef void (*nessie_mac_conv_fpt)(void* buffer, void* ctx);
|
||||
|
||||
|
||||
typedef struct nessie_mac_ctx_st{
|
||||
uint16_t macsize_b;
|
||||
uint16_t keysize_b;
|
||||
uint16_t blocksize_B;
|
||||
uint16_t ctx_size_B;
|
||||
char* name;
|
||||
nessie_mac_init_fpt mac_init;
|
||||
nessie_mac_next_fpt mac_next;
|
||||
nessie_mac_last_fpt mac_last;
|
||||
nessie_mac_conv_fpt mac_conv;
|
||||
} nessie_mac_ctx_t;
|
||||
|
||||
|
||||
extern nessie_mac_ctx_t nessie_mac_ctx;
|
||||
|
||||
void nessie_mac_run(void);
|
||||
|
||||
#endif /*NESSIE_MAC_TEST_H_*/
|
2
sha256.c
2
sha256.c
|
@ -185,7 +185,7 @@ void sha256(sha256_hash_t *dest, void* msg, uint32_t length){ /* length could be
|
|||
sha256_init(&s);
|
||||
while(length >= SHA256_BLOCK_BITS){
|
||||
sha256_nextBlock(&s, msg);
|
||||
msg += SHA256_BLOCK_BITS/8;
|
||||
msg = (uint8_t*)msg + SHA256_BLOCK_BITS/8;
|
||||
length -= SHA256_BLOCK_BITS;
|
||||
}
|
||||
sha256_lastBlock(&s, msg, length);
|
||||
|
|
Loading…
Reference in New Issue