Source for gnu.javax.crypto.key.OutgoingMessage

   1: /* OutgoingMessage.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.dss.DSSKey;
  43: import gnu.java.security.key.rsa.GnuRSAKey;
  44: import gnu.java.security.util.FormatUtil;
  45: import gnu.javax.crypto.key.dh.GnuDHKey;
  46: import gnu.javax.crypto.key.srp6.SRPKey;
  47: 
  48: import java.io.ByteArrayOutputStream;
  49: import java.io.UnsupportedEncodingException;
  50: import java.security.Key;
  51: import java.security.PrivateKey;
  52: import java.security.PublicKey;
  53: import java.math.BigInteger;
  54: 
  55: /**
  56:  * An implementation of outgoing messages for use with key agreement protocols.
  57:  */
  58: public class OutgoingMessage
  59: {
  60:   /** The internal output stream. */
  61:   private ByteArrayOutputStream out;
  62: 
  63:   public OutgoingMessage()
  64:   {
  65:     super();
  66: 
  67:     out = new ByteArrayOutputStream();
  68:   }
  69: 
  70:   /**
  71:    * Returns the encoded form of the current message including the 4-byte length
  72:    * header.
  73:    *
  74:    * @throws KeyAgreementException if an encoding size constraint is violated.
  75:    */
  76:   public byte[] toByteArray() throws KeyAgreementException
  77:   {
  78:     byte[] buffer = wrap();
  79:     int length = buffer.length;
  80:     byte[] result = new byte[length + 4];
  81:     result[0] = (byte)(length >>> 24);
  82:     result[1] = (byte)(length >>> 16);
  83:     result[2] = (byte)(length >>> 8);
  84:     result[3] = (byte) length;
  85:     System.arraycopy(buffer, 0, result, 4, length);
  86:     return result;
  87:   }
  88: 
  89:   /**
  90:    * Returns the encoded form of the current message excluding the 4-byte length
  91:    * header.
  92:    *
  93:    * @throws KeyAgreementException if an encoding size constraint is violated.
  94:    */
  95:   public byte[] wrap() throws KeyAgreementException
  96:   {
  97:     int length = out.size();
  98:     if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
  99:       throw new KeyAgreementException("message content is too long");
 100:     return out.toByteArray();
 101:   }
 102: 
 103:   /**
 104:    * Encodes a public key into the message.
 105:    * <p>
 106:    * When a public key is encoded into an outgoing message, the byte array of
 107:    * the encoded key --according to its encoding/decoding format specified when
 108:    * the key was first instantiated-- are put in the message (a) preceeded by
 109:    * one byte representing both the type of key (upper 4-bit) and the identifier
 110:    * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity
 111:    * representing the total length, excluding these 4 bytes, of the bytes
 112:    * representing the encoded key and the one-byte representing the key-type and
 113:    * format; i.e.
 114:    * <pre>
 115:    * key --&gt; 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
 116:    * </pre>
 117:    *
 118:    * @param k the public key to encode.
 119:    * @throws KeyAgreementException if an encoding size constraint is violated.
 120:    */
 121:   public void writePublicKey(PublicKey k) throws KeyAgreementException
 122:   {
 123:     writeKey(k);
 124:   }
 125: 
 126:   /**
 127:    * Encodes a private key into the message.
 128:    * <p>
 129:    * When a private key is encoded into an outgoing message, the byte array of
 130:    * the encoded key --according to its encoding/decoding format specified when
 131:    * the key was first instantiated-- are put in the message (a) preceeded by
 132:    * one byte representing both the type of key (upper 4-bit) and the identifier
 133:    * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity
 134:    * representing the total length, excluding these 4 bytes, of the bytes
 135:    * representing the encoded key and the one-byte representing the key-type and
 136:    * format; i.e.
 137:    * <pre>
 138:    * key --&gt; 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
 139:    * </pre>
 140:    *
 141:    * @param k the private key to encode.
 142:    * @throws KeyAgreementException if an encoding size constraint is violated.
 143:    */
 144:   public void writePrivateKey(PrivateKey k) throws KeyAgreementException
 145:   {
 146:     writeKey(k);
 147:   }
 148: 
 149:   /**
 150:    * Encodes an MPI into the message.
 151:    *
 152:    * @param val the MPI to encode.
 153:    * @throws KeyAgreementException if an encoding size constraint is violated.
 154:    */
 155:   public void writeMPI(BigInteger val) throws KeyAgreementException
 156:   {
 157:     byte[] b = val.toByteArray();
 158:     int length = b.length;
 159:     if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
 160:       throw new KeyAgreementException("MPI is too long");
 161:     byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
 162:     out.write(lengthBytes, 0, 2);
 163:     out.write(b, 0, b.length);
 164:   }
 165: 
 166:   /**
 167:    * Encodes a string into the message.
 168:    *
 169:    * @param s the string to encode.
 170:    * @throws KeyAgreementException if the UTF8 encoding is not supported on this
 171:    *           platform, or if an encoding size constraint is violated.
 172:    */
 173:   public void writeString(String s) throws KeyAgreementException
 174:   {
 175:     byte[] b = null;
 176:     try
 177:       {
 178:         b = s.getBytes("UTF8");
 179:       }
 180:     catch (UnsupportedEncodingException x)
 181:       {
 182:         throw new KeyAgreementException("unxupported UTF8 encoding", x);
 183:       }
 184:     int length = b.length;
 185:     if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
 186:       throw new KeyAgreementException("text too long");
 187:     byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
 188:     out.write(lengthBytes, 0, 2);
 189:     out.write(b, 0, b.length);
 190:   }
 191: 
 192:   /**
 193:    * @param k the key to encode.
 194:    * @throws KeyAgreementException if an encoding size constraint is violated.
 195:    */
 196:   private void writeKey(Key k) throws KeyAgreementException
 197:   {
 198:     byte[] b = k.getEncoded();
 199:     int keyType = getKeyType(k);
 200:     int formatID = FormatUtil.getFormatID(k.getFormat());
 201:     int length = b.length + 1;
 202:     if (length > Registry.SASL_FOUR_BYTE_MAX_LIMIT)
 203:       throw new KeyAgreementException("Encoded key is too long");
 204:     byte[] lengthBytes = {
 205:         (byte)(length >>> 24),
 206:         (byte)(length >>> 16),
 207:         (byte)(length >>> 8),
 208:         (byte) length };
 209:     out.write(lengthBytes, 0, 4);
 210:     out.write(((keyType & 0x0F) << 4) | (formatID & 0x0F));
 211:     out.write(b, 0, b.length);
 212:   }
 213: 
 214:   /**
 215:    * @param k the key to find an identifier for.
 216:    * @return an integer from <code>0</code> to <code>3</code> identifying
 217:    *         the type of key.
 218:    * @throws KeyAgreementException if the designated key is of unknown or
 219:    *           unsupported type.
 220:    */
 221:   private int getKeyType(Key k) throws KeyAgreementException
 222:   {
 223:     if (k instanceof DSSKey)
 224:       return 0;
 225:     if (k instanceof GnuRSAKey)
 226:       return 1;
 227:     if (k instanceof GnuDHKey)
 228:       return 2;
 229:     if (k instanceof SRPKey)
 230:       return 3;
 231:     throw new KeyAgreementException("Unknown or unsupported key type: "
 232:                                     + k.getClass().getName());
 233:   }
 234: }