not-yet-commons-ssl-0.3.11

6;
      }
      javaCipher = "AES";
      ivSize = 128;
    }
    else if (javaCipher.startsWith("CAMELLIA"))
    {
      if (javaCipher.startsWith("CAMELLIA128")) {
        keySize = 128;
      } else if (javaCipher.startsWith("CAMELLIA192")) {
        keySize = 192;
      } else if (javaCipher.startsWith("CAMELLIA256")) {
        keySize = 256;
      }
      javaCipher = "CAMELLIA";
      ivSize = 128;
    }
    if (keySize == -1) {
      if (javaCipher.startsWith("DESede")) {
        keySize = 192;
      } else if (javaCipher.startsWith("DES")) {
        keySize = 64;
      } else {
        keySize = 128;
      }
    }
    return new CipherInfo(javaCipher, blockMode, keySize, ivSize, des2);
  }
  
  public static void main(String[] args)
    throws IOException, GeneralSecurityException
  {
    if (args.length < 3)
    {
      System.out.println(Version.versionString());
      System.out.println("Pure-java utility to decrypt files previously encrypted by 'openssl enc'");
      System.out.println();
      System.out.println("Usage:  java -cp commons-ssl.jar org.apache.commons.ssl.OpenSSL [args]");
      System.out.println("        [args]   == [password] [cipher] [file-to-decrypt]");
      System.out.println("        [cipher] == des, des3, des-ede3-cbc, aes256, rc2, rc4, bf, bf-cbc, etc...");
      System.out.println("                    Try 'man enc' on a unix box to see what's possible.");
      System.out.println();
      System.out.println("This utility can handle base64 or raw, salted or unsalted.");
      System.out.println();
      System.exit(1);
    }
    char[] password = args[0].toCharArray();
    
    InputStream in = new FileInputStream(args[2]);
    in = decrypt(args[1], password, in);
    
    in = new BufferedInputStream(in);
    BufferedOutputStream bufOut = new BufferedOutputStream(System.out);
    Util.pipeStream(in, bufOut, false);
    bufOut.flush();
    System.out.flush();
  }
}

