Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: cryptix/openpgp/util/PGPMPI.java


1   /* $Id: PGPMPI.java,v 1.2 2005/03/13 17:47:08 woudt Exp $
2    *
3    * Copyright (C) 1999-2005 The Cryptix Foundation Limited.
4    * All rights reserved.
5    * 
6    * Use, modification, copying and distribution of this software is subject 
7    * the terms and conditions of the Cryptix General Licence. You should have 
8    * received a copy of the Cryptix General License along with this library; 
9    * if not, you can download a copy from http://www.cryptix.org/ .
10   */
11  
12  package cryptix.openpgp.util;
13  
14  
15  import cryptix.openpgp.PGPDataFormatException;
16  import cryptix.openpgp.PGPFatalDataFormatException;
17  
18  import java.io.DataInput;
19  import java.io.DataOutput;
20  import java.io.IOException;
21  
22  import java.math.BigInteger;
23  
24  
25  /**
26   * Read and write BigIntegers in a PGP compatible format.
27   *
28   * <p>From <A HREF="http://www.ietf.org/rfc/rfc2440.txt">RFC 2440</A>:</p>
29   * <pre>     3.2. Multi-Precision Integers
30   *
31   *     Multi-Precision Integers (also called MPIs) are unsigned integers
32   *     used to hold large integers such as the ones used in cryptographic
33   *     calculations.
34   *
35   *     An MPI consists of two pieces: a two-octet scalar that is the length
36   *     of the MPI in bits followed by a string of octets that contain the
37   *     actual integer.
38   *
39   *     These octets form a big-endian number; a big-endian number can be
40   *     made into an MPI by prefixing it with the appropriate length.
41   *
42   *     Examples:
43   *
44   *     (all numbers are in hexadecimal)
45   *
46   *     The string of octets [00 01 01] forms an MPI with the value 1. The
47   *     string [00 09 01 FF] forms an MPI with the value of 511.
48   *
49   *     Additional rules:
50   *
51   *     The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
52   *    
53   *     The length field of an MPI describes the length starting from its
54   *     most significant non-zero bit. Thus, the MPI [00 02 01] is not formed
55   *     correctly. It should be [00 01 01].</pre>
56   *
57   * @author Edwin Woudt (edwin@cryptix.org)
58   * @author Jeroen C. van Gelderen (gelderen@cryptix.org)
59   * @version $Revision: 1.2 $
60   */
61  
62  public class PGPMPI {
63      
64      private PGPMPI() {} //static methods only
65      
66  
67      /**
68       * Read a BigInteger from a stream
69       *
70       * @param in the DataInput that contains a BigInteger in PGP format
71       * @return the BigInteger read
72       * @throws IOException if an I/O error occurs
73       * @throws EOFException if the end of the stream is reached before a
74       *                      complete BigInteger could be read
75       */
76      public static BigInteger decode(DataInput in) throws IOException {
77  
78          int len = in.readUnsignedShort();
79          byte[] buf = new byte[(len + 7) / 8];
80          in.readFully(buf);
81          return new BigInteger(1,buf);
82  
83      }
84      
85  
86      /**
87       * Write a BigInteger to a stream
88       *
89       * @param out the DataOutput to write the BigInteger to
90       * @param x the BigInteger to be written
91       * @throws IOException if an I/O error occurs
92       */
93      public static void encode(DataOutput out, BigInteger x) 
94          throws IOException 
95      {
96  
97          out.writeShort(x.bitLength());
98          byte[] bytes = x.toByteArray();
99          if (bytes[0] == 0) {
100             out.write(bytes,1,bytes.length-1);   // remove sign byte
101         } else {
102             out.write(bytes);
103         }
104 
105     }
106 
107 
108     /**
109      * Fit (stretch or shrink) the given positive BigInteger into a 
110      * byte[] of resultByteLen bytes without losing precision.
111      *
112      * @trhows IllegalArgumentException
113      *         If x negative, or won't fit in requested number of bytes.
114      */
115     public static byte[] toFixedLenByteArray(BigInteger x, int resultByteLen) {
116 
117         if (x.signum() != 1)
118             throw new IllegalArgumentException("BigInteger not positive.");
119 
120         byte[] x_bytes = x.toByteArray();
121         int x_len = x_bytes.length;
122 
123         if (x_len <= 0)
124             throw new IllegalArgumentException("BigInteger too small.");
125 
126         /*
127          * The BigInteger contract specifies that we now have at most one
128          * superfluous leading zero byte:
129          */
130         int x_off = (x_bytes[0] == 0) ? 1 : 0;
131         x_len -= x_off;
132 
133         /*
134          * Check whether the BigInteger will fit in the requested byte length.
135          */
136         if ( x_len > resultByteLen)
137             throw new IllegalArgumentException("BigInteger too large.");
138 
139         /*
140          * Now stretch or shrink the encoding to fit in resByteLen bytes.
141          */
142         byte[] res_bytes = new byte[resultByteLen];
143         int res_off = resultByteLen-x_len;
144         System.arraycopy(x_bytes, x_off, res_bytes, res_off, x_len);
145         return res_bytes;
146     }
147 }