Home | History | Annotate | Download | only in integer
      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 (at) 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 */
     29 int 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