Encrypt RijndaelManaged 128 in unity c# and Decrypt in Node.JS - c#

I'm looking for a way to encrypt a byte array in unity c# and decrypt on a node.js server.
I'm open to any implementation of either but I have currently gone with the below code which encrypts/decrypts fine in unity but I receive the error:
TypeError: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
When decrypting a file encrypted in unity using RijndaelManaged 128
Find the encrypting and decrypting code below:
Unity C# Encrypt
private void GenerateEncryptionKey(string userID)
{
//Generate the Salt, with any custom logic and using the user's ID
StringBuilder salt = new StringBuilder();
for (int i = 0; i < 8; i++)
{
salt.Append("," + userID.Length.ToString());
}
Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes (Encoding.UTF8.GetBytes(userID), Encoding.UTF8.GetBytes(salt.ToString()), 100);
m_cryptoKey = pwdGen.GetBytes(KEY_SIZE / 8);
m_cryptoIV = pwdGen.GetBytes(KEY_SIZE / 8);
}
public void Save(string path)
{
string json = MiniJSON.Json.Serialize(m_saveData);
using (RijndaelManaged crypto = new RijndaelManaged())
{
crypto.BlockSize = KEY_SIZE;
crypto.Padding = PaddingMode.PKCS7;
crypto.Key = m_cryptoKey;
crypto.IV = m_cryptoIV;
crypto.Mode = CipherMode.CBC;
ICryptoTransform encryptor = crypto.CreateEncryptor(crypto.Key, crypto.IV);
byte[] compressed = null;
using (MemoryStream compMemStream = new MemoryStream())
{
using (StreamWriter writer = new StreamWriter(compMemStream, Encoding.UTF8))
{
writer.Write(json);
writer.Close();
compressed = compMemStream.ToArray();
}
}
if (compressed != null)
{
using (MemoryStream encMemStream = new MemoryStream(compressed))
{
using (CryptoStream cryptoStream = new CryptoStream(encMemStream, encryptor, CryptoStreamMode.Write))
{
using (FileStream fs = File.Create(GetSavePath(path)))
{
byte[] encrypted = encMemStream.ToArray();
fs.Write(encrypted, 0, encrypted.Length);
fs.Close();
}
}
}
}
}
}
ignore the compressed bit, I'll eventually be compressing the data for encryption but I have removed it in this example.
Node.JS Decrypt
var sUserID = "hello-me";
var sSalt = "";
for (var i = 0; i < 8; i++)
{
sSalt += "," + sUserID.length;
}
var KEY_SIZE = 128;
crypto.pbkdf2(sUserID, sSalt, 100, KEY_SIZE / 4, function(cErr, cBuffer){
var cKey = cBuffer.slice(0, cBuffer.length / 2);
var cIV = cBuffer.slice(cBuffer.length / 2, cBuffer.length);
fs.readFile("save.sav", function (cErr, cData){
try
{
var cDecipher = crypto.createDecipheriv("AES-128-CBC", cKey, cIV);
var sDecoded = cDecipher.update(cData, null, "utf8");
sDecoded += cDecipher.final("utf8");
console.log(sDecoded);
}
catch(e)
{
console.log(e.message);
console.log(e.stack);
}
});
});
I believe the problem is something to do with padding! I am not using:
cryptoStream.FlushFinalBlock();
when saving the file in c# land because for some reason after doing that c# can't decrypt it anymore and it doesn't really have an effect on the ability of node to decrypt it either, but maybe I'm just missing something in the decryption of it with padding?
Any help is appreciated

One problem is that you're using PasswordDeriveBytes which according to this article is for PBKDF1, whereas Rfc2898DeriveBytes is for PBKDF2. You're using PBKDF2 in your node script.
Then you should check that your cKey and cIV values match between C# and node.

