From a6923ff10078ee95bd6b39f211af16d5427836be Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 30 Sep 2020 17:16:47 -0600 Subject: [PATCH] initial implementation of RC2-CBC --- wolfcrypt/src/rc2.c | 76 ++++++++++++--- wolfcrypt/test/test.c | 203 +++++++++++++++++++++++++++++++++++++++- wolfssl/wolfcrypt/rc2.h | 13 ++- 3 files changed, 274 insertions(+), 18 deletions(-) diff --git a/wolfcrypt/src/rc2.c b/wolfcrypt/src/rc2.c index 32411b8a1..f52ff9caf 100644 --- a/wolfcrypt/src/rc2.c +++ b/wolfcrypt/src/rc2.c @@ -79,6 +79,25 @@ static const byte pitable[256] = { 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad }; +/** + Sets RC2 IV, for use with CBC mode. + rc2 RC2 structure to load IV into + iv IV, of size RC2_BLOCK_SIZE octets + return 0 on success, negative on error +*/ +int wc_Rc2SetIV(RC2* rc2, const byte* iv) +{ + if (rc2 == NULL) + return BAD_FUNC_ARG; + + if (iv) + XMEMCPY(rc2->reg, iv, RC2_BLOCK_SIZE); + else + XMEMSET(rc2->reg, 0, RC2_BLOCK_SIZE); + + return 0; +} + /** Set RC2 key, performing key expansion operation rc2 RC2 structure to load expanded key into @@ -87,7 +106,8 @@ static const byte pitable[256] = { bits Effective RC2 key length in bits (max 1024 bits) return 0 on success, negative on error */ -int wc_Rc2SetKey(RC2* rc2, const byte* key, word32 length, word32 bits) +int wc_Rc2SetKey(RC2* rc2, const byte* key, word32 length, + const byte* iv, word32 bits) { int i; unsigned int T8, TM; @@ -102,6 +122,8 @@ int wc_Rc2SetKey(RC2* rc2, const byte* key, word32 length, word32 bits) } rc2->keylen = length; + rc2->bits = bits; + L = (byte*)rc2->key; XMEMCPY(L, key, length); @@ -127,7 +149,7 @@ int wc_Rc2SetKey(RC2* rc2, const byte* key, word32 length, word32 bits) rc2->key[i] = (word16)L[2*i] + ((word16)L[2*i+1] << 8); } - return 0; + return wc_Rc2SetIV(rc2, iv); } /** @@ -260,21 +282,51 @@ int wc_Rc2EcbDecrypt(RC2* rc2, byte* out, const byte* in, word32 sz) int wc_Rc2CbcEncrypt(RC2* rc2, byte* out, const byte* in, word32 sz) { - /* STUB */ - (void)rc2; - (void)out; - (void)in; - (void)sz; + word32 blocks = (sz / RC2_BLOCK_SIZE); + + if (rc2 == NULL || out == NULL || in == NULL) { + return BAD_FUNC_ARG; + } + + if (sz == 0) { + return 0; + } + + while (blocks--) { + xorbuf((byte*)rc2->reg, in, RC2_BLOCK_SIZE); + wc_Rc2EcbEncrypt(rc2, (byte*)rc2->reg, (byte*)rc2->reg, RC2_BLOCK_SIZE); + XMEMCPY(out, rc2->reg, RC2_BLOCK_SIZE); + + out += RC2_BLOCK_SIZE; + in += RC2_BLOCK_SIZE; + } + return 0; } int wc_Rc2CbcDecrypt(RC2* rc2, byte* out, const byte* in, word32 sz) { - /* STUB */ - (void)rc2; - (void)out; - (void)in; - (void)sz; + word32 blocks = (sz / RC2_BLOCK_SIZE); + + if (rc2 == NULL || out == NULL || in == NULL) { + return BAD_FUNC_ARG; + } + + if (sz == 0) { + return 0; + } + + while (blocks--) { + XMEMCPY(rc2->tmp, in, RC2_BLOCK_SIZE); + wc_Rc2EcbDecrypt(rc2, out, (byte*)rc2->tmp, RC2_BLOCK_SIZE); + xorbuf(out, (byte*)rc2->reg, RC2_BLOCK_SIZE); + /* store iv for next call */ + XMEMCPY(rc2->reg, rc2->tmp, RC2_BLOCK_SIZE); + + out += RC2_BLOCK_SIZE; + in += RC2_BLOCK_SIZE; + } + return 0; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index d04267083..027d33a35 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -4272,14 +4272,15 @@ static int hmac_sha3_test(void) typedef struct rc2TestVector { const char* input; const char* output; - const char* key; + const char* key; /* Key, variable up to 128 bytes */ + const char* iv; /* IV, 8-bytes */ int inLen; int outLen; int keyLen; - int effectiveKeyBits; + int effectiveKeyBits; /* Up to 1024 bits supported */ } rc2TestVector; -int rc2_test(void) +static int rc2_ecb_test(void) { int ret = 0; byte cipher[RC2_BLOCK_SIZE]; @@ -4376,7 +4377,7 @@ int rc2_test(void) XMEMSET(plain, 0, RC2_BLOCK_SIZE); ret = wc_Rc2SetKey(&enc, (byte*)test_rc2[i].key, test_rc2[i].keyLen, - test_rc2[i].effectiveKeyBits); + NULL, test_rc2[i].effectiveKeyBits); if (ret != 0) { return -4106; } @@ -4405,6 +4406,200 @@ int rc2_test(void) return 0; } + +static int rc2_cbc_test(void) +{ + int ret = 0; + byte cipher[128]; + byte plain[128]; + + rc2TestVector a, b, c, d, e, f, g, h, i; + rc2TestVector test_rc2[9]; + + int times = sizeof(test_rc2) / sizeof(rc2TestVector), j; + + /* key length = 7, effective key bits = 63 */ + a.input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + a.output = "\xEB\xB7\x73\xF9\x93\x27\x8E\xFF" + "\xF0\x51\x77\x8B\x65\xDB\x13\x57"; + a.key = "\x00\x00\x00\x00\x00\x00\x00\x00"; + a.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"; + a.inLen = RC2_BLOCK_SIZE*2; + a.outLen = RC2_BLOCK_SIZE*2; + a.keyLen = 8; + a.effectiveKeyBits = 63; + + /* key length = 8, effective key bits = 64, all 0xFF */ + b.input = "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff"; + b.output = "\xA3\xA1\x12\x65\x4F\x81\xC5\xCD" + "\xB6\x94\x3E\xEA\x3E\x8B\x9D\x1F"; + b.key = "\xff\xff\xff\xff\xff\xff\xff\xff"; + b.iv = "\xff\xff\xff\xff\xff\xff\xff\xff"; + b.inLen = RC2_BLOCK_SIZE*2; + b.outLen = RC2_BLOCK_SIZE*2; + b.keyLen = 8; + b.effectiveKeyBits = 64; + + /* key length = 8, effective key bits = 64 */ + c.input = "\x10\x00\x00\x00\x00\x00\x00\x01" + "\x10\x00\x00\x00\x00\x00\x00\x01"; + c.output = "\x30\x64\x9e\xdf\x9b\xe7\xd2\xc2"; + c.output = "\xB5\x70\x14\xA2\x5F\x40\xE3\x6D" + "\x81\x99\x8D\xE0\xB5\xD5\x3A\x05"; + c.key = "\x30\x00\x00\x00\x00\x00\x00\x00"; + c.iv = "\x30\x00\x00\x00\x00\x00\x00\x00"; + c.inLen = RC2_BLOCK_SIZE*2; + c.outLen = RC2_BLOCK_SIZE*2; + c.keyLen = 8; + c.effectiveKeyBits = 64; + + /* key length = 1, effective key bits = 64 */ + d.input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + d.output = "\x61\xA8\xA2\x44\xAD\xAC\xCC\xF0" + "\x6D\x19\xE8\xF1\xFC\xE7\x38\x87"; + d.key = "\x88"; + d.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"; + d.inLen = RC2_BLOCK_SIZE*2; + d.outLen = RC2_BLOCK_SIZE*2; + d.keyLen = 1; + d.effectiveKeyBits = 64; + + /* key length = 7, effective key bits = 64 */ + e.input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + e.output = "\x6C\xCF\x43\x08\x97\x4C\x26\x7F" + "\xCC\x3C\x53\x57\x7C\xA1\xA4\x4B"; + e.key = "\x88\xbc\xa9\x0e\x90\x87\x5a"; + e.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"; + e.inLen = RC2_BLOCK_SIZE*2; + e.outLen = RC2_BLOCK_SIZE*2; + e.keyLen = 7; + e.effectiveKeyBits = 64; + + /* key length = 16, effective key bits = 64 */ + f.input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + f.output = "\x1A\x80\x7D\x27\x2B\xBE\x5D\xB1" + "\x64\xEF\xE1\xC3\xB8\xAD\xFB\xBA"; + f.key = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f" + "\x0f\x79\xc3\x84\x62\x7b\xaf\xb2"; + f.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"; + f.inLen = RC2_BLOCK_SIZE*2; + f.outLen = RC2_BLOCK_SIZE*2; + f.keyLen = 16; + f.effectiveKeyBits = 64; + + /* key length = 16, effective bits = 128 */ + g.input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + g.output = "\x22\x69\x55\x2A\xB0\xF8\x5C\xA6" + "\x53\x6E\xFD\x2D\x89\xE1\x2A\x73"; + g.key = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f" + "\x0f\x79\xc3\x84\x62\x7b\xaf\xb2"; + g.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"; + g.inLen = RC2_BLOCK_SIZE*2; + g.outLen = RC2_BLOCK_SIZE*2; + g.keyLen = 16; + g.effectiveKeyBits = 128; + + /* key length = 33, effective bits = 129 */ + h.input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + h.output = "\x5B\x78\xD3\xA4\x3D\xFF\xF1\xF1" + "\x45\x30\xA8\xD5\xC7\x7C\x46\x19"; + h.key = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f" + "\x0f\x79\xc3\x84\x62\x7b\xaf\xb2" + "\x16\xf8\x0a\x6f\x85\x92\x05\x84" + "\xc4\x2f\xce\xb0\xbe\x25\x5d\xaf" + "\x1e"; + h.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"; + h.inLen = RC2_BLOCK_SIZE*2; + h.outLen = RC2_BLOCK_SIZE*2; + h.keyLen = 33; + h.effectiveKeyBits = 129; + + /* key length = 10, effective bits = 40 */ + i.input = "\x11\x22\x33\x44\x55\x66\x77\x88" + "\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00" + "\x11\x22\x33\x44\x55\x66\x77\x88" + "\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00"; + i.output = "\x71\x2D\x11\x99\xC9\xA0\x78\x4F" + "\xCD\xF1\x1E\x3D\xFD\x21\x7E\xDB" + "\xB2\x6E\x0D\xA4\x72\xBC\x31\x51" + "\x48\xEF\x4E\x68\x3B\xDC\xCD\x7D"; + i.key = "\x26\x1E\x57\x8E\xC9\x62\xBF\xB8" + "\x3E\x96"; + i.iv = "\x01\x02\x03\x04\x05\x06\x07\x08"; + i.inLen = RC2_BLOCK_SIZE*4; + i.outLen = RC2_BLOCK_SIZE*4; + i.keyLen = 10; + i.effectiveKeyBits = 40; + + test_rc2[0] = a; + test_rc2[1] = b; + test_rc2[2] = c; + test_rc2[3] = d; + test_rc2[4] = e; + test_rc2[5] = f; + test_rc2[6] = g; + test_rc2[7] = h; + test_rc2[8] = i; + + for (j = 0; j < times; ++j) { + RC2 rc2; + + XMEMSET(cipher, 0, sizeof(cipher)); + XMEMSET(plain, 0, sizeof(plain)); + + ret = wc_Rc2SetKey(&rc2, (byte*)test_rc2[j].key, test_rc2[j].keyLen, + (byte*)test_rc2[j].iv, test_rc2[j].effectiveKeyBits); + if (ret != 0) { + return -4111; + } + + ret = wc_Rc2CbcEncrypt(&rc2, cipher, (byte*)test_rc2[j].input, + test_rc2[j].inLen); + if (ret != 0) { + return -4112; + } + + if (XMEMCMP(cipher, (byte*)test_rc2[j].output, test_rc2[j].outLen)) { + return -4113; + } + + /* reset IV for decrypt, since overriden by encrypt operation */ + ret = wc_Rc2SetIV(&rc2, (byte*)test_rc2[j].iv); + if (ret != 0) { + return -4114; + } + + ret = wc_Rc2CbcDecrypt(&rc2, plain, cipher, test_rc2[j].outLen); + if (ret != 0) { + return -4115; + } + + if (XMEMCMP(plain, (byte*)test_rc2[j].input, test_rc2[j].inLen)) { + return -4116; + } + } + + return 0; +} + +int rc2_test(void) +{ + int ret = 0; + + ret = rc2_ecb_test(); + if (ret != 0) { + return ret; + } + + return rc2_cbc_test(); +} #endif diff --git a/wolfssl/wolfcrypt/rc2.h b/wolfssl/wolfcrypt/rc2.h index 4b559b5f2..d33e0ed0d 100644 --- a/wolfssl/wolfcrypt/rc2.h +++ b/wolfssl/wolfcrypt/rc2.h @@ -37,15 +37,24 @@ enum { /* RC2 encryption and decryption */ typedef struct RC2 { - word32 keylen; + word32 keylen; /* key length, octets */ + word32 bits; /* effective key length, bits */ ALIGN16 word16 key[RC2_MAX_KEY_SIZE/2]; + ALIGN16 word32 reg[RC2_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */ + ALIGN16 word32 tmp[RC2_BLOCK_SIZE / sizeof(word32)]; /* same */ } RC2; -WOLFSSL_API int wc_Rc2SetKey(RC2*, const byte*, word32, word32); +WOLFSSL_API int wc_Rc2SetKey(RC2* rc2, const byte* key, word32 length, + const byte* iv, word32 bits); +WOLFSSL_API int wc_Rc2SetIV(RC2* rc2, const byte* iv); + +/* RC2-ECB */ WOLFSSL_API int wc_Rc2EcbEncrypt(RC2* rc2, byte* out, const byte* in, word32 sz); WOLFSSL_API int wc_Rc2EcbDecrypt(RC2* rc2, byte* out, const byte* in, word32 sz); + +/* RC2-CBC */ WOLFSSL_API int wc_Rc2CbcEncrypt(RC2* rc2, byte* out, const byte* in, word32 sz); WOLFSSL_API int wc_Rc2CbcDecrypt(RC2* rc2, byte* out,