]> git.cryptolib.org Git - avr-crypto-lib.git/blob - whirlpool/whirlpool.c
e975b28badd41953cc58e797d88cabee7cc2442d
[avr-crypto-lib.git] / whirlpool / whirlpool.c
1 /* whirlpool.c */
2 /*
3     This file is part of the AVR-Crypto-Lib.
4     Copyright (C) 2006-2011 Daniel Otte (daniel.otte@rub.de)
5
6     This program is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdint.h>
21 #include <avr/pgmspace.h>
22 #include <string.h>
23 #include "gf256mul.h"
24 #include "memxor.h"
25 #include "whirlpool.h"
26
27 #define DEBUG 0
28
29 #if DEBUG
30 #include "cli.h"
31 #endif
32
33 #if WHIRLPOOL_0
34   #ifdef SBOX_PROG
35     #undef SBOX_PROG
36   #endif
37   #define SBOX_PROG 0
38 #endif
39
40 #if SBOX_PROG
41 /*
42 u       0       1       2       3       4       5       6       7       8       9       A       B       C       D       E       F
43 E(u)    1       B       9       C       D       6       F       3       E       8       7       4       A       2       5       0
44 E -1(u) F       0       D       7       B       E       5       A       9       2       C       1       3       4       8       6
45 */
46 static const uint8_t eeinv_box[16] PROGMEM = {
47         /*      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
48         0x1F, 0xB0, 0x9D, 0xC7, 0xDB, 0x6E, 0xF5, 0x3A,
49         0xE9, 0x82, 0x7C, 0x41, 0xA3, 0x24, 0x58, 0x06
50 };
51
52 static const uint8_t r_box[16] PROGMEM = {
53         0x77, 0xCC, 0xBB, 0xDD, 0xEE, 0x44, 0x99, 0xFF,
54         0x66, 0x33, 0x88, 0xAA, 0x22, 0x55, 0x11, 0x00
55 };
56
57 static uint8_t whirlpool_sbox(uint8_t a){
58         uint8_t b,c,d;
59         b = pgm_read_byte(eeinv_box+(a&0x0f));
60         d = pgm_read_byte(eeinv_box+(a>>4));
61         c = ((d>>4)^b)&0x0f;
62         b = (b&0x0f)|(d&0xf0);
63         b ^= pgm_read_byte(r_box+c);
64         c = pgm_read_byte(eeinv_box+(b&0x0f))&0x0f;
65         c |= pgm_read_byte(eeinv_box+(b>>4))&0xf0;
66         return c;
67 }
68
69 #else
70 #if WHIRLPOOL_0
71 static const  uint8_t sbox[256] PROGMEM = {
72         0x68, 0xd0, 0xeb, 0x2b, 0x48, 0x9d, 0x6a, 0xe4, 0xe3, 0xa3, 0x56, 0x81, 0x7d, 0xf1, 0x85, 0x9e,
73         0x2c, 0x8e, 0x78, 0xca, 0x17, 0xa9, 0x61, 0xd5, 0x5d, 0x0b, 0x8c, 0x3c, 0x77, 0x51, 0x22, 0x42,
74         0x3f, 0x54, 0x41, 0x80, 0xcc, 0x86, 0xb3, 0x18, 0x2e, 0x57, 0x06, 0x62, 0xf4, 0x36, 0xd1, 0x6b,
75         0x1b, 0x65, 0x75, 0x10, 0xda, 0x49, 0x26, 0xf9, 0xcb, 0x66, 0xe7, 0xba, 0xae, 0x50, 0x52, 0xab,
76         0x05, 0xf0, 0x0d, 0x73, 0x3b, 0x04, 0x20, 0xfe, 0xdd, 0xf5, 0xb4, 0x5f, 0x0a, 0xb5, 0xc0, 0xa0,
77         0x71, 0xa5, 0x2d, 0x60, 0x72, 0x93, 0x39, 0x08, 0x83, 0x21, 0x5c, 0x87, 0xb1, 0xe0, 0x00, 0xc3,
78         0x12, 0x91, 0x8a, 0x02, 0x1c, 0xe6, 0x45, 0xc2, 0xc4, 0xfd, 0xbf, 0x44, 0xa1, 0x4c, 0x33, 0xc5,
79         0x84, 0x23, 0x7c, 0xb0, 0x25, 0x15, 0x35, 0x69, 0xff, 0x94, 0x4d, 0x70, 0xa2, 0xaf, 0xcd, 0xd6,
80         0x6c, 0xb7, 0xf8, 0x09, 0xf3, 0x67, 0xa4, 0xea, 0xec, 0xb6, 0xd4, 0xd2, 0x14, 0x1e, 0xe1, 0x24,
81         0x38, 0xc6, 0xdb, 0x4b, 0x7a, 0x3a, 0xde, 0x5e, 0xdf, 0x95, 0xfc, 0xaa, 0xd7, 0xce, 0x07, 0x0f,
82         0x3d, 0x58, 0x9a, 0x98, 0x9c, 0xf2, 0xa7, 0x11, 0x7e, 0x8b, 0x43, 0x03, 0xe2, 0xdc, 0xe5, 0xb2,
83         0x4e, 0xc7, 0x6d, 0xe9, 0x27, 0x40, 0xd8, 0x37, 0x92, 0x8f, 0x01, 0x1d, 0x53, 0x3e, 0x59, 0xc1,
84         0x4f, 0x32, 0x16, 0xfa, 0x74, 0xfb, 0x63, 0x9f, 0x34, 0x1a, 0x2a, 0x5a, 0x8d, 0xc9, 0xcf, 0xf6,
85         0x90, 0x28, 0x88, 0x9b, 0x31, 0x0e, 0xbd, 0x4a, 0xe8, 0x96, 0xa6, 0x0c, 0xc8, 0x79, 0xbc, 0xbe,
86         0xef, 0x6e, 0x46, 0x97, 0x5b, 0xed, 0x19, 0xd9, 0xac, 0x99, 0xa8, 0x29, 0x64, 0x1f, 0xad, 0x55,
87         0x13, 0xbb, 0xf7, 0x6f, 0xb9, 0x47, 0x2f, 0xee, 0xb8, 0x7b, 0x89, 0x30, 0xd3, 0x7f, 0x76, 0x82
88 };
89 #else
90 static const uint8_t sbox[256] PROGMEM = {
91         0x18, 0x23, 0xC6, 0xE8, 0x87, 0xB8, 0x01, 0x4F, 0x36, 0xA6, 0xD2, 0xF5, 0x79, 0x6F, 0x91, 0x52,
92     0x60, 0xBC, 0x9B, 0x8E, 0xA3, 0x0C, 0x7B, 0x35, 0x1D, 0xE0, 0xD7, 0xC2, 0x2E, 0x4B, 0xFE, 0x57,
93     0x15, 0x77, 0x37, 0xE5, 0x9F, 0xF0, 0x4A, 0xDA, 0x58, 0xC9, 0x29, 0x0A, 0xB1, 0xA0, 0x6B, 0x85,
94         0xBD, 0x5D, 0x10, 0xF4, 0xCB, 0x3E, 0x05, 0x67, 0xE4, 0x27, 0x41, 0x8B, 0xA7, 0x7D, 0x95, 0xD8,
95         0xFB, 0xEE, 0x7C, 0x66, 0xDD, 0x17, 0x47, 0x9E, 0xCA, 0x2D, 0xBF, 0x07, 0xAD, 0x5A, 0x83, 0x33,
96         0x63, 0x02, 0xAA, 0x71, 0xC8, 0x19, 0x49, 0xD9, 0xF2, 0xE3, 0x5B, 0x88, 0x9A, 0x26, 0x32, 0xB0,
97         0xE9, 0x0F, 0xD5, 0x80, 0xBE, 0xCD, 0x34, 0x48, 0xFF, 0x7A, 0x90, 0x5F, 0x20, 0x68, 0x1A, 0xAE,
98         0xB4, 0x54, 0x93, 0x22, 0x64, 0xF1, 0x73, 0x12, 0x40, 0x08, 0xC3, 0xEC, 0xDB, 0xA1, 0x8D, 0x3D,
99         0x97, 0x00, 0xCF, 0x2B, 0x76, 0x82, 0xD6, 0x1B, 0xB5, 0xAF, 0x6A, 0x50, 0x45, 0xF3, 0x30, 0xEF,
100         0x3F, 0x55, 0xA2, 0xEA, 0x65, 0xBA, 0x2F, 0xC0, 0xDE, 0x1C, 0xFD, 0x4D, 0x92, 0x75, 0x06, 0x8A,
101         0xB2, 0xE6, 0x0E, 0x1F, 0x62, 0xD4, 0xA8, 0x96, 0xF9, 0xC5, 0x25, 0x59, 0x84, 0x72, 0x39, 0x4C,
102         0x5E, 0x78, 0x38, 0x8C, 0xD1, 0xA5, 0xE2, 0x61, 0xB3, 0x21, 0x9C, 0x1E, 0x43, 0xC7, 0xFC, 0x04,
103         0x51, 0x99, 0x6D, 0x0D, 0xFA, 0xDF, 0x7E, 0x24, 0x3B, 0xAB, 0xCE, 0x11, 0x8F, 0x4E, 0xB7, 0xEB,
104         0x3C, 0x81, 0x94, 0xF7, 0xB9, 0x13, 0x2C, 0xD3, 0xE7, 0x6E, 0xC4, 0x03, 0x56, 0x44, 0x7F, 0xA9,
105         0x2A, 0xBB, 0xC1, 0x53, 0xDC, 0x0B, 0x9D, 0x6C, 0x31, 0x74, 0xF6, 0x46, 0xAC, 0x89, 0x14, 0xE1,
106         0x16, 0x3A, 0x69, 0x09, 0x70, 0xB6, 0xD0, 0xED, 0xCC, 0x42, 0x98, 0xA4, 0x28, 0x5C, 0xF8, 0x86
107 };
108 #endif
109
110 #define whirlpool_sbox(a) pgm_read_byte(sbox+a)
111
112 #endif
113
114 static void gamma(uint8_t* a){
115         uint8_t i;
116         for(i=0; i<64; ++i){
117                 *a = whirlpool_sbox(*a);
118                 ++a;
119         }
120 }
121
122 static void pi(uint8_t* a){
123         uint8_t b[8];
124         uint8_t i,j;
125         for(i=1; i<8; ++i){
126                 for(j=0; j<8; ++j){
127                         b[j] = a[i+8*((8+j-i)%8)];
128                 }
129                 for(j=0; j<8; ++j){
130                         a[j*8+i] = b[j];
131                 }
132         }
133 }
134
135 #if WHIRLPOOL_0 || WHIRLPOOL_T
136 static const uint8_t theta_matrix[8] PROGMEM = {
137         0x1, 0x1, 0x3, 0x1, 0x5, 0x8, 0x9, 0x5
138 };
139 #else
140 static const uint8_t theta_matrix[8] PROGMEM = {
141         0x1, 0x1, 0x4, 0x1, 0x8, 0x5, 0x2, 0x9
142 };
143 #endif
144
145 #define POLYNOM 0x1D
146
147 static void theta(uint8_t* a){
148         uint8_t b[8], c, accu;
149         uint8_t i,j,k;
150         for(i=0; i<8; ++i){
151                 for(j=0; j<8;++j){
152                         accu = 0;
153                         for(k=0; k<8; ++k){
154                                 c = pgm_read_byte(theta_matrix+((8+j-k)%8));
155                                 accu ^= gf256mul(a[8*i+k], c, POLYNOM);
156                         }
157                         b[j] = accu;
158                 }
159                 memcpy(a+8*i, b, 8);
160         }
161 }
162
163 static void w_round(uint8_t* a, const uint8_t* k){
164         gamma(a);
165 #if DEBUG
166         cli_putstr_P(PSTR("\r\n pre-pi:"));
167         cli_hexdump_block(a, 64, 4, 8);
168 #endif
169         pi(a);
170 #if DEBUG
171         cli_putstr_P(PSTR("\r\n post-pi & pre-theta:"));
172         cli_hexdump_block(a, 64, 4, 8);
173 #endif
174         theta(a);
175 #if DEBUG
176         cli_putstr_P(PSTR("\r\n post-theta:"));
177         cli_hexdump_block(a, 64, 4, 8);
178 #endif
179         memxor(a, k, 64);
180 }
181
182 static void w_enc(uint8_t *a, const uint8_t* k){
183 #if DEBUG
184         cli_putstr_P(PSTR("\r\n== w_enc ==\r\n w'_00:"));
185         cli_hexdump_block(a, 64, 4, 8);
186         cli_putstr_P(PSTR("\r\n k_00:"));
187         cli_hexdump_block(k, 64, 4, 8);
188 #endif
189         uint8_t rk[64], rc[64];
190         uint8_t r;
191         memxor(a, k, 64);
192         memcpy(rk, k, 64);
193         memset(rc+8, 0, 56);
194         for(r=0; r<10; ++r){
195 #if SBOX_PROG
196                 uint8_t i;
197                 for(i=0; i<8; ++i){
198                         rc[i] = whirlpool_sbox(r*8+i);
199                 }
200 #else
201                 memcpy_P(rc, sbox+r*8, 8);
202 #endif
203                 w_round(rk, rc);
204                 w_round(a, rk);
205 #if DEBUG
206                 cli_putstr_P(PSTR("\r\n w'_"));
207                 cli_hexdump_byte(r+1);
208                 cli_putc(':');
209                 cli_hexdump_block(a, 64, 4, 8);
210                 cli_putstr_P(PSTR("\r\n k_"));
211                 cli_hexdump_byte(r+1);
212                 cli_putc(':');
213                 cli_hexdump_block(rk, 64, 4, 8);
214 #endif
215         }
216 }
217
218 void whirlpool_init(whirlpool_ctx_t* ctx){
219         memset(ctx->s, 0, 64);
220         ctx->blocks = 0;
221 }
222
223 void whirlpool_nextBlock(whirlpool_ctx_t* ctx, const void* block){
224         uint8_t state[64];
225         ctx->blocks += 1;
226         memcpy(state, block, 64);
227         w_enc(state, (uint8_t*)(ctx->s));
228         memxor(ctx->s, state, 64);
229         memxor((ctx->s), block, 64);
230 }
231
232 void whirlpool_lastBlock(whirlpool_ctx_t* ctx, const void* block, uint16_t length_b){
233         while(length_b>=512){
234                 whirlpool_nextBlock(ctx, block);
235                 block = (uint8_t*)block + 64;
236                 length_b -= 512;
237         }
238         uint8_t buffer[64];
239         uint8_t i=8;
240         uint64_t length;
241         length = ctx->blocks*512+length_b;
242         memset(buffer, 0, 64);
243         memcpy(buffer, block, (length_b+7)/8);
244         buffer[length_b/8] |= 0x80>>(length_b&7);
245         if(length_b>255){
246                 whirlpool_nextBlock(ctx, buffer);
247                 memset(buffer, 0, 56);
248         }
249         do{
250                 buffer[56+(--i)] = length&0xff;
251                 length >>= 8;
252         }while(i);
253         whirlpool_nextBlock(ctx, buffer);
254 }
255
256 void whirlpool_ctx2hash(void* dest, const whirlpool_ctx_t* ctx){
257         memcpy(dest, (ctx->s), 64);
258 }