/* Location:
 * Qualified Name:     org.apache.commons.ssl.OpenSSL
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package org.apache.commons.ssl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

public class PBETestCreate
{
  public static void main(String[] args)
    throws Exception
  {
    FileInputStream in = new FileInputStream(args[0]);
    Properties p = new Properties();
    p.load(in);
    in.close();
    
    String targetDir = p.getProperty("target");
    File dir = new File(targetDir);
    dir.mkdirs();
    if (!dir.exists()) {
      throw new IOException(dir.getCanonicalPath() + " doesn't exist!");
    }
    TreeSet ciphers = new TreeSet();
    Iterator it = p.entrySet().iterator();
    while (it.hasNext())
    {
      Map.Entry entry = (Map.Entry)it.next();
      String key = (String)entry.getKey();
      if (!"target".equalsIgnoreCase(key))
      {
        ciphers.add(key);
        ciphers.add(key + "-cbc");
        ciphers.add(key + "-cfb");
        ciphers.add(key + "-cfb1");
        ciphers.add(key + "-cfb8");
        ciphers.add(key + "-ecb");
        ciphers.add(key + "-ofb");
      }
    }
    byte[] toEncrypt = "Hello World!".getBytes("UTF-8");
    char[] pwd = "changeit".toCharArray();
    it = ciphers.iterator();
    while (it.hasNext())
    {
      String cipher = (String)it.next();
      String cipherPadded = Util.pad(cipher, 15, false);
      String fileNameBase64 = cipher + ".base64";
      String fileNameRaw = cipher + ".raw";
      String d = dir.getCanonicalPath() + "/";
      try
      {
        byte[] base64 = OpenSSL.encrypt(cipher, pwd, toEncrypt, true);
        FileOutputStream out = new FileOutputStream(d + fileNameBase64);
        out.write(base64);
        out.close();
      }
      catch (Exception e)
      {
        System.err.println("FAILURE \t" + cipherPadded + "\t" + fileNameBase64 + "\t" + e);
      }
      try
      {
        byte[] raw = OpenSSL.encrypt(cipher, pwd, toEncrypt, false);
        FileOutputStream out = new FileOutputStream(d + fileNameRaw);
        out.write(raw);
        out.close();
      }
      catch (Exception e)
      {
        System.err.println("FAILURE \t" + cipherPadded + "\t" + fileNameRaw + "\t" + e);
      }
    }
  }
}

/* Location:
 * Qualified Name:     org.apache.commons.ssl.PBETestCreate
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package org.apache.commons.ssl;

import java.util.Collections;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import org.apache.commons.ssl.util.Hex;

public class PEMItem
{
  public static final String DEK_INFO = "dek-info";
  private final byte[] derBytes;
  public final String pemType;
  public final Map properties;
  public final String dekInfo;
  public final byte[] iv;
  public final String cipher;
  public final boolean des2;
  public final String mode;
  public final int keySizeInBits;
  
  public PEMItem(byte[] derBytes, String type)
  {
    this(derBytes, type, null);
  }
  
  public PEMItem(byte[] derBytes, String type, Map properties)
  {
    this.derBytes = derBytes;
    pemType = type;
    if (properties == null) {
      properties = new TreeMap();
    }
    this.properties = Collections.unmodifiableMap(properties);
    String di = (String)properties.get("dek-info");
    String diCipher = "";
    String diIV = "";
    if (di != null)
    {
      StringTokenizer st = new StringTokenizer(di, ",");
      if (st.hasMoreTokens()) {
        diCipher = st.nextToken().trim().toLowerCase();
      }
      if (st.hasMoreTokens()) {
        diIV = st.nextToken().trim().toLowerCase();
      }
    }
    dekInfo = diCipher;
    iv = Hex.decode(diIV);
    if (!"".equals(diCipher))
    {
      OpenSSL.CipherInfo cipherInfo = OpenSSL.lookup(diCipher);
      cipher = javaCipher;
      mode = blockMode;
      keySizeInBits = keySize;
      des2 = des2;
    }
    else
    {
      mode = "";
      cipher = "UNKNOWN";
      keySizeInBits = -1;
      des2 = false;
    }
  }
  
  public byte[] getDerBytes()
  {
    byte[] b = new byte[derBytes.length];
    System.arraycopy(derBytes, 0, b, 0, derBytes.length);
    return b;
  }
}

/* Location:
 * Qualified Name:     org.apache.commons.ssl.PEMItem
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package org.apache.commons.ssl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.PublicKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.ssl.util.ByteArrayReadLine;

public class PEMUtil
{
  static final String LINE_SEPARATOR = System.getProperty("line.separator");
  
  public static byte[] encode(Collection items)
    throws IOException
  {
    byte[] LINE_SEPARATOR_BYTES = LINE_SEPARATOR.getBytes("UTF-8");
    ByteArrayOutputStream out = new ByteArrayOutputStream(8192);
    Iterator it = items.iterator();
    while (it.hasNext())
    {
      PEMItem item = (PEMItem)it.next();
      out.write("-----BEGIN ".getBytes("UTF-8"));
      out.write(pemType.getBytes("UTF-8"));
      out.write("-----".getBytes("UTF-8"));
      out.write(LINE_SEPARATOR_BYTES);
      
      byte[] derBytes = item.getDerBytes();
      ByteArrayInputStream bin = new ByteArrayInputStream(derBytes);
      byte[] line = Util.streamToBytes(bin, 48);
      while (line.length == 48)
      {
        byte[] base64Line = Base64.encodeBase64(line);
        out.write(base64Line);
        out.write(LINE_SEPARATOR_BYTES);
        line = Util.streamToBytes(bin, 48);
      }
      if (line.length > 0)
      {
        byte[] base64Line = Base64.encodeBase64(line);
        out.write(base64Line);
        out.write(LINE_SEPARATOR_BYTES);
      }
      out.write("-----END ".getBytes("UTF-8"));
      out.write(pemType.getBytes("UTF-8"));
      out.write("-----".getBytes("UTF-8"));
      out.write(LINE_SEPARATOR_BYTES);
    }
    return out.toByteArray();
  }
  
  public static List decode(byte[] pemBytes)
  {
    LinkedList pemItems = new LinkedList();
    ByteArrayInputStream in = new ByteArrayInputStream(pemBytes);
    ByteArrayReadLine readLine = new ByteArrayReadLine(in);
    String line = readLine.next();
    while (line != null)
    {
      int len = 0;
      
      ArrayList listOfByteArrays = new ArrayList(64);
      Map properties = new HashMap();
      String type = "[unknown]";
      while ((line != null) && (!beginBase64(line))) {
        line = readLine.next();
      }
      if (line != null)
      {
        String upperLine = line.toUpperCase();
        int x = upperLine.indexOf("-BEGIN") + "-BEGIN".length();
        int y = upperLine.indexOf("-", x);
        type = upperLine.substring(x, y).trim();
        line = readLine.next();
      }
      while ((line != null) && (!endBase64(line)))
      {
        line = Util.trim(line);
        if (!"".equals(line))
        {
          int x = line.indexOf(':');
          if (x > 0)
          {
            String k = line.substring(0, x).trim();
            String v = "";
            if (line.length() > x + 1) {
              v = line.substring(x + 1).trim();
            }
            properties.put(k.toLowerCase(), v.toLowerCase());
          }
          else
          {
            byte[] base64 = line.getBytes();
            byte[] rawBinary = Base64.decodeBase64(base64);
            listOfByteArrays.add(rawBinary);
            len += rawBinary.length;
          }
        }
        line = readLine.next();
      }
      if (line != null) {
        line = readLine.next();
      }
      if (!listOfByteArrays.isEmpty())
      {
        byte[] decoded = new byte[len];
        int pos = 0;
        Iterator it = listOfByteArrays.iterator();
        while (it.hasNext())
        {
          byte[] oneLine = (byte[])it.next();
          System.arraycopy(oneLine, 0, decoded, pos, oneLine.length);
          pos += oneLine.length;
        }
        PEMItem item = new PEMItem(decoded, type, properties);
        pemItems.add(item);
      }
    }
    return pemItems;
  }
  
  private static boolean beginBase64(String line)
  {
    line = line != null ? line.trim().toUpperCase() : "";
    int x = line.indexOf("-BEGIN");
    return (x > 0) && (startsAndEndsWithDashes(line));
  }
  
  private static boolean endBase64(String line)
  {
    line = line != null ? line.trim().toUpperCase() : "";
    int x = line.indexOf("-END");
    return (x > 0) && (startsAndEndsWithDashes(line));
  }
  
  private static boolean startsAndEndsWithDashes(String line)
  {
    line = Util.trim(line);
    char c = line.charAt(0);
    char d = line.charAt(line.length() - 1);
    return (c == '-') && (d == '-');
  }
  
  public static String formatRSAPrivateKey(RSAPrivateCrtKey key)
  {
    StringBuffer buf = new StringBuffer(2048);
    buf.append("Private-Key:");
    buf.append(LINE_SEPARATOR);
    buf.append("modulus:");
    buf.append(LINE_SEPARATOR);
    buf.append(formatBigInteger(key.getModulus(), 258));
    buf.append(LINE_SEPARATOR);
    buf.append("publicExponent: ");
    buf.append(key.getPublicExponent());
    buf.append(LINE_SEPARATOR);
    buf.append("privateExponent:");
    buf.append(LINE_SEPARATOR);
    buf.append(formatBigInteger(key.getPrivateExponent(), 256));
    buf.append(LINE_SEPARATOR);
    buf.append("prime1:");
    buf.append(LINE_SEPARATOR);
    buf.append(formatBigInteger(key.getPrimeP(), 130));
    buf.append(LINE_SEPARATOR);
    buf.append("prime2:");
    buf.append(LINE_SEPARATOR);
    buf.append(formatBigInteger(key.getPrimeQ(), 130));
    buf.append(LINE_SEPARATOR);
    buf.append("exponent1:");
    buf.append(LINE_SEPARATOR);
    buf.append(formatBigInteger(key.getPrimeExponentP(), 130));
    buf.append(LINE_SEPARATOR);
    buf.append("exponent2:");
    buf.append(LINE_SEPARATOR);
    buf.append(formatBigInteger(key.getPrimeExponentQ(), 130));
    buf.append(LINE_SEPARATOR);
    buf.append("coefficient:");
    buf.append(LINE_SEPARATOR);
    buf.append(formatBigInteger(key.getCrtCoefficient(), 130));
    return buf.toString();
  }
  
  public static String formatBigInteger(BigInteger bi, int length)
  {
    String s = bi.toString(16);
    StringBuffer buf = new StringBuffer(s.length());
    int zeroesToAppend = length - s.length();
    int count = 0;
    buf.append("    ");
    for (int i = 0; i < zeroesToAppend; i++)
    {
      count++;
      buf.append('0');
      if (i % 2 == 1) {
        buf.append(':');
      }
    }
    for (int i = 0; i < s.length() - 2; i++)
    {
      count++;
      buf.append(s.charAt(i));
      if (i % 2 == 1) {
        buf.append(':');
      }
      if (count % 30 == 0)
      {
        buf.append(LINE_SEPARATOR);
        buf.append("    ");
      }
    }
    buf.append(s.substring(s.length() - 2));
    return buf.toString();
  }
  
  public static String toPem(PublicKey key)
    throws IOException
  {
    PEMItem item = null;
    if ((key instanceof RSAPublicKey)) {
      item = new PEMItem(key.getEncoded(), "PUBLIC KEY");
    } else if ((key instanceof DSAPublicKey)) {
      item = new PEMItem(key.getEncoded(), "PUBLIC KEY");
    } else {
      throw new IOException("Not an RSA or DSA key");
    }
    byte[] pem = encode(Collections.singleton(item));
    return new String(pem, "UTF-8");
  }
}

/* Location:
 * Qualified Name:     org.apache.commons.ssl.PEMUtil
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package org.apache.commons.ssl;

public class PKCS8Key$DecryptResult
{
  public final String transformation;
  public final int keySize;
  public final byte[] bytes;
  
  protected PKCS8Key$DecryptResult(String transformation, int keySize, byte[] decryptedBytes)
  {
    this.transformation = transformation;
    this.keySize = keySize;
    bytes = decryptedBytes;
  }
}

/* Location:
 * Qualified Name:     org.apache.commons.ssl.PKCS8Key.DecryptResult
 * Java Class Version: 1.2 (46.0)
 * JD-Core Version:    0.7.1
 */
