maxtweak added to block
[rofl0r-kripto.git] / lib / block / rc6.c
blobc2dcb43a44ed67f607a838cceeadea480dba78ff
1 /*
2 * Written in 2011 by Gregor Pintar <grpintar@gmail.com>
4 * To the extent possible under law, the author(s) have dedicated
5 * all copyright and related and neighboring rights to this software
6 * to the public domain worldwide.
7 *
8 * This software is distributed without any warranty.
10 * You should have received a copy of the CC0 Public Domain Dedication.
11 * If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
14 #include <stdint.h>
15 #include <stdlib.h>
16 #include <limits.h>
18 #include <kripto/cast.h>
19 #include <kripto/loadstore.h>
20 #include <kripto/rotate.h>
21 #include <kripto/memwipe.h>
22 #include <kripto/block.h>
23 #include <kripto/desc/block.h>
24 #include <kripto/object/block.h>
26 #include <kripto/block/rc6.h>
28 struct kripto_block
30 struct kripto_block_object obj;
31 unsigned int rounds;
32 size_t size;
33 uint32_t *k;
36 #define RC6_K_LEN(r) (((r) + 2) << 1)
38 static void rc6_setup
40 kripto_block *s,
41 const uint8_t *key,
42 unsigned int key_len
45 unsigned int i;
46 unsigned int j;
47 unsigned int k;
48 const unsigned int ls = (key_len + 3) >> 2;
49 uint32_t a;
50 uint32_t b;
51 uint32_t x[64];
53 for(i = 0; i < ls; i++) x[i] = 0;
55 for(j = key_len - 1; j != UINT_MAX; j--)
56 x[j >> 2] = (x[j >> 2] << 8) | key[j];
58 *s->k = 0xB7E15163;
59 for(i = 1; i < RC6_K_LEN(s->rounds); i++)
60 s->k[i] = s->k[i-1] + 0x9E3779B9;
62 a = b = i = j = k = 0;
63 while(k < RC6_K_LEN(s->rounds) * 3)
65 a = s->k[i] = ROL32(s->k[i] + a + b, 3);
66 b = x[j] = ROL32(x[j] + a + b, a + b);
67 if(++i == RC6_K_LEN(s->rounds)) i = 0;
68 if(++j == ls) j = 0;
69 k++;
72 /* wipe */
73 kripto_memwipe(x, ls << 2);
74 kripto_memwipe(&a, sizeof(uint32_t));
75 kripto_memwipe(&b, sizeof(uint32_t));
78 static void rc6_encrypt(const kripto_block *s, const void *pt, void *ct)
80 uint32_t a;
81 uint32_t b;
82 uint32_t c;
83 uint32_t d;
84 uint32_t m0;
85 uint32_t m1;
86 uint32_t t;
87 unsigned int i = 2;
89 a = LOAD32L(CU8(pt));
90 b = LOAD32L(CU8(pt) + 4);
91 c = LOAD32L(CU8(pt) + 8);
92 d = LOAD32L(CU8(pt) + 12);
94 b += s->k[0];
95 d += s->k[1];
97 while(i <= (s->rounds << 1))
99 m0 = ROL32(b * ((b << 1) | 1), 5);
100 m1 = ROL32(d * ((d << 1) | 1), 5);
102 t = ROL32(a ^ m0, m1) + s->k[i++];
103 a = b;
104 b = ROL32(c ^ m1, m0) + s->k[i++];
105 c = d;
106 d = t;
109 a += s->k[i];
110 c += s->k[i + 1];
112 STORE32L(a, U8(ct));
113 STORE32L(b, U8(ct) + 4);
114 STORE32L(c, U8(ct) + 8);
115 STORE32L(d, U8(ct) + 12);
118 static void rc6_decrypt(const kripto_block *s, const void *ct, void *pt)
120 uint32_t a;
121 uint32_t b;
122 uint32_t c;
123 uint32_t d;
124 uint32_t m0;
125 uint32_t m1;
126 uint32_t t;
127 unsigned int i = s->rounds << 1;
129 a = LOAD32L(CU8(ct));
130 b = LOAD32L(CU8(ct) + 4);
131 c = LOAD32L(CU8(ct) + 8);
132 d = LOAD32L(CU8(ct) + 12);
134 a -= s->k[i + 2];
135 c -= s->k[i + 3];
137 while(i)
139 m0 = ROL32(a * ((a << 1) | 1), 5);
140 m1 = ROL32(c * ((c << 1) | 1), 5);
142 t = d;
143 d = c;
144 c = ROR32(b - s->k[i + 1], m0) ^ m1;
145 b = a;
146 a = ROR32(t - s->k[i], m1) ^ m0;
148 i -= 2;
151 b -= s->k[0];
152 d -= s->k[1];
154 STORE32L(a, U8(pt));
155 STORE32L(b, U8(pt) + 4);
156 STORE32L(c, U8(pt) + 8);
157 STORE32L(d, U8(pt) + 12);
160 static kripto_block *rc6_create
162 unsigned int r,
163 const void *key,
164 unsigned int key_len
167 kripto_block *s;
169 if(!r) r = 20;
171 s = malloc(sizeof(kripto_block) + (RC6_K_LEN(r) << 2));
172 if(!s) return 0;
174 s->obj.desc = kripto_block_rc6;
175 s->size = sizeof(kripto_block) + (RC6_K_LEN(r) << 2);
176 s->rounds = r;
177 s->k = (uint32_t *)((uint8_t *)s + sizeof(kripto_block));
179 rc6_setup(s, key, key_len);
181 return s;
184 static void rc6_destroy(kripto_block *s)
186 kripto_memwipe(s, s->size);
187 free(s);
190 static kripto_block *rc6_recreate
192 kripto_block *s,
193 unsigned int r,
194 const void *key,
195 unsigned int key_len
198 if(!r) r = 20;
200 if(sizeof(kripto_block) + (RC6_K_LEN(r) << 2) > s->size)
202 rc6_destroy(s);
203 s = rc6_create(r, key, key_len);
205 else
207 s->rounds = r;
208 rc6_setup(s, key, key_len);
211 return s;
214 static const kripto_block_desc rc6 =
216 &rc6_create,
217 &rc6_recreate,
218 0, /* tweak */
219 &rc6_encrypt,
220 &rc6_decrypt,
221 &rc6_destroy,
222 16, /* block size */
223 255, /* max key */
224 0 /* max tweak */
227 const kripto_block_desc *const kripto_block_rc6 = &rc6;