FileStream.Read() Throws ArgumentException - c#

I would like to make some secure container for my application, and here's the map :
I finished opening/saving code now, and tested it, however, ArgumentException was thrown.
The code will run like this.
Create byte[] type variable for containing not crypted user data.
FileStream Writes Magic Number to first 5 bytes.
RijndaelManaged accepts key, and generates Initialization Vector.
FileStream Writes Initialization Vector to next 16 bytes. <- Exception thrown!
CryptoStream transform the variable from 1.
FileStream Writes the crypted data from 22th bytes.
Debugging, and I found the reason that FileStream.Read() has been thrown the Exception. and the message is:
Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.
I tried to set the length of stream as (user data) + 21. but it doesn't work. I attach entire code for saving file, and I hope this problem will be solved.
Thank you!
private bool SaveFile(string FilePath, bool IsCrypt)
{
byte[] Data = Encoding.UTF8.GetBytes(WorkspaceList[CurrentIndex]._textbox.Text);
using (var Stream = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
if (IsCrypt)
{
Stream.SetLength(Data.Length + 21); // Tried when I got Exception
Stream.Write(MagicNumber, 0, 5); //Magic Number
using (var CryptoHandler = new RijndaelManaged()) // AES256 Encryption
{
CryptoHandler.BlockSize = 128;
CryptoHandler.KeySize = 256;
CryptoHandler.Padding = PaddingMode.PKCS7;
CryptoHandler.Mode = CipherMode.CBC;
var tempKey = WorkspaceList[CurrentIndex]._cryptkey;
if(tempKey.Length < 32)
{
tempKey.PadRight(32);
}
else if (tempKey.Length > 32)
{
tempKey.Remove(33);
}
CryptoHandler.Key = Encoding.UTF8.GetBytes(WorkspaceList[CurrentIndex]._cryptkey.PadRight(32));
CryptoHandler.GenerateIV();
Stream.Write(CryptoHandler.IV, 5, 16); //IV Insertion *** ArgumentException ***
var CryptoInstance = CryptoHandler.CreateEncryptor(CryptoHandler.Key, CryptoHandler.IV);
using (var MemoryHandler = new MemoryStream())
{
using (var Crypto = new CryptoStream(MemoryHandler, CryptoInstance, CryptoStreamMode.Write))
{
byte[] _Buffer = Data;
Crypto.Read(Data, 0, Data.Length);
_Buffer = MemoryHandler.ToArray();
Stream.Write(_Buffer, 21, _Buffer.Length); // Insert Crypted Data
Stream.Close();
return true;
}
}
}
}
else
{
Stream.Write(Data, 0, Data.Length);
Stream.Close();
return true;
}
}
}

Replace Stream.Write(CryptoHandler.IV, 5, 16); //IV Insertion
With Stream.Write(CryptoHandler.IV, 0, CryptoHandler.IV.Length); //IV Insertion
array = CryptoHandler.IV (the data you want to write)
offset = 0 (you write from the first byte of array)
count = CryptoHandler.IV.Length (you write all bytes from CryptoHandler.IV)
Note that offset is intrinsic to array, not to the Stream. After a successful Write operation, the stream cursor waits at the last written position. I suppose you specified an offset of 5 to take into account the MagicNumber?
You would have add the same problem with Stream.Write(_Buffer, 21, _Buffer.Length);

Related

Encrypting and decrypting audio clip to file unity

