1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6   @file der_encode_integer.c
7   ASN.1 DER, encode an integer, Tom St Denis
8 */
9 
10 
11 #ifdef LTC_DER
12 
13 /* Exports a positive bignum as DER format (upto 2^32 bytes in size) */
14 /**
15   Store a mp_int integer
16   @param num      The first mp_int to encode
17   @param out      [out] The destination for the DER encoded integers
18   @param outlen   [in/out] The max size and resulting size of the DER encoded integers
19   @return CRYPT_OK if successful
20 */
der_encode_integer(void * num,unsigned char * out,unsigned long * outlen)21 int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen)
22 {
23    unsigned long tmplen, y, len;
24    int           err, leading_zero;
25 
26    LTC_ARGCHK(num    != NULL);
27    LTC_ARGCHK(out    != NULL);
28    LTC_ARGCHK(outlen != NULL);
29 
30    /* find out how big this will be */
31    if ((err = der_length_integer(num, &tmplen)) != CRYPT_OK) {
32       return err;
33    }
34 
35    if (*outlen < tmplen) {
36       *outlen = tmplen;
37       return CRYPT_BUFFER_OVERFLOW;
38    }
39 
40    if (mp_cmp_d(num, 0) != LTC_MP_LT) {
41       /* we only need a leading zero if the msb of the first byte is one */
42       if ((mp_count_bits(num) & 7) == 0 || mp_iszero(num) == LTC_MP_YES) {
43          leading_zero = 1;
44       } else {
45          leading_zero = 0;
46       }
47 
48       /* get length of num in bytes (plus 1 since we force the msbyte to zero) */
49       y = mp_unsigned_bin_size(num) + leading_zero;
50    } else {
51       leading_zero = 0;
52       y            = mp_count_bits(num);
53       y            = y + (8 - (y & 7));
54       y            = y >> 3;
55       if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --y;
56    }
57 
58    /* now store initial data */
59    *out++ = 0x02;
60    len = *outlen - 1;
61    if ((err = der_encode_asn1_length(y, out, &len)) != CRYPT_OK) {
62       return err;
63    }
64    out += len;
65 
66    /* now store msbyte of zero if num is non-zero */
67    if (leading_zero) {
68       *out++ = 0x00;
69    }
70 
71    /* if it's not zero store it as big endian */
72    if (mp_cmp_d(num, 0) == LTC_MP_GT) {
73       /* now store the mpint */
74       if ((err = mp_to_unsigned_bin(num, out)) != CRYPT_OK) {
75           return err;
76       }
77    } else if (mp_iszero(num) != LTC_MP_YES) {
78       void *tmp;
79 
80       /* negative */
81       if (mp_init(&tmp) != CRYPT_OK) {
82          return CRYPT_MEM;
83       }
84 
85       /* 2^roundup and subtract */
86       y = mp_count_bits(num);
87       y = y + (8 - (y & 7));
88       if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) y -= 8;
89       if (mp_2expt(tmp, y) != CRYPT_OK || mp_add(tmp, num, tmp) != CRYPT_OK) {
90          mp_clear(tmp);
91          return CRYPT_MEM;
92       }
93       if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) {
94          mp_clear(tmp);
95          return err;
96       }
97       mp_clear(tmp);
98    }
99 
100    /* we good */
101    *outlen = tmplen;
102    return CRYPT_OK;
103 }
104 
105 #endif
106