1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 /* SPDX-License-Identifier: Unlicense */ 3 4 /** 5 @file tea.c 6 Implementation of TEA, Steffen Jaeckel 7 */ 8 #include "tomcrypt_private.h" 9 10 #ifdef LTC_TEA 11 12 const struct ltc_cipher_descriptor tea_desc = 13 { 14 "tea", 15 26, 16 16, 16, 8, 32, 17 &tea_setup, 18 &tea_ecb_encrypt, 19 &tea_ecb_decrypt, 20 &tea_test, 21 &tea_done, 22 &tea_keysize, 23 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 24 }; 25 26 #define DELTA 0x9E3779B9uL 27 #define SUM 0xC6EF3720uL 28 29 int tea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) 30 { 31 LTC_ARGCHK(key != NULL); 32 LTC_ARGCHK(skey != NULL); 33 34 /* check arguments */ 35 if (keylen != 16) { 36 return CRYPT_INVALID_KEYSIZE; 37 } 38 39 if (num_rounds != 0 && num_rounds != 32) { 40 return CRYPT_INVALID_ROUNDS; 41 } 42 43 /* load key */ 44 LOAD32H(skey->tea.k[0], key+0); 45 LOAD32H(skey->tea.k[1], key+4); 46 LOAD32H(skey->tea.k[2], key+8); 47 LOAD32H(skey->tea.k[3], key+12); 48 49 return CRYPT_OK; 50 } 51 52 /** 53 Encrypts a block of text with TEA 54 @param pt The input plaintext (8 bytes) 55 @param ct The output ciphertext (8 bytes) 56 @param skey The key as scheduled 57 @return CRYPT_OK if successful 58 */ 59 int tea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey) 60 { 61 ulong32 y, z, sum = 0; 62 const ulong32 delta = DELTA; 63 int r; 64 65 LTC_ARGCHK(pt != NULL); 66 LTC_ARGCHK(ct != NULL); 67 LTC_ARGCHK(skey != NULL); 68 69 LOAD32H(y, &pt[0]); 70 LOAD32H(z, &pt[4]); 71 for (r = 0; r < 32; r++) { 72 sum += delta; 73 y += ((z<<4) + skey->tea.k[0]) ^ (z + sum) ^ ((z>>5) + skey->tea.k[1]); 74 z += ((y<<4) + skey->tea.k[2]) ^ (y + sum) ^ ((y>>5) + skey->tea.k[3]); 75 } 76 STORE32H(y, &ct[0]); 77 STORE32H(z, &ct[4]); 78 return CRYPT_OK; 79 } 80 81 /** 82 Decrypts a block of text with TEA 83 @param ct The input ciphertext (8 bytes) 84 @param pt The output plaintext (8 bytes) 85 @param skey The key as scheduled 86 @return CRYPT_OK if successful 87 */ 88 int tea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey) 89 { 90 ulong32 v0, v1, sum = SUM; 91 const ulong32 delta = DELTA; 92 int r; 93 94 LTC_ARGCHK(pt != NULL); 95 LTC_ARGCHK(ct != NULL); 96 LTC_ARGCHK(skey != NULL); 97 98 LOAD32H(v0, &ct[0]); 99 LOAD32H(v1, &ct[4]); 100 101 for (r = 0; r < 32; r++) { 102 v1 -= ((v0 << 4) + skey->tea.k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + skey->tea.k[3]); 103 v0 -= ((v1 << 4) + skey->tea.k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + skey->tea.k[1]); 104 sum -= delta; 105 } 106 107 STORE32H(v0, &pt[0]); 108 STORE32H(v1, &pt[4]); 109 return CRYPT_OK; 110 } 111 112 /** 113 Performs a self-test of the TEA block cipher 114 @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled 115 */ 116 int tea_test(void) 117 { 118 #ifndef LTC_TEST 119 return CRYPT_NOP; 120 #else 121 static const struct { 122 const char *key, *pt, *ct; 123 } tests[] = { 124 { 125 "00000000000000000000000000000000", 126 "0000000000000000", 127 "41ea3a0a94baa940" 128 }, { 129 "32a1e65408b63bb9214105744ec5d2e2", 130 "5ada1d89a9c3801a", 131 "dd46249e28aa0b4b" 132 }, { 133 "60388adadf70a1f5d9cb4e097d2c6c57", 134 "7a6adb4d69c53e0f", 135 "44b71215cf25368a" 136 }, { 137 "4368d2249bd0321eb7c56d5b63a1bfac", 138 "5a5d7ca2e186c41a", 139 "91f56dff7281794f" 140 }, { 141 "5c60bff27072d01c4513c5eb8f3a38ab", 142 "80d9c4adcf899635", 143 "2bb0f1b3c023ed11" 144 } 145 }; 146 unsigned char ptct[2][8]; 147 unsigned char tmp[2][8]; 148 unsigned char key[16]; 149 unsigned long l; 150 symmetric_key skey; 151 size_t i; 152 int err, y; 153 for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { 154 zeromem(&skey, sizeof(skey)); 155 156 l = sizeof(key); 157 if ((err = base16_decode(tests[i].key, XSTRLEN(tests[i].key), key, &l)) != CRYPT_OK) return err; 158 l = sizeof(ptct[0]); 159 if ((err = base16_decode(tests[i].pt, XSTRLEN(tests[i].pt), ptct[0], &l)) != CRYPT_OK) return err; 160 l = sizeof(ptct[1]); 161 if ((err = base16_decode(tests[i].ct, XSTRLEN(tests[i].ct), ptct[1], &l)) != CRYPT_OK) return err; 162 163 if ((err = tea_setup(key, 16, 0, &skey)) != CRYPT_OK) { 164 return err; 165 } 166 tea_ecb_encrypt(ptct[0], tmp[0], &skey); 167 tea_ecb_decrypt(tmp[0], tmp[1], &skey); 168 169 if (compare_testvector(tmp[0], 8, ptct[1], 8, "TEA Encrypt", i) != 0 || 170 compare_testvector(tmp[1], 8, ptct[0], 8, "TEA Decrypt", i) != 0) { 171 return CRYPT_FAIL_TESTVECTOR; 172 } 173 174 /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ 175 for (y = 0; y < 8; y++) tmp[0][y] = 0; 176 for (y = 0; y < 1000; y++) tea_ecb_encrypt(tmp[0], tmp[0], &skey); 177 for (y = 0; y < 1000; y++) tea_ecb_decrypt(tmp[0], tmp[0], &skey); 178 for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; 179 } /* for */ 180 181 return CRYPT_OK; 182 #endif 183 } 184 185 /** Terminate the context 186 @param skey The scheduled key 187 */ 188 void tea_done(symmetric_key *skey) 189 { 190 LTC_UNUSED_PARAM(skey); 191 } 192 193 /** 194 Gets suitable key size 195 @param keysize [in/out] The length of the recommended key (in bytes). This function will store the suitable size back in this variable. 196 @return CRYPT_OK if the input key size is acceptable. 197 */ 198 int tea_keysize(int *keysize) 199 { 200 LTC_ARGCHK(keysize != NULL); 201 if (*keysize < 16) { 202 return CRYPT_INVALID_KEYSIZE; 203 } 204 *keysize = 16; 205 return CRYPT_OK; 206 } 207 208 #endif 209 210