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