128 bit key issue in AES algorithm Java/ Java Script - java

I need to encrypt values in my Java code with user choice key and decrypt the values in Java script module.
Below is my Java code to encrypt the values. Here I am generating 128 bit key value from the user choice key and same is using to encrypt the values.
String plainText = "Hello, World! This is a Java/Javascript AES test.";
try {
byte[] rawKey = getRawKey("12345".getBytes());
SecretKey key = new SecretKeySpec(rawKey, "AES");
AlgorithmParameterSpec iv = new IvParameterSpec(
Base64.decodeBase64("5D9r9ZVzEYYgha93/aUK2w=="));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
System.out.println(Base64.encodeBase64String(cipher
.doFinal(plainText.getBytes("UTF-8"))));
} catch (Exception e) {
e.printStackTrace();
System.out.println("Exception in crypto...");
}
public static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
String s = new String(raw);
System.out.println("raw key.." + raw);
return raw;
}
Above code printing the below values:
raw key..[B#45b9ce4b
vN2GouJcVli/rFMDHEwCNZejraO5cQxBtlo5D64qkaRTkxxRTIo+Vm38H4fUZp7ABxj7ul0Ha6bO5aFxMzMY0g==
When I use the above values to decrypt in JS code , I am not getting any response.
<html>
<head>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script >
var encrypted = CryptoJS.enc.Base64.parse('vN2GouJcVli/rFMDHEwCNZejraO5cQxBtlo5D64qkaRTkxxRTIo+Vm38H4fUZp7ABxj7ul0Ha6bO5aFxMzMY0g==');
var key = CryptoJS.enc.Base64.parse('[B#45b9ce4b');
var iv = CryptoJS.enc.Base64.parse('5D9r9ZVzEYYgha93/aUK2w==');
document.write(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(
{ ciphertext: encrypted },
key,
{ mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: iv, })));
</script>
</head>
<body>
<h1>hsd h </h1>
</body>
</html>
Please point me If there's anything missing from my code or please suggest me if any alternative to produce the same result.

