Frames | No Frames |
1: /* DHKeyPairX509Codec.java -- X.509 DER encoder/decoder for DH keys 2: Copyright (C) 2006 Free Software Foundation, Inc. 3: 4: This file is 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, or (at your option) 9: 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; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 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.dh; 40: 41: import java.io.ByteArrayOutputStream; 42: import java.io.IOException; 43: import java.math.BigInteger; 44: import java.security.InvalidParameterException; 45: import java.security.PrivateKey; 46: import java.security.PublicKey; 47: import java.util.ArrayList; 48: 49: import gnu.java.security.OID; 50: import gnu.java.security.Registry; 51: import gnu.java.security.der.BitString; 52: import gnu.java.security.der.DER; 53: import gnu.java.security.der.DERReader; 54: import gnu.java.security.der.DERValue; 55: import gnu.java.security.der.DERWriter; 56: import gnu.java.security.key.IKeyPairCodec; 57: import gnu.java.security.util.DerUtil; 58: 59: public class DHKeyPairX509Codec 60: implements IKeyPairCodec 61: { 62: private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING); 63: 64: // implicit 0-arguments constructor 65: 66: public int getFormatID() 67: { 68: return X509_FORMAT; 69: } 70: 71: /** 72: * Returns the DER-encoded form of the X.509 ASN.1 <i>SubjectPublicKeyInfo</i> 73: * representation of a DH public key. The ASN.1 specification, as defined in 74: * RFC-3280, and RFC-2459, is as follows: 75: * 76: * <pre> 77: * SubjectPublicKeyInfo ::= SEQUENCE { 78: * algorithm AlgorithmIdentifier, 79: * subjectPublicKey BIT STRING 80: * } 81: * 82: * AlgorithmIdentifier ::= SEQUENCE { 83: * algorithm OBJECT IDENTIFIER, 84: * parameters ANY DEFINED BY algorithm OPTIONAL 85: * } 86: * 87: * DhParams ::= SEQUENCE { 88: * p INTEGER, -- odd prime, p=jq +1 89: * g INTEGER, -- generator, g 90: * q INTEGER -- factor of p-1 91: * } 92: * </pre> 93: * 94: * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the 95: * DER-encoded form of the DH public key as an INTEGER.</p> 96: * 97: * <pre> 98: * DHPublicKey ::= INTEGER -- public key, y = g^x mod p 99: * </pre> 100: * <p> 101: * <b>IMPORTANT</b>: with RI's {@link javax.crypto.spec.DHGenParameterSpec} 102: * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with 103: * Diffie-Hellman keys that have a <code>null</code> for the <code>q</code> 104: * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that 105: * parameter, hence we replace such null values with <code>0</code>, and do 106: * the reverse in the corresponding decode method. 107: * 108: * @param key the {@link PublicKey} instance to encode. MUST be an instance of 109: * {@link GnuDHPublicKey}. 110: * @return the DER-encoded form of the ASN.1 representation of the 111: * <i>SubjectPublicKeyInfo</i> in an X.509 certificate. 112: * @throw InvalidParameterException if <code>key</code> is not an instance 113: * of {@link GnuDHPublicKey} or if an exception occurs during the 114: * marshalling process. 115: */ 116: public byte[] encodePublicKey(PublicKey key) 117: { 118: if (! (key instanceof GnuDHPublicKey)) 119: throw new InvalidParameterException("Wrong key type"); 120: 121: DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID); 122: 123: GnuDHPublicKey dhKey = (GnuDHPublicKey) key; 124: BigInteger p = dhKey.getParams().getP(); 125: BigInteger g = dhKey.getParams().getG(); 126: BigInteger q = dhKey.getQ(); 127: if (q == null) 128: q = BigInteger.ZERO; 129: BigInteger y = dhKey.getY(); 130: 131: DERValue derP = new DERValue(DER.INTEGER, p); 132: DERValue derG = new DERValue(DER.INTEGER, g); 133: DERValue derQ = new DERValue(DER.INTEGER, q); 134: 135: ArrayList params = new ArrayList(3); 136: params.add(derP); 137: params.add(derG); 138: params.add(derQ); 139: DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); 140: 141: ArrayList algorithmID = new ArrayList(2); 142: algorithmID.add(derOID); 143: algorithmID.add(derParams); 144: DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, 145: algorithmID); 146: 147: DERValue derDHPublicKey = new DERValue(DER.INTEGER, y); 148: byte[] yBytes = derDHPublicKey.getEncoded(); 149: DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes)); 150: 151: ArrayList spki = new ArrayList(2); 152: spki.add(derAlgorithmID); 153: spki.add(derSPK); 154: DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); 155: 156: byte[] result; 157: ByteArrayOutputStream baos = new ByteArrayOutputStream(); 158: try 159: { 160: DERWriter.write(baos, derSPKI); 161: result = baos.toByteArray(); 162: } 163: catch (IOException x) 164: { 165: InvalidParameterException e = new InvalidParameterException(); 166: e.initCause(x); 167: throw e; 168: } 169: 170: return result; 171: } 172: 173: /** 174: * @throws InvalidParameterException ALWAYS. 175: */ 176: public byte[] encodePrivateKey(PrivateKey key) 177: { 178: throw new InvalidParameterException("Wrong format for private keys"); 179: } 180: 181: /** 182: * @param input the byte array to unmarshall into a valid DH 183: * {@link PublicKey} instance. MUST NOT be null. 184: * @return a new instance of a {@link GnuDHPublicKey} decoded from the 185: * <i>SubjectPublicKeyInfo</i> material in an X.509 certificate. 186: * @throw InvalidParameterException if an exception occurs during the 187: * unmarshalling process. 188: */ 189: public PublicKey decodePublicKey(byte[] input) 190: { 191: if (input == null) 192: throw new InvalidParameterException("Input bytes MUST NOT be null"); 193: 194: BigInteger p, g, q, y; 195: DERReader der = new DERReader(input); 196: try 197: { 198: DERValue derSPKI = der.read(); 199: DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); 200: 201: DERValue derAlgorithmID = der.read(); 202: DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); 203: 204: DERValue derOID = der.read(); 205: if (! (derOID.getValue() instanceof OID)) 206: throw new InvalidParameterException("Wrong Algorithm field"); 207: 208: OID algOID = (OID) derOID.getValue(); 209: if (! algOID.equals(DH_ALG_OID)) 210: throw new InvalidParameterException("Unexpected OID: " + algOID); 211: 212: DERValue derParams = der.read(); 213: DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field"); 214: 215: DERValue val = der.read(); 216: DerUtil.checkIsBigInteger(val, "Wrong P field"); 217: p = (BigInteger) val.getValue(); 218: val = der.read(); 219: DerUtil.checkIsBigInteger(val, "Wrong G field"); 220: g = (BigInteger) val.getValue(); 221: val = der.read(); 222: DerUtil.checkIsBigInteger(val, "Wrong Q field"); 223: q = (BigInteger) val.getValue(); 224: if (q.compareTo(BigInteger.ZERO) == 0) 225: q = null; 226: 227: val = der.read(); 228: if (! (val.getValue() instanceof BitString)) 229: throw new InvalidParameterException("Wrong SubjectPublicKey field"); 230: 231: byte[] yBytes = ((BitString) val.getValue()).toByteArray(); 232: 233: DERReader dhPub = new DERReader(yBytes); 234: val = dhPub.read(); 235: DerUtil.checkIsBigInteger(val, "Wrong Y field"); 236: y = (BigInteger) val.getValue(); 237: } 238: catch (IOException x) 239: { 240: InvalidParameterException e = new InvalidParameterException(); 241: e.initCause(x); 242: throw e; 243: } 244: 245: return new GnuDHPublicKey(Registry.X509_ENCODING_ID, q, p, g, y); 246: } 247: 248: /** 249: * @throws InvalidParameterException ALWAYS. 250: */ 251: public PrivateKey decodePrivateKey(byte[] input) 252: { 253: throw new InvalidParameterException("Wrong format for private keys"); 254: } 255: }