|
@@ -22,7 +22,7 @@
|
|
|
|
|
|
/**
|
|
/**
|
|
@file rc2.c
|
|
@file rc2.c
|
|
- Implementation of LTC_RC2
|
|
|
|
|
|
+ Implementation of RC2 with fixed effective key length of 64bits
|
|
*/
|
|
*/
|
|
|
|
|
|
#ifdef LTC_RC2
|
|
#ifdef LTC_RC2
|
|
@@ -60,26 +60,30 @@ static const unsigned char permute[256] = {
|
|
};
|
|
};
|
|
|
|
|
|
/**
|
|
/**
|
|
- Initialize the LTC_RC2 block cipher
|
|
|
|
|
|
+ Initialize the RC2 block cipher
|
|
@param key The symmetric key you wish to pass
|
|
@param key The symmetric key you wish to pass
|
|
@param keylen The key length in bytes
|
|
@param keylen The key length in bytes
|
|
|
|
+ @param bits The effective key length in bits
|
|
@param num_rounds The number of rounds desired (0 for default)
|
|
@param num_rounds The number of rounds desired (0 for default)
|
|
@param skey The key in as scheduled by this function.
|
|
@param skey The key in as scheduled by this function.
|
|
@return CRYPT_OK if successful
|
|
@return CRYPT_OK if successful
|
|
*/
|
|
*/
|
|
-int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
|
|
|
|
|
|
+int rc2_setup_ex(const unsigned char *key, int keylen, int bits, int num_rounds, symmetric_key *skey)
|
|
{
|
|
{
|
|
unsigned *xkey = skey->rc2.xkey;
|
|
unsigned *xkey = skey->rc2.xkey;
|
|
unsigned char tmp[128];
|
|
unsigned char tmp[128];
|
|
unsigned T8, TM;
|
|
unsigned T8, TM;
|
|
- int i, bits;
|
|
|
|
|
|
+ int i;
|
|
|
|
|
|
LTC_ARGCHK(key != NULL);
|
|
LTC_ARGCHK(key != NULL);
|
|
LTC_ARGCHK(skey != NULL);
|
|
LTC_ARGCHK(skey != NULL);
|
|
|
|
|
|
- if (keylen < 8 || keylen > 128) {
|
|
|
|
|
|
+ if (keylen == 0 || keylen > 128 || bits > 1024) {
|
|
return CRYPT_INVALID_KEYSIZE;
|
|
return CRYPT_INVALID_KEYSIZE;
|
|
}
|
|
}
|
|
|
|
+ if (bits == 0) {
|
|
|
|
+ bits = 1024;
|
|
|
|
+ }
|
|
|
|
|
|
if (num_rounds != 0 && num_rounds != 16) {
|
|
if (num_rounds != 0 && num_rounds != 16) {
|
|
return CRYPT_INVALID_ROUNDS;
|
|
return CRYPT_INVALID_ROUNDS;
|
|
@@ -97,7 +101,6 @@ int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke
|
|
}
|
|
}
|
|
|
|
|
|
/* Phase 2 - reduce effective key size to "bits" */
|
|
/* Phase 2 - reduce effective key size to "bits" */
|
|
- bits = keylen<<3;
|
|
|
|
T8 = (unsigned)(bits+7)>>3;
|
|
T8 = (unsigned)(bits+7)>>3;
|
|
TM = (255 >> (unsigned)(7 & -bits));
|
|
TM = (255 >> (unsigned)(7 & -bits));
|
|
tmp[128 - T8] = permute[tmp[128 - T8] & TM];
|
|
tmp[128 - T8] = permute[tmp[128 - T8] & TM];
|
|
@@ -117,11 +120,27 @@ int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke
|
|
return CRYPT_OK;
|
|
return CRYPT_OK;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ Initialize the RC2 block cipher
|
|
|
|
+
|
|
|
|
+ The effective key length is here always keylen * 8
|
|
|
|
+
|
|
|
|
+ @param key The symmetric key you wish to pass
|
|
|
|
+ @param keylen The key length in bytes
|
|
|
|
+ @param num_rounds The number of rounds desired (0 for default)
|
|
|
|
+ @param skey The key in as scheduled by this function.
|
|
|
|
+ @return CRYPT_OK if successful
|
|
|
|
+*/
|
|
|
|
+int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
|
|
|
|
+{
|
|
|
|
+ return rc2_setup_ex(key, keylen, keylen * 8, num_rounds, skey);
|
|
|
|
+}
|
|
|
|
+
|
|
/**********************************************************************\
|
|
/**********************************************************************\
|
|
* Encrypt an 8-byte block of plaintext using the given key. *
|
|
* Encrypt an 8-byte block of plaintext using the given key. *
|
|
\**********************************************************************/
|
|
\**********************************************************************/
|
|
/**
|
|
/**
|
|
- Encrypts a block of text with LTC_RC2
|
|
|
|
|
|
+ Encrypts a block of text with RC2
|
|
@param pt The input plaintext (8 bytes)
|
|
@param pt The input plaintext (8 bytes)
|
|
@param ct The output ciphertext (8 bytes)
|
|
@param ct The output ciphertext (8 bytes)
|
|
@param skey The key as scheduled
|
|
@param skey The key as scheduled
|
|
@@ -199,7 +218,7 @@ int rc2_ecb_encrypt( const unsigned char *pt,
|
|
* Decrypt an 8-byte block of ciphertext using the given key. *
|
|
* Decrypt an 8-byte block of ciphertext using the given key. *
|
|
\**********************************************************************/
|
|
\**********************************************************************/
|
|
/**
|
|
/**
|
|
- Decrypts a block of text with LTC_RC2
|
|
|
|
|
|
+ Decrypts a block of text with RC2
|
|
@param ct The input ciphertext (8 bytes)
|
|
@param ct The input ciphertext (8 bytes)
|
|
@param pt The output plaintext (8 bytes)
|
|
@param pt The output plaintext (8 bytes)
|
|
@param skey The key as scheduled
|
|
@param skey The key as scheduled
|
|
@@ -275,7 +294,7 @@ int rc2_ecb_decrypt( const unsigned char *ct,
|
|
#endif
|
|
#endif
|
|
|
|
|
|
/**
|
|
/**
|
|
- Performs a self-test of the LTC_RC2 block cipher
|
|
|
|
|
|
+ Performs a self-test of the RC2 block cipher
|
|
@return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
|
|
@return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
|
|
*/
|
|
*/
|
|
int rc2_test(void)
|
|
int rc2_test(void)
|
|
@@ -284,18 +303,47 @@ int rc2_test(void)
|
|
return CRYPT_NOP;
|
|
return CRYPT_NOP;
|
|
#else
|
|
#else
|
|
static const struct {
|
|
static const struct {
|
|
- int keylen;
|
|
|
|
|
|
+ int keylen, bits;
|
|
unsigned char key[16], pt[8], ct[8];
|
|
unsigned char key[16], pt[8], ct[8];
|
|
} tests[] = {
|
|
} tests[] = {
|
|
|
|
|
|
- { 8,
|
|
|
|
|
|
+ { 8, 63,
|
|
|
|
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
+ { 0xeb, 0xb7, 0x73, 0xf9, 0x93, 0x27, 0x8e, 0xff }
|
|
|
|
+ },
|
|
|
|
+ { 8, 64,
|
|
|
|
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
|
|
|
+ { 0x27, 0x8b, 0x27, 0xe4, 0x2e, 0x2f, 0x0d, 0x49 }
|
|
|
|
+ },
|
|
|
|
+ { 8, 64,
|
|
{ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
{ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
{ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
|
|
{ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
|
|
{ 0x30, 0x64, 0x9e, 0xdf, 0x9b, 0xe7, 0xd2, 0xc2 }
|
|
{ 0x30, 0x64, 0x9e, 0xdf, 0x9b, 0xe7, 0xd2, 0xc2 }
|
|
-
|
|
|
|
},
|
|
},
|
|
- { 16,
|
|
|
|
|
|
+ { 1, 64,
|
|
|
|
+ { 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
+ { 0x61, 0xa8, 0xa2, 0x44, 0xad, 0xac, 0xcc, 0xf0 }
|
|
|
|
+ },
|
|
|
|
+ { 7, 64,
|
|
|
|
+ { 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x00,
|
|
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
+ { 0x6c, 0xcf, 0x43, 0x08, 0x97, 0x4c, 0x26, 0x7f }
|
|
|
|
+ },
|
|
|
|
+ { 16, 64,
|
|
|
|
+ { 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x7f,
|
|
|
|
+ 0x0f, 0x79, 0xc3, 0x84, 0x62, 0x7b, 0xaf, 0xb2 },
|
|
|
|
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
|
+ { 0x1a, 0x80, 0x7d, 0x27, 0x2b, 0xbe, 0x5d, 0xb1 }
|
|
|
|
+ },
|
|
|
|
+ { 16, 128,
|
|
{ 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x7f,
|
|
{ 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x7f,
|
|
0x0f, 0x79, 0xc3, 0x84, 0x62, 0x7b, 0xaf, 0xb2 },
|
|
0x0f, 0x79, 0xc3, 0x84, 0x62, 0x7b, 0xaf, 0xb2 },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
@@ -308,14 +356,22 @@ int rc2_test(void)
|
|
|
|
|
|
for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
|
|
for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
|
|
zeromem(tmp, sizeof(tmp));
|
|
zeromem(tmp, sizeof(tmp));
|
|
- if ((err = rc2_setup(tests[x].key, tests[x].keylen, 0, &skey)) != CRYPT_OK) {
|
|
|
|
- return err;
|
|
|
|
|
|
+ if (tests[x].bits == (tests[x].keylen * 8)) {
|
|
|
|
+ if ((err = rc2_setup(tests[x].key, tests[x].keylen, 0, &skey)) != CRYPT_OK) {
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ if ((err = rc2_setup_ex(tests[x].key, tests[x].keylen, tests[x].bits, 0, &skey)) != CRYPT_OK) {
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
rc2_ecb_encrypt(tests[x].pt, tmp[0], &skey);
|
|
rc2_ecb_encrypt(tests[x].pt, tmp[0], &skey);
|
|
rc2_ecb_decrypt(tmp[0], tmp[1], &skey);
|
|
rc2_ecb_decrypt(tmp[0], tmp[1], &skey);
|
|
|
|
|
|
- if (XMEMCMP(tmp[0], tests[x].ct, 8) != 0 || XMEMCMP(tmp[1], tests[x].pt, 8) != 0) {
|
|
|
|
|
|
+ if (compare_testvector(tmp[0], 8, tests[x].ct, 8, "RC2 CT", x) != 0 ||
|
|
|
|
+ compare_testvector(tmp[1], 8, tests[x].pt, 8, "RC2 PT", x) != 0) {
|
|
return CRYPT_FAIL_TESTVECTOR;
|
|
return CRYPT_FAIL_TESTVECTOR;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -345,7 +401,7 @@ void rc2_done(symmetric_key *skey)
|
|
int rc2_keysize(int *keysize)
|
|
int rc2_keysize(int *keysize)
|
|
{
|
|
{
|
|
LTC_ARGCHK(keysize != NULL);
|
|
LTC_ARGCHK(keysize != NULL);
|
|
- if (*keysize < 8) {
|
|
|
|
|
|
+ if (*keysize < 5) {
|
|
return CRYPT_INVALID_KEYSIZE;
|
|
return CRYPT_INVALID_KEYSIZE;
|
|
} else if (*keysize > 128) {
|
|
} else if (*keysize > 128) {
|
|
*keysize = 128;
|
|
*keysize = 128;
|