Your key is incorrect in your JS code. In your Java code you called System.out.println() using a byte[] as an argument which will not give you meaningful output. [B#45b9ce4b is not valid Base64 data.
To fix this you need take the byte[] representing the key and Base64 encode it into a String and then print the string.
A comment on key generation:
You should avoid using a random number generator to derive key material from user input (i.e. a password). The correct way to create key material from user input is by using a key stretching algorithm.
You should absolutely use a standard algorithm for this such as PBKDF2. In Java you can get a key factory for this via SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

Related

AES Encryption in android and decryption in nodejs

I was trying encryption in android and decryption in nodejs server. I generated an AES 128bit key and encrypt it using AES algorithm and then encrypt this generated key using RSA algorithm. Then send both to the server. But while decrypting on the server side, I think the RSA decryption works fine but have a problem in AES decryption.
I'm not getting the string in server side that I encrypted on the client side.
This is the code for the encryption on android side:
String encryptedSecretKey;
String cipherTextString;
// 1. generate secret key using AES
KeyGenerator keyGenerator = null;
keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
// 2. get string which needs to be encrypted
String text = "This is the message to be encrypted";
// 3. encrypt string using secret key
byte[] raw = secretKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
cipherTextString = Base64.encodeToString(cipher.doFinal(text.getBytes(Charset.forName("UTF-8"))), Base64.DEFAULT);
// 4. get public key
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(Base64.decode(publicKeyString, Base64.DEFAULT));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(publicSpec);
// 5. encrypt secret key using public key
Cipher cipher2 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher2.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedSecretKey = Base64.encodeToString(cipher2.doFinal(secretKey.getEncoded()), Base64.DEFAULT);
Then send this to the server side.
The code for server side is given below:
var encryptedMessage = req.body.cipherText;
var encryptedAesKey = req.body.secretKey;
//printing those values
console.log("\nEncryptedMessage: \n" + encryptedMessage);
console.log("\nEncrypted key: \n" + encryptedAesKey);
var privateKey = fs.readFileSync('././Keys/privkey_server.pem', "utf8");
var bufferForAesKey = new Buffer(encryptedAesKey, "base64");
var obj = {
key: privateKey
// , padding: constants.RSA_PKCS1_PADDING
// , padding: constants.RSA/ECB/OAEPWithSHA-1
};
var decryptedAes = crypto.privateDecrypt(obj, bufferForAesKey);
console.log("Decrypted AES: " + decryptedAes);
var decryptedAesKeyString = decryptedAes.toString("base64");
console.log("Decrypted AES Key: " + decryptedAesKeyString);
var bufferForAES = new Buffer(decryptedAes, "base64");
//decrypting using AES
var bufferForEncryptedMsg = new Buffer(encryptedMessage, "base64");
var decipher = crypto.createDecipher('aes-128-cbc',bufferForAES);
decipher.setAutoPadding(false);
var dec = decipher.update(bufferForEncryptedMsg,"base64", "utf8");
dec += decipher.final("utf8");
console.log(dec);
Here the final result 'dec' is not giving the correct result but the intermediate results are same in client and server. That means, RSA works fine but have problem in AES.
The output is given below:
EncryptedMessage:
SfosHg+cTrQXYUdF0FuqCJMHgfcP13ckp2L0B9QqOcl8UtWnnl8fLi5lxgR2SKOj
Encrypted key:
C/pa52PZda3xShrPXkHZx8OL6sW4JBEhG/ggNAoHhSVXIGt+iDq/B1ByG5yStBGF3GFJRQT0aGsG
+bZJydP7j9gTivmt99H/bxiZan4CHZnqfGKG1dJCI7ILAYZMCw7JhIcRC8qHMM4LMdF+rxRhENDe
alUfnsLWpcrX9J6fKejJ7EWnWQ1VadKqCDmrJ5xw0lBbsOpwN/vY09+VhF4WkOz8Y3cQGk+FVdz5
tr4L9/jgXlTZdOC2KVBLSH+9pvtHwMWFKKoDSAzvkil4htBjbWTqlBuEINC4I/J/4P3RX2riT5Pv
xHQi/Dv7vdBlo9AEdvWe3Ek8oBleIpmIQHXwQWknPOYghhBAVmACG/tbEQcAtbcmRLruT/XzjPJt
HNBt2HeG9JHYKNoHC3kOuJdnlGe8mv8k0Nzwj04RhEGKSmPIiu/oDgYwS0l96KIlS2ELqBlS5O0L
AJ+RBG7m0WwC9dfrufsuwu0+SPUmg5/ElXRmA3T81lXtQqQbGg8G6r/bAVFGduy4a49s/VWoylx+
/sI079IwyY0IOfwQTVGZRyDC5O1ZBjoYv2+TRo3bjG8GXNQoybkmWkhgotcqVD9mXO67D2NBsFPT
EJnw+1ApSqR7ggIAF+qsMxejFKBICBL/4J8FP4+obA07J1pWiciTRKX+G130qzIBKM08Zdaf/50=
Decrypted AES: %Kp[ϪS�/�W l��9ӊ˽��~��
B�A�
Decrypted AES Key: JUtwW8+qU6Mv/FcgbMbkOdOKy72pun4B490KQrRB4QQ=
T�Ϝ��u��q�
���w�p���u`�̗r[`H0[tW��=��~i-�W
Here the Decrypted AES key is same as the key that we generate in android. But the final output is not giving the desired result. Is there any error in my code??
Neardupe Decrypting strings from node.js in Java? which is the same thing in the opposite direction.
[In Java] I generated an AES 128bit key and encrypt [with] it using AES algorithm and then encrypt this generated key using RSA algorithm.
No you didn't. Your Java code instantiates a KeyGenerator for AES-128, but doesn't use it to generate any key. The key you actually used (and as you say the server correctly decrypted from RSA-OAEP) is 32 bytes, corresponding to AES-256.
But your main problem is that createDecipher takes a password NOT the key. Per the doc
crypto.createDecipher(algorithm, password[, options])
The implementation of crypto.createDecipher() derives keys using the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt.
You passed what is actually a key as a password; this results in nodejs using a key that is completely different from the one used in Java and thus getting completely wrong results. You should instead use createDecipheriv which does take the key, and IV (Initialization Vector).
And that is your other problem. To decrypt you must use the same IV as encrypt did, normally by including the IV with the ciphertext sent from the sender to receiver, but you don't. As a result the following (simplified) code cannot decrypt the first 16 bytes of your data, but does the rest.
const crypto = require('crypto');
msg = Buffer.from('SfosHg+cTrQXYUdF0FuqCJMHgfcP13ckp2L0B9QqOcl8UtWnnl8fLi5lxgR2SKOj','base64');
aeskey = Buffer.from('JUtwW8+qU6Mv/FcgbMbkOdOKy72pun4B490KQrRB4QQ=','base64');
dec = crypto.createDecipheriv('aes-256-cbc',aeskey,Buffer.alloc(16)/*this should be the IV*/);
console.log(dec.update(msg,'','latin1')+dec.final('latin1'));
// I used latin1 instead of utf8 because the garbaged first block
// isn't valid UTF-8, and the rest is ASCII which works as either.
->
Y;øï«*M2WÚâeage to be encrypted
// some garbaged chars are control chars and Stack (or browser?)
// may not display them but there really are 16 in total
As an aside, the statement in the doc that 'Initialization vectors [must] be unpredictable and unique ... [but not secret]' is correct for CBC mode, but not some other modes supported by OpenSSL (thus nodejs) and Java. However, that's not a programming Q and thus offtopic here; it belongs on crypto.SX or possibly security.SX where it has already been answered many times.

AES-256-CBC encrypted with PHP and decrypt in Java

I am in a situation where a JSON is encrypted in PHP's openssl_encrypt and needs to be decrypted in JAVA.
$encrypted = "...ENCRYPTED DATA...";
$secretFile = "/path/to/secret/saved/in/text_file";
$secret = base64_decode(file_get_contents($secretFile));
var_dump(strlen($secret)); // prints : int(370)
$iv = substr($encrypted, 0, 16);
$data = substr($encrypted, 16);
$decrypted = openssl_decrypt($data, "aes-256-cbc", $secret, null, $iv);
This $decrypted has correct data which is now decrypted.
Now, the problem is when I try to do same things in Java it doesn't work :(
String path = "/path/to/secret/saved/in/text";
String payload = "...ENCRYPTED DATA...";
StringBuilder output = new StringBuilder();
String iv = payload.substring(0, 16);
byte[] secret = Base64.getDecoder().decode(Files.readAllBytes(Paths.get(path)));
String data = payload.substring(16);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(secret, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(), 0, cipher.getBlockSize());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); // This line throws exception :
cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
Here it is:
Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 370 bytes
at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87)
at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:91)
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:591)
at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:346)
at javax.crypto.Cipher.init(Cipher.java:1394)
at javax.crypto.Cipher.init(Cipher.java:1327)
at com.sample.App.main(App.java:70)
I have already visited similar question like
AES-256 CBC encrypt in php and decrypt in Java or vice-versa
openssl_encrypt 256 CBC raw_data in java
Unable to exchange data encrypted with AES-256 between Java and PHP
and list continues.... but no luck there
btw, this is how encryption is done in PHP
$secretFile = "/path/to/secret/saved/in/text_file";
$secret = base64_decode(file_get_contents($secretFile));
$iv = bin2hex(openssl_random_pseudo_bytes(8));
$enc = openssl_encrypt($plainText, "aes-256-cbc", $secret, false, $iv);
return $iv.$enc;
and yes, I forgot to mention that my JRE is already at UnlimitedJCEPolicy and I can't change PHP code.
I am totally stuck at this point and can't move forward. Please help out.
EDIT#1
byte[] payload = ....;
byte[] iv = ....;
byte[] secret = ....; // Now 370 bits
byte[] data = Base64.getDecoder().decode(payload);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOfRange(secret, 0, 32), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv, 0, cipher.getBlockSize());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] output = cipher.doFinal(data);
System.out.println(new String(output).trim());
Above snippet seems to be working with openssl_encrypt
EDIT#2
I am not sure if this is correct, but following is what I have done and encryption-decryption on both side are working fine.
Encrypt in PHP, Decrypt in JAVA use AES/CBC/NoPadding
Encrypt in JAVA, Decrypt in PHP use AES/CBC/PKCS5Padding
I won't provide a complete solution, but there are a few differences you should take care of
Encoding:
String iv = payload.substring(0, 16);
String data = payload.substring(16);
are you sure the IV and data are the same in Java and PHP (The IV is string?)? If the data are encrypted, they should be treated as a byte array, not string. Just REALLY make sure they are THE SAME (print hex/base64 in php and java)
For the IV you at the end call iv.getBytes(), but the locale encoding may/will corrupt your values. The String should be use only when it's really string (text). Don't use string for binaries.
Simply treat data and iv as byte[]
Key generation according to the openssl
AES key must have length of 256 bit for aes-256-cbc used. The thing is - openssl by default doesn't use the provided secret as a key (I believe it can, but I don't know how it is to be specified in PHP).
see OpenSSL EVP_BytesToKey issue in Java
and here is the EVP_BytesToKey implementation: https://olabini.com/blog/tag/evp_bytestokey/
you should generate a 256 bit key usging the EVP_BytesToKey function (it's a key derivation function used by openssl).
Edit:
Maarten (in the comments) is right. The key parameter is the key. Seems the PHP function is accepting parameter of any length which is misleading. According to some articles (e.g. http://thefsb.tumblr.com/post/110749271235/using-opensslendecrypt-in-php-instead-of) the key is trucated or padded to necessary length (so seems 370 bit key is truncated to length of 256 bits).
According to your example, I wrote fully working code for PHP and Java:
AesCipher class: https://gist.github.com/demisang/716250080d77a7f65e66f4e813e5a636
Notes:
-By default algo is AES-128-CBC.
-By default init vector is 16 bytes.
-Encoded result = base64(initVector + aes crypt).
-Encoded/Decoded results present as itself object, it gets more helpful and get possibility to check error, get error message and get init vector value after encode/decode operations.
PHP:
$secretKey = '26kozQaKwRuNJ24t';
$text = 'Some text'
$encrypted = AesCipher::encrypt($secretKey, $text);
$decrypted = AesCipher::decrypt($secretKey, $encrypted);
$encrypted->hasError(); // TRUE if operation failed, FALSE otherwise
$encrypted->getData(); // Encoded/Decoded result
$encrypted->getInitVector(); // Get used (random if encode) init vector
// $decrypted->* has identical methods
JAVA:
String secretKey = "26kozQaKwRuNJ24t";
String text = "Some text";
AesCipher encrypted = AesCipher.encrypt(secretKey, text);
AesCipher decrypted = AesCipher.decrypt(secretKey, encrypted);
encrypted.hasError(); // TRUE if operation failed, FALSE otherwise
encrypted.getData(); // Encoded/Decoded result
encrypted.getInitVector(); // Get used (random if encode) init vector
// decrypted.* has identical methods

Decrypt AES/CBC/PKCS5Padding with CryptoJS

I generate 128bit AES/CBC/PKCS5Padding key using Java javax.crypto API. Here is the algorithm that I use:
public static String encryptAES(String data, String secretKey) {
try {
byte[] secretKeys = Hashing.sha1().hashString(secretKey, Charsets.UTF_8)
.toString().substring(0, 16)
.getBytes(Charsets.UTF_8);
final SecretKey secret = new SecretKeySpec(secretKeys, "AES");
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
final AlgorithmParameters params = cipher.getParameters();
final byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
final byte[] cipherText = cipher.doFinal(data.getBytes(Charsets.UTF_8));
return DatatypeConverter.printHexBinary(iv) + DatatypeConverter.printHexBinary(cipherText);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
public static String decryptAES(String data, String secretKey) {
try {
byte[] secretKeys = Hashing.sha1().hashString(secretKey, Charsets.UTF_8)
.toString().substring(0, 16)
.getBytes(Charsets.UTF_8);
// grab first 16 bytes - that's the IV
String hexedIv = data.substring(0, 32);
// grab everything else - that's the cipher-text (encrypted message)
String hexedCipherText = data.substring(32);
byte[] iv = DatatypeConverter.parseHexBinary(hexedIv);
byte[] cipherText = DatatypeConverter.parseHexBinary(hexedCipherText);
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKeys, "AES"), new IvParameterSpec(iv));
return new String(cipher.doFinal(cipherText), Charsets.UTF_8);
} catch (BadPaddingException e) {
throw new IllegalArgumentException("Secret key is invalid");
}catch (Exception e) {
throw Throwables.propagate(e);
}
}
I can easily encrypt and decrypt messages using secretKey with these methods. Since Java has 128bit AES encryption by default, it generates a hash of the original secret key with SHA1 and takes the first 16-bytes of the hash to use it as secret key in AES. Then it dumps the IV and cipherText in HEX format.
For example encryptAES("test", "test") generates CB5E759CE5FEAFEFCC9BABBFD84DC80C0291ED4917CF1402FF03B8E12716E44C and I want to decrypt this key with CryptoJS.
Here is my attempt:
var str = 'CB5E759CE5FEAFEFCC9BABBFD84DC80C0291ED4917CF1402FF03B8E12716E44C';
CryptJS.AES.decrypt(
CryptJS.enc.Hex.parse(str.substring(32)),
CryptJS.SHA1("test").toString().substring(0,16),
{
iv: CryptJS.enc.Hex.parse(str.substring(0,32)),
mode: CryptJS.mode.CBC,
formatter: CryptJS.enc.Hex,
blockSize: 16,
padding: CryptJS.pad.Pkcs7
}).toString()
However it returns an empty string.
The problem is that you're using a 64 bit key as a 128 bit. Hashing.sha1().hashString(secretKey, Charsets.UTF_8) is an instance of HashCode and its toString method is described as such:
Returns a string containing each byte of asBytes(), in order, as a two-digit unsigned hexadecimal number in lower case.
It is a Hex-encoded string. If you take only 16 characters of that string and use it as a key, you only have 64 bits of entropy and not 128 bits. You really should be using HashCode#asBytes() directly.
Anyway, the problem with the CryptoJS code is manyfold:
The ciphertext must be a CipherParams object, but it is enough if it contains the ciphertext bytes as a WordArray in the ciphertext property.
The key must be passed in as a WordArray instead of a string. Otherwise, an OpenSSL-compatible (EVP_BytesToKey) key derivation function is used to derive the key and IV from the string (assumed to be a password).
Additional options are either unnecessary, because they are defaults, or they are wrong, because the blockSize is calculated in words and not bytes.
Here is CryptoJS code that is compatible with your broken Java code:
var str = 'CB5E759CE5FEAFEFCC9BABBFD84DC80C0291ED4917CF1402FF03B8E12716E44C';
console.log("Result: " + CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse(str.substring(32))
}, CryptoJS.enc.Utf8.parse(CryptoJS.SHA1("test").toString().substring(0,16)),
{
iv: CryptoJS.enc.Hex.parse(str.substring(0,32)),
}).toString(CryptoJS.enc.Utf8))
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/sha1.js"></script>
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Here is CryptoJS code that is compatible with the fixed Java code:
var str = 'F6A5230232062D2F0BDC2080021E997C6D07A733004287544C9DDE7708975525';
console.log("Result: " + CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse(str.substring(32))
}, CryptoJS.enc.Hex.parse(CryptoJS.SHA1("test").toString().substring(0,32)),
{
iv: CryptoJS.enc.Hex.parse(str.substring(0,32)),
}).toString(CryptoJS.enc.Utf8))
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/sha1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
The equivalent encryption code in CryptoJS would look like this:
function encrypt(plaintext, password){
var iv = CryptoJS.lib.WordArray.random(128/8);
var key = CryptoJS.enc.Hex.parse(CryptoJS.SHA1(password).toString().substring(0,32));
var ct = CryptoJS.AES.encrypt(plaintext, key, { iv: iv });
return iv.concat(ct.ciphertext).toString();
}
console.log("ct: " + encrypt("plaintext", "test"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/sha1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
This one perfectly worked for me
import * as CryptoJS from 'crypto-js';
const SECRET_CREDIT_CARD_KEY = '1231231231231231' // 16 digits key
decrypt(cipherText) {
const iv = CryptoJS.enc.Hex.parse(this.SECRET_CREDIT_CARD_KEY);
const key = CryptoJS.enc.Utf8.parse(this.SECRET_CREDIT_CARD_KEY);
const result = CryptoJS.AES.decrypt(cipherText, key,
{
iv,
mode: CryptoJS.mode.ECB,
}
)
const final = result.toString(CryptoJS.enc.Utf8)
return final
}
console.log(decrypt('your encrypted text'))
using this library in Angular 8
https://www.npmjs.com/package/crypto-js

Java to JS and JS to Java encryption using cryptojs

I got on this post a couple of weeks ago and worked perfectly:
Compatible AES algorithm for Java and Javascript
Now, I need to do the reverse operation, but once in java, I am getting this exception:
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:2165)
This is my "reverse" operation I did in JavaScript:
var rkEncryptionKey = CryptoJS.enc.Base64.parse('u/Gu5posvwDsXUnV5Zaq4g==');
var rkEncryptionIv = CryptoJS.enc.Base64.parse('5D9r9ZVzEYYgha93/aUK2w==');
function encryptString(stringToEncrypt) {
var utf8Stringified = CryptoJS.enc.Utf8.parse(stringToEncrypt);
var encrypted = CryptoJS.AES.encrypt(utf8Stringified.toString(), rkEncryptionKey, {mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: rkEncryptionIv});
return CryptoJS.enc.Base64.parse(encrypted.toString()).toString();
}
I though this would be all?
[EDIT]
Encrypted string is the following: {"company_name":"asdfasdfasd","customer_name":"asdfasdfasdfasdf","phone_number":"asdfasdfasdfasdf","email":"asdfasdfasdfasdfads"}
When doing the encrypt / decrypt from java to java it works, when doing so from java to javascript, also works, but from javascript to java, not working.
Java Code
public String toJson(final String encrypted) {
try {
SecretKey key = new SecretKeySpec(Base64.decodeBase64("u/Gu5posvwDsXUnV5Zaq4g=="), "AES");
AlgorithmParameterSpec iv = new IvParameterSpec(Base64.decodeBase64("5D9r9ZVzEYYgha93/aUK2w=="));
byte[] decodeBase64 = Base64.decodeBase64(encrypted);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
return new String(cipher.doFinal(decodeBase64), "UTF-8");
} catch (Exception e) {
throw new RuntimeException("This should not happen in production.", e);
}
}
Change
return CryptoJS.enc.Base64.parse(encrypted.toString()).toString();
to
return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
The encrypted object usually stringifies into an OpenSSL format which might also contain the salt. If you're only interested in the actual ciphertext, then you need to stringify the ciphertext property.
Note that toString() takes an optional encoding function. Use the one that you need.

How to generate secret key in Java once and use that key in 2 different programs

My aim is to write a Java program to encrypt a text file (cipher text) using AES algorithm. And then, write another program to decrypt that encrypted file (cipher text) to get the plain text back. I want to use same key (same key, generate once, save it somewhere, and use it in both encryption and decryption program) for encryption and decryption process. If I generate key and do the encryption and decryption line by line in the same program then it works perfectly. Here is the working code snippet for that:
String strDataToEncrypt = new String();
String strCipherText = new String();
String strDecryptedText = new String();
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey secretKey = keyGen.generateKey();
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE,secretKey);
strDataToEncrypt = "any text input";
byte[] byteDataToEncrypt = strDataToEncrypt.getBytes();
byte[] byteCipherText = aesCipher.doFinal(byteDataToEncrypt);
strCipherText = new BASE64Encoder().encode(byteCipherText);
System.out.println("cipher text: " +strCipherText);
aesCipher.init(Cipher.DECRYPT_MODE,secretKey,aesCipher.getParameters());
byte[] byteDecryptedText = aesCipher.doFinal(new BASE64Decoder().decodeBuffer(strCipherText));
strDecryptedText = new String(byteDecryptedText);
System.out.println("plain text again: " +strDecryptedText);
But, I need to have two different programs (java files) for encryption and decryption. So, I have to somehow generate a key and save that somewhere. Then use the same key for both encryption and decryption program. How can I do that?
EDIT_1
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey secretKey = keyGen.generateKey();
byte[] encoded = secretKey.getEncoded();
System.out.println("key: "+encoded);// key: [B#52b2a2d8
I can get the encoded key value using the above program. But my question is how to generate the SecretKey using this value in my decryption program?
Forgive me if I misunderstood your question but I believe you wish to reconstruct a SecretKey object from a existing key encoded in a byte array.
This can be performed simply by using the javax.crypto.spec.SecretKeySpec's constructor as such:
byte[] encoded = //Key data
SecretKey secretKey = new SecretKeySpec(encoded, "AES");
Since SecretKeySpec is a subclass of SecretKey no casting is needed. Should your encryption/decrption algorithm change please make sure to change the string literal used in the constructor AES to whatever algorithm you decided to use in the future.
Here's one way to print out the values in a byte[] array in hex:
byte[] a = {-120, 17, 42,121};
for (byte b : a)
{
System.out.printf("%2X",b);
}
System.out.println();

Categories

Resources