Angular 7 AES encrypting password with crypt-js - c#

I am trying to encrypt the password using AES technique and sending it to api which is developed on .net. Issue I am facing is I am getting error:
I am using Crypto-JS typed version: Crypto-JS Doc
Padding is invalid and cannot be removed.
My typescript code is :
let encrypted = CryptoJS.AES.encrypt('Coll#123', '16ad55fd-598b-45d7-a371-a1e011ec1345', {iv: '6fcc45cc3a8a4764'}).ciphertext.toString();
console.log("Encrypted: ", encrypted);
let decrypted = CryptoJS.AES.decrypt(encrypted, "16ad55fd-598b-45d7-a371-a1e011ec1345", {iv: '6fcc45cc3a8a4764'}).toString(CryptoJS.enc.Base64)
console.log("Decrypted: ", decrypted);
My .net code is :
public static string encrypt(string encryptString, string EncryptionKey)
{
Cryptography cript = new Cryptography();
string ivString = AppConstants.EncryptionKey_IV_Default; //16 character IV
string key = cript.getHashSha256(EncryptionKey, 32);
string cipherText = cript.Encrypt(encryptString, key, ivString);
return cipherText;
}
Note: I have not developed the .net code I am consuming someone else API.
Please help I dont know what I am doing wrong here. Is there something which I am missing here.

Related

GCP KMS : Encryption taking place but decryption isn't

I'm working on a project where encryption and decryption is going to be done using GCP KMS. As a part of the POC, I'm trying to create a function which encrypts and decrypts a string using KMS. While I believe encryption is happening properly, the decryption isn't happening as expected. Here is my code :
public String encryptAndDecrypt() throws IOException {
try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
String plaintext = "Just an ordinary string";
CryptoKeyName keyVersionName = CryptoKeyName.of("us-con-gcp-npr-0000305-041421",
"global", "test", "test1");
// Encrypt the plaintext.
EncryptResponse response = client.encrypt(keyVersionName, ByteString.copyFromUtf8(plaintext));
String cipherText = response.getCiphertext().toStringUtf8();
System.out.printf("Ciphertext: %s%n", cipherText);
// Decrypt the ciphertext
DecryptResponse decryptResponse = client.decrypt(keyVersionName, ByteString.copyFrom(cipherText.getBytes()));
System.out.printf("Plaintext: %s%n", decryptResponse.getPlaintext().toStringUtf8());
}
return "Done";
}
I actually got this code from GCP documents. However, I keepgetting this error :
INVALID_ARGUMENT: Decryption failed: the ciphertext is invalid.
Please help
The ciphertext is a byte array and not a UTF8 encoded string. Your code is corrupting the ciphertext.
Change:
String cipherText = response.getCiphertext().toStringUtf8();
To:
byte[] cipherText = response.Ciphertext.ToByteArray();

Encrypt in Java using RSA/ECB/OAEPWithSHA-256AndMGF1Padding, decrypt in c# using OAEPSHA256 Padding

