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*/
29int 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 $ */
131