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

Quick Search    Search Deep

Source code: gnu/javax/crypto/key/IncomingMessage.java


1   /* IncomingMessage.java -- 
2      Copyright (C) 2003, 2006 Free Software Foundation, Inc.
3   
4   This file is a part of GNU Classpath.
5   
6   GNU Classpath is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or (at
9   your option) any later version.
10  
11  GNU Classpath is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  General Public License for more details.
15  
16  You should have received a copy of the GNU General Public License
17  along with GNU Classpath; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19  USA
20  
21  Linking this library statically or dynamically with other modules is
22  making a combined work based on this library.  Thus, the terms and
23  conditions of the GNU General Public License cover the whole
24  combination.
25  
26  As a special exception, the copyright holders of this library give you
27  permission to link this library with independent modules to produce an
28  executable, regardless of the license terms of these independent
29  modules, and to copy and distribute the resulting executable under
30  terms of your choice, provided that you also meet, for each linked
31  independent module, the terms and conditions of the license of that
32  module.  An independent module is a module which is not derived from
33  or based on this library.  If you modify this library, you may extend
34  this exception to your version of the library, but you are not
35  obligated to do so.  If you do not wish to do so, delete this
36  exception statement from your version.  */
37  
38  
39  package gnu.javax.crypto.key;
40  
41  import gnu.java.security.Registry;
42  import gnu.java.security.key.IKeyPairCodec;
43  import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec;
44  import gnu.java.security.key.dss.DSSKeyPairRawCodec;
45  import gnu.java.security.key.dss.DSSKeyPairX509Codec;
46  import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec;
47  import gnu.java.security.key.rsa.RSAKeyPairRawCodec;
48  import gnu.java.security.key.rsa.RSAKeyPairX509Codec;
49  import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec;
50  import gnu.javax.crypto.key.dh.DHKeyPairRawCodec;
51  import gnu.javax.crypto.key.dh.DHKeyPairX509Codec;
52  import gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec;
53  
54  import java.io.ByteArrayInputStream;
55  import java.io.UnsupportedEncodingException;
56  import java.math.BigInteger;
57  import java.security.PrivateKey;
58  import java.security.PublicKey;
59  
60  /**
61   * <p>An implementation of an incoming message for use with key agreement
62   * protocols.</p>
63   */
64  public class IncomingMessage
65  {
66  
67    // Constants and variables
68    // -------------------------------------------------------------------------
69  
70    /** The internal buffer stream containing the message's contents. */
71    protected ByteArrayInputStream in;
72  
73    /** The length of the message contents, according to its 4-byte header. */
74    protected int length;
75  
76    // Constructor(s)
77    // -------------------------------------------------------------------------
78  
79    /**
80     * <p>Constructs an incoming message given the message's encoded form,
81     * including its header bytes.</p>
82     *
83     * @param b the encoded form, including the header bytes, of an incoming
84     * message.
85     * @throws KeyAgreementException if the buffer is malformed.
86     */
87    public IncomingMessage(byte[] b) throws KeyAgreementException
88    {
89      this();
90  
91      if (b.length < 4)
92        {
93          throw new KeyAgreementException("message header too short");
94        }
95      length = b[0] << 24 | (b[1] & 0xFF) << 16 | (b[2] & 0xFF) << 8
96               | (b[3] & 0xFF);
97      if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
98        {
99          throw new KeyAgreementException("message size limit exceeded");
100       }
101     in = new ByteArrayInputStream(b, 4, length);
102   }
103 
104   /** Trivial private constructor for use by the class method. */
105   private IncomingMessage()
106   {
107     super();
108   }
109 
110   // Class methods
111   // -------------------------------------------------------------------------
112 
113   /**
114    * <p>Returns an instance of a message given its encoded contents, excluding
115    * the message's header bytes.</p>
116    *
117    * <p>Calls the method with the same name and three arguments as:
118    * <code>getInstance(raw, 0, raw.length)</code>.
119    *
120    * @param raw the encoded form, excluding the header bytes.
121    * @return a new instance of <code>IncomingMessage</code>.
122    */
123   public static IncomingMessage getInstance(byte[] raw)
124   {
125     return getInstance(raw, 0, raw.length);
126   }
127 
128   /**
129    * <p>Returns an instance of a message given its encoded contents, excluding
130    * the message's header bytes.</p>
131    *
132    * @param raw the encoded form, excluding the header bytes.
133    * @param offset offset where to start using raw bytes from.
134    * @param len number of bytes to use.
135    * @return a new instance of <code>IncomingMessage</code>.
136    */
137   public static IncomingMessage getInstance(byte[] raw, int offset, int len)
138   {
139     IncomingMessage result = new IncomingMessage();
140     result.in = new ByteArrayInputStream(raw, offset, len);
141     return result;
142   }
143 
144   /**
145    * <p>Converts two octets into the number that they represent.</p>
146    *
147    * @param b the two octets.
148    * @return the length.
149    */
150   public static int twoBytesToLength(byte[] b) throws KeyAgreementException
151   {
152     int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF);
153     if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT)
154       {
155         throw new KeyAgreementException("encoded MPI size limit exceeded");
156       }
157     return result;
158   }
159 
160   /**
161    * <p>Converts four octets into the number that they represent.</p>
162    *
163    * @param b the four octets.
164    * @return the length.
165    */
166   public static int fourBytesToLength(byte[] b) throws KeyAgreementException
167   {
168     int result = b[0] << 24 | (b[1] & 0xFF) << 16 | (b[2] & 0xFF) << 8
169                  | (b[3] & 0xFF);
170     if (result > Registry.SASL_FOUR_BYTE_MAX_LIMIT || result < 0)
171       {
172         throw new KeyAgreementException("encoded entity size limit exceeded");
173       }
174     return result;
175   }
176 
177   // Instance methods
178   // -------------------------------------------------------------------------
179 
180   public boolean hasMoreElements()
181   {
182     return (in.available() > 0);
183   }
184 
185   /**
186    * Decodes a public key from the message.
187    * <p>
188    * See {@link OutgoingMessage#writePublicKey(java.security.PublicKey)} for
189    * more details on the internal format.
190    * 
191    * @throws KeyAgreementException if an encoding size constraint is violated or
192    *           a mismatch was detected in the encoding.
193    */
194   public PublicKey readPublicKey() throws KeyAgreementException
195   {
196     if (in.available() < 5)
197       throw new KeyAgreementException("not enough bytes for a public key in message");
198 
199     byte[] elementLengthBytes = new byte[4];
200     in.read(elementLengthBytes, 0, 4);
201     int elementLength = fourBytesToLength(elementLengthBytes);
202     if (in.available() < elementLength)
203       throw new KeyAgreementException("illegal public key encoding");
204 
205     int keyTypeAndFormatID = in.read() & 0xFF;
206     elementLength--;
207     byte[] kb = new byte[elementLength];
208     in.read(kb, 0, elementLength);
209 
210     // instantiate the right codec and decode
211     IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID);
212     return kpc.decodePublicKey(kb);
213   }
214 
215   /**
216    * Decodes a private key from the message.
217    * <p>
218    * See {@link OutgoingMessage#writePrivateKey(java.security.PrivateKey)} for
219    * more details.
220    * 
221    * @throws KeyAgreementException if an encoding size constraint is violated or
222    *           a mismatch was detected in the encoding.
223    */
224   public PrivateKey readPrivateKey() throws KeyAgreementException
225   {
226     if (in.available() < 5)
227       throw new KeyAgreementException("not enough bytes for a private key in message");
228 
229     byte[] elementLengthBytes = new byte[4];
230     in.read(elementLengthBytes, 0, 4);
231     int elementLength = fourBytesToLength(elementLengthBytes);
232     if (in.available() < elementLength)
233       throw new KeyAgreementException("illegal private key encoding");
234 
235     int keyTypeAndFormatID = in.read() & 0xFF;
236     elementLength--;
237     byte[] kb = new byte[elementLength];
238     in.read(kb, 0, elementLength);
239 
240     // instantiate the right codec and decode
241     IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID);
242     return kpc.decodePrivateKey(kb);
243   }
244 
245   /**
246    * <p>Decodes an MPI from the current message's contents.</p>
247    *
248    * @return a native representation of an MPI.
249    * @throws KeyAgreementException if an encoding exception occurs during the
250    * operation.
251    */
252   public BigInteger readMPI() throws KeyAgreementException
253   {
254     if (in.available() < 2)
255       {
256         throw new KeyAgreementException(
257                                         "not enough bytes for an MPI in message");
258       }
259     byte[] elementLengthBytes = new byte[2];
260     in.read(elementLengthBytes, 0, 2);
261     int elementLength = twoBytesToLength(elementLengthBytes);
262     if (in.available() < elementLength)
263       {
264         throw new KeyAgreementException("illegal MPI encoding");
265       }
266 
267     byte[] element = new byte[elementLength];
268     in.read(element, 0, element.length);
269 
270     return new BigInteger(1, element);
271   }
272 
273   public String readString() throws KeyAgreementException
274   {
275     if (in.available() < 2)
276       {
277         throw new KeyAgreementException(
278                                         "not enough bytes for a text in message");
279       }
280     byte[] elementLengthBytes = new byte[2];
281     in.read(elementLengthBytes, 0, 2);
282     int elementLength = twoBytesToLength(elementLengthBytes);
283     if (in.available() < elementLength)
284       {
285         throw new KeyAgreementException("illegal text encoding");
286       }
287 
288     byte[] element = new byte[elementLength];
289     in.read(element, 0, element.length);
290     String result = null;
291     try
292       {
293         result = new String(element, "UTF8");
294       }
295     catch (UnsupportedEncodingException x)
296       {
297         throw new KeyAgreementException("unxupported UTF8 encoding", x);
298       }
299 
300     return result;
301   }
302 
303   private IKeyPairCodec getKeyPairCodec(int keyTypeAndFormatID)
304       throws KeyAgreementException
305   {
306     int keyType = (keyTypeAndFormatID >>> 4) & 0x0F;
307     int formatID = keyTypeAndFormatID & 0x0F;
308     switch (formatID)
309       {
310       case Registry.RAW_ENCODING_ID:
311         switch (keyType)
312           {
313           case 0:
314             return new DSSKeyPairRawCodec();
315           case 1:
316             return new RSAKeyPairRawCodec();
317           case 2:
318             return new DHKeyPairRawCodec();
319           case 3:
320             return new SRPKeyPairRawCodec();
321           default:
322             throw new KeyAgreementException("Unknown key-type for Raw format: "
323                                             + keyType);
324           }
325       case Registry.X509_ENCODING_ID:
326         switch (keyType)
327           {
328           case 0:
329             return new DSSKeyPairX509Codec();
330           case 1:
331             return new RSAKeyPairX509Codec();
332           case 2:
333             return new DHKeyPairX509Codec();
334           default:
335             throw new KeyAgreementException("Unknown key-type for X.509 format: "
336                                             + keyType);
337           }
338       case Registry.PKCS8_ENCODING_ID:
339         switch (keyType)
340           {
341           case 0:
342             return new DSSKeyPairPKCS8Codec();
343           case 1:
344             return new RSAKeyPairPKCS8Codec();
345           case 2:
346             return new DHKeyPairPKCS8Codec();
347           default:
348             throw new KeyAgreementException("Unknown key-type for PKCS#8 format: "
349                                             + keyType);
350           }
351       default:
352         throw new KeyAgreementException("Unknown format identifier: "
353                                         + formatID);
354       }
355   }
356 }