I've wrote a method to encrypt/decrypt a string. Encryption is happening successfully but I cannot manage to make the decryption work... This is the code I have written:
public String encrypt(String a, int x) {
String ret = "";
String text = a;
String key = "Bar12345Bar12345"; // 128 bit key
try {
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
if(x == 0) { //x==0 means I want to encrypt
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(text.getBytes());
ret =new String(encrypted);
}
else { //if not 0 I want to decrypt
// decrypt the text
byte[] encrypted = text.getBytes(Charset.forName("UTF-8"));
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(encrypted));
ret=decrypted;
}
} catch(Exception e) {
e.printStackTrace();
}
return ret;
}
I think the problem arise when I'm trying to convert the string into byte array. The error I get is:
javax.crypto.BadPaddingException: Given final block not properly padded
So what is the problem ? If I am not converting the string into byte array in right way, how should I do it ?
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I am trying to create a simple AES encryption/decryption module for use in a larger project, but I'm having trouble getting the AES methods to work. I've done a good amount of research, but I can't figure out what is going wrong within my code (I'm suspecting something simple that I'm missing).
Main:
public static byte[] genKey() {
// Create key generator
KeyGenerator keyGen;
try {
keyGen = KeyGenerator.getInstance("AES");
}
catch(GeneralSecurityException e) {
e.printStackTrace();
return null;
}
// Create random byte generator
SecureRandom r = new SecureRandom();
// Initialize key generator
keyGen.init(256, r);
SecretKey key = keyGen.generateKey();
return key.getEncoded();
}
public static void main(String[] args) throws GeneralSecurityException {
// write your code here
// Create AES handler
AES aes = new AES();
// Generate key
byte[] key = genKey();
// Set key for AES
aes.setKey(key);
Scanner in = new Scanner(System.in);
System.out.print("Please enter a phrase to encrypt: ");
String input = in.nextLine();
// Encrypt phrase
byte[][] encrypted = aes.encrypt(input);
// Decrypt phrase
String plaintext = aes.decrypt(encrypted[0], encrypted[1]);
// Print results
System.out.println("Ciphertext: " + encrypted[1]);
System.out.println("Plaintext: " + plaintext);
}
AES:
private Cipher cipher;
private SecretKey key;
public AES() {
// Create Cipher
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
public void setKey(byte[] key) {
this.key = new SecretKeySpec(key, "AES");
}
public byte[][] encrypt(String plaintext) throws GeneralSecurityException {
System.out.println("Using key : " + key.getEncoded() + " to encrypt");
byte[][] values = new byte[2][];
// Decode plaintext into bytes
byte[] decodedPlaintext = new byte[0];
try {
decodedPlaintext = plaintext.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// Generate an IV and set up the Cipher to encrypt
byte[] ivBytes = new byte[16];
SecureRandom rand = new SecureRandom();
rand.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
// Encrypt decoded plaintext
byte[] ciphertext = cipher.doFinal(decodedPlaintext);
values[0] = ivBytes;
values[1] = ciphertext;
return values;
}
public String decrypt(byte[] ivBytes, byte[] ciphertext) throws GeneralSecurityException {
System.out.println("Using key " + key.getEncoded() + " to decrypt");
// Set up cipher to decrypt
IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decodedPlaintext = cipher.doFinal(ciphertext);
// Encode plaintext
String plaintext = Base64.getEncoder().encodeToString(decodedPlaintext);
return plaintext;
}
Results:
Please enter a phrase to encrypt: test
Using key : [B#442d9b6e to encrypt
Using key [B#3d012ddd to decrypt
Ciphertext: [B#515f550a
Plaintext: dGVzdA==
I don't understand why my encryption/decryption seem to be using different keys when I only set the key once in the beginning. Am I creating a key wrong?
I've also tried:
byte[] key = new byte[32];
SecureRandom r = new SecureRandom();
r.nextBytes(key);
// Set key for AES
aes.setKey(key);
And run into the same issue.
If you trace this.key in AES class all the way through encode and decode using Arrays.toString(this.key.getEncoded()) it does look like it's using a persistent key.
this.key.getEncoded().toString()) returns a different representation each time but it seems like the actual byte array is the same.
I replaced
String plaintext = Base64.getEncoder().encodeToString(decodedPlaintext);
with
String plaintext = new String(decodedPlaintext, StandardCharsets.UTF_8);
and it seemed to work.
I am using third party application which is in PHP and mine is in java, for which I need to send a few data in an encrypted format. They have shared the secret key and IV. But I am not able to get the same output as they are getting while encryption. Although whatever I am encrypting in java, I am able to get the same while decrypting in java. Please help me out with this.
public static String secret_key = "abc";
public static String secret_iv = "abc#243";
public static String strKeyString = toHexString(getSHA(secret_key));
public static String ivString = toHexString(getSHA(secret_iv));
public static String strKey= strKeyString.substring(0, 16);
public static String strIv = ivString.substring(0, 16);
public static byte[] getSHA(String input)
{
// Static getInstance method is called with hashing SHA
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
// digest() method called
// to calculate message digest of an input
// and return array of byte
return md.digest(input.getBytes(StandardCharsets.UTF_8));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static String toHexString(byte[] hash)
{
// Convert byte array into signum representation
BigInteger number = new BigInteger(1, hash);
// Convert message digest into hex value
StringBuilder hexString = new StringBuilder(number.toString(16));
// Pad with leading zeros
while (hexString.length() < 32)
{
hexString.insert(0, '0');
}
return hexString.toString();
}
public static String openssl_encrypt(String data) throws Exception {
Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec(strKey.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(strIv.getBytes(), 0, ciper.getBlockSize());
// Encrypt
ciper.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encryptedCiperBytes = ciper.doFinal(data.getBytes());
System.out.println("Ciper encrypted : " + Base64.encodeBase64String(encryptedCiperBytes));
//Decrypt
ciper.init(Cipher.DECRYPT_MODE, key, iv);
byte[] output = ciper.doFinal(Base64.decodeBase64(Base64.encodeBase64String(encryptedCiperBytes)));
System.out.println("Ciper decrypted : " +new String(output).trim());
return Base64.encodeBase64String(encryptedCiperBytes);
}
I try to do a PHP openssl_encrypt aes-256-cbc with OPENSSL_RAW_DATA in java 6 without success. I found some topic about this, but I'ved successful only to do it in aes-128-cbc without raw_data. The best topic I founded about this it's : AES-256 CBC encrypt in php and decrypt in Java or vice-versa
But the raw_data doesn't work and the 256 bits key is randomly generated.
In fact the Php version is :
<?php>
openssl(
"hello",
"aes-256-cbc",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
OPENSSL_RAW_DATA,
"aaaaaaaaaaaaaaaa"
)
?>
And I actually have this :
public static void main(String[] args) {
try {
// 128 bits key
openssl_encrypt("hello", "bbbbbbbbbbbbbbbb", "aaaaaaaaaaaaaaaa");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static String openssl_encrypt(String data, String strKey, String strIv) throws Exception {
Base64 base64 = new Base64();
Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec(strKey.getBytes("UTF-8"), "AES");
IvParameterSpec iv = new IvParameterSpec(strIv.getBytes("UTF-8"), 0, ciper.getBlockSize());
// Encrypt
ciper.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encryptedCiperBytes = base64.encode((ciper.doFinal(data.getBytes())));
String s = new String(encryptedCiperBytes);
System.out.println("Ciper : " + s);
return s;
}
After few modification and some testing I found it :
private static String openssl_encrypt(String data, String strKey, String strIv) throws Exception {
Base64 base64 = new Base64();
Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec(strKey.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(strIv.getBytes(), 0, ciper.getBlockSize());
// Encrypt
ciper.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encryptedCiperBytes = ciper.doFinal(data.getBytes());
String s = new String(encryptedCiperBytes);
System.out.println("Ciper : " + s);
return s;
}
openssl_encrypt in PHP don't convert his result in base64, and I also use getBytes() without param cause, for some keys, I had an error about the key's lentgh.
So this method do the same thing than :
<?php>
openssl_encrypt(data, "aes-256-cbc", key, OPENSSL_RAW_DATA, iv);
?>
I would like to encrypt 3 strings using AES 128 in Java / Grails, and using the code below, but i get the error "An error occurred when encrypting", can someone tell me what is wrong with my code, how to fix it. thanks in advance and to Stackoverflow.
String url = "https://someurl.com"
String token = createToken(bookNumber, invNumber, cusNumber)
url += '?ref=' + token
class AesEncryptor {
static byte[] encrypt(String clearText) {
byte[] encrypted = null
try {
byte[] iv = new byte[16]
Arrays.fill(iv, (byte) 0)
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
encrypted = cipher.doFinal(clearText.getBytes("UTF-8"))
}
catch (Exception e) {
log.error "An error occurred when encrypting", e
}
encrypted
}
/**
* Creates a token.
* #return
*/
static String createToken(final String bookNumber, final String invNumber, final String cusNumber) {
String data = bookNumber + invNumber + cusNumber
String token = URLEncoder.encode(Base64.encodeBase64String(encrypt(data)), "UTF-8")
token
}
}
the error i get:
java.lang.IllegalStateException: Cipher not initialized
at javax.crypto.Cipher.checkCipherState(Cipher.java:1672)
at javax.crypto.Cipher.doFinal(Cipher.java:2079)
at javax.crypto.Cipher$doFinal$1.call(Unknown Source)
cipher.init method call is missed in your code. Check the below code.
public byte[] encrypt(byte[] data, byte[] key) {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
return cipher.doFinal(data);
}
For decrypt have to change mode to Cipher.DECRYPT_MODE
This is the code for encrypting and decrypting a string in java using AES algorithm. Its throwing illegalblocksize exception while decrypting.
I know it is occuring because length of input string to the decryption method isn't matching with the padding. I don't have an idea of how to solve this.
I am a new bie to the encryption decryption. Plz help me....
StackTrace:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at test.AES.AESdecryptalgo(AES.java:76)
at test.AES.main(AES.java:95)
Code:
package test;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
public class AES
{
public byte[] encrypted;
public byte[] original;
public String originalString;
Cipher cipher;
SecretKeySpec skeySpec;
IvParameterSpec spec;
byte [] iv;
/*public static String asHex (byte buf[])
{
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10)
strbuf.append("0");
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}*/
public AES()
{
try
{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
skeySpec = new SecretKeySpec(raw, "AES");
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}
catch(Exception ex)
{ex.printStackTrace();}
}
public String AESencryptalgo(byte[] text)
{
String newtext="";
try
{
// byte[] raw = skey.getEncoded();
//SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
AlgorithmParameters param = cipher.getParameters();
IvParameterSpec ivspec=param.getParameterSpec(IvParameterSpec.class);
iv=ivspec.getIV();
spec=new IvParameterSpec(iv);
//AlgorithmParameters params = cipher.getParameters();
//iv = params.getParameterSpec(IvParameterSpec.class).getIV();
encrypted = cipher.doFinal(text);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
newtext=new String(encrypted);
//System.out.println("ENCRYPTED "+newtext);
return newtext;
}
}
public String AESdecryptalgo(byte[] text)
{
try
{
cipher.init(Cipher.DECRYPT_MODE, skeySpec,spec);
original = cipher.doFinal(text); //Exception occurs here
originalString = new String(original);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
return originalString;
}
}
public static void main(String[] args)
{
AES a=new AES();
String encrypt=a.AESencryptalgo("hello".getBytes());
System.out.println(encrypt);
String decrypt=a.AESdecryptalgo(encrypt.getBytes());
System.out.println(decrypt);
}
}`
You have to provide an initialization vector when using CBC mode.
When encrypting, let the provider choose the IV for you:
…
cipher.init(Cipher.ENCRYPT_MODE, key);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
…
Later, when decrypting, use the same IV to initialize the cipher:
…
IvParameterSpec spec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
…
You must change AESencryptalgo to return byte[] rather than a String. This is where the trouble begins:
newtext = new String(encrypted);
// System.out.println("ENCRYPTED "+newtext);
return newtext;
After changing the return type of the method, you should make the following change:
//newtext = new String(encrypted);
// System.out.println("ENCRYPTED "+newtext);
//return newtext;
return encrypted;
The problem is that a String is a sequence of characters, whereas the encrypted text is a sequence of bytes (for a good summary of this difference, see The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)).
When you try to construct a String from a byte array, Java tries its best to convert those bytes into characters, using the system's default character set. Unfortunately, this mapping doesn't always work successfully (typically when the encrypted bytes fall outside the ASCII character set). You will only ever notice the problem when it comes time to decrypt your new String (which will fail to properly convert the sequence of characters back into the original sequence of bytes).