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 
tea_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)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 */
tea_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)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 */
tea_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)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 */
tea_test(void)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 */
tea_done(symmetric_key * skey)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 */
tea_keysize(int * keysize)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