CryptoStream behaves differently on local and aws - c#

I have encryption decryption code which is perfectly working fine in local. From local system using code first approach I created database in aws which created successfully with seeds values in which I have decrypted the password.
Now, I have published the .net6 application in aws ec2 instance. On logging it is giving error of incorrect credentials.
I have logged the username and passwords and rechecked the scenario. The issue I have found is the encryption is changed.
I have updated the password and successfully logged in. But now the problem is with roles. I have applied checks on encrypted role ids which are not maching now.
Can anyone please help me here on this issue please?
`
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Common
{
public static class EncyptionDcryption
{
static string key = "85OIbnI9";
static string vector = "eH90BDl0";
////////////////////////////////////////////////////////////////////////////////
// Decryption
////////////////////////////////////////////////////////////////////////////////
public static string GetDecryptedText(string txt)
{
txt = txt.Replace(' ', '+');
DESCryptoServiceProvider key = new DESCryptoServiceProvider();
key.Key = ASCIIEncoding.ASCII.GetBytes(key); // decryption key
key.IV = ASCIIEncoding.ASCII.GetBytes(vector);// initialization vector
int length = txt.Length;
byte[] buffer = new byte[length];
buffer = Convert.FromBase64String(txt);
string decText = Decrypt(buffer, key);
return decText;
}
public static string Decrypt(byte[] CypherText, SymmetricAlgorithm key)
{
// Create a memory stream to the passed buffer.
MemoryStream ms = new MemoryStream(CypherText);
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Read);
// Create a StreamReader for reading the stream.
StreamReader sr = new StreamReader(encStream);
// Read the stream as a string.
string val = sr.ReadLine();
// Close the streams.
sr.Close();
encStream.Close();
ms.Close();
return val;
}
////////////////////////////////////////////////////////////////////////////////
// Encryption
////////////////////////////////////////////////////////////////////////////////
public static byte[] Encrypt(string PlainText, SymmetricAlgorithm key)
{
// Create a memory stream.
MemoryStream ms = new MemoryStream();
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
// Create a StreamWriter to write a string
// to the stream.
StreamWriter sw = new StreamWriter(encStream);
// Write the plaintext to the stream.
sw.WriteLine(PlainText);
// Close the StreamWriter and CryptoStream.
sw.Close();
encStream.Close();
// Get an array of bytes that represents
// the memory stream.
byte[] buffer = ms.ToArray();
// Close the memory stream.
ms.Close();
// Return the encrypted byte array.
return buffer;
}
public static string GetEncryptedText(string txt)
{
DESCryptoServiceProvider key = new DESCryptoServiceProvider();
key.Key = ASCIIEncoding.ASCII.GetBytes(key); // decryption key
key.IV = ASCIIEncoding.ASCII.GetBytes(vector);// initialization vector
// Encrypt a string to a byte array.
byte[] buffer = Encrypt(txt, key);
string encText;
encText = Convert.ToBase64String(buffer);
return encText;
}
}
}
`
Why it behaves differently on server and local? But no clue.

Related

C# getting error on decrypting byte[] from a file

