AES encryption with Javascript using cryptojs same as Java - AES/CBC/PKCS5Padding - javascript

I am using AES encryption in Java and want to do same in Javascript/Typescript using cryptojs.
I am trying below Javascript code but both are returning different results.
Java Code
String sKey = 'MySecureKeyText1';
String _text = "ValuetoEncrypt";
byte key[] = sKey.getBytes("UTF-8");
KeySpec aKeySpec = new SecretKeySpec(key, "AES");
MessageDigest hashMD5 = MessageDigest.getInstance("MD5");
hashMD5.update(sKey.getBytes("UTF-8"));
byte[] ivbytes = hashMD5.digest();
IvParameterSpec IV = new IvParameterSpec(ivbytes, 0, ivbytes.length);
Cipher mCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
mCipher.init(Cipher.ENCRYPT_MODE, (Key) aKeySpec, IV);
string ciphertext = mCipher.doFinal(_text.getBytes());
ciphertext = ByteToHex(ciphertext); // .CAAFD9C519C23E91A4B58D158ECA5462
JavaScript Code
this.encrypt('ValuetoEncrypt', 'MySecureKeyText1');
encrypt(value : string, key:string) : string{
let ivHash = cryptoJS.MD5(key).toString();
let cipher = this.cipher(value, key, ivHash);
return cipher.ciphertext.toString(); // 5a78aa6905208aa6fa63d1d452ea482e
}
cipher(value, key, iv) {
const cipher = cryptoJS.AES.encrypt(value, key, {
iv: iv,
mode: cryptoJS.mode.CBC,
keySize: 128,
padding: cryptoJS.pad.Pkcs7
});
return cipher;
}
Issue Resolved
Fixed this issue by converting key into byte array using cryptoJS.enc.Utf8.parse before passing for ecryption.
As per the crypto-js documentation if we pass key in string format then they use it to derive an actual key and iv, If we pass in word array then it will use actual value we sent.
this.encrypt('ValuetoEncrypt', 'MySecureKeyText1');
encrypt(value: string, key: string): string {
const ivMd5Hash = cryptoJS.MD5(cryptoJS.enc.Utf8.parse(key));
const cipher = this.cipher(cryptoJS.enc.Utf8.parse(value), cryptoJS.enc.Utf8.parse(key), ivMd5Hash);
return cipher.ciphertext.toString();
}
cipher(value, key, iv): any {
const cipher = cryptoJS.AES.encrypt(value, key, {
iv: iv,
mode: cryptoJS.mode.CBC,
keySize: 128,
padding: cryptoJS.pad.Pkcs7
});
return cipher;
}
Note:- It is better to use their default behaviour as it generates different key every time that will be more secure But in my case it was requirement to use fix format.

Related

CryptoJs decrypt function equivalent in Java

