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