I have a situation where a Java program encrypts text using RSA/ECB/OAEPWithSHA-256AndMGF1Padding.
I need to decrypt it in c#.
Encryption and decryption work fine in Java.
Encryption in Java and decryption in c# with RSA/ECB/OAEPWithSHA-1AndMGF1Padding works absolutely fine.
However, with RSA/ECB/OAEPWithSHA-256AndMGF1Padding encryption in Java and decryption with OaepSHA256 in C# gives me the error : The parameter is incorrect.
Java Code for encrypt:
public static String encrypt(KeyPair keypair, String data) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
Cipher c = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
//Cipher c = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
c.init(Cipher.ENCRYPT_MODE, keypair.getPublic());
return Base64.getEncoder().encodeToString(c.doFinal(data.getBytes()));
}
C # code for decrypt :
public string DecryptRsa(byte[] encryptedBytes, X509Certificate2 x509Certificate2, RSAEncryptionPadding rSAEncryptionPadding)
{
var text = string.Empty;
using (RSACng csp = (RSACng)x509Certificate2.GetRSAPrivateKey())
{
byte[] bytesDecrypted = csp.Decrypt(encryptedBytes, rSAEncryptionPadding);
text = Encoding.UTF8.GetString(bytesDecrypted);
}
return text;
}
What am i doing wrong? Please help.
OAEP uses two digests, the OAEP digest and the MGF1 digest, see RFC8017.
The SunJCE provider specifies with RSA/ECB/OAEPWithSHA-256AndMGF1Padding the OAEP digest as SHA256, while the MGF1 digest defaults to SHA1, see here. The C# code, on the other hand, specifies with OaepSHA256 both digests as SHA256. Therefore, both codes are incompatible.
The fix is to either explicitly specify the digests in Java with OAEPParameterSpec (which should always be done anyway for this very reason). On the C# side, no fix is possible with on board means, since a separate specification of both digests is not supported. But BouncyCastle can be used which supports this.
Fix, Java code side (SHA256 for both digests):
RSAPublicKey publicKey = ...
OAEPParameterSpec oaepParameterSpec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParameterSpec);
byte[] ciphertext = cipher.doFinal(plaintext);
Fix, C# code side, using BouncyCastle (SHA256 for OAEP digest, SHA1 for MGF1 digest):
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Parameters;
...
RsaKeyParameters privateKey = ...
OaepEncoding oaepEncoding = new OaepEncoding(new RsaEngine(), new Sha256Digest(), new Sha1Digest(), null);
oaepEncoding.Init(false, privateKey);
byte[] decrypted = oaepEncoding.ProcessBlock(ciphertext, 0, ciphertext.Length);

AES Encryption In .Net And Decryption In Node JS

I have a simple node js code with crypto js library through which I am decrypting a json object which I will receive from a .net based desktop application, hence the whole process is cross-platform. For testing I can easily encrypt using crypto js library and decrypt the cipher text generated by it. But my doubt is if this method is going to be compatible with encryption in .net. As I'm new to this, so far what I've learned is that the crypto js library generates a random Integration vector (IV) value. If an IV is generated by the .net code as well, do I need to specify it during decryption in node js as well? Currently I'm just using the simple example given in the documentation and no IV or padding is specified and I'm not sure if any default specifications are used by this library. In short I just need to make sure I'm doing this correctly and the method used for decryption won't cause any issues for the encryption part.
var CryptoJS = require("crypto-js");
var aeskey = "bQeThWmZq4t7w!z%C*F-JaNcRfUjXn2r";
var cloudcreds = {
accessKeyId: "abcdef",
accessKeySecret: "zxywvt",
};
//Encryption - Tbd with .net
var encryptedData = CryptoJS.AES.encrypt(
JSON.stringify(cloudcreds),
aeskey
).toString();
console.log("Encrypted Cloud Creds =>", encryptedData);
//Decryption - With node js
var bytes = CryptoJS.AES.decrypt(encryptedData, aeskey);
var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
console.log("Decrypted Cloud Creds => ", decryptedData);
With the crypto module I'm now using my own IV and so far it seems like this could work.
var crypto = require("crypto");
var algorithm = "aes-256-cbc"; //algorithm to use
const key = "3zTvzr3p67VC61jmV54rIYu1545x4TlY"; //create key
var data = {
name: "Catalin",
surname: "Munteanu",
address: "Romania",
};
data = JSON.stringify(data);
const iv = "0000000000000000"; // generate different ciphertext everytime
const cipher = crypto.createCipheriv(algorithm, key, iv);
var encrypted = cipher.update(data, "utf8", "base64") + cipher.final("base64"); // encrypted text
console.log(encrypted);
const decipher = crypto.createDecipheriv(algorithm, key, iv);
var decrypted = decipher.update(encrypted, "base64", "utf8") + decipher.final("utf8"); //deciphered text
console.log(JSON.parse(decrypted));

RSA in C# does not produce same encrypted string for specific keys?