Okay well it seems that order of operation is very important when encrypting and decryption using RijndaelManaged.
Below is the code to encrypt and decrypt in Unity and works with the node.js code posted in the question.
public void Save(string path)
{
string json = MiniJSON.Json.Serialize(m_saveData);
using (RijndaelManaged crypto = new RijndaelManaged())
{
crypto.BlockSize = KEY_SIZE;
crypto.Padding = PaddingMode.PKCS7;
crypto.Key = m_cryptoKey;
crypto.IV = m_cryptoIV;
crypto.Mode = CipherMode.CBC;
ICryptoTransform encryptor = crypto.CreateEncryptor(crypto.Key, crypto.IV);
byte[] compressed = null;
using (MemoryStream compMemStream = new MemoryStream())
{
using (StreamWriter writer = new StreamWriter(compMemStream, Encoding.UTF8))
{
writer.Write(json);
writer.Close();
//compressed = CLZF2.Compress(compMemStream.ToArray());
compressed = compMemStream.ToArray();
}
}
if (compressed != null)
{
using (MemoryStream encMemStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(encMemStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(compressed, 0, compressed.Length);
cryptoStream.FlushFinalBlock();
using (FileStream fs = File.Create(GetSavePath(path)))
{
encMemStream.WriteTo(fs);
}
}
}
}
}
}
public void Load(string path)
{
path = GetSavePath(path);
try
{
byte[] decrypted = null;
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
using (RijndaelManaged crypto = new RijndaelManaged())
{
crypto.BlockSize = KEY_SIZE;
crypto.Padding = PaddingMode.PKCS7;
crypto.Key = m_cryptoKey;
crypto.IV = m_cryptoIV;
crypto.Mode = CipherMode.CBC;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = crypto.CreateDecryptor(crypto.Key, crypto.IV);
using (CryptoStream cryptoStream = new CryptoStream(fs, decryptor, CryptoStreamMode.Read))
{
using (MemoryStream decMemStream = new MemoryStream())
{
var buffer = new byte[512];
var bytesRead = 0;
while ((bytesRead = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
{
decMemStream.Write(buffer, 0, bytesRead);
}
//decrypted = CLZF2.Decompress(decMemStream.ToArray());
decrypted = decMemStream.ToArray();
}
}
}
}
if (decrypted != null)
{
using (MemoryStream jsonMemoryStream = new MemoryStream(decrypted))
{
using (StreamReader reader = new StreamReader(jsonMemoryStream))
{
string json = reader.ReadToEnd();
Dictionary<string, object> saveData = MiniJSON.Json.Deserialize(json) as Dictionary<string, object>;
if (saveData != null)
{
m_saveData = saveData;
}
else
{
Debug.LogWarning("Trying to load invalid JSON file at path: " + path);
}
}
}
}
}
catch (FileNotFoundException e)
{
Debug.LogWarning("No save file found at path: " + path);
}
}

Related

When decrypting an encrypted string in c#, only the first character is returned

I have an encryption algorithm and decryption algorithm used for a login page. When encrypting, everything seems fine and seems to encrypt everything as expected, but when the encrypted password is put back through my decryption algorithm, only the first character is returned.
Example
Here is the code:
public string encrypt(string key, string data)
{
byte[] clearBytes = Encoding.Unicode.GetBytes(data);
byte[] iv = new byte[16];
using (Aes encryptor = Aes.Create())
{
encryptor.Key = Encoding.UTF8.GetBytes(key);
encryptor.IV = iv;
encryptor.Padding = PaddingMode.PKCS7;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
data = Convert.ToBase64String(ms.ToArray());
}
}
return data;
}
public static string decryptData(string key, string data)
{
byte[] iv = new byte[16];
byte[] clearBytes = Convert.FromBase64String(data);
using (Aes decrpytor = Aes.Create())
{
decrpytor.Key = Encoding.UTF8.GetBytes(key);
decrpytor.IV = iv;
ICryptoTransform decryptor = decrpytor.CreateDecryptor(decrpytor.Key, decrpytor.IV);
decrpytor.Padding = PaddingMode.PKCS7;
using (MemoryStream ms = new MemoryStream(clearBytes))
{
using (CryptoStream cs = new CryptoStream((Stream)ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader((Stream)cs))
{
return sr.ReadToEnd();
}
}
}
}
}
public void button1_Click(object sender, EventArgs e)
{
var key = "b14ca5898a4e4133bbce2ea2315a1916";
var str = passWord.Text;
var encryptedPassword = encrypt(key, str);
var decrpted = decryptData(key, encryptedPassword);
passwordTest.Text = encryptedPassword;
decryptedtest.Text = decrpted;
}
the last 2 lines are purely for testing to see what they output.
Any help is appreciated.

C# Send byte[] to server, decrypt content and send it as byte[] back to client

