Ok so for a school project I am making an app that has an encryption function.
Here is my code
public static string EncryptString(string stringToEncrypt, string hash)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToEncrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider() {
Key = keys, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 })
{
ICryptoTransform transform = tripleDES.CreateEncryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
public static string DecryptString(string stringToDecrypt, string hash)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToDecrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider()
{
Key = keys,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
})
{
ICryptoTransform transform = tripleDES.CreateDecryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
Currently the encryption method works, however the decryption method crashes the entire app. The error message is as follows:
System.Security.Cryptography.CryptographicException: 'Length of the data to decrypt is invalid.'
It it important for the app that the user can set their own encryption/decryption key.
What exactly is causing the app to not work? I can provide more information if needed.
Thanks.
This should resolve your problem, you just need to decode the base64 string in the decrypt function, ie byte[] data = Convert.FromBase64String(stringToDecrypt);.
Also we want to return a string, rather than base64 data, so we'll do UTF8Encoding.UTF8.GetString() at then end of DecryptString.
I would take note of the fact that this would not be considered secure as the comments above indicate, but this is a learning exercise, so this will get you up and running!
I've also created a DotNetFiddle here: https://dotnetfiddle.net/PPzXKo
using System;
using System.Security;
using System.Text;
using System.Security.Cryptography;
namespace triple_des_test
{
public class Program
{
public void Main()
{
string key = "my key";
string encrypted = EncryptString("Hello world", key);
Console.WriteLine("Encrypted: " + encrypted);
Console.WriteLine("Decrypted: " + DecryptString(encrypted, key));
}
public static string EncryptString(string stringToEncrypt, string key)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToEncrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider() {
Key = keys, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 })
{
ICryptoTransform transform = tripleDES.CreateEncryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
public static string DecryptString(string stringToDecrypt, string key)
{
byte[] data = Convert.FromBase64String(stringToDecrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider()
{
Key = keys,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
})
{
ICryptoTransform transform = tripleDES.CreateDecryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return UTF8Encoding.UTF8.GetString(results, 0, results.Length);
}
}
}
}
}
Related
In C# language, my purpose is to hash password with hash_password(), then verify it with verify() methods. I hash and salt for password 's3cr3t', then check for two examples and return true if password is 's3cr3t' and return false for password 's3cr4t'.
using System;
using System.Text;
using System.Security.Cryptography;
public class Pbkdf2_test4
{
public const int salt_size = 24;
public const int hash_size = 24;
public const int iteration = 100000;
static byte[] salt1 = new byte[salt_size];
private static Rfc2898DeriveBytes hash_password(string password)
{
RandomNumberGenerator generator = RandomNumberGenerator.Create();
byte[] salt = new byte[salt_size];
generator.GetBytes(salt);
salt1 = salt;
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt1, iteration);
return pbkdf2;
}
private static bool verify(Rfc2898DeriveBytes pw_hash, string password)
{
//data1 can be a string or contents of a file.
string data1 = "Some test data";
try
{
Rfc2898DeriveBytes k1 = pw_hash;
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(password, salt1, iteration);
// Encrypt the data.
Aes encAlg = Aes.Create();
encAlg.Key = k1.GetBytes(16);
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream, encAlg.CreateEncryptor(), CryptoStreamMode.Write);
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);
encrypt.Write(utfD1, 0, utfD1.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] edata1 = encryptionStream.ToArray();
k1.Reset();
// Try to decrypt, thus showing it can be round-tripped.
Aes decAlg = Aes.Create();
decAlg.Key = k2.GetBytes(16);
decAlg.IV = encAlg.IV;
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(edata1, 0, edata1.Length);
decrypt.Flush();
decrypt.Close();
k2.Reset();
string data2 = new UTF8Encoding(false).GetString(decryptionStreamBacking.ToArray());
if (!data1.Equals(data2))
{
return false;
}
else
{
return true;
}
}
catch (Exception e)
{
return false;
}
}
public static void Run()
{
Rfc2898DeriveBytes pw_hash = hash_password("s3cr3t");
Console.WriteLine(System.Text.Encoding.UTF8.GetString(pw_hash.GetBytes(hash_size)));
var result1 = verify(pw_hash, "s3cr3t");
Console.WriteLine(result1);
var result2 = verify(pw_hash, "s3cr4t");
Console.WriteLine(result2);
}
}
My question, somehow there is a problem that for verify(pw_hash, "s3cr3t") that returns false however it should return true. In verify(), there is a problem but still could not understand because I give keys k1 and k2 true, but still does not receive hash/salt same, how can I fix this problem?
Apart from this, shuld I add anything to make password storage safest?
Here is program to encrypt and decrypt pass
internal class Program
{
static void Main(string[] args)
{
Pbkdf2_test4 test4 = new Pbkdf2_test4();
test4.Run();
Console.ReadLine();
}
}
public class Pbkdf2_test4
{
static string key = string.Empty;
static string iv = string.Empty;
public Pbkdf2_test4()
{
Aes encAlg = Aes.Create();
encAlg.GenerateKey();
key = Convert.ToBase64String(encAlg.Key);
encAlg.GenerateIV();
iv = Convert.ToBase64String(encAlg.IV);
}
public string Encrypt(string plainText, string Key, string IV)
{
// Check arguments.
if (string.IsNullOrWhiteSpace(plainText))
throw new ArgumentNullException(nameof(plainText));
if (string.IsNullOrWhiteSpace(Key))
throw new ArgumentNullException(nameof(Key));
if (string.IsNullOrWhiteSpace(IV))
throw new ArgumentNullException(nameof(IV));
byte[] encrypted;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(Key);
aes.IV = Convert.FromBase64String(IV);
// Create an encrypt-or to perform the stream transform.
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}
encrypted = msEncrypt.ToArray();
}
}
// Return the encrypted bytes from the memory stream.
return Convert.ToBase64String(encrypted);
}
public string Decrypt(string cipherText, string Key, string IV)
{
// Check arguments.
if (string.IsNullOrWhiteSpace(cipherText))
throw new ArgumentNullException(nameof(cipherText));
if (string.IsNullOrWhiteSpace(Key))
throw new ArgumentNullException(nameof(Key));
if (string.IsNullOrWhiteSpace(IV))
throw new ArgumentNullException(nameof(IV));
// Declare the string used to hold
// the decrypted text.
string plaintext = string.Empty;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(Key);
aes.IV = Convert.FromBase64String(IV);
// Create a decrypt-or to perform the stream transform.
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
public void Run()
{
Console.WriteLine("Key is : " + key);
Console.WriteLine("IV is : " + iv);
string passord = "s3cr3t";
string encryptedPassowrd = Encrypt(passord, key, iv);
string decryptedPassowrd = Decrypt(encryptedPassowrd, key, iv);
Console.WriteLine($"Password = {passord} and Encrypted password = {encryptedPassowrd}");
Console.WriteLine($"Password = {passord} and Decrypted password = {decryptedPassowrd}");
string passord1 = "s3cr4t";
string encryptedPassowrd1 = Encrypt(passord1, key, iv);
string decryptedPassowrd1 = Decrypt(encryptedPassowrd1, key, iv);
Console.WriteLine($"Password = {passord1} and Encrypted password = {encryptedPassowrd1}");
Console.WriteLine($"Password = {passord1} and Decrypted password = {decryptedPassowrd1}");
}
}
I think you misunderstood the example in the documentation of Rfc2898DeriveBytes. This function can be used for password hashing (PBKDF2), but then you don't need the encryption parts. The original use case of a key derivation function like PBKDF2 was to take a (weak) user password and turn it into a (strong) key which can then be used to encrypt data (thus the name key-derivation). Later one saw that the same functions are suitable to generate password hashes.
In your case I would recommend to use an appropriate library for password hashing, like BCrypt.Net. The usage would look like:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
string hashToStoreInDb = BCrypt.HashPassword(password);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from existingHashFromDb.
bool isPasswordCorrect = BCrypt.Verify(password, existingHashFromDb);
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'm trying to decrypt AES-128 CBC strings in C# but with no success (tried every decrypt method I found on internet for this type of encryption).
The only way I got a result was decrypting those strings in PHP using this code:
<?php
$crypto_data = hex2bin($crypto_data_hex);
$real_data = openssl_decrypt($crypto_data,
'AES-128-CBC',
'23d854ce7364b4f7',
OPENSSL_RAW_DATA,
'23d854ce7364b4f7');
?>
So, is there a way to run this PHP code in .NET (using a PHP.dll library or something similar) ? Or is there a real equivalent method for this operation in .NET C# ?
Thank you
The question seems to boil down to writing C# function that is equivalent to PHP function.
Try this code:
public class Program
{
public static byte[] HexToBytes(string hex)
{
int numberChars = hex.Length;
byte[] bytes = new byte[numberChars / 2];
for (int i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
static string Decrypt(byte[] cipherText, byte[] key, byte[] iv)
{
string plaintext;
AesManaged aes = new AesManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
BlockSize = 128,
Key = key,
IV = iv
};
using (aes)
{
ICryptoTransform decryptor = aes.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(cipherText))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd();
}
}
}
}
return plaintext;
}
public static void Main()
{
string crypto_data_hex = "00965fa56e761b11d37b887f98e6bcc2"; // paste $crypto_data_hex value here
string sKey = "23d854ce7364b4f7";
string sIv = "23d854ce7364b4f7";
byte[] encrypted = HexToBytes(crypto_data_hex);
byte[] key = Encoding.ASCII.GetBytes(sKey);
byte[] iv = Encoding.ASCII.GetBytes(sIv);
string decrypted = Decrypt(encrypted, key, iv);
Console.WriteLine(decrypted);
}
}
I want encryption in my wcf service. For that I am writing a class to encrypt and decrypt strings. The encryption seems to work fine and produces a encrypted string but while doing decryption it was giving error of double escape not allowed or error 401. I have add in webconfig the following
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
Now it is giving error of either the length of the string is not correct or for shorter strings Bad String. The code is
To Encrypt
static string hash = "mypass#mysitec0m";
public static string Encrypt(string decrypted)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(decrypted);
using (MD5CryptoServiceProvider mds = new MD5CryptoServiceProvider())
{
byte[] keys = mds.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider())
{
ICryptoTransform transform = tripDes.CreateEncryptor();
byte[] result = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(result);
}
}
}
and to decrypt
public static string decrypt(string encrypted)
{
byte[] data = Convert.FromBase64String(encrypted);
using (MD5CryptoServiceProvider mds = new MD5CryptoServiceProvider())
{
byte[] keys = mds.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider())
{
ICryptoTransform transform = tripDes.CreateDecryptor();
byte[] result = transform.TransformFinalBlock(data, 0, data.Length);
return UTF8Encoding.UTF8.GetString(result);
}
}
}
Why is the error there and how can I fix it.
You never initialized the cipher with your key, thus you are using one random key for the encryptor and a different random key with your decryptor.
Use the CreateEncryptor(Byte[], Byte[]) method instead, and similarly for the decryptor.
CreateEncryptor(Byte[], Byte[])...
creates a symmetric encryptor object with the specified Key property
and initialization vector (IV).
This has nothing to do with WCF, more like a question about TripleDESCryptoServiceProvider.There is an error in your encryption and decryption code. If IV is not set, the encryption mode should use ECB. The default is CBC.CBC needs to set IV.
This is my modified code:
To Encrypt
public static string Encrypt(string decrypted)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(decrypted);
using (MD5CryptoServiceProvider mds = new MD5CryptoServiceProvider())
{
byte[] keys = mds.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider() {
Key=keys,
Mode=CipherMode.ECB
})
{
ICryptoTransform transform = tripDes.CreateEncryptor();
byte[] result = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(result);
}
}
}
To decrypt
public static string decrypt(string encrypted)
{
byte[] data = Convert.FromBase64String(encrypted);
using (MD5CryptoServiceProvider mds = new MD5CryptoServiceProvider())
{
byte[] keys = mds.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider()
{
Key = keys,
Mode = CipherMode.ECB
})
{
ICryptoTransform transform = tripDes.CreateDecryptor();
byte[] result = transform.TransformFinalBlock(data, 0, data.Length);
return UTF8Encoding.UTF8.GetString(result);
}
}
}
I would suggest you use POST in place of GET. Because encrypted string might be long and will have many special characters as you have mentioned in the question
Below is the sample.
[OperationContract(Name = "Decrypt")]
[WebInvoke(Method = "POST",
UriTemplate = "Decrypt")]
string Decrypt(string data);
I'm currently working on a class that encrypts large amounts of text with a randomly generated encryption key encrypted by a X509 certificate from a smart card, using a RSACryptoServiceProvider to perform the master key encryption and decryption operations. However, when I have the fOEAP padding option set to true, I have the "Error while decoding OAEP padding" error on decryption every time. I've checked the key size and it is within acceptable limits. And I've gone through breakpoints to make sure that the Base64 string that gets returned from the encryption function is the exact same as the encrypted Base64 string that gets passed back to the decryption function when the file gets loaded again.
The key pair is definitely correct, since it works fine without OAEP. And I've checked the text encoding too.
EDIT: It turns out this could be a smart card specific issue, when I tried decryption with a local X509 certificate the decryption succeeded.
EDIT: This is the decryption code that fails:
string TestString = "Hello World!";
X509Certificate2 cert = DRXEncrypter.GetCertificate("Select a test certificate", "Select a certificate to use for this test from the local store.");
string key = DRXEncrypter.GenerateEncryptionKey(214);
Console.WriteLine("Encryption Key: " + key);
string encrypted = DRXEncrypter.EncryptBody(TestString, key);
Console.WriteLine("Encrypted Body: " + encrypted);
string cryptokey = DRXEncrypter.EncryptWithCert(cert, key);
Console.WriteLine("Encrypted Decryption Key: " + cryptokey);
string decrypted = DRXEncrypter.DecryptBody(encrypted, cryptokey, cert);
Console.WriteLine("Decrypted Body: " + decrypted);
Console.WriteLine("Output String: " + decrypted + ".");
Here is the code from the crypto provider class I've written. I've been stuck on this issue for hours, so it would be great if someone could help me out.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.IO;
namespace CoreDRXEditor
{
public class DRXEncrypter
{
private byte[] Salt = Encoding.ASCII.GetBytes("81PO9j8I1a94j");
private string EncryptionKey;
private const bool UseOAEP = true;
public DRXEncrypter(string EncryptionKey)
{
this.EncryptionKey = EncryptionKey;
}
public static string EncryptBody(string body, string encryptionkey)
{
// Use the plaintext master key to encrypt the body.
DRXEncrypter enc = new DRXEncrypter(encryptionkey);
// Encrypt the body.
return enc.Encrypt(body);
}
public static int GetMaxKeySize(X509Certificate2 cert)
{
RSACryptoServiceProvider csp = cert.PublicKey.Key as RSACryptoServiceProvider;
return csp.KeySize;
}
public static string DecryptBody(string body, string encryptionkey, X509Certificate2 cert)
{
// Decrypt the encrypted encryption key with the certificate.
string DecryptedKey = Convert.ToBase64String(DecryptWithCert(cert, encryptionkey));
// Create a new DRXEncrypter using the decrypted encryption key to decrypt the body.
DRXEncrypter enc = new DRXEncrypter(DecryptedKey);
// Return the decrypted body.
return enc.Decrypt(body);
}
public static string GenerateEncryptionKey(int KeyLength)
{
using (RandomNumberGenerator rng = new RNGCryptoServiceProvider())
{
byte[] CryptoBytes = new byte[KeyLength];
rng.GetBytes(CryptoBytes);
return Convert.ToBase64String(CryptoBytes);
}
}
public static X509Certificate2 GetCertificate(string title, string message)
{
X509Store cstore = new X509Store(StoreLocation.CurrentUser);
cstore.Open(OpenFlags.ReadOnly);
X509CertificateCollection certs = X509Certificate2UI.SelectFromCollection(cstore.Certificates, title, message, X509SelectionFlag.SingleSelection);
if (certs.Count == 1)
{
X509Certificate2 mcert = certs[0] as X509Certificate2;
return mcert;
}
else
{
return null;
}
}
public static string EncryptWithCert(X509Certificate2 cert, string PlainText)
{
RSACryptoServiceProvider csp = cert.PublicKey.Key as RSACryptoServiceProvider;
byte[] PlainBytes = Convert.FromBase64String(PlainText);
// This converts the plain text into a byte array and then encrypts the raw bytes.
byte[] CryptoBytes = csp.Encrypt(PlainBytes, UseOAEP);
// This converts the encrypted bytes into a Base64 string.
string ReturnString = Convert.ToBase64String(CryptoBytes);
return ReturnString;
}
public static byte[] DecryptWithCert(X509Certificate2 cert, string EncryptedText)
{
RSACryptoServiceProvider csp = cert.PrivateKey as RSACryptoServiceProvider;
//CspParameters csps = new CspParameters();
byte[] EncryptedBytes = Convert.FromBase64String(EncryptedText);
// This converts the encrypted, Base64 encoded byte array from EncryptWithCert() to a byte[] and decrypts it.
byte[] CryptoBytes = csp.Decrypt(EncryptedBytes, UseOAEP);
return CryptoBytes;
}
public string Encrypt(string PlainText)
{
RijndaelManaged Algorithm = null;
string Output = null;
try
{
Rfc2898DeriveBytes PrivateKey = new Rfc2898DeriveBytes(this.EncryptionKey, this.Salt);
Algorithm = new RijndaelManaged();
Algorithm.Key = PrivateKey.GetBytes(Algorithm.KeySize / 8);
Algorithm.Padding = PaddingMode.PKCS7;
ICryptoTransform Encryption = Algorithm.CreateEncryptor(Algorithm.Key, Algorithm.IV);
using (MemoryStream msa = new MemoryStream())
{
msa.Write(BitConverter.GetBytes(Algorithm.IV.Length), 0, sizeof(int));
msa.Write(Algorithm.IV, 0, Algorithm.IV.Length);
using (CryptoStream csa = new CryptoStream(msa, Encryption, CryptoStreamMode.Write))
{
using (StreamWriter swa = new StreamWriter(csa))
{
swa.Write(PlainText);
}
}
Output = Convert.ToBase64String(msa.ToArray());
}
}
finally
{
if (Algorithm != null)
{
Algorithm.Clear();
}
}
return Output;
}
public string Decrypt(string EncryptedText)
{
RijndaelManaged Algorithm = null;
string Output = null;
try
{
Rfc2898DeriveBytes PrivateKey = new Rfc2898DeriveBytes(this.EncryptionKey, this.Salt);
byte[] KeyBytes = Convert.FromBase64String(EncryptedText);
using (MemoryStream msb = new MemoryStream(KeyBytes))
{
Algorithm = new RijndaelManaged();
Algorithm.Key = PrivateKey.GetBytes(Algorithm.KeySize / 8);
Algorithm.IV = ReadByteArray(msb);
Algorithm.Padding = PaddingMode.PKCS7;
ICryptoTransform Decryption = Algorithm.CreateDecryptor(Algorithm.Key, Algorithm.IV);
using (CryptoStream csb = new CryptoStream(msb, Decryption, CryptoStreamMode.Read))
{
using (StreamReader srb = new StreamReader(csb))
{
Output = srb.ReadToEnd();
}
}
}
}
finally
{
if (Algorithm != null)
{
Algorithm.Clear();
}
}
return Output;
}
public static string Sha512(string ToHash)
{
using (SHA512 SHA = new SHA512Managed())
{
byte[] HashByte = Encoding.UTF8.GetBytes(ToHash);
byte[] HashBytes = SHA.ComputeHash(HashByte);
string Hash = System.Text.Encoding.UTF8.GetString(HashBytes, 0, HashBytes.Length);
return Hash;
}
}
public static string Base64Encode(string data)
{
byte[] str = Encoding.UTF8.GetBytes(data);
return Convert.ToBase64String(str);
}
public static string Base64Decode(string data)
{
byte[] str = Convert.FromBase64String(data);
return Encoding.UTF8.GetString(str);
}
private byte[] ReadByteArray(Stream st)
{
byte[] Length = new byte[sizeof(int)];
st.Read(Length, 0, Length.Length);
byte[] Buffer = new byte[BitConverter.ToInt32(Length, 0)];
st.Read(Buffer, 0, Buffer.Length);
return Buffer;
}
}
}
I've been arguing with this today with smartcards (or more accurately, a Yubikey Neo with the smartcard PIV applet enabled); using this code:
var encryptor = (RSACryptoServiceProvider)c.PublicKey.Key;
var decryptor = (RSACryptoServiceProvider)c.PrivateKey;
var encrypt = encryptor.Encrypt(bytes, RSAEncryptionPadding.Pkcs1);
var decrypt = decryptor.Decrypt(encrypt, RSAEncryptionPadding.Pkcs1);
I've found that it matters what padding algo I use. If I use PKCS1 padding, everything works. If I use OaepSHA1, I get the Error while decoding [...] error. If I use anything else (e.g., OaepSHA256) I get a Not supported error.
I can only conclude that my smartcard doesn't properly support OAEP SHA1, but padding with PKCS#1 everything is good.
Even if this answers what you already know, it may be useful as another datapoint for anyone else coming along using smartcards.
Make sure your key size is not too small or too large.
See comments from MSDN
The RSACryptoServiceProvider supports key sizes from 384 bits to 16384
bits in increments of 8 bits if you have the Microsoft Enhanced
Cryptographic Provider installed. It supports key sizes from 384 bits
to 512 bits in increments of 8 bits if you have the Microsoft Base
Cryptographic Provider installed.
So you might need to pad short key strings with some bytes to get the minimum key length
Ok, I managed to check this and from what I can see, I have problems with some certificates. I am not sure why some certificates work while others don't. It would be good to know why some certificates fail in this case?
Anyway, I created a new self signed certificate using windows "Manage File Encryption Certificates" and used this certificate, and all seems to work.
The out put from your code.
Encryption Key: aUc/GXWDoh2LktaEGeCJfju1dHP118yD/fzfT0iJLuhOq2QeyGpG6m3aBHaxvdH0ufeXRHbMjmlmPgIL/bhABzkT2C5Oa6ZhY3IFXb5t7JXZ3AtUunvtNAnRyFJ7MzklrSZGgQ
vF67DSNfIVE17doKt6j6mkCpSco56ooZCrOs2Mp3vSXqNjvjiwMEfQbk41aYUNVNVNlBGhdNQCIZIAKezQCUpWqzn2II27FIDfqDIEW4ieyzpXC05GzUlGXDxFOiFUPk3n0Y94vgeF8AlCD74eyZtz
WQ==
Encrypted Body: EAAAANS/W7+GGRbT1q5NCYvZlDZYtxaA8g55HzUqP5qxhenn
Encrypted Decryption Key: vc/tcsApmY1503BFi7oSu/RDvZivA1Ed58KJuLoEC6eE8q0BIa6ye2JvtXyxkVbzzL0MA51pZ2ZhMIsfCnBsEDjCgy+JLTZTGM1Mv+em9frFUKb0zHbICnPUa/3H
yd1yOWsdn5ws19QN2dzC6eau+ExhT2T/vyZO4Nf9NdHKnB8n2yB1rrQ/T+N2EYCNH/AVPDAsme6JG7k9Od2XIipBXMyCgXgWYZmQusq+JQjA9d3c4CrQYcg/ERF+K3oZv/gPicBkAR5taxwSxAajGg
bpkJNsbhTMHTN9bOn333qZ6ojlo5e882baZXuZWPr9qtj1b7ONoOyuSx/OvGKjt93BQg==
Decrypted Body: Hello World!
Output String: Hello World!.
Hope that helps