I have a requirement, where I need to encrypt my connection string in one application and decrypt it in another. With this in mind, I save the public key and private keys in App.Config of the application respectively.
Now, shouldn't RSA should give me same encrypted string with same keys which I use?
I get different encrypted strings all the time, with same keys used.!! Please help me to clear the confusion. I am not understanding how I can solve this problem, that I get BAD Data exception if I use the saved encrypted string, as every time the encryption gives me different encrypted strings.
Here is my code:
private string connecString;
private RSACryptoServiceProvider rsaEncryptDecrypt;
public EncryptAndDecrypt(string connecString)
{
this.connecString = connecString;
this.rsaEncryptDecrypt = new RSACryptoServiceProvider(4096);
}
public string EncryptTheConnecString(string publicKeyValue)
{
byte[] encryptedData;
rsaEncryptDecrypt.FromXmlString(publicKeyValue);
byte[] message = Encoding.UTF8.GetBytes(connecString);
encryptedData = rsaEncryptDecrypt.Encrypt(message, false);
return Convert.ToBase64String(encryptedData);
}
public string DecryptTheConnecString(string privateKeyValue, string encrystr)
{
byte[] decryptedData;
rsaEncryptDecrypt.FromXmlString(privateKeyValue);
byte[] message = Convert.FromBase64String(encrystr);
decryptedData = rsaEncryptDecrypt.Decrypt(message, false);
return Encoding.UTF8.GetString((decryptedData));
}
Thank you in advance.
Update 1:
I used
UnicodeEncoding ByteConverter = new UnicodeEncoding();
ByteConverter.GetBytes("data to encrypt");
//Which is not Connection string but a small test str
Still I see that the encrypted data is changing everytime.
But the Bad Data error is no more seen. Yet I cannot use UTF16(UnicodeEncoding) over Encoding.UTF8 because it cannot encrypt the huge string like connection string and throws an exception:
CryptographicException: Key not valid for use in specified state.
Update 2:
I could solve the problem of bad data by using UTF8Encoding ByteConverter = new UTF8Encoding(); and then doing ByteConverter .GetString("HUGE STRING");
It can happen because of Random Padding.
In general the answer to your question is yes, it should always produce the same result if the same parameters are given.
The best way to tackle these issues is to stay as close to the best practice code as possible, currently you a using the crypto provider slightly different than the framework docs propose, see the following:
static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
This is an excerpt from the official MSDN doc:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx
First try and adopt the best practice and then see if this issue still comes up.

AES Java Encryption

I am developing an application in java for a mobile platform. The program uses data from a Windows C# application which encrypts passwords in an online database which the mobile app will use.
The mobile app needs to connect to the database and retrieve the encrypted string from the database and decrypt it.
I have the decryption working fine using the following code
public String decrypt(String encryptedPassword)
{
String plainPassword = "";
try
{
SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");
IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(Base64.decodeBase64(encryptedPassword.getBytes()));
plainPassword = new String(encoded);
}
catch (Exception ex)
{
Log.d("Decryption Error", ex.toString());
}
return plainPassword;
}
The decryption works absolutely fine so I have used the same code from the decryption for the encryption but changed the cipher mode from decrypt to encrypt. However, when I print to the console the encrypted password it prints a load of rubbish which shows no resemblance the string that should be stored in the database.
I have used the following code in order to do the encryption
public String encrypt(String plainPasword)
{
String password = "";
try
{
SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");
IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(plainPasword.getBytes());
password = new String(encoded);
}
catch (Exception ex)
{
Log.d("Encryption Error", ex.toString());
}
return password;
}
Thanks for any help you can give me
In the decryption function you are calling
byte[] encoded = cipher.doFinal(Base64.decodeBase64(encryptedPassword.getBytes()));
so you are converting ASCII bytes to Base64 bytes, then decrypting them.
Wouldn't you do the same in the reverse, when you actually call only
byte[] encoded = cipher.doFinal(plainPasword.getBytes());
You also are creating new String() from byte[] array without specifying encoding, that uses platform's default encoding, not ASCII. That might break stuff too.
If you look at the bytes returned by cipher.doFinal() that's supposed to be gibberish, don't they have any resemblance to the expected data?

Categories