I need to decrypt a string that was encrypted with OpenSSL as following:
openssl rand -out secret.key -hex 192
openssl aes-256-cbc -pbkdf2 -in file_to_encrypt -out encrypted_file -pass file:secret.key
And i can't get it to work in C#
public void OnStartup()
{
using var rsa = RSA.Create();
var privateKeyContent = File.ReadAllText("/cert/customer.pem");
rsa.ImportFromPem(privateKeyContent);
var encryptedSecret = File.ReadAllBytes("license/secret.key.enc");
var decrypted = rsa.Decrypt(encryptedSecret, RSAEncryptionPadding.Pkcs1);
_logger.LogInformation(Encoding.UTF8.GetString(decrypted));
var bytes = File.ReadAllBytes("license/license.json.enc");
var license = DecryptAesCbc(bytes, decrypted);
_logger.LogInformation(license);
}
public string DecryptAesCbc(byte[] cipheredData, byte[] passphrase)
{
string decrypted = null;
using (var ms = new MemoryStream(cipheredData))
{
// Get salt
var salt = new byte[8];
ms.Seek(8, SeekOrigin.Begin);
ms.Read(salt, 0, 8);
_logger.LogInformation("Salt: {Salt}", string.Concat(Array.ConvertAll(salt, x => x.ToString("X2"))));
// Derive key and IV
var pbkdf2 = new Rfc2898DeriveBytes(passphrase, salt, 10000, HashAlgorithmName.SHA256);
byte[] key = pbkdf2.GetBytes(32);
byte[] iv = pbkdf2.GetBytes(16);
_logger.LogInformation("Key: {Key}", string.Concat(Array.ConvertAll(key, x => x.ToString("X2"))));
_logger.LogInformation("IV: {IV}", string.Concat(Array.ConvertAll(iv, x => x.ToString("X2"))));
using Aes aes = Aes.Create();
aes.KeySize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.Key = key;
aes.IV = iv;
// Decrypt
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using var cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read);
using var sr = new StreamReader(cs, Encoding.UTF8);
decrypted = sr.ReadToEnd();
}
return decrypted;
}
With this code i receive an exception at decrypted = sr.ReadToEnd()
Padding is invalid and cannot be removed.
The secret is encrypted via RSA and decrypted, the result is the same as the the decrypted file, so this should be working.
Im very thankful for help
Solution:
public static string DecryptLicense(byte[] cipherData, byte[] passphrase)
{
string decrypted = null;
using (var ms = new MemoryStream(cipherData))
{
// Get salt
var salt = new byte[8];
ms.Seek(8, SeekOrigin.Begin);
ms.Read(salt, 0, 8);
// Derive key and IV
var pbkdf2 = new Rfc2898DeriveBytes(passphrase, salt, 10000, HashAlgorithmName.SHA256);
byte[] key = pbkdf2.GetBytes(32);
byte[] iv = pbkdf2.GetBytes(16);
using Aes aes = Aes.Create();
aes.KeySize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.Key = key;
aes.IV = iv;
// Decrypt
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using var cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read);
using var sr = new StreamReader(cs, Encoding.UTF8);
decrypted = sr.ReadToEnd();
}
return decrypted;
}
and generate the passphrase with: openssl rand 192 | openssl enc -A -base64 -out secret.key
The problem was a passphrase which was generated with newlines and openssl uses just the first line from a passphrase file, but C# uses the whole file to derive the keys. In order to prevent that, i now generate a file with no linebreaks.