I have been stuck in a long time. I am using Hybrid Crypto library in React Native to encrypt the message. Both public and private key are in PEM format.
let crypt = new Crypt({rsaStandard: 'RSA-OAEP'});
let encrypted = crypt.encrypt(publicKey, "This is a message");
return JSON.parse(encrypted).cipher;
This is the code I use to decrypt in Java. I followed this tutorial to read private key from pem file using bouncycastle library.
String str = "M2vFz/28sWhwAK4rGmnFAPRORRTlfa+XYpHFWQsi0bo=";
Security.addProvider(new BouncyCastleProvider());
KeyFactory factory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = generatePrivateKey(factory, RESOURCES_DIR + "private-key.pem");
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptOut = decryptCipher.doFinal(Base64.getDecoder().decode(str));
System.out.println(new String(decryptOut));
I've been trying many ways, the private key works fine when I decrypt in React but with Java I keep getting javax.crypto.BadPaddingException: Decryption error.
Updated Solution
Because I'm using hybrid crypto so it will include RSA + AES
Flow in frondend: Using AES key to encrypt text => Using public RSA key to encrypt AES key. Then you send everything you need to decrypt (encrypted AES key, Iv, and cipher text)
let crypt = new Crypt({rsaStandard: 'RSAES-PKCS1-V1_5',aesIvSize: 16});
let encrypted = crypt.encrypt(publicKey, str);
const encryptedObj = JSON.parse(encrypted);
return Object.values(encryptedObj.keys)[0] + ',' + encryptedObj.iv + ',' + encryptedObj.cipher;
Flow in java: Using RSA private key to decrypt AES key => Using AES key + Iv to decrypt cipher text
PrivateKey privateKey = generatePrivateKey();
Cipher decryptCipher=Cipher.getInstance("RSA/ECB/PKCS1Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] keyb = decryptCipher.doFinal(Base64.getDecoder().decode(AESkey));
SecretKeySpec skey = new SecretKeySpec(keyb, "AES");
IvParameterSpecivspec = new IvParameterSpec(Base64.getDecoder().decode(iv));
decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, skey, ivspec);
byte[] decryptOut = decryptCipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(decryptOut);
Related
I am using CryptoJS in my angular app to implement AES encryption but I am keep getting TypeError: Cannot read property '0' of undefined error when I try to send empty 16 byte array in IV
Here's my typescript code:
aesEncrypt(keys: string, value: string) { // encrypt api request parameter with aes secretkey
var key = CryptoJS.enc.Utf8.parse(keys);
//var iv = CryptoJS.enc.Utf8.parse(keys);
var iv = new Uint16Array(16);
var encrypted = CryptoJS.AES.encrypt(JSON.stringify(value), key,
{
//keySize: 256,
keySize: 128,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString();
}
But same thing works fine in .NET, android, ios when I send empty 16 byte array in IV
.NET code:
private static AesCryptoServiceProvider AesCryptoServiceProvider(string key)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.KeySize = 128;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.UTF8.GetBytes(key);
//aes.IV = Encoding.UTF8.GetBytes(key);
aes.IV = new byte[16];
return aes;
}
android code:
public static String encryptURLEncoding(byte[] key, String encryption) throws GeneralSecurityException
{
if (key.length != 16)
{
throw new IllegalArgumentException("Invalid key size.");
}
// Setup AES tool.
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
byte[] dstBuff = cipher.doFinal(encryption.getBytes());
String encryptedStringData = android.util.Base64.encodeToString(dstBuff, android.util.Base64.DEFAULT);
return encryptedStringData;
}
I want to implement AES encrypt decrypt by providing empty 16 byte array because this app is interconnected with my other apps which are on android, ios platform with same encryption setup but I am getting error in my angular app, How can I resolve this issue?
In the JavaScript code the IV must be passed as WordArray. Since a 0-IV was used in the C# code, this must also be done in the JavaScript code. The corresponding WordArray could be e.g.
var iv = CryptoJS.enc.Hex.parse("00000000000000000000000000000000");
Note that the Hex encoder is used so that the 16 bytes 0-IV correspond to 32 0-values.
Also be aware that generally a 0-IV should only be used for testing purposes. In practice, for security reasons, a random IV has to be generated for each encryption. Additionally, a key / IV pair may only be used once.
Furthermore CryptoJS does not know the parameter keySize and ignores it. The used AES variant is determined by the key size, e.g. for a 32 bytes key AES-256 is applied, here.
For those who faced a similar error in typescript for encrypting a string, you just need to import the package this way
import * as Crypto from 'crypto-js';
I faced the same problem.
Including the iv option solved it.
var iv = CryptoJS.enc.Hex.parse("101112131415161718191a1b1c1d1e1f"); var ciphertext = CryptoJS.AES.encrypt("msg", CryptoJS.enc.Hex.parse("000102030405060708090a0b0c0d0e0f"),{ iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.AnsiX923 });
This is the crypto AES encryption code in server side. How can I decrypt in javascript. I can't find any decryption logic having both iv and key with padding.
public static String encrypt(String key, String initVector, String value) {
try {
IvParameterSpec iv = new IvParameterSpec("l353b3l3jk3bk3j3".getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec("2353c3l3jk3bk3j8".getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
System.out.println("encrypted string: " + Base64.encodeBase64String(encrypted));
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
You can use CryptoJS in the following way:
var decryptedData = CryptoJS.AES.decrypt(cipherText, CryptoJS.enc.Base64.parse(key),
{
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7 //default
});
console.log('Decrypted Data: ' + decrypted);
PKCS5 is not supported by this library but you should not be using it as it was designed for DES rather than AES. However if you dont want to change it then you can still use PKCS7 for decryption and it will work because the difference is in the block size both paddings supports. PKCS5 only works with 8-byte blocks whereas PKCS7 works with block sizes betwheen 1 and 255 bytes. DES uses block size of 8 bytes.
In my code I am encrypting data using AES encryption using crypto.js and i am decrypting the encrypted text
in java.
Encryption and Decryption are working correctly if i try to encrypt and decrypt both in javascript or java.But if i encrypt in javascript
and trying to decrypt in java i am getting below error.
javax.crypto.BadPaddingException: Given final block not properly
padded at
com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
Below is my JSCode:
var keyHex = CryptoJS.enc.Utf8.parse('584771624934175587013168');
var iv = CryptoJS.enc.Hex.parse('000000000000000000000000');
var encrypted = CryptoJS.AES.encrypt('1111', keyHex, {
iv:iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log('encryptByAES key: ',encrypted.toString());
Below is my java code.
String key = "584771624934175587013168";
String plainText = "1111";
public String encryptTextusingAES(String text, String kek) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes= new byte[16];
byte[] b= kek.getBytes("UTF-8");
int len= b.length;
if (len> keyBytes.length) len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec);
byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(results);
}
public String decryptTextusingAES(String text, String kek) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes= new byte[16];
byte[] b= kek.getBytes("UTF-8");
int len= b.length;
if (len> keyBytes.length) len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec);
BASE64Decoder decoder = new BASE64Decoder();
byte [] results = cipher.doFinal(decoder.decodeBuffer(text));
return new String(results,"UTF-8");
}
How to decrypt correctly any help will be greatly appreciated!!!!
When you are using a block encryption such as AES, your input needs to be padded before encryption. There are various standard ways of doing this.
In your JS code your are specifying PKCS-7:
padding: CryptoJS.pad.Pkcs7
but in your Java code you are specifying PKCS-5:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Make sure you are using the same padding algorithm on both sides.
I am using CryptoJS to encrypt a message and send it to the server, and decrypting it on the other end in C# using Aes Manager. I get a response back when I send it to the server, but it isn't correct.
Javascript:
this.CryptoJS=require("crypto-js");
var temp=this.CryptoJS.AES.encrypt("hello","yyyyyyyyyyyyyyyyyyyyyyyyyyyyykey",{
keySize:128/8,
iv:this.CryptoJS.enc.Utf8.parse("helllooohelllooo"),
mode:this.CryptoJS.mode.CBC,
padding:this.CryptoJS.pad.ZeroPadding
});
data.text=temp.toString(); // This is how I send it to the server
C#:
byte[] Key = UTF8Encoding.UTF8.GetBytes("yyyyyyyyyyyyyyyyyyyyyyyyyyyyykey");
byte[] toBytes = UTF8Encoding.UTF8.GetBytes("helllooohelllooo");
AesManaged aes = new AesManaged();
aes.Key = Key;
aes.IV = toBytes;
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CBC;
aes.KeySize = 128;
aes.BlockSize = 128;
byte[] bytes = Convert.FromBase64String(data.text);
UTF8Encoding utf8 = new UTF8Encoding();
using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
{
MemoryStream MS = new MemoryStream(bytes);
CryptoStream CS = new CryptoStream(MS, decryptor, CryptoStreamMode.Write);
CS.Write(bytes, 0, bytes.Length);
CS.FlushFinalBlock();
MS.Position = 0;
bytes = new byte[MS.Length];
MS.Read(bytes, 0, bytes.Length);
Plaintext = utf8.GetString(bytes);
var temp = 5;
}
This is what I get as a result from the Plaintext variable: t�k�\a``\u007f������\f^,F~\u0017�\u001fp��#5�\u007f\\
You should explicitly pass the key, plaintext and IV as binary data rather than strings:
let iv = CryptoJS.enc.Utf8.parse("helllooohelllooo");
let pt = CryptoJS.enc.Utf8.parse("hello");
let key = CryptoJS.enc.Utf8.parse("yyyyyyyyyyyyyyyyyyyyyyyyyyyyykey");
Then use in the code like so:
CryptoJS.AES.encrypt(pt, key, ...);
Note that your use of zero padding, fixed IV, and no HMAC or AEAD mode makes the code you have completely insecure. You definitely should not use it. Consult this GitHub repository for examples of secure encryption between JavaScript and C#.
I was able to fix my problem i was not converting the original key to utf8 and once i did that it fixed itself
Resource
I'm making an app that has to decrypt QRs and well... It doesn't, because i get the QR string but i cannot decrypt it.
I'm using this encryption method in VB.NET, and it works perfectly when i read an decrypt from VB.NET:
Private Function GetCodedQR(ByVal str As String) As String
Dim sToEncrypt As String = str
Dim encrypted() As Byte
' Create an Rijndael object
' with the specified key and IV.
Using rijAlg = Rijndael.Create()
rijAlg.Padding = PaddingMode.Zeros
rijAlg.Mode = CipherMode.CBC
rijAlg.KeySize = 256
rijAlg.BlockSize = 256
rijAlg.Key = System.Text.Encoding.ASCII.GetBytes("12345678912345678912345678912345")
rijAlg.IV = System.Text.Encoding.ASCII.GetBytes("123452hheeyy66#cs!9hjv887mxx7#8y")
' Create an encryptor to perform the stream transform.
Dim encryptor As ICryptoTransform = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV)
' Create the streams used for encryption.
Using msEncrypt As New MemoryStream()
Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
Using swEncrypt As New StreamWriter(csEncrypt)
'Write all data to the stream.
swEncrypt.Write(sToEncrypt)
End Using
encrypted = msEncrypt.ToArray()
End Using
End Using
End Using
sToEncrypt = Convert.ToBase64String(encrypted)
Return sToEncrypt
End Function
But when im using JS (CryptoJS) to decrypt the message it just dont work!
var iv = CryptoJS.enc.Utf8.parse('123452hheeyy66#cs!9hjv887mxx7#8y');
var decrypted = CryptoJS.AES.decrypt(encrypted, '12345678912345678912345678912345', { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding });
Please help me I'm doing my best but JS is not my thing.