001: package org.bouncycastle.jce.provider;
002:
003: import org.bouncycastle.asn1.DERObjectIdentifier;
004: import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
005: import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
006: import org.bouncycastle.asn1.x9.X9IntegerConverter;
007: import org.bouncycastle.crypto.BasicAgreement;
008: import org.bouncycastle.crypto.CipherParameters;
009: import org.bouncycastle.crypto.DerivationFunction;
010: import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
011: import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
012: import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
013: import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
014: import org.bouncycastle.crypto.digests.SHA1Digest;
015: import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
016: import org.bouncycastle.jce.interfaces.ECPrivateKey;
017: import org.bouncycastle.jce.interfaces.ECPublicKey;
018:
019: import javax.crypto.KeyAgreementSpi;
020: import javax.crypto.SecretKey;
021: import javax.crypto.ShortBufferException;
022: import javax.crypto.spec.SecretKeySpec;
023: import java.math.BigInteger;
024: import java.security.InvalidAlgorithmParameterException;
025: import java.security.InvalidKeyException;
026: import java.security.Key;
027: import java.security.NoSuchAlgorithmException;
028: import java.security.PrivateKey;
029: import java.security.PublicKey;
030: import java.security.SecureRandom;
031: import java.security.spec.AlgorithmParameterSpec;
032: import java.util.Hashtable;
033:
034: /**
035: * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
036: * both the simple one, and the simple one with cofactors are supported.
037: */
038: public class JCEECDHKeyAgreement extends KeyAgreementSpi {
039: private static final X9IntegerConverter converter = new X9IntegerConverter();
040: private static final Hashtable algorithms = new Hashtable();
041:
042: static {
043: Integer i128 = new Integer(128);
044: Integer i192 = new Integer(192);
045: Integer i256 = new Integer(256);
046:
047: algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(),
048: i128);
049: algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(),
050: i192);
051: algorithms.put(NISTObjectIdentifiers.id_aes256_CBC.getId(),
052: i256);
053: algorithms.put(NISTObjectIdentifiers.id_aes128_wrap.getId(),
054: i128);
055: algorithms.put(NISTObjectIdentifiers.id_aes192_wrap.getId(),
056: i192);
057: algorithms.put(NISTObjectIdentifiers.id_aes256_wrap.getId(),
058: i256);
059: algorithms.put(
060: PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
061: }
062:
063: private BigInteger result;
064: private ECPrivateKeyParameters privKey;
065: private BasicAgreement agreement;
066: private DerivationFunction kdf;
067:
068: private byte[] bigIntToBytes(BigInteger r) {
069: return converter.integerToBytes(r, converter
070: .getByteLength(privKey.getParameters().getG().getX()));
071: }
072:
073: protected JCEECDHKeyAgreement(BasicAgreement agreement) {
074: this .agreement = agreement;
075: }
076:
077: protected JCEECDHKeyAgreement(BasicAgreement agreement,
078: DerivationFunction kdf) {
079: this .agreement = agreement;
080: this .kdf = kdf;
081: }
082:
083: protected Key engineDoPhase(Key key, boolean lastPhase)
084: throws InvalidKeyException, IllegalStateException {
085: if (privKey == null) {
086: throw new IllegalStateException(
087: "EC Diffie-Hellman not initialised.");
088: }
089:
090: if (!lastPhase) {
091: throw new IllegalStateException(
092: "EC Diffie-Hellman can only be between two parties.");
093: }
094:
095: if (!(key instanceof ECPublicKey)) {
096: throw new InvalidKeyException(
097: "EC Key Agreement doPhase requires ECPublicKey");
098: }
099:
100: CipherParameters pubKey = ECUtil
101: .generatePublicKeyParameter((PublicKey) key);
102:
103: result = agreement.calculateAgreement(pubKey);
104:
105: return null;
106: }
107:
108: protected byte[] engineGenerateSecret()
109: throws IllegalStateException {
110: return bigIntToBytes(result);
111: }
112:
113: protected int engineGenerateSecret(byte[] sharedSecret, int offset)
114: throws IllegalStateException, ShortBufferException {
115: byte[] secret = bigIntToBytes(result);
116:
117: if (sharedSecret.length - offset < secret.length) {
118: throw new ShortBufferException(
119: "ECKeyAgreement - buffer too short");
120: }
121:
122: System
123: .arraycopy(secret, 0, sharedSecret, offset,
124: secret.length);
125:
126: return secret.length;
127: }
128:
129: protected SecretKey engineGenerateSecret(String algorithm)
130: throws NoSuchAlgorithmException {
131: if (kdf != null) {
132: if (!algorithms.containsKey(algorithm)) {
133: throw new NoSuchAlgorithmException(
134: "unknown algorithm encountered: " + algorithm);
135: }
136:
137: int keySize = ((Integer) algorithms.get(algorithm))
138: .intValue();
139:
140: DHKDFParameters params = new DHKDFParameters(
141: new DERObjectIdentifier(algorithm), keySize,
142: bigIntToBytes(result));
143:
144: byte[] keyBytes = new byte[keySize / 8];
145:
146: kdf.init(params);
147:
148: kdf.generateBytes(keyBytes, 0, keyBytes.length);
149:
150: return new SecretKeySpec(keyBytes, algorithm);
151: }
152:
153: return new SecretKeySpec(bigIntToBytes(result), algorithm);
154: }
155:
156: protected void engineInit(Key key, AlgorithmParameterSpec params,
157: SecureRandom random) throws InvalidKeyException,
158: InvalidAlgorithmParameterException {
159: if (!(key instanceof ECPrivateKey)) {
160: throw new InvalidKeyException(
161: "ECKeyAgreement requires ECPrivateKey for initialisation");
162: }
163:
164: privKey = (ECPrivateKeyParameters) ECUtil
165: .generatePrivateKeyParameter((PrivateKey) key);
166:
167: agreement.init(privKey);
168: }
169:
170: protected void engineInit(Key key, SecureRandom random)
171: throws InvalidKeyException {
172: if (!(key instanceof ECPrivateKey)) {
173: throw new InvalidKeyException(
174: "ECKeyAgreement requires ECPrivateKey");
175: }
176:
177: privKey = (ECPrivateKeyParameters) ECUtil
178: .generatePrivateKeyParameter((PrivateKey) key);
179:
180: agreement.init(privKey);
181: }
182:
183: public static class DH extends JCEECDHKeyAgreement {
184: public DH() {
185: super (new ECDHBasicAgreement());
186: }
187: }
188:
189: public static class DHC extends JCEECDHKeyAgreement {
190: public DHC() {
191: super (new ECDHCBasicAgreement());
192: }
193: }
194:
195: public static class DHwithSHA1KDF extends JCEECDHKeyAgreement {
196: public DHwithSHA1KDF() {
197: super (new ECDHBasicAgreement(), new ECDHKEKGenerator(
198: new SHA1Digest()));
199: }
200: }
201: }
|