Convert this PHP code to C# Rijndael Algorithm - c#

I've got this php code and I'd like to get the exact equivalent C#
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_192, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
$encryptedData = mcrypt_encrypt(MCRYPT_RIJNDAEL_192, $key, $salt . $message . $nonce, MCRYPT_MODE_CBC, $iv);
$base64Data = base64_encode($salt . $iv . $encryptedData);
$urlEncodedData = rawurlencode($base64Data);
All contributions gratefully received!

Too many variables to convert directly; I recommend that you examine what it does and rewrite it in C# to adhere to the intent of the original code.

Nay sayers and doom mongers, behold!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Web;
namespace EncryptData
{
class EncryptData
{
private static readonly Encoding ASCII_ENCODING = new System.Text.ASCIIEncoding();
private static string md5(string text)
{
return BitConverter.ToString(new MD5CryptoServiceProvider().ComputeHash(ASCII_ENCODING.GetBytes(text))).Replace("-", "").ToLower();
}
public abstract string nonce();
public abstract string salt();
public readonly string EncryptedData;
public EncryptData(string message)
{
// set up encrytion object
RijndaelManaged aes192 = new RijndaelManaged();
aes192.KeySize = 192;
aes192.BlockSize = 192;
aes192.Padding = PaddingMode.None;
aes192.Mode = CipherMode.CBC;
aes192.Key = ASCII_ENCODING.GetBytes(md5(SECRET_KEY));
aes192.GenerateIV();
string localSalt = salt();
string localNonce = nonce();
// form the string for encrypting
// and put into byte array
string textToEncrypt = localSalt + message+ localNonce;
byte[] plainTextBytes = ASCII_ENCODING.GetBytes(textToEncrypt);
// encrypt the data
ICryptoTransform encryptor = aes192.CreateEncryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
cs.Write(plainTextBytes, 0, plainTextBytes.Length);
// convert our encrypted data from a memory stream into a byte array.
byte[] cypherTextBytes = ms.ToArray();
// close memory stream
ms.Close();
byte[] combined = null;
// combine data and convert to byte array
combined = CombinedData(localSalt, aes192.IV, cypherTextBytes);
// url encode data once converted to base64 string
EncryptedData = HttpUtility.UrlEncode(base64CombinedData(combined), ASCII_ENCODING);
}
public byte[] CombinedData(string salt, byte[] IV, byte[] cypherTextBytes)
{
// convert salt string into byte array
byte[] saltBytes = ASCII_ENCODING.GetBytes(salt);
// catenate all the byte arrays into one
// set up dest byte array with required size
byte[] rv = new byte[saltBytes.Length + IV.Length + cypherTextBytes.Length];
// copy in each byte array
Buffer.BlockCopy(saltBytes, 0, rv, 0, saltBytes.Length);
Buffer.BlockCopy(IV, 0, rv, saltBytes.Length, IV.Length);
Buffer.BlockCopy(cypherTextBytes, 0, rv, saltBytes.Length + IV.Length, cypherTextBytes.Length);
return rv;
}
public string base64CombinedData(byte[] rv)
{
return Convert.ToBase64String(rv);
}
}
}

Sorry, but to be honest - the question is rather silly.
All this code does is some nasty crypting and encoding.
PHP is full of global functions from modules that do the thing.
For C# You need to find proper libs/classes that have methods for crypting etc. It will probably ahve different logic and parameters.
I bet You'll even get some output differences due to different implementations.
I suppose this is the closest thing You'll find to an answer to Your question

In the example provided by Rob I think he should have used PaddingMode.Zero instead of PaddingMode.None, as this is the way mcrypt_encrypt() adds paddings.

Related

How to properly call openssl_decrypt method if I have base64 string which contains from IV and encrypted data?