I'm using AES for encrypting and decrypting, I can write it to a file and when I try to read the file back to audio clip, I'm getting input exception
I tried to convert the audio file to base64 byte array while saving in file so that when I read the file I can read it as byte array which is required for creating audio clip
I have attached the code below
private float[] ConvertByteToFloat(byte[] array)
{
float[] floatArr = new float[array.Length / 4];
for (int i = 0; i < floatArr.Length; i++)
{
if (BitConverter.IsLittleEndian)
{
Array.Reverse(array, i * 4, 4);
}
floatArr[i] = BitConverter.ToSingle(array, i * 4) / 0x80000000;
}
return floatArr;
}
public void ReadFile()
{
// Does the file exist AND does the "key" preference exist?
if (File.Exists(saveFile) && PlayerPrefs.HasKey("Key"))
{
// Update key based on PlayerPrefs
// (Convert the String into a Base64 byte[] array.)
byte[] savedKey = Convert.FromBase64String(PlayerPrefs.GetString("Key"));
byte[] savedIV = Convert.FromBase64String(PlayerPrefs.GetString("IV"));
// Create FileStream for opening files.
dataStream = new FileStream(saveFile, FileMode.Open);
Debug.Log(PlayerPrefs.GetString("Key"));
// Create new AES instance.
Aes oAes = Aes.Create();
// Create an array of correct size based on AES IV.
byte[] outputIV = new byte[savedIV.Length];
// Read the IV from the file.
dataStream.Read(savedIV, 0, outputIV.Length);
// Create CryptoStream, wrapping FileStream
CryptoStream oStream = new CryptoStream(dataStream, oAes.CreateDecryptor(savedKey, outputIV), CryptoStreamMode.Read);
// Create a StreamReader, wrapping CryptoStream
StreamReader reader = new StreamReader(oStream);
// Read the entire file into a String value.
string text = reader.ReadToEnd();
byte[] songDataBytes = Convert.FromBase64String(text);
AudioClip audioClip = AudioClip.Create("SongName", songDataBytes.Length, 1, 48000, false);
float[] f = ConvertByteToFloat(songDataBytes);
audioClip.SetData(f, 0);
ass.clip = audioClip;
ass.Play();
Debug.Log("C");
// Deserialize the JSON data
// into a pattern matching the GameData class.
//gameData = JsonUtility.FromJson<GameData>(text);
}
Debug.Log("D");
}
public void WriteFile()
{
string songLoc = Application.persistentDataPath + "/song.mp3";
// Create new AES instance.
Aes iAes = Aes.Create();
// Update the internal key.
string key = PlayerPrefs.GetString("Key");
string IV = PlayerPrefs.GetString("Key");
byte[] savedKey;
byte[] savedIV;
if (key == "")
{
iAes.GenerateIV();
savedKey = iAes.Key;
savedIV = iAes.IV;
key = Convert.ToBase64String(savedKey);
IV = Convert.ToBase64String(savedIV);
}
else
{
savedIV = Convert.FromBase64String(PlayerPrefs.GetString("IV"));
savedKey = Convert.FromBase64String(PlayerPrefs.GetString("Key"));
}
Debug.Log(key);
// Convert the byte[] into a Base64 String.
//string key = System.Convert.ToBase64String(savedKey);
// Update the PlayerPrefs
PlayerPrefs.SetString("Key", key);
PlayerPrefs.SetString("IV", IV);
// Create a FileStream for creating files.
dataStream = new FileStream(saveFile, FileMode.Create);
// Save the new generated IV.
byte[] inputIV = savedIV;
// Write the IV to the FileStream unencrypted.
dataStream.Write(inputIV, 0, inputIV.Length);
// Create CryptoStream, wrapping FileStream.
CryptoStream iStream = new CryptoStream(dataStream, iAes.CreateEncryptor(savedKey, savedIV), CryptoStreamMode.Write);
// Create StreamWriter, wrapping CryptoStream.
StreamWriter sWriter = new StreamWriter(iStream);
// Serialize the object into JSON and save string.
byte[] songData = File.ReadAllBytes(songLoc);
//string songString = Convert.ToBase64String(songData);
//File.WriteAllBytes(saveFile, songData);
// Write to the innermost stream (which will encrypt).
sWriter.BaseStream.Write(songData, 0, songData.Length);
// Close StreamWriter.
sWriter.Close();
// Close CryptoStream.
iStream.Close();
// Close FileStream.
dataStream.Close();
}

Converting stream encryption method from .NET to RT

