blob: 0eda1db7a746e8d8dbdf61e514dfeab2af29ec53 [file] [log] [blame]
/*
* $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.16/src/java/org/apache/commons/ssl/OpenSSL.java $
* $Revision: 144 $
* $Date: 2009-05-25 11:14:29 -0700 (Mon, 25 May 2009) $
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.commons.ssl;
import org.apache.kerby.util.Base64;
import org.apache.kerby.util.Base64InputStream;
import org.apache.kerby.util.Hex;
import org.apache.kerby.util.Util;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.StringTokenizer;
/**
* Class for encrypting or decrypting data with a password (PBE - password
* based encryption). Compatible with "openssl enc" unix utility. An OpenSSL
* compatible cipher name must be specified along with the password (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* <pre>
* <em style="color: green;">// Encrypt!</em>
* byte[] encryptedData = OpenSSL.encrypt( "des3", password, data );
* </pre>
* <p/>
* If you want to specify a raw key and iv directly (without using PBE), use
* the methods that take byte[] key, byte[] iv. Those byte[] arrays can be
* the raw binary, or they can be ascii (hex representation: '0' - 'F'). If
* you want to use PBE to derive the key and iv, then use the methods that
* take char[] password.
* <p/>
* This class is able to decrypt files encrypted with "openssl" unix utility.
* <p/>
* The "openssl" unix utility is able to decrypt files encrypted by this class.
* <p/>
* This class is also able to encrypt and decrypt its own files.
*
* @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@gmail.com</a>
* @since 18-Oct-2007
*/
public class OpenSSL {
/**
* Decrypts data using a password and an OpenSSL compatible cipher
* name.
*
* @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* @param pwd password to use for this PBE decryption
* @param encrypted byte array to decrypt. Can be raw, or base64.
* @return decrypted bytes
* @throws java.io.IOException problems with encrypted bytes (unlikely!)
* @throws java.security.GeneralSecurityException problems decrypting
*/
public static byte[] decrypt(String cipher, char[] pwd, byte[] encrypted)
throws IOException, GeneralSecurityException {
ByteArrayInputStream in = new ByteArrayInputStream(encrypted);
InputStream decrypted = decrypt(cipher, pwd, in);
return Util.streamToBytes(decrypted);
}
/**
* Decrypts data using a password and an OpenSSL compatible cipher
* name.
*
* @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* @param pwd password to use for this PBE decryption
* @param encrypted InputStream to decrypt. Can be raw, or base64.
* @return decrypted bytes as an InputStream
* @throws java.io.IOException problems with InputStream
* @throws java.security.GeneralSecurityException problems decrypting
*/
public static InputStream decrypt(String cipher, char[] pwd,
InputStream encrypted)
throws IOException, GeneralSecurityException {
CipherInfo cipherInfo = lookup(cipher);
boolean salted = false;
// First 16 bytes of raw binary will hopefully be OpenSSL's
// "Salted__[8 bytes of hex]" thing. Might be in Base64, though.
byte[] saltLine = Util.streamToBytes(encrypted, 16);
if (saltLine.length <= 0) {
throw new IOException("encrypted InputStream is empty");
}
String firstEightBytes = "";
if (saltLine.length >= 8) {
firstEightBytes = new String(saltLine, 0, 8);
}
if ("SALTED__".equalsIgnoreCase(firstEightBytes)) {
salted = true;
} else {
// Maybe the reason we didn't find the salt is because we're in
// base64.
if (Base64.isArrayByteBase64(saltLine)) {
InputStream head = new ByteArrayInputStream(saltLine);
// Need to put that 16 byte "saltLine" back into the Stream.
encrypted = new ComboInputStream(head, encrypted);
encrypted = new Base64InputStream(encrypted);
saltLine = Util.streamToBytes(encrypted, 16);
if (saltLine.length >= 8) {
firstEightBytes = new String(saltLine, 0, 8);
}
if ("SALTED__".equalsIgnoreCase(firstEightBytes)) {
salted = true;
}
}
}
byte[] salt = null;
if (salted) {
salt = new byte[8];
System.arraycopy(saltLine, 8, salt, 0, 8);
} else {
// Encrypted data wasn't salted. Need to put the "saltLine" we
// extracted back into the stream.
InputStream head = new ByteArrayInputStream(saltLine);
encrypted = new ComboInputStream(head, encrypted);
}
int keySize = cipherInfo.keySize;
int ivSize = cipherInfo.ivSize;
boolean des2 = cipherInfo.des2;
DerivedKey dk = deriveKey(pwd, salt, keySize, ivSize, des2);
Cipher c = PKCS8Key.generateCipher(
cipherInfo.javaCipher, cipherInfo.blockMode, dk, des2, null, true
);
return new CipherInputStream(encrypted, c);
}
/**
* Encrypts data using a password and an OpenSSL compatible cipher
* name.
*
* @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* @param pwd password to use for this PBE encryption
* @param data byte array to encrypt
* @return encrypted bytes as an array in base64. First 16 bytes include the
* special OpenSSL "Salted__" info encoded into base64.
* @throws java.io.IOException problems with the data byte array
* @throws java.security.GeneralSecurityException problems encrypting
*/
public static byte[] encrypt(String cipher, char[] pwd, byte[] data)
throws IOException, GeneralSecurityException {
// base64 is the default output format.
return encrypt(cipher, pwd, data, true);
}
/**
* Encrypts data using a password and an OpenSSL compatible cipher
* name.
*
* @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* @param pwd password to use for this PBE encryption
* @param data InputStream to encrypt
* @return encrypted bytes as an InputStream. First 16 bytes include the
* special OpenSSL "Salted__" info encoded into base64.
* @throws java.io.IOException problems with the data InputStream
* @throws java.security.GeneralSecurityException problems encrypting
*/
public static InputStream encrypt(String cipher, char[] pwd,
InputStream data)
throws IOException, GeneralSecurityException {
// base64 is the default output format.
return encrypt(cipher, pwd, data, true);
}
/**
* Encrypts data using a password and an OpenSSL compatible cipher
* name.
*
* @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* @param pwd password to use for this PBE encryption
* @param data byte array to encrypt
* @param toBase64 true if resulting InputStream should contain base64,
* <br>false if InputStream should contain raw binary.
* @return encrypted bytes as an array. First 16 bytes include the
* special OpenSSL "Salted__" info.
* @throws java.io.IOException problems with the data byte array
* @throws java.security.GeneralSecurityException problems encrypting
*/
public static byte[] encrypt(String cipher, char[] pwd, byte[] data,
boolean toBase64)
throws IOException, GeneralSecurityException {
// we use a salt by default.
return encrypt(cipher, pwd, data, toBase64, true);
}
/**
* Encrypts data using a password and an OpenSSL compatible cipher
* name.
*
* @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* @param pwd password to use for this PBE encryption
* @param data InputStream to encrypt
* @param toBase64 true if resulting InputStream should contain base64,
* <br>false if InputStream should contain raw binary.
* @return encrypted bytes as an InputStream. First 16 bytes include the
* special OpenSSL "Salted__" info.
* @throws java.io.IOException problems with the data InputStream
* @throws java.security.GeneralSecurityException problems encrypting
*/
public static InputStream encrypt(String cipher, char[] pwd,
InputStream data, boolean toBase64)
throws IOException, GeneralSecurityException {
// we use a salt by default.
return encrypt(cipher, pwd, data, toBase64, true);
}
/**
* Encrypts data using a password and an OpenSSL compatible cipher
* name.
*
* @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* @param pwd password to use for this PBE encryption
* @param data byte array to encrypt
* @param toBase64 true if resulting InputStream should contain base64,
* <br>false if InputStream should contain raw binary.
* @param useSalt true if a salt should be used to derive the key.
* <br>false otherwise. (Best security practises
* always recommend using a salt!).
* @return encrypted bytes as an array. First 16 bytes include the
* special OpenSSL "Salted__" info if <code>useSalt</code> is true.
* @throws java.io.IOException problems with the data InputStream
* @throws java.security.GeneralSecurityException problems encrypting
*/
public static byte[] encrypt(String cipher, char[] pwd, byte[] data,
boolean toBase64, boolean useSalt)
throws IOException, GeneralSecurityException {
ByteArrayInputStream in = new ByteArrayInputStream(data);
InputStream encrypted = encrypt(cipher, pwd, in, toBase64, useSalt);
return Util.streamToBytes(encrypted);
}
/**
* Encrypts data using a password and an OpenSSL compatible cipher
* name.
*
* @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
* unix box to see what's possible). Some examples:
* <ul><li>des, des3, des-ede3-cbc
* <li>aes128, aes192, aes256, aes-256-cbc
* <li>rc2, rc4, bf</ul>
* @param pwd password to use for this PBE encryption
* @param data InputStream to encrypt
* @param toBase64 true if resulting InputStream should contain base64,
* <br>false if InputStream should contain raw binary.
* @param useSalt true if a salt should be used to derive the key.
* <br>false otherwise. (Best security practises
* always recommend using a salt!).
* @return encrypted bytes as an InputStream. First 16 bytes include the
* special OpenSSL "Salted__" info if <code>useSalt</code> is true.
* @throws java.io.IOException problems with the data InputStream
* @throws java.security.GeneralSecurityException problems encrypting
*/
public static InputStream encrypt(String cipher, char[] pwd,
InputStream data, boolean toBase64,
boolean useSalt)
throws IOException, GeneralSecurityException {
CipherInfo cipherInfo = lookup(cipher);
byte[] salt = null;
if (useSalt) {
SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
salt = new byte[8];
rand.nextBytes(salt);
}
int keySize = cipherInfo.keySize;
int ivSize = cipherInfo.ivSize;
boolean des2 = cipherInfo.des2;
DerivedKey dk = deriveKey(pwd, salt, keySize, ivSize, des2);
Cipher c = PKCS8Key.generateCipher(
cipherInfo.javaCipher, cipherInfo.blockMode, dk, des2, null, false
);
InputStream cipherStream = new CipherInputStream(data, c);
if (useSalt) {
byte[] saltLine = new byte[16];
byte[] salted = "Salted__".getBytes();
System.arraycopy(salted, 0, saltLine, 0, salted.length);
System.arraycopy(salt, 0, saltLine, salted.length, salt.length);
InputStream head = new ByteArrayInputStream(saltLine);
cipherStream = new ComboInputStream(head, cipherStream);
}
if (toBase64) {
cipherStream = new Base64InputStream(cipherStream, true);
}
return cipherStream;
}
public static byte[] decrypt(String cipher, byte[] key, byte[] iv,
byte[] encrypted)
throws IOException, GeneralSecurityException {
ByteArrayInputStream in = new ByteArrayInputStream(encrypted);
InputStream decrypted = decrypt(cipher, key, iv, in);
return Util.streamToBytes(decrypted);
}
public static InputStream decrypt(String cipher, byte[] key, byte[] iv,
InputStream encrypted)
throws IOException, GeneralSecurityException {
CipherInfo cipherInfo = lookup(cipher);
byte[] firstLine = Util.streamToBytes(encrypted, 16);
if (Base64.isArrayByteBase64(firstLine)) {
InputStream head = new ByteArrayInputStream(firstLine);
// Need to put that 16 byte "firstLine" back into the Stream.
encrypted = new ComboInputStream(head, encrypted);
encrypted = new Base64InputStream(encrypted);
} else {
// Encrypted data wasn't base64. Need to put the "firstLine" we
// extracted back into the stream.
InputStream head = new ByteArrayInputStream(firstLine);
encrypted = new ComboInputStream(head, encrypted);
}
int keySize = cipherInfo.keySize;
int ivSize = cipherInfo.ivSize;
// Looks like key is in hex
if (key.length == keySize / 4) {
key = Hex.decode(key);
}
// Looks like IV is in hex
if (iv.length == ivSize / 4) {
iv = Hex.decode(iv);
}
DerivedKey dk = new DerivedKey(key, iv);
Cipher c = PKCS8Key.generateCipher(cipherInfo.javaCipher,
cipherInfo.blockMode,
dk, cipherInfo.des2, null, true);
return new CipherInputStream(encrypted, c);
}
public static byte[] encrypt(String cipher, byte[] key, byte[] iv,
byte[] data)
throws IOException, GeneralSecurityException {
return encrypt(cipher, key, iv, data, true);
}
public static byte[] encrypt(String cipher, byte[] key, byte[] iv,
byte[] data, boolean toBase64)
throws IOException, GeneralSecurityException {
ByteArrayInputStream in = new ByteArrayInputStream(data);
InputStream encrypted = encrypt(cipher, key, iv, in, toBase64);
return Util.streamToBytes(encrypted);
}
public static InputStream encrypt(String cipher, byte[] key, byte[] iv,
InputStream data)
throws IOException, GeneralSecurityException {
return encrypt(cipher, key, iv, data, true);
}
public static InputStream encrypt(String cipher, byte[] key, byte[] iv,
InputStream data, boolean toBase64)
throws IOException, GeneralSecurityException {
CipherInfo cipherInfo = lookup(cipher);
int keySize = cipherInfo.keySize;
int ivSize = cipherInfo.ivSize;
if (key.length == keySize / 4) {
key = Hex.decode(key);
}
if (iv.length == ivSize / 4) {
iv = Hex.decode(iv);
}
DerivedKey dk = new DerivedKey(key, iv);
Cipher c = PKCS8Key.generateCipher(cipherInfo.javaCipher,
cipherInfo.blockMode,
dk, cipherInfo.des2, null, false);
InputStream cipherStream = new CipherInputStream(data, c);
if (toBase64) {
cipherStream = new Base64InputStream(cipherStream, true);
}
return cipherStream;
}
public static DerivedKey deriveKey(char[] password, byte[] salt,
int keySize, boolean des2)
throws NoSuchAlgorithmException {
return deriveKey(password, salt, keySize, 0, des2);
}
@SuppressWarnings("PMD.UselessParentheses")
public static DerivedKey deriveKey(char[] password, byte[] salt,
int keySize, int ivSize, boolean des2)
throws NoSuchAlgorithmException {
if (des2) {
keySize = 128;
}
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] pwdAsBytes = new byte[password.length];
for (int i = 0; i < password.length; i++) {
pwdAsBytes[i] = (byte) password[i];
}
md.reset();
byte[] keyAndIv = new byte[(keySize / 8) + (ivSize / 8)];
if (salt == null || salt.length == 0) {
// Unsalted! Bad idea!
salt = null;
}
byte[] result;
int currentPos = 0;
while (currentPos < keyAndIv.length) {
md.update(pwdAsBytes);
if (salt != null) {
// First 8 bytes of salt ONLY! That wasn't obvious to me
// when using AES encrypted private keys in "Traditional
// SSLeay Format".
//
// Example:
// DEK-Info: AES-128-CBC,8DA91D5A71988E3D4431D9C2C009F249
//
// Only the first 8 bytes are salt, but the whole thing is
// re-used again later as the IV. MUCH gnashing of teeth!
md.update(salt, 0, 8);
}
result = md.digest();
int stillNeed = keyAndIv.length - currentPos;
// Digest gave us more than we need. Let's truncate it.
if (result.length > stillNeed) {
byte[] b = new byte[stillNeed];
System.arraycopy(result, 0, b, 0, b.length);
result = b;
}
System.arraycopy(result, 0, keyAndIv, currentPos, result.length);
currentPos += result.length;
if (currentPos < keyAndIv.length) {
// Next round starts with a hash of the hash.
md.reset();
md.update(result);
}
}
if (des2) {
keySize = 192;
byte[] buf = new byte[keyAndIv.length + 8];
// Make space where 3rd key needs to go (16th - 24th bytes):
System.arraycopy(keyAndIv, 0, buf, 0, 16);
if (ivSize > 0) {
System.arraycopy(keyAndIv, 16, buf, 24, keyAndIv.length - 16);
}
keyAndIv = buf;
// copy first 8 bytes into last 8 bytes to create 2DES key.
System.arraycopy(keyAndIv, 0, keyAndIv, 16, 8);
}
if (ivSize == 0) {
// if ivSize == 0, then "keyAndIv" array is actually all key.
// Must be "Traditional SSLeay Format" encrypted private key in
// PEM. The "salt" in its entirety (not just first 8 bytes) will
// probably be re-used later as the IV (initialization vector).
return new DerivedKey(keyAndIv, salt);
} else {
byte[] key = new byte[keySize / 8];
byte[] iv = new byte[ivSize / 8];
System.arraycopy(keyAndIv, 0, key, 0, key.length);
System.arraycopy(keyAndIv, key.length, iv, 0, iv.length);
return new DerivedKey(key, iv);
}
}
public static class CipherInfo {
public final String javaCipher;
public final String blockMode;
public final int keySize;
public final int ivSize;
public final boolean des2;
public CipherInfo(String javaCipher, String blockMode, int keySize,
int ivSize, boolean des2) {
this.javaCipher = javaCipher;
this.blockMode = blockMode;
this.keySize = keySize;
this.ivSize = ivSize;
this.des2 = des2;
}
public String toString() {
return javaCipher + "/" + blockMode + " " + keySize + "bit des2=" + des2;
}
}
/**
* Converts the way OpenSSL names its ciphers into a Java-friendly naming.
*
* @param openSSLCipher OpenSSL cipher name, e.g. "des3" or "des-ede3-cbc".
* Try "man enc" on a unix box to see what's possible.
* @return CipherInfo object with the Java-friendly cipher information.
*/
public static CipherInfo lookup(String openSSLCipher) {
openSSLCipher = openSSLCipher.trim();
if (openSSLCipher.charAt(0) == '-') {
openSSLCipher = openSSLCipher.substring(1);
}
String javaCipher = openSSLCipher.toUpperCase();
String blockMode = "CBC";
int keySize = -1;
int ivSize = 64;
boolean des2 = false;
StringTokenizer st = new StringTokenizer(openSSLCipher, "-");
if (st.hasMoreTokens()) {
javaCipher = st.nextToken().toUpperCase();
if (st.hasMoreTokens()) {
// Is this the middle token? Or the last token?
String tok = st.nextToken();
if (st.hasMoreTokens()) {
try {
keySize = Integer.parseInt(tok);
} catch (NumberFormatException nfe) {
// I guess 2nd token isn't an integer
String upper = tok.toUpperCase();
if (upper.startsWith("EDE3")) {
javaCipher = "DESede";
} else if (upper.startsWith("EDE")) {
javaCipher = "DESede";
des2 = true;
}
}
blockMode = st.nextToken().toUpperCase();
} else {
try {
keySize = Integer.parseInt(tok);
} catch (NumberFormatException nfe) {
// It's the last token, so must be mode (usually "CBC").
blockMode = tok.toUpperCase();
if (blockMode.startsWith("EDE3")) {
javaCipher = "DESede";
blockMode = "ECB";
} else if (blockMode.startsWith("EDE")) {
javaCipher = "DESede";
blockMode = "ECB";
des2 = true;
}
}
}
}
}
if (javaCipher.startsWith("BF")) {
javaCipher = "Blowfish";
} else if (javaCipher.startsWith("TWOFISH")) {
javaCipher = "Twofish";
ivSize = 128;
} else if (javaCipher.startsWith("IDEA")) {
javaCipher = "IDEA";
} else if (javaCipher.startsWith("CAST6")) {
javaCipher = "CAST6";
ivSize = 128;
} else if (javaCipher.startsWith("CAST")) {
javaCipher = "CAST5";
} else if (javaCipher.startsWith("GOST")) {
keySize = 256;
} else if (javaCipher.startsWith("DESX")) {
javaCipher = "DESX";
} else if ("DES3".equals(javaCipher)) {
javaCipher = "DESede";
} else if ("DES2".equals(javaCipher)) {
javaCipher = "DESede";
des2 = true;
} else if (javaCipher.startsWith("RIJNDAEL")) {
javaCipher = "Rijndael";
ivSize = 128;
} else if (javaCipher.startsWith("SEED")) {
javaCipher = "SEED";
ivSize = 128;
} else if (javaCipher.startsWith("SERPENT")) {
javaCipher = "Serpent";
ivSize = 128;
} else if (javaCipher.startsWith("Skipjack")) {
javaCipher = "Skipjack";
ivSize = 128;
} else if (javaCipher.startsWith("RC6")) {
javaCipher = "RC6";
ivSize = 128;
} else if (javaCipher.startsWith("TEA")) {
javaCipher = "TEA";
} else if (javaCipher.startsWith("XTEA")) {
javaCipher = "XTEA";
} else if (javaCipher.startsWith("AES")) {
if (javaCipher.startsWith("AES128")) {
keySize = 128;
} else if (javaCipher.startsWith("AES192")) {
keySize = 192;
} else if (javaCipher.startsWith("AES256")) {
keySize = 256;
}
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 {
// RC2, RC4, RC5 and Blowfish ?
keySize = 128;
}
}
return new CipherInfo(javaCipher, blockMode, keySize, ivSize, des2);
}
/**
* @param args command line arguments: [password] [cipher] [file-to-decrypt]
* <br>[cipher] == OpenSSL cipher name, e.g. "des3" or "des-ede3-cbc".
* Try "man enc" on a unix box to see what's possible.
* @throws java.io.IOException problems with the [file-to-decrypt]
* @throws java.security.GeneralSecurityException decryption problems
*/
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 = encrypt( args[ 1 ], pwdAsBytes, in, true );
in = new BufferedInputStream(in);
BufferedOutputStream bufOut = new BufferedOutputStream(System.out);
Util.pipeStream(in, bufOut, false);
bufOut.flush();
System.out.flush();
}
}