I have code in C# which encrypts and decrypts string:
private readonly UTF8Encoding _encoder;
private readonly ICryptoTransform _encryptor;
private readonly RijndaelManaged _rijndael;
public Crypter()
{
_rijndael = new RijndaelManaged { Key = { 1, 2, 3, 4, ..., 16 } };
_rijndael.GenerateIV();
_encryptor = _rijndael.CreateEncryptor();
_encoder = new UTF8Encoding();
}
public string Encrypt(string unencrypted)
=> Convert.ToBase64String(Encrypt(_encoder.GetBytes(unencrypted)));
private byte[] Encrypt(byte[] buffer)
{
byte[] inputBuffer = _encryptor.TransformFinalBlock(buffer, 0, buffer.Length);
return _rijndael.IV.Concat(inputBuffer).ToArray();
}
public string Decrypt(string encrypted)
=> _encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
private byte[] Decrypt(byte[] buffer)
{
byte[] iv = buffer.Take(16).ToArray();
using (ICryptoTransform decryptor = _rijndael.CreateDecryptor(_rijndael.Key, iv))
{
return decryptor.TransformFinalBlock(buffer, 16, buffer.Length - 16);
}
}
If you check Decrypt(byte[] buffer), I take first 16 bytes which is IV.
Now I similar want to implement in PHP (imagine, that I will encode on C# side and send it to server which runs on php, where I want to decrypt it back). As the param to my PHP decrypt function will be output of C# public string Encrypt(string unencrypted). I somehow need to get those 16 bytes to get IV and the rest part, which I respectively will pass as $data and $iv params to $decrypted_data = openssl_decrypt($data, $cipher, $encryption_key, 0, $iv); function
I have tried to use something like this (using unpack):
$stringValue = base64_decode($encrypted_data, true);
$integers = unpack("s*", $stringValue);
and then tried to take 16 first numbers and somehow convert them back with pack method. But probably I have lack of knowledge.
Could you please help me with this?
P.S. This one I have tried based on Ilya's answer and comments.
$cipher = "aes-256-cbc";
$encryption_key = hex2bin(env("ENCRYPTION_KEY"));
$base64decoded = base64_decode($encrypted_data, true);
$iv = substr($base64decoded, 0, 16);
$data = substr($base64decoded, 16, strlen($base64decoded) - 16);
$decrypted_data = openssl_decrypt($data, $cipher, $encryption_key, OPENSSL_RAW_DATA, $iv);
dd($decrypted_data);
also if I debug code and check which bytes are in $iv using this code:
$stringValue = base64_decode($iv, true);
$integers = unpack("C*", $encrypted_data);
and comparing with C# this byte array byte[] iv = buffer.Take(16).ToArray(); , they are equals, then I expect, that I am using wrongly openssl_decrypt method
In php any string is just a sequence of bytes, so you can work with it directly, e.g. access single byte by its index, or use substr to trim some amount of bytes. Example:
$str = 'some text or binary data received by http';
$first16Bytes = substr($str, 0, 16);
Firstly, I was having an issue how to correct retrieve 16 first bytes from string, because I thought I was doing it incorrectly. Thanks from #Ilia Yatsenko for his answer:
$first16Bytes = substr($str, 0, 16);
But then I have realised, that I am wrongly using openssl_decrypt() method. After having conversation in comments, particularly with #Topaco, we found what was the proble. Here is working code:
$cipher = "aes-256-cbc";
$encryption_key = hex2bin(env("ENCRYPTION_KEY"));
$base64decoded = base64_decode($encrypted_data, true);
$iv = substr($base64decoded, 0, 16);
$data = substr($base64decoded, 16, strlen($base64decoded) - 16);
$decrypted_data = openssl_decrypt($data, $cipher, $encryption_key,
OPENSSL_RAW_DATA, $iv);
dd($decrypted_data);

How to limit the maximmum length of the AES Encryption Password

I would like to limit the length of the encrypted output code like 8 or 10 or 12 character etc.
I have created the very small encrypted coed using he "Advanced Encryption Standard (AES)" with Cryptography.SymmetricAlgorithm.IV.
But the result of the Encrypted code as example below:
Input Password = "090400551"
Converted Output = "mkopj3WFb6RZMp34urFLew==" // This should be half the length
I want to reduce the length of 8 to 12 character. Any C# cryptography library or algorithm would be fine
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace AnotherEncryption
{
class Encryption
{
public static class Global
{
// set password
public const string strPassword = "090400551";
public const String strPermutation = "Secure1234";
public const Int32 bytePermutation1 = 0x78;
public const Int32 bytePermutation2 = 0x56;
public const Int32 bytePermutation3 = 0x34;
public const Int32 bytePermutation4 = 0x88;
}
static void Main(string[] args)
{
Console.Title = "Secure Password v2";
Console.WriteLine("Output---");
Console.WriteLine("");
Console.WriteLine("Password: " + Global.strPassword);
string strEncrypted = (Encrypt(Global.strPassword));
Console.WriteLine("Encrypted: " + strEncrypted);
string strDecrypted = Decrypt(strEncrypted);
Console.WriteLine("Decrypted: " + strDecrypted);
//mkopj3WFb6RZMp34urFLew==
Console.ReadKey();
}
public static string Encrypt(string strData)
{
byte[] test = Encoding.UTF8.GetBytes(strData);
return Convert.ToBase64String(Encrypt(test));
}
public static string Decrypt(string strData)
{
return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(strData)));
}
// encrypt
public static byte[] Encrypt(byte[] strData)
{
PasswordDeriveBytes passbytes =
new PasswordDeriveBytes(Global.strPermutation,
new byte[] { Global.bytePermutation1,
Global.bytePermutation2,
Global.bytePermutation3,
Global.bytePermutation4
});
MemoryStream memstream = new MemoryStream();
Aes aes = new AesManaged();
aes.Key = passbytes.GetBytes(aes.KeySize / 8);
aes.IV = passbytes.GetBytes(aes.BlockSize / 8);
CryptoStream cryptostream = new CryptoStream(memstream, aes.CreateEncryptor(), CryptoStreamMode.Write);
cryptostream.Write(strData, 0, strData.Length);
cryptostream.Close();
return memstream.ToArray();
}
// decrypt
public static byte[] Decrypt(byte[] strData)
{
PasswordDeriveBytes passbytes =
new PasswordDeriveBytes(Global.strPermutation,
new byte[] { Global.bytePermutation1,
Global.bytePermutation2,
Global.bytePermutation3,
Global.bytePermutation4
});
MemoryStream memstream = new MemoryStream();
Aes aes = new AesManaged();
aes.Key = passbytes.GetBytes(aes.KeySize / 8);
aes.IV = passbytes.GetBytes(aes.BlockSize / 8);
CryptoStream cryptostream = new CryptoStream(memstream,
aes.CreateDecryptor(), CryptoStreamMode.Write);
cryptostream.Write(strData, 0, strData.Length);
cryptostream.Close();
return memstream.ToArray();
}
}
}
If you put Rijndael into CFB mode with a block size of 8, then it acts as a stream cipher - for every byte you put in, you get a byte out again.
public static void Main(string[] args)
{
var algorithm = new RijndaelManaged()
{
Mode = CipherMode.CFB,
// This is the equivalent of BlockSize in CFB mode. We set it to 8 (bits) to prevent any buffering of data
// while waiting for whole blocks.
FeedbackSize = 8,
};
// Don't hard-code in real life, obviously
var key = new byte[32];
var iv = new byte[16];
var input = new byte[] { 1, 2, 3 };
byte[] result;
using (var ms = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(ms, algorithm.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
cryptoStream.Write(input, 0, input.Length);
}
result = ms.ToArray();
}
}
Note that this only appears to work on .NET Framework - .NET Core doesn't seem to support CFB (see this GitHub issue).
Note that encryption doesn't prevent tampering! People can't read your plaintext message, but they can very easily change the ciphertext to control what it gets decrypted to. Stream ciphers tend to be particularly vulnerable to this. If you need to stop someone controlling what the encrypted output decrypts into, then you need a signature.
Also note that you should not use the same IV across multiple messages. Create a random IV, and transfer it alongside your message, frequently as the first 2 bytes.

