We're trying to figure out how to do this in Java/scala:
use Crypt::CBC;
$aesKey = "some key"
$cipher = new Crypt::CBC($aesKey, "DES");
$encrypted = $cipher->encrypt("hello world");
print $encrypted // prints: Salted__�,%�8XL�/1�&�n;����쀍c
print encode_base64($encrypted); // prints: U2FsdGVkX19JwL/Dc4gwehTfZ1ahNlO6Jf41vALcshg=
$decrypted = $cipher->decrypt($encrypted);
print $decrypted // prints: hello world
The problem is that the perl code is something we can not chanage.
I tried a few things in scala but didn't really get it right, for example something like this:
val secretKey = new SecretKeySpec("some key".getBytes("UTF-8"), "DES")
val encipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
encipher.init(Cipher.ENCRYPT_MODE, secretKey)
val encrypted = encipher.doFinal("hello world".getBytes)
println(encrypted) // prints: [B#4896ceb3
println(java.util.Arrays.toString(encrypted)) // [-45, -126, -90, 36, 8, -73, 6, 85, -94, 108, 100, -120, 15, -8, 126, 76]
println(Hex.encodeHexString(encrypted)) //prints: 822c90f1116686e75160ff06c8faf4a4
What we eventually need to do is to be able to decrypt cookies in Java set by Perl.
Any help or direction in Java/scala would very much be appreciated
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
final class CrapEncryption
{
private static final byte[] MAGIC = "Salted__".getBytes(StandardCharsets.US_ASCII);
private static final int KEY_LEN = 8;
private static final int SALT_LEN = 8;
private static final SecureRandom random = new SecureRandom();
static byte[] pretendToEncrypt(byte[] password, byte[] msg)
throws GeneralSecurityException
{
byte[] salt = new byte[SALT_LEN];
random.nextBytes(salt);
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password);
md5.update(salt);
byte[] dk = md5.digest();
Cipher des;
try {
SecretKey key = new SecretKeySpec(dk, 0, KEY_LEN, "DES");
AlgorithmParameterSpec iv = new IvParameterSpec(dk, KEY_LEN, SALT_LEN);
des = Cipher.getInstance("DES/CBC/PKCS5Padding");
des.init(Cipher.ENCRYPT_MODE, key, iv);
}
finally {
Arrays.fill(dk, (byte) 0);
}
byte[] pkg = new byte[des.getOutputSize(msg.length) + MAGIC.length + SALT_LEN];
System.arraycopy(MAGIC, 0, pkg, 0, MAGIC.length);
System.arraycopy(salt, 0, pkg, MAGIC.length, SALT_LEN);
des.doFinal(msg, 0, msg.length, pkg, MAGIC.length + SALT_LEN);
return pkg;
}
static byte[] decrypt(byte[] password, byte[] pkg)
throws GeneralSecurityException
{
if ((pkg.length < MAGIC.length) || !Arrays.equals(Arrays.copyOfRange(pkg, 0, MAGIC.length), MAGIC))
throw new IllegalArgumentException("Expected magic number \"Salted__\"");
if (pkg.length < MAGIC.length + SALT_LEN)
throw new IllegalArgumentException("Missing salt");
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password); /* password */
md5.update(pkg, MAGIC.length, SALT_LEN); /* salt */
byte[] dk = md5.digest();
Cipher des;
try {
SecretKey secret = new SecretKeySpec(dk, 0, KEY_LEN, "DES");
des = Cipher.getInstance("DES/CBC/PKCS5Padding");
des.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(dk, KEY_LEN, SALT_LEN));
}
finally {
Arrays.fill(dk, (byte) 0);
}
return des.doFinal(pkg, MAGIC.length + SALT_LEN, pkg.length - MAGIC.length - SALT_LEN);
}
public static void main(String... argv)
throws Exception
{
byte[] password = "some key".getBytes(StandardCharsets.UTF_8);
byte[] message = "hello world".getBytes(StandardCharsets.UTF_8);
byte[] encrypted = pretendToEncrypt(password, message);
byte[] recovered = decrypt(password, encrypted);
System.out.println(new String(recovered, StandardCharsets.UTF_8));
}
}
Why "CrapEncryption" and "pretendToEncrypt"? Because the algorithms used here are the worst! DES is not secure. MD5 is not secure. The key derivation function uses only one iteration. This is all garbage. Use AES with PBKDF2 instead.
Related
I am trying to use PBKDF2WithHmacSHA512 in PHP with OpenSSL.
But I am not able to create same string as Java created encrypted string. Data which I am trying to encrypt is Atom Insta Pay. With the below mentioned java code I am getting vneGN6vnDJ3Z4wj4u3+z1g== but in PHP I am getting JQubY9xCf+g9yASdNkq7cQ== which is totally different.
// Java code
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class myEncryption {
static Logger log = Logger.getLogger(myEncryption.class.getName());
private static int pswdIterations = 65536;
private static int keySize = 256;
private static final byte[] ivBytes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
public static String encrypt(String plainText, String key) {
try {
byte[] saltBytes = key.getBytes("UTF-8");
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, pswdIterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(1, secret, localIvParameterSpec);
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return byteToHex(encryptedTextBytes);
}catch (Exception e) {
log.info("Exception while encrypting data:" + e.toString());
}
return null;
}
public static String decrypt(String encryptedText, String key) {
try {
byte[] saltBytes = key.getBytes("UTF-8");
byte[] encryptedTextBytes = hex2ByteArray(encryptedText);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, pswdIterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secret, localIvParameterSpec);
byte[] decryptedTextBytes = (byte[]) null;
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
}catch (Exception e) {
log.info("Exception while decrypting data:" + e.toString());
}
return null;
}
private static String byteToHex(byte[] byData) {
StringBuffer sb = new StringBuffer(byData.length * 2);
for (int i = 0; i < byData.length; ++i) {
int v = byData[i] & 0xFF;
if (v < 16)
sb.append('0');
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase();
}
private static byte[] hex2ByteArray(String sHexData) {
byte[] rawData = new byte[sHexData.length() / 2];
for (int i = 0; i < rawData.length; ++i) {
int index = i * 2;
int v = Integer.parseInt(sHexData.substring(index, index + 2), 16);
rawData[i] = (byte) v;
}
return rawData;
}
}
//PHP code
$method = "AES-256-CBC";
$salt = 'A4476C2062FFA58980DC8F79EB6A799E';
$key = 'A4476C2062FFA58980DC8F79EB6A799E';
$data = 'Demo String';
//Converting Array to bytes
$iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
$chars = array_map("chr", $iv);
$IVbytes = join($chars);
$salt1 = mb_convert_encoding($salt, "UTF-8"); //Encoding to UTF-8
$key1 = mb_convert_encoding($key, "UTF-8"); //Encoding to UTF-8
//SecretKeyFactory Instance of PBKDF2WithHmacSHA512 Java Equivalent
$hash = openssl_pbkdf2($key1,$salt1,'256','65536', 'sha512');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
echo base64_encode($encrypted);
The PHP-solution is much "easier" as the Java-side and can consume the key and salt as direct input (without converting them).
As you like to compare base64-encoded ciphertexts the sample code returns the base64-encoded ciphertext and not the hex string
as the Java-prog is giving out.
This is the output with equal results:
expected: JQubY9xCf+g9yASdNkq7cQ==
encrypted: JQubY9xCf+g9yASdNkq7cQ==
Security warning: your code is using static salt and iv that makes the encryption unsecure (I hope it's just for demonstration).
This is the code:
<?php
//PHP code
$method = "AES-256-CBC";
$salt = 'A4476C2062FFA58980DC8F79EB6A799E';
$key = 'A4476C2062FFA58980DC8F79EB6A799E';
$data = 'Atom Insta Pay';
//Converting Array to bytes
$iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
$chars = array_map("chr", $iv);
$IVbytes = join($chars);
$hash = openssl_pbkdf2($key,$salt,32,65536, 'sha512');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
echo 'expected: JQubY9xCf+g9yASdNkq7cQ==' . PHP_EOL;
echo 'encrypted: ' . base64_encode($encrypted);
?>
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 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;
}
}
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();
}
}
}
return Base64.encodeBase64String(cipherText);
im getting an error in this line.It suggest me to make a class in base64,but is there any standard class for Base64?Im using this to encrypt.
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Arrays;
import java.io.*;
import java.lang.*;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class TRIPPLE_DES {
public static void main(String[] args) throws Exception {
String text = "cardNumber=28293939493330&securityCode=123&cardExpiryMonth=07&cardExpiryYear=2013&cardHolderName=Test&transactionAmount=50.00¤cyCode=356&customerReferenceNo=9393938393938&cardProvider=VISA&name=Test&mobileNo=983345123412&email=test#test.com&contactNo=983345123412&password=wyzgames&amount=100&remoteIP=10.10.10.50&checkSum=92be84d25b60b3f9f233c074d12ade1ddef158cb369a0734afff3fb6adc9d7ddb4b26f7e6001563747a8d47457e713750e5802b4871cfbe70baca9304d4c385f";
String codedtext = new TRIPPLE_DES().encrypt(text);
String decodedtext = new TRIPPLE_DES().decrypt(codedtext);
String encodedurl = URLEncoder.encode(codedtext,"UTF-8");
System.out.println(encodedurl);
System.out.println(decodedtext);
}
public String encrypt(String message) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest("HG58YZ3CR9".getBytes("utf-8"));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
final byte[] plainTextBytes = message.getBytes("utf-8");
final byte[] cipherText = cipher.doFinal(plainTextBytes);
return Base64.encodeBase64String(cipherText);
}
public String decrypt(String message) throws Exception
{
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest("HG58YZ3CR9".getBytes("utf-8"));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] byteMessage= Base64.decodeBase64(message);
final byte[] plainText = decipher.doFinal(byteMessage);
return new String(plainText, "UTF-8");
}
}
There isn't an official Base64 class in JDK.
I can suggest you to use this: Apache Commons Codec
you can use Base64Encoder and Base64Decoder for you purpose.
Change
Base64.encodeBase64String(cipherText)
to
new BASE64Encoder().encode(cipherText)
and
Base64.decodeBase64(message)
to
new BASE64Decoder().decodeBuffer(message)