Initial commit of vpp code.
[vpp.git] / vppinfra / vppinfra / md5.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */
16
17 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
18 rights reserved.
19
20 License to copy and use this software is granted provided that it
21 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
22 Algorithm" in all material mentioning or referencing this software
23 or this function.
24
25 License is also granted to make and use derivative works provided
26 that such works are identified as "derived from the RSA Data
27 Security, Inc. MD5 Message-Digest Algorithm" in all material
28 mentioning or referencing the derived work.
29
30 RSA Data Security, Inc. makes no representations concerning either
31 the merchantability of this software or the suitability of this
32 software for any particular purpose. It is provided "as is"
33 without express or implied warranty of any kind.
34
35 These notices must be retained in any copies of any part of this
36 documentation and/or software.
37  */
38
39 #include <vppinfra/string.h>    /* for memset */
40 #include <vppinfra/byte_order.h>
41 #include <vppinfra/md5.h>
42
43 /* F, G, H and I are basic MD5 functions. */
44 #define F(b, c, d) (d ^ (b & (c ^ d)))
45 #define G(b, c, d) F (d, b, c)
46 #define H(b, c, d) (b ^ c ^ d)
47 #define I(b, c, d) (c ^ (b | ~d))
48
49 /* ROTATE_LEFT rotates x left n bits. */
50 #define ROTATE_LEFT(x,n) \
51   (((x) << (n)) | ((x) >> (32 - (n))))
52
53 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
54    Rotation is separate from addition to prevent recomputation. */
55 #define FF(a,b,c,d,x,s,ac)                      \
56 do {                                            \
57   a += F (b, c, d) + x + ac;                    \
58   a = ROTATE_LEFT (a, s);                       \
59   a += b;                                       \
60 } while (0)
61
62 #define GG(a,b,c,d,x,s,ac)                      \
63 do {                                            \
64   a += G (b, c, d) + x + ac;                    \
65   a = ROTATE_LEFT (a, s);                       \
66   a += b;                                       \
67 } while (0)
68
69 #define HH(a,b,c,d,x,s,ac)                      \
70 do {                                            \
71   a += H (b, c, d) + x + ac;                    \
72   a = ROTATE_LEFT (a, s);                       \
73   a += b;                                       \
74 } while (0)
75
76 #define II(a,b,c,d,x,s,ac)                      \
77 do {                                            \
78   a += I (b, c, d) + x + ac;                    \
79   a = ROTATE_LEFT (a, s);                       \
80   a += b;                                       \
81 } while (0)
82
83 #undef _
84
85 /* MD5 basic transformation. Transforms state based on block. */
86 static void md5_transform (md5_context_t * m,
87                            u32 * data,
88                            u32 * result,
89                            int zero_buffer)
90 {
91   u32 a = m->state[0], b = m->state[1], c = m->state[2], d = m->state[3];
92   u32 * x = data;
93
94 /* Constants for MD5Transform routine. */
95 #define S11 7
96 #define S12 12
97 #define S13 17
98 #define S14 22
99 #define S21 5
100 #define S22 9
101 #define S23 14
102 #define S24 20
103 #define S31 4
104 #define S32 11
105 #define S33 16
106 #define S34 23
107 #define S41 6
108 #define S42 10
109 #define S43 15
110 #define S44 21
111
112   /* Round 1 */
113   FF (a, b, c, d, clib_host_to_little_u32 (x[ 0]), S11, 0xd76aa478); /* 1 */
114   FF (d, a, b, c, clib_host_to_little_u32 (x[ 1]), S12, 0xe8c7b756); /* 2 */
115   FF (c, d, a, b, clib_host_to_little_u32 (x[ 2]), S13, 0x242070db); /* 3 */
116   FF (b, c, d, a, clib_host_to_little_u32 (x[ 3]), S14, 0xc1bdceee); /* 4 */
117   FF (a, b, c, d, clib_host_to_little_u32 (x[ 4]), S11, 0xf57c0faf); /* 5 */
118   FF (d, a, b, c, clib_host_to_little_u32 (x[ 5]), S12, 0x4787c62a); /* 6 */
119   FF (c, d, a, b, clib_host_to_little_u32 (x[ 6]), S13, 0xa8304613); /* 7 */
120   FF (b, c, d, a, clib_host_to_little_u32 (x[ 7]), S14, 0xfd469501); /* 8 */
121   FF (a, b, c, d, clib_host_to_little_u32 (x[ 8]), S11, 0x698098d8); /* 9 */
122   FF (d, a, b, c, clib_host_to_little_u32 (x[ 9]), S12, 0x8b44f7af); /* 10 */
123   FF (c, d, a, b, clib_host_to_little_u32 (x[10]), S13, 0xffff5bb1); /* 11 */
124   FF (b, c, d, a, clib_host_to_little_u32 (x[11]), S14, 0x895cd7be); /* 12 */
125   FF (a, b, c, d, clib_host_to_little_u32 (x[12]), S11, 0x6b901122); /* 13 */
126   FF (d, a, b, c, clib_host_to_little_u32 (x[13]), S12, 0xfd987193); /* 14 */
127   FF (c, d, a, b, clib_host_to_little_u32 (x[14]), S13, 0xa679438e); /* 15 */
128   FF (b, c, d, a, clib_host_to_little_u32 (x[15]), S14, 0x49b40821); /* 16 */
129
130   /* Round 2 */
131   GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
132   GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
133   GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
134   GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
135   GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
136   GG (d, a, b, c, x[10], S22, 0x02441453); /* 22 */
137   GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
138   GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
139   GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
140   GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
141   GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
142   GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
143   GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
144   GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
145   GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
146   GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
147
148   /* Round 3 */
149   HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
150   HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
151   HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
152   HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
153   HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
154   HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
155   HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
156   HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
157   HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
158   HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
159   HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
160   HH (b, c, d, a, x[ 6], S34, 0x04881d05); /* 44 */
161   HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
162   HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
163   HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
164   HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
165
166   /* Round 4 */
167   II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
168   II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
169   II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
170   II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
171   II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
172   II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
173   II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
174   II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
175   II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
176   II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
177   II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
178   II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
179   II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
180   II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
181   II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
182   II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
183
184   a += m->state[0];
185   b += m->state[1];
186   c += m->state[2];
187   d += m->state[3];
188
189   if (result)
190     {
191       result[0] = clib_host_to_little_u32 (a);
192       result[1] = clib_host_to_little_u32 (b);
193       result[2] = clib_host_to_little_u32 (c);
194       result[3] = clib_host_to_little_u32 (d);
195     }
196   else
197     {
198       m->state[0] = a;
199       m->state[1] = b;
200       m->state[2] = c;
201       m->state[3] = d;
202     }
203
204   /* Zero sensitive information. */
205   if (result)
206     memset (m, ~0, sizeof (m[0]));
207   else if (zero_buffer)
208     memset (m->input_buffer.b8, 0, sizeof (m->input_buffer));
209 }
210
211 /* MD5 initialization. Begins an MD5 operation, writing a new context. */
212 void md5_init (md5_context_t * c)
213 {
214   memset (c, 0, sizeof (c[0]));
215
216   /* Load magic initialization constants. */
217   c->state[0] = 0x67452301;
218   c->state[1] = 0xefcdab89;
219   c->state[2] = 0x98badcfe;
220   c->state[3] = 0x10325476;
221 }
222
223 always_inline void
224 md5_fill_buffer_aligned (md5_context_t * c,
225                          u32 * d32)
226 {
227   int i;
228   for (i = 0; i < ARRAY_LEN (c->input_buffer.b32); i++)
229     c->input_buffer.b32[i] = d32[i];
230 }
231
232 /* MD5 block update operation. Continues an MD5 message-digest
233   operation, processing another message block, and updating the
234   context.
235  */
236 void md5_add (md5_context_t * c, void * data, int data_bytes)
237 {
238   u32 data_bytes_left;
239   void * d;
240
241   if (data_bytes == 0)
242     return;
243
244   d = data;
245   data_bytes_left = data_bytes;
246
247   if ((pointer_to_uword (d) % sizeof (u32)) == 0
248       && (c->n_bits % BITS (c->input_buffer)) == 0
249       && data_bytes >= sizeof (c->input_buffer))
250     {
251       int is_last_iteration;
252       /* Fast aligned version. */
253       do {
254         data_bytes_left -= sizeof (c->input_buffer);
255         is_last_iteration = data_bytes_left < sizeof (c->input_buffer);
256         md5_transform (c, d, /* result */ 0, /* zero_buffer */ is_last_iteration);
257         d += sizeof (c->input_buffer);
258       } while (! is_last_iteration);
259     }
260
261   /* Slow unaligned version. */
262   {
263     int bi;
264     u8 * d8 = d;
265
266     bi = (c->n_bits / BITS (u8)) % ARRAY_LEN (c->input_buffer.b8);
267
268     while (data_bytes_left > 0)
269       {
270         c->input_buffer.b8[bi] = d8[0];
271         data_bytes_left -= 1;
272         d8++;
273         bi++;
274         if (bi == ARRAY_LEN (c->input_buffer.b8))
275           {
276             bi = 0;
277             md5_transform (c, c->input_buffer.b32,
278                            /* result */ 0,
279                            /* zero_buffer */ 1);
280           }
281       }
282   }
283
284   c->n_bits += data_bytes * BITS (u8);
285 }
286
287 void md5_finish (md5_context_t * c, u8 * digest)
288 {
289   u64 n_bits_save;
290   int bi, n_pad;
291   static u8 padding[sizeof (c->input_buffer)] = { 0x80, 0, };
292
293   n_bits_save = c->n_bits;
294   bi = (n_bits_save / BITS (u8)) % ARRAY_LEN (c->input_buffer.b8);
295
296   n_pad = sizeof (c->input_buffer) - (bi + sizeof (u64));
297   if (n_pad <= 0)
298     n_pad += sizeof (c->input_buffer);
299   md5_add (c, padding, n_pad);
300
301   c->input_buffer.b64[ARRAY_LEN (c->input_buffer.b64) - 1]
302     = clib_host_to_little_u64 (n_bits_save);
303
304   md5_transform (c, c->input_buffer.b32,
305                  (u32 *) digest,
306                  /* zero_buffer */ 1);
307 }