I am pretty new in Java Cryptography.I have provided with the following PHP code to decrypt a AES-256 / CBC / ZeroBytePadding encrypted object.
function decrypt($key, $data)
{
if (!in_array(strlen($key), array(32, 48, 64)))
{
throw new Exception("Invalid key");
}
$key_hex = pack('H*', $key);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$ciphertext = base64_decode($data);
# retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
$iv_dec = substr($ciphertext, 0, $iv_size);
# retrieves the cipher text (everything except the $iv_size in the front)
$ciphertext_dec = substr($ciphertext, $iv_size);
# may remove 00h valued characters from end of plain text
$result = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key_hex, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
return $result;
}
I need to do the same in java. After lots of searching I have made the following code:
public String decrypt(byte key[], String encrypted)
throws GeneralSecurityException {
if (key.length != 32 || key.length != 48 || key.length != 64) {
throw new IllegalArgumentException("Invalid key size.");
}
byte[] ciphertextBytes = Base64.decodeBase64(encrypted.getBytes());
// Need to find the IV length here. I am using 16 here
IvParameterSpec iv = new IvParameterSpec(ciphertextBytes, 0, 16);
ciphertextBytes = Arrays.copyOfRange(ciphertextBytes, 16,
ciphertextBytes.length);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(ciphertextBytes);
// remove zero bytes at the end
int lastLength = original.length;
for (int i = original.length - 1; i > original.length - 16; i--) {
if (original[i] == (byte) 0) {
lastLength--;
} else {
break;
}
}
return new String(original, 0, lastLength);
}
But I need to find the IV length here. In PHP they are doing this using:
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
How to implement it in java? Can anybody help me please?
I am calling the method like this:
public static void main(String args[]) {
String key = "F5D4471791B79B6360C1EFF4A76250C1D7E5C23F5E4C3C43893B6CCAA796E307";
String encrypted = "F4N8SvpF1zgyMnQKwLlX\\/Dfgsj4kU58pg3kaSrt+AJt9D7\\/3vAfngegtytAdCUwwkQ2nxj8PVABRy0aaeBfsJN9n2Ltco6oPjdcmx8eOI";
try {
String decrypted = decrypt(Hex.decodeHex(key.toCharArray()), encrypted);
System.out.println(decrypted);
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
An IV for AES (Rijndael-128) in CBC mode has always the same size as the block, which is 16 bytes or 128 bits. If you keep using CBC mode, then you can hardcode that value or use Cipher#getBlockSize().
If you want to use AES-256, then you need to install the Unlimited Strength policy files for your JRE/JDK (Link for Java 8). AES-128 can be used without modification, but the US export restrictions require that you enable the higher key sizes yourself.
Answer: With the help of Artjom B. I have created the code that will decrypt the AES-256 / CBC / ZeroBytePadding encrypted string. I am posting this for others who need the help.
1. Firstly you have to download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy for your JDK version.
2. Extract the zip file & put the local_policy.jar & US_export_policy.jar in the path /JDK Path/jre/lib/security. This is required as my key is 64 byte. AES requires 16/24/32 bytes of key.
3. Copy paste my code & change it as per your requirement :P.
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.binary.Base64;
public class Decryption {
public static void main(String args[]) {
//I have changed the original key. So mere copy pasting may not work. Put your key here.
String key = "FfDaaaaaaa444aaaa7aaEFF4A76efaaaaaE5C23F5E4C3adeaaaaaaCAA796E307";
String encrypted = "8AQ8SvpF1zgyNyxKwLlX\\/cGzwLE5skU58pg3kaSrt+AJt9D7\\/3vaNRPZISIKMdCUwwkQ2nxj8PVABRy0aaeBfsJN9n2Ltco6oPjdcmx8eOI";
String decrypted = "";
try {
try {
decrypted = decrypt(Hex.decodeHex(key.toCharArray()), encrypted);
} catch (DecoderException e) {
e.printStackTrace();
}
System.out.println(decrypted);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
public static String decrypt(byte key[], String encrypted)
throws GeneralSecurityException {
/*
* if (key.length != 32 || key.length != 48 || key.length != 64) { throw
* new IllegalArgumentException("Invalid key size."); }
*/
byte[] ciphertextBytes = Base64.decodeBase64(encrypted.getBytes());
IvParameterSpec iv = new IvParameterSpec(ciphertextBytes, 0, 16);
ciphertextBytes = Arrays.copyOfRange(ciphertextBytes, 16,
ciphertextBytes.length);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(ciphertextBytes);
// Remove zero bytes at the end.
int lastLength = original.length;
for (int i = original.length - 1; i > original.length - 16; i--) {
if (original[i] == (byte) 0) {
lastLength--;
} else {
break;
}
}
return new String(original, 0, lastLength);
}
}
Thanks #Artjom B. for your help & expertise :).
Related
public long copyStreamsLong(InputStream in, OutputStream out, long sizeLimit) throws IOException {
long byteCount = 0;
IOException error = null;
long totalBytesRead = 0;
try {
String key = "C4F9EA21977047D6"; // user value (16/24/32 bytes)
// byte[] keyBytes = DatatypeConverter.parseHexBinary(aesKey);
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
System.out.println(secretKey.toString());
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] buffer = new byte[CustomLimitedStreamCopier.BYTE_BUFFER_SIZE];
// in.read(buffer);
int bytesRead = -1;
while ((bytesRead = in.read(buffer)) != -1) {
// We are able to abort the copy immediately upon limit violation.
totalBytesRead += bytesRead;
if (sizeLimit > 0 && totalBytesRead > sizeLimit) {
StringBuilder msg = new StringBuilder();
msg.append("Content size violation, limit = ").append(sizeLimit);
throw new ContentLimitViolationException(msg.toString());
}
byte[] obuf = cipher.update(buffer, 0, bytesRead);
if (obuf != null) {
out.write(obuf);
}
byteCount += bytesRead;
}
byte[] obuf = cipher.doFinal();
if (obuf != null) {
out.write(obuf);
}
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
error = e;
CustomLimitedStreamCopier.logger.error("Failed to close input stream: " + this, e);
}
try {
out.close();
} catch (IOException e) {
error = e;
CustomLimitedStreamCopier.logger.error("Failed to close output stream: " + this, e);
}
}
if (error != null)
throw error;
return byteCount;
}
public InputStream getContentInputStream() throws ContentIOException {
ReadableByteChannel channel = getReadableChannel();
InputStream is = Channels.newInputStream(channel);
try {
final String ALGORITHM = "AES";
final String TRANSFORMATION = "AES";
String key = "C4F9EA21977047D6";
Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] buffer = ByteStreams.toByteArray(is);
System.out.println("in read" + buffer.length);
is.read(buffer);
byte[] outputBytes = cipher.doFinal(buffer);
is = new ByteArrayInputStream(outputBytes);
}
When i m trying to encrypt input stream i will get increased byte array and after that when i will decrypt that input stream at that time in decryption it will take original byte size .so,when i tried to open that file it will give error that premature end tag so i want same file size after encryption ,and this method is part of java class.
What will be the solution for this problem?
You initialize the cipher with the TRANSFORMATION = "AES" and that means that your Java implementation will choose a default AES mode, usually it is "AES/ECB/PKCS5Padding". Beneath the fact that ECB-mode is unsecure and should not any longer used for plaintext/streams longer than 16 bytes the padding will add additional bytes up to a (multiple) blocklength of 16.
So running my small program you see that in your implementation an inputLen of "10" (means a plaintext/stream of 10 byte length) will result in an outputSize of "16".
To avoid this you do need another AES mode and that the output is of the same length as the input on encryption side. You can use AES CTR mode for this - you just need an additional parameter (initialization vector, 16 byte long). It is very important that you never ever use the same iv for more than 1 encryption so it should get generated as random value. For decryption the recipient of the message ("the decryptor") needs to know what initvector was used on encryption side.
cipher algorithm: AES inputLen 10 outputSize 16
cipher algorithm: AES/CTR/NOPADDING inputLen 10 outputSize 10
Edit (security warning): As reminded by President James K. Polk "CTR mode makes it trivial to modify individual bytes of the attacker's choosing, so it needs to be coupled with an authentication tag.". It depends on the kind of data that are going to get encrypted if they need a authentication (e.g. if you are encrypting music files then any modifying will result in a "piep" or "krk", changing of financial data will end catastrophical).
code:
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
public class Main {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException {
System.out.println("");
int inputLen = 10;
final String ALGORITHM = "AES";
// aes ecb mode
final String TRANSFORMATION = "AES";
//final String TRANSFORMATION = "AES/ECB/PKCS5PADDING";
String key = "C4F9EA21977047D6";
Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
System.out.format("cipher algorithm: %-20s inputLen %3d outputSize %3d%n", cipher.getAlgorithm(), inputLen, cipher.getOutputSize(inputLen));
// aes ctr mode
String TRANSFORMATION2 = "AES/CTR/NOPADDING";
// you need an unique (random) iv for each encryption
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[16];
secureRandom.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher2 = Cipher.getInstance(TRANSFORMATION2);
cipher2.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
System.out.format("cipher algorithm: %-20s inputLen %3d outputSize %3d%n", cipher2.getAlgorithm(), inputLen, cipher2.getOutputSize(inputLen));
}
}
A running implementation of the AES CTR-mode can be found here: https://stackoverflow.com/a/62662276/8166854
Unable to decrypt the cipher text in Java which is ecrypted in GoLang using Blowfish.
Encryption
import (
"testing"
"golang.org/x/crypto/blowfish"
"github.com/andreburgaud/crypt2go/ecb"
"github.com/andreburgaud/crypt2go/padding"
"fmt"
"encoding/base64"
)
func TestEncrypt(t *testing.T) {
bytes := []byte("cap")
key := []byte("1c157d26e2db9a96a556e7614e1fbe36")
encByte := encrypt(bytes, key)
enc := base64.StdEncoding.EncodeToString(encByte)
fmt.Printf("ENC - %s\n", enc)
}
func encrypt(pt, key []byte) []byte {
block, err := blowfish.NewCipher(key)
if err != nil {
panic(err.Error())
}
mode := ecb.NewECBEncrypter(block)
padder := padding.NewPkcs5Padding()
pt, err = padder.Pad(pt) // padd last block of plaintext if block size less than block cipher size
if err != nil {
panic(err.Error())
}
ct := make([]byte, len(pt))
mode.CryptBlocks(ct, pt)
return ct
}
// Output
// ENC - AP9atM49v8o=
Decryption
import lombok.SneakyThrows;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import static java.util.Base64.getDecoder;
import static java.util.Base64.getEncoder;
public class UserAuthenticationFilter {
public static void main(String[] args) throws Exception {
String key = "1c157d26e2db9a96a556e7614e1fbe36";
System.out.println(decrypt(getDecoder().decode("AP9atM49v8o="), key));
// encryption and decryption verification
// String plainText = "cap";
// String cipher = encrypt(plainText, key);
// String decrypted = decrypt(getDecoder().decode(enc), key);
// assert decrypted.equals(plainText);
}
#SneakyThrows
public static String encrypt(String plainText, String key) {
byte[] myKeyByte = hexToBytes(key);
SecretKeySpec skeySpec = new SecretKeySpec(myKeyByte, "Blowfish");
Cipher ecipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
ecipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] src = ecipher.doFinal(plainText.getBytes("ISO-8859-1"));
return getEncoder().encodeToString(src);
}
#SneakyThrows
public static String decrypt(byte[] cipherContent, String key) {
byte[] myKeyByte = hexToBytes(key);
SecretKeySpec skeySpec = new SecretKeySpec(myKeyByte, "Blowfish");
Cipher dcipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
dcipher.init(2, skeySpec);
byte[] dcontent = dcipher.doFinal(cipherContent);
return (new String(dcontent, "ISO-8859-1")).trim();
}
private static byte[] hexToBytes(String str) {
if (str == null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for(int i = 0; i < len; ++i) {
buffer[i] = (byte)Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
}
return buffer;
}
}
}
// Output
// BY x³
As per the outputs, encryption in GoLang and decryption in Java doesn't produce the same plain text. Initially, thought the problem might be related to golang's byte (0 to 255) and java's byte (-128 to 127) involved in base64 encoding and decoding. But poking in Java's decryption code, it's handled correctly with value & 255.
Decryption of the same cipher text in golang works perfectly. Also encryption and decryption in Java works perfectly. But not the encryption in one and decryption in other.
I think the encryption and decryption logic were correct. Only guess might be there's some language specific ??? is missing when the cipher text is ported to other language for decryption.
key := []byte("1c157d26e2db9a96a556e7614e1fbe36")
I believe this piece of code returns byte array of the string itself, not hex decoded value. To get a valid key you may try to use hex decoding
I am trying to reuse an AES implementation with Initialization Vector. So far I am only implementing the part where data is being encrypted on the android application and being decrypted on the php server. However, the algorithm has a major loophole, that the Initialization Vector is constant, which I just recently found out is a major security flaw. Unfortunately I have already implemented it on every single activity of my application and all scripts on the server side.
I wanted to know if there was a way to modify this code so that the initialization vector is randomized, and some way to send that vector to the server (or vice versa), so that every time the message is encrypted the pattern keeps changing. Here are my codes for Android and PHP:
Android:
package com.fyp.merchantapp;
// This file and its contents have been taken from http://www.androidsnippets.com/encrypt-decrypt-between-android-and-php.html
//Ownership has been acknowledged
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class MCrypt {
static char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
private String iv = "MyNameIsHamza100";//(IV)
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey = "MyNameIsBilal100";//(SECRETKEY)
public MCrypt()
{
ivspec = new IvParameterSpec(iv.getBytes());
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public byte[] encrypt(String text) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty string");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}
public byte[] decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
//Remove trailing zeroes
if( decrypted.length > 0)
{
int trim = 0;
for( int i = decrypted.length - 1; i >= 0; i-- ) if( decrypted[i] == 0 ) trim++;
if( trim > 0 )
{
byte[] newArray = new byte[decrypted.length - trim];
System.arraycopy(decrypted, 0, newArray, 0, decrypted.length - trim);
decrypted = newArray;
}
}
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] buf)
{
char[] chars = new char[2 * buf.length];
for (int i = 0; i < buf.length; ++i)
{
chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
}
return new String(chars);
}
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
private static String padString(String source)
{
char paddingChar = 0;
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++)
{
source += paddingChar;
}
return source;
}
}
PHP:
<?php
class MCrypt
{
private $iv = 'MyNameIsHamza100'; #Same as in JAVA
private $key = 'MyNameIsBilal100'; #Same as in JAVA
function __construct()
{
}
/**
* #param string $str
* #param bool $isBinary whether to encrypt as binary or not. Default is: false
* #return string Encrypted data
*/
function encrypt($str, $isBinary = false)
{
$iv = $this->iv;
$str = $isBinary ? $str : utf8_decode($str);
$td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$encrypted = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $isBinary ? $encrypted : bin2hex($encrypted);
}
/**
* #param string $code
* #param bool $isBinary whether to decrypt as binary or not. Default is: false
* #return string Decrypted data
*/
function decrypt($code, $isBinary = false)
{
$code = $isBinary ? $code : $this->hex2bin($code);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$decrypted = mdecrypt_generic($td, $code);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $isBinary ? trim($decrypted) : utf8_encode(trim($decrypted));
}
protected function hex2bin($hexdata)
{
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
?>
To directly answer your question: you can simply generate a random IV and prefix it to the ciphertext. You need to do this before encoding the ciphertext to hexadecimals. Then during decryption first decode, then "remove" the IV bytes, initialize the IV and finally decrypt the ciphertext to obtain the plaintext.
Note that the IV will always be 16 bytes for AES in CBC mode, so there is no direct need to include the IV length anywhere. I used quotes around "remove" as both IvParameterSpec as Cipher.doFinal accept buffers with offset and length; there is no need to copy the bytes to different arrays.
Notes:
keys should not be strings; lookup PBKDF's such as PBKDF2 to derive a key from a password or pass phrase;
CBC is generally vulnerable to padding oracle attacks; however, by keeping to PHP's zero padding you may have avoided attacks by accident;
CBC doesn't provide integrity protection, so note that adversaries may change the ciphertext without decryption failing;
if the underlying code that uses the text generates errors then you may be vulnerable to plaintext oracle attacks (padding oracle attacks are only part of the larger group of plaintext oracles);
your Java code is unbalanced; the encrypt and decrypt mode should either perform hex encoding / decoding or they should not;
the exception handling is of course not good (although that may be just for the example);
String#getBytes() will use UTF-8 on Android, but it may use Windows-1252 on Java SE on Windows, so this is prone to generating the wrong key if you're not careful - always define the character set to use.
To use a shared secret to communicate, try TLS in pre-shared secret mode, defined by one of the PSK_ cipher suites.
Hi I have java code which decrypt the ciphertext encrypted using CryptoJS library(AES).
Now i wanted to write the javacode which will encrypt the plaintext again.
Please find the below code.
try {
String secret = "René Über";
String cipherText="U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=";
byte[] cipherData = Base64.decode(cipherText, Base64.DEFAULT);
byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);
MessageDigest md5 = MessageDigest.getInstance("MD5");
final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes("utf-8"), md5);
SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);
byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decryptedData = aesCBC.doFinal(encrypted);
String decryptedText = new String(decryptedData,"utf-8");
System.out.println("Decrypted "+decryptedText);
//Here I get right plain text as
//System.out: Decrypted The quick brown fox jumps over the lazy dog.
Cipher abc=Cipher.getInstance("AES/CBC/PKCS5Padding");
abc.init(Cipher.ENCRYPT_MODE,key,iv);
byte[] encryptedData=abc.doFinal(decryptedData);
String str=Base64.encodeToString(encryptedData,Base64.DEFAULT);
System.out.println("encrypted "+str);
//Here i want the encrypted text as
// encrypted U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hy//aQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=
//but i receive
//System.out: encrypted IZ5IDQruC+Cz0pd5krBsIM0KzbM+j4FeO8pgusm60wr6HFPCX+HJpAs5oPssshGjYjl/J5Ew+//eui
}catch (Exception e)
{}
When I decrypt the code I get correct Plain Text but when I again encrypt the plain text I didnt get the encrypted text as previous.
Please Help.
GenerateKeyAndIV function code:-
public static byte[][] GenerateKeyAndIV(int keyLength, int ivLength, int iterations, byte[] salt, byte[] password, MessageDigest md) {
int digestLength = md.getDigestLength();
int requiredLength = (keyLength + ivLength + digestLength - 1) / digestLength * digestLength;
byte[] generatedData = new byte[requiredLength];
int generatedLength = 0;
try {
md.reset();
// Repeat process until sufficient data has been generated
while (generatedLength < keyLength + ivLength) {
// Digest data (last digest if available, password data, salt if available)
if (generatedLength > 0)
md.update(generatedData, generatedLength - digestLength, digestLength);
md.update(password);
if (salt != null)
md.update(salt, 0, 8);
md.digest(generatedData, generatedLength, digestLength);
// additional rounds
for (int i = 1; i < iterations; i++) {
md.update(generatedData, generatedLength, digestLength);
md.digest(generatedData, generatedLength, digestLength);
}
generatedLength += digestLength;
}
// Copy key and IV into separate byte arrays
byte[][] result = new byte[2][];
result[0] = Arrays.copyOfRange(generatedData, 0, keyLength);
if (ivLength > 0)
result[1] = Arrays.copyOfRange(generatedData, keyLength, keyLength + ivLength);
return result;
} catch (DigestException e) {
throw new RuntimeException(e);
} finally {
// Clean out temporary data
Arrays.fill(generatedData, (byte)0);
}
}
Your ciphertext has "Salted__<8 byte salt>" at the beginning, which you skip when decrypting. You need to prefix the same in your encryption mode if you want to create OpenSSL compatible ciphertext.
Your encryption code ciphertext seems correct when you view it in a base64 to hex decoder, e.g. the one provided here. However, because each character only contains 64 bits and since the bytes have shifted 16 places (which is not divisible by 3), it just seams that your entire ciphertext is incorrect, while it is just missing 16 bytes at the front.
Here posting my working code for android I have used crypto for decryption on the server. Below code is using AES Algorithm
private static final String key = "aesExamplekey";
private static final String initVector = "exampleintvec";
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;
}`
Server side code asp.net
public string DecryptStringAES(string cipherText)
{
// var keybytes = Encoding.UTF8.GetBytes("7061737323313233");
// var iv = Encoding.UTF8.GetBytes("7061737323313233");
var keybytes = Encoding.UTF8.GetBytes("aesExamplekey");
var iv = Encoding.UTF8.GetBytes("exampleintvec");
var encrypted = Convert.FromBase64String(cipherText);
var decriptedFromJavascript = DecryptStringFromBytes(encrypted, keybytes, iv);
return string.Format(decriptedFromJavascript);
}
I am doing some simple encryption/decryption coding, and I am having a problem, which I cannot figure out by myself.
I have a ciphertext which is hex encoded. The ciphertext is AES with a block length of 128bits and a key length of 256bits. The cipher block mode is CBC. IV is the first block of the cipher text.
The Exception Message is Illegal Key Size.
Here is my decrypt() function:
public static byte[] decrypt() throws Exception
{
try{
byte[] ciphertextBytes = convertToBytes("cb12f5ca1bae224ad44fdff6e66f9a53e25f1000183ba5568958430c11c6eafc62c04de8bf27e0ac7104b598fb492142");
byte[] keyBytes = convertToBytes("CFDC65CB003DD50FF5D6D826D62CF9CA6C64489D60CB02D18C1B58C636F8220D");
byte[] ivBytes = convertToBytes("cb12f5ca1bae224a");
SecretKey aesKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(ivBytes));
byte[] result = cipher.doFinal(ciphertextBytes);
return result;
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
return null;
}
And I have those functions to do the conversion String/ByteArray
//convert ByteArray to Hex String
public static String convertToHex(byte[] byteArray)
{
StringBuilder sb = new StringBuilder();
for (byte b : byteArray)
{
sb.append(String.format("%02X", b));
}
return sb.toString();
}
//convert String to ByteArray
private static byte[] convertToBytes(String input) {
int length = input.length();
byte[] output = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
output[i / 2] = (byte) ((digit(input.charAt(i), 16) << 4) | digit(input.charAt(i+1), 16));
}
return output;
}
Maybe you can help me.
Thank you very much!
You might have hit the key-size limit in Oracle JRE. From the linked document:
If stronger algorithms are needed (for example, AES with 256-bit keys), the JCE Unlimited Strength Jurisdiction Policy Files must be obtained and installed in the JDK/JRE.
It is the user's responsibility to verify that this action is permissible under local regulations.