Home | History | Annotate | Download | only in openssl
      1 package org.bouncycastle.openssl;
      2 
      3 import org.bouncycastle.crypto.PBEParametersGenerator;
      4 import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
      5 import org.bouncycastle.crypto.params.KeyParameter;
      6 
      7 import javax.crypto.Cipher;
      8 import javax.crypto.SecretKey;
      9 import javax.crypto.spec.IvParameterSpec;
     10 import javax.crypto.spec.RC2ParameterSpec;
     11 import java.io.IOException;
     12 import java.security.Key;
     13 import java.security.spec.AlgorithmParameterSpec;
     14 
     15 final class PEMUtilities
     16 {
     17     static byte[] crypt(
     18         boolean encrypt,
     19         String  provider,
     20         byte[]  bytes,
     21         char[]  password,
     22         String  dekAlgName,
     23         byte[]  iv)
     24         throws IOException
     25     {
     26         AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
     27         String                 alg;
     28         String                 blockMode = "CBC";
     29         String                 padding = "PKCS5Padding";
     30         Key                    sKey;
     31 
     32 
     33         // Figure out block mode and padding.
     34         if (dekAlgName.endsWith("-CFB"))
     35         {
     36             blockMode = "CFB";
     37             padding = "NoPadding";
     38         }
     39         if (dekAlgName.endsWith("-ECB") ||
     40             "DES-EDE".equals(dekAlgName) ||
     41             "DES-EDE3".equals(dekAlgName))
     42         {
     43             // ECB is actually the default (though seldom used) when OpenSSL
     44             // uses DES-EDE (des2) or DES-EDE3 (des3).
     45             blockMode = "ECB";
     46             paramSpec = null;
     47         }
     48         if (dekAlgName.endsWith("-OFB"))
     49         {
     50             blockMode = "OFB";
     51             padding = "NoPadding";
     52         }
     53 
     54 
     55         // Figure out algorithm and key size.
     56         if (dekAlgName.startsWith("DES-EDE"))
     57         {
     58             alg = "DESede";
     59             // "DES-EDE" is actually des2 in OpenSSL-speak!
     60             // "DES-EDE3" is des3.
     61             boolean des2 = !dekAlgName.startsWith("DES-EDE3");
     62             sKey = getKey(password, alg, 24, iv, des2);
     63         }
     64         else if (dekAlgName.startsWith("DES-"))
     65         {
     66             alg = "DES";
     67             sKey = getKey(password, alg, 8, iv);
     68         }
     69         else if (dekAlgName.startsWith("BF-"))
     70         {
     71             alg = "Blowfish";
     72             sKey = getKey(password, alg, 16, iv);
     73         }
     74         else if (dekAlgName.startsWith("RC2-"))
     75         {
     76             alg = "RC2";
     77             int keyBits = 128;
     78             if (dekAlgName.startsWith("RC2-40-"))
     79             {
     80                 keyBits = 40;
     81             }
     82             else if (dekAlgName.startsWith("RC2-64-"))
     83             {
     84                 keyBits = 64;
     85             }
     86             sKey = getKey(password, alg, keyBits / 8, iv);
     87             if (paramSpec == null) // ECB block mode
     88             {
     89                 paramSpec = new RC2ParameterSpec(keyBits);
     90             }
     91             else
     92             {
     93                 paramSpec = new RC2ParameterSpec(keyBits, iv);
     94             }
     95         }
     96         else if (dekAlgName.startsWith("AES-"))
     97         {
     98             alg = "AES";
     99             byte[] salt = iv;
    100             if (salt.length > 8)
    101             {
    102                 salt = new byte[8];
    103                 System.arraycopy(iv, 0, salt, 0, 8);
    104             }
    105 
    106             int keyBits;
    107             if (dekAlgName.startsWith("AES-128-"))
    108             {
    109                 keyBits = 128;
    110             }
    111             else if (dekAlgName.startsWith("AES-192-"))
    112             {
    113                 keyBits = 192;
    114             }
    115             else if (dekAlgName.startsWith("AES-256-"))
    116             {
    117                 keyBits = 256;
    118             }
    119             else
    120             {
    121                 throw new EncryptionException("unknown AES encryption with private key");
    122             }
    123             sKey = getKey(password, "AES", keyBits / 8, salt);
    124         }
    125         else
    126         {
    127             throw new EncryptionException("unknown encryption with private key");
    128         }
    129 
    130         String transformation = alg + "/" + blockMode + "/" + padding;
    131 
    132         try
    133         {
    134             Cipher c = Cipher.getInstance(transformation, provider);
    135             int    mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
    136 
    137             if (paramSpec == null) // ECB block mode
    138             {
    139                 c.init(mode, sKey);
    140             }
    141             else
    142             {
    143                 c.init(mode, sKey, paramSpec);
    144             }
    145             return c.doFinal(bytes);
    146         }
    147         catch (Exception e)
    148         {
    149             throw new EncryptionException("exception using cipher - please check password and data.", e);
    150         }
    151     }
    152 
    153     private static SecretKey getKey(
    154         char[]  password,
    155         String  algorithm,
    156         int     keyLength,
    157         byte[]  salt)
    158     {
    159         return getKey(password, algorithm, keyLength, salt, false);
    160     }
    161 
    162     private static SecretKey getKey(
    163         char[]  password,
    164         String  algorithm,
    165         int     keyLength,
    166         byte[]  salt,
    167         boolean des2)
    168     {
    169         OpenSSLPBEParametersGenerator   pGen = new OpenSSLPBEParametersGenerator();
    170 
    171         pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt);
    172 
    173         KeyParameter keyParam;
    174         keyParam = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8);
    175         byte[] key = keyParam.getKey();
    176         if (des2 && key.length >= 24)
    177         {
    178             // For DES2, we must copy first 8 bytes into the last 8 bytes.
    179             System.arraycopy(key, 0, key, 16, 8);
    180         }
    181         return new javax.crypto.spec.SecretKeySpec(key, algorithm);
    182     }
    183 }
    184