This is a method, for encrypting a text and returning the cipher text:
public static string Encrypt(this string clearText, CryptologyMethod method)
{
ICryptoTransform cryptoTransform = null;
switch (method)
{
case CryptologyMethod.TripleDes:
cryptoTransform = new TripleDESCryptoServiceProvider().CreateEncryptor(Config.TripleDesKey, Config.TripleDesIV);
break;
case CryptologyMethod.AES:
cryptoTransform = new AesCryptoServiceProvider().CreateEncryptor(Config.AesKey, Config.AesIV);
break;
}
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
{
streamWriter.Write(clearText);
cryptoStream.FlushFinalBlock();
return memoryStream.Text();
}
}
}
}
public enum CryptologyMethod
{
TripleDes,
AES
}
Text() is an extension method, to read the content of a stream:
public static string Text(this Stream stream)
{
return new StreamReader(stream).ReadToEnd();
}
Also, Config.TripleDesKey and other properties return array of bytes read from configuration file.
The problem is that when I use this extension method, the result is always an empty string:
string cipherText = "some clear text".Encrypt(CryptologyMethod.TripleDes);
// cipherText is empty
I think I've had that issue before, the solution was pretty obvious once I figured it out and completely opaque before then.
The problem was that ReadToEnd is relative, as in "from current location to end". The problem being that "current position" already WAS "end" because I'd just finished writing to the end of the stream. So I would fix your problem like this:
public static string Text(this Stream stream)
{
stream.Position = 0
return new StreamReader(stream).ReadToEnd();
}
Worked for me with a similar issue, hope it helps.
Related
I'm developing a game using Unity engine. Currently, I'm on my very first journey to creating a secure and universal game data saving/loading. My game is able to succesfully save its data (game progress) and metadata (custom savable types, encapsulating the data, and necessary for succesfull data deserialization) into two files, but when it comes to loading the data, a weird error occurs upon decoding. It appears a really weird one to me because I googled similar error topics but wasn't able to find a satisfying answer.
The error and its stacktrace are:
CryptographicException: Bad PKCS7 padding. Invalid length 0.
Mono.Security.Cryptography.SymmetricTransform.ThrowBadPaddingException (System.Security.Cryptography.PaddingMode padding, System.Int32 length, System.Int32 position) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
Mono.Security.Cryptography.SymmetricTransform.FinalDecrypt (System.Byte[] inputBuffer, System.Int32 inputOffset, System.Int32 inputCount) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
Mono.Security.Cryptography.SymmetricTransform.TransformFinalBlock (System.Byte[] inputBuffer, System.Int32 inputOffset, System.Int32 inputCount) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
System.Security.Cryptography.CryptoStream.FlushFinalBlock () (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
System.Security.Cryptography.CryptoStream.Dispose (System.Boolean disposing) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
System.IO.Stream.Close () (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
System.IO.StreamReader.Dispose (System.Boolean disposing) (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
System.IO.TextReader.Dispose () (at <9aad1b3a47484d63ba2b3985692d80e9>:0)
AuxMath.Decode (System.String input, System.Security.Cryptography.Aes decoder, System.Text.Encoding encoding) (at Assets/Scripts/Misc/AuxMath.cs:191)
SavingSystem.TryLoadMetadata (System.Security.Cryptography.Aes decoder, System.Text.Encoding encoding) (at Assets/Scripts/Saving System/SavingSystem.cs:164)
Rethrow as Exception: Metadata loading failed!
SavingSystem.TryLoadMetadata (System.Security.Cryptography.Aes decoder, System.Text.Encoding encoding) (at Assets/Scripts/Saving System/SavingSystem.cs:180)
SavingSystem.Load () (at Assets/Scripts/Saving System/SavingSystem.cs:82)
SavingSystem.Awake () (at Assets/Scripts/Saving System/SavingSystem.cs:43)
My saving/loading.
private void Save()
{
Aes encoder = Aes.Create();
encoder.Key = _keyContainer.Key;
PrepareSavableData();
SaveGameData(encoder, Encoding.UTF8);
SaveMetadata(encoder, Encoding.UTF8);
SavegameCompleted?.Invoke(this, EventArgs.Empty);
}
private bool Load()
{
Aes decoder = Aes.Create();
decoder.Key = _keyContainer.Key;
if (TryLoadMetadata(decoder, Encoding.UTF8) && TryLoadGameData(decoder, Encoding.UTF8))
{
return true;
}
return false;
}
The key for encryption is created randomly using default Aes settings and stored inside a KeyContainer ScriptableObject.
Here is the actual saving.
private void PrepareSavableData()
{
foreach (var entity in _registeredEntities)
{
_storedStates[entity.ID] = entity.GetState();
}
}
private void SaveMetadata(Aes encoder, Encoding encoding)
{
using FileStream fileStream = new(MetadataPath, FileMode.Create, FileAccess.Write);
using StreamWriter writer = new(fileStream, encoding);
List<string> knownTypesNames = new(_knownSavableDataCustomTypes.Count);
foreach (var type in _knownSavableDataCustomTypes)
{
knownTypesNames.Add(type.ToString());
}
string data = AuxMath.SerializeObjectToString(knownTypesNames, encoding);
string encodedData = AuxMath.Encode(data, encoder, encoding);
writer.Write(encodedData);
writer.Close();
}
private bool TryLoadMetadata(Aes decoder, Encoding encoding)
{
if (File.Exists(MetadataPath))
{
try
{
using FileStream fileStream = new(MetadataPath, FileMode.Open, FileAccess.Read);
using StreamReader reader = new(fileStream, encoding);
string encodedData = reader.ReadToEnd();
string decodedData = AuxMath.Decode(encodedData, decoder, encoding);
var knownTypesNames = AuxMath.DeserializeStringToObject<List<string>>(decodedData, encoding, _knownSavableDataCustomTypes);
HashSet<Type> knownTypes = new(knownTypesNames.Count);
foreach (var typeName in knownTypesNames)
{
knownTypes.Add(Type.GetType(typeName));
}
_knownSavableDataCustomTypes.UnionWith(knownTypes);
return true;
}
catch (Exception e)
{
throw new Exception("Metadata loading failed!", e);
}
}
return false;
}
private void SaveGameData(Aes encoder, Encoding encoding)
{
using FileStream fileStream = new(SavegamePath, FileMode.Create, FileAccess.Write);
using StreamWriter writer = new(fileStream, encoding);
string data = AuxMath.SerializeObjectToString(_storedStates, encoding);
string encodedData = AuxMath.Encode(data, encoder, encoding);
writer.Write(encodedData);
writer.Close();
}
private bool TryLoadGameData(Aes decoder, Encoding encoding)
{
if (File.Exists(SavegamePath))
{
try
{
using FileStream fileStream = new(SavegamePath, FileMode.Open, FileAccess.Read);
using StreamReader reader = new(fileStream, encoding);
string encodedData = reader.ReadToEnd();
string decodedData = AuxMath.Decode(encodedData, decoder, encoding);
_storedStates = AuxMath.DeserializeStringToObject<Dictionary<string, IEnumerable<object>>>(decodedData, encoding, _knownSavableDataCustomTypes);
return true;
}
catch (Exception e)
{
throw new Exception("Game data loading failed!", e);
}
}
return false;
}
I'm using DataContractSerializer to convert custom object types with a valuable game data to XML string representation in preparation for encoding/decoding.
public static string SerializeObjectToString(object obj, Encoding encoding)
{
if (obj is null)
{
throw new ArgumentNullException($"{nameof(obj)}", "Cannot serialize a null object!");
}
using MemoryStream memoryStream = new();
using StreamReader reader = new(memoryStream, encoding);
DataContractSerializer serializer = new(obj.GetType());
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
return reader.ReadToEnd();
}
public static T DeserializeStringToObject<T>(string objectAsXml, Encoding encoding, IEnumerable<Type> knownTypes)
{
if (string.IsNullOrEmpty(objectAsXml))
{
throw new ArgumentNullException($"{nameof(objectAsXml)}", "Data is empty!");
}
if (knownTypes is null)
{
throw new ArgumentException("Known types are not supplied! Deserialization will fail!", $"{nameof(knownTypes)}");
}
using MemoryStream memoryStream = new();
byte[] xmlAsBytes = encoding.GetBytes(objectAsXml);
DataContractSerializer deserializer = new(typeof(T), knownTypes);
memoryStream.Write(xmlAsBytes, 0, xmlAsBytes.Length);
memoryStream.Position = 0;
if (deserializer.ReadObject(memoryStream) is T value)
{
return value;
}
else
{
throw new Exception("Passed data is invalid or corrupted and cannot be restored!");
}
}
Finally, encoding and decoding. Encryption algorithm gets a new initialization vector on every encoding. It gets written unencryptedly directly into the stream, before the encrypted stream writes the secured data. Upon decryption it is necessary to read 16 bytes first from the stream, as they represent the decryption initialization vector.
public static string Encode(string input, Aes encoder, Encoding encoding)
{
if (string.IsNullOrEmpty(input))
{
throw new ArgumentNullException($"{nameof(input)}", "Attempted to encode an empty input!");
}
if (encoder is null)
{
throw new ArgumentNullException($"{nameof(encoder)}", "Encoder is not set!");
}
encoder.GenerateIV();
using MemoryStream memoryStream = new();
using CryptoStream encodingStream = new(memoryStream, encoder.CreateEncryptor(), CryptoStreamMode.Write);
using StreamWriter encodedWriter = new(encodingStream, encoding);
memoryStream.Write(encoder.IV);
encodedWriter.Write(input);
memoryStream.Position = 0;
encodedWriter.Close();
return encoding.GetString(memoryStream.ToArray());
}
public static string Decode(string input, Aes decoder, Encoding encoding)
{
if (string.IsNullOrEmpty(input))
{
throw new ArgumentNullException($"{nameof(input)}", "Attempted to decode an empty input!");
}
if (decoder is null)
{
throw new ArgumentNullException($"{nameof(decoder)}", "Decoder is not set!");
}
using MemoryStream memoryStream = new();
memoryStream.Write(encoding.GetBytes(input));
byte[] iv = new byte[decoder.IV.Length];
memoryStream.Read(iv, 0, decoder.IV.Length);
decoder.IV = iv;
using CryptoStream decodingStream = new(memoryStream, decoder.CreateDecryptor(), CryptoStreamMode.Read);
using StreamReader decodedReader = new(decodingStream, encoding);
return decodedReader.ReadToEnd();
}
The following code both works perfectly and is a lot shorter:
public static byte[] Encrypt(byte[] input, KeyContainer container)
{
byte[] iv = container.GetNewIV();
using SymmetricAlgorithm algorithm = Aes.Create();
using ICryptoTransform encryptor = algorithm.CreateEncryptor(container.GetKey(), iv);
List<byte> output = new(iv.Length + input.Length + algorithm.BlockSize / 8);
byte[] encryptedInput = encryptor.TransformFinalBlock(input, 0, input.Length);
output.AddRange(iv);
output.AddRange(encryptedInput);
algorithm.Clear();
return output.ToArray();
}
public static byte[] Decrypt(byte[] input, KeyContainer container)
{
byte[] iv = input[..KeyContainer.IVLength];
byte[] encryptedInput = input[KeyContainer.IVLength..];
using SymmetricAlgorithm algorithm = Aes.Create();
using ICryptoTransform decryptor = algorithm.CreateDecryptor(container.GetKey(), iv);
byte[] output = decryptor.TransformFinalBlock(encryptedInput, 0, encryptedInput.Length);
algorithm.Clear();
return output;
}
Instead of referring to an Aes instance directly a more generalized SymmetricAlgorithm must be used because AES is one of the implementations of a symmetric encryption.
Instead of trying to perform cryptographic transformations implicitly by using ICryptoTransform as a backing resource inside a stream, one must be performed by calling TransformFinalBlock() method.
After all the crypto activity is done, any memory containing valuable data must be overridden by calling the Clear() method on a symmetric algorithm instance. This way hackers cannot recower any data to attempt and actually succesfully decrypt the result.
Currently I creating a save\load system for my game. Its purpose is to be able to convert a Dictionary<string, object> to an encrypted string, and write it to disk file, and vice versa.
Saving functionality works just fine as follows:
public void Save()
{
PrepareSavableData();
using StreamWriter writer = new(SavegamePath);
string rawData = AuxMath.SerializeObjectToString(_storedStates);
string encodedData = AuxMath.Encode(rawData, PublicKey, PrivateKey);
writer.Write(encodedData);
writer.Close();
SavegameCompleted?.Invoke(this, EventArgs.Empty);
}
private void PrepareSavableData()
{
foreach (var entity in _registeredEntities)
{
_storedStates[entity.ID] = entity.GetState();
}
}
I fetch the data from every registered SavableEntitiy as follows:
public object GetState()
{
List<object> states = new(_savables.Count);
foreach (var savable in _savables)
{
states.Add(savable.CaptureState());
}
return states;
}
In the Save() above I use DES algorithm to encrypt data that is previously serialized to a string. No problems with that as well - I tested it thoroughly.
public static string SerializeObjectToString(object obj)
{
using MemoryStream memoryStream = new();
using StreamReader reader = new(memoryStream, Encoding.UTF8);
DataContractSerializer serializer = new(obj.GetType());
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
return reader.ReadToEnd();
}
public static string Encode(string input, string publicKey, string privateKey)
{
try
{
byte[] inputAsBytes = Encoding.UTF8.GetBytes(input);
byte[] publicKeyAsBytes = Encoding.UTF8.GetBytes(publicKey);
byte[] privateKeyAsBytes = Encoding.UTF8.GetBytes(privateKey);
using DESCryptoServiceProvider cryptoServiceProvider = new();
using MemoryStream memoryStream = new();
using CryptoStream cryptoStream = new(memoryStream,
cryptoServiceProvider.CreateEncryptor(publicKeyAsBytes, privateKeyAsBytes),
CryptoStreamMode.Write);
cryptoStream.Write(inputAsBytes, 0, inputAsBytes.Length);
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(memoryStream.ToArray());
}
catch (Exception e)
{
return e.Message;
}
}
So fetching the savable data, serializing it, encoding, and writing to a disc file works without a hitch. At the game startup save file loading is performed, decoding, and deserialization, so that later any SavableEntity which registers itself can restore its previous state if one exists in the state dictionary. Reading the save file and decoding it works just fine.
private bool Load()
{
if (File.Exists(SavegamePath))
{
try
{
using StreamReader reader = new(SavegamePath);
string encodedData = reader.ReadToEnd();
string decodedData = AuxMath.Decode(encodedData, PublicKey, PrivateKey);
_storedStates = AuxMath.DeserializeStringToObject<Dictionary<string, object>>(decodedData, _knownSavableTypes);
SavegameLoadSuccesful?.Invoke(this, EventArgs.Empty);
return true;
}
catch (Exception e)
{
SavegameLoadFailed?.Invoke(this, new SavegameLoadFailedEventArgs(e.Message));
return false;
}
}
return false;
}
public static string Decode(string encodedInput, string publicKey, string privateKey)
{
try
{
byte[] encodedInputAsBytes = Convert.FromBase64String(encodedInput);
byte[] publicKeyAsBytes = Encoding.UTF8.GetBytes(publicKey);
byte[] privateKeyAsBytes = Encoding.UTF8.GetBytes(privateKey);
using DESCryptoServiceProvider cryptoServiceProvider = new();
using MemoryStream memoryStream = new();
using CryptoStream cryptoStream = new(memoryStream,
cryptoServiceProvider.CreateDecryptor(publicKeyAsBytes, privateKeyAsBytes),
CryptoStreamMode.Write);
cryptoStream.Write(encodedInputAsBytes, 0, encodedInputAsBytes.Length);
cryptoStream.FlushFinalBlock();
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
catch (Exception e)
{
return e.Message;
}
}
But, when it finally comes to the data deserialization phase from a successfully loaded and decoded file, an error occurs inside exactly this deserialization method right inside the if statement. DataContractSerializer cannot properly deserialize a states dictionary from a memory stream.
public static T DeserializeStringToObject<T>(string objectAsXml, IEnumerable<Type> knownTypes)
{
using MemoryStream memoryStream = new();
using StreamWriter writer = new(memoryStream, Encoding.UTF8);
DataContractSerializer deserializer = new(typeof(T), knownTypes);
writer.Write(objectAsXml);
memoryStream.Position = 0;
if (deserializer.ReadObject(memoryStream) is T value)
{
return value;
}
else
{
throw new Exception("Passed data is invalid or corrupted and cannot be properly restored!");
}
}
Currently this error occurs:
XmlException: Unexpected end of file. Following elements are not closed: Value, KeyValueOfstringanyType, ArrayOfKeyValueOfstringanyType. Line 1, position 197.
It may be something trivial, but I wasn't able to crack it on my own so far. Please, help!
Best regards, Vyacheslav.
im trying to write an En-/Decrypter in C#. As the title suggests I get a System.Security.Cryptography.CryptographicException at CryptoStream.close(). I haven't find a solution yet. Hope anyone can help.
public static string viaRijndael(byte[] input, string key, string iV)
{
Rijndael RijCrypt = Rijndael.Create();
RijCrypt.Key = System.Text.Encoding.UTF8.GetBytes(Tools.GetMD5Hash(Tools.GetMD5Hash(key)));
RijCrypt.IV = System.Text.Encoding.UTF8.GetBytes(Tools.GetMD5Hash(Tools.GetMD5Hash(key)).Substring(0, 16));
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, RijCrypt.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(input, 0, input.Length);
cs.Close(); // System.Security.Cryptography.CryptographicException
byte[] DecryptedBytes = ms.ToArray();
return System.Text.Encoding.UTF8.GetString(DecryptedBytes);
}
MSDN Stream.Close documentation says:
"This method calls Dispose, specifying true to release all resources. You do not have to specifically call the Close method. Instead, ensure that every Stream object is properly disposed. You can declare Stream objects within a using block (or Using block in Visual Basic) to ensure that the stream and all of its resources are disposed, or you can explicitly call the Dispose method."
As such I would suggest trying something like the following to handle the disposal of your streams:
public static string viaRijndael(byte[] input, string key, string iV)
{
byte[] decryptedBytes;
using (Rijndael rijCrypt = Rijndael.Create())
{
rijCrypt.Key = System.Text.Encoding.UTF8.GetBytes(Tools.GetMD5Hash(Tools.GetMD5Hash(key)));
rijCrypt.IV = System.Text.Encoding.UTF8.GetBytes(Tools.GetMD5Hash(Tools.GetMD5Hash(key)).Substring(0, 16));
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, rijCrypt.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(input, 0, input.Length);
}
decrpytedBytes = ms.ToArray();
}
}
return System.Text.Encoding.UTF8.GetString(decryptedBytes);
}
All of this and more is explained in good detail on MSDN for the CryptoStream class.
I am a little programmer in C # , VB.NET do however have to code a lot of time . Now I was in doubt if the code was doing well . I need your help to create a function that makes the return of a string , already tested the following code , but the compiler gives an error :
public class Main
{
private System.Text.UTF8Encoding enc;
private ICryptoTransform encryptor;
private ICryptoTransform decryptor;
public string utf16_encrypt(string input)
{
string sPlainText = input;
string output;
if (!string.IsNullOrEmpty(sPlainText))
{
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, this.encryptor, CryptoStreamMode.Write);
cryptoStream.Write(enc.GetBytes(sPlainText), 0, sPlainText.Length);
cryptoStream.FlushFinalBlock();
output = Convert.ToBase64String(memoryStream.ToArray());
memoryStream.Close();
cryptoStream.Close();
return output;
}
}
}
The error given by the compiler is :
User, your method will not return anything if sPlainText is null. You have to keep this in mind and make sure all execution paths return code. You could change the code to be like this:
if (!string.IsNullOrEmpty(sPlainText))
{
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, this.encryptor, CryptoStreamMode.Write);
cryptoStream.Write(enc.GetBytes(sPlainText), 0, sPlainText.Length);
cryptoStream.FlushFinalBlock();
output = Convert.ToBase64String(memoryStream.ToArray());
memoryStream.Close();
cryptoStream.Close();
return output;
}
return "Invalid Input"; //Or whatever message you want to pass back to the user/code.
Put this : return output; out of the } brace like this :
if (!string.IsNullOrEmpty(sPlainText))
{
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, this.encryptor, CryptoStreamMode.Write);
cryptoStream.Write(enc.GetBytes(sPlainText), 0, sPlainText.Length);
cryptoStream.FlushFinalBlock();
output = Convert.ToBase64String(memoryStream.ToArray());
memoryStream.Close();
cryptoStream.Close();
}
return output;
You should think what your function should do if it doesn't enter the if statement.
You need a default return statement. Right now if the condition is not true you return nothing. Instead write at the end something like :
if (!string.IsNullOrEmpty(sPlainText))
{
...
return output;
}
return String.Empty;
The really short version of your code is
public string utf16_encrypt(string input)
{
string output;
if (somecondition)
{
return output;
}
}
The compiler knows what to do if some condition is true, but if it's false, it has no idea. It's looking for something like
public string utf16_encrypt(string input)
{
string output;
if (somecondition)
{
return output;
}
else {
return "banana"; //when in doubt, return bananas
}
}
The compiler is telling you that every logical path through the code must return a value. Since the method declares a return type:
public string utf16_encrypt(string input)
it must return something of that type (string). So the question becomes...
What happens if sPlainText is null or empty?
If it isn't null or empty, the code returns something:
return output;
But if it isn't null or empty, then that if block is never executed and there is no return statement. So you need to add one:
if (!string.IsNullOrEmpty(sPlainText))
{
// your current code
}
return output;
You don't have to return output specifically, I just guessed on what you might want to return. You may return a default value instead, something like:
return string.Empty;
It's up to you. The point is that logically the method must always return something (assuming it doesn't terminate in an exception condition instead).
Not all code parths return a value is meaningful, isn't it?
You have to ensure that a value is returned from the method in any case. You return only from inside the if, so nothing is returned if sPlainText==null. In that case you could return null:
public string utf16_encrypt(string input)
{
string sPlainText = input;
string output;
if (!string.IsNullOrEmpty(sPlainText))
{
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, this.encryptor, CryptoStreamMode.Write);
cryptoStream.Write(enc.GetBytes(sPlainText), 0, sPlainText.Length);
cryptoStream.FlushFinalBlock();
output = Convert.ToBase64String(memoryStream.ToArray());
memoryStream.Close();
cryptoStream.Close();
return output;
}
else
return null;
}
by the way, you also get a compiler warning in VB.NET if you comment out Return Nothing
Public Function utf16_encrypt(input As String) As String
Dim sPlainText As String = input
Dim output As String
If Not String.IsNullOrEmpty(sPlainText) Then
' ... '
Return output
Else
Return Nothing
End If
End Function
better to do like this, looks a lot simpler and easier
public string utf16_encrypt(string input)
{
if (!string.IsNullOrEmpty(input)) return null;
using (var memoryStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(memoryStream, this.encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(enc.GetBytes(input), 0, input.Length);
cryptoStream.FlushFinalBlock();
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(memoryStream.ToArray());
}
}
okay so I have this code for decrypting files
public static byte[] DecryptFile(string inputFile, string skey)
{
RijndaelManaged aes = new RijndaelManaged();
byte[] key = ASCIIEncoding.UTF8.GetBytes(skey);
using (FileStream fsCrypt = new FileStream(inputFile, FileMode.Open))
{
using (CryptoStream cs =
new CryptoStream(fsCrypt, aes.CreateDecryptor(key, key),
CryptoStreamMode.Read))
{
using (BinaryReader reader = new BinaryReader(cs))
{
byte[] str = reader.ReadBytes(Convert.ToInt32(cs.Length));
reader.Close();
cs.Close();
return (str);
}
}
}
}
}
NOW i've got a problem with it, i can't determine the byte length! I tried
cs.Length
but it says the Stream doesn't support seeking (something like tht)
I also tried counting the bytes of the file by
File.ReadAllBytes(encrypted_file_path).Length
but it says the file is in use...it is indeed in use because of the FileStream fsCrypt
for the meantime I replaced cs.Length with some large integer to make it work..like 1000000..the maximum integer that doesn't cause any exception..it does work that way.
You cannot know the length until after you decrypt the entire file.
Therefore, you need to start with a small array, and make it bigger as it gets full.
The MemoryStream class does just that; you can just cs.CopyTo() into a new MemoryStream and call ToArray().