Home | History | Annotate | Download | only in ciphers
      1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
      2  *
      3  * LibTomCrypt is a library that provides various cryptographic
      4  * algorithms in a highly modular and flexible manner.
      5  *
      6  * The library is free for all purposes without any express
      7  * guarantee it works.
      8  *
      9  * Tom St Denis, tomstdenis (at) gmail.com, http://libtomcrypt.com
     10  */
     11 
     12 /**
     13    @file rc6.c
     14    RC6 code by Tom St Denis
     15 */
     16 #include "tomcrypt.h"
     17 
     18 #ifdef RC6
     19 
     20 const struct ltc_cipher_descriptor rc6_desc =
     21 {
     22     "rc6",
     23     3,
     24     8, 128, 16, 20,
     25     &rc6_setup,
     26     &rc6_ecb_encrypt,
     27     &rc6_ecb_decrypt,
     28     &rc6_test,
     29     &rc6_done,
     30     &rc6_keysize,
     31     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
     32 };
     33 
     34 static const ulong32 stab[44] = {
     35 0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL,
     36 0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL,
     37 0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL,
     38 0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL,
     39 0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL,
     40 0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL };
     41 
     42  /**
     43     Initialize the RC6 block cipher
     44     @param key The symmetric key you wish to pass
     45     @param keylen The key length in bytes
     46     @param num_rounds The number of rounds desired (0 for default)
     47     @param skey The key in as scheduled by this function.
     48     @return CRYPT_OK if successful
     49  */
     50 #ifdef LTC_CLEAN_STACK
     51 static int _rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
     52 #else
     53 int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
     54 #endif
     55 {
     56     ulong32 L[64], S[50], A, B, i, j, v, s, l;
     57 
     58     LTC_ARGCHK(key != NULL);
     59     LTC_ARGCHK(skey != NULL);
     60 
     61     /* test parameters */
     62     if (num_rounds != 0 && num_rounds != 20) {
     63        return CRYPT_INVALID_ROUNDS;
     64     }
     65 
     66     /* key must be between 64 and 1024 bits */
     67     if (keylen < 8 || keylen > 128) {
     68        return CRYPT_INVALID_KEYSIZE;
     69     }
     70 
     71     /* copy the key into the L array */
     72     for (A = i = j = 0; i < (ulong32)keylen; ) {
     73         A = (A << 8) | ((ulong32)(key[i++] & 255));
     74         if (!(i & 3)) {
     75            L[j++] = BSWAP(A);
     76            A = 0;
     77         }
     78     }
     79 
     80     /* handle odd sized keys */
     81     if (keylen & 3) {
     82        A <<= (8 * (4 - (keylen&3)));
     83        L[j++] = BSWAP(A);
     84     }
     85 
     86     /* setup the S array */
     87     XMEMCPY(S, stab, 44 * sizeof(stab[0]));
     88 
     89     /* mix buffer */
     90     s = 3 * MAX(44, j);
     91     l = j;
     92     for (A = B = i = j = v = 0; v < s; v++) {
     93         A = S[i] = ROLc(S[i] + A + B, 3);
     94         B = L[j] = ROL(L[j] + A + B, (A+B));
     95         if (++i == 44) { i = 0; }
     96         if (++j == l)  { j = 0; }
     97     }
     98 
     99     /* copy to key */
    100     for (i = 0; i < 44; i++) {
    101         skey->rc6.K[i] = S[i];
    102     }
    103     return CRYPT_OK;
    104 }
    105 
    106 #ifdef LTC_CLEAN_STACK
    107 int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
    108 {
    109    int x;
    110    x = _rc6_setup(key, keylen, num_rounds, skey);
    111    burn_stack(sizeof(ulong32) * 122);
    112    return x;
    113 }
    114 #endif
    115 
    116 /**
    117   Encrypts a block of text with RC6
    118   @param pt The input plaintext (16 bytes)
    119   @param ct The output ciphertext (16 bytes)
    120   @param skey The key as scheduled
    121 */
    122 #ifdef LTC_CLEAN_STACK
    123 static int _rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
    124 #else
    125 int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
    126 #endif
    127 {
    128    ulong32 a,b,c,d,t,u, *K;
    129    int r;
    130 
    131    LTC_ARGCHK(skey != NULL);
    132    LTC_ARGCHK(pt   != NULL);
    133    LTC_ARGCHK(ct   != NULL);
    134    LOAD32L(a,&pt[0]);LOAD32L(b,&pt[4]);LOAD32L(c,&pt[8]);LOAD32L(d,&pt[12]);
    135 
    136    b += skey->rc6.K[0];
    137    d += skey->rc6.K[1];
    138 
    139 #define RND(a,b,c,d) \
    140        t = (b * (b + b + 1)); t = ROLc(t, 5); \
    141        u = (d * (d + d + 1)); u = ROLc(u, 5); \
    142        a = ROL(a^t,u) + K[0];                \
    143        c = ROL(c^u,t) + K[1]; K += 2;
    144 
    145    K = skey->rc6.K + 2;
    146    for (r = 0; r < 20; r += 4) {
    147        RND(a,b,c,d);
    148        RND(b,c,d,a);
    149        RND(c,d,a,b);
    150        RND(d,a,b,c);
    151    }
    152 
    153 #undef RND
    154 
    155    a += skey->rc6.K[42];
    156    c += skey->rc6.K[43];
    157    STORE32L(a,&ct[0]);STORE32L(b,&ct[4]);STORE32L(c,&ct[8]);STORE32L(d,&ct[12]);
    158    return CRYPT_OK;
    159 }
    160 
    161 #ifdef LTC_CLEAN_STACK
    162 int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
    163 {
    164    int err = _rc6_ecb_encrypt(pt, ct, skey);
    165    burn_stack(sizeof(ulong32) * 6 + sizeof(int));
    166    return err;
    167 }
    168 #endif
    169 
    170 /**
    171   Decrypts a block of text with RC6
    172   @param ct The input ciphertext (16 bytes)
    173   @param pt The output plaintext (16 bytes)
    174   @param skey The key as scheduled
    175 */
    176 #ifdef LTC_CLEAN_STACK
    177 static int _rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
    178 #else
    179 int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
    180 #endif
    181 {
    182    ulong32 a,b,c,d,t,u, *K;
    183    int r;
    184 
    185    LTC_ARGCHK(skey != NULL);
    186    LTC_ARGCHK(pt   != NULL);
    187    LTC_ARGCHK(ct   != NULL);
    188 
    189    LOAD32L(a,&ct[0]);LOAD32L(b,&ct[4]);LOAD32L(c,&ct[8]);LOAD32L(d,&ct[12]);
    190    a -= skey->rc6.K[42];
    191    c -= skey->rc6.K[43];
    192 
    193 #define RND(a,b,c,d) \
    194        t = (b * (b + b + 1)); t = ROLc(t, 5); \
    195        u = (d * (d + d + 1)); u = ROLc(u, 5); \
    196        c = ROR(c - K[1], t) ^ u; \
    197        a = ROR(a - K[0], u) ^ t; K -= 2;
    198 
    199    K = skey->rc6.K + 40;
    200 
    201    for (r = 0; r < 20; r += 4) {
    202        RND(d,a,b,c);
    203        RND(c,d,a,b);
    204        RND(b,c,d,a);
    205        RND(a,b,c,d);
    206    }
    207 
    208 #undef RND
    209 
    210    b -= skey->rc6.K[0];
    211    d -= skey->rc6.K[1];
    212    STORE32L(a,&pt[0]);STORE32L(b,&pt[4]);STORE32L(c,&pt[8]);STORE32L(d,&pt[12]);
    213 
    214    return CRYPT_OK;
    215 }
    216 
    217 #ifdef LTC_CLEAN_STACK
    218 int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
    219 {
    220    int err = _rc6_ecb_decrypt(ct, pt, skey);
    221    burn_stack(sizeof(ulong32) * 6 + sizeof(int));
    222    return err;
    223 }
    224 #endif
    225 
    226 /**
    227   Performs a self-test of the RC6 block cipher
    228   @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
    229 */
    230 int rc6_test(void)
    231 {
    232  #ifndef LTC_TEST
    233     return CRYPT_NOP;
    234  #else
    235    static const struct {
    236        int keylen;
    237        unsigned char key[32], pt[16], ct[16];
    238    } tests[] = {
    239    {
    240        16,
    241        { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
    242          0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
    243          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    244          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
    245        { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
    246          0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
    247        { 0x52, 0x4e, 0x19, 0x2f, 0x47, 0x15, 0xc6, 0x23,
    248          0x1f, 0x51, 0xf6, 0x36, 0x7e, 0xa4, 0x3f, 0x18 }
    249    },
    250    {
    251        24,
    252        { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
    253          0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
    254          0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0,
    255          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
    256        { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
    257          0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
    258        { 0x68, 0x83, 0x29, 0xd0, 0x19, 0xe5, 0x05, 0x04,
    259          0x1e, 0x52, 0xe9, 0x2a, 0xf9, 0x52, 0x91, 0xd4 }
    260    },
    261    {
    262        32,
    263        { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
    264          0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
    265          0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0,
    266          0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe },
    267        { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
    268          0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
    269        { 0xc8, 0x24, 0x18, 0x16, 0xf0, 0xd7, 0xe4, 0x89,
    270          0x20, 0xad, 0x16, 0xa1, 0x67, 0x4e, 0x5d, 0x48 }
    271    }
    272    };
    273    unsigned char tmp[2][16];
    274    int x, y, err;
    275    symmetric_key key;
    276 
    277    for (x  = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
    278       /* setup key */
    279       if ((err = rc6_setup(tests[x].key, tests[x].keylen, 0, &key)) != CRYPT_OK) {
    280          return err;
    281       }
    282 
    283       /* encrypt and decrypt */
    284       rc6_ecb_encrypt(tests[x].pt, tmp[0], &key);
    285       rc6_ecb_decrypt(tmp[0], tmp[1], &key);
    286 
    287       /* compare */
    288       if (XMEMCMP(tmp[0], tests[x].ct, 16) || XMEMCMP(tmp[1], tests[x].pt, 16)) {
    289 #if 0
    290          printf("\n\nFailed test %d\n", x);
    291          if (XMEMCMP(tmp[0], tests[x].ct, 16)) {
    292             printf("Ciphertext:  ");
    293             for (y = 0; y < 16; y++) printf("%02x ", tmp[0][y]);
    294             printf("\nExpected  :  ");
    295             for (y = 0; y < 16; y++) printf("%02x ", tests[x].ct[y]);
    296             printf("\n");
    297          }
    298          if (XMEMCMP(tmp[1], tests[x].pt, 16)) {
    299             printf("Plaintext:  ");
    300             for (y = 0; y < 16; y++) printf("%02x ", tmp[0][y]);
    301             printf("\nExpected :  ");
    302             for (y = 0; y < 16; y++) printf("%02x ", tests[x].pt[y]);
    303             printf("\n");
    304          }
    305 #endif
    306          return CRYPT_FAIL_TESTVECTOR;
    307       }
    308 
    309       /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
    310       for (y = 0; y < 16; y++) tmp[0][y] = 0;
    311       for (y = 0; y < 1000; y++) rc6_ecb_encrypt(tmp[0], tmp[0], &key);
    312       for (y = 0; y < 1000; y++) rc6_ecb_decrypt(tmp[0], tmp[0], &key);
    313       for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
    314    }
    315    return CRYPT_OK;
    316   #endif
    317 }
    318 
    319 /** Terminate the context
    320    @param skey    The scheduled key
    321 */
    322 void rc6_done(symmetric_key *skey)
    323 {
    324 }
    325 
    326 /**
    327   Gets suitable key size
    328   @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
    329   @return CRYPT_OK if the input key size is acceptable.
    330 */
    331 int rc6_keysize(int *keysize)
    332 {
    333    LTC_ARGCHK(keysize != NULL);
    334    if (*keysize < 8) {
    335       return CRYPT_INVALID_KEYSIZE;
    336    } else if (*keysize > 128) {
    337       *keysize = 128;
    338    }
    339    return CRYPT_OK;
    340 }
    341 
    342 #endif /*RC6*/
    343 
    344 
    345 
    346 /* $Source: /cvs/libtom/libtomcrypt/src/ciphers/rc6.c,v $ */
    347 /* $Revision: 1.12 $ */
    348 /* $Date: 2006/11/08 23:01:06 $ */
    349