Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /* memxor3.c  | 
2  |  |  | 
3  |  |    Copyright (C) 2010, 2014 Niels Möller  | 
4  |  |  | 
5  |  |    This file is part of GNU Nettle.  | 
6  |  |  | 
7  |  |    GNU Nettle is free software: you can redistribute it and/or  | 
8  |  |    modify it under the terms of either:  | 
9  |  |  | 
10  |  |      * the GNU Lesser General Public License as published by the Free  | 
11  |  |        Software Foundation; either version 3 of the License, or (at your  | 
12  |  |        option) any later version.  | 
13  |  |  | 
14  |  |    or  | 
15  |  |  | 
16  |  |      * the GNU General Public License as published by the Free  | 
17  |  |        Software Foundation; either version 2 of the License, or (at your  | 
18  |  |        option) any later version.  | 
19  |  |  | 
20  |  |    or both in parallel, as here.  | 
21  |  |  | 
22  |  |    GNU Nettle is distributed in the hope that it will be useful,  | 
23  |  |    but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
24  |  |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  | 
25  |  |    General Public License for more details.  | 
26  |  |  | 
27  |  |    You should have received copies of the GNU General Public License and  | 
28  |  |    the GNU Lesser General Public License along with this program.  If  | 
29  |  |    not, see http://www.gnu.org/licenses/.  | 
30  |  | */  | 
31  |  |  | 
32  |  | /* Implementation inspired by memcmp in glibc, contributed to the FSF  | 
33  |  |    by Torbjorn Granlund.  | 
34  |  |  */  | 
35  |  |  | 
36  |  | #if HAVE_CONFIG_H  | 
37  |  | # include "config.h"  | 
38  |  | #endif  | 
39  |  |  | 
40  |  | #include <assert.h>  | 
41  |  | #include <limits.h>  | 
42  |  |  | 
43  |  | #include "memxor.h"  | 
44  |  | #include "memxor-internal.h"  | 
45  |  |  | 
46  | 0  | #define WORD_T_THRESH 16  | 
47  |  |  | 
48  |  | /* For fat builds */  | 
49  |  | #if HAVE_NATIVE_memxor3  | 
50  |  | void *  | 
51  |  | _nettle_memxor3_c(void *dst_in, const void *a_in, const void *b_in, size_t n);  | 
52  |  | # define nettle_memxor3 _nettle_memxor3_c  | 
53  |  | #endif  | 
54  |  |  | 
55  |  | /* XOR word-aligned areas. n is the number of words, not bytes. */  | 
56  |  | static void  | 
57  |  | memxor3_common_alignment (word_t *dst,  | 
58  |  |         const word_t *a, const word_t *b, size_t n)  | 
59  | 0  | { | 
60  |  |   /* FIXME: Require n > 0? */  | 
61  | 0  |   if (n & 1)  | 
62  | 0  |     { | 
63  | 0  |       n--;  | 
64  | 0  |       dst[n] = a[n] ^ b[n];  | 
65  | 0  |     }  | 
66  | 0  |   while (n > 0)  | 
67  | 0  |     { | 
68  | 0  |       n -= 2;  | 
69  | 0  |       dst[n+1] = a[n+1] ^ b[n+1];  | 
70  | 0  |       dst[n] = a[n] ^ b[n];  | 
71  | 0  |     }  | 
72  | 0  | }  | 
73  |  |  | 
74  |  | static void  | 
75  |  | memxor3_different_alignment_b (word_t *dst,  | 
76  |  |              const word_t *a, const unsigned char *b,  | 
77  |  |              unsigned offset, size_t n)  | 
78  | 0  | { | 
79  | 0  |   int shl, shr;  | 
80  | 0  |   const word_t *b_word;  | 
81  |  | 
  | 
82  | 0  |   word_t s0, s1;  | 
83  |  | 
  | 
84  | 0  |   assert (n > 0);  | 
85  |  |  | 
86  | 0  |   shl = CHAR_BIT * offset;  | 
87  | 0  |   shr = CHAR_BIT * (sizeof(word_t) - offset);  | 
88  |  | 
  | 
89  | 0  |   b_word = (const word_t *) ((uintptr_t) b & -sizeof(word_t));  | 
90  |  |  | 
91  |  |   /* Read top offset bytes, in native byte order. */  | 
92  | 0  |   READ_PARTIAL (s0, (unsigned char *) &b_word[n], offset);  | 
93  |  | #ifdef WORDS_BIGENDIAN  | 
94  |  |   s0 <<= shr;  | 
95  |  | #endif  | 
96  |  | 
  | 
97  | 0  |   if (n & 1)  | 
98  | 0  |     s1 = s0;  | 
99  | 0  |   else  | 
100  | 0  |     { | 
101  | 0  |       n--;  | 
102  | 0  |       s1 = b_word[n];  | 
103  | 0  |       dst[n] = a[n] ^ MERGE (s1, shl, s0, shr);  | 
104  | 0  |     }  | 
105  |  | 
  | 
106  | 0  |   while (n > 2)  | 
107  | 0  |     { | 
108  | 0  |       n -= 2;  | 
109  | 0  |       s0 = b_word[n+1];  | 
110  | 0  |       dst[n+1] = a[n+1] ^ MERGE(s0, shl, s1, shr);  | 
111  | 0  |       s1 = b_word[n];  | 
112  | 0  |       dst[n] = a[n] ^ MERGE(s1, shl, s0, shr);  | 
113  | 0  |     }  | 
114  | 0  |   assert (n == 1);  | 
115  |  |   /* Read low wordsize - offset bytes */  | 
116  | 0  |   READ_PARTIAL (s0, b, sizeof(word_t) - offset);  | 
117  | 0  | #ifndef WORDS_BIGENDIAN  | 
118  | 0  |   s0 <<= shl;  | 
119  | 0  | #endif /* !WORDS_BIGENDIAN */  | 
120  |  | 
  | 
121  | 0  |   dst[0] = a[0] ^ MERGE(s0, shl, s1, shr);  | 
122  | 0  | }  | 
123  |  |  | 
124  |  | static void  | 
125  |  | memxor3_different_alignment_ab (word_t *dst,  | 
126  |  |         const unsigned char *a, const unsigned char *b,  | 
127  |  |         unsigned offset, size_t n)  | 
128  | 0  | { | 
129  | 0  |   int shl, shr;  | 
130  | 0  |   const word_t *a_word;  | 
131  | 0  |   const word_t *b_word;  | 
132  |  | 
  | 
133  | 0  |   word_t s0, s1, t;  | 
134  |  | 
  | 
135  | 0  |   assert (n > 0);  | 
136  |  |  | 
137  | 0  |   shl = CHAR_BIT * offset;  | 
138  | 0  |   shr = CHAR_BIT * (sizeof(word_t) - offset);  | 
139  |  | 
  | 
140  | 0  |   a_word = (const word_t *) ((uintptr_t) a & -sizeof(word_t));  | 
141  | 0  |   b_word = (const word_t *) ((uintptr_t) b & -sizeof(word_t));  | 
142  |  |  | 
143  |  |   /* Read top offset bytes, in native byte order. */  | 
144  | 0  |   READ_PARTIAL (s0, (unsigned char *) &a_word[n], offset);  | 
145  | 0  |   READ_PARTIAL (t,  (unsigned char *) &b_word[n], offset);  | 
146  | 0  |   s0 ^= t;  | 
147  |  | #ifdef WORDS_BIGENDIAN  | 
148  |  |   s0 <<= shr;  | 
149  |  | #endif  | 
150  |  | 
  | 
151  | 0  |   if (n & 1)  | 
152  | 0  |     s1 = s0;  | 
153  | 0  |   else  | 
154  | 0  |     { | 
155  | 0  |       n--;  | 
156  | 0  |       s1 = a_word[n] ^ b_word[n];  | 
157  | 0  |       dst[n] = MERGE (s1, shl, s0, shr);  | 
158  | 0  |     }  | 
159  |  | 
  | 
160  | 0  |   while (n > 2)  | 
161  | 0  |     { | 
162  | 0  |       n -= 2;  | 
163  | 0  |       s0 = a_word[n+1] ^ b_word[n+1];  | 
164  | 0  |       dst[n+1] = MERGE(s0, shl, s1, shr);  | 
165  | 0  |       s1 = a_word[n] ^ b_word[n];  | 
166  | 0  |       dst[n] = MERGE(s1, shl, s0, shr);  | 
167  | 0  |     }  | 
168  | 0  |   assert (n == 1);  | 
169  |  |   /* Read low wordsize - offset bytes */  | 
170  | 0  |   READ_PARTIAL (s0, a, sizeof(word_t) - offset);  | 
171  | 0  |   READ_PARTIAL (t,  b, sizeof(word_t) - offset);  | 
172  | 0  |   s0 ^= t;  | 
173  | 0  | #ifndef WORDS_BIGENDIAN  | 
174  | 0  |   s0 <<= shl;  | 
175  | 0  | #endif /* !WORDS_BIGENDIAN */  | 
176  |  | 
  | 
177  | 0  |   dst[0] = MERGE(s0, shl, s1, shr);  | 
178  | 0  | }  | 
179  |  |  | 
180  |  | static void  | 
181  |  | memxor3_different_alignment_all (word_t *dst,  | 
182  |  |          const unsigned char *a, const unsigned char *b,  | 
183  |  |          unsigned a_offset, unsigned b_offset,  | 
184  |  |          size_t n)  | 
185  | 0  | { | 
186  | 0  |   int al, ar, bl, br;  | 
187  | 0  |   const word_t *a_word;  | 
188  | 0  |   const word_t *b_word;  | 
189  |  | 
  | 
190  | 0  |   word_t a0, a1, b0, b1;  | 
191  |  | 
  | 
192  | 0  |   al = CHAR_BIT * a_offset;  | 
193  | 0  |   ar = CHAR_BIT * (sizeof(word_t) - a_offset);  | 
194  | 0  |   bl = CHAR_BIT * b_offset;  | 
195  | 0  |   br = CHAR_BIT * (sizeof(word_t) - b_offset);  | 
196  |  | 
  | 
197  | 0  |   a_word = (const word_t *) ((uintptr_t) a & -sizeof(word_t));  | 
198  | 0  |   b_word = (const word_t *) ((uintptr_t) b & -sizeof(word_t));  | 
199  |  |  | 
200  |  |   /* Read top offset bytes, in native byte order. */  | 
201  | 0  |   READ_PARTIAL (a0, (unsigned char *) &a_word[n], a_offset);  | 
202  | 0  |   READ_PARTIAL (b0, (unsigned char *) &b_word[n], b_offset);  | 
203  |  | #ifdef WORDS_BIGENDIAN  | 
204  |  |   a0 <<= ar;  | 
205  |  |   b0 <<= br;  | 
206  |  | #endif  | 
207  |  | 
  | 
208  | 0  |   if (n & 1)  | 
209  | 0  |     { | 
210  | 0  |       a1 = a0; b1 = b0;  | 
211  | 0  |     }  | 
212  | 0  |   else  | 
213  | 0  |     { | 
214  | 0  |       n--;  | 
215  | 0  |       a1 = a_word[n];  | 
216  | 0  |       b1 = b_word[n];  | 
217  |  | 
  | 
218  | 0  |       dst[n] = MERGE (a1, al, a0, ar) ^ MERGE (b1, bl, b0, br);  | 
219  | 0  |     }  | 
220  | 0  |   while (n > 2)  | 
221  | 0  |     { | 
222  | 0  |       n -= 2;  | 
223  | 0  |       a0 = a_word[n+1]; b0 = b_word[n+1];  | 
224  | 0  |       dst[n+1] = MERGE(a0, al, a1, ar) ^ MERGE(b0, bl, b1, br);  | 
225  | 0  |       a1 = a_word[n]; b1 = b_word[n];  | 
226  | 0  |       dst[n] = MERGE(a1, al, a0, ar) ^ MERGE(b1, bl, b0, br);  | 
227  | 0  |     }  | 
228  | 0  |   assert (n == 1);  | 
229  |  |   /* Read low wordsize - offset bytes */  | 
230  | 0  |   READ_PARTIAL (a0, a, sizeof(word_t) - a_offset);  | 
231  | 0  |   READ_PARTIAL (b0, b, sizeof(word_t) - b_offset);  | 
232  | 0  | #ifndef WORDS_BIGENDIAN  | 
233  | 0  |   a0 <<= al;  | 
234  | 0  |   b0 <<= bl;  | 
235  | 0  | #endif /* !WORDS_BIGENDIAN */  | 
236  |  | 
  | 
237  | 0  |   dst[0] = MERGE(a0, al, a1, ar) ^ MERGE(b0, bl, b1, br);  | 
238  | 0  | }  | 
239  |  |  | 
240  |  | /* Current implementation processes data in descending order, to  | 
241  |  |    support overlapping operation with one of the sources overlapping  | 
242  |  |    the start of the destination area. This feature is used only  | 
243  |  |    internally by cbc decrypt, and it is not advertised or documented  | 
244  |  |    to nettle users. */  | 
245  |  | void *  | 
246  |  | nettle_memxor3(void *dst_in, const void *a_in,   | 
247  |  |          const void *b_in, size_t n)  | 
248  | 0  | { | 
249  | 0  |   unsigned char *dst = dst_in;  | 
250  | 0  |   const unsigned char *a = a_in;  | 
251  | 0  |   const unsigned char *b = b_in;  | 
252  |  | 
  | 
253  | 0  |   if (n >= WORD_T_THRESH)  | 
254  | 0  |     { | 
255  | 0  |       unsigned i;  | 
256  | 0  |       unsigned a_offset;  | 
257  | 0  |       unsigned b_offset;  | 
258  | 0  |       size_t nwords;  | 
259  |  | 
  | 
260  | 0  |       for (i = ALIGN_OFFSET(dst + n); i > 0; i--)  | 
261  | 0  |   { | 
262  | 0  |     n--;  | 
263  | 0  |     dst[n] = a[n] ^ b[n];  | 
264  | 0  |   }  | 
265  |  | 
  | 
266  | 0  |       a_offset = ALIGN_OFFSET(a + n);  | 
267  | 0  |       b_offset = ALIGN_OFFSET(b + n);  | 
268  |  | 
  | 
269  | 0  |       nwords = n / sizeof (word_t);  | 
270  | 0  |       n %= sizeof (word_t);  | 
271  |  | 
  | 
272  | 0  |       if (a_offset == b_offset)  | 
273  | 0  |   { | 
274  | 0  |     if (!a_offset)  | 
275  | 0  |       memxor3_common_alignment((word_t *) (dst + n),  | 
276  | 0  |              (const word_t *) (a + n),  | 
277  | 0  |              (const word_t *) (b + n), nwords);  | 
278  | 0  |     else  | 
279  | 0  |       memxor3_different_alignment_ab((word_t *) (dst + n),  | 
280  | 0  |              a + n, b + n, a_offset,  | 
281  | 0  |              nwords);  | 
282  | 0  |   }  | 
283  | 0  |       else if (!a_offset)  | 
284  | 0  |   memxor3_different_alignment_b((word_t *) (dst + n),  | 
285  | 0  |               (const word_t *) (a + n), b + n,  | 
286  | 0  |               b_offset, nwords);  | 
287  | 0  |       else if (!b_offset)  | 
288  | 0  |   memxor3_different_alignment_b((word_t *) (dst + n),  | 
289  | 0  |               (const word_t *) (b + n), a + n,  | 
290  | 0  |               a_offset, nwords);  | 
291  | 0  |       else  | 
292  | 0  |   memxor3_different_alignment_all((word_t *) (dst + n), a + n, b + n,  | 
293  | 0  |           a_offset, b_offset, nwords);  | 
294  |  | 
  | 
295  | 0  |     }  | 
296  | 0  |   while (n-- > 0)  | 
297  | 0  |     dst[n] = a[n] ^ b[n];  | 
298  |  | 
  | 
299  | 0  |   return dst;  | 
300  | 0  | }  |