I have the following code for encryption and decryption. The problem is that at decryption besides the decrypted text i have some "aaaaa" after the text. why? need some help. THX!
public static byte[] Encrypt(byte[] PlainTextBytes, string key , string InitialVector)
{
try
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Byte[] KeyBytes = encoding.GetBytes(key);
byte[] InitialVectorBytes = encoding.GetBytes(InitialVector);
RijndaelManaged SymmetricKey = new RijndaelManaged();
ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream = new MemoryStream();
CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
CryptoStream.FlushFinalBlock();
byte[] CipherTextBytes = MemStream.ToArray();
return CipherTextBytes;
//decrytion
public static string Decrypt(byte[] PlainTextBytes1, string key, string InitialVector)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Byte[] KeyBytes = encoding.GetBytes(key);
RijndaelManaged SymmetricKey = new RijndaelManaged();
byte[] InitialVectorBytes = Encoding.UTF8.GetBytes(InitialVector);
ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream1 = new MemoryStream(PlainTextBytes1);
CryptoStream CryptoStream = new CryptoStream(MemStream1, Decryptor, CryptoStreamMode.Read);
Byte[] pltxt = new byte[PlainTextBytes1.Length];
CryptoStream.Read(pltxt, 0, pltxt.Length);
ASCIIEncoding textConverter = new ASCIIEncoding();
round = textConverter.GetString(pltxt);
return round;
}
where am i wrong?
In your decrypt function you have:
Byte[] pltxt = new byte[PlainTextBytes1.Length];
This is wrong because the cypher text is longer than the plain text, because it's padded to get a multiple of the block size.
CryptoStream.Read(pltxt, 0, pltxt.Length);
Read returns how many bytes were actually returned. It doesn't guarantee that it will return as many bytes as you requested.
And then there are multiple other defects/bad style things:
The parameter passed into Decrypt is called PlainTextBytes1 it should be called cyphertext.
The way you create the key/initvec bytes from the string. ASCII encoding is a bad choice here. ASCII can't represent any byte string. Perhaps you want to hex en/decode a string of twice the size of the key instead?
ASCII en/decoding the plaintext will only work for ASCII characters and silently corrupt all other characters. Why don't you use UTF-8 instead?
.net naming conventions say you should use lowercase names for parameters
Related
I am looking for a ReactNative equivalent for the following C# Crypto methods. Basically, I am calling a C# API endpoint that requires Json calls to be encrypted. Its also sending back encrypted results using the same Cryptography. The C# methods where provided by my client.
I am fairly new to ReactNative as such I have been unable to successfully reproduced the methods in ReactNative.
I have looked at similar functions online such as one highlighted here but to no avail.
I will higly appreciate your help.
C# METHODS
public string EncryptFromDataObject(string jsonString)
{
byte[] initVectorBytes = Encoding.UTF8.GetBytes(MySecret.sInitVector);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(jsonString);
PasswordDeriveBytes password = new PasswordDeriveBytes(MySecret.sPassPhrase, null);
byte[] keyBytes = password.GetBytes(MySecret.iKeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
//string s = Convert.ToBase64String(cipherTextBytes); // base64 without padding
//s = s.PadRight(s.Length + (s.Length * 3) % 4, '='); // add padding
return Convert.ToBase64String(cipherTextBytes);
}
//Decrypt
public string DecryptToDataObject(string cipherDataObj)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(MySecret.sInitVector);
byte[] cipherTextBytes = Convert.FromBase64String(cipherDataObj);
PasswordDeriveBytes password = new PasswordDeriveBytes(MySecret.sPassPhrase, null);
byte[] keyBytes = password.GetBytes(MySecret.iKeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
string jsonString = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
return jsonString;
}
I actually managed though not by using the above C# class but used the implementation here.
I managed to encrypt from C# and decrypt using ReactNative and vise-versa. The only catch is to make sure that the iv value used in ReactNative is generated is obtained from C# code.
I have a problem when performing a decryption in TRIPLEDES that a provider sends me in HEX: EF69FF79BBD7E8E4EF69FF79BBD7E8E4 with the following key "0123456789ABCDEFFEDCBA9876543210", applying the following method:
public IActionResult GetTokenTemp1()
{
TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
tDESalg.Key = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes("0123456789ABCDEFFEDCBA9876543210"));
byte[] cipherBytes = Convert.FromBase64String("EF69FF79BBD7E8E4EF69FF79BBD7E8E4");
string finalDecrypt = _3desTest.DecryptTextFromMemory(cipherBytes, tDESalg.Key, tDESalg.IV);
return Ok(finalDecrypt);
}
public static string DecryptTextFromMemory(byte[] Data, byte[] Key, byte[] IV)
{
try
{
// Create a new MemoryStream using the passed
// array of encrypted data.
MemoryStream msDecrypt = new MemoryStream(Data);
TripleDESCryptoServiceProvider de = new TripleDESCryptoServiceProvider();
var descritor = de.CreateDecryptor(Key, IV);
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
CryptoStream csDecrypt = new CryptoStream(msDecrypt,
descritor,
CryptoStreamMode.Read);
// Create buffer to hold the decrypted data.
byte[] fromEncrypt = new byte[Data.Length];
// Read the decrypted data out of the crypto stream
// and place it into the temporary buffer.
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
string es = new UTF8Encoding().GetString(fromEncrypt);
//Convert the buffer into a string and return it.
return new UTF8Encoding().GetString(fromEncrypt);
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
}
When I leave the default padding or any other to zero or none, I get the following error "adding is invalid and cannot be removed.",
but when I leave the padding at zero or none tripleDescryptorService.Padding = PaddingMode.None I get a format:
padding.none
I don't know what to do very well, when I do it on this page:
https://neapay.com/online-tools/des-calculator.html?data=EF69FF79BBD7E8E4EF69FF79BBD7E8E4&key=0123456789ABCDEFFEDCBA9876543210&algo=3DES&decr=true
I get the desired result.
I'm already desperate, I'm not very expert in encryption.
Thank you so much
The website uses neither a padding nor an IV. Therefore in the code the padding must be disabled and the ECB mode must be applied.
Furthermore the website expects a hex encoded key and ciphertext and returns the decrypted data also hex encoded, which therefore must not be UTF-8 decoded in the code:
public static byte[] DecryptTextFromMemory(byte[] encryptedData, byte[] key)
{
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider())
{
tripleDES.Key = key;
tripleDES.Padding = PaddingMode.None;
tripleDES.Mode = CipherMode.ECB;
byte[] decryptedData = new byte[encryptedData.Length];
using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
{
ICryptoTransform decryptor = tripleDES.CreateDecryptor(tripleDES.Key, null);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
csDecrypt.Read(decryptedData, 0, decryptedData.Length);
}
}
return decryptedData;
}
}
For the hex encoding and decoding you can use arbitrary methods, e.g. from here.
With this the code:
byte[] data = HexStringToByteArray("EF69FF79BBD7E8E4EF69FF79BBD7E8E4");
byte[] key = HexStringToByteArray("0123456789ABCDEFFEDCBA9876543210");
Console.WriteLine(ByteArrayToHexString(DecryptTextFromMemory(data, key)));
returns the result of the website:
00000000003331720000000000333172
Please note: Your last change is not useful because it applies conversions and algorithms that are not consistent with the website.
I am getting an error while decrypting and encrypted string:
5duOH+Tlg5deIrWZiHoNaQ==wVxXSl9pFu6A8h14/nLdyBkDzO4xmec7PQ0cB7MHjCDqhSRum3C7I1OfqL1rEWbNonU/ayCaJS18zV7ivQQU7A==MBJzKMrrrbmc2/vBZSPDkQ==I09Kj25UO+LcmRzgoqTT2g==+Fkm9VCGplEK6eEyHyEtuEodKSbckC07M2FShu2ukCg=
Error is as follows:
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.
My encryption code is:
public string EncryptQueryString(string inputText, string key, string salt)
{
byte[] plainText = Encoding.UTF8.GetBytes(inputText);
using (RijndaelManaged rijndaelCipher = new RijndaelManaged())
{
PasswordDeriveBytes secretKey = new PasswordDeriveBytes(Encoding.ASCII.GetBytes(key), Encoding.ASCII.GetBytes(salt));
using (ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(secretKey.GetBytes(32), secretKey.GetBytes(16)))
using (MemoryStream memoryStream = new MemoryStream())
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainText, 0, plainText.Length);
cryptoStream.FlushFinalBlock();
string base64 = Convert.ToBase64String(memoryStream.ToArray());
// Generate a string that won't get screwed up when passed as a query string.
string urlEncoded = HttpUtility.UrlEncode(base64);
return urlEncoded;
}
}
}
Decryption:
public string DecryptQueryString(string inputText, string key, string salt)
{
byte[] encryptedData = Convert.FromBase64String(inputText);
PasswordDeriveBytes secretKey = new PasswordDeriveBytes(Encoding.ASCII.GetBytes(key), Encoding.ASCII.GetBytes(salt));
using (RijndaelManaged rijndaelCipher = new RijndaelManaged())
using (ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16)))
using (MemoryStream memoryStream = new MemoryStream(encryptedData))
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainText = new byte[encryptedData.Length];
cryptoStream.Read(plainText, 0, plainText.Length);
string utf8 = Encoding.UTF8.GetString(plainText);
return utf8;
}
}
Base64 padding consists of = or ==, and so it looks like multiple Base64 strings where appended together somehow. You'll have to find where they all originally ended, split them there, and try again.
Note that Base64 strings do not always have padding, only when it is needed, so there may even need to be breaks in places that you cannot see here.
I am currently working on a project assigned by my teacher and I need to ensure the application it has strong encryption. Below is my encrypt method:
private String Encrypt(string text)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
string Password = System.Configuration.ConfigurationManager.AppSettings["Password"];
byte[] PlainText = System.Text.Encoding.Unicode.GetBytes(TextBox1.Text);
byte[] Salt = Encoding.ASCII.GetBytes(Password.Length.ToString());
PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(Password, Salt);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(PlainText, 0, PlainText.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string EncryptedData = Convert.ToBase64String(CipherBytes);
return EncryptedData;
}
This is my Decrypt Method
public string Decrypt(string encrypted)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
string Password = System.Configuration.ConfigurationManager.AppSettings["Password"];
string DecryptedData;
try
{
byte[] EncryptedData = Convert.FromBase64String(TextBox2.Text);
byte[] Salt = Encoding.ASCII.GetBytes(Password.Length.ToString());
PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(Password, Salt);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));
MemoryStream memoryStream = new MemoryStream(EncryptedData);
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] PlainText = new byte[EncryptedData.Length];
int DecryptedCount = cryptoStream.Read(PlainText, 0, PlainText.Length);
memoryStream.Close();
cryptoStream.Close();
DecryptedData = Encoding.Unicode.GetString(PlainText, 0, DecryptedCount);
}
catch
{
DecryptedData = TextBox3.Text;
}
return DecryptedData;
}
As you can see from my codes, I am using the password from the web config and I do not store any IV and key into the database. So my question is if the encryptions method that I use is as secure as using AES method. If it isn't, is there any other possible solutions that I can refer to? Thanks for replying and sorry for my poor english skills.
This bad in several ways:
It's unauthenticated. Add a MAC on use an existing authenticated algorithm like AES-GCM, AES-SIV.
The salt is derived deterministically from the password, which is equivalent to using no salt at all. Each user needs to use a different salt.
Similar to the salt, the point of an IV is to ensure that encrypting similar or identical plaintexts using a fixed key produces completely different outputs every time. If your key is single-use (e.g. because its derivation involves a single-use salt), a fixes IV would be acceptable.
PasswordDeriveBytes is a mix of PBKDF1 and undocumented Microsoft specific extensions. Don't use it. At minimum use Rfc2898DeriveBytes which is standard compliant PBKDF2-HMAC-SHA1. Using about 100000 iterations, instead of the much too small default.
I recommend using jbtule's answer to Encrypt and decrypt a string in C#
I want to pass an id to QueryString of my webpage, as I don't want visitors to see the number, I encode it using RijndaelManaged algorithm, My issue is, this encryption sometimes add a character for example '+' which causes double escape sequence error.
I was wondering if there is way to exclude some characters from encryption output.
My encryption code is as below:
public static string Encrypt(string plainText)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
byte[] cipherTextBytes;
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
cipherTextBytes = memoryStream.ToArray();
cryptoStream.Close();
}
memoryStream.Close();
}
return Convert.ToBase64String(cipherTextBytes);
}
You could convert your bytearray to a Hex string instead of a base64 string. Hex will only contain [a-f0-9]
See this question for details.
But as for your original Problem: you should really use URL encoding for your query strings, which will solve the Problem of the + character.