So I am doing a small project and getting extremely frusterated. Ive tried inputting different algorithms for the KeyGenerator and different key sizes but with no luck. Could someone please help me out?
If I put simply "AES" - I get ECB Mode can not use IV
and if I put "AES/CBC/PKCS5PADDING" - I get KeyGenerator not available
#SpringBootApplication
public class SslServerApplication {
private static final String ALGORITHM = "AES/CBC/PKCS5PADDING";
private static final int KEY_SIZE = 192;
public static void main(String[] args) throws Exception {
SecretKey key = generateKey();
String message = "Hello, Professor Conlan!";
byte[] encrypted = encrypt(message, key);
byte[] hash = hash(encrypted);
System.out.println("Hash: " + bytesToHex(hash));
boolean verified = verifyChecksum(hash, encrypted, key);
System.out.println("Checksum verified: " + verified);
}
//generates secret key
private static SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(KEY_SIZE);
return keyGenerator.generateKey();
}
//encrypts secret key key
static byte[] encrypt(String message, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
byte[] iv = new byte[cipher.getBlockSize()];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
return cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
}
static byte[] hash(byte[] message) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
return md.digest(message);
}
private static boolean verifyChecksum(byte[] checksum, byte[] message, SecretKey key) throws Exception {
byte[] hash = hash(decrypt(message, key));
return MessageDigest.isEqual(hash, checksum);
}
//decrypts the encrypted secret key
static byte[] decrypt(byte[] message, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
byte[] iv = Arrays.copyOfRange(message, 0, cipher.getBlockSize());
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
return cipher.doFinal(Arrays.copyOfRange(message, cipher.getBlockSize(), message.length));
}
static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}
EDIT: This is my POM file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.snhu</groupId>
<artifactId>ssl-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ssl-server</name>
<description>ssl-server skeleton for CS-305</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>5.3.0</version>
<configuration>
<outputDirectory default-value="C:\Users\Shawn\Documents\M7 Folder"/>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
"AES/CBC/PKCS5PADDING" is a Cipher specification consisting of
an algorithm name (AES - Cipher Algorithm Names)
an algorithm mode (CBC - Cipher Algorithm Modes)
an algorithm padding (PKCS5PADDING - Cipher Algorithm Paddings)
For the KeyGenerator only the algorithm itself is relevant (KeyGenerator Algorithms) and you must only specify the algorithm when calling KeyGenerator.getInstance().
KeyGenerator.getInstance("AES") will work for the KeyGenerator.
Note: For the Cipher you still must use "AES/CBC/PKCS5PADDING"! Otherwise you will get a provider-specific Cipher:
A transformation is of the form:
"algorithm/mode/padding" or
"algorithm"
(in the latter case, provider-specific default values for the mode and padding scheme are used).
You cannot use the same value for the KeyGenerator algorithm and the Cipher algorithm.
These are the legal values of KeyGenerator algorithm. Your value of AES/CBC/PKCS5PADDING is not among them as Thomas's answer correctly indicates.
AES
ARCFOUR
Blowfish
DES
DESede
HmacMD5
HmacSHA1 HmacSHA256 HmacSHA384 HmacSHA512
RC2
The following are the Cipher algorithms that must be supported by Java implementations. Your value of AES/CBC/PKCS5PADDING will work here (if your code gets far enough.
AES/CBC/NoPadding (128)
AES/CBC/PKCS5Padding (128)
AES/ECB/NoPadding (128)
AES/ECB/PKCS5Padding (128)
DES/CBC/NoPadding (56)
DES/CBC/PKCS5Padding (56)
DES/ECB/NoPadding (56)
DES/ECB/PKCS5Padding (56)
DESede/CBC/NoPadding (168)
DESede/CBC/PKCS5Padding (168)
DESede/ECB/NoPadding (168)
DESede/ECB/PKCS5Padding (168)
RSA/ECB/PKCS1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)
The following is code that 'works'. Your code has other issues.
#SpringBootApplication
public class SslServerApplication {
private static final String KEYGENERATOR_ALGORITHM = "AES";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5PADDING";
private static final int KEY_SIZE = 192;
public static void main(String[] args) throws Exception {
SecretKey key = generateKey();
String message = "Hello, Professor Conlan!";
byte[] encrypted = encrypt(message, key);
byte[] hash = hash(encrypted);
System.out.println("Hash: " + bytesToHex(hash));
boolean verified = verifyChecksum(hash, encrypted, key);
System.out.println("Checksum verified: " + verified);
String decrypted = new String(decrypt(encrypted, key));
System.out.println("Decrypted messaged: " + decrypted);
}
//generates secret key
private static SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEYGENERATOR_ALGORITHM);
keyGenerator.init(KEY_SIZE);
return keyGenerator.generateKey();
}
//encrypts secret key key
static byte[] encrypt(String message, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
byte[] iv = new byte[cipher.getBlockSize()];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
return cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
}
static byte[] hash(byte[] message) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
return md.digest(message);
}
private static boolean verifyChecksum(byte[] checksum, byte[] message, SecretKey key) throws Exception {
byte[] hash = hash(decrypt(message, key));
return MessageDigest.isEqual(hash, checksum);
}
//decrypts the encrypted secret key
static byte[] decrypt(byte[] message, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
byte[] iv = Arrays.copyOfRange(message, 0, cipher.getBlockSize());
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
return cipher.doFinal(Arrays.copyOfRange(message, cipher.getBlockSize(), message.length));
}
static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
Related
I'm currently attempting to implement an encryption and decryption function for a basic Java program, using the following methods:
private static String encryptString(PublicKey publicKey, String message) throws Exception {
Cipher encrypt = Cipher.getInstance("RSA/ECB/PKCS1Padding");
encrypt.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypted = encrypt.doFinal(message.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}
private static String decryptString(PrivateKey privateKey, String message) throws Exception {
Cipher decrypt = Cipher.getInstance("RSA/ECB/PKCS1Padding");
decrypt.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = decrypt.doFinal(message.getBytes());
return Base64.getEncoder().encodeToString(decrypted);
}
Encoding the message using the public key appears to work correctly. However, when attempting to decrypt it using the private key, javax.crypto throws an IllegalBlockSizeException saying data must not be longer than 128 bytes.
I would try to use RC6 algorithm but i have an error:
RC6 KeyGenerator not available
How can i obtain the keygenerator of the rc6?
Exception in thread "main" java.security.NoSuchAlgorithmException: RC6 KeyGenerator not available
at javax.crypto.KeyGenerator.(KeyGenerator.java:169)
at javax.crypto.KeyGenerator.getInstance(KeyGenerator.java:223)
at RC6.encrypt(RC6.java:27)
at RC6.main(RC6.java:16)
import javax.crypto.spec.*;
import java.security.*;
import javax.crypto.*;
public class Main
{
private static String algorithm = "RC6";
public static void main(String []args) throws Exception {
String toEncrypt = "The shorter you live, the longer you're dead!";
System.out.println("Encrypting...");
byte[] encrypted = encrypt(toEncrypt, "password");
System.out.println("Decrypting...");
String decrypted = decrypt(encrypted, "password");
System.out.println("Decrypted text: " + decrypted);
}
public static byte[] encrypt(String toEncrypt, String key) throws Exception {
// create a binary key from the argument key (seed)
SecureRandom sr = new SecureRandom(key.getBytes());
KeyGenerator kg = KeyGenerator.getInstance(algorithm);
kg.init(sr);
SecretKey sk = kg.generateKey();
// create an instance of cipher
Cipher cipher = Cipher.getInstance(algorithm);
// initialize the cipher with the key
cipher.init(Cipher.ENCRYPT_MODE, sk);
// enctypt!
byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
return encrypted;
}
public static String decrypt(byte[] toDecrypt, String key) throws Exception {
// create a binary key from the argument key (seed)
SecureRandom sr = new SecureRandom(key.getBytes());
KeyGenerator kg = KeyGenerator.getInstance(algorithm);
kg.init(sr);
SecretKey sk = kg.generateKey();
// do the decryption with that key
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, sk);
byte[] decrypted = cipher.doFinal(toDecrypt);
return new String(decrypted);
}
}
RC6 is not an algorithm that is provided by one of the Oracle security providers. The providers provide the algorithm implementations that are behind Cipher and indeed KeyGenerator.
This should work, after adding the Bouncy Castle provider .jar in the classpath:
static {
Security.addProvider(new BouncyCastleProvider());
}
You may also need to install the unlimited cryptography files in your JRE folder.
I am currently working in a solution, where I have encrypt a password in Java (Running in Jboss server), and then send to Data Power and de-crypt in DataPower. I able to encrypt the password in Java. I dont have much knowledge in DataPower. I have got the code to decrypt in datapower, but not sure how to send the key to datapower. Can anyone please help me out. The code is like below,
Encryption Code (Java)
package test;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.util.ArrayList;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class Test {
private static final String ALGO = "AES";
public static String encrypt(String data,String secretKey) throws Exception {
Key key = generateKey(secretKey);
byte[] ivAES = {(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22,(byte)0x22};
IvParameterSpec ivspec = new IvParameterSpec(ivAES);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, ivspec);
byte[] encVal = cipher.doFinal(data.getBytes());
byte[] finalByte=copyBytes(encVal, ivAES);
String encryptedValue = new BASE64Encoder().encode(finalByte);
return encryptedValue;
}
public static String decrypt(String encryptedData,String secretKey) throws Exception {
Key key = generateKey(secretKey);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
ArrayList<byte[]> al = retreiveIv(decordedValue);
byte[] data = al.get(0);
byte[] iv = al.get(1);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
byte[] decValue = cipher.doFinal(data);
String decryptedValue = new String(decValue);
return decryptedValue;
}
private static Key generateKey(String secretKey) throws Exception {
Key key = new SecretKeySpec(secretKey.getBytes(), ALGO);
return key;
}
private static byte[] copyBytes(byte[] encVal, byte[] iv) throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
os.write(iv);
os.write(encVal);
return os.toByteArray();
}
private static ArrayList<byte[]> retreiveIv(byte[] combineByte) {
ByteArrayOutputStream iv = new ByteArrayOutputStream(16);
ByteArrayOutputStream data = new ByteArrayOutputStream();
data.write(combineByte, combineByte.length - 16, 16);
iv.write(combineByte, 0, combineByte.length - 16);
ArrayList<byte[]> al = new ArrayList<byte[]>();
al.add(data.toByteArray());
al.add(iv.toByteArray());
return al;
}
public static void main(String[] args) throws Exception{
System.out.println(AESUtil.decrypt(AESUtil.encrypt("Hello", "AVH4TU8AC99dhL2l"), "AVH4TU8AC99dhL2l"));
}
}
Decryption (DataPower)
<xsl:variable name="algorithm">http://www.w3.org/2001/04/xmlenc#aes128-cbc</xsl:variable>
<xsl:variable name="decryptOut"><xsl:value-of select="dp:decrypt-data($algorithm,'name:danadp',$valueToDecrypt)"/></xsl:variable>
Decrypted Value: <xsl:copy-of select="$decryptOut"/>
But, I am not getting how to share the Key object to DataPower that we generated in Java code for encryption.
It will be great, if anyone can help me.
Create a shared secret key object with name 'danadp' and the key copied into a file and imported into the cert:/ folder in the DataPower domain where this code is running.
P.S Remember to prefix the key with "0x" if key is in hex.
I'm relatively new to developing something with encryption. Right now I'm trying to write a class which encrypts and decrypts Strings using BouncyCastle with AES-GCM. I read about the things you have to consider when implementing encryption. One of them was that you should always use a randomized IV.
The problem is, everytime I try to initialize my Cipher with an IV it won't decrypt my text properly.
It just throws the following exception:
javax.crypto.AEADBadTagException: mac check in GCM failed
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at BouncyCastleEX.decrypt(BouncyCastleEX.java:78)
at BouncyCastleEX.main(BouncyCastleEX.java:43)
I'm using the following methods to encrypt and decrypt my data.
private static final String fallbackSalt = "ajefa6tc73t6raiw7tr63wi3r7citrawcirtcdg78o2vawri7t";
private static final int iterations = 2000;
private static final int keyLength = 256;
private static final SecureRandom random = new SecureRandom();
public byte[] encrypt(String plaintext, String passphrase, String salt)
throws Exception {
SecretKey key = generateKey(passphrase, salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key, generateIV(cipher),random);
return cipher.doFinal(plaintext.getBytes());
}
public String decrypt(byte[] encrypted, String passphrase, String salt)
throws Exception {
SecretKey key = generateKey(passphrase, salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key, generateIV(cipher),random);
return new String(cipher.doFinal(encrypted));
}
private SecretKey generateKey(String passphrase, String salt)
throws Exception {
PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(),
salt.getBytes(), iterations, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
return keyFactory.generateSecret(keySpec);
}
private IvParameterSpec generateIV(Cipher cipher) throws Exception {
byte[] ivBytes = new byte[cipher.getBlockSize()];
random.nextBytes(ivBytes);
return new IvParameterSpec(ivBytes);
}
If I remove the "generateIV(cipher)" from my cipher.init(...) everything works flawlessly. But as far as I know it weakens the encryption tremendously.
Right know I'm unable to figure out whether this is a small mistake in the code or something else I know nothing about.
I really appreciate your help and thanks a lot!
You have to use the same IV for encryption and decryption. It doesn't have to be secret, but only unique for AES-GCM (it's technically a nonce). A common way is to prepend the IV to the ciphertext and remove it before decryption.
It's also common to use a message counter instead of randomly generating an IV. If the key is changed then you should reset the IV to an initial value and start counting again. At some number of messages, you need a new key, because the security guarantees of AES-GCM break down. That number is somewhere between 248 and 264 messages.
Here is the final version of my code which I wrote with the help of Artjom.
It seems to work great but if you find any mistakes or things that weaken the security, please let me know.
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class BouncyCastleEX {
private static final int iterations = 2000;
private static final int keyLength = 256;
private static final SecureRandom random = new SecureRandom();
private static BouncyCastleEX instance = null;
public String encryptString(String plaintext, String passphrase, String salt)
throws Exception {
return Base64.encode(encrypt(plaintext, passphrase, salt));
}
public String decryptString(String encrypted, String passphrase, String salt)
throws Exception {
return decrypt(Base64.decode(encrypted), passphrase, salt);
}
private BouncyCastleEX() {
Security.addProvider(new BouncyCastleProvider());
}
public static BouncyCastleEX getInstance() {
if (instance == null) {
instance = new BouncyCastleEX();
}
return instance;
}
private byte[] encrypt(String plaintext, String passphrase, String salt)
throws Exception {
SecretKey key = generateKey(passphrase, salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
byte[] ivBytes = generateIVBytes(cipher);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes),
random);
return Arrays
.concatenate(ivBytes, cipher.doFinal(plaintext.getBytes()));
}
private String decrypt(byte[] encrypted, String passphrase, String salt)
throws Exception {
SecretKey key = generateKey(passphrase, salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key,
new IvParameterSpec(Arrays.copyOfRange(encrypted, 0, 12)),
random);
return new String(cipher.doFinal(Arrays.copyOfRange(encrypted, 12,
encrypted.length)));
}
private SecretKey generateKey(String passphrase, String salt)
throws Exception {
PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(),
salt.getBytes(), iterations, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
return keyFactory.generateSecret(keySpec);
}
private byte[] generateIVBytes(Cipher cipher) throws Exception {
byte[] ivBytes = new byte[12];
random.nextBytes(ivBytes);
return ivBytes;
}
}
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();
}
}
}