I'm trying to convert Encryption/Decryption methods from managed .NET to WinRT version for use in Windows Store app. The managed .NET encryption methods are already used largely in production, so the assumption is they work correctly.
This is the managed .NET encryption method:
public static byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
public static void EncryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
FileStream fsInput = null;
FileStream fsOutput = null;
CryptoStream cryptostream = null;
try
{
#region Prep
fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
fsOutput = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write);
var cryptoDes = new DESCryptoServiceProvider { IV = iv, Key = Convert.FromBase64String(sKey), Mode = CipherMode.CBC };
var desEncrypt = cryptoDes.CreateEncryptor();
#endregion
cryptostream = new CryptoStream(fsOutput, desEncrypt, CryptoStreamMode.Write);
long startIndex = 0;
var bytearrayinput = new byte[64];
var byteCount = bytearrayinput.Length;
while (startIndex < fsInput.Length)
{
if (fsInput.Length - startIndex < byteCount)
{
byteCount = (int)(fsInput.Length - startIndex);
}
fsInput.Read(bytearrayinput, 0, byteCount);
cryptostream.Write(bytearrayinput, 0, byteCount);
startIndex += byteCount;
}
cryptostream.FlushFinalBlock();
}
finally
{
if (fsInput != null) { fsInput.Close(); }
if (cryptostream != null) { cryptostream.Close(); }
if (fsOutput != null) { fsOutput.Close(); }
}
}
This is the WinRT version that uses CryptographicEngine.
public static async Task EncryptContentFile(IRandomAccessStream inputStream, IRandomAccessStream outputStream, string key)
{
var iv = CryptographicBuffer.CreateFromByteArray(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
var keyMaterial = CryptographicBuffer.DecodeFromBase64String(key);
var cryptoProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.DesCbcPkcs7);
var symmetricKey = cryptoProvider.CreateSymmetricKey(keyMaterial);
var inStream = inputStream.AsStreamForRead();
var outStream = outputStream.AsStreamForWrite();
try
{
var size = (long)inputStream.Size;
var chunkSize = 64L;
//var finalChunk = false;
while (inStream.Position < size)
{
if (size - inStream.Position < chunkSize)
{
chunkSize = size - inStream.Position;
//finalChunk = true;
}
var chunk = new byte[chunkSize];
await inStream.ReadAsync(chunk, 0, (int)chunkSize);
var writeBuffer = CryptographicEngine.Encrypt(symmetricKey, chunk.AsBuffer(), iv).ToArray();
await outStream.WriteAsync(writeBuffer, 0, (int)chunkSize);
//await outStream.WriteAsync(writeBuffer, 0, finalChunk ? writeBuffer.Length : (int)chunkSize);
}
await outputStream.FlushAsync();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
The goal is to be able to encrypt large files by reading and encrypting chunks of bytes. The problem that I have with the RT method is that everytime it encrypts a chunk, the encrypted bytes are larger by 8 bytes. I understand on the .NET side this is what CryptoStream.FlushFinalBlock() adds.
I tried trimming the bytes to the original size (the commented finalChunk code), but it didn't help.
How can I reliably encrypt in WinRT and have the final encrypted file be identical with what the .NET method produces.
Thank you
To answer my question, I found the problem. Windows Runtime doesn't support buffered encryption and will always treat data as a whole. While the .NET ICryptoTransform contains methods like TransformBlock and TransformFinalBlock, the RT API always uses treats data as final, which makes it impossible to encrypt large streams by chunks.
I ended up using BouncyCastle PCL library which worked out perfectly. Similarly, DesEngine in BouncyCastle has method ProcessBytes and DoFinal which correspond to the above mentioned .NET methods in ICryptoTransform.
Hope this helps someone.
private Task TransformStream_DesCbcPkcs7_WithProgress(bool forEncryption, Stream inputStream, Stream outputStream, byte[] key, byte[] iv, IProgress<int> progress)
{
return Task.Run(async () =>
{
// Initialize symmetric crypto engine
// Algorithm: DES
// Mode of operation: CBC
// Byte padding: PKCS#7
var engine = new PaddedBufferedBlockCipher(new CbcBlockCipher(new DesEngine()), new Pkcs7Padding());
engine.Init(forEncryption, new ParametersWithIV(new DesParameters(key), iv));
// Report progress if available
Action<int> report = x =>
{
if (progress != null)
progress.Report(x);
};
var size = inputStream.Length;
var current = inputStream.Position;
var chunkSize = 1024 * 1024L;
var lastChunk = false;
report(0);
await Task.Yield();
// Initialize DataReader and DataWriter for reliable reading and writing
// to a stream. Writing directly to a stream is unreliable.
using (var reader = new BinaryReader(inputStream))
using (var writer = new BinaryWriter(outputStream))
{
while (current < size)
{
if (size - current < chunkSize)
{
chunkSize = (uint)(size - current);
lastChunk = true;
}
var chunk = new byte[chunkSize];
reader.Read(chunk, 0, (int)chunkSize);
// The last chunk must call DoFinal() as it appends additional bytes
var processedBytes = lastChunk ? engine.DoFinal(chunk) : engine.ProcessBytes(chunk);
writer.Write(processedBytes);
current = inputStream.Position;
report((int)(current * 100F / size));
await Task.Yield();
}
await outputStream.FlushAsync();
}
});
}

Sending and receiving compressed data over a TCP socket

Need help with sending and receiving compressed data over TCP socket.
The code works perfectly fine if I don't use compression, but something very strange happens when I do use compression.. Basically, the problem is that the stream.Read() operation gets skipped and I don't know why..
My code:
using (var client = new TcpClient())
{
client.Connect("xxx.xxx.xx.xx", 6100);
using (var stream = client.GetStream())
{
// SEND REQUEST
byte[] bytesSent = Encoding.UTF8.GetBytes(xml);
// send compressed bytes (if this is used, then stream.Read() below doesn't work.
//var compressedBytes = bytesSent.ToStream().GZipCompress();
//stream.Write(compressedBytes, 0, compressedBytes.Length);
// send normal bytes (uncompressed)
stream.Write(bytesSent, 0, bytesSent.Length);
// GET RESPONSE
byte[] bytesReceived = new byte[client.ReceiveBufferSize];
// PROBLEM HERE: when using compression, this line just gets skipped over very quickly
stream.Read(bytesReceived, 0, client.ReceiveBufferSize);
//var decompressedBytes = bytesReceived.ToStream().GZipDecompress();
//string response = Encoding.UTF8.GetString(decompressedBytes);
string response = Encoding.UTF8.GetString(bytesReceived);
Console.WriteLine(response);
}
}
You will notice some extension methods above. Here is the code in case you are wondering if something is wrong there.
public static MemoryStream ToStream(this byte[] bytes)
{
return new MemoryStream(bytes);
}
public static byte[] GZipCompress(this Stream stream)
{
using (var memoryStream = new MemoryStream())
{
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress))
{
stream.CopyTo(gZipStream);
}
return memoryStream.ToArray();
}
}
public static byte[] GZipDecompress(this Stream stream)
{
using (var memoryStream = new MemoryStream())
{
using (var gZipStream = new GZipStream(stream, CompressionMode.Decompress))
{
gZipStream.CopyTo(memoryStream);
}
return memoryStream.ToArray();
}
}
The extensions work quite well in the following, so I'm sure they're not the problem:
string original = "the quick brown fox jumped over the lazy dog";
byte[] compressedBytes = Encoding.UTF8.GetBytes(original).ToStream().GZipCompress();
byte[] decompressedBytes = compressedBytes.ToStream().GZipDecompress();
string result = Encoding.UTF8.GetString(decompressedBytes);
Console.WriteLine(result);
Does anyone have any idea why the Read() operation is being skipped when the bytes being sent are compressed?
EDIT
I received a message from the API provider after showing them the above sample code. They had this to say:
at a first glance I guess the header is missing. The input must start
with a 'c' followed by the length of the input
(sprintf(cLength,"c%09d",hres) in our example). We need this because
we can't read until we find a binary 0 to recognize the end.
They previously provided some sample code in C, which I don't fully understand 100%, as follows:
example in C:
#include <zlib.h>
uLongf hres;
char cLength[COMPRESS_HEADER_LEN + 1] = {'\0'};
n = read(socket,buffer,10);
// check if input is compressed
if(msg[0]=='c') {
compressed = 1;
}
n = atoi(msg+1);
read.....
hres = 64000;
res = uncompress((Bytef *)msg, &hres, (const Bytef*)
buffer/*compressed*/, n);
if(res == Z_OK && hres > 0 ){
msg[hres]=0; //original
}
else // errorhandling
hres = 64000;
if (compressed){
res = compress((Bytef *)buffer, &hres, (const Bytef *)msg, strlen(msg));
if(res == Z_OK && hres > 0 ) {
sprintf(cLength,"c%09d",hres);
write(socket,cLength,10);
write(socket, buffer, hres);
}
else // errorhandling
makefile: add "-lz" to the libs
They're using zlib. I don't suspect that to make any difference, but I did try using zlib.net and I still get no response anyway.
Can someone give me an example of how exactly I'm supposed to send this input length in C#?
EDIT 2
In response to #quantdev, here is what I am trying now for the length prefix:
using (var client = new TcpClient())
{
client.Connect("xxx.xxx.xx.xx", 6100);
using (var stream = client.GetStream())
{
// SEND REQUEST
byte[] bytes = Encoding.UTF8.GetBytes(xml);
byte[] compressedBytes = ZLibCompressor.Compress(bytes);
byte[] prefix = Encoding.UTF8.GetBytes("c" + compressedBytes.Length);
byte[] bytesToSend = new byte[prefix.Length + compressedBytes.Length];
Array.Copy(prefix, bytesToSend, prefix.Length);
Array.Copy(compressedBytes, 0, bytesToSend, prefix.Length, compressedBytes.Length);
stream.Write(bytesToSend, 0, bytesToSend.Length);
// WAIT
while (client.Available == 0)
{
Thread.Sleep(1000);
}
// GET RESPONSE
byte[] bytesReceived = new byte[client.ReceiveBufferSize];
stream.Read(bytesReceived, 0, client.ReceiveBufferSize);
byte[] decompressedBytes = ZLibCompressor.DeCompress(bytesReceived);
string response = Encoding.UTF8.GetString(decompressedBytes);
Console.WriteLine(response);
}
}
You need to check the return value of the Read() calls you are making on the TCP stream: it is the number of bytes effectively read.
MSDN says :
Return Value
The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not
currently available, or zero (0) if the end of the stream has been
reached.
If the socket is closed, the call will return immediately 0 (which is what might be happening here).
If is not 0, then you must check how many bytes you did actually received, if it is less than client.ReceiveBufferSize, you will need additional calls to Read to retrieve the remaining bytes.
Prior to you call to read, check that some data is actually available on the socket :
while(client.Available == 0)
// wait ...
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.available%28v=vs.110%29.aspx
I think you may have the end of file or so. Can you try setting the stream position before reading the stream
stream.position = 0;
http://msdn.microsoft.com/en-us/library/vstudio/system.io.stream.read
Encoding.UTF8.GetString shouldn't be used on arbitrary byte array.
e.g.: The compressed bytes may contain NULL character, which is not allowed in UTF-8 encoded text except for being used as terminator.
If you want to print the received bytes for debugging, maybe you should just print them as integers.

Rijndael: same string, different results

We had a small desktop app that needs to be provided as a web feature now (.Net). This app contains some code for encryption and uses Rijndael classes from .Net framework. The code accepts an input string, encrypts it and writes it out the results to a file. Since all the code is contained in one class, I just copied the class to my web service application. When I encrypt the same string, using the same key, in the original app and the new app, the results are different.
The result string given by the original app is a subset of the result string given by my web service. The latter has additional characters at the end of the encrypted string.
Below is the code I am using. Please note that I did not develop this code nor do I understand it fully. Any thoughts on the difference in behaviour? Please help!!
Here is the code that gets the user input and calls the encryptor.
public void EncryptDomain(string EncryptValue, string outputDomainFile)
{
if (EncryptValue.Length > 0)
{
if ((outputDomainFile != null) && (outputDomainFile.Length > 0))
{
_outputDomainFile = outputDomainFile;
}
byte[] input = Encoding.UTF8.GetBytes(EncryptValue);
Transform(input, TransformType.ENCRYPT);
}
This is the encryptor code:
private byte[] Transform(byte[] input, TransformType transformType)
{
CryptoStream cryptoStream = null; // Stream used to encrypt
RijndaelManaged rijndael = null; // Rijndael provider
ICryptoTransform rijndaelTransform = null;// Encrypting object
FileStream fsIn = null; //input file
FileStream fsOut = null; //output file
MemoryStream memStream = null; // Stream to contain data
try
{
// Create the crypto objects
rijndael = new RijndaelManaged();
rijndael.Key = this._Key;
rijndael.IV = this._IV;
rijndael.Padding = PaddingMode.Zeros;
if (transformType == TransformType.ENCRYPT)
{
rijndaelTransform = rijndael.CreateEncryptor();
}
else
{
rijndaelTransform = rijndael.CreateDecryptor();
}
if ((input != null) && (input.Length > 0))
{
//memStream = new MemoryStream();
//string outputDomainFile =
FileStream fsOutDomain = new FileStream(_outputDomainFile,
FileMode.OpenOrCreate, FileAccess.Write);
cryptoStream = new CryptoStream(
fsOutDomain, rijndaelTransform, CryptoStreamMode.Write);
cryptoStream.Write(input, 0, input.Length);
cryptoStream.FlushFinalBlock();
//return memStream.ToArray();
return null;
}
return null;
}
catch (CryptographicException)
{
throw new CryptographicException("Password is invalid. Please verify once again.");
}
finally
{
if (rijndael != null) rijndael.Clear();
if (rijndaelTransform != null) rijndaelTransform.Dispose();
if (cryptoStream != null) cryptoStream.Close();
if (memStream != null) memStream.Close();
if (fsOut != null) fsOut.Close();
if (fsIn != null) fsIn.Close();
}
}
Code that sets up the IV values:
private void GenerateKey(string SecretPhrase)
{
// Initialize internal values
this._Key = new byte[24];
this._IV = new byte[16];
// Perform a hash operation using the phrase. This will
// generate a unique 32 character value to be used as the key.
byte[] bytePhrase = Encoding.ASCII.GetBytes(SecretPhrase);
SHA384Managed sha384 = new SHA384Managed();
sha384.ComputeHash(bytePhrase);
byte[] result = sha384.Hash;
// Transfer the first 24 characters of the hashed value to the key
// and the remaining 8 characters to the intialization vector.
for (int loop = 0; loop < 24; loop++) this._Key[loop] = result[loop];
for (int loop = 24; loop < 40; loop++) this._IV[loop - 24] = result[loop];
}
I would guess that's because of the IV (Initialisation Vector)
This is a classic mistake. Whether you generate an IV yourself or not Rijndael (AES) will provide one for you. The trick is to always save the IV (there's a getter on RijndaelManaged).
When you decrypt, you need to pass both the Key and IV.
If you're saving data to a file or database you can store the IV as a plain text. You can even pass the IV on wire (network, internet) as a plain text. The attacker wont be able(as far as I know) break your cipher based just on an IV. Passing or storing the IV is usually done by prefixing it in front of ciphertext or appending it at the end. (concatenating the two strings)
e.g.
CiphertextIV or IVCiphertext. (remember IV is in plaintext is it should be of a fixed length - making it easy to separate upon receiving for decryption or for database insertion)
So, if your Key is ABCDEFABCDEFABCD and your IV is ABCDEF0123456789
and this plaintext:
'this is some secrect text' (let's say) produces a cipher such as: abcd1234abcd00
You would transmit(or store) like it this: ABCDEF0123456789abcd1234abcd00

How do I remove .net CryptoStream padding

When I use the following class the output is padded.
public static string EncryptString(string ClearText) {
byte[] clearTextBytes = Encoding.UTF8.GetBytes(ClearText);
System.Security.Cryptography.SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
MemoryStream ms = new MemoryStream();
byte[] rgbIV = Encoding.ASCII.GetBytes("ryojvlzmdalyglrj");
byte[] key = Encoding.ASCII.GetBytes("hcxilkqbbhczfeultgbskdmaunivmfuo");
CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV),
CryptoStreamMode.Write);
cs.Write(clearTextBytes, 0, clearTextBytes.Length);
cs.Close();
return Convert.ToBase64String(ms.ToArray());
}
public static string DecryptString(string EncryptedText)
{
byte[] encryptedTextBytes = Convert.FromBase64String(EncryptedText);
MemoryStream ms = new MemoryStream();
System.Security.Cryptography.SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
rijn.Mode = CipherMode.CFB;
byte[] rgbIV = Encoding.ASCII.GetBytes("ryojvlzmdalyglrj");
byte[] key = Encoding.ASCII.GetBytes("hcxilkqbbhczfeultgbskdmaunivmfuo"); ;
CryptoStream cs = new CryptoStream(ms, rijn.CreateDecryptor(key, rgbIV),
CryptoStreamMode.Write);
cs.Write(encryptedTextBytes, 0, encryptedTextBytes.Length);
cs.Close();
return Encoding.UTF8.GetString(ms.ToArray());
}
I understood from another post that there is
rijn.Padding = PaddingMode.None;
When I added this I get an error that says "Length of the data to encrypt is invalid"
Even when I try to encrypt a 6 byte string then I see get a long result.
var def1 = Encrypt.EncryptString("abcdefg");
gives me 24 bytes!
Can someone give me some advice here.
UPDATE
Changed to the following:
byte[] bytOut = ms.GetBuffer();
int i = 0;
for (i = 0; i < bytOut.Length; i++)
if (bytOut[i] == 0)
break;
// convert into Base64 so that the result can be used in xml
return System.Convert.ToBase64String(bytOut, 0, i);
When I check bytOut it's 16bytes Then the value returned after ToBase64 is 24 bytes. I am still not sure why the size is so large
Your problem is the mode of operation. The default is Cipher Block Chaining (CBC), which requires each block match up the block size of the algorithm, and padding to be used if necessary.
You can use another mode. Take CFB for example, it will internally pad your data before doing the plain ECB mode, and cut off the padding when it returns your result. (and do some clever stuff with the IVs so that you can continue to use the cipher without padding.) But it seems suitable for your case.
rijn.Mode = CipherMode.CFB;
Encryption algorithms work in blocks. It will always round up to the nearest block size. You just need a well-defined padding algorithm, so you can correctly remove the padding after decryption.

Categories

Resources