|
1 /** |
|
2 * XML Security Library (http://www.aleksey.com/xmlsec). |
|
3 * |
|
4 * Big Numbers. |
|
5 * |
|
6 * This is free software; see Copyright file in the source |
|
7 * distribution for preciese wording. |
|
8 * |
|
9 * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> |
|
10 * Copyright (C) 2003 Cordys R&D BV, All rights reserved. |
|
11 * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
12 */ |
|
13 #include "xmlsec_globals.h" |
|
14 |
|
15 #include <stdlib.h> |
|
16 #include <string.h> |
|
17 #include <ctype.h> |
|
18 |
|
19 #include <libxml2_tree.h> |
|
20 #include <libxml2_globals.h> |
|
21 |
|
22 #include "xmlsec_xmlsec.h" |
|
23 #include "xmlsec_xmltree.h" |
|
24 #include "xmlsec_base64.h" |
|
25 #include "xmlsec_bn.h" |
|
26 #include "xmlsec_errors.h" |
|
27 |
|
28 /* table for converting hex digits back to bytes */ |
|
29 static const int xmlSecBnLookupTable[] = |
|
30 { |
|
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
34 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, |
|
35 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
36 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
37 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
38 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
39 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
40 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
41 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
42 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
43 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
44 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
45 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|
46 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 |
|
47 }; |
|
48 |
|
49 static const char xmlSecBnRevLookupTable[] = |
|
50 { |
|
51 '0', '1', '2', '3', '4', '5', '6', '7', |
|
52 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' |
|
53 }; |
|
54 |
|
55 /***************************************************************************** |
|
56 * |
|
57 * xmlSecBn |
|
58 * |
|
59 ****************************************************************************/ |
|
60 /** |
|
61 * xmlSecBnCreate: |
|
62 * @size: the initial allocated BN size. |
|
63 * |
|
64 * Creates a new BN object. Caller is responsible for destroying it |
|
65 * by calling @xmlSecBnDestroy function. |
|
66 * |
|
67 * Returns the newly BN or a NULL if an error occurs. |
|
68 */ |
|
69 EXPORT_C |
|
70 xmlSecBnPtr |
|
71 xmlSecBnCreate(xmlSecSize size) { |
|
72 return(xmlSecBufferCreate(size)); |
|
73 } |
|
74 |
|
75 /** |
|
76 * xmlSecBnDestroy: |
|
77 * @bn: the pointer to BN. |
|
78 * |
|
79 * Destroys @bn object created with @xmlSecBnCreate function. |
|
80 */ |
|
81 EXPORT_C |
|
82 void |
|
83 xmlSecBnDestroy(xmlSecBnPtr bn) { |
|
84 xmlSecBufferDestroy(bn); |
|
85 } |
|
86 |
|
87 /** |
|
88 * xmlSecBnInitialize: |
|
89 * @bn: the pointer to BN. |
|
90 * @size: the initial allocated BN size. |
|
91 * |
|
92 * Initializes a BN object. Caller is responsible for destroying it |
|
93 * by calling @xmlSecBnFinalize function. |
|
94 * |
|
95 * Returns 0 on success or a negative value if an error occurs. |
|
96 */ |
|
97 EXPORT_C |
|
98 int |
|
99 xmlSecBnInitialize(xmlSecBnPtr bn, xmlSecSize size) { |
|
100 return(xmlSecBufferInitialize(bn, size)); |
|
101 } |
|
102 |
|
103 /** |
|
104 * xmlSecBnFinalize: |
|
105 * @bn: the pointer to BN. |
|
106 * |
|
107 * Destroys @bn object created with @xmlSecBnInitialize function. |
|
108 */ |
|
109 EXPORT_C |
|
110 void |
|
111 xmlSecBnFinalize(xmlSecBnPtr bn) { |
|
112 xmlSecBufferFinalize(bn); |
|
113 } |
|
114 |
|
115 /** |
|
116 * xmlSecBnGetData: |
|
117 * @bn: the pointer to BN. |
|
118 * |
|
119 * Gets pointer to the binary @bn representation. |
|
120 * |
|
121 * Returns pointer to binary BN data or NULL if an error occurs. |
|
122 */ |
|
123 EXPORT_C |
|
124 xmlSecByte* |
|
125 xmlSecBnGetData(xmlSecBnPtr bn) { |
|
126 return(xmlSecBufferGetData(bn)); |
|
127 } |
|
128 |
|
129 /** |
|
130 * xmlSecBnSetData: |
|
131 * @bn: the pointer to BN. |
|
132 * @data: the pointer to new BN binary data. |
|
133 * @size: the size of new BN data. |
|
134 * |
|
135 * Sets the value of @bn to @data. |
|
136 * |
|
137 * Returns 0 on success or a negative value if an error occurs. |
|
138 */ |
|
139 EXPORT_C |
|
140 int |
|
141 xmlSecBnSetData(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize size) { |
|
142 return(xmlSecBufferSetData(bn, data, size)); |
|
143 } |
|
144 |
|
145 /** |
|
146 * xmlSecBnGetSize: |
|
147 * @bn: the pointer to BN. |
|
148 * |
|
149 * Gets the size of binary data in @bn. |
|
150 * |
|
151 * Returns the size of binary data. |
|
152 */ |
|
153 EXPORT_C |
|
154 xmlSecSize |
|
155 xmlSecBnGetSize(xmlSecBnPtr bn) { |
|
156 return(xmlSecBufferGetSize(bn)); |
|
157 } |
|
158 |
|
159 /** |
|
160 * xmlSecBnZero: |
|
161 * @bn: the pointer to BN. |
|
162 * |
|
163 * Sets the value of @bn to zero. |
|
164 */ |
|
165 EXPORT_C |
|
166 void |
|
167 xmlSecBnZero(xmlSecBnPtr bn) { |
|
168 xmlSecBufferEmpty(bn); |
|
169 } |
|
170 |
|
171 /** |
|
172 * xmlSecBnFromString: |
|
173 * @bn: the pointer to BN. |
|
174 * @str: the string with BN. |
|
175 * @base: the base for @str. |
|
176 * |
|
177 * Reads @bn from string @str assuming it has base @base. |
|
178 * |
|
179 * Returns 0 on success or a negative value if an error occurs. |
|
180 */ |
|
181 EXPORT_C |
|
182 int |
|
183 xmlSecBnFromString(xmlSecBnPtr bn, const xmlChar* str, xmlSecSize base) { |
|
184 xmlSecSize i, len, size; |
|
185 xmlSecByte ch; |
|
186 xmlSecByte* data; |
|
187 int positive; |
|
188 int nn; |
|
189 int ret; |
|
190 |
|
191 xmlSecAssert2(bn != NULL, -1); |
|
192 xmlSecAssert2(str != NULL, -1); |
|
193 xmlSecAssert2(base > 1, -1); |
|
194 xmlSecAssert2(base <= sizeof(xmlSecBnRevLookupTable), -1); |
|
195 |
|
196 /* trivial case */ |
|
197 len = xmlStrlen(str); |
|
198 if(len == 0) { |
|
199 return(0); |
|
200 } |
|
201 |
|
202 /* The result size could not exceed the input string length |
|
203 * because each char fits inside a byte in all cases :) |
|
204 * In truth, it would be likely less than 1/2 input string length |
|
205 * because each byte is represented by 2 chars. If needed, |
|
206 * buffer size would be increased by Mul/Add functions. |
|
207 * Finally, we can add one byte for 00 or 10 prefix. |
|
208 */ |
|
209 ret = xmlSecBufferSetMaxSize(bn, xmlSecBufferGetSize(bn) + len / 2 + 1 + 1); |
|
210 if(ret < 0) { |
|
211 xmlSecError(XMLSEC_ERRORS_HERE, |
|
212 NULL, |
|
213 "xmlSecBnRevLookupTable", |
|
214 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
215 "size=%d", len / 2 + 1); |
|
216 return (-1); |
|
217 } |
|
218 |
|
219 /* figure out if it is positive or negative number */ |
|
220 positive = 1; |
|
221 i = 0; |
|
222 while(i < len) { |
|
223 ch = str[i++]; |
|
224 |
|
225 /* skip spaces */ |
|
226 if(isspace(ch)) { |
|
227 continue; |
|
228 } |
|
229 |
|
230 /* check if it is + or - */ |
|
231 if(ch == '+') { |
|
232 positive = 1; |
|
233 break; |
|
234 } else if(ch == '-') { |
|
235 positive = 0; |
|
236 break; |
|
237 } |
|
238 |
|
239 /* otherwise, it must be start of the number */ |
|
240 nn = xmlSecBnLookupTable[ch]; |
|
241 if((nn >= 0) && ((xmlSecSize)nn < base)) { |
|
242 xmlSecAssert2(i > 0, -1); |
|
243 |
|
244 /* no sign, positive by default */ |
|
245 positive = 1; |
|
246 --i; /* make sure that we will look at this character in next loop */ |
|
247 break; |
|
248 } else { |
|
249 xmlSecError(XMLSEC_ERRORS_HERE, |
|
250 NULL, |
|
251 NULL, |
|
252 XMLSEC_ERRORS_R_INVALID_DATA, |
|
253 "char=%c;base=%d", |
|
254 ch, base); |
|
255 return (-1); |
|
256 } |
|
257 } |
|
258 |
|
259 /* now parse the number itself */ |
|
260 while(i < len) { |
|
261 ch = str[i++]; |
|
262 if(isspace(ch)) { |
|
263 continue; |
|
264 } |
|
265 |
|
266 xmlSecAssert2(ch <= sizeof(xmlSecBnLookupTable), -1); |
|
267 nn = xmlSecBnLookupTable[ch]; |
|
268 if((nn < 0) || ((xmlSecSize)nn > base)) { |
|
269 xmlSecError(XMLSEC_ERRORS_HERE, |
|
270 NULL, |
|
271 NULL, |
|
272 XMLSEC_ERRORS_R_INVALID_DATA, |
|
273 "char=%c;base=%d", |
|
274 ch, base); |
|
275 return (-1); |
|
276 } |
|
277 |
|
278 ret = xmlSecBnMul(bn, base); |
|
279 if(ret < 0) { |
|
280 xmlSecError(XMLSEC_ERRORS_HERE, |
|
281 NULL, |
|
282 "xmlSecBnMul", |
|
283 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
284 "base=%d", base); |
|
285 return (-1); |
|
286 } |
|
287 |
|
288 ret = xmlSecBnAdd(bn, nn); |
|
289 if(ret < 0) { |
|
290 xmlSecError(XMLSEC_ERRORS_HERE, |
|
291 NULL, |
|
292 "xmlSecBnAdd", |
|
293 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
294 "base=%d", base); |
|
295 return (-1); |
|
296 } |
|
297 } |
|
298 |
|
299 /* check if we need to add 00 prefix, do this for empty bn too */ |
|
300 data = xmlSecBufferGetData(bn); |
|
301 size = xmlSecBufferGetSize(bn); |
|
302 if(((size > 0) && (data[0] > 127)) || (size == 0)) { |
|
303 ch = 0; |
|
304 ret = xmlSecBufferPrepend(bn, &ch, 1); |
|
305 if(ret < 0) { |
|
306 xmlSecError(XMLSEC_ERRORS_HERE, |
|
307 NULL, |
|
308 "xmlSecBufferPrepend", |
|
309 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
310 "base=%d", base); |
|
311 return (-1); |
|
312 } |
|
313 } |
|
314 |
|
315 /* do 2's compliment and add 1 to represent negative value */ |
|
316 if(positive == 0) { |
|
317 data = xmlSecBufferGetData(bn); |
|
318 size = xmlSecBufferGetSize(bn); |
|
319 for(i = 0; i < size; ++i) { |
|
320 data[i] ^= 0xFF; |
|
321 } |
|
322 |
|
323 ret = xmlSecBnAdd(bn, 1); |
|
324 if(ret < 0) { |
|
325 xmlSecError(XMLSEC_ERRORS_HERE, |
|
326 NULL, |
|
327 "xmlSecBnAdd", |
|
328 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
329 "base=%d", base); |
|
330 return (-1); |
|
331 } |
|
332 } |
|
333 |
|
334 return(0); |
|
335 } |
|
336 |
|
337 /** |
|
338 * xmlSecBnToString: |
|
339 * @bn: the pointer to BN. |
|
340 * @base: the base for returned string. |
|
341 * |
|
342 * Writes @bn to string with base @base. Caller is responsible for |
|
343 * freeing returned string with @xmlFree. |
|
344 * |
|
345 * Returns the string represenataion if BN or a NULL if an error occurs. |
|
346 */ |
|
347 EXPORT_C |
|
348 xmlChar* |
|
349 xmlSecBnToString(xmlSecBnPtr bn, xmlSecSize base) { |
|
350 xmlSecBn bn2; |
|
351 int positive = 1; |
|
352 xmlChar* res; |
|
353 xmlSecSize i, len, size; |
|
354 xmlSecByte* data; |
|
355 int ret; |
|
356 int nn; |
|
357 xmlChar ch; |
|
358 |
|
359 xmlSecAssert2(bn != NULL, NULL); |
|
360 xmlSecAssert2(base > 1, NULL); |
|
361 xmlSecAssert2(base <= sizeof(xmlSecBnRevLookupTable), NULL); |
|
362 |
|
363 |
|
364 /* copy bn */ |
|
365 data = xmlSecBufferGetData(bn); |
|
366 size = xmlSecBufferGetSize(bn); |
|
367 ret = xmlSecBnInitialize(&bn2, size); |
|
368 if(ret < 0) { |
|
369 xmlSecError(XMLSEC_ERRORS_HERE, |
|
370 NULL, |
|
371 "xmlSecBnCreate", |
|
372 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
373 "size=%d", size); |
|
374 return (NULL); |
|
375 } |
|
376 |
|
377 ret = xmlSecBnSetData(&bn2, data, size); |
|
378 if(ret < 0) { |
|
379 xmlSecError(XMLSEC_ERRORS_HERE, |
|
380 NULL, |
|
381 "xmlSecBnSetData", |
|
382 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
383 "size=%d", size); |
|
384 xmlSecBnFinalize(&bn2); |
|
385 return (NULL); |
|
386 } |
|
387 |
|
388 /* check if it is a negative number or not */ |
|
389 data = xmlSecBufferGetData(&bn2); |
|
390 size = xmlSecBufferGetSize(&bn2); |
|
391 if((size > 0) && (data[0] > 127)) { |
|
392 /* subtract 1 and do 2's compliment */ |
|
393 ret = xmlSecBnAdd(&bn2, -1); |
|
394 if(ret < 0) { |
|
395 xmlSecError(XMLSEC_ERRORS_HERE, |
|
396 NULL, |
|
397 "xmlSecBnAdd", |
|
398 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
399 "size=%d", size); |
|
400 xmlSecBnFinalize(&bn2); |
|
401 return (NULL); |
|
402 } |
|
403 for(i = 0; i < size; ++i) { |
|
404 data[i] ^= 0xFF; |
|
405 } |
|
406 |
|
407 positive = 0; |
|
408 } else { |
|
409 positive = 1; |
|
410 } |
|
411 |
|
412 /* Result string len is |
|
413 * len = log base (256) * <bn size> |
|
414 * Since the smallest base == 2 then we can get away with |
|
415 * len = 8 * <bn size> |
|
416 */ |
|
417 len = 8 * size + 1 + 1; |
|
418 res = (xmlChar*)xmlMalloc(len + 1); |
|
419 if(res == NULL) { |
|
420 xmlSecError(XMLSEC_ERRORS_HERE, |
|
421 NULL, |
|
422 NULL, |
|
423 XMLSEC_ERRORS_R_MALLOC_FAILED, |
|
424 "len=%d", len); |
|
425 xmlSecBnFinalize(&bn2); |
|
426 return (NULL); |
|
427 } |
|
428 memset(res, 0, len + 1); |
|
429 |
|
430 for(i = 0; (xmlSecBufferGetSize(&bn2) > 0) && (i < len); i++) { |
|
431 if(xmlSecBnDiv(&bn2, base, &nn) < 0) { |
|
432 xmlSecError(XMLSEC_ERRORS_HERE, |
|
433 NULL, |
|
434 "xmlSecBnDiv", |
|
435 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
436 "base=%d", base); |
|
437 xmlFree(res); |
|
438 xmlSecBnFinalize(&bn2); |
|
439 return (NULL); |
|
440 } |
|
441 xmlSecAssert2((size_t)nn < sizeof(xmlSecBnRevLookupTable), NULL); |
|
442 res[i] = xmlSecBnRevLookupTable[nn]; |
|
443 } |
|
444 xmlSecAssert2(i < len, NULL); |
|
445 |
|
446 /* we might have '0' at the beggining, remove it but keep one zero */ |
|
447 for(len = i; (len > 1) && (res[len - 1] == '0'); len--) |
|
448 { |
|
449 }; |
|
450 res[len] = '\0'; |
|
451 |
|
452 /* add "-" for negative numbers */ |
|
453 if(positive == 0) { |
|
454 res[len] = '-'; |
|
455 res[++len] = '\0'; |
|
456 } |
|
457 |
|
458 /* swap the string because we wrote it in reverse order */ |
|
459 for(i = 0; i < len / 2; i++) { |
|
460 ch = res[i]; |
|
461 res[i] = res[len - i - 1]; |
|
462 res[len - i - 1] = ch; |
|
463 } |
|
464 |
|
465 xmlSecBnFinalize(&bn2); |
|
466 return(res); |
|
467 } |
|
468 |
|
469 /** |
|
470 * xmlSecBnFromHexString: |
|
471 * @bn: the pointer to BN. |
|
472 * @str: the string with BN. |
|
473 * |
|
474 * Reads @bn from hex string @str. |
|
475 * |
|
476 * Returns 0 on success or a negative value if an error occurs. |
|
477 */ |
|
478 EXPORT_C |
|
479 int |
|
480 xmlSecBnFromHexString(xmlSecBnPtr bn, const xmlChar* str) { |
|
481 return(xmlSecBnFromString(bn, str, 16)); |
|
482 } |
|
483 |
|
484 /** |
|
485 * xmlSecBnToHexString: |
|
486 * @bn: the pointer to BN. |
|
487 * |
|
488 * Writes @bn to hex string. Caller is responsible for |
|
489 * freeing returned string with @xmlFree. |
|
490 * |
|
491 * Returns the string represenataion if BN or a NULL if an error occurs. |
|
492 */ |
|
493 EXPORT_C |
|
494 xmlChar* |
|
495 xmlSecBnToHexString(xmlSecBnPtr bn) { |
|
496 return(xmlSecBnToString(bn, 16)); |
|
497 } |
|
498 |
|
499 /** |
|
500 * xmlSecBnFromDecString: |
|
501 * @bn: the pointer to BN. |
|
502 * @str: the string with BN. |
|
503 * |
|
504 * Reads @bn from decimal string @str. |
|
505 * |
|
506 * Returns 0 on success or a negative value if an error occurs. |
|
507 */ |
|
508 EXPORT_C |
|
509 int |
|
510 xmlSecBnFromDecString(xmlSecBnPtr bn, const xmlChar* str) { |
|
511 return(xmlSecBnFromString(bn, str, 10)); |
|
512 } |
|
513 |
|
514 /** |
|
515 * xmlSecBnToDecString: |
|
516 * @bn: the pointer to BN. |
|
517 * |
|
518 * Writes @bn to decimal string. Caller is responsible for |
|
519 * freeing returned string with @xmlFree. |
|
520 * |
|
521 * Returns the string represenataion if BN or a NULL if an error occurs. |
|
522 */ |
|
523 EXPORT_C |
|
524 xmlChar* |
|
525 xmlSecBnToDecString(xmlSecBnPtr bn) { |
|
526 return(xmlSecBnToString(bn, 10)); |
|
527 } |
|
528 |
|
529 /** |
|
530 * xmlSecBnMul: |
|
531 * @bn: the pointer to BN. |
|
532 * @multiplier: the multiplier. |
|
533 * |
|
534 * Multiplies @bn with @multiplier. |
|
535 * |
|
536 * Returns 0 on success or a negative value if an error occurs. |
|
537 */ |
|
538 EXPORT_C |
|
539 int |
|
540 xmlSecBnMul(xmlSecBnPtr bn, int multiplier) { |
|
541 xmlSecByte* data; |
|
542 int over; |
|
543 xmlSecSize i; |
|
544 xmlSecByte ch; |
|
545 int ret; |
|
546 |
|
547 xmlSecAssert2(bn != NULL, -1); |
|
548 xmlSecAssert2(multiplier > 0, -1); |
|
549 |
|
550 if(multiplier == 1) { |
|
551 return(0); |
|
552 } |
|
553 |
|
554 data = xmlSecBufferGetData(bn); |
|
555 i = xmlSecBufferGetSize(bn); |
|
556 over = 0; |
|
557 while(i > 0) { |
|
558 xmlSecAssert2(data != NULL, -1); |
|
559 |
|
560 over = over + multiplier * data[--i]; |
|
561 data[i] = over % 256; |
|
562 over = over / 256; |
|
563 } |
|
564 |
|
565 while(over > 0) { |
|
566 ch = over % 256; |
|
567 over = over / 256; |
|
568 |
|
569 ret = xmlSecBufferPrepend(bn, &ch, 1); |
|
570 if(ret < 0) { |
|
571 xmlSecError(XMLSEC_ERRORS_HERE, |
|
572 NULL, |
|
573 "xmlSecBufferPrepend", |
|
574 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
575 "size=1"); |
|
576 return (-1); |
|
577 } |
|
578 } |
|
579 |
|
580 return(0); |
|
581 } |
|
582 |
|
583 /** |
|
584 * xmlSecBnDiv: |
|
585 * @bn: the pointer to BN. |
|
586 * @divider: the divider |
|
587 * @mod: the pointer for modulus result. |
|
588 * |
|
589 * Divides @bn by @divider and places modulus into @mod. |
|
590 * |
|
591 * Returns 0 on success or a negative value if an error occurs. |
|
592 */ |
|
593 EXPORT_C |
|
594 int |
|
595 xmlSecBnDiv(xmlSecBnPtr bn, int divider, int* mod) { |
|
596 int over; |
|
597 xmlSecSize i, size; |
|
598 xmlSecByte* data; |
|
599 int ret; |
|
600 |
|
601 xmlSecAssert2(bn != NULL, -1); |
|
602 xmlSecAssert2(divider > 0, -1); |
|
603 xmlSecAssert2(mod != NULL, -1); |
|
604 |
|
605 if(divider == 1) { |
|
606 return(0); |
|
607 } |
|
608 |
|
609 data = xmlSecBufferGetData(bn); |
|
610 size = xmlSecBufferGetSize(bn); |
|
611 for(over = 0, i = 0; i < size; i++) { |
|
612 xmlSecAssert2(data != NULL, -1); |
|
613 |
|
614 over = over * 256 + data[i]; |
|
615 data[i] = over / divider; |
|
616 over = over % divider; |
|
617 } |
|
618 (*mod) = over; |
|
619 |
|
620 /* remove leading zeros */ |
|
621 for(i = 0; i < size; i++) { |
|
622 xmlSecAssert2(data != NULL, -1); |
|
623 |
|
624 if(data[i] != 0) { |
|
625 break; |
|
626 } |
|
627 } |
|
628 if(i > 0) { |
|
629 ret = xmlSecBufferRemoveHead(bn, i); |
|
630 if(ret < 0) { |
|
631 xmlSecError(XMLSEC_ERRORS_HERE, |
|
632 NULL, |
|
633 "xmlSecBufferRemoveHead", |
|
634 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
635 "size=%d", i); |
|
636 return (-1); |
|
637 } |
|
638 } |
|
639 return(0); |
|
640 } |
|
641 |
|
642 /** |
|
643 * xmlSecBnAdd: |
|
644 * @bn: the pointer to BN. |
|
645 * @delta: the delta. |
|
646 * |
|
647 * Adds @delta to @bn. |
|
648 * |
|
649 * Returns 0 on success or a negative value if an error occurs. |
|
650 */ |
|
651 EXPORT_C |
|
652 int |
|
653 xmlSecBnAdd(xmlSecBnPtr bn, int delta) { |
|
654 int over, tmp; |
|
655 xmlSecByte* data; |
|
656 xmlSecSize i; |
|
657 xmlSecByte ch; |
|
658 int ret; |
|
659 |
|
660 xmlSecAssert2(bn != NULL, -1); |
|
661 |
|
662 if(delta == 0) { |
|
663 return(0); |
|
664 } |
|
665 |
|
666 data = xmlSecBufferGetData(bn); |
|
667 if(delta > 0) { |
|
668 for(over = delta, i = xmlSecBufferGetSize(bn); (i > 0) && (over > 0) ;) { |
|
669 xmlSecAssert2(data != NULL, -1); |
|
670 |
|
671 tmp = data[--i]; |
|
672 over += tmp; |
|
673 data[i] = over % 256; |
|
674 over = over / 256; |
|
675 } |
|
676 |
|
677 while(over > 0) { |
|
678 ch = over % 256; |
|
679 over = over / 256; |
|
680 |
|
681 ret = xmlSecBufferPrepend(bn, &ch, 1); |
|
682 if(ret < 0) { |
|
683 xmlSecError(XMLSEC_ERRORS_HERE, |
|
684 NULL, |
|
685 "xmlSecBufferPrepend", |
|
686 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
687 "size=1"); |
|
688 return (-1); |
|
689 } |
|
690 } |
|
691 } else { |
|
692 for(over = -delta, i = xmlSecBufferGetSize(bn); (i > 0) && (over > 0);) { |
|
693 xmlSecAssert2(data != NULL, -1); |
|
694 |
|
695 tmp = data[--i]; |
|
696 if(tmp < over) { |
|
697 data[i] = 0; |
|
698 over = (over - tmp) / 256; |
|
699 } else { |
|
700 data[i] = tmp - over; |
|
701 over = 0; |
|
702 } |
|
703 } |
|
704 } |
|
705 return(0); |
|
706 } |
|
707 |
|
708 /** |
|
709 * xmlSecBnReverse: |
|
710 * @bn: the pointer to BN. |
|
711 * |
|
712 * Reverses bytes order in @bn. |
|
713 * |
|
714 * Returns 0 on success or a negative value if an error occurs. |
|
715 */ |
|
716 EXPORT_C |
|
717 int |
|
718 xmlSecBnReverse(xmlSecBnPtr bn) { |
|
719 xmlSecByte* data; |
|
720 xmlSecSize i, j, size; |
|
721 xmlSecByte ch; |
|
722 |
|
723 xmlSecAssert2(bn != NULL, -1); |
|
724 |
|
725 data = xmlSecBufferGetData(bn); |
|
726 size = xmlSecBufferGetSize(bn); |
|
727 for(i = 0, j = size - 1; i < size / 2; ++i, --j) { |
|
728 xmlSecAssert2(data != NULL, -1); |
|
729 |
|
730 ch = data[i]; |
|
731 data[i] = data[j]; |
|
732 data[j] = ch; |
|
733 } |
|
734 |
|
735 return(0); |
|
736 } |
|
737 |
|
738 /** |
|
739 * xmlSecBnCompare: |
|
740 * @bn: the pointer to BN. |
|
741 * @data: the data to compare BN to. |
|
742 * @dataSize: the @data size. |
|
743 * |
|
744 * Compares the @bn with @data. |
|
745 * |
|
746 * Returns 0 if data is equal, negative value if @bn is less or positive value if @bn |
|
747 * is greater than @data. |
|
748 */ |
|
749 EXPORT_C |
|
750 int |
|
751 xmlSecBnCompare(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize dataSize) { |
|
752 xmlSecByte* bnData; |
|
753 xmlSecSize bnSize; |
|
754 |
|
755 xmlSecAssert2(bn != NULL, -1); |
|
756 |
|
757 bnData = xmlSecBnGetData(bn); |
|
758 bnSize = xmlSecBnGetSize(bn); |
|
759 |
|
760 /* skip zeros in the beggining */ |
|
761 while((dataSize > 0) && (data != 0) && (data[0] == 0)) { |
|
762 ++data; |
|
763 --dataSize; |
|
764 } |
|
765 while((bnSize > 0) && (bnData != 0) && (bnData[0] == 0)) { |
|
766 ++bnData; |
|
767 --bnSize; |
|
768 } |
|
769 |
|
770 if(((bnData == NULL) || (bnSize == 0)) && ((data == NULL) || (dataSize == 0))) { |
|
771 return(0); |
|
772 } else if((bnData == NULL) || (bnSize == 0)) { |
|
773 return(-1); |
|
774 } else if((data == NULL) || (dataSize == 0)) { |
|
775 return(1); |
|
776 } else if(bnSize < dataSize) { |
|
777 return(-1); |
|
778 } else if(bnSize > dataSize) { |
|
779 return(-1); |
|
780 } |
|
781 |
|
782 xmlSecAssert2(bnData != NULL, -1); |
|
783 xmlSecAssert2(data != NULL, -1); |
|
784 xmlSecAssert2(bnSize == dataSize, -1); |
|
785 |
|
786 return(memcmp(bnData, data, dataSize)); |
|
787 } |
|
788 |
|
789 /** |
|
790 * xmlSecBnCompareReverse: |
|
791 * @bn: the pointer to BN. |
|
792 * @data: the data to compare BN to. |
|
793 * @dataSize: the @data size. |
|
794 * |
|
795 * Compares the @bn with reverse @data. |
|
796 * |
|
797 * Returns 0 if data is equal, negative value if @bn is less or positive value if @bn |
|
798 * is greater than @data. |
|
799 */ |
|
800 EXPORT_C |
|
801 int |
|
802 xmlSecBnCompareReverse(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize dataSize) { |
|
803 xmlSecByte* bnData; |
|
804 xmlSecSize bnSize; |
|
805 xmlSecSize i, j; |
|
806 |
|
807 xmlSecAssert2(bn != NULL, -1); |
|
808 |
|
809 bnData = xmlSecBnGetData(bn); |
|
810 bnSize = xmlSecBnGetSize(bn); |
|
811 |
|
812 /* skip zeros in the beggining */ |
|
813 while((dataSize > 0) && (data != 0) && (data[dataSize - 1] == 0)) { |
|
814 --dataSize; |
|
815 } |
|
816 while((bnSize > 0) && (bnData != 0) && (bnData[0] == 0)) { |
|
817 ++bnData; |
|
818 --bnSize; |
|
819 } |
|
820 |
|
821 if(((bnData == NULL) || (bnSize == 0)) && ((data == NULL) || (dataSize == 0))) { |
|
822 return(0); |
|
823 } else if((bnData == NULL) || (bnSize == 0)) { |
|
824 return(-1); |
|
825 } else if((data == NULL) || (dataSize == 0)) { |
|
826 return(1); |
|
827 } else if(bnSize < dataSize) { |
|
828 return(-1); |
|
829 } else if(bnSize > dataSize) { |
|
830 return(-1); |
|
831 } |
|
832 |
|
833 xmlSecAssert2(bnData != NULL, -1); |
|
834 xmlSecAssert2(data != NULL, -1); |
|
835 xmlSecAssert2(bnSize == dataSize, -1); |
|
836 for(i = 0, j = dataSize - 1; i < dataSize; ++i, --j) { |
|
837 if(bnData[i] < data[j]) { |
|
838 return(-1); |
|
839 } else if(data[j] < bnData[i]) { |
|
840 return(1); |
|
841 } |
|
842 } |
|
843 |
|
844 return(0); |
|
845 } |
|
846 |
|
847 /** |
|
848 * xmlSecBnGetNodeValue: |
|
849 * @bn: the pointer to BN. |
|
850 * @cur: the poitner to an XML node. |
|
851 * @format: the BN format. |
|
852 * @reverse: if set then reverse read buffer after reading. |
|
853 * |
|
854 * Converts the node content from @format to @bn. |
|
855 * |
|
856 * Returns 0 on success and a negative values if an error occurs. |
|
857 */ |
|
858 EXPORT_C |
|
859 int |
|
860 xmlSecBnGetNodeValue(xmlSecBnPtr bn, xmlNodePtr cur, xmlSecBnFormat format, int reverse) { |
|
861 xmlChar* content; |
|
862 int ret; |
|
863 |
|
864 xmlSecAssert2(bn != NULL, -1); |
|
865 xmlSecAssert2(cur != NULL, -1); |
|
866 |
|
867 switch(format) { |
|
868 case xmlSecBnBase64: |
|
869 ret = xmlSecBufferBase64NodeContentRead(bn, cur); |
|
870 if(ret < 0) { |
|
871 xmlSecError(XMLSEC_ERRORS_HERE, |
|
872 NULL, |
|
873 "xmlSecBufferBase64NodeContentRead", |
|
874 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
875 XMLSEC_ERRORS_NO_MESSAGE); |
|
876 return(-1); |
|
877 } |
|
878 break; |
|
879 case xmlSecBnHex: |
|
880 content = xmlNodeGetContent(cur); |
|
881 if(content == NULL) { |
|
882 xmlSecError(XMLSEC_ERRORS_HERE, |
|
883 NULL, |
|
884 "xmlNodeGetContent", |
|
885 XMLSEC_ERRORS_R_XML_FAILED, |
|
886 XMLSEC_ERRORS_NO_MESSAGE); |
|
887 return(-1); |
|
888 } |
|
889 ret = xmlSecBnFromHexString(bn, content); |
|
890 if(ret < 0) { |
|
891 xmlSecError(XMLSEC_ERRORS_HERE, |
|
892 NULL, |
|
893 "xmlSecBnFromHexString", |
|
894 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
895 XMLSEC_ERRORS_NO_MESSAGE); |
|
896 xmlFree(content); |
|
897 return(-1); |
|
898 } |
|
899 xmlFree(content); |
|
900 break; |
|
901 case xmlSecBnDec: |
|
902 content = xmlNodeGetContent(cur); |
|
903 if(content == NULL) { |
|
904 xmlSecError(XMLSEC_ERRORS_HERE, |
|
905 NULL, |
|
906 "xmlNodeGetContent", |
|
907 XMLSEC_ERRORS_R_XML_FAILED, |
|
908 XMLSEC_ERRORS_NO_MESSAGE); |
|
909 return(-1); |
|
910 } |
|
911 ret = xmlSecBnFromDecString(bn, content); |
|
912 if(ret < 0) { |
|
913 xmlSecError(XMLSEC_ERRORS_HERE, |
|
914 NULL, |
|
915 "xmlSecBnFromDecString", |
|
916 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
917 XMLSEC_ERRORS_NO_MESSAGE); |
|
918 xmlFree(content); |
|
919 return(-1); |
|
920 } |
|
921 xmlFree(content); |
|
922 break; |
|
923 } |
|
924 |
|
925 if(reverse != 0) { |
|
926 ret = xmlSecBnReverse(bn); |
|
927 if(ret < 0) { |
|
928 xmlSecError(XMLSEC_ERRORS_HERE, |
|
929 NULL, |
|
930 "xmlSecBnReverse", |
|
931 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
932 XMLSEC_ERRORS_NO_MESSAGE); |
|
933 return(-1); |
|
934 } |
|
935 } |
|
936 return(0); |
|
937 } |
|
938 |
|
939 /** |
|
940 * xmlSecBnSetNodeValue: |
|
941 * @bn: the pointer to BN. |
|
942 * @cur: the poitner to an XML node. |
|
943 * @format: the BN format. |
|
944 * @reverse: the flag that indicates whether to reverse the buffer before writing. |
|
945 * @addLineBreaks: the flag; it is equal to 1 then linebreaks will be added before and after new buffer content. |
|
946 * |
|
947 * Converts the @bn and sets it to node content. |
|
948 * |
|
949 * Returns 0 on success and a negative values if an error occurs. |
|
950 */ |
|
951 EXPORT_C |
|
952 int |
|
953 xmlSecBnSetNodeValue(xmlSecBnPtr bn, xmlNodePtr cur, xmlSecBnFormat format, int reverse, int addLineBreaks) { |
|
954 xmlChar* content; |
|
955 int ret; |
|
956 |
|
957 xmlSecAssert2(bn != NULL, -1); |
|
958 xmlSecAssert2(cur != NULL, -1); |
|
959 |
|
960 if(reverse != 0) { |
|
961 ret = xmlSecBnReverse(bn); |
|
962 if(ret < 0) { |
|
963 xmlSecError(XMLSEC_ERRORS_HERE, |
|
964 NULL, |
|
965 "xmlSecBnReverse", |
|
966 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
967 XMLSEC_ERRORS_NO_MESSAGE); |
|
968 return(-1); |
|
969 } |
|
970 } |
|
971 |
|
972 if(addLineBreaks) { |
|
973 xmlNodeAddContent(cur, xmlSecStringCR); |
|
974 } |
|
975 |
|
976 switch(format) { |
|
977 case xmlSecBnBase64: |
|
978 ret = xmlSecBufferBase64NodeContentWrite(bn, cur, XMLSEC_BASE64_LINESIZE); |
|
979 if(ret < 0) { |
|
980 xmlSecError(XMLSEC_ERRORS_HERE, |
|
981 NULL, |
|
982 "xmlSecBufferBase64NodeContentWrite", |
|
983 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
984 XMLSEC_ERRORS_NO_MESSAGE); |
|
985 return(-1); |
|
986 } |
|
987 break; |
|
988 case xmlSecBnHex: |
|
989 content = xmlSecBnToHexString(bn); |
|
990 if(content == NULL) { |
|
991 xmlSecError(XMLSEC_ERRORS_HERE, |
|
992 NULL, |
|
993 "xmlSecBnToHexString", |
|
994 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
995 XMLSEC_ERRORS_NO_MESSAGE); |
|
996 xmlFree(content); |
|
997 return(-1); |
|
998 } |
|
999 xmlNodeSetContent(cur, content); |
|
1000 xmlFree(content); |
|
1001 break; |
|
1002 case xmlSecBnDec: |
|
1003 content = xmlSecBnToDecString(bn); |
|
1004 if(content == NULL) { |
|
1005 xmlSecError(XMLSEC_ERRORS_HERE, |
|
1006 NULL, |
|
1007 "xmlSecBnToDecString", |
|
1008 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
1009 XMLSEC_ERRORS_NO_MESSAGE); |
|
1010 xmlFree(content); |
|
1011 return(-1); |
|
1012 } |
|
1013 xmlNodeSetContent(cur, content); |
|
1014 xmlFree(content); |
|
1015 break; |
|
1016 } |
|
1017 |
|
1018 if(addLineBreaks) { |
|
1019 xmlNodeAddContent(cur, xmlSecStringCR); |
|
1020 } |
|
1021 |
|
1022 return(0); |
|
1023 } |
|
1024 |
|
1025 /** |
|
1026 * xmlSecBnBlobSetNodeValue: |
|
1027 * @data: the pointer to BN blob. |
|
1028 * @dataSize: the size of BN blob. |
|
1029 * @cur: the poitner to an XML node. |
|
1030 * @format: the BN format. |
|
1031 * @reverse: the flag that indicates whether to reverse the buffer before writing. |
|
1032 * @addLineBreaks: if the flag is equal to 1 then |
|
1033 * linebreaks will be added before and after |
|
1034 * new buffer content. |
|
1035 * |
|
1036 * Converts the @blob and sets it to node content. |
|
1037 * |
|
1038 * Returns 0 on success and a negative values if an error occurs. |
|
1039 */ |
|
1040 EXPORT_C |
|
1041 int |
|
1042 xmlSecBnBlobSetNodeValue(const xmlSecByte* data, xmlSecSize dataSize, |
|
1043 xmlNodePtr cur, xmlSecBnFormat format, int reverse, |
|
1044 int addLineBreaks) { |
|
1045 xmlSecBn bn; |
|
1046 int ret; |
|
1047 |
|
1048 xmlSecAssert2(data != NULL, -1); |
|
1049 xmlSecAssert2(cur != NULL, -1); |
|
1050 |
|
1051 ret = xmlSecBnInitialize(&bn, dataSize); |
|
1052 if(ret < 0) { |
|
1053 xmlSecError(XMLSEC_ERRORS_HERE, |
|
1054 NULL, |
|
1055 "xmlSecBnInitialize", |
|
1056 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
1057 XMLSEC_ERRORS_NO_MESSAGE); |
|
1058 return(-1); |
|
1059 } |
|
1060 |
|
1061 ret = xmlSecBnSetData(&bn, data, dataSize); |
|
1062 if(ret < 0) { |
|
1063 xmlSecError(XMLSEC_ERRORS_HERE, |
|
1064 NULL, |
|
1065 "xmlSecBnSetData", |
|
1066 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
1067 XMLSEC_ERRORS_NO_MESSAGE); |
|
1068 xmlSecBnFinalize(&bn); |
|
1069 return(-1); |
|
1070 } |
|
1071 |
|
1072 ret = xmlSecBnSetNodeValue(&bn, cur, format, reverse, addLineBreaks); |
|
1073 if(ret < 0) { |
|
1074 xmlSecError(XMLSEC_ERRORS_HERE, |
|
1075 NULL, |
|
1076 "xmlSecBnSetNodeValue", |
|
1077 XMLSEC_ERRORS_R_XMLSEC_FAILED, |
|
1078 XMLSEC_ERRORS_NO_MESSAGE); |
|
1079 xmlSecBnFinalize(&bn); |
|
1080 return(-1); |
|
1081 } |
|
1082 |
|
1083 xmlSecBnFinalize(&bn); |
|
1084 return(0); |
|
1085 } |
|
1086 |
|
1087 |