My problem is the following:
I have a client/server application connected over sockets. My client´s task is to send a file byte-wise to the server. The server gets the bytes, decrypt them, send it back to the client and he writes them in a new file on disk.
I get everytime a serverside exception (System.Security.Cryptography.Exception: Padding is invalid and cannot be removed) at this line of code: plaintext = sr.ReadToEnd();
Could somebody help me to solve my problem?
Here is the decryption code:
public byte[] Dec(byte[] content, byte[] Key, byte[] IV, int fileLength, string filepath, int chunkSize, int bytesToRead)
{
byte[] contentDec;
string plaintext = null;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
using (MemoryStream ms = new MemoryStream(content))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
plaintext = sr.ReadToEnd();
cs.FlushFinalBlock();
}
contentDec = encoding.GetBytes(plaintext);
}
}
}
return contentDec;
}
Here is my encryption code:
public byte[] Enc(byte[] content,byte[] Key, byte[] IV, int fileLength,string filepath, int chunkSize, int bytesToRead)
{
byte[] contentEnc;
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(content);
}
contentEnc = ms.ToArray();
}
}
}
return contentEnc;
}
On client side I call encryption method like this
int chunkSize = 1024;
byte[] chunk = new byte[chunkSize];
using (FileStream fileReader = new FileStream(plainPath, FileMode.Open, FileAccess.Read))
using (FileStream filewriter = new FileStream(pathEncrypt, FileMode.Create, FileAccess.ReadWrite))
using (BinaryReader binaryReader = new BinaryReader(fileReader))
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
myRijndael.GenerateKey();
myRijndael.GenerateIV();
Key = myRijndael.Key;
IV = myRijndael.IV;
int bytesToRead = (int)fileReader.Length;
do
{
chunk = service.Enc(binaryReader.ReadBytes(chunkSize), Key, IV,(int)fileReader.Length,
fileReader.Name, chunkSize, bytesToRead);
filewriter.Write(chunk, 0, chunk.Length);
bytesToRead -= chunkSize;
} while (bytesToRead > 0);
}
Key and IV are declared as private byte[]
On client side I call decryption method like this
int chunkSize = 1024;
byte[] chunk = new byte[chunkSize];
using (FileStream fileReader = new FileStream(pathEncrypt, FileMode.Open, FileAccess.Read))
using (FileStream filewriter = new FileStream(pathDecrypt, FileMode.Create, FileAccess.ReadWrite))
using (BinaryReader binaryReader = new BinaryReader(fileReader))
{
int bytesToRead = (int)fileReader.Length;
do
{
chunk = service.Dec(binaryReader.ReadBytes(chunkSize), Key, IV, (int)fileReader.Length,
fileReader.Name, chunkSize, bytesToRead);
filewriter.Write(chunk, 0, chunk.Length);
bytesToRead -= chunkSize;
} while (bytesToRead > 0);
}
Edit: This is my connection establishment between client and server.
Server:
var host = new ServiceHost(typeof(Service),
new Uri("net.pipe://localhost"));
host.AddServiceEndpoint(typeof(TiService),
new NetNamedPipeBinding(), "TestService");
host.Open();
Console.WriteLine("Server connection established...");
Console.ReadKey();
Client:
var callback = new Callback();
var context = new InstanceContext(callback);
var pipeFactory =
new DuplexChannelFactory<TiService>(context,
new NetNamedPipeBinding(),
new EndpointAddress("net.pipe://localhost/TestService"));
service = pipeFactory.CreateChannel();
service.Connect();
Your problem start from using StreamWriter in the encryption. It's meant for writing Text file, not arbitrary file. When you call sw.Write(content), it simply call content.ToString(), which return "System.Byte[]", instead what you'd probably expect, each byte of the array. To fix it, simply write the CryptoStream, no need to use StreamWriter, like this :
using (var rijAlg = new AesCng())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor();
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(content, 0, content.Length);
}
contentEnc = ms.ToArray();
}
}
You probably noticed I used AesCng instead of RijndaelManaged. Why? Because it's much faster in my test, and unless you really need non-standard block, there's no benefit of using RijndaelManaged. Also, I use the parameterless CreateEncryptor because you already set the Key & IV on the previous lines anyway.
Same deal in the decryption. You shouldn't treat them as text, thus :
var buffer = new byte[content.Length]; //at first its size is actual size+padding
using (var rijAlg = new AesCng())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform decryptor = rijAlg.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(content))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
var actualSize = cs.Read(buffer, 0, content.Length);
//we write the decrypted content to the buffer, and get the actual size
Array.Resize(ref buffer, actualSize);
//then we resize the buffer to the actual size
}
}
}
return buffer;
Also, your usage of the Enc and Dec is needlessly complex. It's already able to handle the whole file by itself. So to encrypt the file, simply use
var original = File.ReadAllBytes("originalPath");
var enc = Enc(original, rM.Key, rM.IV);
File.WriteAllBytes("encryptedPath", enc);
And to decrypt the file, just use
var enc = File.ReadAllBytes("encryptedPath");
var dec = Dec(enc, rM.Key, rM.IV);
File.WriteAllBytes("decryptedPath", dec);
As you can see, I throw away the fileLength,filepath, chunkSize, and bytesToRead on Enc & Dec, because your current code doesn't actually use them anyway. I've tried the code with short text file on ASCII, Unicode and UTF-8, and with large binary files, all encrypted & decrypted successfully with identical hash on the final decrypted files.
Edit :
Turning the code into direct filestream writing affair actually makes everything so much simpler.
public static void Transform(string source, string target, ICryptoTransform transf)
{
var bufferSize = 65536;
var buffer = new byte[bufferSize];
using (var sourceStream = new FileStream(source, FileMode.Open))
{
using (var targetStream = new FileStream(target, FileMode.OpenOrCreate))
{
using (CryptoStream cs = new CryptoStream(targetStream, transf, CryptoStreamMode.Write))
{
var bytesRead = 0;
do
{
bytesRead = sourceStream.Read(buffer, 0, bufferSize);
cs.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
}
}
}
}
public static void Enc(string source, byte[] Key, byte[] IV, string target)
{
using (var rijAlg = new AesCng())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor();
Transform(source, target, encryptor);
}
}
public static void Dec(string source, byte[] Key, byte[] IV, string target)
{
using (var rijAlg = new AesCng())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform decryptor = rijAlg.CreateDecryptor();
Transform(source, target, decryptor);
}
}
Usage is :
Enc(#"originalPath", key, iv, #"encryptedPath");
Dec(#"encrypedPath", key, iv, #"decryptedPath");

small file cause OutofMemoryException

I have an encrypted file which I decrypt first and then try to deserialize it using memorystream and binaryformatter but when I try to assign deserialized files to a list I catch OutOfMemoryException (file is really small - 17KB)
here is the code
byte[] encryptedData = File.ReadAllBytes(fileName);
byte[] result = Decrypt(Algo, key, vector, encryptedData) ;
BinaryFormatter ser = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(result)) {
try {
files = ser.Deserialize(ms) as List<IItem>;
} catch (OutOfMemoryException) {
} catch (SerializationException) {
MessageBox.Show("Incorrect password!");
return;
}
}
files = ser.Deserialize(ms) as List<IItem>; - this what cause exception
encrypted file size 1696
after decryption 1691 - normal size.
here Decryption code
public byte[] Decode(byte[] data)
{
string key = ASCIIEncoding.ASCII.GetString(rc2.Key);
string IV = ASCIIEncoding.ASCII.GetString(rc2.IV);
ICryptoTransform decryptor = rc2.CreateDecryptor(rc2.Key,rc2.IV);
StringBuilder roundtrip = new StringBuilder();
using (MemoryStream msDecrypt = new MemoryStream(data))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
int b = 0;
do
{
b = csDecrypt.ReadByte();
if (b != -1)
{
roundtrip.Append((char) b);
}
} while (b != -1);
}
}
byte[] decrypted = ASCIIEncoding.ASCII.GetBytes(roundtrip.ToString());
return decrypted;
}
#MineR and #HansPassant was right problem was in using chars while decrypting)) i have changed my code
public byte[] Decode(byte[] data)
{
ICryptoTransform decryptor = rc2.CreateDecryptor(rc2.Key,rc2.IV);
byte[] decrypted = new byte[data.Length];
using (MemoryStream msDecrypt = new MemoryStream(data))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
csDecrypt.Read(decrypted, 0, data.Length);
}
}
return decrypted;
}
and now it works. Thx all for answers.