package org.apache.commons.ssl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.RC2ParameterSpec;
import javax.crypto.spec.RC5ParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.ssl.asn1.ASN1EncodableVector;
import org.apache.commons.ssl.asn1.ASN1OutputStream;
import org.apache.commons.ssl.asn1.DEREncodable;
import org.apache.commons.ssl.asn1.DERInteger;
import org.apache.commons.ssl.asn1.DERNull;
import org.apache.commons.ssl.asn1.DERObjectIdentifier;
import org.apache.commons.ssl.asn1.DEROctetString;
import org.apache.commons.ssl.asn1.DERSequence;

public class PKCS8Key
{
  public static final String RSA_OID = "1.2.840.113549.1.1.1";
  public static final String DSA_OID = "1.2.840.10040.4.1";
  public static final String PKCS8_UNENCRYPTED = "PRIVATE KEY";
  public static final String PKCS8_ENCRYPTED = "ENCRYPTED PRIVATE KEY";
  public static final String OPENSSL_RSA = "RSA PRIVATE KEY";
  public static final String OPENSSL_DSA = "DSA PRIVATE KEY";
  private final PrivateKey privateKey;
  private final byte[] decryptedBytes;
  private final String transformation;
  private final int keySize;
  private final boolean isDSA;
  private final boolean isRSA;
  
