1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2 *
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
5 *
6 * The library is free for all purposes without any express
7 * guarantee it works.
8 *
9 * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
10 */
11 #include "tomcrypt.h"
12
13 /**
14 @file der_encode_integer.c
15 ASN.1 DER, encode an integer, Tom St Denis
16 */
17
18
19 #ifdef LTC_DER
20
21 /* Exports a positive bignum as DER format (upto 2^32 bytes in size) */
22 /**
23 Store a mp_int integer
24 @param num The first mp_int to encode
25 @param out [out] The destination for the DER encoded integers
26 @param outlen [in/out] The max size and resulting size of the DER encoded integers
27 @return CRYPT_OK if successful
28 */
der_encode_integer(void * num,unsigned char * out,unsigned long * outlen)29 int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen)
30 {
31 unsigned long tmplen, y;
32 int err, leading_zero;
33
34 LTC_ARGCHK(num != NULL);
35 LTC_ARGCHK(out != NULL);
36 LTC_ARGCHK(outlen != NULL);
37
38 /* find out how big this will be */
39 if ((err = der_length_integer(num, &tmplen)) != CRYPT_OK) {
40 return err;
41 }
42
43 if (*outlen < tmplen) {
44 *outlen = tmplen;
45 return CRYPT_BUFFER_OVERFLOW;
46 }
47
48 if (mp_cmp_d(num, 0) != LTC_MP_LT) {
49 /* we only need a leading zero if the msb of the first byte is one */
50 if ((mp_count_bits(num) & 7) == 0 || mp_iszero(num) == LTC_MP_YES) {
51 leading_zero = 1;
52 } else {
53 leading_zero = 0;
54 }
55
56 /* get length of num in bytes (plus 1 since we force the msbyte to zero) */
57 y = mp_unsigned_bin_size(num) + leading_zero;
58 } else {
59 leading_zero = 0;
60 y = mp_count_bits(num);
61 y = y + (8 - (y & 7));
62 y = y >> 3;
63 if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --y;
64 }
65
66 /* now store initial data */
67 *out++ = 0x02;
68 if (y < 128) {
69 /* short form */
70 *out++ = (unsigned char)y;
71 } else if (y < 256) {
72 *out++ = 0x81;
73 *out++ = (unsigned char)y;
74 } else if (y < 65536UL) {
75 *out++ = 0x82;
76 *out++ = (unsigned char)((y>>8)&255);
77 *out++ = (unsigned char)y;
78 } else if (y < 16777216UL) {
79 *out++ = 0x83;
80 *out++ = (unsigned char)((y>>16)&255);
81 *out++ = (unsigned char)((y>>8)&255);
82 *out++ = (unsigned char)y;
83 } else {
84 return CRYPT_INVALID_ARG;
85 }
86
87 /* now store msbyte of zero if num is non-zero */
88 if (leading_zero) {
89 *out++ = 0x00;
90 }
91
92 /* if it's not zero store it as big endian */
93 if (mp_cmp_d(num, 0) == LTC_MP_GT) {
94 /* now store the mpint */
95 if ((err = mp_to_unsigned_bin(num, out)) != CRYPT_OK) {
96 return err;
97 }
98 } else if (mp_iszero(num) != LTC_MP_YES) {
99 void *tmp;
100
101 /* negative */
102 if (mp_init(&tmp) != CRYPT_OK) {
103 return CRYPT_MEM;
104 }
105
106 /* 2^roundup and subtract */
107 y = mp_count_bits(num);
108 y = y + (8 - (y & 7));
109 if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) y -= 8;
110 if (mp_2expt(tmp, y) != CRYPT_OK || mp_add(tmp, num, tmp) != CRYPT_OK) {
111 mp_clear(tmp);
112 return CRYPT_MEM;
113 }
114 if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) {
115 mp_clear(tmp);
116 return err;
117 }
118 mp_clear(tmp);
119 }
120
121 /* we good */
122 *outlen = tmplen;
123 return CRYPT_OK;
124 }
125
126 #endif
127
128 /* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/integer/der_encode_integer.c,v $ */
129 /* $Revision: 1.8 $ */
130 /* $Date: 2006/12/04 21:34:03 $ */
131