1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /**
5    @file rc5.c
6    LTC_RC5 code by Tom St Denis
7 */
8 
9 #include "tomcrypt_private.h"
10 
11 #ifdef LTC_RC5
12 
13 const struct ltc_cipher_descriptor rc5_desc =
14 {
15     "rc5",
16     2,
17     8, 128, 8, 12,
18     &rc5_setup,
19     &rc5_ecb_encrypt,
20     &rc5_ecb_decrypt,
21     &rc5_test,
22     &rc5_done,
23     &rc5_keysize,
24     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
25 };
26 
27 static const ulong32 stab[50] = {
28 0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL,
29 0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL,
30 0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL,
31 0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL,
32 0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL,
33 0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL, 0xe96a3d2fUL, 0x87a1b6e8UL, 0x25d930a1UL, 0xc410aa5aUL,
34 0x62482413UL, 0x007f9dccUL
35 };
36 
37  /**
38     Initialize the LTC_RC5 block cipher
39     @param key The symmetric key you wish to pass
40     @param keylen The key length in bytes
41     @param num_rounds The number of rounds desired (0 for default)
42     @param skey The key in as scheduled by this function.
43     @return CRYPT_OK if successful
44  */
45 #ifdef LTC_CLEAN_STACK
s_rc5_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)46 static int s_rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
47 #else
48 int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
49 #endif
50 {
51     ulong32 L[64], *S, A, B, i, j, v, s, t, l;
52 
53     LTC_ARGCHK(skey != NULL);
54     LTC_ARGCHK(key  != NULL);
55 
56     /* test parameters */
57     if (num_rounds == 0) {
58        num_rounds = rc5_desc.default_rounds;
59     }
60 
61     if (num_rounds < 12 || num_rounds > 24) {
62        return CRYPT_INVALID_ROUNDS;
63     }
64 
65     /* key must be between 64 and 1024 bits */
66     if (keylen < 8 || keylen > 128) {
67        return CRYPT_INVALID_KEYSIZE;
68     }
69 
70     skey->rc5.rounds = num_rounds;
71     S = skey->rc5.K;
72 
73     /* copy the key into the L array */
74     for (A = i = j = 0; i < (ulong32)keylen; ) {
75         A = (A << 8) | ((ulong32)(key[i++] & 255));
76         if ((i & 3) == 0) {
77            L[j++] = BSWAP(A);
78            A = 0;
79         }
80     }
81 
82     if ((keylen & 3) != 0) {
83        A <<= (ulong32)((8 * (4 - (keylen&3))));
84        L[j++] = BSWAP(A);
85     }
86 
87     /* setup the S array */
88     t = (ulong32)(2 * (num_rounds + 1));
89     XMEMCPY(S, stab, t * sizeof(*S));
90 
91     /* mix buffer */
92     s = 3 * MAX(t, j);
93     l = j;
94     for (A = B = i = j = v = 0; v < s; v++) {
95         A = S[i] = ROLc(S[i] + A + B, 3);
96         B = L[j] = ROL(L[j] + A + B, (A+B));
97         if (++i == t) { i = 0; }
98         if (++j == l) { j = 0; }
99     }
100     return CRYPT_OK;
101 }
102 
103 #ifdef LTC_CLEAN_STACK
rc5_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)104 int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
105 {
106    int x;
107    x = s_rc5_setup(key, keylen, num_rounds, skey);
108    burn_stack(sizeof(ulong32) * 122 + sizeof(int));
109    return x;
110 }
111 #endif
112 
113 /**
114   Encrypts a block of text with LTC_RC5
115   @param pt The input plaintext (8 bytes)
116   @param ct The output ciphertext (8 bytes)
117   @param skey The key as scheduled
118   @return CRYPT_OK if successful
119 */
120 #ifdef LTC_CLEAN_STACK
s_rc5_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)121 static int s_rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
122 #else
123 int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
124 #endif
125 {
126    ulong32 A, B;
127    const ulong32 *K;
128    int r;
129    LTC_ARGCHK(skey != NULL);
130    LTC_ARGCHK(pt   != NULL);
131    LTC_ARGCHK(ct   != NULL);
132 
133    if (skey->rc5.rounds < 12 || skey->rc5.rounds > 24) {
134       return CRYPT_INVALID_ROUNDS;
135    }
136 
137    LOAD32L(A, &pt[0]);
138    LOAD32L(B, &pt[4]);
139    A += skey->rc5.K[0];
140    B += skey->rc5.K[1];
141    K  = skey->rc5.K + 2;
142 
143    if ((skey->rc5.rounds & 1) == 0) {
144       for (r = 0; r < skey->rc5.rounds; r += 2) {
145           A = ROL(A ^ B, B) + K[0];
146           B = ROL(B ^ A, A) + K[1];
147           A = ROL(A ^ B, B) + K[2];
148           B = ROL(B ^ A, A) + K[3];
149           K += 4;
150       }
151    } else {
152       for (r = 0; r < skey->rc5.rounds; r++) {
153           A = ROL(A ^ B, B) + K[0];
154           B = ROL(B ^ A, A) + K[1];
155           K += 2;
156       }
157    }
158    STORE32L(A, &ct[0]);
159    STORE32L(B, &ct[4]);
160 
161    return CRYPT_OK;
162 }
163 
164 #ifdef LTC_CLEAN_STACK
rc5_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)165 int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
166 {
167    int err = s_rc5_ecb_encrypt(pt, ct, skey);
168    burn_stack(sizeof(ulong32) * 2 + sizeof(int));
169    return err;
170 }
171 #endif
172 
173 /**
174   Decrypts a block of text with LTC_RC5
175   @param ct The input ciphertext (8 bytes)
176   @param pt The output plaintext (8 bytes)
177   @param skey The key as scheduled
178   @return CRYPT_OK if successful
179 */
180 #ifdef LTC_CLEAN_STACK
s_rc5_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)181 static int s_rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
182 #else
183 int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
184 #endif
185 {
186    ulong32 A, B;
187    const ulong32 *K;
188    int r;
189    LTC_ARGCHK(skey != NULL);
190    LTC_ARGCHK(pt   != NULL);
191    LTC_ARGCHK(ct   != NULL);
192 
193    if (skey->rc5.rounds < 12 || skey->rc5.rounds > 24) {
194       return CRYPT_INVALID_ROUNDS;
195    }
196 
197    LOAD32L(A, &ct[0]);
198    LOAD32L(B, &ct[4]);
199    K = skey->rc5.K + (skey->rc5.rounds << 1);
200 
201    if ((skey->rc5.rounds & 1) == 0) {
202        K -= 2;
203        for (r = skey->rc5.rounds - 1; r >= 0; r -= 2) {
204           B = ROR(B - K[3], A) ^ A;
205           A = ROR(A - K[2], B) ^ B;
206           B = ROR(B - K[1], A) ^ A;
207           A = ROR(A - K[0], B) ^ B;
208           K -= 4;
209         }
210    } else {
211       for (r = skey->rc5.rounds - 1; r >= 0; r--) {
212           B = ROR(B - K[1], A) ^ A;
213           A = ROR(A - K[0], B) ^ B;
214           K -= 2;
215       }
216    }
217    A -= skey->rc5.K[0];
218    B -= skey->rc5.K[1];
219    STORE32L(A, &pt[0]);
220    STORE32L(B, &pt[4]);
221 
222    return CRYPT_OK;
223 }
224 
225 #ifdef LTC_CLEAN_STACK
rc5_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)226 int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
227 {
228    int err = s_rc5_ecb_decrypt(ct, pt, skey);
229    burn_stack(sizeof(ulong32) * 2 + sizeof(int));
230    return err;
231 }
232 #endif
233 
234 /**
235   Performs a self-test of the LTC_RC5 block cipher
236   @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
237 */
rc5_test(void)238 int rc5_test(void)
239 {
240  #ifndef LTC_TEST
241     return CRYPT_NOP;
242  #else
243    static const struct {
244        unsigned char key[16], pt[8], ct[8];
245    } tests[] = {
246    {
247        { 0x91, 0x5f, 0x46, 0x19, 0xbe, 0x41, 0xb2, 0x51,
248          0x63, 0x55, 0xa5, 0x01, 0x10, 0xa9, 0xce, 0x91 },
249        { 0x21, 0xa5, 0xdb, 0xee, 0x15, 0x4b, 0x8f, 0x6d },
250        { 0xf7, 0xc0, 0x13, 0xac, 0x5b, 0x2b, 0x89, 0x52 }
251    },
252    {
253        { 0x78, 0x33, 0x48, 0xe7, 0x5a, 0xeb, 0x0f, 0x2f,
254          0xd7, 0xb1, 0x69, 0xbb, 0x8d, 0xc1, 0x67, 0x87 },
255        { 0xF7, 0xC0, 0x13, 0xAC, 0x5B, 0x2B, 0x89, 0x52 },
256        { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 }
257    },
258    {
259        { 0xDC, 0x49, 0xdb, 0x13, 0x75, 0xa5, 0x58, 0x4f,
260          0x64, 0x85, 0xb4, 0x13, 0xb5, 0xf1, 0x2b, 0xaf },
261        { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 },
262        { 0x65, 0xc1, 0x78, 0xb2, 0x84, 0xd1, 0x97, 0xcc }
263    }
264    };
265    unsigned char tmp[2][8];
266    int x, y, err;
267    symmetric_key key;
268 
269    for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
270       /* setup key */
271       if ((err = rc5_setup(tests[x].key, 16, 12, &key)) != CRYPT_OK) {
272          return err;
273       }
274 
275       /* encrypt and decrypt */
276       rc5_ecb_encrypt(tests[x].pt, tmp[0], &key);
277       rc5_ecb_decrypt(tmp[0], tmp[1], &key);
278 
279       /* compare */
280       if (compare_testvector(tmp[0], 8, tests[x].ct, 8, "RC5 Encrypt", x) != 0 ||
281             compare_testvector(tmp[1], 8, tests[x].pt, 8, "RC5 Decrypt", x) != 0) {
282          return CRYPT_FAIL_TESTVECTOR;
283       }
284 
285       /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
286       for (y = 0; y < 8; y++) tmp[0][y] = 0;
287       for (y = 0; y < 1000; y++) rc5_ecb_encrypt(tmp[0], tmp[0], &key);
288       for (y = 0; y < 1000; y++) rc5_ecb_decrypt(tmp[0], tmp[0], &key);
289       for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
290    }
291    return CRYPT_OK;
292   #endif
293 }
294 
295 /** Terminate the context
296    @param skey    The scheduled key
297 */
rc5_done(symmetric_key * skey)298 void rc5_done(symmetric_key *skey)
299 {
300   LTC_UNUSED_PARAM(skey);
301 }
302 
303 /**
304   Gets suitable key size
305   @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
306   @return CRYPT_OK if the input key size is acceptable.
307 */
rc5_keysize(int * keysize)308 int rc5_keysize(int *keysize)
309 {
310    LTC_ARGCHK(keysize != NULL);
311    if (*keysize < 8) {
312       return CRYPT_INVALID_KEYSIZE;
313    }
314    if (*keysize > 128) {
315       *keysize = 128;
316    }
317    return CRYPT_OK;
318 }
319 
320 #endif
321 
322 
323 
324