  public PKCS8Key(InputStream in, char[] password)
    throws GeneralSecurityException, IOException
  {
    this(Util.streamToBytes(in), password);
  }
  
  public PKCS8Key(ByteArrayInputStream in, char[] password)
    throws GeneralSecurityException
  {
    this(Util.streamToBytes(in), password);
  }
  
  public PKCS8Key(byte[] encoded, char[] password)
    throws GeneralSecurityException
  {
    DecryptResult decryptResult = new DecryptResult("UNENCRYPTED", 0, encoded);
    
    List pemItems = PEMUtil.decode(encoded);
    PEMItem keyItem = null;
    byte[] derBytes = null;
    if (pemItems.isEmpty())
    {
      derBytes = encoded;
    }
    else
    {
      Iterator it = pemItems.iterator();
      boolean opensslRSA = false;
      boolean opensslDSA = false;
      while (it.hasNext())
      {
        PEMItem item = (PEMItem)it.next();
        String type = pemType.trim().toUpperCase();
        boolean plainPKCS8 = type.startsWith("PRIVATE KEY");
        boolean encryptedPKCS8 = type.startsWith("ENCRYPTED PRIVATE KEY");
        boolean rsa = type.startsWith("RSA PRIVATE KEY");
        boolean dsa = type.startsWith("DSA PRIVATE KEY");
        if ((plainPKCS8) || (encryptedPKCS8) || (rsa) || (dsa))
        {
          opensslRSA = (opensslRSA) || (rsa);
          opensslDSA = (opensslDSA) || (dsa);
          if (derBytes != null) {
            throw new ProbablyNotPKCS8Exception("More than one pkcs8 or OpenSSL key found in the supplied PEM Base64 stream");
          }
          derBytes = item.getDerBytes();
          keyItem = item;
          decryptResult = new DecryptResult("UNENCRYPTED", 0, derBytes);
        }
      }
      if (derBytes == null) {
        throw new ProbablyNotPKCS8Exception("No pkcs8 or OpenSSL key found in the supplied PEM Base64 stream");
      }
      if ((opensslDSA) || (opensslRSA))
      {
        String c = cipher.trim();
        boolean encrypted = (!"UNKNOWN".equals(c)) && (!"".equals(c));
        if (encrypted) {
          decryptResult = opensslDecrypt(keyItem, password);
        }
        String oid = "1.2.840.113549.1.1.1";
        if (opensslDSA) {
          oid = "1.2.840.10040.4.1";
        }
        derBytes = formatAsPKCS8(bytes, oid, null);
        
        String tf = transformation;
        int ks = keySize;
        decryptResult = new DecryptResult(tf, ks, derBytes);
      }
    }
    try
    {
      pkcs8 = ASN1Util.analyze(derBytes);
    }
    catch (Exception e)
    {
      ASN1Structure pkcs8;
      throw new ProbablyNotPKCS8Exception("asn1 parse failure: " + e);
    }
    ASN1Structure pkcs8;
    String oid = "1.2.840.113549.1.1.1";
    
    int derIntegerCount = -1;
    if (derIntegers != null) {
      derIntegerCount = derIntegers.size();
    }
    switch (derIntegerCount)
    {
    case 6: 
      oid = "1.2.840.10040.4.1";
    case 9: 
      derBytes = formatAsPKCS8(derBytes, oid, pkcs8);
      oid1 = oid;
      
      String tf = transformation;
      int ks = keySize;
      decryptResult = new DecryptResult(tf, ks, derBytes);
      break;
    }
    oid = oid1;
    if (!oid.startsWith("1.2.840.113549.1"))
    {
      boolean isOkay = false;
      if (oid.startsWith("1.2.840.10040.4."))
      {
        String s = oid.substring("1.2.840.10040.4.".length());
        
        isOkay = (s.equals("1")) || (s.startsWith("1.")) || (s.equals("3")) || (s.startsWith("3."));
      }
      if (!isOkay) {
        throw new ProbablyNotPKCS8Exception("Valid ASN.1, but not PKCS8 or OpenSSL format.  OID=" + oid);
      }
    }
    boolean isRSA = "1.2.840.113549.1.1.1".equals(oid);
    boolean isDSA = "1.2.840.10040.4.1".equals(oid);
    boolean encrypted = (!isRSA) && (!isDSA);
    byte[] decryptedPKCS8 = encrypted ? null : derBytes;
    if (encrypted)
    {
      decryptResult = decryptPKCS8(pkcs8, password);
      decryptedPKCS8 = bytes;
    }
    if (encrypted)
    {
      try
      {
        pkcs8 = ASN1Util.analyze(decryptedPKCS8);
      }
      catch (Exception e)
      {
        throw new ProbablyBadPasswordException("Decrypted stream not ASN.1.  Probably bad decryption password.");
      }
      oid = oid1;
      isDSA = "1.2.840.10040.4.1".equals(oid);
    }
    KeySpec spec = new PKCS8EncodedKeySpec(decryptedPKCS8);
    String type = "RSA";
    try
    {
      KeyFactory KF;
      KeyFactory KF;
      if (isDSA)
      {
        type = "DSA";
        KF = KeyFactory.getInstance("DSA");
      }
      else
      {
        KF = KeyFactory.getInstance("RSA");
      }
      pk = KF.generatePrivate(spec);
    }
    catch (Exception e)
    {
      PrivateKey pk;
      throw new ProbablyBadPasswordException("Cannot create " + type + " private key from decrypted stream.  Probably bad decryption password. " + e);
    }
    PrivateKey pk;
    if (pk != null)
    {
      privateKey = pk;
      this.isDSA = isDSA;
      this.isRSA = (!isDSA);
      decryptedBytes = decryptedPKCS8;
      transformation = transformation;
      keySize = keySize;
    }
    else
    {
      throw new GeneralSecurityException("KeyFactory.generatePrivate() returned null and didn't throw exception!");
    }
  }
  
