Home | History | Annotate | Download | only in symmetric
      1 package org.bouncycastle.jcajce.provider.symmetric;
      2 
      3 import java.io.IOException;
      4 import java.security.spec.AlgorithmParameterSpec;
      5 import java.security.spec.InvalidKeySpecException;
      6 import java.security.spec.InvalidParameterSpecException;
      7 import java.security.spec.KeySpec;
      8 
      9 import javax.crypto.SecretKey;
     10 import javax.crypto.spec.PBEKeySpec;
     11 import javax.crypto.spec.PBEParameterSpec;
     12 
     13 import org.bouncycastle.asn1.ASN1Encoding;
     14 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     15 import org.bouncycastle.asn1.ASN1Primitive;
     16 // Android-removed: Unsupported algorithms
     17 // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
     18 import org.bouncycastle.asn1.pkcs.PBKDF2Params;
     19 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     20 import org.bouncycastle.crypto.CipherParameters;
     21 import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
     22 import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
     23 import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
     24 import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
     25 import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
     26 import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
     27 import org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
     28 
     29 public class PBEPBKDF2
     30 {
     31     private PBEPBKDF2()
     32     {
     33 
     34     }
     35 
     36     // BEGIN Android-removed: Unsupported algorithms
     37     /*
     38     public static class AlgParams
     39         extends BaseAlgorithmParameters
     40     {
     41         PBKDF2Params params;
     42 
     43         protected byte[] engineGetEncoded()
     44         {
     45             try
     46             {
     47                 return params.getEncoded(ASN1Encoding.DER);
     48             }
     49             catch (IOException e)
     50             {
     51                 throw new RuntimeException("Oooops! " + e.toString());
     52             }
     53         }
     54 
     55         protected byte[] engineGetEncoded(
     56             String format)
     57         {
     58             if (this.isASN1FormatString(format))
     59             {
     60                 return engineGetEncoded();
     61             }
     62 
     63             return null;
     64         }
     65 
     66         protected AlgorithmParameterSpec localEngineGetParameterSpec(
     67             Class paramSpec)
     68             throws InvalidParameterSpecException
     69         {
     70             if (paramSpec == PBEParameterSpec.class)
     71             {
     72                 return new PBEParameterSpec(params.getSalt(),
     73                                 params.getIterationCount().intValue());
     74             }
     75 
     76             throw new InvalidParameterSpecException("unknown parameter spec passed to PBKDF2 PBE parameters object.");
     77         }
     78 
     79         protected void engineInit(
     80             AlgorithmParameterSpec paramSpec)
     81             throws InvalidParameterSpecException
     82         {
     83             if (!(paramSpec instanceof PBEParameterSpec))
     84             {
     85                 throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PBKDF2 PBE parameters algorithm parameters object");
     86             }
     87 
     88             PBEParameterSpec    pbeSpec = (PBEParameterSpec)paramSpec;
     89 
     90             this.params = new PBKDF2Params(pbeSpec.getSalt(),
     91                                 pbeSpec.getIterationCount());
     92         }
     93 
     94         protected void engineInit(
     95             byte[] params)
     96             throws IOException
     97         {
     98             this.params = PBKDF2Params.getInstance(ASN1Primitive.fromByteArray(params));
     99         }
    100 
    101         protected void engineInit(
    102             byte[] params,
    103             String format)
    104             throws IOException
    105         {
    106             if (this.isASN1FormatString(format))
    107             {
    108                 engineInit(params);
    109                 return;
    110             }
    111 
    112             throw new IOException("Unknown parameters format in PBKDF2 parameters object");
    113         }
    114 
    115         protected String engineToString()
    116         {
    117             return "PBKDF2 Parameters";
    118         }
    119     }
    120     */
    121     // END Android-removed: Unsupported algorithms
    122 
    123     public static class BasePBKDF2
    124         extends BaseSecretKeyFactory
    125     {
    126         private int scheme;
    127         // BEGIN Android-added: Allow to specify a key using only the password.
    128         private int keySizeInBits;
    129         private int ivSizeInBits;
    130         // END Android-added: Allow to specify a key using only the password.
    131         private int defaultDigest;
    132 
    133         public BasePBKDF2(String name, int scheme)
    134         {
    135             this(name, scheme, SHA1);
    136         }
    137 
    138         // BEGIN Android-changed: Allow to specify a key using only the password.
    139         // public BasePBKDF2(String name, int scheme, int defaultDigest)
    140         private BasePBKDF2(
    141                 String name, int scheme, int digest, int keySizeInBits, int ivSizeInBits)
    142         // END Android-changed: Allow to specify a key using only the password.
    143         {
    144             super(name, PKCSObjectIdentifiers.id_PBKDF2);
    145 
    146             this.scheme = scheme;
    147             // BEGIN Android-added: Support key-restricted versions.
    148             this.keySizeInBits = keySizeInBits;
    149             this.ivSizeInBits = ivSizeInBits;
    150             // END Android-added: Support key-restricted versions.
    151             this.defaultDigest = digest;
    152         }
    153 
    154         // BEGIN Android-added: Allow to specify a key using only the password.
    155         private BasePBKDF2(String name, int scheme, int digest) {
    156             this(name, scheme, digest, 0, 0);
    157         }
    158         // END Android-added: Allow to specify a key using only the password.
    159 
    160         protected SecretKey engineGenerateSecret(
    161             KeySpec keySpec)
    162             throws InvalidKeySpecException
    163         {
    164             if (keySpec instanceof PBEKeySpec)
    165             {
    166                 PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
    167 
    168                 // BEGIN Android-added: Allow to specify a key using only the password.
    169                 // The key will be generated later when other parameters are known.
    170                 if (pbeSpec.getSalt() == null
    171                         && pbeSpec.getIterationCount() == 0
    172                         && pbeSpec.getKeyLength() == 0
    173                         && pbeSpec.getPassword().length > 0
    174                         && keySizeInBits != 0) {
    175                     return new BCPBEKey(
    176                             this.algName, this.algOid, scheme, defaultDigest, keySizeInBits,
    177                             ivSizeInBits, pbeSpec,
    178                             // cipherParameters, to be generated when the PBE parameters are known.
    179                             null);
    180                 }
    181                 // END Android-added: Allow to specify a key using only the password.
    182 
    183                 if (pbeSpec.getSalt() == null)
    184                 {
    185                     throw new InvalidKeySpecException("missing required salt");
    186                 }
    187 
    188                 if (pbeSpec.getIterationCount() <= 0)
    189                 {
    190                     throw new InvalidKeySpecException("positive iteration count required: "
    191                         + pbeSpec.getIterationCount());
    192                 }
    193 
    194                 if (pbeSpec.getKeyLength() <= 0)
    195                 {
    196                     throw new InvalidKeySpecException("positive key length required: "
    197                         + pbeSpec.getKeyLength());
    198                 }
    199 
    200                 if (pbeSpec.getPassword().length == 0)
    201                 {
    202                     throw new IllegalArgumentException("password empty");
    203                 }
    204 
    205                 if (pbeSpec instanceof PBKDF2KeySpec)
    206                 {
    207                     PBKDF2KeySpec spec = (PBKDF2KeySpec)pbeSpec;
    208 
    209                     int digest = getDigestCode(spec.getPrf().getAlgorithm());
    210                     int keySize = pbeSpec.getKeyLength();
    211                     int ivSize = -1;    // JDK 1,2 and earlier does not understand simplified version.
    212                     CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
    213 
    214                     return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
    215                 }
    216                 else
    217                 {
    218                     int digest = defaultDigest;
    219                     int keySize = pbeSpec.getKeyLength();
    220                     int ivSize = -1;    // JDK 1,2 and earlier does not understand simplified version.
    221                     CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
    222 
    223                     return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
    224                 }
    225             }
    226 
    227             throw new InvalidKeySpecException("Invalid KeySpec");
    228         }
    229 
    230 
    231         private int getDigestCode(ASN1ObjectIdentifier algorithm)
    232             throws InvalidKeySpecException
    233         {
    234             // BEGIN Android-removed: Unsupported algorithms
    235             /*
    236             if (algorithm.equals(CryptoProObjectIdentifiers.gostR3411Hmac))
    237             {
    238                 return GOST3411;
    239             }
    240             else
    241             */
    242             // END Android-removed: Unsupported algorithms
    243             if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA1))
    244             {
    245                 return SHA1;
    246             }
    247             else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA256))
    248             {
    249                 return SHA256;
    250             }
    251             else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA224))
    252             {
    253                 return SHA224;
    254             }
    255             else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA384))
    256             {
    257                 return SHA384;
    258             }
    259             else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA512))
    260             {
    261                 return SHA512;
    262             }
    263 
    264             throw new InvalidKeySpecException("Invalid KeySpec: unknown PRF algorithm " + algorithm);
    265         }
    266     }
    267 
    268     // BEGIN Android-removed: Unsupported algorithms
    269     /*
    270     public static class PBKDF2withUTF8
    271         extends BasePBKDF2
    272     {
    273         public PBKDF2withUTF8()
    274         {
    275             super("PBKDF2", PKCS5S2_UTF8);
    276         }
    277     }
    278 
    279     public static class PBKDF2withSHA224
    280         extends BasePBKDF2
    281     {
    282         public PBKDF2withSHA224()
    283         {
    284             super("PBKDF2", PKCS5S2_UTF8, SHA224);
    285         }
    286     }
    287 
    288     public static class PBKDF2withSHA256
    289         extends BasePBKDF2
    290     {
    291         public PBKDF2withSHA256()
    292         {
    293             super("PBKDF2", PKCS5S2_UTF8, SHA256);
    294         }
    295     }
    296 
    297     public static class PBKDF2withSHA384
    298         extends BasePBKDF2
    299     {
    300         public PBKDF2withSHA384()
    301         {
    302             super("PBKDF2", PKCS5S2_UTF8, SHA384);
    303         }
    304     }
    305     public static class PBKDF2withSHA512
    306         extends BasePBKDF2
    307     {
    308         public PBKDF2withSHA512()
    309         {
    310             super("PBKDF2", PKCS5S2_UTF8, SHA512);
    311         }
    312     }
    313 
    314     public static class PBKDF2with8BIT
    315         extends BasePBKDF2
    316     {
    317         public PBKDF2with8BIT()
    318         {
    319             super("PBKDF2", PKCS5S2);
    320         }
    321     }
    322     */
    323     // END Android-removed: Unsupported algorithms
    324 
    325     // BEGIN Android-added: Android implementations of PBKDF2 algorithms.
    326     // See note in Mappings below.
    327     public static class BasePBKDF2WithHmacSHA1 extends BasePBKDF2 {
    328         public BasePBKDF2WithHmacSHA1(String name, int scheme)
    329         {
    330             super(name, scheme, SHA1);
    331         }
    332     }
    333 
    334     public static class PBKDF2WithHmacSHA1UTF8
    335             extends BasePBKDF2WithHmacSHA1
    336     {
    337         public PBKDF2WithHmacSHA1UTF8()
    338         {
    339             super("PBKDF2WithHmacSHA1", PKCS5S2_UTF8);
    340         }
    341     }
    342 
    343     public static class PBKDF2WithHmacSHA18BIT
    344             extends BasePBKDF2WithHmacSHA1
    345     {
    346         public PBKDF2WithHmacSHA18BIT()
    347         {
    348             super("PBKDF2WithHmacSHA1And8bit", PKCS5S2);
    349         }
    350     }
    351 
    352     public static class BasePBKDF2WithHmacSHA224 extends BasePBKDF2 {
    353         public BasePBKDF2WithHmacSHA224(String name, int scheme)
    354         {
    355             super(name, scheme, SHA224);
    356         }
    357     }
    358 
    359     public static class PBKDF2WithHmacSHA224UTF8
    360             extends BasePBKDF2WithHmacSHA224
    361     {
    362         public PBKDF2WithHmacSHA224UTF8()
    363         {
    364             super("PBKDF2WithHmacSHA224", PKCS5S2_UTF8);
    365         }
    366     }
    367 
    368     public static class BasePBKDF2WithHmacSHA256 extends BasePBKDF2 {
    369         public BasePBKDF2WithHmacSHA256(String name, int scheme)
    370         {
    371             super(name, scheme, SHA256);
    372         }
    373     }
    374 
    375     public static class PBKDF2WithHmacSHA256UTF8
    376             extends BasePBKDF2WithHmacSHA256
    377     {
    378         public PBKDF2WithHmacSHA256UTF8()
    379         {
    380             super("PBKDF2WithHmacSHA256", PKCS5S2_UTF8);
    381         }
    382     }
    383 
    384 
    385     public static class BasePBKDF2WithHmacSHA384 extends BasePBKDF2 {
    386         public BasePBKDF2WithHmacSHA384(String name, int scheme)
    387         {
    388             super(name, scheme, SHA384);
    389         }
    390     }
    391 
    392     public static class PBKDF2WithHmacSHA384UTF8
    393             extends BasePBKDF2WithHmacSHA384
    394     {
    395         public PBKDF2WithHmacSHA384UTF8()
    396         {
    397             super("PBKDF2WithHmacSHA384", PKCS5S2_UTF8);
    398         }
    399     }
    400 
    401     public static class BasePBKDF2WithHmacSHA512 extends BasePBKDF2 {
    402         public BasePBKDF2WithHmacSHA512(String name, int scheme)
    403         {
    404             super(name, scheme, SHA512);
    405         }
    406     }
    407 
    408     public static class PBKDF2WithHmacSHA512UTF8
    409             extends BasePBKDF2WithHmacSHA512
    410     {
    411         public PBKDF2WithHmacSHA512UTF8()
    412         {
    413             super("PBKDF2WithHmacSHA512", PKCS5S2_UTF8);
    414         }
    415     }
    416 
    417     public static class PBEWithHmacSHA1AndAES_128
    418             extends BasePBKDF2 {
    419         public PBEWithHmacSHA1AndAES_128() {
    420             super("PBEWithHmacSHA1AndAES_128", PKCS5S2_UTF8, SHA1, 128, 128);
    421         }
    422     }
    423 
    424     public static class PBEWithHmacSHA224AndAES_128
    425             extends BasePBKDF2 {
    426         public PBEWithHmacSHA224AndAES_128() {
    427             super("PBEWithHmacSHA224AndAES_128", PKCS5S2_UTF8, SHA224, 128, 128);
    428         }
    429     }
    430 
    431     public static class PBEWithHmacSHA256AndAES_128
    432             extends BasePBKDF2 {
    433         public PBEWithHmacSHA256AndAES_128() {
    434             super("PBEWithHmacSHA256AndAES_128", PKCS5S2_UTF8, SHA256, 128, 128);
    435         }
    436     }
    437 
    438     public static class PBEWithHmacSHA384AndAES_128
    439             extends BasePBKDF2 {
    440         public PBEWithHmacSHA384AndAES_128() {
    441             super("PBEWithHmacSHA384AndAES_128", PKCS5S2_UTF8, SHA384, 128, 128);
    442         }
    443     }
    444 
    445     public static class PBEWithHmacSHA512AndAES_128
    446             extends BasePBKDF2 {
    447         public PBEWithHmacSHA512AndAES_128() {
    448             super("PBEWithHmacSHA512AndAES_128", PKCS5S2_UTF8, SHA512, 128, 128);
    449         }
    450     }
    451 
    452 
    453     public static class PBEWithHmacSHA1AndAES_256
    454             extends BasePBKDF2 {
    455         public PBEWithHmacSHA1AndAES_256() {
    456             super("PBEWithHmacSHA1AndAES_256", PKCS5S2_UTF8, SHA1, 256, 128);
    457         }
    458     }
    459 
    460     public static class PBEWithHmacSHA224AndAES_256
    461             extends BasePBKDF2 {
    462         public PBEWithHmacSHA224AndAES_256() {
    463             super("PBEWithHmacSHA224AndAES_256", PKCS5S2_UTF8, SHA224, 256, 128);
    464         }
    465     }
    466 
    467     public static class PBEWithHmacSHA256AndAES_256
    468             extends BasePBKDF2 {
    469         public PBEWithHmacSHA256AndAES_256() {
    470             super("PBEWithHmacSHA256AndAES_256", PKCS5S2_UTF8, SHA256, 256, 128);
    471         }
    472     }
    473 
    474     public static class PBEWithHmacSHA384AndAES_256
    475             extends BasePBKDF2 {
    476         public PBEWithHmacSHA384AndAES_256() {
    477             super("PBEWithHmacSHA384AndAES_256", PKCS5S2_UTF8, SHA384, 256, 128);
    478         }
    479     }
    480 
    481     public static class PBEWithHmacSHA512AndAES_256
    482             extends BasePBKDF2 {
    483         public PBEWithHmacSHA512AndAES_256() {
    484             super("PBEWithHmacSHA512AndAES_256", PKCS5S2_UTF8, SHA512, 256, 128);
    485         }
    486     }
    487     // END Android-added: Android implementations of PBKDF2 algorithms.
    488 
    489     public static class Mappings
    490         extends AlgorithmProvider
    491     {
    492         private static final String PREFIX = PBEPBKDF2.class.getName();
    493 
    494         public Mappings()
    495         {
    496         }
    497 
    498         public void configure(ConfigurableProvider provider)
    499         {
    500             // Android-note: Provided classes differ significantly from upstream.
    501             // Before BC 1.56, this class was omitted in Android and the algorithms we desired
    502             // were provided in org.bouncycastle.jcajce.provider.digest.SHA1.  During that
    503             // time, Android added some additional versions of these algorithms for fixed key sizes.
    504             // BC eventually consolidated the algorithms into this class.  As a result, when
    505             // upgrading to BC 1.56, we added this class but replaced its contents with
    506             // our versions.
    507             // BEGIN Android-removed: Bouncy Castle versions of algorithms.
    508             /*
    509             provider.addAlgorithm("AlgorithmParameters.PBKDF2", PREFIX + "$AlgParams");
    510             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
    511             provider.addAlgorithm("SecretKeyFactory.PBKDF2", PREFIX + "$PBKDF2withUTF8");
    512             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1", "PBKDF2");
    513             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1ANDUTF8", "PBKDF2");
    514             provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
    515             provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHASCII", PREFIX + "$PBKDF2with8BIT");
    516             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITH8BIT", "PBKDF2WITHASCII");
    517             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1AND8BIT", "PBKDF2WITHASCII");
    518             provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA224", PREFIX + "$PBKDF2withSHA224");
    519             provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA256", PREFIX + "$PBKDF2withSHA256");
    520             provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA384", PREFIX + "$PBKDF2withSHA384");
    521             provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA512", PREFIX + "$PBKDF2withSHA512");
    522             */
    523             // END Android-removed: Bouncy Castle versions of algorithms.
    524             // BEGIN Android-added: Android versions of algorithms.
    525             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WithHmacSHA1AndUTF8", "PBKDF2WithHmacSHA1");
    526             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2with8BIT", "PBKDF2WithHmacSHA1And8BIT");
    527             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2withASCII", "PBKDF2WithHmacSHA1And8BIT");
    528             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1", PREFIX + "$PBKDF2WithHmacSHA1UTF8");
    529             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA224", PREFIX + "$PBKDF2WithHmacSHA224UTF8");
    530             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA256", PREFIX + "$PBKDF2WithHmacSHA256UTF8");
    531             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA384", PREFIX + "$PBKDF2WithHmacSHA384UTF8");
    532             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA512", PREFIX + "$PBKDF2WithHmacSHA512UTF8");
    533             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA1AndAES_128", PREFIX + "$PBEWithHmacSHA1AndAES_128");
    534             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA224AndAES_128", PREFIX + "$PBEWithHmacSHA224AndAES_128");
    535             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA256AndAES_128", PREFIX + "$PBEWithHmacSHA256AndAES_128");
    536             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA384AndAES_128", PREFIX + "$PBEWithHmacSHA384AndAES_128");
    537             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_128", PREFIX + "$PBEWithHmacSHA512AndAES_128");
    538             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA1AndAES_256", PREFIX + "$PBEWithHmacSHA1AndAES_256");
    539             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA224AndAES_256", PREFIX + "$PBEWithHmacSHA224AndAES_256");
    540             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA256AndAES_256", PREFIX + "$PBEWithHmacSHA256AndAES_256");
    541             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA384AndAES_256", PREFIX + "$PBEWithHmacSHA384AndAES_256");
    542             provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_256", PREFIX + "$PBEWithHmacSHA512AndAES_256");
    543             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
    544             // END Android-added: Android versions of algorithms.
    545         }
    546     }
    547 }
    548