Reputation: 35
When I tried to encrypt and decrypt a simple string, everything went perfectly fine..
But when I encoded a jpg into a bytearray and did the exact same thing with that bytearray, the decryption didn't work anymore (the bytearray is completely different to the original one and cannot be displayed anymore)...
Is it because the bytearray is too big?
Or does someone have a solution for my problem?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Encrypter2
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine();
// Create a new instance of the Rijndael
// class. This generates a new key and initialization
// vector (IV).
byte[] originalFile = File.ReadAllBytes(@"C:/Users/Elron/Documents/Visual Studio 2015/Projects/FileEncrypt/FileEncrypt/bin/Debug/harambe.jpg");
using (Rijndael myRijndael = Rijndael.Create())
{
// Encrypt the string to an array of bytes
// Encrypted byte[]
byte[] encrypted = EncryptStringToBytes(originalFile, myRijndael.Key, myRijndael.IV);
using (FileStream fs = File.Create(@"C:/Users/Elron/Documents/Visual Studio 2015/Projects/FileEncrypt/FileEncrypt/bin/Debug/harambeEncrypted.jpg"))
{
//Add some information to the file.
fs.Write(encrypted, 0, encrypted.Length);
}
// Decrypted byte[]
byte[] roundtrip = DecryptStringFromBytes(encrypted, myRijndael.Key, myRijndael.IV);
using (FileStream fs = File.Create(@"C:/Users/Elron/Documents/Visual Studio 2015/Projects/FileEncrypt/FileEncrypt/bin/Debug/harambeDecrypted.jpg"))
{
//Add some information to the file.
fs.Write(roundtrip, 0, roundtrip.Length);
}
// Display the original data and the decrypted data.
// Encrypted string
Console.ReadKey();
}
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
}
}
static byte[] EncryptStringToBytes(byte[] plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
// Create an Rijndael object
// with the specified key and IV.
using (Rijndael rijAlg = Rijndael.Create())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.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.
string toEncrypt = Encoding.Default.GetString(plainText);
swEncrypt.Write(toEncrypt);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
static byte[] DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
byte[] returnText;
// Create an Rijndael object
// with the specified key and IV.
using (Rijndael rijAlg = Rijndael.Create())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(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();
ASCIIEncoding asc = new ASCIIEncoding();
returnText = asc.GetBytes(plaintext);
}
}
}
}
return returnText;
}
}
}
Upvotes: 0
Views: 150
Reputation: 120496
You can't treat an arbitrary array of bytes as a string. You're taking the bytes, converting them to a string, then writing the string into a StreamWriter, which converts the string back to bytes. This will be a lossy operation over a bunch of arbitrary bytes.
Your method EncryptStringToBytes
is a mistaken concept. You should have a method EncryptBytes
(and DecryptBytes
) which don't concern themselves with strings. Then you can pass in a byte array and feed it directly into the CryptoStream
. How those bytes are interpreted isn't the concern of an encryption algorithm.
So you could tweak your methods as follows:
static byte[] EncryptBytes(byte[] bytes, byte[] Key, byte[] IV)
{
// Check arguments.
if (bytes == null || bytes.Length <= 0)
throw new ArgumentNullException("bytes");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Create an Rijndael object
// with the specified key and IV.
using (Rijndael rijAlg = Rijndael.Create())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor,
CryptoStreamMode.Write))
{
csEncrypt.Write(bytes,0,bytes.Length);
csEncrypt.FlushFinalBlock();
return msEncrypt.ToArray();
}
}
}
}
and
static byte[] DecryptBytes(byte[] encryptedBytes, byte[] Key, byte[] IV)
{
// Check arguments.
if (encryptedBytes == null || encryptedBytes.Length <= 0)
throw new ArgumentNullException("encryptedBytes");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Create an Rijndael object
// with the specified key and IV.
using (Rijndael rijAlg = Rijndael.Create())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream())
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor,
CryptoStreamMode.Write))
{
csDecrypt.Write(encryptedBytes,0,encryptedBytes.Length);
csDecrypt.FlushFinalBlock();
return msDecrypt.ToArray();
}
}
}
}
then test with a roundtrip:
using(var rijndael = Rijndael.Create())
{
var stringToEncrypt = "foobar";
var bytesToEncrypt = Encoding.UTF8.GetBytes(stringToEncrypt);
var encryptedBytes = EncryptBytes(bytesToEncrypt, rijndael.Key, rijndael.IV);
var decryptedBytes = DecryptBytes(encryptedBytes, rijndael.Key, rijndael.IV);
var originalString = Encoding.UTF8.GetString(decryptedBytes);
Debug.Assert(string.Equals(stringToEncrypt, originalString,
StringComparison.InvariantCulture));
}
hopefully, by this point, it's clear how we've disentangled the string encoding issues from the encryption and how you might now repurpose these methods for any kind of binary data.
Upvotes: 3
Reputation: 3541
I think you are using different Encodings in your encryption and decryption methods
static byte[] DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
...
ASCIIEncoding asc = new ASCIIEncoding();
returnText = asc.GetBytes(plaintext);
...
}
And
static byte[] EncryptStringToBytes(byte[] plainText, byte[] Key, byte[] IV)
{
...
string toEncrypt = Encoding.Default.GetString(plainText);
swEncrypt.Write(toEncrypt);
...
}
Upvotes: 0