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