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();
Related
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.
So, what I need is next:
Create certifiactes for development, get one for the client and one for server
Retrieve password through API that is encoded from client and decode it on server
Now, I managed to create certifiactes following this link. The girl there gave step by step instructions on how to get self signed certifiactes, put them in store, etc... Now, the part I'm having problem with:
I've managed to encrypt my data using this code:
public static string Encrypt(string stringForEncription, string PathToPrivateKey)
{
X509Certificate2 myCertificate;
try
{
myCertificate = new X509Certificate2(PathToPrivateKey, "Test123");
}
catch (Exception e)
{
throw new CryptographicException("Unable to open key file.");
}
RSACryptoServiceProvider rsaObj;
if (myCertificate.HasPrivateKey)
{
rsaObj = (RSACryptoServiceProvider)myCertificate.PrivateKey;
}
else
throw new CryptographicException("Private key not contained within certificate.");
if (rsaObj == null)
return String.Empty;
byte[] decryptedBytes;
byte[] array = Encoding.UTF8.GetBytes(stringForEncription);
try
{
decryptedBytes = rsaObj.Encrypt(array, false);
//decryptedBytes = rsaObj.Encrypt(Convert.FromBase64String(Base64EncryptedData), false);
}
catch (Exception e)
{
throw new CryptographicException("Unable to encrypt data.");
}
// Check to make sure we decrpyted the string
if (decryptedBytes.Length == 0)
return String.Empty;
else
return System.Text.Encoding.UTF8.GetString(decryptedBytes);
}
For PathToPrivate key variable I am using the path to my client ClientCert.pfx. I don't know if I should use any other, but here is the snap of the folder with all the certificates that I made:
Now, for the decryption, I'm using next code:
public static string DecryptEncryptedData(string Base64EncryptedData, string PathToPrivateKey)
{
X509Certificate2 myCertificate;
try
{
myCertificate = new X509Certificate2(PathToPrivateKey, "Test123");
}
catch (Exception e)
{
throw new CryptographicException("Unable to open key file.");
}
RSACryptoServiceProvider rsaObj;
if (myCertificate.HasPrivateKey)
{
rsaObj = (RSACryptoServiceProvider)myCertificate.PrivateKey;
}
else
throw new CryptographicException("Private key not contained within certificate.");
if (rsaObj == null)
return String.Empty;
byte[] decryptedBytes;
try
{
decryptedBytes = rsaObj.Decrypt(Convert.FromBase64String(Base64EncryptedData), false);
}
catch (Exception e)
{
throw new CryptographicException("Unable to decrypt data.");
}
// Check to make sure we decrpyted the string
if (decryptedBytes.Length == 0)
return String.Empty;
else
return System.Text.Encoding.UTF8.GetString(decryptedBytes);
}
And whatever I try to do, it gives me exception:
{"The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. "}
Would really apreciate somebody helping me out.
The reason you are getting the error is the string you are trying to Convert.FromBase64String from a value that is not actually a base-64 string.
After encrypting your data, you should convert the byte array to a base-64 string.
Use Convert.ToBase64String for this.
return Convert.ToBase64String(decryptedBytes);
Then your decrypt line will work:
decryptedBytes =
rsaObj.Decrypt(Convert.FromBase64String(Base64EncryptedData), false);
This is not the exact answer which you might expected but I write here as it's too long as a comment.
I think the decryption itself has no problem at all (I've found the example blog of your code with php encryption) That's why I commented I was curious on the encryptedstring which is the target of decryption.
I also struggled in understanding Security for months and now I use symmetric(AES) and asymmetric(RSA) together. Understanding is really important and everybody takes time..
RSA is asymmetric and one-way which means the Encryption can be done only by public key and the Decryption can be done only by private key.
You're using private key in Encryption method and it seems just copied from Decryption.
The answer by Zesty is right only in terms of formatting. You're also needed to understand the formatting. We need Convert.ToBase64String and Convert.FromBase64String in Encryption and Decryption from byte to base64string and vice versa. However this base64string is not just plain like 'hello' but
'SABlAGwAbABvACAAVwBvAHIAbABkAA==' as you see here
And I kindly recommend to use complete solution(not half one like php encryption) like this blog so that Encryption and Decryption and all are in harmony.
And as last as I commented also, you're needed to think about how to prevent the black users if encryption is done from client side and you don't have only good users.
I hope my experience helps to understand Security which is of most importance.
I have below code to encrypt and decrypt the message in c#. when i am trying to run it is giving an exception ie "The data to be decrypted exceeds the maximum for this modulus of 256 bytes"
public static void Main(string[] args)
{
X509Certificate2 cert = new X509Certificate2(#"C:\Data\ABC-rsa-public-key-certificate.cer");
string encryptedText = EncrypIt("Hello", cert);
string decryptedText = DecrptIt(encryptedText, cert);
System.Console.WriteLine(decryptedText);
}
public static string EncrypIt(string inputString, X509Certificate2 cert)
{
RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] plainBytes = Encoding.UTF8.GetBytes(inputString);
byte[] encryptedBytes = publicKey.Encrypt(plainBytes, false);
string encryptedText = Encoding.UTF8.GetString(encryptedBytes);
return encryptedText;
}
public static string DecrptIt(string encryptedText, X509Certificate2 cert)
{
RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] encryptedBytes = Encoding.UTF8.GetBytes(encryptedText);
byte[] decryptedBytes = privateKey.Decrypt(encryptedBytes, false);
string decryptedText = Encoding.UTF8.GetString(decryptedBytes);
return decryptedText;
}
Several problems:
RSA by default only encrypts one block. It's not suitable for long messages. You shouldn't encrypt the message itself with RSA. Generate a random AES key and encrypt the key with RSA and the actual message with AES.
You must use a binary safe encoding such as Hex or Base64 for the ciphertext. Using UTF-8 corrupts the data since it doesn't allow arbitrary byte sequences.
UTF-8 is designed to encode text, so it's fine for your plaintext.
Use OAEP, the old 1.5 padding mode is not secure. i.e. pass true as second parameter to Encrypt/Decrypt. (Technically it's possible to use it securely, but it's tricky and I wouldn't recommend it)
As a further note, once you use AES, there are some more pitfalls: 1) Use a MAC in an encrypt-then-mac scheme, else active attacks including padding-oracles will break your code 2) Use a random IV that's different for each message
RSA should not be used to encrypt this kind of data. You should be encrypting your data with a symmetric key like AES, then encrypting the symmetric key with RSA.
I using RSA(1024) to encrypt/decrypt strings. The encryption is implemented using public key and is written in C#, and the decryption is implementation by c. I encrypt the string:
86afaecb-c211-4d55-8e90-2b715d6d64b9
and write the encrypted data to a file. Then, I using openssl api to read the encrypted data from the file and decrypt it. However, I got the output as:
86afaecb-c211-4d55-8e90-2b715d6d64b9oeheBjQ8fo1AmDnor1D3BLuPyq9wJBAOV+M/WVNYzYr
PJBKoskOj+4LaNpT+SpkfK81nsnQEbHbjgao4eHNU+PmWl9
It seems that there are some trashy padding at the end of original string. Why It Occurs? And how to solve the problem?
Some code snippet is shown below:
// Encrypt
{
string plainData = “86afaecb-c211-4d55-8e90-2b715d6d64b9”;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(paraPub);
byte[] testData = Encoding.UTF8.GetBytes(plainData);
byte[] encryptedData = rsa.Encrypt(testData, true);
FileStream pFileStream = null;
string fileName = "encryptedData.dat";
pFileStream = new FileStream(fileName, FileMode.OpenOrCreate);
pFileStream.Write(encryptedData, 0, encryptedData.Length);
...
}
// Decrypt
{
char *encrypt = malloc(RSA_size(privateKey));
FILE *out = fopen("encryptedData.dat", "r");
int encrypt_len = fread(encrypt, sizeof(*encrypt), RSA_size(privateKey), out);
fclose(out);
decrypt = malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len,
(unsigned char*)encrypt,
(unsigned char*)decrypt,
privateKey, RSA_PKCS1_OAEP_PADDING) == -1) {
// error handle
}
printf("Decrypted message: %s\n", decrypt);
}
I solve the problem by initializing the decrypt using "memset(decrypt, 0, encrypt_len);" after "decrypt = malloc(encrypt_len);". Thx everyone.
The issue is that you should use the decrypted size instead of directly treating the output of the decryption as a null terminated string.
RSA_private_decrypt() returns the size of the recovered plaintext.
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?