Is there any difference between implementation of Triple DES in C# and Java? Java gives error wrong IV size

In our application we are using Triple DES to encrypt and decrypt the data. We have the enc/dec code in C# which uses 24 byte key and 12 byte IV which works fine. Now we want to implement same code in java but when I use 12 byte IV, I get an error in java saying wrong IV size. When I googled around, I came to know that java uses 8 byte IV. Now I am confused as how come there is implementation difference in C# and JAVA for triple DES. Or am I missing anything?
This is something similar to our encryption code
class cTripleDES
{
// define the triple des provider
private TripleDESCryptoServiceProvider m_des = new TripleDESCryptoServiceProvider();
// define the string handler
private UTF8Encoding m_utf8 = new UTF8Encoding();
// define the local property arrays
private byte[] m_key;
private byte[] m_iv;
public cTripleDES(byte[] key, byte[] iv)
{
this.m_key = key;
this.m_iv = iv;
}
public byte[] Encrypt(byte[] input)
{
return Transform(input,
m_des.CreateEncryptor(m_key, m_iv));
}
public byte[] Decrypt(byte[] input)
{
return Transform(input,
m_des.CreateDecryptor(m_key, m_iv));
}
public string Encrypt(string text)
{
byte[] input = m_utf8.GetBytes(text);
byte[] output = Transform(input,
m_des.CreateEncryptor(m_key, m_iv));
return Convert.ToBase64String(output);
}
public string Decrypt(string text)
{
byte[] input = Convert.FromBase64String(text);
byte[] output = Transform(input,
m_des.CreateDecryptor(m_key, m_iv));
return m_utf8.GetString(output);
}
private byte[] Transform(byte[] input,
ICryptoTransform CryptoTransform)
{
// create the necessary streams
MemoryStream memStream = new MemoryStream();
CryptoStream cryptStream = new CryptoStream(memStream,
CryptoTransform, CryptoStreamMode.Write);
// transform the bytes as requested
cryptStream.Write(input, 0, input.Length);
cryptStream.FlushFinalBlock();
// Read the memory stream and
// convert it back into byte array
memStream.Position = 0;
byte[] result = memStream.ToArray();
// close and release the streams
memStream.Close();
cryptStream.Close();
// hand back the encrypted buffer
return result;
}
}
This is how we are utilizing it:
string IVasAString = "AkdrIFjaQrRQ";
byte[] iv = Convert.FromBase64String(IVasAString);
byte[] key = ASCIIEncoding.UTF8.GetBytes(KEY);
// instantiate the class with the arrays
cTripleDES des = new cTripleDES(key, iv);
string output = des.Encrypt("DATA TO BE ENCRYPTED");
TripleDES has a 64-bit block size. You need to use an 8 byte IV in C#.
Got the answer.
decodeBase64 method from apache common framework (commons.codec.binary.Base64) does the necessary.
Thanks mfanto for the heads up.!