I'm trying to decrypt a token that the server I'm using brings in order to load correctly users access to the page.
I already achieved the goal using CryptoJs using JavaScript. However now I need to transfer that function to my java backend.
Look my code using CryptoJs which works correctly
const token = "U2FsdGVkX1+6YueVRKp6h0dZfk/a8AC9vyFfAjxD4nb7mXsKrM7rI7xZ0OgrF1sShHYNLMJglz4+67n/I7P+fg=="
const key = "p80a0811-47db-2c39-bcdd-4t3g5h2d5d1a"
// Decrypt
const iv = CryptoJS.enc.Utf8.parse(key);
const decryptedToken = CryptoJS.AES.decrypt(token, key, {
keySize: 16,
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
const stringToken = decryptedToken.toString(CryptoJS.enc.Utf8);
const dataToUse = JSON.parse(stringToken)
console.log("decryptedToken => ", stringToken);
console.log("data => ",dataToUse);
And this is my code in Java using javax.crypto
public String decrypt() {
String finalToken = null;
Cipher cipher;
try {
String token = "U2FsdGVkX1+6YueVRKp6h0dZfk/a8AC9vyFfAjxD4nb7mXsKrM7rI7xZ0OgrF1sShHYNLMJglz4+67n/I7P+fg==";
String key = "p80a0811-47db-2c39-bcdd-4t3g5h2d5d1a";
Key skeySpec = new SecretKeySpec(Arrays.copyOf(key.getBytes(), 16), "AES");
byte[] iv = Arrays.copyOf(key.getBytes(StandardCharsets.UTF_8), 16);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
byte[] bytesToDecrypt = Base64.decodeBase64(token.getBytes());
cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
byte[] decrypted = cipher.doFinal(bytesToDecrypt);
finalToken = new String(decrypted);
log.info("Decrypt token succesfully {}", finalToken);
} catch (NoSuchAlgorithmException
| InvalidAlgorithmParameterException
| IllegalBlockSizeException
| NoSuchPaddingException
| BadPaddingException
| InvalidKeyException e) {
e.printStackTrace();
log.error("Error decrypting");
}
return finalToken;
}
I'm not sure I'm setting correctly the key and the iv. With the piece of code above I get this error:
javax.crypto.BadPaddingException: pad block corrupted
If I don't "cut" the key and the iv in order to have 16 bytes I get wrong length error.
Can someone help me to figure out what's wrong please!
The expected result is to get this info in java so then I can manipulate the object:
{name: "Burak", surName: "Bayraktaroglu"}
Decryption fails because CryptoJS interprets the key material as password when passed as string (as in the posted code).
In this case, the password and a salt are used to derive the key and IV applying the OpenSSL proprietary key derivation function EVP_BytesToKey().
The random 8 bytes salt is generated during encryption, which returns as result the Base64 encoding of the concatenation of a prefix, the salt and the actual ciphertext. The prefix consists of the ASCII encoding of Salted__.
Therefore, the following steps are necessary in the decryption process:
Determining salt and ciphertext from the CryptoJS return value
Deriving key and IV using password and salt
Decryption of the ciphertext with the derived key and IV
There are several ways to implement the last two steps in Java.
You can find various ports of EVP_BytesToKey() on the web which can be used in conjunction with the native JCA/JCE for decryption. These EVP_BytesToKey() ports are not always reliable, a solid port is this one.
A convenient (and reliable) alternative is BouncyCastle (with its own EVP_BytesToKey() port), described below:
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.ParametersWithIV;
...
// Get salt and ciphertext
String saltCiphertextB64 = "U2FsdGVkX1+6YueVRKp6h0dZfk/a8AC9vyFfAjxD4nb7mXsKrM7rI7xZ0OgrF1sShHYNLMJglz4+67n/I7P+fg==";
byte[] saltCiphertext = Base64.getDecoder().decode(saltCiphertextB64);
ByteBuffer byteBuffer = ByteBuffer.wrap(saltCiphertext);
byte[] prefix = new byte[8];
byte[] salt = new byte[8];
byteBuffer.get(prefix);
byteBuffer.get(salt);
byte[] ciphertext = new byte[byteBuffer.remaining()];
byteBuffer.get(ciphertext);
// Key derivation via EVP_BytesToKey() (using BouncyCastle)
String passwordStr = "p80a0811-47db-2c39-bcdd-4t3g5h2d5d1a";
byte[] password = passwordStr.getBytes(StandardCharsets.UTF_8);
OpenSSLPBEParametersGenerator pbeGenerator = new OpenSSLPBEParametersGenerator(new MD5Digest());
pbeGenerator.init(password, salt);
ParametersWithIV parameters = (ParametersWithIV) pbeGenerator.generateDerivedParameters(256, 128); // keySize, ivSize in bits
// FYI: key: ((KeyParameter)parameters.getParameters()).getKey()
// IV : parameters.getIV()
// Decryption (using BouncyCastle)
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
cipher.init(false, parameters);
byte[] plaintext = new byte[cipher.getOutputSize(ciphertext.length)];
int length = cipher.processBytes(ciphertext, 0, ciphertext.length, plaintext, 0);
length += cipher.doFinal(plaintext, length);
String plaintextSr = new String(plaintext, 0, length, StandardCharsets.UTF_8);
System.out.println(plaintextSr); // {"name":"Burak","surName":"Bayraktaroglu"}

CryptoJS encrypt in aes-256-cbc returns an unexpected value

I am encrypting some data using CryptoJS and comparing it to an online tool and I am not getting the same result. In fact the result from CryptoJS in not decryptable with the tool.
I am trying to encrypt in AES-256-CBC with the following parameters:
text = '111222333'
iv = 'I8zyA4lVhMCaJ5Kg'
key = '6fa979f20126cb08aa645a8f495f6d85'
Here's my code:
let text = '111222333';
aesEncrypt(data) {
let key = '6fa979f20126cb08aa645a8f495f6d85'; //length 32
let iv = 'I8zyA4lVhMCaJ5Kg'; //length 16
let cipher = CryptoJS.AES.encrypt(data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return cipher.toString();
}
aesEncrypt(text);
The resulting encrypted string is U2FsdGVkX1+f3UywYmIdtb50bzdxASRCSqB00OijOb0= while the one obtained with the online tool is B6AeMHPHkEe7/KHsZ6TW/Q==. Why are they different, I seem to be using the same parameters?
My plan in using CryptoJS is to encrypt some data client side and then be able to decrypt it server side, if needed. But the differences in both encrypted values is stopping me to do so.
How 'bout encoding your data as UTF-8. Just like the "online tool" is doing.
Use CryptoJS.enc.Utf8.parse to achieve what I'm saying.
aesEncrypt (data) {
const key = '6fa979f20126cb08aa645a8f495f6d85'
const iv = 'I8zyA4lVhMCaJ5Kg'
const cipher = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv), // parse the IV
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
})
// e.g. B6AeMHPHkEe7/KHsZ6TW/Q==
return cipher.toString()
}
Code snippet using CryptoJS.
function aesEncrypt (data) {
const key = '6fa979f20126cb08aa645a8f495f6d85'
const iv = 'I8zyA4lVhMCaJ5Kg'
const cipher = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv),
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
})
return cipher.toString()
}
// e.g. B6AeMHPHkEe7/KHsZ6TW/Q==
console.log(aesEncrypt('111222333'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
Working Stackblitz example
Based on WeeGee's answer, added this function aesDecrypt in order to decrypt back the encrypted text and return the string in UTF8. #WeeGee you saved my day.
const key = CryptoJS.enc.Utf8.parse('6fa979f20126cb08aa645a8f495f6d85');
const iv = CryptoJS.enc.Utf8.parse('I8zyA4lVhMCaJ5Kg');
const text = '111222333';
function aesEncrypt(data) {
let cipher = CryptoJS.AES.encrypt(data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return cipher.toString();
}
function aesDecrypt(data) {
let cipher = CryptoJS.AES.decrypt(data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return cipher.toString(CryptoJS.enc.Utf8);
}
const encryptedText = aesEncrypt(text);
const decryptedText = aesDecrypt(encryptedText);
console.log('Before Encrypt - ' + text);
console.log('Encrypted Text - ' + encryptedText);
console.log('Decrypted Text - ' + decryptedText);
Output
Before Encrypt - 111222333
Encrypted Text - B6AeMHPHkEe7/KHsZ6TW/Q==
Decrypted Text - 111222333

Unable to decrypt message using Crypto-Js

I am new to encryption. What I am trying to do is decrypt a cipher text using javascript library, CryptoJS. This code example works fine. The encryption part returns ciphertext "ae06b481cecfa67c98c125" (which is right) while decrypting the same object returns the original string "Hello World".
var key = CryptoJS.enc.Latin1.parse("bad8deadcafef00d");
var iv = CryptoJS.enc.Latin1.parse("bad8deadcafef00d");
var encrypted = CryptoJS.AES.encrypt("Hello World", key, {iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
alert(encrypted.ciphertext);
var decryptedData = CryptoJS.AES.decrypt(encrypted, key, {iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
originalData = decryptedData.toString(CryptoJS.enc.Utf8);
alert(originalData);
Well this part works fine but when I try this chunk of code by passing the cipher text as a string independently, I don't get the decrypted message.
var key = CryptoJS.enc.Latin1.parse("bad8deadcafef00d");
var iv = CryptoJS.enc.Latin1.parse("bad8deadcafef00d");
var ciphertext = "ae06b481cecfa67c98c125";
// raw = CryptoJS.enc.Base64.parse(cipher);
var decryptedData = CryptoJS.AES.decrypt(ciphertext, key, {iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
originalData = decryptedData.toString(CryptoJS.enc.Utf8);
alert(originalData);
console.log(originalData);
Can somebody please point out why?
I have the following libraries included in the html file.
<script src="js/rollups/aes.js"></script>
<script src="js/components/mode-ctr.js"></script>
<script src="js/components/pad-nopadding.js"></script>
CryptoJS.AES.decrypt expects either a CipherParams object or an OpenSSL-formatted string. If the passed key is a string then the OpenSSL-formatted string is expected and otherwise the CipherParams object.
Since your key is not a string, you need this:
var decryptedData = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse("ae06b481cecfa67c98c125")
}, key, {
iv: iv,
mode: CryptoJS.mode.CTR,
padding: CryptoJS.pad.NoPadding
});
If the key is a string, then it isn't actually a key, but assumed to be a password and a key will be derived from that password with a random 8 byte salt. This would be comparable to OpenSSL's EVP_BytesToKey function.

Encrypt in javascript and decrypt in C# with AES algorithm

I tried to encrypt in angular using AES library from AES.
I encrypted the string using the CryptoJS.AES.encrypt() method from AES.
Here is my code:
var txtloginKod = 'Some String...';
var key = CryptoJS.enc.Utf8.parse('8080808080808080');
var iv = CryptoJS.enc.Utf8.parse('8080808080808080');
var encryptedlogin = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(txtloginKod), key,
{
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
The method CryptoJS.AES.encrypt() return a Object to my encryptedlogin variable.
I don't know how to send this object to my WCF Web server in C#
When I tried to send the whole object (and define the Web service method to expect get C# Object), I got the error below:
"Converting circular structure to JSON"
Using Dot net core and Type Script.
npm instal crypto-js
//Inside imports of your TS file include
import * as CryptoJS from 'crypto-js';
// Declare this key and iv values in declaration
private key = CryptoJS.enc.Utf8.parse('4512631236589784');
private iv = CryptoJS.enc.Utf8.parse('4512631236589784');
// Methods for the encrypt and decrypt Using AES
encryptUsingAES256() {
var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(JSON.stringify("Your Json Object data or string")), this.key, {
keySize: 128 / 8,
iv: this.iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log('Encrypted :' + encrypted);
this.decryptUsingAES256(encrypted);
return encrypted;
}
decryptUsingAES256(decString) {
var decrypted = CryptoJS.AES.decrypt(decString, this.key, {
keySize: 128 / 8,
iv: this.iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log('Decrypted : ' + decrypted);
console.log('utf8 = ' + decrypted.toString(CryptoJS.enc.Utf8));
}
The C# code to encode or decode is here.
public class encr {
public static string DecryptStringAES(string cipherText) {
var keybytes = Encoding.UTF8.GetBytes("4512631236589784");
var iv = Encoding.UTF8.GetBytes("4512631236589784");
var encrypted = Convert.FromBase64String(cipherText);
var decriptedFromJavascript = DecryptStringFromBytes(encrypted, keybytes, iv);
return decriptedFromJavascript;
}
private static string DecryptStringFromBytes(byte[] cipherText, byte[] key, byte[] iv) {
// Check arguments.
if (cipherText == null || cipherText.Length <= 0) {
throw new ArgumentNullException("cipherText");
}
if (key == null || key.Length <= 0) {
throw new ArgumentNullException("key");
}
if (iv == null || iv.Length <= 0) {
throw new ArgumentNullException("key");
}
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using(var rijAlg = new RijndaelManaged()) {
//Settings
rijAlg.Mode = CipherMode.CBC;
rijAlg.Padding = PaddingMode.PKCS7;
rijAlg.FeedbackSize = 128;
rijAlg.Key = key;
rijAlg.IV = iv;
// Create a decrytor to perform the stream transform.
var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
try {
// Create the streams used for decryption.
using(var msDecrypt = new MemoryStream(cipherText)) {
using(var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) {
using(var srDecrypt = new StreamReader(csDecrypt)) {
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
} catch {
plaintext = "keyError";
}
}
return plaintext;
}
public static string EncryptStringAES(string plainText) {
var keybytes = Encoding.UTF8.GetBytes("4512631236589784");
var iv = Encoding.UTF8.GetBytes("4512631236589784");
var encryoFromJavascript = EncryptStringToBytes(plainText, keybytes, iv);
return Convert.ToBase64String(encryoFromJavascript);
}
private static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv) {
// Check arguments.
if (plainText == null || plainText.Length <= 0) {
throw new ArgumentNullException("plainText");
}
if (key == null || key.Length <= 0) {
throw new ArgumentNullException("key");
}
if (iv == null || iv.Length <= 0) {
throw new ArgumentNullException("key");
}
byte[] encrypted;
// Create a RijndaelManaged object
// with the specified key and IV.
using(var rijAlg = new RijndaelManaged()) {
rijAlg.Mode = CipherMode.CBC;
rijAlg.Padding = PaddingMode.PKCS7;
rijAlg.FeedbackSize = 128;
rijAlg.Key = key;
rijAlg.IV = iv;
// Create a decrytor to perform the stream transform.
var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using(var msEncrypt = new MemoryStream()) {
using(var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
using(var swEncrypt = new StreamWriter(csEncrypt)) {
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
}
I too had the requirement to send encrypted JSON object to .Net CORE API 2.0 and searched on internet to find if there is any help. I know by now you would have solved this issue but to help anyone interested I am providing my solution to help them.
With the sample codes I found here on stackoverflow, I managed to implement the solution. The tricky bit is the key and IV has to be 16 in length for the code to work.
public static encrypt(model: any) {
const key = CryptoJS.enc.Utf8.parse('TestMyOwnKeyForI');
const iv = CryptoJS.enc.Utf8.parse('TestMyOwnIV1ForI');
// padding and truncating
const encryptedMessage = CryptoJS.AES.encrypt(JSON.stringify(model), key, {
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
return encryptedMessage;
}
In CORE I've implemented my customer model binding provider as follows:
public class DecryptModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(MyModel))
return new DecryptModelBinder();
return null;
}
}
Then my own decryptmodelbinder as follows:
public class DecryptModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
using (var sr = new StreamReader(bindingContext.HttpContext.Request.Body))
{
string valueFromBody = sr.ReadToEnd();
if (valueFromBody != null && valueFromBody.Length > 0)
{
var decrypted = Encryption.DecryptString(valueFromBody, "TestMyOwnKeyForI");
var model = JsonConvert.DeserializeObject(decrypted, bindingContext.ModelType);
bindingContext.Result = ModelBindingResult.Success(model);
bindingContext.Model = model;
}
}
return Task.CompletedTask;
}
}
You would need to serialize the ciphertext yourself. There are many ways to do it.
If the key is not a string, but a WordArray (as in your case), then a simple encryptedlogin.toString() would produce a Base64 encoded string only containing the ciphertext. Remember that you need to include the enc-base64.js source file.
If the "key" (actually password) is a string, then an OpenSSL-compatible key derivation is applied. In that case encryptedlogin.toString() would be a Base64 encoded string which contains the "Salted__" string, 8 byte random salt and the ciphertext.
If you only want to get the ciphertext then encryptedlogin.ciphertext.toString() will give you a Hex-encoded string which contains only the ciphertext and encryptedlogin.iv.toString() will give you a Hex-encoded IV. You can produce a Base64-encoded string in this way encryptedlogin.ciphertext.toString(CryptoJS.enc.Base64).
Remember that the IV must be randomly chosen for every encryption in order to provide semantic security. It doesn't have to be secret, so you can send it along with the ciphertext.
On the server side, you would decode the values (Base64 or Hex depending on what you used during encryption) and use them with the AesCryptoServiceProvider class (or similar) to decrypt the ciphertext.
Remember that you additionally need to authenticate your ciphertext in order to detect (malicious) manipulation. This can be done with an encrypt-then-MAC scheme with a strong MAC like HMAC-SHA256.
Also, if the key is transmitted along with the ciphertext or over an insecure channel, then this is basically just data obfuscation and doesn't provide real security. See more: Javascript Cryptography Considered Harmful
Use encryptedLogin.cipherText from the returned object
Check pls https://social.msdn.microsoft.com/Forums/vstudio/en-US/47800a60-4461-4f8e-a8d1-751fa62c7884/aes-encrypt-in-javascript-and-decrypt-in-c?forum=csharpgeneral
Also, you should use CryptoJS v3.1.2 AES realization to use it. You can download it here : https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/crypto-js/CryptoJS%20v3.1.2.zip
Js side code you can find here : jsfiddle.net/aEKw5/22/
So using info above you can encode at C# side, and decode it on js. or vice versa.

Encrypt text using AES in Javascript then Decrypt in C# WCF Service

I am trying to Encrypt a string using AES 128bit encryption. I have code for both Javascript and C#. The main objective is to encrypt the string using Javascript CryptoJS and then take the resultant cipher text and Decrypt it using C# AES AesCryptoServiceProvider.
Javascript Code:
function EncryptText()
{
var text = document.getElementById('textbox').value;
var Key = CryptoJS.enc.Hex.parse("PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0=");
var IV = CryptoJS.enc.Hex.parse("YWlFLVEZZUFNaWl=");
var encryptedText = CryptoJS.AES.encrypt(text, Key, {iv: IV, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7});
//var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");
var encrypted = document.getElementById('encrypted');
encrypted.value = encryptedText;
}
C# Code:
private String AES_decrypt(string encrypted)
{
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.Pkcs7;
aes.Key = Key;
aes.IV = IV;
ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
return System.Text.ASCIIEncoding.ASCII.GetString(secret);
}
When using "hello" as the plain text for javascript i get this ciphertext:
uqhe5ya+mISuK4uc1WxxeQ==
When passing that into the C# application, upon running the Decrypt method i recieve:
Padding is invalid and cannot be removed.
I am stumped here and have tried many solutions resulting in the same error.
When encrypting hello through the C# encryption AES method I receive:
Y9nb8DrV73+rmmYRUcJiOg==
I thank you for your help in advance!
javascript code :
function EncryptText()
{
var text = CryptoJS.enc.Utf8.parse(document.getElementById('textbox').value);
var Key = CryptoJS.enc.Utf8.parse("PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0="); //secret key
var IV = CryptoJS.enc.Utf8.parse("2314345645678765"); //16 digit
var encryptedText = CryptoJS.AES.encrypt(text, Key, {keySize: 128 / 8,iv: IV, mode: CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7});
var encrypted = document.getElementById('encrypted');
encrypted.value = encryptedText;
//Pass encryptedText through service
}
C# code :
private String AES_decrypt(string encrypted,String secretKey,String initVec)
{
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
//aes.BlockSize = 128; Not Required
//aes.KeySize = 256; Not Required
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.Pkcs7;
aes.Key = Encoding.UTF8.GetBytes(secretKey);PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0=
aes.IV = Encoding.UTF8.GetBytes(initVec); //2314345645678765
ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
return System.Text.ASCIIEncoding.ASCII.GetString(secret);
}
Used above code working fine !!!
Try using var Key = CryptoJS.enc.Utf8.parse("PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0="); instead of HEX.
Because actually the string you are putting in your key (and IV) and parsing is not a hex string. hex is 0 to F.
First, your Key variable in JS contains a string with 32 characters (after the odd-looking parse call). Although this might be interpreted as a 128-bit key, there is a certain chance that CryptoJS takes it as a pass phrase instead (and generates a key from it using some algorithm). So your actual key looks quite different. The string also looks suspiciously like hex-encoded, so there might be some additional confusion about its C# value. You have to make sure that you are using the same key in JS and C#.
Second, the IV variable also, after parsing, looks like a hex-encoded value. So you have to be careful what value you are using on the C# side as well.
FYI, here are the values for Key and IV after parsing:
Key = 00000000000e00000d000c0000010000,
IV = 0000000e000f0a00
Thank you "Uwe" parsing with UTF8 solved everything.
What happens if you use: var Key = CryptoJS.enc.Utf8.parse("PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0="); instead >of HEX? And what is your Key and IV in C#? Because actually the string you are putting in your key and >parsing is not a hex string. hex is 0 to F
Thank you so much!

Categories