Home | History | Annotate | Download | only in ec
      1 package org.bouncycastle.jcajce.provider.asymmetric.ec;
      2 
      3 import java.math.BigInteger;
      4 import java.security.InvalidAlgorithmParameterException;
      5 import java.security.InvalidKeyException;
      6 import java.security.Key;
      7 import java.security.NoSuchAlgorithmException;
      8 import java.security.PrivateKey;
      9 import java.security.PublicKey;
     10 import java.security.SecureRandom;
     11 import java.security.spec.AlgorithmParameterSpec;
     12 import java.util.Hashtable;
     13 
     14 import javax.crypto.SecretKey;
     15 import javax.crypto.ShortBufferException;
     16 import javax.crypto.spec.SecretKeySpec;
     17 
     18 import org.bouncycastle.asn1.DERObjectIdentifier;
     19 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
     20 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     21 import org.bouncycastle.asn1.x9.X9IntegerConverter;
     22 import org.bouncycastle.crypto.BasicAgreement;
     23 import org.bouncycastle.crypto.CipherParameters;
     24 import org.bouncycastle.crypto.DerivationFunction;
     25 import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
     26 // BEGIN android-removed
     27 // import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
     28 // import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
     29 // import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
     30 // import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
     31 // END android-removed
     32 import org.bouncycastle.crypto.digests.SHA1Digest;
     33 import org.bouncycastle.crypto.params.ECDomainParameters;
     34 import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
     35 import org.bouncycastle.crypto.params.ECPublicKeyParameters;
     36 // BEGIN android-removed
     37 // import org.bouncycastle.crypto.params.MQVPrivateParameters;
     38 // import org.bouncycastle.crypto.params.MQVPublicParameters;
     39 // END android-removed
     40 import org.bouncycastle.jce.interfaces.ECPrivateKey;
     41 import org.bouncycastle.jce.interfaces.ECPublicKey;
     42 // BEGIN android-removed
     43 // import org.bouncycastle.jce.interfaces.MQVPrivateKey;
     44 // import org.bouncycastle.jce.interfaces.MQVPublicKey;
     45 // END android-removed
     46 import org.bouncycastle.util.Integers;
     47 
     48 /**
     49  * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
     50  * both the simple one, and the simple one with cofactors are supported.
     51  *
     52  * Also, MQV key agreement per SEC-1
     53  */
     54 public class KeyAgreementSpi
     55     extends javax.crypto.KeyAgreementSpi
     56 {
     57     private static final X9IntegerConverter converter = new X9IntegerConverter();
     58     private static final Hashtable algorithms = new Hashtable();
     59 
     60     static
     61     {
     62         Integer i128 = Integers.valueOf(128);
     63         Integer i192 = Integers.valueOf(192);
     64         Integer i256 = Integers.valueOf(256);
     65 
     66         algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
     67         algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
     68         algorithms.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
     69         algorithms.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
     70         algorithms.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
     71         algorithms.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
     72         algorithms.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
     73     }
     74 
     75     private String                 kaAlgorithm;
     76     private BigInteger             result;
     77     private ECDomainParameters     parameters;
     78     private BasicAgreement         agreement;
     79     // BEGIN android-removed
     80     // private DerivationFunction     kdf;
     81     // END android-removed
     82 
     83     private byte[] bigIntToBytes(
     84         BigInteger    r)
     85     {
     86         return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX()));
     87     }
     88 
     89     protected KeyAgreementSpi(
     90         String kaAlgorithm,
     91         BasicAgreement agreement,
     92         DerivationFunction kdf)
     93     {
     94         this.kaAlgorithm = kaAlgorithm;
     95         this.agreement = agreement;
     96         // BEGIN android-removed
     97         // this.kdf = kdf;
     98         // END android-removed
     99     }
    100 
    101     protected Key engineDoPhase(
    102         Key     key,
    103         boolean lastPhase)
    104         throws InvalidKeyException, IllegalStateException
    105     {
    106         if (parameters == null)
    107         {
    108             throw new IllegalStateException(kaAlgorithm + " not initialised.");
    109         }
    110 
    111         if (!lastPhase)
    112         {
    113             throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
    114         }
    115 
    116         CipherParameters pubKey;
    117         // BEGIN android-removed
    118         // if (agreement instanceof ECMQVBasicAgreement)
    119         // {
    120         //     if (!(key instanceof MQVPublicKey))
    121         //     {
    122         //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
    123         //             + getSimpleName(MQVPublicKey.class) + " for doPhase");
    124         //     }
    125         //
    126         //     MQVPublicKey mqvPubKey = (MQVPublicKey)key;
    127         //     ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
    128         //         ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
    129         //     ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
    130         //         ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
    131         //
    132         //     pubKey = new MQVPublicParameters(staticKey, ephemKey);
    133         //
    134         //     // TODO Validate that all the keys are using the same parameters?
    135         // }
    136         // else
    137         // END android-removed
    138         {
    139             if (!(key instanceof PublicKey))
    140             {
    141                 throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
    142                     + getSimpleName(ECPublicKey.class) + " for doPhase");
    143             }
    144 
    145             pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key);
    146 
    147             // TODO Validate that all the keys are using the same parameters?
    148         }
    149 
    150         result = agreement.calculateAgreement(pubKey);
    151 
    152         return null;
    153     }
    154 
    155     protected byte[] engineGenerateSecret()
    156         throws IllegalStateException
    157     {
    158         // BEGIN android-removed
    159         // if (kdf != null)
    160         // {
    161         //     throw new UnsupportedOperationException(
    162         //         "KDF can only be used when algorithm is known");
    163         // }
    164         // END android-removed
    165 
    166         return bigIntToBytes(result);
    167     }
    168 
    169     protected int engineGenerateSecret(
    170         byte[]  sharedSecret,
    171         int     offset)
    172         throws IllegalStateException, ShortBufferException
    173     {
    174         byte[] secret = engineGenerateSecret();
    175 
    176         if (sharedSecret.length - offset < secret.length)
    177         {
    178             throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
    179         }
    180 
    181         System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
    182 
    183         return secret.length;
    184     }
    185 
    186     protected SecretKey engineGenerateSecret(
    187         String algorithm)
    188         throws NoSuchAlgorithmException
    189     {
    190         byte[] secret = bigIntToBytes(result);
    191 
    192         // BEGIN android-removed
    193         // if (kdf != null)
    194         // {
    195         //     if (!algorithms.containsKey(algorithm))
    196         //     {
    197         //         throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
    198         //     }
    199         //
    200         //     int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
    201         //
    202         //     DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
    203         //
    204         //     byte[] keyBytes = new byte[keySize / 8];
    205         //     kdf.init(params);
    206         //     kdf.generateBytes(keyBytes, 0, keyBytes.length);
    207         //     secret = keyBytes;
    208         // }
    209         // else
    210         // END android-removed
    211         {
    212             // TODO Should we be ensuring the key is the right length?
    213         }
    214 
    215         return new SecretKeySpec(secret, algorithm);
    216     }
    217 
    218     protected void engineInit(
    219         Key                     key,
    220         AlgorithmParameterSpec  params,
    221         SecureRandom            random)
    222         throws InvalidKeyException, InvalidAlgorithmParameterException
    223     {
    224         // BEGIN android-added
    225         if (params != null)
    226         {
    227             throw new InvalidAlgorithmParameterException("No algorithm parameters supported");
    228         }
    229         // END android-added
    230         initFromKey(key);
    231     }
    232 
    233     protected void engineInit(
    234         Key             key,
    235         SecureRandom    random)
    236         throws InvalidKeyException
    237     {
    238         initFromKey(key);
    239     }
    240 
    241     private void initFromKey(Key key)
    242         throws InvalidKeyException
    243     {
    244         // BEGIN android-removed
    245         // if (agreement instanceof ECMQVBasicAgreement)
    246         // {
    247         //     if (!(key instanceof MQVPrivateKey))
    248         //     {
    249         //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
    250         //             + getSimpleName(MQVPrivateKey.class) + " for initialisation");
    251         //     }
    252         //
    253         //     MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
    254         //     ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
    255         //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
    256         //     ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
    257         //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
    258         //
    259         //     ECPublicKeyParameters ephemPubKey = null;
    260         //     if (mqvPrivKey.getEphemeralPublicKey() != null)
    261         //     {
    262         //         ephemPubKey = (ECPublicKeyParameters)
    263         //             ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
    264         //     }
    265         //
    266         //     MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
    267         //     this.parameters = staticPrivKey.getParameters();
    268         //
    269         //     // TODO Validate that all the keys are using the same parameters?
    270         //
    271         //     agreement.init(localParams);
    272         // }
    273         // else
    274         // END android-removed
    275         {
    276             if (!(key instanceof PrivateKey))
    277             {
    278                 throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
    279                     + getSimpleName(ECPrivateKey.class) + " for initialisation");
    280             }
    281 
    282             ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
    283             this.parameters = privKey.getParameters();
    284 
    285             agreement.init(privKey);
    286         }
    287     }
    288 
    289     private static String getSimpleName(Class clazz)
    290     {
    291         String fullName = clazz.getName();
    292 
    293         return fullName.substring(fullName.lastIndexOf('.') + 1);
    294     }
    295 
    296     public static class DH
    297         extends KeyAgreementSpi
    298     {
    299         public DH()
    300         {
    301             super("ECDH", new ECDHBasicAgreement(), null);
    302         }
    303     }
    304 
    305     // BEGIN android-removed
    306     // public static class DHC
    307     //     extends KeyAgreementSpi
    308     // {
    309     //     public DHC()
    310     //     {
    311     //         super("ECDHC", new ECDHCBasicAgreement(), null);
    312     //     }
    313     // }
    314     //
    315     // public static class MQV
    316     //     extends KeyAgreementSpi
    317     // {
    318     //     public MQV()
    319     //     {
    320     //         super("ECMQV", new ECMQVBasicAgreement(), null);
    321     //     }
    322     // }
    323     //
    324     // public static class DHwithSHA1KDF
    325     //     extends KeyAgreementSpi
    326     // {
    327     //     public DHwithSHA1KDF()
    328     //     {
    329     //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
    330     //     }
    331     // }
    332     //
    333     // public static class MQVwithSHA1KDF
    334     //     extends KeyAgreementSpi
    335     // {
    336     //     public MQVwithSHA1KDF()
    337     //     {
    338     //         super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
    339     //     }
    340     // }
    341     // END android-removed
    342 }
    343