so I'm trying to encrypt data in C# with RSA and decrypt it with JavaScript also with RSA.
This is the function that I use to encrypt the data in C#:
private static byte[] Encrypt(byte[] input, bool server)
{
byte[] encrypted;
using (var rsa = new RSACryptoServiceProvider(4096))
{
rsa.PersistKeyInCsp = false;
if (server)
{
rsa.ImportParameters(ImportPublicKey(Main.PUBLIC_KEY_SERVER).ExportParameters(false));
}
else
{
rsa.ImportParameters(publicKey);
}
encrypted = rsa.Encrypt(input, true);
}
return encrypted;
}
And this is the code I use to decrypt the data in JavaScript:
function decryptMessage(encryptedMessage, privateKey) {
console.log(encryptedMessage);
const rsaPrivateKey = {
key: privateKey,
passphrase: '',
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
};
const decryptedMessage = crypto.privateDecrypt(
rsaPrivateKey,
Buffer.from(encryptedMessage, 'base64'),
);
return decryptedMessage.toString('utf8');
}
Now the problem is I'm always getting the Error:
Error: error:04099079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
And I don't know why. For some reason, the Encryption Padding doesn't seem to be the same anymore. Is there a way around this problem?
~Louis
Related
I have been reading several similar questions and based on that for my initial code. Unfortunately, I still can't get it to work.
key="fb52042ada308dd1d4dfd8a3870d5ab5"
iv = "bb8e0b158f57f63dfeea86e24af1abfc"
data = {"MerchantId":"0000000000000001"}
Get SHA256 from "data" (dataSha256)
Get encryption from Encrypt dataSha256 + iv + key
Result of Hexa encryption, similar to:
fd72fcc16b66d04cf0f4dd2265a59eb675103482bae806b405bb85595056f5770b3202b42d42a87b767892591a333eb6b5c9ad3ef34f4d415f8d3bbc3d0f389e2e5b6f7cd915520c7b2c19225680728b
When migrating the code from Java to Node.js, I don't get similar result. The first problem is that the "iv" should be 16 bytes, however in the code it is 32.
JAVA EXTRACT (original)
public class AesEncryption implements SymmetricEncryptionComponent {
Map<String, String> initParams;
String key, iv;
String mode, encoding;
String keyFile;
String ENCODING = "ISO-8859-1";
public AesEncryption() {
Security.addProvider(new BouncyCastleProvider());
}
// PARAMETERS INITIALITATION
public void setInitParams()
{
initParams=params;
key=” 1ea9a91b0ba908b44f598d2822499441”;
iv= "f20946931dd6e8594dc6f469b5e583ab";
mode= "AES/CBC/PKCS7Padding";
encoding= "HEX";
if(encoding.equalsIgnoreCase("BASE64")&&encoding.equalsIgnoreCase("HEX"))
throw new IllegalArgumentException("AES.ENCODING can only be 'HEX' of 'BASE64'")
}
// INFORMATION CIPHERING return encodeBase24
public String encrypt(String data) {
byte[] output = null;
try {
byte[] keyBytes = decode(key);
byte[] input = data.getBytes(ENCODING);
AlgorithmParameterSpec ivSpec = new
IvParameterSpec(Hex.decodeHex(iv.toCharArray()));
SecretKeySpec keySpec = null;
keySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(mode);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
output = cipher.doFinal(input);
} catch (Exception e) {
throw new EncryptionException("Error", e);
}
return encode(output);
}
// INFORMATION ENCODE
private String encode(byte[] output) {
if (mode.equalsIgnoreCase("BASE64"))
return Base64.encodeBase64String(output);
else
return new String(Hex.encodeHex(output));
}
// INFORMATION DECODE
private byte[] decode(String data) throws DecoderException {
if (data.indexOf("=") > 0 || data.indexOf("+") > 0)
return Base64.decodeBase64(data);
else
return Hex.decodeHex(data.toCharArray());
}
}
NODE EXTRACT (using crypto-js)
const cryptojs = require("crypto-js");
const crypto = require("crypto");
let jsonData = {"MerchantId":"0000000000000001"};
let key = 'fb52042ada308dd1d4dfd8a3870d5ab5';
let iv = 'bb8e0b158f57f63dfeea86e24af1abfc';
const jsonDataSha256 =
crypto.createHash('sha256').update(JSON.stringify(jsonData)).digest('hex');
key = cryptojs.enc.Latin1.parse(key); //Convierte hex string -> word array
iv = cryptojs.enc.Latin1.parse(iv);
jsonDataSha256Bin = cryptojs.enc.Latin1.parse(jsonDataSha256); //Convert hex
string -> word array
console.log(key);
console.log(iv);
console.log(jsonDataSha256);
let encrypted = cryptojs.AES.encrypt(jsonDataSha256Bin, key, {
iv: iv,
mode: cryptojs.mode.CBC,
padding: cryptojs.pad.Pkcs7,
});
encrypted = encrypted.toString();
const salida = crypto.createHash('sha256').update(encrypted).digest('hex');
console.log(`${salida}`);
//Equals to ce994c4d2b1f398ff0bed22c4b48e1f2170dbf26baf2eaacec96ea6b31667cd6
//No match to Java output.
What will I be doing wrong? Any help is appreciated!
I generated a private and public key in javascript like this.
import crypto from "crypto";
/*export const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
modulusLength: 2048,
});*/
const pair = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 });
export const privateKey = pair.privateKey.export({
type: "pkcs1",
format: "pem",
});
export const publicKey = pair.publicKey.export({
type: "pkcs1",
format: "pem",
});
Then i use the private key to create a signature for a jsonfile like this, and the public key to verify it before i return the signature.
//Lav signatur
const signate = crypto.createSign("SHA384");
signate.update(Buffer.from(licenseRelationship, "utf-8"));
const signature = signate.sign(privateKey, "hex");
const verifier = crypto.createVerify("SHA384");
// verificer signature, besked
verifier.update(Buffer.from(licenseRelationship, "utf-8"));
const verificationResult = verifier.verify(publicKey, signature, "hex");
This works perfectly, and then i return the json and the signature as a http response.
I recieve it in c# code and store the two components so im can use them later on request.
Upon request i fetch the two components and want to use the signature to check if the json has been tampered with.
I also has the public key in this code.
I do it like this.
string licenseRelationshipJson = licenseRelationshipDAO.getLicenseRelationshipWithoutSignatureAsJson(licenseRelationship);
byte[] signature = Encoding.UTF8.GetBytes(licenseRelationship.signature);
byte[] licenseRelationshipJsonAsArray = Encoding.UTF8.GetBytes(licenseRelationshipJson);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
result = rsa.VerifyData(licenseRelationshipJsonAsArray, signature,
HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1);
if (result)
{
log.write("Message verified ", null);
} else
{
log.write("Message not Verified ", null);
}
All debug code and exception handling removed.
I'm a crypto virgin, and am trying to understand this. But i must have misunderstood something serious.
I have the public key as a string (not base64 encoded)
Ive checked the json, and it is the exact same bytes when signed in Javascript as when being verified in c#
The public key is not used in this process. That has to be wrong i think ?
How do i get the public key into the RWACryptoServiceProvider ?
Im sure im using RWACryptoServiceProvider wrong.
EDIT....:
Ive tried this instead, but still to no avail.
string licenseRelationshipJson = licenseRelationshipDAO.getLicenseRelationshipWithoutSignatureAsJson(licenseRelationship);
byte[] signature = Encoding.UTF8.GetBytes(licenseRelationship.signature);
byte[] licenseRelationshipJsonAsArray = Encoding.UTF8.GetBytes(licenseRelationshipJson);
byte[] asBytes = Encoding.ASCII.GetBytes(DataStorage.Instance.PUBLIC_KEY);
char[] publicKeyAsArray = Encoding.ASCII.GetChars(asBytes);
ReadOnlySpan<char> publicKeyChars = publicKeyAsArray;
RSA rsa = RSA.Create();
try
{
rsa.ImportFromPem(publicKeyChars);
result = rsa.VerifyData(licenseRelationshipJsonAsArray, signature, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1);
} catch (CryptographicException cex)
{
log.write("Something went wrong with the crypto verification process", cex);
}
.
.
.
Thankyou for your time.
i have a mobile app developed on ionic and i have this portion of code that get a base64 string and encrypt it (the same thing for decryption) here is the code
globalEncrypt(input: string): string {
return crypto.AES.encrypt(input, '****************').toString();
}
globalDecrypt(input: string):string {
return crypto.AES.decrypt(input, '****************', {
iv: '****************',
mode: crypto.mode.CBC,
padding: crypto.pad.Pkcs7
}).toString(crypto.enc.Utf8);
}
NB: '****************' are strings of 16 length but note the same (key <> Iv).
this works fine.
the problème is that i tried to use the same AES in C#
with the same configuration but i don't get the same result.
public static string DecryptStringFromBytes(String TextBase64)
{
byte[] cipherText = Encoding.UTF8.GetBytes(TextBase64);
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 = Encoding.UTF8.GetBytes("****************");
rijAlg.IV = Encoding.UTF8.GetBytes("****************"); ;
// 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;
}
Any help will appreciated.
Thank you
I want to encrypt the password before to submit.
app.js
function encryptPass() {
var encrypted = CryptoJS.AES.encrypt("Test", "1234").toString();
$("#password").val(encrypted)
}
After to submit, the tool call method: decrypt
pass.java
public static String decrypt(String strToDecrypt) {
def result
try {
if (strToDecrypt) {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, obtenerSecretKey());
result = new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt)))
}
} catch (Exception e) {
println e
throw e;
} finally {
return result
}
}
private static SecretKeySpec obtenerSecretKey () {
MessageDigest sha = MessageDigest.getInstance("SHA-1");
def semilla = "1234"
def key = sha.digest(semilla.getBytes("UTF-8"));
key = Arrays.copyOf(key, 16);
return new SecretKeySpec(key, "AES");
}
I'm getting this error:
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
Any suggestions or other encrypt type?
I have a function written in C#. Basically the function is used to generate a token on the basis of parameters like text and key.
public string Encrypt(string input, string key) {
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncrptArray = UTF8Encoding.UTF8.GetBytes(input);
Aes kgen = Aes.Create("AES");
kgen.Mode = CipherMode.ECB;
kgen.Key = keyArray;
ICryptoTransform cTransform = kgen.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncrptArray, 0, toEncrptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
I'm trying to search any same alternative for the above function in NodeJS or run this function inside the NodeJS script through any compiler.
I have tried the crypto-js module in NodeJS but got a different token string. Please suggest the alternative function or any idea about running this function inside the NodeJS script.
My Recent code in NodeJS :
First Method :
var CryptoJS = require("crypto-js");
// Encrypt
var ciphertext = CryptoJS.AES.encrypt("<input>", "<key>").toString();
Second Method :
var crypto = require('crypto'),
algorithm = 'aes-256-ctr',
password = '<key>';
function encrypt(text){
var cipher = crypto.createCipher(algorithm,password)
var crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex');
return crypted;
}
Both the method is giving different token if compared to C# function.
The AES algorithm used in the C# code is AES 128-bit in ECB mode.
We can perform the same encryption in Node.js (and decrypt as well if we wish), using the following code:
Node.js Code
const crypto = require("crypto");
function encrypt(plainText, key, outputEncoding = "base64") {
const cipher = crypto.createCipheriv("aes-128-ecb", key, null);
let encrypted = cipher.update(plainText, 'utf8', outputEncoding)
encrypted += cipher.final(outputEncoding);
return encrypted;
}
function decrypt(cipherText, key, outputEncoding = "utf8") {
const cipher = crypto.createDecipheriv("aes-128-ecb", key, null);
let encrypted = cipher.update(cipherText)
encrypted += cipher.final(outputEncoding);
return encrypted;
}
const KEY = Buffer.from("abcdefghijklmnop", "utf8");
console.log("Key length (bits):", KEY.length * 8);
const encrypted = encrypt("hello world", KEY, "base64");
console.log("Encrypted string (base64):", encrypted);
// And if we wish to decrypt as well:
const decrypted = decrypt(Buffer.from(encrypted, "base64"), KEY, "utf8")
console.log("Decrypted string:", decrypted);
C# Code
using System;
using System.Text;
using System.Security.Cryptography;
public class Program
{
public static void Main()
{
Console.WriteLine("Result: " + Encrypt("hello world", "abcdefghijklmnop"));
}
public static string Encrypt(string input, string key) {
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncrptArray = UTF8Encoding.UTF8.GetBytes(input);
Aes kgen = Aes.Create("AES");
kgen.Mode = CipherMode.ECB;
kgen.Key = keyArray;
ICryptoTransform cTransform = kgen.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncrptArray, 0, toEncrptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
}
The results for the encryption (with plaintext and key as above) are:
.Net: f7sSBDV0N6MOpRJLpSJL0w==
Node.js: f7sSBDV0N6MOpRJLpSJL0w==
Obviously we must not use this key in production!