Created
December 1, 2011 19:16
-
-
Save koehler8/1419123 to your computer and use it in GitHub Desktop.
OpenSSL Encryption
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/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.commons.ssl.util.Hex; | |
import javax.crypto.Cipher; | |
import javax.crypto.CipherInputStream; | |
import java.io.*; | |
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:[email protected]">[email protected]</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 IOException problems with encrypted bytes (unlikely!) | |
* @throws 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 IOException problems with InputStream | |
* @throws 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 IOException problems with the data byte array | |
* @throws 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 IOException problems with the data InputStream | |
* @throws 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 IOException problems with the data byte array | |
* @throws 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 IOException problems with the data InputStream | |
* @throws 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 IOException problems with the data InputStream | |
* @throws 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 IOException problems with the data InputStream | |
* @throws 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; | |
if (key.length == keySize / 4) // Looks like key is in hex | |
{ | |
key = Hex.decode(key); | |
} | |
if (iv.length == ivSize / 4) // Looks like IV is in hex | |
{ | |
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); | |
} | |
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 IOException problems with the [file-to-decrypt] | |
* @throws 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(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment