summaryrefslogtreecommitdiffstats
path: root/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
diff options
context:
space:
mode:
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java')
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java337
1 files changed, 337 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
new file mode 100644
index 0000000..38a7143
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -0,0 +1,337 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+import org.bouncycastle.crypto.BasicAgreement;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
+// import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
+// import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
+// import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.MQVPrivateParameters;
+// import org.bouncycastle.crypto.params.MQVPublicParameters;
+// END android-removed
+import org.bouncycastle.jce.interfaces.ECPrivateKey;
+import org.bouncycastle.jce.interfaces.ECPublicKey;
+// BEGIN android-removed
+// import org.bouncycastle.jce.interfaces.MQVPrivateKey;
+// import org.bouncycastle.jce.interfaces.MQVPublicKey;
+// END android-removed
+
+/**
+ * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+ * both the simple one, and the simple one with cofactors are supported.
+ *
+ * Also, MQV key agreement per SEC-1
+ */
+public class KeyAgreementSpi
+ extends javax.crypto.KeyAgreementSpi
+{
+ private static final X9IntegerConverter converter = new X9IntegerConverter();
+ private static final Hashtable algorithms = new Hashtable();
+
+ static
+ {
+ // BEGIN android-changed
+ Integer i128 = Integer.valueOf(128);
+ Integer i192 = Integer.valueOf(192);
+ Integer i256 = Integer.valueOf(256);
+ // END android-changed
+
+ algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
+ algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
+ algorithms.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
+ algorithms.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
+ algorithms.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
+ algorithms.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
+ algorithms.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
+ }
+
+ private String kaAlgorithm;
+ private BigInteger result;
+ private ECDomainParameters parameters;
+ private BasicAgreement agreement;
+ // BEGIN android-removed
+ // private DerivationFunction kdf;
+ // END android-removed
+
+ private byte[] bigIntToBytes(
+ BigInteger r)
+ {
+ return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX()));
+ }
+
+ protected KeyAgreementSpi(
+ String kaAlgorithm,
+ BasicAgreement agreement,
+ DerivationFunction kdf)
+ {
+ this.kaAlgorithm = kaAlgorithm;
+ this.agreement = agreement;
+ // BEGIN android-removed
+ // this.kdf = kdf;
+ // END android-removed
+ }
+
+ protected Key engineDoPhase(
+ Key key,
+ boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ if (parameters == null)
+ {
+ throw new IllegalStateException(kaAlgorithm + " not initialised.");
+ }
+
+ if (!lastPhase)
+ {
+ throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
+ }
+
+ CipherParameters pubKey;
+ // BEGIN android-removed
+ // if (agreement instanceof ECMQVBasicAgreement)
+ // {
+ // if (!(key instanceof MQVPublicKey))
+ // {
+ // throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ // + getSimpleName(MQVPublicKey.class) + " for doPhase");
+ // }
+ //
+ // MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+ // ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+ // ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+ // ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+ // ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+ //
+ // pubKey = new MQVPublicParameters(staticKey, ephemKey);
+ //
+ // // TODO Validate that all the keys are using the same parameters?
+ // }
+ // else
+ // END android-removed
+ {
+ if (!(key instanceof ECPublicKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPublicKey.class) + " for doPhase");
+ }
+
+ pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key);
+
+ // TODO Validate that all the keys are using the same parameters?
+ }
+
+ result = agreement.calculateAgreement(pubKey);
+
+ return null;
+ }
+
+ protected byte[] engineGenerateSecret()
+ throws IllegalStateException
+ {
+ // BEGIN android-removed
+ // if (kdf != null)
+ // {
+ // throw new UnsupportedOperationException(
+ // "KDF can only be used when algorithm is known");
+ // }
+ // END android-removed
+
+ return bigIntToBytes(result);
+ }
+
+ protected int engineGenerateSecret(
+ byte[] sharedSecret,
+ int offset)
+ throws IllegalStateException, ShortBufferException
+ {
+ byte[] secret = engineGenerateSecret();
+
+ if (sharedSecret.length - offset < secret.length)
+ {
+ throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
+ }
+
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+
+ return secret.length;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ byte[] secret = bigIntToBytes(result);
+
+ // BEGIN android-removed
+ // if (kdf != null)
+ // {
+ // if (!algorithms.containsKey(algorithm))
+ // {
+ // throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
+ // }
+ //
+ // int keySize = ((Integer)algorithms.get(algorithm)).intValue();
+ //
+ // DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
+ //
+ // byte[] keyBytes = new byte[keySize / 8];
+ // kdf.init(params);
+ // kdf.generateBytes(keyBytes, 0, keyBytes.length);
+ // secret = keyBytes;
+ // }
+ // else
+ // END android-removed
+ {
+ // TODO Should we be ensuring the key is the right length?
+ }
+
+ return new SecretKeySpec(secret, algorithm);
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initFromKey(key);
+ }
+
+ protected void engineInit(
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ initFromKey(key);
+ }
+
+ private void initFromKey(Key key)
+ throws InvalidKeyException
+ {
+ // BEGIN android-removed
+ // if (agreement instanceof ECMQVBasicAgreement)
+ // {
+ // if (!(key instanceof MQVPrivateKey))
+ // {
+ // throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ // + getSimpleName(MQVPrivateKey.class) + " for initialisation");
+ // }
+ //
+ // MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+ // ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
+ // ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+ // ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
+ // ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+ //
+ // ECPublicKeyParameters ephemPubKey = null;
+ // if (mqvPrivKey.getEphemeralPublicKey() != null)
+ // {
+ // ephemPubKey = (ECPublicKeyParameters)
+ // ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+ // }
+ //
+ // MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+ // this.parameters = staticPrivKey.getParameters();
+ //
+ // // TODO Validate that all the keys are using the same parameters?
+ //
+ // agreement.init(localParams);
+ // }
+ // else
+ // END android-removed
+ {
+ if (!(key instanceof ECPrivateKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPrivateKey.class) + " for initialisation");
+ }
+
+ ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+ this.parameters = privKey.getParameters();
+
+ agreement.init(privKey);
+ }
+ }
+
+ private static String getSimpleName(Class clazz)
+ {
+ String fullName = clazz.getName();
+
+ return fullName.substring(fullName.lastIndexOf('.') + 1);
+ }
+
+ public static class DH
+ extends KeyAgreementSpi
+ {
+ public DH()
+ {
+ super("ECDH", new ECDHBasicAgreement(), null);
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class DHC
+ // extends KeyAgreementSpi
+ // {
+ // public DHC()
+ // {
+ // super("ECDHC", new ECDHCBasicAgreement(), null);
+ // }
+ // }
+ //
+ // public static class MQV
+ // extends KeyAgreementSpi
+ // {
+ // public MQV()
+ // {
+ // super("ECMQV", new ECMQVBasicAgreement(), null);
+ // }
+ // }
+ //
+ // public static class DHwithSHA1KDF
+ // extends KeyAgreementSpi
+ // {
+ // public DHwithSHA1KDF()
+ // {
+ // super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ // }
+ // }
+ //
+ // public static class MQVwithSHA1KDF
+ // extends KeyAgreementSpi
+ // {
+ // public MQVwithSHA1KDF()
+ // {
+ // super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ // }
+ // }
+ // END android-removed
+}