Encrypting & Decrypting a String in C# [duplicate]

This question already has answers here:
Encrypt and decrypt a string in C#? [closed]
(29 answers)
Closed 6 years ago.
What is the most modern (best) way of satisfying the following in C#?
string encryptedString = SomeStaticClass.Encrypt(sourceString);
string decryptedString = SomeStaticClass.Decrypt(encryptedString);
BUT with a minimum of fuss involving salts, keys, mucking about with byte[], etc.
Been Googling and confused at what I'm finding (you can see the list of similar SO Qs to see this is a deceptive question to ask).
UPDATE 23/Dec/2015: Since this answer seems to be getting a lot of upvotes, I've updated it to fix silly bugs and to generally improve the code based upon comments and feedback. See the end of the post for a list of specific improvements.
As other people have said, Cryptography is not simple so it's best to avoid "rolling your own" encryption algorithm.
You can, however, "roll your own" wrapper class around something like the built-in RijndaelManaged cryptography class.
Rijndael is the algorithmic name of the current Advanced Encryption Standard, so you're certainly using an algorithm that could be considered "best practice".
The RijndaelManaged class does indeed normally require you to "muck about" with byte arrays, salts, keys, initialization vectors etc. but this is precisely the kind of detail that can be somewhat abstracted away within your "wrapper" class.
The following class is one I wrote a while ago to perform exactly the kind of thing you're after, a simple single method call to allow some string-based plaintext to be encrypted with a string-based password, with the resulting encrypted string also being represented as a string. Of course, there's an equivalent method to decrypt the encrypted string with the same password.
Unlike the first version of this code, which used the exact same salt and IV values every time, this newer version will generate random salt and IV values each time. Since salt and IV must be the same between the encryption and decryption of a given string, the salt and IV is prepended to the cipher text upon encryption and extracted from it again in order to perform the decryption. The result of this is that encrypting the exact same plaintext with the exact same password gives and entirely different ciphertext result each time.
The "strength" of using this comes from using the RijndaelManaged class to perform the encryption for you, along with using the Rfc2898DeriveBytes function of the System.Security.Cryptography namespace which will generate your encryption key using a standard and secure algorithm (specifically, PBKDF2) based upon the string-based password you supply. (Note this is an improvement of the first version's use of the older PBKDF1 algorithm).
Finally, it's important to note that this is still unauthenticated encryption. Encryption alone provides only privacy (i.e. message is unknown to 3rd parties), whilst authenticated encryption aims to provide both privacy and authenticity (i.e. recipient knows message was sent by the sender).
Without knowing your exact requirements, it's difficult to say whether the code here is sufficiently secure for your needs, however, it has been produced to deliver a good balance between relative simplicity of implementation vs "quality". For example, if your "receiver" of an encrypted string is receiving the string directly from a trusted "sender", then authentication may not even be necessary.
If you require something more complex, and which offers authenticated encryption, check out this post for an implementation.
Here's the code:
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Linq;
namespace EncryptStringSample
{
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
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();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
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))
using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
{
return streamReader.ReadToEnd();
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
}
The above class can be used quite simply with code similar to the following:
using System;
namespace EncryptStringSample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please enter a password to use:");
string password = Console.ReadLine();
Console.WriteLine("Please enter a string to encrypt:");
string plaintext = Console.ReadLine();
Console.WriteLine("");
Console.WriteLine("Your encrypted string is:");
string encryptedstring = StringCipher.Encrypt(plaintext, password);
Console.WriteLine(encryptedstring);
Console.WriteLine("");
Console.WriteLine("Your decrypted string is:");
string decryptedstring = StringCipher.Decrypt(encryptedstring, password);
Console.WriteLine(decryptedstring);
Console.WriteLine("");
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
}
}
(You can download a simple VS2013 sample solution (which includes a few unit tests) here).
UPDATE 23/Dec/2015:
The list of specific improvements to the code are:
Fixed a silly bug where encoding was different between encrypting and
decrypting. As the mechanism by which salt & IV values are generated has changed, encoding is no longer necessary.
Due to the salt/IV change, the previous code comment that incorrectly indicated that UTF8 encoding a 16 character string produces 32 bytes is no longer applicable (as encoding is no longer necessary).
Usage of the superseded PBKDF1 algorithm has been replaced with usage of the more modern PBKDF2 algorithm.
The password derivation is now properly salted whereas previously it wasn't salted at all (another silly bug squished).
using System.IO;
using System.Text;
using System.Security.Cryptography;
public static class EncryptionHelper
{
public static string Encrypt(string clearText)
{
string EncryptionKey = "abc123";
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
public static string Decrypt(string cipherText)
{
string EncryptionKey = "abc123";
cipherText = cipherText.Replace(" ", "+");
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
}
If you are targeting ASP.NET Core that does not support RijndaelManaged yet, you can use IDataProtectionProvider.
First, configure your application to use data protection:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection();
}
// ...
}
Then you'll be able to inject IDataProtectionProvider instance and use it to encrypt/decrypt data:
public class MyService : IService
{
private const string Purpose = "my protection purpose";
private readonly IDataProtectionProvider _provider;
public MyService(IDataProtectionProvider provider)
{
_provider = provider;
}
public string Encrypt(string plainText)
{
var protector = _provider.CreateProtector(Purpose);
return protector.Protect(plainText);
}
public string Decrypt(string cipherText)
{
var protector = _provider.CreateProtector(Purpose);
return protector.Unprotect(cipherText);
}
}
See this article for more details.
Try this class:
public class DataEncryptor
{
TripleDESCryptoServiceProvider symm;
#region Factory
public DataEncryptor()
{
this.symm = new TripleDESCryptoServiceProvider();
this.symm.Padding = PaddingMode.PKCS7;
}
public DataEncryptor(TripleDESCryptoServiceProvider keys)
{
this.symm = keys;
}
public DataEncryptor(byte[] key, byte[] iv)
{
this.symm = new TripleDESCryptoServiceProvider();
this.symm.Padding = PaddingMode.PKCS7;
this.symm.Key = key;
this.symm.IV = iv;
}
#endregion
#region Properties
public TripleDESCryptoServiceProvider Algorithm
{
get { return symm; }
set { symm = value; }
}
public byte[] Key
{
get { return symm.Key; }
set { symm.Key = value; }
}
public byte[] IV
{
get { return symm.IV; }
set { symm.IV = value; }
}
#endregion
#region Crypto
public byte[] Encrypt(byte[] data) { return Encrypt(data, data.Length); }
public byte[] Encrypt(byte[] data, int length)
{
try
{
// Create a MemoryStream.
var ms = new MemoryStream();
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
var cs = new CryptoStream(ms,
symm.CreateEncryptor(symm.Key, symm.IV),
CryptoStreamMode.Write);
// Write the byte array to the crypto stream and flush it.
cs.Write(data, 0, length);
cs.FlushFinalBlock();
// Get an array of bytes from the
// MemoryStream that holds the
// encrypted data.
byte[] ret = ms.ToArray();
// Close the streams.
cs.Close();
ms.Close();
// Return the encrypted buffer.
return ret;
}
catch (CryptographicException ex)
{
Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
}
return null;
}
public string EncryptString(string text)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(text)));
}
public byte[] Decrypt(byte[] data) { return Decrypt(data, data.Length); }
public byte[] Decrypt(byte[] data, int length)
{
try
{
// Create a new MemoryStream using the passed
// array of encrypted data.
MemoryStream ms = new MemoryStream(data);
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
CryptoStream cs = new CryptoStream(ms,
symm.CreateDecryptor(symm.Key, symm.IV),
CryptoStreamMode.Read);
// Create buffer to hold the decrypted data.
byte[] result = new byte[length];
// Read the decrypted data out of the crypto stream
// and place it into the temporary buffer.
cs.Read(result, 0, result.Length);
return result;
}
catch (CryptographicException ex)
{
Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
}
return null;
}
public string DecryptString(string data)
{
return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(data))).TrimEnd('\0');
}
#endregion
}
and use it like this:
string message="A very secret message here.";
DataEncryptor keys=new DataEncryptor();
string encr=keys.EncryptString(message);
// later
string actual=keys.DecryptString(encr);
If you need to store a password in memory and would like to have it encrypted you should use SecureString:
http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx
For more general uses I would use a FIPS approved algorithm such as Advanced Encryption Standard, formerly known as Rijndael. See this page for an implementation example:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx
You may be looking for the ProtectedData class, which encrypts data using the user's logon credentials.
The easiest way that I've seen to do encryption is through RSA
Check out the MSDN on it: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx
It does involve using bytes, but when it comes down to it you kind of do want encryption and decryption to be tough to figure out otherwise it will be easy to hack.