  public boolean isRSA()
  {
    return isRSA;
  }
  
  public boolean isDSA()
  {
    return isDSA;
  }
  
  public String getTransformation()
  {
    return transformation;
  }
  
  public int getKeySize()
  {
    return keySize;
  }
  
  public byte[] getDecryptedBytes()
  {
    return decryptedBytes;
  }
  
  public PrivateKey getPrivateKey()
  {
    return privateKey;
  }
  
  public PublicKey getPublicKey()
    throws GeneralSecurityException
  {
    if ((privateKey instanceof DSAPrivateKey))
    {
      DSAPrivateKey dsa = (DSAPrivateKey)privateKey;
      DSAParams params = dsa.getParams();
      BigInteger g = params.getG();
      BigInteger p = params.getP();
      BigInteger q = params.getQ();
      BigInteger x = dsa.getX();
      BigInteger y = q.modPow(x, p);
      DSAPublicKeySpec dsaKeySpec = new DSAPublicKeySpec(y, p, q, g);
      return KeyFactory.getInstance("DSA").generatePublic(dsaKeySpec);
    }
    if ((privateKey instanceof RSAPrivateCrtKey))
    {
      RSAPrivateCrtKey rsa = (RSAPrivateCrtKey)privateKey;
      RSAPublicKeySpec rsaKeySpec = new RSAPublicKeySpec(rsa.getModulus(), rsa.getPublicExponent());
      
      return KeyFactory.getInstance("RSA").generatePublic(rsaKeySpec);
    }
    throw new GeneralSecurityException("Not an RSA or DSA key");
  }
  
  public static class DecryptResult
  {
    public final String transformation;
    public final int keySize;
    public final byte[] bytes;
    
    protected DecryptResult(String transformation, int keySize, byte[] decryptedBytes)
    {
      this.transformation = transformation;
      this.keySize = keySize;
      bytes = decryptedBytes;
    }
  }
  
  private static DecryptResult opensslDecrypt(PEMItem item, char[] password)
    throws GeneralSecurityException
  {
    String cipher = item.cipher;
    String mode = item.mode;
    int keySize = keySizeInBits;
    byte[] salt = iv;
    boolean des2 = item.des2;
    DerivedKey dk = OpenSSL.deriveKey(password, salt, keySize, des2);
    return decrypt(cipher, mode, dk, des2, null, item.getDerBytes());
  }
  
  public static Cipher generateCipher(String cipher, String mode, DerivedKey dk, boolean des2, byte[] iv, boolean decryptMode)
    throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException
  {
    if ((des2) && (key.length >= 24)) {
      System.arraycopy(key, 0, key, 16, 8);
    }
    int keySize = key.length * 8;
    cipher = cipher.trim();
    String cipherUpper = cipher.toUpperCase();
    mode = mode.trim().toUpperCase();
    
    Cipher.getInstance(cipher);
    String padding = "PKCS5Padding";
    if ((mode.startsWith("CFB")) || (mode.startsWith("OFB"))) {
      padding = "NoPadding";
    }
    String transformation = cipher + "/" + mode + "/" + padding;
    if (cipherUpper.startsWith("RC4")) {
      transformation = cipher;
    }
    SecretKey secret = new SecretKeySpec(key, cipher);
    IvParameterSpec ivParams;
    IvParameterSpec ivParams;
    if (iv != null) {
      ivParams = new IvParameterSpec(iv);
    } else {
      ivParams = iv != null ? new IvParameterSpec(iv) : null;
    }
    Cipher c = Cipher.getInstance(transformation);
    int cipherMode = 1;
    if (decryptMode) {
      cipherMode = 2;
    }
    if (cipherUpper.startsWith("RC2"))
    {
      RC2ParameterSpec rcParams;
      RC2ParameterSpec rcParams;
      if ((mode.startsWith("ECB")) || (ivParams == null)) {
        rcParams = new RC2ParameterSpec(keySize);
      } else {
        rcParams = new RC2ParameterSpec(keySize, ivParams.getIV());
      }
      c.init(cipherMode, secret, rcParams);
    }
    else if (cipherUpper.startsWith("RC5"))
    {
      RC5ParameterSpec rcParams;
      RC5ParameterSpec rcParams;
      if ((mode.startsWith("ECB")) || (ivParams == null)) {
        rcParams = new RC5ParameterSpec(16, 12, 32);
      } else {
        rcParams = new RC5ParameterSpec(16, 12, 32, ivParams.getIV());
      }
      c.init(cipherMode, secret, rcParams);
    }
    else if ((mode.startsWith("ECB")) || (cipherUpper.startsWith("RC4")))
    {
      c.init(cipherMode, secret);
    }
    else
    {
      c.init(cipherMode, secret, ivParams);
    }
    return c;
  }
  
