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