The code bellow takes a String and encrypts it using AES/CBC/PKCS5PADDING as transformation. I am learning as I go and I have a few questions about my code.
1. Is SecureRandom ok for generating my KEY and my IV ?
2. Whats up with all these exceptions?
4. Is my code creating any vulnerabilities in the encryption process? (mistakes maybe?)
3. Am I seeding SEcureRandom Properly?
I'm hopping to incorporate this into a larger project or build on this. Any suggestions for making the code easier to work with multiple classes?
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class AESCrypt {
private SecureRandom r = new SecureRandom();
private Cipher c;
private IvParameterSpec IV;
private SecretKey s_KEY;
// Constructor
public AESCrypt() throws NoSuchAlgorithmException, NoSuchPaddingException {
this.c = Cipher.getInstance("AES/CBC/PKCS5PADDING");
this.IV = generateIV();
this.s_KEY = generateKEY();
}
// COnvert the String to bytes..Should I be using UTF-8? I dont think it
// messes with the encryption and this way any pc can read it ?
// Initialize the cipher
// Encrypt the String of bytes
// Return encrypted bytes
protected byte[] encrypt(String strToEncrypt) throws InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException {
byte[] byteToEncrypt = strToEncrypt.getBytes("UTF-8");
this.c.init(Cipher.ENCRYPT_MODE, this.s_KEY, this.IV, this.r);
byte[] encryptedBytes = this.c.doFinal(byteToEncrypt);
return encryptedBytes;
}
// Initialize the cipher in DECRYPT_MODE
// Decrypt and store as byte[]
// Convert to plainText and return
protected String decrypt(byte[] byteToDecrypt) throws InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException {
this.c.init(Cipher.DECRYPT_MODE, this.s_KEY, this.IV);
byte[] plainByte = this.c.doFinal(byteToDecrypt);
String plainText = new String(plainByte);
return plainText;
}
// Create the IV.
// Create a Secure Random Number Generator and an empty 16byte array. Fill
// the array.
// Returns IV
private IvParameterSpec generateIV() {
byte[] newSeed = r.generateSeed(16);
r.setSeed(newSeed);
byte[] byteIV = new byte[16];
r.nextBytes(byteIV);
IV = new IvParameterSpec(byteIV);
return IV;
}
// Create a "KeyGenerator" that takes in 'AES' as parameter
// Create a "SecureRandom" Object and use it to initialize the
// "KeyGenerator"
// keyGen.init(256, sRandom); Initialize KeyGenerator with parameters
// 256bits AES
private SecretKey generateKEY() throws NoSuchAlgorithmException {
// byte[] bytKey = AES_KEY.getBytes(); // Converts the Cipher Key to
// Byte format
// Should I use SHA-2 to get a random key or is this better?
byte[] newSeed = r.generateSeed(32);
r.setSeed(newSeed);
KeyGenerator keyGen = KeyGenerator.getInstance("AES"); // A
// "KEyGenerator"
// object,
SecureRandom sRandom = r.getInstanceStrong(); // A "SecureRandom" object
// used to init the
// keyGenerator
keyGen.init(256, sRandom); // Initialize RAndom Number Generator
s_KEY = keyGen.generateKey();
return s_KEY;
}
public String byteArrayToString(byte[] s) {
String string = new String(s);
return string;
}
// Get Methods for all class variables
public Cipher getCipher() {
return c;
}
public IvParameterSpec getIV() {
return IV;
}
public SecretKey getSecretKey() {
return s_KEY;
}
}
Thanks to everyone who responds!
Related
This question already has answers here:
What's the simplest way to print a Java array?
(37 answers)
Closed 1 year ago.
The way i understand it, a key encoding should return a sequence of bytes in some specific encoding such as UTF-8 for example.
However, logging the following:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair kp = kpg.generateKeyPair();
Log("TEST : ${kp.public.encoded}")
Log("Test : ${kp.public.encoded}")
Equivalently, in Java:
kp.getPublic().getEncoded();
Is giving me 2 different byte arrays! What am i missing here?
It seems that every time i call the encoded method, different pairs are generated.
Try in this way
import android.util.Base64;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class AESEncyption {
private static final int pswdIterations = 10;
private static final int keySize = 128;
private static final String cypherInstance = "AES/CBC/PKCS5Padding";
private static final String secretKeyInstance = "PBKDF2WithHmacSHA1";
private static final String plainText = "sampleText";
private static final String AESSalt = "exampleSalt";
private static final String initializationVector = "8119745113154120";
public static String encrypt(String textToEncrypt) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(getRaw(plainText, AESSalt), "AES");
Cipher cipher = Cipher.getInstance(cypherInstance);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(initializationVector.getBytes()));
byte[] encrypted = cipher.doFinal(textToEncrypt.getBytes());
return Base64.encodeToString(encrypted, Base64.DEFAULT);
}
public static String decrypt(String textToDecrypt) throws Exception {
byte[] encryted_bytes = Base64.decode(textToDecrypt, Base64.DEFAULT);
SecretKeySpec skeySpec = new SecretKeySpec(getRaw(plainText, AESSalt), "AES");
Cipher cipher = Cipher.getInstance(cypherInstance);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(initializationVector.getBytes()));
byte[] decrypted = cipher.doFinal(encryted_bytes);
return new String(decrypted, "UTF-8");
}
private static byte[] getRaw(String plainText, String salt) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance(secretKeyInstance);
KeySpec spec = new PBEKeySpec(plainText.toCharArray(), salt.getBytes(), pswdIterations, keySize);
return factory.generateSecret(spec).getEncoded();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return new byte[0];
}
}
I have this code in my rails app:
require 'openssl'
require 'digest/sha1'
require 'base64'
KEY="secret_key"
data = "secret message"
def encrypt_value(data)
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.encrypt
cipher.key = Digest::SHA256.digest(KEY)
encrypted = cipher.update(data)+cipher.final
return encrypted
end
def decrypt_value1(data)
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.decrypt
cipher.key = Digest::SHA256.digest(KEY)
decrypted = cipher.update(data)+cipher.final
data = Base64.decode64(decrypted)
return data
end
And java code:
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class EncryptionDecryption {
private static String salt;
private static int iterations = 65536 ;
private static int keySize = 256;
private static byte[] ivBytes;
// private static SecretKey secretKey;
private static final byte[] secretKey = "secret_key".getBytes();
public static void main(String []args) throws Exception {
salt = getSalt();
char[] message = "secret message".toCharArray();
System.out.println("Message: " + String.valueOf(message));
System.out.println("Encrypted: " + encrypt(message));
System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray()));
}
public static String encrypt(char[] plaintext) throws Exception {
byte[] saltBytes = salt.getBytes();
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize);
//secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretSpec);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(encryptedTextBytes);
}
public static String decrypt(char[] encryptedText) throws Exception {
System.out.println(encryptedText);
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedText));
SecretKeySpec secretSpec = new SecretKeySpec(secretKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return new String(decryptedTextBytes);
}
public static String getSalt() throws Exception {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[20];
sr.nextBytes(salt);
return new String(salt);
}
}
How can I have both of them work with each other, for example if I send an encrypted data to java app from rails app it should be able to decode it and vice-versa.
As far as you are using the same cypher algorithms and message padding characters, they should work just fine.
Also, it is better to use some key exchange protocol, like Diffie-Hellman. Both Ruby's OpenSSL wrapper and Java's Crypto lib support it. It is a safer way to generate per session keys.
PS. Your code as you have it, seems to be written for a standalone execution. For example, your Java code for decoding assumes that your string was encoded with the same instance's encode method. Because, your decode method is using IV that was initialized in encode method (ivBytes).
I am still searching for a good solution of my encryption needs. I found a solution on the internet that I reworked to fit the program needs but the encryption fails. I don't know why. Any suggestions?
Dear Maarten Bodeswes I tried your solution, but could not get it to work stable. I send the encrypted data via php to a database and get it back via php. I figured I have to exchange the plus-signs with something else, but it still would not work stable.
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import java.util.Random;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
public class AESplus
{
// AES specification
private static final String CIPHER_SPEC = "AES/CBC/PKCS5Padding";
// Key derivation specification
private static final String KEYGEN_SPEC = "PBKDF2WithHmacSHA1";
private static final int SALT_LENGTH = 16; // in bytes
private static final int ITERATIONS = 32768;
private static final int KEY_LENGTH = 128;
private static final String SPLITCHAR = "###";
public static SecretKey makeKey(String kennwort) throws NoSuchAlgorithmException, InvalidKeySpecException
{
char[] password = kennwort.toCharArray();
// generate salt
byte[] salt = generateSalt(SALT_LENGTH);
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEYGEN_SPEC);
KeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
SecretKey tmp = factory.generateSecret(spec);
return tmp;
}
private static byte[] generateSalt(int length)
{
Random r = new SecureRandom();
byte[] salt = new byte[length];
r.nextBytes(salt);
return salt;
}
public static String encrypt(String input, SecretKey key) throws InvalidKeyLengthException, StrongEncryptionNotAvailableException,
IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException,
IllegalBlockSizeException, BadPaddingException
{
StringBuilder output = new StringBuilder();
// initialize AES encryption
Cipher encrypt = null;
encrypt = Cipher.getInstance(CIPHER_SPEC);
encrypt.init(Cipher.ENCRYPT_MODE, key);
// get initialization vector
byte[] iv = encrypt.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
byte[] encrypted = encrypt.update(input.getBytes());
output.append(HexUtils.toHex(encrypted));
encrypted = encrypt.doFinal();
if (encrypted != null)
{
// write authentication and AES initialization data
output.append(HexUtils.toHex(iv) + SPLITCHAR);
// data
output.append(HexUtils.toHex(encrypted));
}
return output.toString();
}
public static String decrypt(String input, SecretKey schlüssel) throws InvalidPasswordException, InvalidAESStreamException,
IOException, StrongEncryptionNotAvailableException, NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
String[] inputArray = input.split(SPLITCHAR);
// initialize AES decryption
byte[] iv = new byte[16]; // 16-byte I.V. regardless of key size
iv = HexUtils.toBytes(inputArray[0]);
Cipher decrypt = Cipher.getInstance(CIPHER_SPEC);
decrypt.init(Cipher.DECRYPT_MODE, schlüssel, new IvParameterSpec(iv));
// read data from input into buffer, decrypt and write to output
byte[] hexInput = HexUtils.toBytes(inputArray[1]);
byte[] decrypted = decrypt.update(hexInput);
StringBuilder output = new StringBuilder();
output.append(new String(decrypted));
// finish decryption - do final block
decrypted = decrypt.doFinal();
if (decrypted != null)
{
output.append(new String(decrypted));
}
return output.toString();
}
// ******** EXCEPTIONS thrown by encrypt and decrypt ********
/**
* Thrown if an attempt is made to decrypt a stream with an incorrect
* password.
*/
public static class InvalidPasswordException extends Exception
{
private static final long serialVersionUID = 1L;
}
/**
* Thrown if an attempt is made to encrypt a stream with an invalid AES key
* length.
*/
public static class InvalidKeyLengthException extends Exception
{
private static final long serialVersionUID = 1L;
InvalidKeyLengthException(int length)
{
super("Invalid AES key length: " + length);
}
}
/**
* Thrown if 192- or 256-bit AES encryption or decryption is attempted,
* but not available on the particular Java platform.
*/
public static class StrongEncryptionNotAvailableException extends Exception
{
private static final long serialVersionUID = 1L;
public StrongEncryptionNotAvailableException(int keySize)
{
super(keySize + "-bit AES encryption is not available on this Java platform.");
}
}
/**
* Thrown if an attempt is made to decrypt an invalid AES stream.
*/
public static class InvalidAESStreamException extends Exception
{
private static final long serialVersionUID = 1L;
public InvalidAESStreamException()
{
super();
};
public InvalidAESStreamException(Exception e)
{
super(e);
}
}
}
This piece of your code puts the IV into the middle of the output:
byte[] encrypted = encrypt.update(input.getBytes());
output.append(HexUtils.toHex(encrypted));
encrypted = encrypt.doFinal();
if (encrypted != null)
{
// write authentication and AES initialization data
output.append(HexUtils.toHex(iv) + SPLITCHAR);
// data
output.append(HexUtils.toHex(encrypted));
}
To work with your decryption method it needs to be at the beginning.
I found a guide for implementing AES encryption/decryption in Java and tried to understand each line as I put it into my own solution. However, I don't fully understand it and am having issues as a result. The end goal is to have passphrase based encryption/decryption. I've read other articles/stackoverflow posts about this, but most do not provide enough explanation (I am very new to crypto in Java)
My main issues right now are that even when I set byte[] saltBytes = "Hello".getBytes();
I still get a different Base64 result in the end (char[] password is random each time, but I read that it is safer to leave passwords in char[] form. My other problem is that when the program gets to decrypt(), I get a NullPointerException at
byte[] saltBytes = salt.getBytes("UTF-8");
Thank you in advance for any help/advice you can give me.
The code in question:
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class EncryptionDecryption {
private static String salt;
private static int iterations = 65536 ;
private static int keySize = 256;
private static byte[] ivBytes;
public static void main(String []args) throws Exception {
char[] message = "PasswordToEncrypt".toCharArray();
System.out.println("Message: " + message.toString());
System.out.println("Encrypted: " + encrypt(message));
System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray()));
}
public static String encrypt(char[] plaintext) throws Exception {
salt = getSalt();
byte[] saltBytes = salt.getBytes();
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize);
SecretKey secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretSpec);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(plaintext.toString().getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(encryptedTextBytes);
}
public static String decrypt(char[] encryptedText) throws Exception {
byte[] saltBytes = salt.getBytes("UTF-8");
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(encryptedText.toString());
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(encryptedText, saltBytes, iterations, keySize);
SecretKey secretkey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretkey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decryptedTextBytes.toString();
}
public static String getSalt() throws Exception {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[20];
sr.nextBytes(salt);
return salt.toString();
}
}
I think that you are making two mistakes :)
I've corrected your sample code to make it work :
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class EncryptionDecryption {
private static String salt;
private static int iterations = 65536 ;
private static int keySize = 256;
private static byte[] ivBytes;
private static SecretKey secretKey;
public static void main(String []args) throws Exception {
salt = getSalt();
char[] message = "PasswordToEncrypt".toCharArray();
System.out.println("Message: " + String.valueOf(message));
System.out.println("Encrypted: " + encrypt(message));
System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray()));
}
public static String encrypt(char[] plaintext) throws Exception {
byte[] saltBytes = salt.getBytes();
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize);
secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretSpec);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(encryptedTextBytes);
}
public static String decrypt(char[] encryptedText) throws Exception {
System.out.println(encryptedText);
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedText));
SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return new String(decryptedTextBytes);
}
public static String getSalt() throws Exception {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[20];
sr.nextBytes(salt);
return new String(salt);
}
}
The first mistake is that you generate 2 different salts (when using the encrypt method), so encrypted/decrypted logs were differents (logical, but the decryption would still work because you are calling the decryption directly after encryption).
The second mistake was for the secret key. You need to generate a secret key when you are encrypting, but not decrypting. To put it more simply, it is as if i was encrypting with the password "encrypt" and that you are trying to decrypt it with the password "decrypt".
I would advise you to generate every random stuff (such as private key, salt etc on startup). But beware that when you'll stop your app, you won't be able to decrypt old stuff unless getting the exact same random stuff.
Hope I helped :)
Regards,
I am new to cryptography, so I have a question:
How can I create my own key (let`s say like a string "1234"). Because I need to encrypt a string with a key (defined by me), save the encrypted string in a database and when I want to use it, take it from the database and decrypt it with the key known by me.
I have this code :
import java.security.InvalidKeyException;
import java.security.*;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
public class LocalEncrypter {
private static String algorithm = "PBEWithMD5AndDES";
//private static Key key = null;
private static Cipher cipher = null;
private static SecretKey key;
private static void setUp() throws Exception {
///key = KeyGenerator.getInstance(algorithm).generateKey();
SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm);
String pass1 = "thisIsTheSecretKeyProvidedByMe";
byte[] pass = pass1.getBytes();
SecretKey key = factory.generateSecret(new DESedeKeySpec(pass));
cipher = Cipher.getInstance(algorithm);
}
public static void main(String[] args)
throws Exception {
setUp();
byte[] encryptionBytes = null;
String input = "1234";
System.out.println("Entered: " + input);
encryptionBytes = encrypt(input);
System.out.println(
"Recovered: " + decrypt(encryptionBytes));
}
private static byte[] encrypt(String input)
throws InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] inputBytes = input.getBytes();
return cipher.doFinal(inputBytes);
}
private static String decrypt(byte[] encryptionBytes)
throws InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException {
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] recoveredBytes =
cipher.doFinal(encryptionBytes);
String recovered =
new String(recoveredBytes);
return recovered;
}
}
Exception in thread "main" java.security.spec.InvalidKeySpecException: Invalid key spec
at com.sun.crypto.provider.PBEKeyFactory.engineGenerateSecret(PBEKeyFactory.java:114)
at javax.crypto.SecretKeyFactory.generateSecret(SecretKeyFactory.java:335)
at LocalEncrypter.setUp(LocalEncrypter.java:22)
at LocalEncrypter.main(LocalEncrypter.java:28)
A KeyGenerator generates random keys. Since you know the secret key, what you need is a SecretKeyFactory. Get an instance for your algorithm (DESede), and then call its generateSecret méthode with an instance of DESedeKeySpec as argument:
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(new DESedeKeySpec(someByteArrayContainingAtLeast24Bytes));
Here is a complete example that works. As I said, DESedeKeySpec must be used with the DESede algorithm. Using a DESede key with PBEWithMD5AndDES makes no sense.
public class EncryptionTest {
public static void main(String[] args) throws Exception {
byte[] keyBytes = "1234567890azertyuiopqsdf".getBytes("ASCII");
DESedeKeySpec keySpec = new DESedeKeySpec(keyBytes);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(keySpec);
byte[] text = "Hello world".getBytes("ASCII");
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(text);
cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println(new String(decrypted, "ASCII"));
}
}
Well, I found the solution after combining from here and there. The encrypted result will be formatted as Base64 String for safe saving as xml file.
package cmdCrypto;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.xml.bind.DatatypeConverter;
public class CmdCrypto {
public static void main(String[] args) {
try{
final String strPassPhrase = "123456789012345678901234"; //min 24 chars
String param = "No body can see me";
System.out.println("Text : " + param);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(new DESedeKeySpec(strPassPhrase.getBytes()));
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
String str = DatatypeConverter.printBase64Binary(cipher.doFinal(param.getBytes()));
System.out.println("Text Encryted : " + str);
cipher.init(Cipher.DECRYPT_MODE, key);
String str2 = new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(str)));
System.out.println("Text Decryted : " + str2);
} catch(Exception e) {
e.printStackTrace();
}
}
}