  public static DecryptResult decrypt(String cipher, String mode, DerivedKey dk, boolean des2, byte[] iv, byte[] encryptedBytes)
    throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
  {
    Cipher c = generateCipher(cipher, mode, dk, des2, iv, true);
    String transformation = c.getAlgorithm();
    int keySize = key.length * 8;
    byte[] decryptedBytes = c.doFinal(encryptedBytes);
    return new DecryptResult(transformation, keySize, decryptedBytes);
  }
  
  private static DecryptResult decryptPKCS8(ASN1Structure pkcs8, char[] password)
    throws GeneralSecurityException
  {
    boolean isVersion1 = true;
    boolean isVersion2 = false;
    boolean usePKCS12PasswordPadding = false;
    boolean use2DES = false;
    String cipher = null;
    String hash = null;
    int keySize = -1;
    
    String mode = "CBC";
    
    int ivSize = 0;
    
    String oid = oid1;
    if (oid.startsWith("1.2.840.113549.1.12."))
    {
      usePKCS12PasswordPadding = true;
      
      oid = oid.substring("1.2.840.113549.1.12.".length());
      if ((oid.equals("1.1")) || (oid.startsWith("1.1.")))
      {
        hash = "SHA1";
        cipher = "RC4";
        keySize = 128;
      }
      else if ((oid.equals("1.2")) || (oid.startsWith("1.2.")))
      {
        hash = "SHA1";
        cipher = "RC4";
        keySize = 40;
      }
      else if ((oid.equals("1.3")) || (oid.startsWith("1.3.")))
      {
        hash = "SHA1";
        cipher = "DESede";
        keySize = 192;
      }
      else if ((oid.equals("1.4")) || (oid.startsWith("1.4.")))
      {
        hash = "SHA1";
        cipher = "DESede";
        keySize = 192;
        use2DES = true;
      }
      else if ((oid.equals("1.5")) || (oid.startsWith("1.5.")))
      {
        hash = "SHA1";
        cipher = "RC2";
        keySize = 128;
      }
      else if ((oid.equals("1.6")) || (oid.startsWith("1.6.")))
      {
        hash = "SHA1";
        cipher = "RC2";
        keySize = 40;
      }
    }
    else if (oid.startsWith("1.2.840.113549.1.5."))
    {
      oid = oid.substring("1.2.840.113549.1.5.".length());
      if ((oid.equals("1")) || (oid.startsWith("1.")))
      {
        hash = "MD2";
        cipher = "DES";
        keySize = 64;
      }
      else if ((oid.equals("3")) || (oid.startsWith("3.")))
      {
        hash = "MD5";
        cipher = "DES";
        keySize = 64;
      }
      else if ((oid.equals("4")) || (oid.startsWith("4.")))
      {
        hash = "MD2";
        cipher = "RC2";
        keySize = 64;
      }
      else if ((oid.equals("6")) || (oid.startsWith("6.")))
      {
        hash = "MD5";
        cipher = "RC2";
        keySize = 64;
      }
      else if ((oid.equals("10")) || (oid.startsWith("10.")))
      {
        hash = "SHA1";
        cipher = "DES";
        keySize = 64;
      }
      else if ((oid.equals("11")) || (oid.startsWith("11.")))
      {
        hash = "SHA1";
        cipher = "RC2";
        keySize = 64;
      }
      else if ((oid.equals("12")) || (oid.startsWith("12.")))
      {
        isVersion2 = true;
      }
      else if ((oid.equals("13")) || (oid.startsWith("13.")))
      {
        isVersion2 = true;
      }
      else if ((oid.equals("14")) || (oid.startsWith("14.")))
      {
        isVersion2 = true;
      }
    }
    if (isVersion2)
    {
      isVersion1 = false;
      hash = "HmacSHA1";
      oid = oid2;
      if (oid3 != null) {
        oid = oid3;
      }
      if (oid.startsWith("1.3.6.1.4.1.3029.1.2"))
      {
        cipher = "Blowfish";
        mode = "CBC";
        keySize = 128;
      }
      else if (oid.startsWith("1.3.14.3.2."))
      {
        oid = oid.substring("1.3.14.3.2.".length());
        if ((oid.equals("6")) || (oid.startsWith("6.")))
        {
          cipher = "DES";
          mode = "ECB";
          keySize = 64;
        }
        else if ((oid.equals("7")) || (oid.startsWith("7.")))
        {
          cipher = "DES";
          mode = "CBC";
          keySize = 64;
        }
        else if ((oid.equals("8")) || (oid.startsWith("8.")))
        {
          cipher = "DES";
          mode = "OFB";
          keySize = 64;
        }
        else if ((oid.equals("9")) || (oid.startsWith("9.")))
        {
          cipher = "DES";
          mode = "CFB";
          keySize = 64;
        }
        else if ((oid.equals("17")) || (oid.startsWith("17.")))
        {
          cipher = "DESede";
          mode = "CBC";
          keySize = 192;
          if (allZeroes(iv))
          {
            mode = "ECB";
            use2DES = true;
            iv = null;
          }
        }
      }
      else if (oid.startsWith("2.16.840.1.101.3.4.1."))
      {
        cipher = "AES";
        if (iv == null) {
          ivSize = 128;
        }
        oid = oid.substring("2.16.840.1.101.3.4.1.".length());
        int x = oid.indexOf('.');
        int finalDigit;
        int finalDigit;
        if (x >= 0) {
          finalDigit = Integer.parseInt(oid.substring(0, x));
        } else {
          finalDigit = Integer.parseInt(oid);
        }
        switch (finalDigit % 10)
        {
        case 1: 
          mode = "ECB";
          break;
        case 2: 
          mode = "CBC";
          break;
        case 3: 
          mode = "OFB";
          break;
        case 4: 
          mode = "CFB";
          break;
        default: 
          throw new RuntimeException("Unknown AES final digit: " + finalDigit);
        }
        switch (finalDigit / 10)
        {
        case 0: 
          keySize = 128;
          break;
        case 2: 
          keySize = 192;
          break;
        case 4: 
          keySize = 256;
          break;
        case 1: 
        case 3: 
        default: 
          throw new RuntimeException("Unknown AES final digit: " + finalDigit);
        }
      }
      else if (oid.startsWith("1.2.840.113549.3."))
      {
        oid = oid.substring("1.2.840.113549.3.".length());
        if ((oid.equals("2")) || (oid.startsWith("2.")))
        {
          cipher = "RC2";
          keySize = pkcs8.keySize * 8;
        }
        else if ((oid.equals("4")) || (oid.startsWith("4.")))
        {
          cipher = "RC4";
          keySize = pkcs8.keySize * 8;
        }
        else if ((oid.equals("7")) || (oid.startsWith("7.")))
        {
          cipher = "DESede";
          keySize = 192;
        }
        else if ((oid.equals("9")) || (oid.startsWith("9.")))
        {
          keySize = pkcs8.keySize * 8;
          cipher = "RC5";
        }
      }
    }
    if ((cipher == null) || (hash == null)) {
      throw new ProbablyNotPKCS8Exception("Unsupported PKCS8 format. oid1=[" + oid1 + "], oid2=[" + oid2 + "]");
    }
    if (iv == null) {
      ivSize = 64;
    }
    byte[] salt = pkcs8.salt;
    int ic = iterationCount;
    
    byte[] pwd = new byte[password.length];
    for (int i = 0; i < pwd.length; i++) {
      pwd[i] = ((byte)password[i]);
    }
    DerivedKey dk;
    DerivedKey dk;
    if (usePKCS12PasswordPadding)
    {
      MessageDigest md = MessageDigest.getInstance(hash);
      dk = deriveKeyPKCS12(password, salt, ic, keySize, ivSize, md);
    }
    else
    {
      DerivedKey dk;
      if (isVersion1)
      {
        MessageDigest md = MessageDigest.getInstance(hash);
        dk = deriveKeyV1(pwd, salt, ic, keySize, ivSize, md);
      }
      else
      {
        Mac mac = Mac.getInstance(hash);
        dk = deriveKeyV2(pwd, salt, ic, keySize, ivSize, mac);
      }
    }
    return decrypt(cipher, mode, dk, use2DES, iv, bigPayload);
  }
  
