I have an Encrypted string and function to decrypt it. Now I need to edit this string and encrypt it. When I use this function to encrypt and decrypt in result strings are not the same.
Orginal encrypted string:
APpuC6G3f3cUKaAuOFXOGIo9rwz/+fQ0tBCi6Fk40THVnIT+au7JXkOQHdgPcpQ3VUrXw69rIL+QRsHea5+Q6TxOeuAnzkU8c3UClx6Toe+jOIVi3DlkLIGzE8DmyBArtZYpKTOt4rrOSDyLKifdgcM+MgwuJbDXyXVuQyp2C42zZ1ETPUOF2TSIZKhnMSR43FFy8WEbpKBAjkPmgVpqqhrjabu+JHbj7kPIxGGjDHGaCCyCtFwsk3264Lv4GTp049SCjNNYV0NVcN4wV0MaWMEO0iLuNGkseHuu5Snvp3YzZfXxDBWSLOUXc2zeXL2tA6So9WA5P3lZ/ga5i366EQ==
Orginal encrypted string after decrypt:
{"status":"PASS","data":{"map_path":"VOtKu0.yGT","file_extension":"KAmXWV","username":"damianek","timestamp":9999999999},"message":"Logged in successfully. Your license will run out at 2021-12-03 18:41:39"}
Orginal decrypt function:
public static string Decypher(string var1)
{
var1 = var1.Trim();
byte[] array = Convert.FromBase64String(var1);
byte[] array2 = new byte[16];
byte[] array3 = new byte[32];
byte[] array4 = new byte[array.Length - 48];
for (int i = 0; i < 16; i++)
{
array2[i] = array[i];
}
for (int j = 16; j < 48; j++)
{
array3[j - 16] = array[j];
}
for (int k = 48; k < array.Length; k++)
{
array4[k - 48] = array[k];
}
ivv = array2;
Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Key = GetToken();
aes.IV = array2;
MemoryStream memoryStream = new MemoryStream();
ICryptoTransform transform = aes.CreateDecryptor();
CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write);
string result = string.Empty;
try
{
cryptoStream.Write(array4, 0, array4.Length);
cryptoStream.FlushFinalBlock();
byte[] array5 = memoryStream.ToArray();
result = Encoding.ASCII.GetString(array5, 0, array5.Length);
memoryStream.Close();
cryptoStream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace);
}
return result;
}
My encrypt function:
public void EncryptStringToBytes()
{
string plainText = textBox2.Text;
byte[] array = Encoding.UTF8.GetBytes(plainText);
byte[] encrypted;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = GetToken();
aesAlg.IV = new byte[16];
aesAlg.Mode = CipherMode.CBC;
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
textBox3.Text = Convert.ToBase64String(encrypted);
}
String after my encrypt & decrypt with orginal function:
?%j>]???r?????":"KAmXWV","username":"damianek","timestamp":1637955589},"message":"Logged in successfully. Your license will run out at 2021-12-03 18:41:39"}
EDIT:
Now encrypt function look:
public void EncryptStringToBytes()
{
string plainText = textBox2.Text.Trim();
byte[] array = Encoding.ASCII.GetBytes(plainText);
byte[] encrypted;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = GetToken();
aesAlg.IV = GetIV();
aesAlg.Mode = CipherMode.CBC;
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (var msEncrypt = new MemoryStream())
{
msEncrypt.Write(aesAlg.Key, 0, aesAlg.Key.Length);
msEncrypt.Flush();
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(aesAlg.Key, 0, aesAlg.Key.Length);
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
textBox3.Text = Convert.ToBase64String(encrypted);
}
But string after encrypt & decrypt look:
;???En Dp??g???{"status":"PASS","data":{"map_path":"VOtKu0.yGT","file_extension":"KAmXWV","username":"damianek","timestamp":1637955589},"message":"Logged in successfully. Your license will run out at 2021-12-03 18:41:39"}
My C# AES implementation
from my answer AES Crypto C# compatible Java
The IV is randomized in every Encrypt process to get different output with same text and avoid to intruders/attackers get original text easily.
The default mode is CBC.
The encoding used is UTF-8. UTF-8 is the most widely used encoding on the web.
You can test/run this code on https://replit.com/#JomaCorpFX/AesCbcEncrypt#main.cs
The code
using System;
using System.Security.Cryptography;
using System.Text;
public enum HashAlgorithm
{
MD5,
SHA1,
SHA256,
SHA384,
SHA512
}
public class HashManager
{
public static byte[] ToRawHash(byte[] data, HashAlgorithm algorithm)
{
byte[] hash;
switch (algorithm)
{
case HashAlgorithm.MD5:
MD5 md5 = MD5.Create();
hash = md5.ComputeHash(data, 0, data.Length);
return hash;
case HashAlgorithm.SHA1:
SHA1Managed sha1 = new SHA1Managed();
hash = sha1.ComputeHash(data);
return hash;
case HashAlgorithm.SHA256:
SHA256Managed sha256 = new SHA256Managed();
hash = sha256.ComputeHash(data);
return hash;
case HashAlgorithm.SHA384:
SHA384Managed sha384 = new SHA384Managed();
hash = sha384.ComputeHash(data);
return hash;
case HashAlgorithm.SHA512:
SHA512Managed sha512 = new SHA512Managed();
hash = sha512.ComputeHash(data, 0, data.Length);
return hash;
default:
throw new ArgumentException("Invalid Algorithm");
}
}
}
public class AesManager
{
private const int MAX_IV_LENGTH = 16;
private const int MAX_KEY_LENGTH = 32;
private static byte[] GenerateValidKey(byte[] keyBytes)
{
byte[] ret = new byte[MAX_KEY_LENGTH];
byte[] hash = HashManager.ToRawHash(keyBytes, HashAlgorithm.SHA256);
Array.Copy(hash, ret, MAX_KEY_LENGTH);
return ret;
}
public static byte[] EncryptRaw(byte[] PlainBytes, byte[] Key)
{
AesManaged AesAlgorithm = new AesManaged()
{
Key = GenerateValidKey(Key)
};
AesAlgorithm.GenerateIV();
var Encrypted = AesAlgorithm.CreateEncryptor().TransformFinalBlock(PlainBytes, 0, PlainBytes.Length);
byte[] ret = new byte[Encrypted.Length + MAX_IV_LENGTH];
Array.Copy(Encrypted, ret, Encrypted.Length);
Array.Copy(AesAlgorithm.IV, 0, ret, ret.Length - MAX_IV_LENGTH, MAX_IV_LENGTH);
return ret;
}
public static byte[] DecryptRaw(byte[] CipherBytes, byte[] Key)
{
AesManaged AesAlgorithm = new AesManaged()
{
Key = GenerateValidKey(Key)
};
byte[] IV = new byte[MAX_IV_LENGTH];
Array.Copy(CipherBytes, CipherBytes.Length - MAX_IV_LENGTH, IV, 0, MAX_IV_LENGTH);
AesAlgorithm.IV = IV;
byte[] RealBytes = new byte[CipherBytes.Length - MAX_IV_LENGTH];
Array.Copy(CipherBytes, RealBytes, CipherBytes.Length - MAX_IV_LENGTH);
return AesAlgorithm.CreateDecryptor().TransformFinalBlock(RealBytes, 0, RealBytes.Length); ;
}
public static String EncryptToBase64(String Plaintext, String Key)
{
byte[] PlainBytes = Encoding.UTF8.GetBytes(Plaintext);
return Base64Manager.ToBase64(EncryptRaw(PlainBytes, Encoding.UTF8.GetBytes(Key)), false);
}
public static String DecryptFromBase64(String CipherText, String Key)
{
byte[] CiPherBytes = Base64Manager.Base64ToByteArray(CipherText);
byte[] Encrypted = DecryptRaw(CiPherBytes, Encoding.UTF8.GetBytes(Key));
return Encoding.UTF8.GetString(Encrypted, 0, Encrypted.Length);
}
}
public class Base64Manager
{
public static byte[] Base64ToByteArray(String base64)
{
return Convert.FromBase64String(base64);
}
public static String ToBase64(byte[] data, Boolean insertLineBreaks = default(Boolean))
{
return insertLineBreaks ? Convert.ToBase64String(data, Base64FormattingOptions.InsertLineBreaks) : Convert.ToBase64String(data);
}
}
public class Program
{
public static void Main()
{
Console.Write("Plain text: ");
string plainText = Console.ReadLine();
Console.Write("Password: ");
string password = Console.ReadLine();
string encrypted = AesManager.EncryptToBase64(plainText, password);
Console.WriteLine();
Console.WriteLine($"Password: {password}" );
Console.WriteLine();
Console.WriteLine($"Encrypted: {encrypted}");
Console.WriteLine();
Console.WriteLine($"Decrypted: {AesManager.DecryptFromBase64(encrypted, password)}");
Console.ReadLine();
}
}
Output
Related
I'm in the middle of porting an older application to .Net 6, and have hit a stumbling block of the encryption / decryption method is now failing. It still works perfectly fine under .Net 4.x.x.
The error being thrown is,
"Padding is invalid and cannot be removed."
Code: - Updated to actual original code. This code worked fine when targeting .Net 4.7.2, however after moving the code to .Net 6.0 RC2, it started to lose anything greater than 32 chars of the decrypted string, which lead to errors elsewhere as the strings weren't complete.
For context. This was running on a webhost & a desktop client, to encrypt messages in transit. The webhost has been updated and validated to be sending the correct encrypted value (decrypting the message using the .Net 4 client is successful). However, the .Net 6 desktop client isn't decrypting it correctly and is losing characters in the decrypted string.
#region Encrypt method(s)
private const int Keysize = 256;
private const int Blocksize = 128;
private const int DerivationIterations = 1000;
public async Task<string> EncryptStringWithValidatedPadding(string plainText, string passPhrase)
{
string encrypted = null;
bool valid = false;
while (!valid)
{
encrypted = await Encrypt(plainText, passPhrase);
if (!string.IsNullOrEmpty(await Decrypt(encrypted, passPhrase)))
{
valid = true;
}
}
return encrypted;
}
private async Task<string> Encrypt(string plainText, string passPhrase)
{
var saltStringBytes = GenerateRandomEntropy(32); // 256 bits
var ivStringBytes = GenerateRandomEntropy(16); // 128 bits
byte[] plainTextBytes = Convert.FromBase64String(plainText);
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new AesManaged())
{
symmetricKey.KeySize = Keysize;
symmetricKey.BlockSize = Blocksize;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
var encrypted64String = Convert.ToBase64String(cipherTextBytes);
return encrypted64String;
}
}
}
}
}
}
private static byte[] GenerateRandomEntropy(int byteSize)
{
var randomBytes = new byte[byteSize];
using (var rngCsp = new RNGCryptoServiceProvider())
{
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
#endregion
#region Decrypt method
public static async Task<string> Decrypt(string cipherText, string passPhrase)
{
try
{
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Blocksize / 8).ToArray();
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) + Blocksize / 8).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) + Blocksize / 8)).ToArray();
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new AesManaged())
{
symmetricKey.KeySize = 256;
symmetricKey.BlockSize = Blocksize;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}
#endregion
This is called with,
encryptedString = await new EncryptDecrypt().EncryptStringWithValidatedPadding(b64String, Convert.ToBase64String(Encoding.UTF8.GetBytes(passPhrase)));
I am assuming that saving the IV should solve this, but I'm wondering if there are any obvious flaws here that I'm just not seeing.
Can anyone explain it?
Update: As suggested I've refactored the code to the below. I've also stripped it right back for the minute to ensure the underlying algo's work.
Ref: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-6.0
namespace Encryption_Helper
{
public class EncryptDecrypt
{
#region Encrypt method(s)
private static byte[] bytes = new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 };
private const int Keysize = 256;
private const int Blocksize = 128;
private const int DerivationIterations = 1000;
public static async Task<string> EncryptStringWithValidatedPadding(string plainText, string passPhrase)
{
string encrypted = null;
bool valid = false;
while (!valid)
{
encrypted = await Encrypt(plainText, passPhrase);
if (!string.IsNullOrEmpty(await Decrypt(encrypted, passPhrase)))
{
valid = true;
}
}
return encrypted;
}
private static async Task<string> Encrypt(string plainText, string passPhrase)
{
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), bytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
var ivBytes = password.GetBytes(Blocksize / 8);
using (var aes = Aes.Create())
{
aes.Key = keyBytes;
aes.IV = ivBytes;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
plainText = Convert.ToBase64String(msEncrypt.ToArray());
}
}
}
return plainText;
}
}
#endregion
#region Decrypt method
public static async Task<string> Decrypt(string cipherText, string passPhrase)
{
try
{
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), bytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
var ivBytes = password.GetBytes(Blocksize / 8);
using (var aes = Aes.Create())
{
aes.Key = keyBytes;
aes.IV = ivBytes;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (var memoryStream = new MemoryStream(Convert.FromBase64String(cipherText)))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(cryptoStream))
{
cipherText = srDecrypt.ReadToEnd();
}
}
}
return cipherText;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
#endregion
}
}
It is still throwing a padding error!
Solved it!
public class EncryptDecrypt
{
#region Encrypt method(s)
private const int Keysize = 256;
private const int Blocksize = 128;
private const int DerivationIterations = 1000;
public static async Task<string> EncryptStringWithValidatedPadding(string plainText, string passPhrase)
{
string encrypted = null;
bool valid = false;
while (!valid)
{
encrypted = await Encrypt(plainText, passPhrase);
if (!string.IsNullOrEmpty(await Decrypt(encrypted, passPhrase)))
{
valid = true;
}
}
return encrypted;
}
private static async Task<string> Encrypt(string plainText, string passPhrase)
{
var saltStringBytes = GenerateRandomEntropy(Keysize / 8); // 256 bits
var ivStringBytes = GenerateRandomEntropy(Blocksize / 8); // 128 bits
byte[] plainTextBytes = Convert.FromBase64String(plainText);
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var aes = Aes.Create())
{
aes.KeySize = Keysize;
aes.BlockSize = Blocksize;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(keyBytes, ivStringBytes), CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
var encrypted64String = Convert.ToBase64String(cipherTextBytes);
return encrypted64String;
}
}
}
}
}
private static byte[] GenerateRandomEntropy(int byteSize)
{
var randomBytes = new byte[byteSize];
using (var rngCsp = new RNGCryptoServiceProvider())
{
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
#endregion
#region Decrypt method
public static async Task<string> Decrypt(string cipherText, string passPhrase)
{
try
{
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Blocksize / 8).ToArray();
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) + Blocksize / 8).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) + Blocksize / 8)).ToArray();
using (var password = new Rfc2898DeriveBytes(Convert.FromBase64String(passPhrase), saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var aes = Aes.Create())
{
aes.KeySize = Keysize;
aes.BlockSize = Blocksize;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using (var ms = new MemoryStream(cipherTextBytes))
{
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(keyBytes, ivStringBytes), CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(cs))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
cipherText = srDecrypt.ReadToEnd();
}
}
}
return cipherText;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}
#endregion
After updating the decryption method, all's good in the world again.
It appears to me that .Net 6 broke the nested using loops, closing the stream before the return value was completely set.
I created public and private keys (pem) with openSsl tool. I used commands:
openssl genrsa -out privatekey.pem 2048
openssl req -new -key privatekey.pem -x509 -days 3650 -out publiccert.pem
Then I generate aesKey:
byte[] GenerateAesKey()
{
var rnd = new RNGCryptoServiceProvider();
var b = new byte[16];
rnd.GetNonZeroBytes(b);
return b;
}
My method for encrypt data:
string CreateSecurePayload(byte[] aesKey)
{
object obj = new
{
contact = new
{
email = "myName#email.com",
firstName = "John",
lastName = "Doe"
}
};
var json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
var res = "";
using (Aes myRijndael = Aes.Create())
{
byte[] encrypted = EncryptStringToBytes(json, aesKey, myRijndael.IV);
res = Convert.ToBase64String(encrypted);
}
return res;
}
byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
byte[] encrypted;
using (Aes rijAlg = Aes.Create())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
return encrypted;
}
And then I encrypt my aesKey with private key:
string SecureKey(byte[] aesKey)
{
byte[] plainTextBytes = aesKey;
AsymmetricCipherKeyPair keys;
FileStream fileStream = new FileStream("path/to/privatekey.pem", FileMode.Open);
using (var reader = new StreamReader(fileStream))
{
var pr = new PemReader(reader);
keys = (AsymmetricCipherKeyPair)pr.ReadObject();
}
var eng = new OaepEncoding(new RsaEngine());
eng.Init(true, keys.Private);
int length = plainTextBytes.Length;
int blockSize = eng.GetInputBlockSize();
var cipherTextBytes = new List<byte>();
for (int chunkPosition = 0;
chunkPosition < length;
chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
cipherTextBytes.AddRange(eng.ProcessBlock(
plainTextBytes, chunkPosition, chunkSize
));
}
return Convert.ToBase64String(cipherTextBytes.ToArray());
}
Call methods:
void Main()
{
var aesKey = GenerateAesKey();
var encryptData = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
securePayload = CreateSecurePayload(aesKey),
secureKey = SecureKey(aesKey)
});
}
I have a problem. Service does not decrypt my data with public key. I upload public key earlier in service.
Could you help me? Thanks
And I have examples of how I can encrypt data but in other languages:
I got the example, but on JS. I think I have a problem with IV, because I don`t send it
Here is the class that help you to perform Encryption/Decryption:
public static class DecryptionHelper
{
private static string EncryptionDecryptionKey = "your_key";
public static string Encrypt(string Text)
{
//var key = GenerateKey();
var key = Encoding.UTF8.GetBytes(EncryptionDecryptionKey);
var plainText = Text;
var encryptedData = EncryptStringToBytes(key, plainText);
return Convert.ToBase64String(encryptedData);
}
public static string Decrypt(string Text)
{
//var key = GenerateKey();
var key = Encoding.UTF8.GetBytes(EncryptionDecryptionKey);
byte[] encryptedData = Convert.FromBase64String(Text);
var decryptedData = DecryptBytesToString(key, encryptedData);
return decryptedData;
}
private static string DecryptBytesToString(byte[] key, byte[] data)
{
// IV was prepended to the encrypted bytes so peel that off
Tuple<byte[], byte[]> splitResult = SplitByteArray(data);
byte[] iv = splitResult.Item1;
byte[] cipherText = splitResult.Item2;
// Declare the string used to hold the decrypted text.
string plaintext;
// Create an RijndaelManaged object
// with the specified key and IV.
using (var aes = CreateAes256Algorithm())
{
aes.Key = key;
aes.IV = iv;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// 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();
}
}
}
}
return plaintext;
}
private static Tuple<byte[], byte[]> SplitByteArray(byte[] data)
{
byte[] first = new byte[16];
Buffer.BlockCopy(data, 0, first, 0, first.Length);
byte[] second = new byte[data.Length - first.Length];
Buffer.BlockCopy(data, first.Length, second, 0, second.Length);
return Tuple.Create(first, second);
}
private static byte[] GenerateKey()
{
using (var aes = CreateAes256Algorithm())
{
aes.GenerateKey();
return aes.Key;
}
}
private static RijndaelManaged CreateAes256Algorithm()
{
return new RijndaelManaged { KeySize = 256, BlockSize = 128 };
}
private static byte[] EncryptStringToBytes(byte[] key, string plainText)
{
byte[] encrypted;
byte[] iv;
// Create an RijndaelManaged object with the specified key and IV.
using (var aes = CreateAes256Algorithm())
{
aes.Key = key;
aes.GenerateIV();
iv = aes.IV;
// Create a encrytor to perform the stream transform.
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
// Create the streams used for encryption.
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
// convert stream to bytes
encrypted = msEncrypt.ToArray();
}
}
}
// Prepend the iV to the encrypted bytes
return CombineByteArrays(iv, encrypted);
}
private static byte[] CombineByteArrays(byte[] first, byte[] second)
{
byte[] ret = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, ret, 0, first.Length);
Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
return ret;
}
}
Then to use it like:
Keys.FacebookClientId = DecryptionHelper.Decrypt(FacebookClientId);
using System;
using System.Text;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Encodings;
using System.Security.Cryptography;
using System.IO;
public static string CreateSecureLoad(string unencryptedPayload, ref byte[] generatedAesKey)
{
// This method generates and returns a secure payload
RijndaelManaged cryptoAlgo = new RijndaelManaged
{
Padding = PaddingMode.PKCS7,
Mode = CipherMode.ECB,
KeySize = 128,
BlockSize = 128
};
generatedAesKey = cryptoAlgo.Key;
var clearTextArray = Encoding.UTF8.GetBytes(unencryptedPayload);
var encryptor = cryptoAlgo.CreateEncryptor();
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(
msEncrypt,
encryptor,
CryptoStreamMode.Write))
{
csEncrypt.Write(clearTextArray);
csEncrypt.FlushFinalBlock();
var cipher = msEncrypt.ToArray();
return Convert.ToBase64String(cipher);
}
}
}
public static string CreateSecureKey(byte[] aesKey, string privateKeyPEM)
{
// This method generates and returns a secure key
// Accepts the string contents of the private key PEM file as input
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var textReader = new StringReader(privateKeyPEM))
{
var pemReader = new PemReader(textReader);
var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
encryptEngine.Init(true, keyPair.Private);
}
var encrypted = Convert.ToBase64String(
encryptEngine.ProcessBlock(
aesKey,
0,
aesKey.Length));
return encrypted;
}
static void Main(string[] args)
{
String payload = "some json";
byte[] generatedAesKey = new byte[16];
var privateKeyPEM = File.ReadAllText("privatekey.pem");
var securePayload = CreateSecureLoad(payload, ref generatedAesKey);
var secureKey = CreateSecureKey(generatedAesKey, privateKeyPEM);
// Return encrypted key
Console.WriteLine("secureKey: " + secureKey);
// Return encrypted payload
Console.WriteLine("securePayload: " + securePayload);
Console.ReadLine();
}
}
encryption in this way works fine but when i try to use Decrypt it gives me padding Error i don't know why ?? Here is main Method and used Key & IV Value.
& BaseEncryptor Class Where i Use Encryption & Decryption Method
I tried uesing every type in padding but it also doesn't work.I tried to change block size and key size it also doesn't work.
static void Main(string[] args)
{
string key = "ldm_encrypt_code1234567891234567";
string IV = "9876897123651785";
string encstr = BaseEncryptor.EncryptUsingAes(Encoding.UTF8.GetBytes(#"Hello Code"), Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(IV)); //Encryption
string xc=BaseEncryptor.Decrypt(Encoding.UTF8.GetBytes(encstr), Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(IV)); //Decryption way
}
public class BaseEncryptor
{
public static string EncryptUsingAes(byte[] inputTextByte, byte[] privateKeyByte, byte[] sharedIVKeyByte)
{
using (var aesEncryption = AesEncryptionType(privateKeyByte, sharedIVKeyByte))
{
// Convert string to byte array
byte[] dest = new byte[inputTextByte.Length];
// encryption
using (ICryptoTransform encrypt = aesEncryption.CreateEncryptor(aesEncryption.Key, aesEncryption.IV))
{
dest = encrypt.TransformFinalBlock(inputTextByte, 0, inputTextByte.Length);
encrypt.Dispose();
}
return BitConverter.ToString(dest).Replace("-", "");
}
}
public static AesCryptoServiceProvider AesEncryptionType(byte[] privateKeyByte, byte[] sharedIVKeyByte)
{
//used in both encryption & Decryption
var aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.IV = sharedIVKeyByte;
aes.Key = privateKeyByte;
aes.Mode = CipherMode.CBC; //Mode
aes.Padding = PaddingMode.PKCS7; //Padding not working in case of none or Zeros
return aes;
}
public static string DecryptUsingAes(byte[] inputTextByte, byte[] privateKeyByte, byte[] sharedIVKeyByte)
{
using (var aesDecryption = AesEncryptionType(privateKeyByte, sharedIVKeyByte))
{
// Convert string to byte array
byte[] dest = new byte[inputTextByte.Length];
// encryption
using (ICryptoTransform decrypt = aesDecryption.CreateDecryptor(aesDecryption.Key, aesDecryption.IV))
{
dest = decrypt.TransformFinalBlock(inputTextByte, 0, inputTextByte.Length);
decrypt.Dispose();
}
// Convert byte array to UTF8 string
return Encoding.UTF8.GetString(dest); ;
}
}
public static string Decrypt(byte[] cipherText, byte[] Key, byte[] IV)
{
string plaintext = null;
// Create AesManaged
using (var aesDecryption = AesEncryptionType(Key, IV))
{
// Create a decryptor
// Create the streams used for decryption.
using (ICryptoTransform decryptor = aesDecryption.CreateDecryptor(Key, IV))
{
string result;
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
result = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
}
}
I encrypt password in postgres
and i want to decrypt it in c#, but two ways can not matching
.How can i do that?
private static byte[] TruncateHash(string key, int length)
{
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
// Hash the key.
byte[] keyBytes = System.Text.Encoding.Unicode.GetBytes(key);
byte[] hash = sha1.ComputeHash(keyBytes);
// Truncate or pad the hash.
Array.Resize(ref hash, length);
return hash;
}
public static string EncryptString(string plaintext, string Passphrase)
{
TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
// Initialize the crypto provider.
tripleDes.Key = TruncateHash(Passphrase, tripleDes.KeySize / 8);
tripleDes.IV = TruncateHash("", tripleDes.BlockSize / 8);
// Convert the plaintext string to a byte array.
byte[] plaintextBytes = System.Text.Encoding.Unicode.GetBytes(plaintext);
// Create the stream.
System.IO.MemoryStream ms = new System.IO.MemoryStream();
// Create the encoder to write to the stream.
CryptoStream encStream = new CryptoStream(ms, tripleDes.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write);
// Use the crypto stream to write the byte array to the stream.
encStream.Write(plaintextBytes, 0, plaintextBytes.Length);
encStream.FlushFinalBlock();
// Convert the encrypted stream to a printable string.
return Convert.ToBase64String(ms.ToArray());
}
public static string DecryptString(string encryptedtext, string Passphrase)
{
TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
// Initialize the crypto provider.
tripleDes.Key = TruncateHash(Passphrase, tripleDes.KeySize / 8);
tripleDes.IV = TruncateHash("", tripleDes.BlockSize / 8);
// Convert the encrypted text string to a byte array.
byte[] encryptedBytes = Convert.FromBase64String(encryptedtext);
// Create the stream.
System.IO.MemoryStream ms = new System.IO.MemoryStream();
// Create the decoder to write to the stream.
CryptoStream decStream = new CryptoStream(ms, tripleDes.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write);
// Use the crypto stream to write the byte array to the stream.
decStream.Write(encryptedBytes, 0, encryptedBytes.Length);
decStream.FlushFinalBlock();
// Convert the plaintext stream to a string.
return System.Text.Encoding.Unicode.GetString(ms.ToArray());
}
I found a way to encrypt in postgres using pgcrypto.
And below is encrypt and decrypt in postgres.
SELECT encode(encrypt_iv('ABCDE121212','Key123', '','3des'), 'base64');
select decrypt_iv(decode('jEI4V5q6h5/p12NRJm666g==','base64'),'Key123','','3des')
What's wrong in my code, c# and postgres can't not matching.
I want to keep c# code and change postgres code to matching
Source Url
Encrypt function:
public static String AES_encrypt(String input, string key, string Iv, int keyLength)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = keyLength;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = mkey(key,keyLength);
aes.IV = mkey(Iv,128);
var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] xBuff = null;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
{
byte[] xXml = Encoding.UTF8.GetBytes(input);
cs.Write(xXml, 0, xXml.Length);
cs.FlushFinalBlock();
}
xBuff = ms.ToArray();
}
return Convert.ToBase64String(xBuff,Base64FormattingOptions.None);
}
Decrypt function:
public static String AES_decrypt(String Input, string key, string Iv, int keyLength)
{
try
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = keyLength;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = mkey(key,keyLength);
aes.IV = mkey(Iv,128);
var decrypt = aes.CreateDecryptor();
byte[] encryptedStr = Convert.FromBase64String(Input);
string Plain_Text;
using (var ms = new MemoryStream(encryptedStr))
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cs))
{
Plain_Text = reader.ReadToEnd();
}
}
}
return Plain_Text;
}
catch (Exception ex)
{
return null;
}
}
Helper function:
private static byte[] mkey(string skey, int keyLength)
{
int length = keyLength / 8;
byte[] key = Encoding.UTF8.GetBytes(skey);
byte[] k = GenerateEmptyArray(length);
for (int i = 0; i < key.Length; i++)
{
//k[i % 16] = (byte)(k[i % 16] ^ key[i]);
k[i] = key[i];
if(i == length-1)
break;
}
return k;
}
Variables:
input = "Hello World"
key = "NBJ42RKQ2vQoYFZO"
Iv = "j1C83921vHExVhVp"
keyLength = 128
Info about variables:
input - string that is not encrypted or encrypted. If it's encrypted it will be in Base64 format
key - Any Unicode character that will match the AES key size(in this example it's 128). I have written a function that will extract the specific length of characters and add them to a byte array
Code:
public static string PasswordFixer(string skey,int keyLength)
{
int length = keyLength / 8;
byte[] key = Encoding.UTF8.GetBytes(skey);
byte[] k = GenerateEmptyArray(length);
for (int i = 0; i < key.Length; i++)
{
k[i] = key[i];
if(i == length-1)
break;
}
return Encoding.UTF8.GetString(k);
}
Iv - it's always 128bit long meaning 16bytes. you can ignore Iv if you want, in PostgreSQL if you planing to use `encrypt` function then you can ignore the Iv by hard coding like this `aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };`
keylength-
This is the AES key length in this example we use 128bit meaning 16 bytes. whatever the characters that you use as the Key need to match the length of 16 bytes.
PostgreSQL
The equivalent SQL statement for the encryption and decryption is this
encrypt_iv,decrypt_iv
select convert_from(decrypt_iv(decode(tbl1.encrypted,'base64')::bytea ,'NBJ42RKQ2vQoYFZO','j1C83921vHExVhVp', 'aes-cbc/pad:pkcs'), 'UTF-8') as decrypted,tbl1.encrypted from (select encode(encrypt_iv('Hello World', 'NBJ42RKQ2vQoYFZO','j1C83921vHExVhVp', 'aes-cbc/pad:pkcs'), 'base64') as encrypted) as tbl1
encrypt,decrypt
select convert_from(decrypt(decode(tbl1.encrypted,'base64')::bytea ,'NBJ42RKQ2vQoYFZO', 'aes-cbc/pad:pkcs'), 'UTF-8') as decrypted,tbl1.encrypted from (select encode(encrypt('Hello World', 'NBJ42RKQ2vQoYFZO', 'aes-cbc/pad:pkcs'), 'base64') as encrypted) as tbl1
When I'm trying to decrypt a string the visual studio throws an exception:
System.Security.Cryptography.CryptographicException and says that length of data for decrypting is invalid. Exception trows when compiler reaches cs.Close() in RC2_Decrypt method.
static byte[] RC2_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
string salt = "D495560961CCCFE0";
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
using (MemoryStream msStream = new MemoryStream())
{
using (RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider())
{
RC2.KeySize = 128;
RC2.BlockSize = 64;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
RC2.Key = key.GetBytes(RC2.KeySize / 8);
RC2.IV = key.GetBytes(RC2.BlockSize / 8);
RC2.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(msStream, RC2.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = msStream.ToArray();
}
}
return encryptedBytes;
}
static byte[] RC2_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
string salt = "D495560961CCCFE0";
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
using (MemoryStream msStream = new MemoryStream())
{
using (RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider())
{
RC2.KeySize = 128;
RC2.BlockSize = 64;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
RC2.Key = key.GetBytes(RC2.KeySize / 8);
RC2.IV = key.GetBytes(RC2.BlockSize / 8);
RC2.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(msStream, RC2.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = msStream.ToArray();
}
}
return decryptedBytes;
}
Here example I'm just testing those methods. So for a start I'm tried to encrypt a simple string.
static void Main(string[] args)
{
string password = "770A8A65DA156D24EE2A093277530142";
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
Console.WriteLine("Encrypting");
string str = "Hello world";
Console.WriteLine(EncString(str, password));
byte[] encArray = Encoding.UTF8.GetBytes(str);
Console.WriteLine(DecString(str, password));
Console.ReadKey();
}
Methods that I'm using for string encrypting:
static string EncString(string message, string password)
{
byte[] byresToBeEncrypted = Encoding.UTF8.GetBytes(message);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] bytesToBeEncrypted = RC2_Encrypt(byresToBeEncrypted, passwordBytes);
string result = Convert.ToBase64String(byresToBeEncrypted);
return result;
}
static string DecString(string message, string password)
{
byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(message);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] bytesToBeDecrypted = RC2_Decrypt(bytesToBeEncrypted, passwordBytes);
string result = Encoding.UTF8.GetString(bytesToBeDecrypted);
return result;
}
Well those methods can encrypt and decrypt text file and thats all I need. But I still have a question. Why this doesn't work with simple string variable?