This is my first project in Java and I decided to make a simple text encryptor using AES.
The error I am getting is: The method init(int, Key) in the type Cipher is not applicable for the arguments (int, byte[])
Code:
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import javax.crypto.*;
import java.util.*;
public class Encryptor {
public static void main(String[] args) throws Exception {
String FileName = "encryptedtext.txt";
String FileName2 = "decryptedtext.txt";
Scanner input = new Scanner(System.in);
System.out.println("Enter your 16 character key here:");
String EncryptionKey = input.next();
KeyGenerator KeyGen = KeyGenerator.getInstance("AES");
KeyGen.init(128);
Cipher AesCipher = Cipher.getInstance("AES");
System.out.println("Enter text to encrypt or decrypt:");
String Text = input.next();
System.out.println("Do you want to encrypt or decrypt (e/d)");
String answer = input.next();
if (answer.equalsIgnoreCase("e")){
byte[] byteKey = (EncryptionKey.getBytes());
byte[] byteText = (Text).getBytes();
AesCipher.init(Cipher.ENCRYPT_MODE, byteKey); // ERROR LINE
byte[] byteCipherText = AesCipher.doFinal(byteText);
Files.write(Paths.get(FileName), byteCipherText);
}
else if (answer.equalsIgnoreCase("d")){
byte[] byteKey = (EncryptionKey.getBytes());
byte[] byteText = (Text).getBytes();
byte[] cipherText = Files.readAllBytes(Paths.get(FileName));
AesCipher.init(Cipher.DECRYPT_MODE, byteKey); // ERROR LINE
byte[] bytePlainText = AesCipher.doFinal(cipherText);
Files.write(Paths.get(FileName2), bytePlainText);
}
}
}
Thanks in advance! :)
This is Full code
Full code:
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
public class Encrypter {
public static void main(String[] args) throws Exception {
String FileName = "encryptedtext.txt";
String FileName2 = "decryptedtext.txt";
Scanner input = new Scanner(System.in);
System.out.println("Enter your 16 character key here:");
String EncryptionKey = input.next();
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
KeyGenerator KeyGen = KeyGenerator.getInstance("AES");
KeyGen.init(128);
Cipher AesCipher = Cipher.getInstance("AES/CFB/NoPadding");
System.out.println("Enter text to encrypt or decrypt:");
String Text = input.next();
System.out.println("Do you want to encrypt or decrypt (e/d)");
String answer = input.next();
if (answer.equalsIgnoreCase("e")){
byte[] byteKey = (EncryptionKey.getBytes());
byte[] byteText = (Text).getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(byteKey, "AES");
AesCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec,ivspec );
AesCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec,ivspec); // ERROR LINE
byte[] byteCipherText = AesCipher.doFinal(byteText);
Files.write(Paths.get(FileName), byteCipherText);
}
else if (answer.equalsIgnoreCase("d")){
byte[] byteKey = (EncryptionKey.getBytes());
byte[] byteText = (Text).getBytes();
byte[] cipherText = Files.readAllBytes(Paths.get(FileName));
SecretKeySpec secretKeySpec = new SecretKeySpec(byteKey, "AES");
AesCipher.init(Cipher.DECRYPT_MODE, secretKeySpec,ivspec); // ERROR LINE
byte[] bytePlainText = AesCipher.doFinal(cipherText);
Files.write(Paths.get(FileName2), bytePlainText);
}
}
}
You should not pass byte array directly to Cipher object, instead you need to create object of SecretKeySpecs.
This is complete Code
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
public class Encrypter {
public static void main(String[] args) throws Exception {
String FileName = "encryptedtext.txt";
String FileName2 = "decryptedtext.txt";
Scanner input = new Scanner(System.in);
System.out.println("Enter your 16 character key here:");
String EncryptionKey = input.next();
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
KeyGenerator KeyGen = KeyGenerator.getInstance("AES");
KeyGen.init(128);
Cipher AesCipher = Cipher.getInstance("AES/CFB/NoPadding");
System.out.println("Enter text to encrypt or decrypt:");
String Text = input.next();
System.out.println("Do you want to encrypt or decrypt (e/d)");
String answer = input.next();
if (answer.equalsIgnoreCase("e")) {
byte[] byteKey = (EncryptionKey.getBytes());
byte[] byteText = (Text).getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(byteKey, "AES");
AesCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivspec);
AesCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivspec); // ERROR LINE
byte[] byteCipherText = AesCipher.doFinal(byteText);
Files.write(Paths.get(FileName), byteCipherText);
} else if (answer.equalsIgnoreCase("d")) {
byte[] byteKey = (EncryptionKey.getBytes());
byte[] byteText = (Text).getBytes();
byte[] cipherText = Files.readAllBytes(Paths.get(FileName));
SecretKeySpec secretKeySpec = new SecretKeySpec(byteKey, "AES");
AesCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivspec); // ERROR LINE
byte[] bytePlainText = AesCipher.doFinal(cipherText);
Files.write(Paths.get(FileName2), bytePlainText);
}
}
}
I had to encrypt a URL for been exposed in a external link, and I have created a class to encrypt on AES. Maybe this can help someone.
I added a method to create my Random Initial Vector and it is on this class also.
package br.com.tokiomarine.captcha.encryption;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.text.CharacterPredicates;
import org.apache.commons.text.RandomStringGenerator;
public class Encryptor
{
public static String encrypt(String key, String initVector, String value) throws Exception
{
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64URLSafeString(encrypted);
}
public static String decrypt(String key, String initVector, String encrypted) throws Exception
{
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
}
public static String generateInitVector() {
RandomStringGenerator randomStringGenerator =
new RandomStringGenerator.Builder()
.withinRange('0', 'z')
.filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS)
.build();
return randomStringGenerator.generate(16);
}
}
And here is my Test Class:
public class EcryptionTest {
#Test
public void encryptionTest() {
try
{
String key = "Key#TokioMarineC";
for(int i = 0; i < 1000; i++)
{
String initVector = Encryptor.generateInitVector();
String encrypted = Encryptor.encrypt(key, initVector, "StringTeste");
assertTrue("StringTeste".equals(Encryptor.decrypt(key, initVector, encrypted)));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
I am not sure what wrong I have done to this. To cut story short I want to decrypt a file with the given secretKey and using iv and I am using the following code to do so :
package com.Crypt.test;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.SecureRandom;
public class AES256CBCTest {
static String encoding = "UTF-8";
public static void main(String[] args) throws Exception {
String key = "BURP6070";
File inputFile = new File("/Users/jaynigam/Documents/workspace/EncryptDecrypt/files/test.xml.enc");
try {
BufferedReader br = new BufferedReader(new FileReader(inputFile));
String st;
File outputFile =null;
FileOutputStream outputStream = null;
try {
while ((st = br.readLine()) != null){
//decrypt(someString.getBytes(encoding), key);
String decrypted = decrypt(st.getBytes(), key);
outputFile = new File("/Users/jaynigam/Documents/workspace/EncryptDecrypt/files/decryptTest.xml.dec");
outputStream = new FileOutputStream(outputFile);
byte[] strToBytes = decrypted.getBytes(encoding);
outputStream.write(strToBytes);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
outputStream.close();
br.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//byte[] encrypted = encrypt(clean, key);
public static byte[] encrypt(String plainText, String key) throws Exception {
byte[] clean = plainText.getBytes();
// Generating IV.
int ivSize = 16;
byte[] iv = new byte[ivSize];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Hashing key.
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(key.getBytes());
byte[] keyBytes = new byte[32];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
// Encrypt.
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(clean);
// Combine IV and encrypted part.
byte[] encryptedIVAndText = new byte[ivSize + encrypted.length];
System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize);
System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length);
return encryptedIVAndText;
}
public static String decrypt(byte[] encryptedIvTextBytes, String key) throws Exception {
int ivSize = 16;
int keySize = 16;
// Extract IV.
byte[] iv = new byte[ivSize];
System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Extract encrypted part.
int encryptedSize = encryptedIvTextBytes.length - ivSize;
byte[] encryptedBytes = new byte[encryptedSize];
System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize);
// Hash key.
byte[] keyBytes = new byte[keySize];
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(key.getBytes());
System.arraycopy(md.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
// Decrypt.
Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/NoPadding");
cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes);
return new String(decrypted);
}
}
This returns me an output like ?lm:#?ڤ?w?)P#?\?s????Ka???0??{???w|k???o?\?. I have already tried UTF-8 decoding. But still no luck till now. Does anyone have any clue on this one?
I've had exactly the same problem as you, and also used the same source code!
I had a problem using the return and input parameters as byte[], so i've converted it to String with Base64 encoding, so i didnt end up with problems with encodings.
My class:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;
public class PasswordManager {
private static final Logger LOGGER = LoggerFactory.getLogger(PasswordManager.class);
private static final String key = "DdFfGg998012jffW"; // 128 bit key
private PasswordManager() {
}
public static String encrypt(String plainText) {
if (plainText == null) {
return null;
}
byte[] clean = plainText.getBytes();
// Generating IV.
int ivSize = 16;
byte[] iv = new byte[ivSize];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
try {
// Hashing key.
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key.getBytes(StandardCharsets.UTF_8));
byte[] keyBytes = new byte[16];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
// Encrypt.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(clean);
// Combine IV and encrypted part.
byte[] encryptedIVAndText = new byte[ivSize + encrypted.length];
System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize);
System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length);
return Base64.getEncoder().encodeToString(encryptedIVAndText);
} catch (Exception e) {
LOGGER.error("Exception in decrypting a password. Returning null", e);
return null;
}
}
public static String decrypt(String encryptedString) {
if (encryptedString == null) {
return null;
}
byte[] encryptedIvTextBytes = Base64.getDecoder().decode(encryptedString);
int ivSize = 16;
int keySize = 16;
// Extract IV.
byte[] iv = new byte[ivSize];
System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Extract encrypted part.
int encryptedSize = encryptedIvTextBytes.length - ivSize;
byte[] encryptedBytes = new byte[encryptedSize];
System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize);
try {
// Hash key.
byte[] keyBytes = new byte[keySize];
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(key.getBytes());
System.arraycopy(md.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
// Decrypt.
Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes);
return new String(decrypted);
} catch (Exception e) {
LOGGER.error("Exception in decrypting a password. Returning null", e);
return null;
}
}
}
Also try using a key with the same length as mine, try that first, as it could be the problem. After try to use Base64 on string operations on your while loop.
Hope it helps you.
I am trying to use AES/GCM/NoPadding for encryption in Java8. But I can't figure out why I am having a AEADBadTagException when decrypting.
Here's my code:
private final int GCM_IV_LENGTH = 12;
private final int GCM_TAG_LENGTH = 16;
private static String encrypt(String privateString, SecretKey skey) {
byte[] iv = new byte[GCM_IV_LENGTH];
(new SecureRandom()).nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);
byte[] ciphertext = cipher.doFinal(privateString.getBytes("UTF8"));
byte[] encrypted = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, encrypted, 0, iv.length);
System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
Base64Encoder encoder = new Base64Encoder();
String encoded = encoder.encode(encrypted);
return encoded;
}
private static String decrypt(String encrypted, SecretKey skey) {
Base64Decoder decoder = new Base64Decoder();
String decoded = encoder.encode(encrypted);
byte[] iv = Arrays.copyOfRange(decoded, 0, GCM_IV_LENGTH);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);
byte[] ciphertext = cipher.doFinal(decoded, GCM_IV_LENGTH, decoded.length - GCM_IV_LENGTH);
String newString = new String(ciphertext, "UTF8");
return newString;
}
Hope someone can help me fix this exception. Thanks!
I've corrected a few typos, and used Java 8's base64 utilities, and it seems to work fine for me. Here is my version and you can compare it to yours.
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
public class Main {
private final static int GCM_IV_LENGTH = 12;
private final static int GCM_TAG_LENGTH = 16;
private static String encrypt(String privateString, SecretKey skey) throws Exception {
byte[] iv = new byte[GCM_IV_LENGTH];
(new SecureRandom()).nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);
byte[] ciphertext = cipher.doFinal(privateString.getBytes("UTF8"));
byte[] encrypted = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, encrypted, 0, iv.length);
System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
String encoded = Base64.getEncoder().encodeToString(encrypted);
return encoded;
}
private static String decrypt(String encrypted, SecretKey skey) throws Exception {
byte[] decoded = Base64.getDecoder().decode(encrypted);
byte[] iv = Arrays.copyOfRange(decoded, 0, GCM_IV_LENGTH);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);
byte[] ciphertext = cipher.doFinal(decoded, GCM_IV_LENGTH, decoded.length - GCM_IV_LENGTH);
String result = new String(ciphertext, "UTF8");
return result;
}
public static void main(String[] args) throws Exception {
SecretKey key = new SecretKeySpec(new byte[16], "AES"); // key is 16 zero bytes
String s = decrypt(encrypt("This is the first string to test", key), key);
System.out.println(s);
}
}
I would like to encrypt this javascript code in android.
let base64Key = CryptoJS.enc.Base64.parse(key);
let encryptedValue = CryptoJS.AES.encrypt(value, base64Key, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: base64Key
});
return encryptedValue.toString();
Code:
String encryptedKey = Base64.encodeToString(keyword.getBytes(), Base64.NO_WRAP);
Key key = new SecretKeySpec(encryptedKey.getBytes(), algorithm);
Cipher chiper = Cipher.getInstance("AES");
chiper.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = chiper.doFinal(plainText.getBytes());
String encryptedValue = Base64.encodeToString(encVal, Base64.NO_WRAP);
return encryptedValue;
But it returns a completely different value.
The first line of the code itself returns a different value in both cases:
So I got this part working.
I just needed to add the following lines to the android code:
byte[] decoded = Base64.decode(key.getBytes());
String hexString = Hex.encodeHexString(decoded);
This is the equivalent of CryptoJS.enc.Base64.parse(key); this line in CryptoJS.
But still trying to figure out the end result though. Both are different.
I am also having same issue but finally, i got a Class from Git.
AESHelper.decrypt("your secret key","encryptedText")
import com.sun.jersey.core.util.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
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.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AESHelper {
/**
*
* Conforming with CryptoJS AES method
* **** YOU NEED TO ADD "JCE policy" to have ability to DEC/ENC 256 key-lenght with AES Cipher ****
*
*/
static int KEY_SIZE = 256;
static int IV_SIZE = 128;
static String HASH_CIPHER = "AES/CBC/PKCS7Padding";
static String AES = "AES";
static String CHARSET_TYPE = "UTF-8";
static String KDF_DIGEST = "MD5";
// Seriously crypto-js, what's wrong with you?
static String APPEND = "Salted__";
/**
* Encrypt
* #param password passphrase
* #param plainText plain string
*/
public static String encrypt(String password,String plainText) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] saltBytes = generateSalt(8);
byte[] key = new byte[KEY_SIZE/8];
byte[] iv = new byte[IV_SIZE/8];
EvpKDF(password.getBytes(CHARSET_TYPE), KEY_SIZE, IV_SIZE, saltBytes, key, iv);
SecretKey keyS = new SecretKeySpec(key, AES);
Cipher cipher = Cipher.getInstance(HASH_CIPHER);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, keyS, ivSpec);
byte[] cipherText = cipher.doFinal(plainText.getBytes(CHARSET_TYPE));
// Thanks kientux for this: https://gist.github.com/kientux/bb48259c6f2133e628ad
// Create CryptoJS-like encrypted !
byte[] sBytes = APPEND.getBytes(CHARSET_TYPE);
byte[] b = new byte[sBytes.length + saltBytes.length + cipherText.length];
System.arraycopy(sBytes, 0, b, 0, sBytes.length);
System.arraycopy(saltBytes, 0, b, sBytes.length, saltBytes.length);
System.arraycopy(cipherText, 0, b, sBytes.length + saltBytes.length, cipherText.length);
byte[] bEncode = Base64.encode(b);
return new String(bEncode);
}
/**
* Decrypt
* Thanks Artjom B. for this: http://stackoverflow.com/a/29152379/4405051
* #param password passphrase
* #param cipherText encrypted string
*/
public static String decrypt(String password,String cipherText) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] ctBytes = Base64.decode(cipherText.getBytes(CHARSET_TYPE));
byte[] saltBytes = Arrays.copyOfRange(ctBytes, 8, 16);
byte[] ciphertextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.length);
byte[] key = new byte[KEY_SIZE/8];
byte[] iv = new byte[IV_SIZE/8];
EvpKDF(password.getBytes(CHARSET_TYPE), KEY_SIZE, IV_SIZE, saltBytes, key, iv);
Cipher cipher = Cipher.getInstance(HASH_CIPHER);
SecretKey keyS = new SecretKeySpec(key, AES);
cipher.init(Cipher.DECRYPT_MODE, keyS, new IvParameterSpec(iv));
byte[] plainText = cipher.doFinal(ciphertextBytes);
return new String(plainText);
}
private static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
return EvpKDF(password, keySize, ivSize, salt, 1, KDF_DIGEST, resultKey, resultIv);
}
private static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
keySize = keySize / 32;
ivSize = ivSize / 32;
int targetKeySize = keySize + ivSize;
byte[] derivedBytes = new byte[targetKeySize * 4];
int numberOfDerivedWords = 0;
byte[] block = null;
MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm);
while (numberOfDerivedWords < targetKeySize) {
if (block != null) {
hasher.update(block);
}
hasher.update(password);
block = hasher.digest(salt);
hasher.reset();
// Iterations
for (int i = 1; i < iterations; i++) {
block = hasher.digest(block);
hasher.reset();
}
System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4,
Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4));
numberOfDerivedWords += block.length/4;
}
System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4);
System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4);
return derivedBytes; // key + iv
}
private static byte[] generateSalt(int length) {
Random r = new SecureRandom();
byte[] salt = new byte[length];
r.nextBytes(salt);
return salt;
}
}
Check out related question here and page on Java Cryptographic Extensions
To turn a text string (UTF-8 encoded) into a base-64 string, you need:
var textString = 'Hello world'; // Utf8-encoded string
var words = CryptoJS.enc.Utf8.parse(textString); // WordArray object
var base64 = CryptoJS.enc.Base64.stringify(words); // string: 'SGVsbG8gd29ybGQ='
Finally got it working in Android using the below code, if anyone else faces the issue:
public static String encrypt(String key, String value) {
try {
SecretKey secretKey = new SecretKeySpec(Base64.decode(key.getBytes(), Base64.NO_WRAP), "AES");
AlgorithmParameterSpec iv = new IvParameterSpec(Base64.decode(key.getBytes(), Base64.NO_WRAP));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return new String(Base64.encode(cipher.doFinal(value.getBytes("UTF-8")), Base64.NO_WRAP));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
The below code works for me,
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class EncryptionUtils {
private static final String key = "123456$##$^#RRRR";//16 characters
private static final String initVector = "123456$##$^#RRRR";//16 characters
public static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
// byte[] finalCiphertext = new byte[encrypted.length+2*16];
return Base64.encodeToString(encrypted, Base64.NO_WRAP);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
[Edit:] SOLVED! See this article. Full working source code. JavaX.
[Original post:]
sorry to hit this fairly dead horse once more, but I can't get this to work... (I've provided a full example): http://tinybrain.de/1000344
Code:
import java.net.*;
import java.io.*;
import javax.swing.*;
import java.util.regex.*;
import java.util.*;
import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class main {
public static void main(String[] args) throws Exception {
byte[] data = "hello".getBytes("UTF-8");
printHex(data);
Random ranGen = new SecureRandom();
byte[] salt = new byte[8]; // 8 grains of salt
ranGen.nextBytes(salt);
String pw = "pw";
byte[] enc = encrypt(data, pw.toCharArray(), salt);
printHex(enc);
System.out.println("enc length: " + enc.length);
byte[] dec = decrypt(enc, pw.toCharArray(), salt);
System.out.println("decrypted: " + new String(dec, "UTF-8"));
}
static void printHex(byte[] data) {
System.out.println(bytesToHex(data));
}
static String bytesToHex(byte[] bytes) {
return bytesToHex(bytes, 0, bytes.length);
}
static String bytesToHex(byte[] bytes, int ofs, int len) {
StringBuilder stringBuilder = new StringBuilder(len*2);
for (int i = 0; i < len; i++) {
String s = "0" + Integer.toHexString(bytes[ofs+i]);
stringBuilder.append(s.substring(s.length()-2, s.length()));
}
return stringBuilder.toString();
}
static SecretKey makeKey(char[] password, byte[] salt) throws Exception {
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
// only with unlimited strength:
//KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
// Let's try this:
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
return secret;
}
public static byte[] encrypt(byte[] data, char[] password, byte[] salt) {
try {
SecretKey secret = makeKey(password, salt);
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(cipher.update(data));
baos.write(cipher.doFinal());
byte[] ciphertext = baos.toByteArray();
return ciphertext;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static byte[] decrypt(byte[] ciphertext, char[] password, byte[] salt) {
try {
SecretKey secret = makeKey(password, salt);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
/* Decrypt the message, given derived key and initialization vector. */
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
baos.write(cipher.update(ciphertext));
baos.write(cipher.doFinal());
return baos.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
It says:
javax.crypto.BadPaddingException: Given final block not properly padded
at main.decrypt(main.java:98)
at main.main(main.java:26)
... 9 more
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2048)
at main.decrypt(main.java:95)
What to do?
You are using a random IV, but you are not sharing the random IV generated during encryption with the decryption method. Instead, it is using a random IV itself.
You've got:
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
but you don't seem to do anything with the IV afterwards.
I am new to Security in java.
I have two clear double length keys which was used for generating ZPK (under LMK) in Futurex HSM.
Below mentioned pin blocks were encrypted using ZPK.
Is there a way to decrypt the block using clear keys in java.
clear_1 = "801CB5C89DC416C149FB645BB36897AD"
clear_2 = "45B98FC7D33149E0512F0ED9135E5826"
encrypted_pin_block = "6288FA9534BF2AA3"
encrypted_pin_block = "B8D876F238348EB0"
Decrypted value for one of these encrypted blocks is 2222.
See Sample Example for 3dec encryption and decryption
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
class ZiggyTest2{
public static void main(String[] args) throws Exception{
String text = "I am sunil";
byte[] codedtext = new ZiggyTest2().encrypt(text);
String decodedtext = new ZiggyTest2().decrypt(codedtext);
System.out.println(codedtext); // this is a byte array, you'll just see a reference to an array
System.out.println(decodedtext); // This correctly shows "kyle boon"
}
public byte[] encrypt(String message) throws Exception {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digestOfPassword = md.digest("ABCDEABCDE"
.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] cipherText = cipher.doFinal(plainTextBytes);
// String encodedCipherText = new sun.misc.BASE64Encoder()
// .encode(cipherText);
return cipherText;
}
public String decrypt(byte[] message) throws Exception {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digestOfPassword = md.digest("ABCDEABCDE"
.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
}