  public static DerivedKey deriveKeyV1(byte[] password, byte[] salt, int iterations, int keySizeInBits, int ivSizeInBits, MessageDigest md)
  {
    int keySize = keySizeInBits / 8;
    int ivSize = ivSizeInBits / 8;
    md.reset();
    md.update(password);
    byte[] result = md.digest(salt);
    for (int i = 1; i < iterations; i++) {
      result = md.digest(result);
    }
    byte[] key = new byte[keySize];
    byte[] iv = new byte[ivSize];
    System.arraycopy(result, 0, key, 0, key.length);
    System.arraycopy(result, key.length, iv, 0, iv.length);
    return new DerivedKey(key, iv);
  }
  
  public static DerivedKey deriveKeyPKCS12(char[] password, byte[] salt, int iterations, int keySizeInBits, int ivSizeInBits, MessageDigest md)
  {
    byte[] pwd;
    if (password.length > 0)
    {
      byte[] pwd = new byte[(password.length + 1) * 2];
      for (int i = 0; i < password.length; i++)
      {
        pwd[(i * 2)] = ((byte)(password[i] >>> '\b'));
        pwd[(i * 2 + 1)] = ((byte)password[i]);
      }
    }
    else
    {
      pwd = new byte[0];
    }
    int keySize = keySizeInBits / 8;
    int ivSize = ivSizeInBits / 8;
    byte[] key = pkcs12(1, keySize, salt, pwd, iterations, md);
    byte[] iv = pkcs12(2, ivSize, salt, pwd, iterations, md);
    return new DerivedKey(key, iv);
  }
  
