I am using CryptoJS to encrypt at the client side I have created a fiddle of the client side code as following -
var onClick = function() {
var iv = "3ad5485e60a4fecde36fa49ff63817dc";
var key = "0a948a068f5d4d8b9cc45df90b58d382d2b916c25822b6f74ea96fe6823132f4";
var encrypted = CryptoJS.AES.encrypt("{'This is ' : 'A Nice day'}",
key, {
iv : CryptoJS.enc.Hex.parse(iv),
mode : CryptoJS.mode.CBC,
padding : CryptoJS.pad.Pkcs7
});
var encryptedInHex = encrypted.ciphertext
.toString(CryptoJS.enc.Hex); // converting the encrypted data in Hexadecimal
document.getElementById("thisDiv").innerHTML = encryptedInHex.toUpperCase();
return encryptedInHex.toUpperCase(); // returning the hashed encrypted data.
};
I have also developed a fiddle for it here -
http://jsfiddle.net/akki166786/1c24d1mj/3/
This is symmetric key cryptography being used here.
when I am trying to decrypt it on server side I am getting,
javax.Crypto.BadPaddingException : Given final block not properly padded exception,
Can there be a problem from Client side as well?
I need a server side(written in java) code to decrypt the out put of the function which i Have written in fiddle.
Thanks for your help.
You'll find the Java code to decrypt the ciphertext below. A couple of notes first:
server-side code uses commons-codec for hex decoder
in client-side code, replace key parameter to encrypt function with CryptoJS.enc.Hex.parse(key)
That should be it. And now the code ...
public class Decryptor {
private static final String IV = "3ad5485e60a4fecde36fa49ff63817dc";
private static final String KEY = "0a948a068f5d4d8b9cc45df90b58d382d2b916c25822b6f74ea96fe6823132f4";
private final static String CIPHERTEXT = "4E6B9EC6B5A0614BF9D69C5B0B5AE03D27484F2DB9D450E50EE623E80B8E34F5";
public static final void main(String[] args) throws DecoderException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
SecretKeySpec sks = new SecretKeySpec(Hex.decodeHex(KEY.toCharArray()), "AES");
IvParameterSpec iv = new IvParameterSpec(Hex.decodeHex(IV.toCharArray()));
Cipher c = Cipher.getInstance("AES/CBC/NoPadding");
c.init(Cipher.DECRYPT_MODE, sks, iv);
byte[] plain = c.doFinal(Hex.decodeHex(CIPHERTEXT.toCharArray()));
String plainText = new String(plain);
System.out.println(plainText);
}
}
Related
I have to change java code for decrypt to flutter code. I use library "encrypt" for flutter. my flutter code show
Key length not 128/192/256 bits.
my java spring boot code.
public static String decryptAES256(String str, String secretKey) throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
String AES = "AES";
String AES_PADDING = "AES/CBC/PKCS5Padding";
byte[] keyData = java.util.Base64.getDecoder().decode(secretKey);
String iv = secretKey.substring(0, 16);
SecretKey secureKey = new SecretKeySpec(keyData, AES);
Cipher c = Cipher.getInstance(AES_PADDING);
c.init(Cipher.DECRYPT_MODE, secureKey, new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8)));
byte[] byteStr = Base64.getDecoder().decode(str.getBytes());
return new String(c.doFinal(byteStr), StandardCharsets.UTF_8);
}
my flutter code.
final encData = codefModel.data!.encData!;
final key = en.Key.fromUtf8(decryptKey);
final b64key = en.Key.fromUtf8(base64Url.encode(key.bytes));
final iv = en.IV.fromLength(16);
final encrypter = en.Encrypter(en.AES(b64key, mode: en.AESMode.cbc));
logger.d(encrypter.decrypt64(encData, iv: iv));
From the Java code it can be deduced that the AES key secretKey and the ciphertext str are Base64 encoded. The first 16 bytes of the Base64 encoded key (not of the raw key!) are used as IV.
In the Dart code the key is incorrectly converted and a wrong IV is used. A possible fix is (together with sample data):
const decryptKey = "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=";
const encData = "lo0dOoJrHNRuefPXgkEa6jtDUhV5CguF9MHWTJ4Y8eGP8zHaKJEQIuOTZxstyk3X";
final key = en.Key.fromBase64(decryptKey);
final iv = en.IV(Uint8List.fromList(utf8.encode(decryptKey).sublist(0, 16)));
final encrypter = en.Encrypter(en.AES(key, mode: en.AESMode.cbc));
final decrypted = encrypter.decrypt64(encData, iv: iv); // The quick brown fox jumps over the lazy dog
As test, key and ciphertext can be used in the Java code that returns the same plaintext for them.
Be aware that deriving the IV from the key is generally insecure, since encryptions with the same key automatically lead to the reuse of key/IV pairs. Instead, a random IV should be used for each encryption.
I'm currently working on a Project where I wanna use RSA for authentification. But as I'm using Java for my Server and C# for my Client I have alot of problems with creating or better initilize the PublicKey class from java.security in Java. I've already used mutlipe solutions for both languages and most of them are working themself.
So thats my basic C# RSA Client:
public static void NewKeyPair()
{
var csp = new RSACryptoServiceProvider(1024);
//how to get the private key
var privKey = csp.ExportParameters(true);
//and the public key ...
var pubKey = csp.ExportParameters(false);
_ = privKey.Modulus;
_ = pubKey.Modulus;
}
public void Encrypt(string text, string publicKey)
{
RSAParameters para = new RSAParameters();
para.Modulus = Convert.FromBase64String(publicKey);
//conversion for the private key is no black magic either ... omitted
//we have a public key ... let's get a new csp and load that key
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(para);
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(text);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
var cypherText = Convert.ToBase64String(bytesCypherText);
}
public static void Decrypt(string encryptedText, RSAParameters para)
{
var bytesCypherText = Convert.FromBase64String(encryptedText);
//we want to decrypt, therefore we need a csp and load our private key
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(para);
//decrypt and strip pkcs#1.5 padding
var bytesPlainTextData = csp.Decrypt(bytesCypherText, false);
//get our original plainText back...
var plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
So this is basically from a Microsoft doc if I remmeber right.
Meanwhile that's my Java code:
public static KeyPair gen() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
return keyGen.generateKeyPair();
}
public static String encrypt(String message, PublicKey pk) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pk);
return Base64.getEncoder().encodeToString(cipher.doFinal(message.getBytes()));
}
public static String decrypt(String encryptedText, PrivateKey pk) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pk);
return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedText)));
}
So for connecting those I'm exporting the Key first in C# with
Convert.ToBase64String(csp.ExportSubjectPublicKeyInfo()
After writing this to Console I paste it into this code snip in Java:
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(""));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
// Encrypting
String encrypted = encrypt("Hello", pubKey);
Afterwards I'm checking everythink by decrypting it again in C# ( Mostly failing before at keyFactory.generatePublic(keySpec); )
Also though aleady that's maybe caused by the byte system as c# using unsigned and java signed, but don't really have an idea how to fix that.
Someone has an idea how to solve this problem? c:
I am trying to decrypt a String with a known key in Java using standard Cipher API.
The encrypted String comes from a Web Service using the standard CommonCrypto Library which responds with some statistics as encrypted strings at regular intervals.
The specs are AES/CBC/PKCS7Padding with KeySize = 32 Bytes and BlockSize = 16 Bytes, and Encoding UTF-8 (raw) & Base64. I intend to write a Java client that can request these statistics, decrypt them and store them for later analyses.
Question 1. Does the CommonCrypto automatically pad keys with extra chars if the key is short? For instance less than 16 Bytes or 32 Bytes.
Question 2. What encoding measures should I take to ensure an identical encryption/decryption on both ends?
Example Strings and Key
String message = "mQp9sp8ri1E0V1Xfso1d5g==Mrf3wtaqUjASlZmUO+BI8MrWsrZSC0MxxMocswfYnqSn/VKB9luv6E8887eCxpLNNAOMB0YXv6OS7rFDFdlvC53pCHo3cVZiLJFqgWN/eNiC9p4RMxyFCcOzWrwKzT5P8sy55DwE25DNJkvMthSaxK5zcP1OdLgBiZFOSxYRsX4rBk7VP7p5xr2uTGjRL+jmGgB9u3TmeCNCr8NxGLNt6g==";
String userKey = "123456789";
private static String decrypt (String message, String userKey) throws UnsupportedEncodingException,
NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException,
ShortBufferException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, NoSuchProviderException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
if (message.length() >= 48) {
ivFromEncryptedString = message.substring(0, Math.min(message.length(), 24));
messageFromEncryptedString = message.substring(24, message.length());
System.out.println(ivFromEncryptedString);
System.out.println(messageFromEncryptedString);
byte[] data = decodeBase64(messageFromEncryptedString);
byte[] ivData = decodeBase64(ivFromEncryptedString);
paddedKey = padShortKeys(userKey);
byte[] keyBytes = paddedKey.getBytes(CHARSET);
MessageDigest sha = MessageDigest.getInstance("SHA-256"); //key
keyBytes = sha.digest(keyBytes);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivData);
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
byte [] encrypted = new byte[cipher.getOutputSize(data.length)];
int ctLength = cipher.update(data, 0, data.length, encrypted, 0);
ctLength += cipher.doFinal(encrypted, ctLength);
} catch (Exception e) {
System.out.println(e);
} finally {
return encrypted;
}
}
return null;
}
private static String encodeBase64(byte [] in){
return Base64.getEncoder().encodeToString(in);
}
private static byte[] decodeBase64(String str) throws UnsupportedEncodingException {
return DatatypeConverter.parseBase64Binary(str);
}
Also with the current code status I am getting placehoder characters instead of the desired result.
Thanks in advance folks. :)
CommonCrypto is unclear, which implementation are you using? Apple, Apache, Java Class Cipher or another, please supply a link to it.
Never assume an encryption will pad the key or IV, they should always be provided in the exact length, there is no standard for such padding. If they need padding (they shouldn't) do it yourself.
Typically if encrypted data needs to be expressed as a character string Base64 encoding is used.
As James states, for one-shot encryption just use doFinal(ByteBuffer input, ByteBuffer output) which
encrypts or decrypts data in a single-part operation.
Note: A 9 digit key only has about 33-bits of security which is not close to sufficient. Simple using a hash function is insufficient for deriving an encryption key from a password, instead PBKDF2 or Argon2 should be used.
I have a node module that can both encrypt and decrypt with AES-256 GCM. Now I am also trying to decrypt with Java whatever the node module encrypts, but I keep getting a AEADBadTagException.
I have tested the node module by itself and can confirm that it works as intended. I know that Java assumes the authentication tag is the last part of the message, so I ensured that the tag is the last thing appended in the node module.
Right now I'm just testing with the word, "hello". This is the encrypted message from node:
Q10blKuyyYozaRf0RVYW7bave8mT5wrJzSdURQQa3lEqEQtgYM3ss825YpCQ70A7hpq5ECPafAxdLMSIBZCxzGbv/Cj4i6W4JCJXuS107rUy0tAAQVQQA2ZhbrQ0gNV9QA==
The salt is not really being used right now because I am trying to keep things simple for testing purposes
Node module:
var crypto = require('crypto');
var encrypt = function(masterkey, plainText) {
// random initialization vector
var iv = crypto.randomBytes(12);
// random salt
var salt = crypto.randomBytes(64);
var key = masterkey;
// AES 256 GCM Mode
var cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
// encrypt the given text
var encrypted = Buffer.concat([cipher.update(plainText, 'utf8'), cipher.final()]);
// extract the auth tag
var tag = cipher.getAuthTag();
return Buffer.concat([salt, iv, encrypted, tag]).toString('base64');
};
var decrypt = function(masterkey, encryptedText) {
// base64 decoding
var bData = new Buffer(encryptedText, 'base64');
// convert data to buffers
var salt = bData.slice(0, 64);
var iv = bData.slice(64, 76);
var tag = bData.slice(bData.length - 16, bData.length);
var text = bData.slice(76, bData.length - 16);
var key = masterkey;
// AES 256 GCM Mode
var decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
// encrypt the given text
var decrypted = decipher.update(text, 'binary', 'utf8') + decipher.final('utf8');
return decrypted;
};
module.exports = {
encrypt: encrypt,
decrypt: decrypt
}
Java Class:
The main method is just there for testing right now and will be removed later.
package decryption;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class DecryptAES256 {
private static String salt;
private static byte[] ivBase64;
private static String base64EncryptedText;
private static String key;
public static void main(String[] args) {
String key = "123456789aabbccddeefffffffffffff";
String sourceText = "Q10blKuyyYozaRf0RVYW7bave8mT5wrJzSdURQQa3lEqEQtgYM3ss825YpCQ70A7hpq5ECPafAxdLMSIBZCxzGbv/Cj4i6W4JCJXuS107rUy0tAAQVQQA2ZhbrQ0gNV9QA==";
System.out.println(decrypt(key, sourceText));
}
public static String decrypt(String masterkey, String encryptedText) {
byte[] parts = encryptedText.getBytes();
salt = new String(Arrays.copyOfRange(parts, 0, 64));
ivBase64 = Arrays.copyOfRange(parts, 64, 76);
ivBase64 = Base64.getDecoder().decode(ivBase64);
base64EncryptedText = new String(Arrays.copyOfRange(parts, 76, parts.length));
key = masterkey;
byte[] decipheredText = decodeAES_256_CBC();
return new String(decipheredText);
}
private static byte[] decodeAES_256_CBC() {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] text = base64EncryptedText.getBytes();
GCMParameterSpec params = new GCMParameterSpec(128, ivBase64, 0, ivBase64.length);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, params);
return cipher.doFinal(Base64.getDecoder().decode(text));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to decrypt");
}
}
}
The exception thrown is normal, you have 2 problems in your Java code:
1- your AES key is not decoded correctly: it is wrapped in hexadecimal representation and you decode it as if it was not. You need to convert it from the hexadecimal representation to bytes, when calling SecretKeySpec().
Replace the following line:
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
By this one:
SecretKeySpec skeySpec = new SecretKeySpec(Hex.decodeHex(key.toCharArray()), "AES");
Note that to get access to the Hex class, you need to import org.apache.commons.codec.binary.Hex in your class file and include the corresponding Apache commons-codec library in your project.
2- you split your base64 cipher text before having converted it to base64, this is not the correct order to do things:
At the start of your decrypt() method, you need to first call Base64.getDecoder().decode() on your cipher text (sourceText) before splitting it into the corresponding fields.
If you want an example of using AES-256-GCM in Java, you can look at the following example I had written some months ago: https://github.com/AlexandreFenyo/kif-idp-client
The source code to encrypt and decrypt is in the following file: https://github.com/AlexandreFenyo/kif-idp-client/blob/master/src/kif/libfc/Tools.java
See the methods named encodeGCM() and decodeGCM().
Those methods are called by the main class here: https://github.com/AlexandreFenyo/kif-idp-client/blob/master/src/kif/libfc/CommandLine.java
I have encrypted string using algorithm RSA/ECB/PKCS1Padding through Java code now the same need to be encrypted using node.js. I don't know how to encrypt through node.js using algorithm RSA/ECB/PKCS1Padding .
Any suggestions?
the Java code is:
public static String encrypt(String source, String publicKey)
throws Exception {
Key key = getPublicKey(publicKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] b = source.getBytes();
byte[] b1 = cipher.doFinal(b);
return new String(Base64.encodeBase64(b1), "UTF-8");
}
node js code using the cryto library:
const crypto = require('crypto')
const encryptWithPublicKey = function(toEncrypt) {
var publicKey = '-----BEGIN PUBLIC KEY-----****' //your public key
var buffer = Buffer.from(toEncrypt, 'utf8');
var encrypted = crypto.publicEncrypt({key:publicKey, padding : crypto.constants.RSA_PKCS1_PADDING}, buffer)
return encrypted.toString("base64");
}