I wrote this code to encrypt a text and write the encrypted text to a file and then decrypt it from the file. But I get this exception: System.Security.Cryptography.CryptographicException: 'The input data is not a complete block.' When I use a byte[] for storing data, it works perfect but it seems that it cant correctly convert a file to byte[]. I also tried File.ReadAllBytes but I got the same error. Please Help me.
class Program
{
static void Main(string[] args)
{
string decrypted;
byte[] encrypted;
Console.Write("Enter a text to encrypt : ");
string plaintext = Console.ReadLine();
using (Aes aes = Aes.Create())
{
encrypted = AesEncryption.Encrypt(plaintext, aes);
File.WriteAllText(#"C:\Users\sepita\Desktop\My.txt", Encoding.UTF8.GetString(encrypted), Encoding.UTF8);
decrypted = AesEncryption.Decrypt(Encoding.UTF8.GetBytes(File.ReadAllText(#"C:\Users\sepita\Desktop\My.txt")), aes);
}
Console.WriteLine($"Encrypted : {Encoding.UTF8.GetString(encrypted)}");
Console.WriteLine($"Decrypted : {decrypted}");
}
}
static class AesEncryption
{
public static byte[] Encrypt(string plaintext, Aes aes)
{
byte[] encrypted;
ICryptoTransform encryptor = aes.CreateEncryptor();
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream stream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(plaintext);
}
encrypted = memoryStream.ToArray();
}
}
return encrypted;
}
public static string Decrypt(byte[] encrypted, Aes aes)
{
string decrypted = null;
ICryptoTransform decryptor = aes.CreateDecryptor();
using (MemoryStream memoryStream = new MemoryStream(encrypted))
{
using (CryptoStream stream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(stream))
{
decrypted = reader.ReadToEnd();
}
}
}
return decrypted;
}
}
The result of your Encrypt function is binary data. It would be pure luck if this were a valid UTF8 string, so Encoding.UTF8.GetString(encrypted) will not work in general.
Replacing it by
File.WriteAllBytes(#"C:\Users\sepita\Desktop\My.bin", encrypted);
decrypted = AesEncryption.Decrypt(File.ReadAllBytes(#"C:\Users\sepita\Desktop\My.bin"), aes);
will work.
If you want a text file, use BASE64 conversion on the binary data:
File.WriteAllText(#"C:\Users\sepita\Desktop\My.txt", Convert.ToBase64String(encrypted));
decrypted = AesEncryption.Decrypt(Convert.FromBase64String(File.ReadAllText(#"C:\Users\sepita\Desktop\My.txt")), aes);

Decryption providing a padding error

I'm trying to save a serialized object to an encrypted file. This isn't production quality and I am aware of the security risks with the way that I am doing this, but ignoring those I will have a key in a resource (data.Settings.key) that wont change and I have a salt that is also a constant.
My encryption seems to work, but decryption returns me an Exception saying that padding is invalid and cannot be closed when I try to close my CryptoStream.
private static byte[] decrypt(byte[] bytes)
{
var decryptor = algorithm.CreateDecryptor();
using (var sMemoryStream = new MemoryStream())
using (var sCryptoStream = new CryptoStream(sMemoryStream, decryptor, CryptoStreamMode.Write))
{
sCryptoStream.Write(bytes, 0, bytes.Length);
sCryptoStream.Close();
return sMemoryStream.ToArray();
}
}
The algorithm variable is the same one that the encrypt method uses and is built by this method which is called in the classes constructor:
private static SymmetricAlgorithm GetAlgorithm()
{
var algorithm = Rijndael.Create();
// Create key from salt and password in config
var rdb = new Rfc2898DeriveBytes(data.Settings.key, new byte[] {
0x44,0x61,0x79,0x6e,0x65,0x44,0x6f,0x75,0x67,0x61,0x6e
});
algorithm.Padding = PaddingMode.PKCS7;
// Set key and IV from rdb
algorithm.Key = rdb.GetBytes(32);
algorithm.IV = rdb.GetBytes(16);
return algorithm;
}
I've tried changing the padding mode in the algorithm but I can't understand why it's fine with this padding when encrypting, but now when decrypting.
If it helps here is the method that calls the decrypt method:
private static User OpenFile(String sUserName)
{
Console.WriteLine("Opening file...");
using (Stream sFileStream = new FileStream(data.Settings.dir + "data\\accounts\\" + sUserName + ".dat",
FileMode.Open, FileAccess.Read, FileShare.None))
using (Stream sMemoryStream = new MemoryStream())
{
// Read from File to memory stream
sFileStream.CopyTo(sMemoryStream);
// Decrypt data and store in new memory stream
byte[] bytes = new byte[sMemoryStream.Length];
Console.WriteLine("\tb:" + bytes.Length);
bytes = decrypt(bytes);
Console.WriteLine("\ta:" + bytes.Length);
Stream stream = new MemoryStream(bytes);
Console.WriteLine("\ts:" + bytes.Length);
// Deserialise memory stream and return as User object
User user = (User)bfFormatter.Deserialize(stream);
stream.Close();
return user;
}
}

C# Decrypting mp3 file using RijndaelManaged and CryptoStream

I have decrypted and saved an mp3 file into a blob storage.
However, when I decrypt and download the file I cant play it. I used an Mp3 validation tool which says "unknown file format". I believe it is the decryption that does not work since it works to download an unencrypted Mp3 file. Below I first show the encryption code within its Azure webjob function. The I show the decryption method and the method using it. I have removed handling of keys and such or clarity.
Encrypt
public static void EncryptBlob(
[BlobTrigger("callstest/{name}")]
[Blob("callstest/{name}", FileAccess.Read)] Stream blobInput,
[Blob("encryptedcalls/{name}.vega", FileAccess.Write)] Stream blobOutput)
{
try
{
var password = "myKey123";
var ue = new UnicodeEncoding();
var key = ue.GetBytes(password);
var rmCrypto = new RijndaelManaged {Padding = PaddingMode.None};
using (var cs = new CryptoStream(blobOutput,
rmCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write))
{
int data;
while ((data = blobInput.ReadByte()) != -1)
cs.WriteByte((byte)data);
}
}
catch
{
Trace.TraceError("an error occured during encryption of the file-get the name?");
}
}
AdminController
public async Task<ActionResult> DownloadMp3FromUrl()
{
var file = await _recordingService.GetRecordingFromUrl();
var fileName = "filetest.mp3";
return File(file,"audio/mpeg", fileName);
}
Recording Service handler
public async Task<byte[]> GetRecordingFromUrl()
{
var container = _blobClient.GetContainerReference("encryptedcalls");
var blockBlob = container.GetBlockBlobReference("SearchFiles.mp3.vega");
try
{
var password = "myKey123";
var ue = new UnicodeEncoding();
var key = ue.GetBytes(password);
var rmCrypto = new RijndaelManaged { Padding = PaddingMode.None };
using (var stream = new MemoryStream())
{
blockBlob.FetchAttributes();
blockBlob.DownloadToStream(stream, null, null);
using (var cs = new CryptoStream(stream, rmCrypto.CreateDecryptor(key, key), CryptoStreamMode.Read))
{
int data;
while ((data = stream.ReadByte()) != -1)
cs.WriteByte((byte)data);
return stream.ToArray();
}
}
}
catch
{
Trace.TraceError("an error occured during encryption of the file-get the name?");
}
return null;
}
You're trying to write the decrypted data back into the source-stream in your Recording Service handler. This will never work. I'm amazed this doesn't throw an exception.
You need to set up your input stream, pass it into a decrypting CryptoStream, then write that to another output stream:
using (var inStream = new MemoryStream())
using (var outStream = new MemoryStream())
{
blockBlob.FetchAttributes();
blockBlob.DownloadToStream(inStream, null, null);
using (var cryptoStream = new CryptoStream(
inStream, rmCrypto.CreateDecryptor(key, key), CryptoStreamMode.Read))
{
cryptoStream.CopyTo(outStream);
return outStream.ToArray();
}
}
As an aside, the implementation as you've presented it here is full of security issues:
Don't use a non-padded cipher. You can leak information this way.
Don't generate your key from a password. Use a cryptographically secure RNG to generate your keys.
If you must use a string as your key's password, use Rfc2898DeriveBytes to generate a cryptographically secure random key from the password.
Absolutely do not use your symmetric key as your IV. This is really, really bad practice. The IV is used to randomize the cipher's output - it is not a secret in the same way as the key, and should be unique to each 'message' (or file) being encrypted.

AESManaged File Encryption and Decryption and prepending initiaization vector

I am trying to encrypt/decrypt bytes - I have done a lot of reading about the Key and IV for the AES algorithm using the AESManaged class in System.Security.Cryptography. I read James Johnson's answer to the following question http://www.techques.com/question/1-7025135/My-Length-of-the-data-to-decrypt-is-invalid-error where he suggests that you use a random IV in the encryption routine and prepend the IV to the encrypted message. The decrypt function strips off the random IV from the beginning of the encrypted message to initialize the decryption class and then decrypts the rest of the bytes. I have attempted to do this in the following code. But I keep getting the "Length of the data to decrypt is invalid." error message when I attempt the decrypt after the encryption. Could someone possibly shed some light on what might be wrong.
USAGE: (streamToEncrypt/streamToDecrypt are System.IO.Stream)
using (var cryptoHelper = new AESHelper())
{
var encryptedBytes = cryptoHelper.Encrypt(AESHelper.StreamToByteArray(streamToEncrypt));
}
using (var cryptoHelper = new AESHelper())
{
var decryptedBytes = cryptoHelper.Decrypt(AESHelper.StreamToByteArray(streamToDecrypt));
}
public class AESHelper : IDisposable
{
public AesManaged AESManaged;
internal ICryptoTransform Encryptor { get; set; }
internal ICryptoTransform Decryptor { get; set; }
private const string KEY = "2428GD19569F9B2C2341839416C8E87G";
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("?pt1$8f]l4g80");
private const Int32 ITERATIONS = 1042;
internal AESHelper()
{
AESManaged = new AesManaged();
AESManaged.BlockSize = AESManaged.LegalBlockSizes[0].MaxSize;
AESManaged.KeySize = AESManaged.LegalKeySizes[0].MaxSize;
AESManaged.Mode= CipherMode.CBC;
}
public void KeyGenerator()
{
var key = new Rfc2898DeriveBytes(KEY, Salt, ITERATIONS);
AESManaged.Key = key.GetBytes(AESManaged.KeySize / 8);
}
public byte[] Encrypt(byte[] input)
{
KeyGenerator();
var ms = new MemoryStream();
//Random IV
Encryptor = AESManaged.CreateEncryptor(AESManaged.Key, AESManaged.IV);
//Add the IV to the beginning of the memory stream
ms.Write(BitConverter.GetBytes(AESManaged.IV.Length), 0, sizeof(int));
ms.Write(AESManaged.IV, 0, AESManaged.IV.Length);
var cs = new CryptoStream(ms,
Encryptor, CryptoStreamMode.Write);
cs.Write(input, 0, input.Length);
cs.Close();
return ms.ToArray();
}
public byte[] Decrypt(byte[] input)
{
KeyGenerator();
// Get the initialization vector from the encrypted stream
var ms = new MemoryStream(input);
AESManaged.IV = ReadByteArray(ms);
Decryptor = AESManaged.CreateDecryptor(AESManaged.Key, AESManaged.IV);
var cs = new CryptoStream(ms,
Decryptor, CryptoStreamMode.Write);
cs.Write(input, 0, input.Length);
cs.Close();//Error occurs here
return ms.ToArray();
}
internal static byte[] ReadByteArray(Stream s)
{
var rawLength = new byte[sizeof(int)];
if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
{
throw new SystemException("Stream did not contain properly formatted byte array");
}
var buffer = new byte[16];
if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
{
throw new SystemException("Did not read byte array properly");
}
return buffer;
}
internal static byte[] StreamToByteArray(Stream inputStream)
{
if (!inputStream.CanRead)
{
throw new ArgumentException();
}
// This is optional
if (inputStream.CanSeek)
{
inputStream.Seek(0, SeekOrigin.Begin);
}
var output = new byte[inputStream.Length];
var bytesRead = inputStream.Read(output, 0, output.Length);
Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length");
return output;
}
public void Dispose()
{
if (AESManaged != null)
((IDisposable) AESManaged).Dispose();
}}
Many Thanks in advance
Probably you have solved this already but I'll just put my answer for others who faces similar issue.
Error occurs due to the additional information present in the input array. In public byte[] Encrypt(byte[] input) method you are writing IV length and IV before the ciphered data is written. Lines:
ms.Write(BitConverter.GetBytes(AESManaged.IV.Length), 0, sizeof(int));
ms.Write(AESManaged.IV, 0, AESManaged.IV.Length);
In public byte[] Decrypt(byte[] input) method you are reading this information and using read IV as initialization vector for AES algorithm. All fine. Then you are constructing CryptoStream with CryptoStreamMode.Write and passing MemoryStream object ms which gets decrypted data. However the passed input array contains not only the encrypted message but also the IV that you wrote during the encryption process. That is why it fails to decrypt.
What you need to do to overcome this is either extract only cipher data from the input array and pass it to: cs.Write(cipherData, 0, cipherData.Length); or change mode into CryptoStreamMode.Read and use cs.Read(outputBuff, 0, outputBuff.Length);.
Also don't use the same MemoryStream object to read and write to because you'll have some garbage in it after CryptoStream will write in it.

C# Encrypt Text Output

I have created a few little programs that export data to a text file using StreamWriter and then I read them back in using StreamReader. This works great and does what I need it to do but I was wondering if there was a way that I could save this information without the user being able to access or modify it either intentionally or unintentionally. An example of something I would have in a text file would be if a checkbox was ticked, when you tick it it outputs "Ticked" to a text file, when the program is re - opened I know what state the form was in when it was closed. I obviously don't want to keep using text files. Does anyone have any ideas on how I can easily store this information without the user being able to modify it? Thank you very much.
The simplest way is to Base-64 encode/decode this text. This is not secure, but will prevent a casual user from modifying the data.
static public string EncodeTo64(string toEncode)
{
byte[] toEncodeAsBytes
= System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
string returnValue
= System.Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
static public string DecodeFrom64(string encodedData)
{
byte[] encodedDataAsBytes
= System.Convert.FromBase64String(encodedData);
string returnValue =
System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
return returnValue;
}
EDIT: Real encryption
#region Encryption
string passPhrase = "Pasword"; // can be any string
string saltValue = "sALtValue"; // can be any string
string hashAlgorithm = "SHA1"; // can be "MD5"
int passwordIterations = 7; // can be any number
string initVector = "~1B2c3D4e5F6g7H8"; // must be 16 bytes
int keySize = 256; // can be 192 or 128
private string Encrypt(string data)
{
byte[] bytes = Encoding.ASCII.GetBytes(this.initVector);
byte[] rgbSalt = Encoding.ASCII.GetBytes(this.saltValue);
byte[] buffer = Encoding.UTF8.GetBytes(data);
byte[] rgbKey = new PasswordDeriveBytes(this.passPhrase, rgbSalt, this.hashAlgorithm, this.passwordIterations).GetBytes(this.keySize / 8);
RijndaelManaged managed = new RijndaelManaged();
managed.Mode = CipherMode.CBC;
ICryptoTransform transform = managed.CreateEncryptor(rgbKey, bytes);
MemoryStream stream = new MemoryStream();
CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write);
stream2.Write(buffer, 0, buffer.Length);
stream2.FlushFinalBlock();
byte[] inArray = stream.ToArray();
stream.Close();
stream2.Close();
return Convert.ToBase64String(inArray);
}
private string Decrypt(string data)
{
byte[] bytes = Encoding.ASCII.GetBytes(this.initVector);
byte[] rgbSalt = Encoding.ASCII.GetBytes(this.saltValue);
byte[] buffer = Convert.FromBase64String(data);
byte[] rgbKey = new PasswordDeriveBytes(this.passPhrase, rgbSalt, this.hashAlgorithm, this.passwordIterations).GetBytes(this.keySize / 8);
RijndaelManaged managed = new RijndaelManaged();
managed.Mode = CipherMode.CBC;
ICryptoTransform transform = managed.CreateDecryptor(rgbKey, bytes);
MemoryStream stream = new MemoryStream(buffer);
CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Read);
byte[] buffer5 = new byte[buffer.Length];
int count = stream2.Read(buffer5, 0, buffer5.Length);
stream.Close();
stream2.Close();
return Encoding.UTF8.GetString(buffer5, 0, count);
}
#endregion
You should call ProtectedData.Protect to encrypt the data using a per-user key.
Note that it wouldn't be very hard for a skilled user to decrypt and modify the data.
Anything that your program does on the user's machine can be done by the user too.
You can add a checksum or hash to the file - if the file contents doesn't agree with the checksum, you know it was tampered with.
If it is important that users can't read the contents of the file, you can encrypt it.
I don't believe you can make a file that can't be tampered with (a savvy user could use a hex editor and change it, for example) - the best you can do is detect such tampering.
You can use the Ionic zip libraries to zip those text files. If necessary you could also use features of Ionic zip like password protection and encryption. And you'll still be able to open the file (with zipping applications like, for example, 7zip) manually yourself using the same settings you used to create it in the first place.
If a program can access the information, a user usually can too. However you can produce data the user will not immediately understand.
I would start by creating a class that holds all state information you want to save, isolating the problem. Coincidentally, the BinaryFormatter class will then allow you to easily save and load this class to/from a file. I don't know if it's results are "unreadable enough" - if not, apply Base64 encoding like Leon mentioned.
While you could base64 encode or even fully encrypt your configuration data (with SHA1 or MD5) as already suggested, I think good practice would be to work with the framework classes dealing with configuration data (Configuration under the System.Configuration namespace) and it's built in ability to encrypt data (via the ProtectSection method of the ConfigurationSection class).
First of all you should declare and initialize an instance:
using System.Configuration;
...
static void Main(string[] args)
{
Configuration config;
config = ConfigurationManager.OpenExeConfiguration(/*path to config file*/); //Use ConfigurationManager.OpenMachineConfiguration(/*path to config file*/) when opening machine configuration
...
After that you need to define a custom configuration section that defines your configuration (msdn example)
Once you've done that you just need to initialize an instance of your custom configuration section and add it to the configuration file using this code:
isTicked = config.Sections.Add("isTicked", customSection);
To encrypt the section you just added use this code (with further examples in both VB.NET and C# found here):
config.Sections["isTicked"].SectionInformation.ProtectSection("protection provider");
The "DPAPIProtectedConfigurationProvider" and "RSAProtectedConfigurationProvider" are built in by default.
Once you want to decrypt the section use this code:
config.Sections["isTicked"].SectionInformation.UnprotectSection();
To stress a point - encryption and decryption both take effect only after you save the configuration file
To save the file, use the code:
config.Save(); //config.SaveAs("string") is also available
Further information about the relevant classes and methods can be found in the msdn, starting with the Configuration class page linked above.
Try this code to encrypt and decrypt your text!
It is quite easy and strong I think...
public static class Crypto
{
private static readonly byte[] IVa = new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
public static string Encrypt(this string text, string salt)
{
try
{
using (Aes aes = new AesManaged())
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
aes.Key = deriveBytes.GetBytes(128 / 8);
aes.IV = aes.Key;
using (MemoryStream encryptionStream = new MemoryStream())
{
using (CryptoStream encrypt = new CryptoStream(encryptionStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] cleanText = Encoding.UTF8.GetBytes(text);
System.Diagnostics.Debug.WriteLine(String.Concat("Before encryption text data size: ", text.Length.ToString()));
System.Diagnostics.Debug.WriteLine(String.Concat("Before encryption byte data size: ", cleanText.Length.ToString()));
encrypt.Write(cleanText, 0, cleanText.Length);
encrypt.FlushFinalBlock();
}
byte[] encryptedData = encryptionStream.ToArray();
string encryptedText = Convert.ToBase64String(encryptedData);
System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted text data size: ", encryptedText.Length.ToString()));
System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted byte data size: ", encryptedData.Length.ToString()));
return encryptedText;
}
}
}
catch(Exception e)
{
return String.Empty;
}
}
public static string Decrypt(this string text, string salt)
{
try
{
using (Aes aes = new AesManaged())
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
aes.Key = deriveBytes.GetBytes(128 / 8);
aes.IV = aes.Key;
using (MemoryStream decryptionStream = new MemoryStream())
{
using (CryptoStream decrypt = new CryptoStream(decryptionStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
byte[] encryptedData = Convert.FromBase64String(text);
System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted text data size: ", text.Length.ToString()));
System.Diagnostics.Debug.WriteLine(String.Concat("Encrypted byte data size: ", encryptedData.Length.ToString()));
decrypt.Write(encryptedData, 0, encryptedData.Length);
decrypt.Flush();
}
byte[] decryptedData = decryptionStream.ToArray();
string decryptedText = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
System.Diagnostics.Debug.WriteLine(String.Concat("After decryption text data size: ", decryptedText.Length.ToString()));
System.Diagnostics.Debug.WriteLine(String.Concat("After decryption byte data size: ", decryptedData.Length.ToString()));
return decryptedText;
}
}
}
catch(Exception e)
{
return String.Empty;
}
}
}
Just to add another implementation of Leon's answer, and following the
Microsoft docs
Here a class example that encrypts and decrypts strings
public static class EncryptionExample
{
#region internal consts
internal const string passPhrase = "pass";
internal const string saltValue = "salt";
internal const string hashAlgorithm = "MD5";
internal const int passwordIterations = 3; // can be any number
internal const string initVector = "0123456789abcdf"; // must be 16 bytes
internal const int keySize = 64; // can be 192 or 256
#endregion
#region public static Methods
public static string Encrypt(string data)
{
string res = string.Empty;
try
{
byte[] bytes = Encoding.ASCII.GetBytes(initVector);
byte[] rgbSalt = Encoding.ASCII.GetBytes(saltValue);
byte[] buffer = Encoding.UTF8.GetBytes(data);
byte[] rgbKey = new PasswordDeriveBytes(passPhrase, rgbSalt, hashAlgorithm, passwordIterations).GetBytes(keySize / 8);
RijndaelManaged managed = new RijndaelManaged();
managed.Mode = CipherMode.CBC;
ICryptoTransform transform = managed.CreateEncryptor(rgbKey, bytes);
byte[] inArray = null;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, transform, CryptoStreamMode.Write))
{
csEncrypt.Write(buffer, 0, buffer.Length);
csEncrypt.FlushFinalBlock();
inArray = msEncrypt.ToArray();
res = Convert.ToBase64String(inArray);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Encrypt " + ex);
}
return res;
}
public static string Decrypt(string data)
{
string res = string.Empty;
try
{
byte[] bytes = Encoding.ASCII.GetBytes(initVector);
byte[] rgbSalt = Encoding.ASCII.GetBytes(saltValue);
byte[] buffer = Convert.FromBase64String(data);
byte[] rgbKey = new PasswordDeriveBytes(passPhrase, rgbSalt, hashAlgorithm, passwordIterations).GetBytes(keySize / 8);
RijndaelManaged managed = new RijndaelManaged();
managed.Mode = CipherMode.CBC;
ICryptoTransform transform = managed.CreateDecryptor(rgbKey, bytes);
using (MemoryStream msEncrypt = new MemoryStream(buffer))
{
using (CryptoStream csDecrypt = new CryptoStream(msEncrypt, transform, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
res = srDecrypt.ReadToEnd();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Decrypt " + ex);
}
return res;
}
}
By the way, here is the "salt value" definition that I had googled to find out what it was.
Salt value
If an attacker does not know the password, and is trying to guess it with a brute-force attack, then every password he tries has to be tried with each salt value. So, for a one-bit salt (0 or 1), this makes the encryption twice as hard to break in this way.
Preventing unintentional string modification can be done using a checksum, as pointed in this answer.
However, it's quite easy to generate such a checksum, as they are not that many widely used algorithms.
Thus that doesn't protect you against intentional modification.
To prevent that, people use digital signatures. That allows anyone to verify your data hasn't be tampered, but only you (the owner of the private secret) can generate the signature.
Here is an example in C#.
However, as others pointed out, you need to embed your private key somewhere in your binary, and a (not so) skilled programmer will be able to retrieve it, even if you obfuscate your .net dll or you make that in a separate native process.
That would be enough for most concerns though.
If you are really concerned by security, then you need to move on the cloud, and execute the code on a machine you own.

Categories

Resources