  private static byte[] pkcs12(int idByte, int n, byte[] salt, byte[] password, int iterationCount, MessageDigest md)
  {
    int u = md.getDigestLength();
    
    int v = 64;
    md.reset();
    byte[] D = new byte[v];
    byte[] dKey = new byte[n];
    for (int i = 0; i != D.length; i++) {
      D[i] = ((byte)idByte);
    }
    byte[] S;
    if ((salt != null) && (salt.length != 0))
    {
      byte[] S = new byte[v * ((salt.length + v - 1) / v)];
      for (int i = 0; i != S.length; i++) {
        S[i] = salt[(i % salt.length)];
      }
    }
    else
    {
      S = new byte[0];
    }
    byte[] P;
    if ((password != null) && (password.length != 0))
    {
      byte[] P = new byte[v * ((password.length + v - 1) / v)];
      for (int i = 0; i != P.length; i++) {
        P[i] = password[(i % password.length)];
      }
    }
    else
    {
      P = new byte[0];
    }
    byte[] I = new byte[S.length + P.length];
    System.arraycopy(S, 0, I, 0, S.length);
    System.arraycopy(P, 0, I, S.length, P.length);
    byte[] B = new byte[v];
    int c = (n + u - 1) / u;
    for (int i = 1; i <= c; i++)
    {
      md.update(D);
      byte[] result = md.digest(I);
      for (int j = 1; j != iterationCount; j++) {
        result = md.digest(result);
      }
      for (int j = 0; j != B.length; j++) {
        B[j] = result[(j % result.length)];
      }
      for (int j = 0; j < I.length / v; j++)
      {
        int aOff = j * v;
        int bLast = B.length - 1;
        int x = (B[bLast] & 0xFF) + (I[(aOff + bLast)] & 0xFF) + 1;
        I[(aOff + bLast)] = ((byte)x);
        x >>>= 8;
        for (int k = B.length - 2; k >= 0; k--)
        {
          x += (B[k] & 0xFF) + (I[(aOff + k)] & 0xFF);
          I[(aOff + k)] = ((byte)x);
          x >>>= 8;
        }
      }
      if (i == c) {
        System.arraycopy(result, 0, dKey, (i - 1) * u, dKey.length - (i - 1) * u);
      } else {
        System.arraycopy(result, 0, dKey, (i - 1) * u, result.length);
      }
    }
    return dKey;
  }
  
  public static DerivedKey deriveKeyV2(byte[] password, byte[] salt, int iterations, int keySizeInBits, int ivSizeInBits, Mac mac)
    throws InvalidKeyException
  {
    int keySize = keySizeInBits / 8;
    int ivSize = ivSizeInBits / 8;
    
    SecretKeySpec sk = new SecretKeySpec(password, "N/A");
    mac.init(sk);
    int macLength = mac.getMacLength();
    int derivedKeyLength = keySize + ivSize;
    int blocks = (derivedKeyLength + macLength - 1) / macLength;
    byte[] blockIndex = new byte[4];
    byte[] finalResult = new byte[blocks * macLength];
    for (int i = 1; i <= blocks; i++)
    {
      int offset = (i - 1) * macLength;
      blockIndex[0] = ((byte)(i >>> 24));
      blockIndex[1] = ((byte)(i >>> 16));
      blockIndex[2] = ((byte)(i >>> 8));
      blockIndex[3] = ((byte)i);
      mac.reset();
      mac.update(salt);
      byte[] result = mac.doFinal(blockIndex);
      System.arraycopy(result, 0, finalResult, offset, result.length);
      for (int j = 1; j < iterations; j++)
      {
        mac.reset();
        result = mac.doFinal(result);
        for (int k = 0; k < result.length; k++)
        {
          int tmp202_201 = (offset + k); byte[] tmp202_195 = finalResult;tmp202_195[tmp202_201] = ((byte)(tmp202_195[tmp202_201] ^ result[k]));
        }
      }
    }
    byte[] key = new byte[keySize];
    byte[] iv = new byte[ivSize];
    System.arraycopy(finalResult, 0, key, 0, key.length);
    System.arraycopy(finalResult, key.length, iv, 0, iv.length);
    return new DerivedKey(key, iv);
  }
  
  public static byte[] formatAsPKCS8(byte[] privateKey, String oid, ASN1Structure pkcs8)
  {
    DERInteger derZero = new DERInteger(BigInteger.ZERO);
    ASN1EncodableVector outterVec = new ASN1EncodableVector();
    ASN1EncodableVector innerVec = new ASN1EncodableVector();
    try
    {
      DERObjectIdentifier derOID = new DERObjectIdentifier(oid);
      innerVec.add(derOID);
      DEROctetString octetsToAppend;
      if ("1.2.840.10040.4.1".equals(oid))
      {
        if (pkcs8 == null) {
          try
          {
            pkcs8 = ASN1Util.analyze(privateKey);
          }
          catch (Exception e)
          {
            throw new RuntimeException("asn1 parse failure " + e);
          }
        }
        if ((derIntegers == null) || (derIntegers.size() < 6)) {
          throw new RuntimeException("invalid DSA key - can't find P, Q, G, X");
        }
        DERInteger[] ints = new DERInteger[derIntegers.size()];
        derIntegers.toArray(ints);
        DERInteger p = ints[1];
        DERInteger q = ints[2];
        DERInteger g = ints[3];
        DERInteger x = ints[5];
        
        byte[] encodedX = encode(x);
        DEROctetString octetsToAppend = new DEROctetString(encodedX);
        ASN1EncodableVector pqgVec = new ASN1EncodableVector();
        pqgVec.add(p);
        pqgVec.add(q);
    
1 2 3 4 5 6 7 8 9 10 11 12 13

Further reading...

For more information on Java 1.5 Tiger, you may find Java 1.5 Tiger, A developer's Notebook by D. Flanagan and B. McLaughlin from O'Reilly of interest.

New!JAR listings


Copyright 2006-2017. Infinite Loop Ltd