I'm trying to encrypt a message in javascript (using crypto-js library) and to decrypt it in java.
This is the javascript code:
var key = CryptoJS.enc.Utf8.parse(aesPassword);
var ive = CryptoJS.enc.Utf8.parse(aesIv);
var encryptedData = CryptoJS.AES.encrypt(dataToEncrypt, key, {mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: ive});
And this is the java code:
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final SecretKeySpec key = new SecretKeySpec(aesPassword().getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(aesIv().getBytes("UTF-8")));
byte[] decrypted = cipher.doFinal(DatatypeConverter.parseBase64Binary(message));
But when I try to decrypt in Java this exception is thrown:
javax.crypto.BadPaddingException: Given final block not properly padded
password: 6h2faBePVxpgyFSN
iv: NKOzRKrmEMKs1kE4
data to encrypt: "{token: cMGOIrYlJm9lPhPW}"
Any help?
Thanks in advance
I may be wrong, but I think BadPaddingException in this case means that you don't possess the correct key to successfully perform the decryption.The exception essentially means that the key is either too short or too long (I think).
Try{
String decrypted = aes.decrypt(...);
System.out.println(decryted);
}catch(Exception e){
}
Something like the code above may work, as System.out is only reached when the BadPaddingException isn't caught, this could be used in a loop when trying possible keys for decryption, for example, if you were trying to calculate all possible keys for the decryption.
Related
I'm attempting to encrypt a message using Javascript's CryptoJS like so:
const encrypted_payload = CryptoJS.AES.encrypt("Hello, world!", "magickey");
console.log(enrypted_payload.toString());
... and then decrypt using Rust's Magic Crypt Library, like so:
#[macro_use] extern crate magic_crypt;
use magic_crypt::MagicCryptTrait;
fn main() {
let message = r#"U2FsdGVkX1+anrxRX8UNTJ8ur9LIf6n2YcmbmDqPSls="#;
let mc = new_magic_crypt!("magickey", 256);
let result = mc.decrypt_base64_to_string(&message)
.expect("Could not decrypt base64 to string");
println!("{}", result)
}
The Cargo.toml file for Rust includes:
[dependencies]
magic-crypt = "3.1.6"
This fails to compile. The error statement is DecryptError(BlockModeError).
If in CryptoJS the key is passed as a string, then it is interpreted as a password and the key/IV is derived using a special derivation function (EVP_BytesToKey). To process the key directly as a key, it must be passed as a WordArray.
In the Rust code the passwords seem to be simply hashed (e.g. MD5 for AES-128, SHA256 for AES-256), which is surprisingly insecure (though I'm not a Rust expert and may be overlooking something).
Anyway this results in incompatible keys. One possibility is to use the hash of the Rust key as WordArray in CryptoJS:
Example: From the magic_crypt documentation, here:
use magic_crypt::MagicCryptTrait;
let mc = new_magic_crypt!("magickey", 256);
let base64 = mc.encrypt_str_to_base64("http://magiclen.org");
assert_eq!("DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=", base64);
assert_eq!("http://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap());
magic_crypt internally derives a 32 bytes key as SHA256 hash from the password. Then the encryption with CryptoJS is:
var key = CryptoJS.SHA256("magickey");
var ciphertext = "DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=";
var iv = CryptoJS.enc.Base64.parse("AAAAAAAAAAAAAAAAAAAAAA==")
var decrypted = CryptoJS.AES.decrypt(ciphertext, key, {iv: iv});
console.log(decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
Both codes apply CBC mode with a zero IV and PKCS7 padding. Note that a static IV is insecure and should only be used for testings.
The other direction is analogous, e.g. encryption with CryptoJS generates the ciphertext from the Rust example (assuming the same key, IV and plaintext):
var key = CryptoJS.SHA256("magickey");
var plaintext = "http://magiclen.org";
var iv = CryptoJS.enc.Base64.parse("AAAAAAAAAAAAAAAAAAAAAA==")
var ciphertext = CryptoJS.AES.encrypt(plaintext, key, {iv: iv});
console.log(ciphertext.toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
I'm trying to decrypt a C# encrypt string using javascript,
This is an example of the encryption on my server side
public class AesCrypt
{
public static string IV = #"!QAZ2WSX#EDC4RFV";
public static string Key = #"5TGB&YHN7UJM(IK<5TGB&YHN7UJM(IK<";
public static string Encrypt(string dectypted)
{
byte[] textbytes = ASCIIEncoding.ASCII.GetBytes(dectypted);
AesCryptoServiceProvider encdec = new AesCryptoServiceProvider();
encdec.BlockSize = 128;
encdec.KeySize = 256;
encdec.Key = ASCIIEncoding.ASCII.GetBytes(Key);
encdec.IV = ASCIIEncoding.ASCII.GetBytes(IV);
encdec.Padding = PaddingMode.PKCS7;
encdec.Mode = CipherMode.CBC;
ICryptoTransform icrypt = encdec.CreateEncryptor(encdec.Key, encdec.IV);
byte[] enc = icrypt.TransformFinalBlock(textbytes, 0, textbytes.Length);
icrypt.Dispose();
return Convert.ToBase64String(enc);
}
}
The encryption of "Hello World" is "1i4zI5rB3Df2CYFalsiTwg=="
Now I'm trying to decrypt it using js on my client and get Hello World and this is where I fail,
I'm using <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script> in order to decrypt and I watch some of examples over the web (including stackoverflow).
Accoring to some examples over the web this is what I came out of, but it's not returning "Hello World" back.
data = "1i4zI5rB3Df2CYFalsiTwg==";
key = "5TGB&YHN7UJM(IK<5TGB&YHN7UJM(IK<";
iv = "!QAZ2WSX#EDC4RFV";
CryptoJS.AES.decrypt(atob(data), key, {
iv: atob(iv),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
I'm using the same mode and padding, but I'm probably missing something.
I'm not that familiar with CryptoJS and I hope someone can help me understand where I went wrong.
Thanks in advance
From the old CryptoJS pages, the Cipher input part:
For the key, when you pass a string, it's treated as a passphrase and used to derive an actual key and IV. Or you can pass a WordArray that represents the actual key. If you pass the actual key, you must also pass the actual IV.
Although you are passing an IV, you do currently put in a string rather than a binary key as word array. I suppose this is the problem as I don't see any other obvious programming mistakes.
Im trying to convert the java library - AESCrypt-Java
to javascript.
This is my implementation so far for the decrypt function. Im not able to decrypt the text. Can someone figure out where I'm going wrong?
function decrypt(password, base64text) {
key = generateKey(password);
var decodedCipherText = new Buffer(base64text, 'base64')
var iv = new Buffer(16);
iv.fill(0);
var decipher = crypto.createDecipheriv("aes-256-cbc", key, iv)
let decrypted = decipher.update(decodedCipherText, 'base64', 'utf-8');
decrypted += decipher.final('utf-8')
return decryptedBytes
}
function generateKey(password) {
return crypto.createHash('sha256').update(usr_id).digest();
}
var encryptedText = '1+2yFMDH1C/uIc1huwezbrsQ==';
var password = '8AVrWtyabQ';
decrypt(password, encryptedText)
The expected plaintext output is Wordpress.
You are making a few decisions that will adversely affect the security of your sensitive values:
You are using a static, all-zero IV. The IV must be unique and non-predictable for every message encrypted with a specific key. The IV can then be prepended to the cipher text and transmitted unprotected to the recipient, where it is sliced and used for decryption.
Your key derivation function (KDF) is weak -- SHA-256 can be cracked at 23 billion attempts per second on commodity hardware. Use a key-stretching algorithm like PBKDF2 with a high iteration count, or bcrypt or scrypt for memory hardness.
Your cipher text is not authenticated -- AES/CBC provides confidentiality, but not integrity or authentication. An interceptor can manipulate the cipher text in transmission and attempt to decrypt it. This can result in unauthorized decryption (i.e. injecting malicious plaintext into your application) or a padding oracle attack, and eventually cipher text recovery. Use an authenticated encryption (with associated data) (AE or AEAD) cipher mode to mitigate this, or add a strong HMAC construction using a separate key over the cipher text and verify prior to decryption with a constant-time equals method.
new Buffer(string, encoding) and new Buffer(size) are deprecated and Buffer.from(string, encoding) and Buffer.alloc(size) should be used instead. You create a Buffer containing the provided cipher text which is encoded in Base64. I have a feeling there is an issue occurring with your encoding (you don't provide any example output for us to see). Here is an example of encrypting and decrypting with Buffer objects.
function encrypt(buffer){
var cipher = crypto.createCipher(algorithm,password)
var crypted = Buffer.concat([cipher.update(buffer),cipher.final()]);
return crypted;
}
function decrypt(buffer){
var decipher = crypto.createDecipher(algorithm,password)
var dec = Buffer.concat([decipher.update(buffer) , decipher.final()]);
return dec;
}
var hw = encrypt(new Buffer("hello world", "utf8"))
// outputs hello world
console.log(decrypt(hw).toString('utf8'));
As you can see, cipher.update(buffer) handles the encoding internally so you don't need to.
Here is my solution to PHP, Ruby & Swift.
I faced issues when using CryptoJS on my test.
my code is like this
var data = "Hello World";
var key = "57119C07F45756AF6E81E662BE2CCE62";
var iv = "GsCJsm/uyxG7rBTgBMrSiA==";
var encryptedData = CryptoJS.AES.encrypt(data,
CryptoJS.enc.Hex.parse(key), {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: CryptoJS.enc.Base64.parse(iv)
}
);
console.log("encryptedData: " + encryptedData);
// var crypttext = encryptedData.toString();
var crypttext = "k4wX2Q9GHU4eU8Tf9pDu+w==";
var decryptedData = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(crypttext)
}, CryptoJS.enc.Hex.parse(key), {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: CryptoJS.enc.Base64.parse(iv)
});
console.log("decryptedData: " + decryptedData);
console.log result
encryptedData: 97SwKfGtNARERiSYyZxdAQ==
decryptedData:
I've looked at your PHP code. You're using a 32 character key which is obviously Hex-encoded, but instead of decoding it to bytes, you're using the characters directly. Therefore the aes-256-cbc cipher is also wrong.
If you don't want to change your misleading PHP code, you can simply make the same mistake in CryptoJS: CryptoJS.enc.Utf8.parse(key) instead of CryptoJS.enc.Hex.parse(key).
Security considerations:
The IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.
It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.
I would like to AES encode in Delphi XE4 and decode in JavaScript.
My Delphi code:
(I use DCPcrypt Cryptographic Component Library v2 Beta 3)
procedure TForm1.Button5Click(Sender: TObject);
var
Cipher : TDCP_rijndael;
key: Ansistring;
data: Ansistring;
iv: Ansistring;
begin
Key := SHA256('password');
IV := 'cd6f6eea9a2a59f2';
Data := '12345678901234567890';
Cipher := TDCP_rijndael.Create(Self);
if Length(Key) <= 16 then
Cipher.Init(Key[1], 128, #IV[1])
else
if Length(Key) <= 24 then
Cipher.Init(Key[1], 192, #IV[1])
else
Cipher.Init(Key[1], 256, #IV[1]);
Cipher.EncryptCBC(Data[1],Data[1],Length(Data));
memo1.Lines.Add('DATA_ENC:'+DATA);
memo1.Lines.Add('DATA_BASE64_ENC: '+Base64encode(DATA));
end;
My JavaScript code (I use CryptoJS):
encypted = 'Pz8/yw0/ck+4tTY/Pn8zPz/f9D8='; //input base64 text from Delphi routine
var key = CryptoJS.SHA256(CryptoJS.enc.Base64.parse("password"));
var iv = CryptoJS.enc.Base64.parse('cd6f6eea9a2a59f2');
var decrypted = CryptoJS.AES.decrypt(encrypted,key,
keySize: 256,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
console.log('DECRYPTED: '+decrypted.toString(CryptoJS.enc.Utf8));
I do not get back the original text, please help me. What is the matter?
I have no idea about Delphi, so I can't help you there, but I can say, that your Delphi code is wrong, because if you parse the Base64 ciphertext and encode it as Hex, you will see this:
3f3f3fcb0d3f724fb8b5363f3e7f333f3fdff43f
A ciphertext of a modern cipher is supposed to be indistinguishable from random noise, but this ciphertext looks rather regular (there are a lot of 0x3f bytes).
Your JavaScript code is rather all over the place. Almost every string that you use, has a wrong encoding.
run.onclick = function(){
var encrypted = CryptoJS.enc.Base64.parse(inVal.value);
var key = CryptoJS.SHA256(CryptoJS.enc.Utf8.parse("password"));
var iv = CryptoJS.enc.Utf8.parse('cd6f6eea9a2a59f2');
var decrypted = CryptoJS.AES.decrypt({
ciphertext: encrypted
}, key, {
iv: iv,
padding: CryptoJS.pad.ZeroPadding
});
outHex.innerHTML = decrypted.toString();
outUtf8.innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
};
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/sha256.js"></script>
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/components/pad-zeropadding-min.js"></script>
<div>Base64 input: <input id="inVal" value="Pz8/yw0/ck+4tTY/Pn8zPz/f9D8="></div>
<div>Decrypted Hex: <span id="outHex">-</span></div>
<div>Decrypted Utf8: <span id="outUtf8">-</span></div>
<div><button id="run">Decrypt</button></div>
When you have fixed your Delphi code, you can include the Base64 in the above runnable snippet and see that decrypts correctly.
Security considerations:
You need to use a random IV, if you're sending multiple ciphertexts with the same key. If you send the same message again, an attacker can see that only by observing ciphertexts. The IV doesn't have to be secret, so you can send it along with the ciphertext. A common way is to prepend it to the ciphertext and remove it before decryption.
SHA-256 is not sufficient for key derivation from a low-entropy password. You should use an iterated key derivation function (KDF) such as PBKDF2, bcrypt, scrypt or Argon2. See more: How to securely hash passwords?
It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.