version 0.3.33
[fms.git] / libs / libtomcrypt / pk / asn1 / der / integer / der_encode_integer.c
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 */
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 $ */