C# Encryption Algorithms

There are many answers on the internet regarding encryption, but I have been unable to find exactly what I'm looking for: simple strong encryption using the tools that c# provides to encrypt strings and text files.
My main problem is that I don't know how to save the IV into the beginning of the text file or how to create a random IV. I have an example on crypto stream and I have seen an example on DES, but they use the same IV and key and that is (by what I know) not a good thing to do.
You're right, using the same IV is a bad practice, especially if either the Key or IV are hard coded. I'd recommend using the AesManaged class. It uses the AES algorithm, the current standard. Generating an IV is fairly simple:
var aes = new AesManaged(); //Set your KeySize if you will generate a key too.
aes.GenerateIV();
var iv = aes.IV;
That's a simple way of getting a new initialization vector. If your goal is to encrypt a file, you can store the File, but what will you do with the Key? Hard coding it within your application is generally not a very good way of doing it. If your application will be password based, then you can generate the key from Rfc2898DeriveBytes to get a byte array based on a password. This way, your application never knows what the encryption key is.
Here is an example for writing the IV to a file, then the file contents.
using (AesManaged aes = new AesManaged())
{
//Set the Key here.
aes.GenerateIV();
using (var transform = aes.CreateEncryptor())
{
using (var fileStream = new FileStream("C:\\in.txt", FileMode.Open))
{
using (var saveTo = new FileStream("C:\\out.txt", FileMode.Create))
{
using (var cryptoStream = new CryptoStream(saveTo, transform,CryptoStreamMode.Write))
{
var iv = aes.IV;
cryptoStream.Write(iv, 0, iv.Length);
fileStream.CopyTo(cryptoStream);
}
}
}
}
}
see the example on following link, it will create a string encryption with hash, salt and VI key.
https://github.com/salahuddinuk/Encryption-Decryption/blob/master/EncryptDecrypt/Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace EncryptDecrypt
{
public partial class Form1 : Form
{
static readonly string PasswordHash = "P!!Sw0rd~";
static readonly string SaltKey = "Sa~LT~KEY";
static readonly string VIKey = "#1B2c3D4#e5F6<7H8<.";
public Form1()
{
InitializeComponent();
}
private void btn_Process_Click(object sender, EventArgs e)
{
try
{
lbl_Error.Text = "";
if (chb_Decrypt.Checked == true)
txt_Result.Text = Decrypt(txt_Value.Text);
else
txt_Result.Text = Encrypt(txt_Value.Text);
}
catch (Exception ex)
{
lbl_Error.Text = ex.Message;
}
}
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);
}
public static string Decrypt(string encryptedText)
{
byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };
var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
var memoryStream = new MemoryStream(cipherTextBytes);
var 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();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
}
}
}
Nowadays, AesGcm would be an appropriate class and algorithm to use. Examples code for it is easy enough to find, and its API is fairly straightforward.
To generate the IV/nonce, use RandomNumberGenerator.Fill to populate an array of the correct size, which is 12 bytes (96 bits) for AES-GCM. RandomNumberGenerator is the cryptographically-secure one.
As for writing the IV to the file, that is up to you. Are you writing to a file stream? Then start by writing the IV, and then proceed to write the ciphertext. For AES-GCM, we would also write the tag, which will give us not just encryption, but authenticated encryption, i.e. on decryption we can confirm that the ciphertext has not been tampered with.
When reading such a file back in, we read each of the components separately - IV, ciphertext, and tag. Since you know how you wrote them, you know how to read them. For example, x bytes IV, then y bytes tag, then the remaining bytes ciphertext, if that is how you wrote the data to the file.
Pass the components to AesGcm.Decrypt and voila.

Categories