Encrypt large file and add to ZIP

my goal is to encrypt large (cca 10 GB) input file and append it to an existing System.IO.Packaging Package. I can use .NET Framework 3.5 only and no third-party libraries.
I tried maybee ten methods with no success. I tried to read the input to Stream, encrypt it and save to PackagePart. I tried to read the input file byte after byte, then encrypt byte read and append it to Stream from PackagePart too. Everytime I found a new issue (e.g. CryptoStream does not supports seeking and so on).
Could you show me the right way, please?
//method to create zip file (just a sample)
public static void AppendToZip(SomeType encryptedData)
{
using (Package zip = Package.Open(#"C:\myarchive.zip", FileMode.OpenOrCreate))
{
Uri uri = PackUriHelper.CreatePartUri(new Uri("/files/test.enc", UriKind.Relative));
try
{
part = zip.GetPart(uri);
}
catch
{
}
if (part == null)
{
part = zip.CreatePart(uri, "", CompressionOption.Maximum);
}
using (Stream dest = part.GetStream())
{
//how to write encryptedData to destination stream?
}
}
}
//sample method for encrypting a file
private static void Encrypt(string inputFile, string cryptFile, byte[] passwordBytes, byte[] saltBytes)
{
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.Zeros;
AES.Mode = CipherMode.CBC;
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
}
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
Try this out - play around with block size for performance. I did this with a 3.5 GB ISO successfully. However the zip file is much larger compressing encrypted content, so as the other guy said you're better compressing the file FIRST and then encrypting it. But I don't know your requirements, so here's this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Packaging;
namespace ZipTest
{
class Program
{
static void Main(string[] args)
{
// Block size we apply to all reads / writes
const int BLOCK_SIZE = 65536;
// The zip file we're using
var zipFileName = #"C:\temp\ZipSO\MyZip.zip";
// Password for encryption
var password = "ThisIsMyPassword";
// Name of temp file where we'll encrypt the file first
var intermediateFile = #"C:\temp\ZipSO\Intermediate_" + Guid.NewGuid().ToString();
// File we're encrypting / adding to archive
var inputFile = #"C:\temp\ZipSO\InputFile.txt";
// Salt for encryption
var salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
// For the new / existing package part
PackagePart part = null;
// Open the archive
using (var zip = Package.Open(zipFileName, System.IO.FileMode.OpenOrCreate))
{
// Uri for the part
var uri = PackUriHelper.CreatePartUri(new Uri("/files/test.enc", UriKind.Relative));
// Get existing part if found, or create new
if (zip.PartExists(uri))
part = zip.GetPart(uri);
else
part = zip.CreatePart(uri, "", CompressionOption.Maximum);
// Encrypt the file first
var passBytes = System.Text.Encoding.ASCII.GetBytes(password);
using (var fs = new System.IO.FileStream(intermediateFile, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write))
{
var key = new System.Security.Cryptography.Rfc2898DeriveBytes(passBytes, salt, 1000);
var keySize = 256;
var blockSize = 128;
var aes = new System.Security.Cryptography.RijndaelManaged()
{
KeySize = keySize,
BlockSize = blockSize,
Key = key.GetBytes(keySize / 8),
IV = key.GetBytes(blockSize / 8),
Padding = System.Security.Cryptography.PaddingMode.Zeros,
Mode = System.Security.Cryptography.CipherMode.CBC
};
using (var fsSource = new System.IO.FileStream(inputFile, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
using (var cs = new System.Security.Cryptography.CryptoStream(fs, aes.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write))
{
var readBytes = new byte[BLOCK_SIZE];
int read;
while ((read = fsSource.Read(readBytes, 0, BLOCK_SIZE)) != 0)
{
cs.Write(readBytes, 0, read);
}
cs.Close();
}
fsSource.Close();
}
fs.Close();
}
// Now add it to the archive
using (var p = part.GetStream(System.IO.FileMode.OpenOrCreate))
{
using (var source = new System.IO.FileStream(intermediateFile, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (var bw = new System.IO.BinaryWriter(p))
{
var readBytes = new byte[BLOCK_SIZE];
int read;
while ((read = source.Read(readBytes, 0, BLOCK_SIZE)) != 0)
{
bw.Write(readBytes.Take(read).ToArray());
}
}
}
// Clean up the intermediate
System.IO.File.Delete(intermediateFile);
}
}
}
}

Why transferring Encrypted data from server to client the decryption doesnt work - The inputdata is not complete block

I'm trying to send and receive encrypted data from clients to asp.Net.
Everythings works fine before the encryption (AES).
Now I can pass the encrypted data from client to server and to decrypt it.
But for some reason, the same algorithm when I pass the data from server to client I cant decrypt it, and I get the error - The input data is not complete block.
Does someone can light me or explain what I miss? or Why is it happend?
the code for the encryption\decryption:
public string Encryption(string i_MessageBytes)
{
string encryptedMessage = string.Empty;
using (Aes aes = new AesCryptoServiceProvider())
{
aes.Key = m_ClientKey;
m_IV = aes.IV;
ClientIV = Convert.ToBase64String(m_IV);
// Encrypt the message
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] plaintextMessage = Encoding.UTF8.GetBytes(i_MessageBytes);
cs.Write(plaintextMessage, 0, plaintextMessage.Length);
cs.Flush();
cs.Close();
}
encryptedMessage = Convert.ToBase64String(memoryStream.ToArray());
}
}
return encryptedMessage;
}
public string Decryption(string i_Message)
{
string originalMessage = string.Empty;
using (Aes aes = new AesCryptoServiceProvider())
{
aes.Key = m_ServerKey;
aes.IV = Convert.FromBase64String(ClientIV);
aes.Padding = PaddingMode.None;
byte[] messageBytes = Convert.FromBase64String(i_Message);
// Decrypt the message
using (MemoryStream plaintext = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(plaintext, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(messageBytes, 0, messageBytes.Length);
cs.Close();
originalMessage = Encoding.UTF8.GetString(plaintext.ToArray());
}
}
}
return originalMessage;
}
((The property ClientIV and the member class m_ClientKey, m_ServerKey are in the correct places ))
In the server side at the api controller:
public HttpResponseMessage PostUser(RegisterUser user)
{
var userItem = s_Repository.Add(user);
var response = Request.CreateResponse<string>(HttpStatusCode.Created, EllipticCurveDiffieHellman.Security.Encryption(JsonConvert.SerializeObject(userItem)));
response.Headers.Add("ServerIV", EllipticCurveDiffieHellman.Security.ServerIV);
string uri = Url.Link("DefaultApi", new { id = userItem.ID });
response.Headers.Location = new Uri(uri);
return response;
}
In the client side
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
s_Result = streamReader.ReadToEnd();
string[] ivString = httpResponse.Headers.GetValues("Sec-Key");
s_StatusCode = httpResponse.StatusCode;
if (httpResponse.StatusCode == HttpStatusCode.Created && ivString.Count() != 0)
{
s_CollectingPublicKiesProcessCompleted = true;
s_ECDH.ServerIV = ivString.First();
UserInfoSaverSingleton.UserInfoInstance.PasswordForServerAndEncryption = i_UserDetails.Password;
UserInfoSaverSingleton.UserInfoInstance.Save();
string userFromServer = s_ECDH.Decryption(s_Result);
s_UserDetails = JsonConvert.DeserializeObject<UserDetailsForConnectingToContactsManagerServer>(userFromServer);
s_ModelDialogService.ShowDialog(s_Dialog, new MessageBoxViewModel() { Message = string.Format("Registration Complete"), Buttons = eMessageBoxButtons.Ok, MessageType = eMessageBoxType.Information, Title = string.Format("") });
}
OK! Now it works.
Server side:
public string Encryption(string i_Message)
{
string encryptedMessage = string.Empty;
using (Aes aes = new AesCryptoServiceProvider())
{
aes.Key = m_ServerKey;
m_IV = aes.IV;
aes.Padding = PaddingMode.PKCS7;
ServerIV = Convert.ToBase64String(m_IV);
// Encrypt the message
using (MemoryStream plaintext = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(plaintext, aes.CreateEncryptor(aes.Key, aes.IV), CryptoStreamMode.Write))
{
byte[] messageBytes = Encoding.UTF8.GetBytes(i_Message);
cs.Write(messageBytes, 0, messageBytes.Length);
cs.Flush();
cs.Close();
}
encryptedMessage = Convert.ToBase64String(plaintext.ToArray());
}
}
return encryptedMessage;
}
Client side:
public string Decryption(string i_Message)
{
string originalMessage = string.Empty;
using (Aes aes = new AesCryptoServiceProvider())
{
aes.Key = m_ClientKey;
aes.IV = Convert.FromBase64String(ServerIV);
aes.Padding = PaddingMode.None;
string message = i_Message.Substring(1, i_Message.Length - 2);
byte[] messageBytes = Convert.FromBase64String(message);
// Decrypt the message
using (MemoryStream plaintext = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(plaintext, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(messageBytes, 0, messageBytes.Length);
cs.Close();
originalMessage = Encoding.UTF8.GetString(plaintext.ToArray());
}
}
}
return originalMessage;
}
I had two problems:
The result of the encryption (string) that pass from server to client got "\" as the string begins and ends. I dont know why if someone knows let me know, so if it wasn't in the server
it not important so I removed it.
KEEPING STRINGS TYPES CONVERTING ORDER - I didn't notice that I convert between utf8 and base64 in the wrong order.
I hope someone will learn from my mistakes.

Categories

Resources