Related
Ok so for a school project I am making an app that has an encryption function.
Here is my code
public static string EncryptString(string stringToEncrypt, string hash)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToEncrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider() {
Key = keys, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 })
{
ICryptoTransform transform = tripleDES.CreateEncryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
public static string DecryptString(string stringToDecrypt, string hash)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToDecrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider()
{
Key = keys,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
})
{
ICryptoTransform transform = tripleDES.CreateDecryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
Currently the encryption method works, however the decryption method crashes the entire app. The error message is as follows:
System.Security.Cryptography.CryptographicException: 'Length of the data to decrypt is invalid.'
It it important for the app that the user can set their own encryption/decryption key.
What exactly is causing the app to not work? I can provide more information if needed.
Thanks.
This should resolve your problem, you just need to decode the base64 string in the decrypt function, ie byte[] data = Convert.FromBase64String(stringToDecrypt);.
Also we want to return a string, rather than base64 data, so we'll do UTF8Encoding.UTF8.GetString() at then end of DecryptString.
I would take note of the fact that this would not be considered secure as the comments above indicate, but this is a learning exercise, so this will get you up and running!
I've also created a DotNetFiddle here: https://dotnetfiddle.net/PPzXKo
using System;
using System.Security;
using System.Text;
using System.Security.Cryptography;
namespace triple_des_test
{
public class Program
{
public void Main()
{
string key = "my key";
string encrypted = EncryptString("Hello world", key);
Console.WriteLine("Encrypted: " + encrypted);
Console.WriteLine("Decrypted: " + DecryptString(encrypted, key));
}
public static string EncryptString(string stringToEncrypt, string key)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(stringToEncrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider() {
Key = keys, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 })
{
ICryptoTransform transform = tripleDES.CreateEncryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(results, 0, results.Length);
}
}
}
public static string DecryptString(string stringToDecrypt, string key)
{
byte[] data = Convert.FromBase64String(stringToDecrypt);
using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider())
{
byte[] keys = md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
using (TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider()
{
Key = keys,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
})
{
ICryptoTransform transform = tripleDES.CreateDecryptor();
byte[] results = transform.TransformFinalBlock(data, 0, data.Length);
return UTF8Encoding.UTF8.GetString(results, 0, results.Length);
}
}
}
}
}
I want encryption in my wcf service. For that I am writing a class to encrypt and decrypt strings. The encryption seems to work fine and produces a encrypted string but while doing decryption it was giving error of double escape not allowed or error 401. I have add in webconfig the following
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
Now it is giving error of either the length of the string is not correct or for shorter strings Bad String. The code is
To Encrypt
static string hash = "mypass#mysitec0m";
public static string Encrypt(string decrypted)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(decrypted);
using (MD5CryptoServiceProvider mds = new MD5CryptoServiceProvider())
{
byte[] keys = mds.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider())
{
ICryptoTransform transform = tripDes.CreateEncryptor();
byte[] result = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(result);
}
}
}
and to decrypt
public static string decrypt(string encrypted)
{
byte[] data = Convert.FromBase64String(encrypted);
using (MD5CryptoServiceProvider mds = new MD5CryptoServiceProvider())
{
byte[] keys = mds.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider())
{
ICryptoTransform transform = tripDes.CreateDecryptor();
byte[] result = transform.TransformFinalBlock(data, 0, data.Length);
return UTF8Encoding.UTF8.GetString(result);
}
}
}
Why is the error there and how can I fix it.
You never initialized the cipher with your key, thus you are using one random key for the encryptor and a different random key with your decryptor.
Use the CreateEncryptor(Byte[], Byte[]) method instead, and similarly for the decryptor.
CreateEncryptor(Byte[], Byte[])...
creates a symmetric encryptor object with the specified Key property
and initialization vector (IV).
This has nothing to do with WCF, more like a question about TripleDESCryptoServiceProvider.There is an error in your encryption and decryption code. If IV is not set, the encryption mode should use ECB. The default is CBC.CBC needs to set IV.
This is my modified code:
To Encrypt
public static string Encrypt(string decrypted)
{
byte[] data = UTF8Encoding.UTF8.GetBytes(decrypted);
using (MD5CryptoServiceProvider mds = new MD5CryptoServiceProvider())
{
byte[] keys = mds.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider() {
Key=keys,
Mode=CipherMode.ECB
})
{
ICryptoTransform transform = tripDes.CreateEncryptor();
byte[] result = transform.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(result);
}
}
}
To decrypt
public static string decrypt(string encrypted)
{
byte[] data = Convert.FromBase64String(encrypted);
using (MD5CryptoServiceProvider mds = new MD5CryptoServiceProvider())
{
byte[] keys = mds.ComputeHash(UTF8Encoding.UTF8.GetBytes(hash));
using (TripleDESCryptoServiceProvider tripDes = new TripleDESCryptoServiceProvider()
{
Key = keys,
Mode = CipherMode.ECB
})
{
ICryptoTransform transform = tripDes.CreateDecryptor();
byte[] result = transform.TransformFinalBlock(data, 0, data.Length);
return UTF8Encoding.UTF8.GetString(result);
}
}
}
I would suggest you use POST in place of GET. Because encrypted string might be long and will have many special characters as you have mentioned in the question
Below is the sample.
[OperationContract(Name = "Decrypt")]
[WebInvoke(Method = "POST",
UriTemplate = "Decrypt")]
string Decrypt(string data);
I'm building a simple PHP script that need to decode input from C# application.
I've created C# app with below encrypting function (I've also included my decrypting function):
public static string Encrypt(string input, string key)
{
var aes = new RijndaelManaged
{
KeySize = 256,
BlockSize = 256,
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC,
Key = Encoding.UTF8.GetBytes(key)
};
aes.GenerateIV();
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] buffer;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
byte[] bytes = Encoding.UTF8.GetBytes(input);
cs.Write(bytes, 0, bytes.Length);
}
buffer = ms.ToArray();
}
buffer = buffer.Concat(aes.IV).ToArray();
return Convert.ToBase64String(buffer);
}
private static String Decrypt(string text, string key)
{
RijndaelManaged aes = new RijndaelManaged
{
KeySize = 256,
BlockSize = 256,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = Encoding.UTF8.GetBytes(key)
};
byte[] encoded = Convert.FromBase64String(text);
byte[] buffer = encoded.Take(encoded.Length - aes.IV.Length).ToArray();
aes.IV = encoded.Skip(encoded.Length - aes.IV.Length).ToArray();
var decrypt = aes.CreateDecryptor();
byte[] xBuff;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
}
xBuff = ms.ToArray();
}
var output = Encoding.UTF8.GetString(xBuff);
return output;
}
After couple of minutes of searching I've found simple decryption function in PHP using mcrypt:
function strippadding($string)
{
$slast = ord(substr($string, -1));
$slastc = chr($slast);
$pcheck = substr($string, -$slast);
if(preg_match("/$slastc{".$slast."}/", $string)){
$string = substr($string, 0, strlen($string)-$slast);
return $string;
} else {
return false;
}
}
function decrypt($string, $key)
{
$string = base64_decode($string);
$iv = substr($string, -32);
$string = str_replace($iv, "", $string);
return strippadding(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_CBC, $iv));
}
This works well, but as I read on multiple sites, mcrypt is no longer recommended and sooner or later will be removed.
I'm trying to recreate same function using openssl, but without any luck.
I've tried replacing mcrypt_decrypt with:
openssl_decrypt($string, 'aes-256-cbc', $encryption_key, 0, $iv);
but as I found out MCRYPT_RIJNDAEL_256 doesn't mean AES-256.
I've been trying with different key size and block size, but without luck.
How can I recreate PHP decrypting function using openssl?
EDIT1 :
I've changed RijndaelManaged with AesCryptoServiceProvider in my C# code:
var aes = new AesCryptoServiceProvider()
{
KeySize = 256,
BlockSize = 128,
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC,
Key = Encoding.UTF8.GetBytes(key)
};
and inside PHP to:
define('AES_128_CBC', 'aes-128-cbc');
function decrypt_openssl($string, $pkey)
{
$key = $pkey;
$string = base64_decode($string);
$iv = substr($string, -32);
$string = str_replace($iv, "", $string);
$decrypted = openssl_decrypt($string, AES_128_CBC, base64_encode($key), 0, base64_encode($iv));
return $decrypted;
}
but still I can't get encoded string to be decoded in PHP.
I need a way to decrypt output of my C# function or change both to get that two way communication working.
EDIT2:
I'm providing full source of my C# class:
public static string EncryptRijndael(string input, string key)
{
var aes = new RijndaelManaged
{
KeySize = 256,
BlockSize = 256,
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC,
Key = Encoding.UTF8.GetBytes(key)
};
aes.GenerateIV();
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] buffer;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
byte[] bytes = Encoding.UTF8.GetBytes(input);
cs.Write(bytes, 0, bytes.Length);
}
buffer = ms.ToArray();
}
buffer = buffer.Concat(aes.IV).ToArray();
aes.Dispose();
return Convert.ToBase64String(buffer);
}
public static string DecryptRijndael(string input, string key)
{
var aes = new RijndaelManaged
{
KeySize = 256,
BlockSize = 256,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = Encoding.UTF8.GetBytes(key)
};
byte[] xXml = Convert.FromBase64String(input);
var buffer = xXml.Take(xXml.Length - aes.IV.Length).ToArray();
var iv = xXml.Skip(xXml.Length - aes.IV.Length).ToArray();
aes.IV = iv;
var decrypt = aes.CreateDecryptor();
byte[] xBuff;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
}
xBuff = ms.ToArray();
}
aes.Dispose();
String output = Encoding.UTF8.GetString(xBuff);
return output;
}
public static string EncryptAes(string input, string key)
{
var aes = new AesCryptoServiceProvider()
{
KeySize = 256,
BlockSize = 128,
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC,
Key = Encoding.UTF8.GetBytes(key)
};
aes.GenerateIV();
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] buffer;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
byte[] bytes = Encoding.UTF8.GetBytes(input);
cs.Write(bytes, 0, bytes.Length);
}
buffer = ms.ToArray();
}
buffer = buffer.Concat(aes.IV).ToArray();
aes.Dispose();
return Convert.ToBase64String(buffer);
}
public static String DecryptAes(string input, string key)
{
var aes = new AesCryptoServiceProvider()
{
KeySize = 256,
BlockSize = 128,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = Encoding.UTF8.GetBytes(key)
};
byte[] xXml = Convert.FromBase64String(input);
var buffer = xXml.Take(xXml.Length - aes.IV.Length).ToArray();
var iv = xXml.Skip(xXml.Length - aes.IV.Length).ToArray();
aes.IV = iv;
var decrypt = aes.CreateDecryptor();
byte[] xBuff;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
}
xBuff = ms.ToArray();
}
aes.Dispose();
String output = Encoding.UTF8.GetString(xBuff);
return output;
}
My test key is: zjPUcCp9Jn7k8RtEzxTRePjn984LqwyN
My test data as plain text: zażółć geślą jaźń
My test data as base64: emHFvMOzxYLEhyBnZcWbbMSFIGphxbrFhA==
And sample output for both encryption functions:
Rijndael: 4gD/tt3I3hqYToLnwxI/HJ37EHfXrd1uxchIOjuxSuZl0Kyvxb+S6h4gG3cWKJTbj0wDSH1zvbeSvHd9Wu1VaA==
AES: B0dKdL4k9J6CeqlAekaXM+eh/zDqd5B4sKK2p6DFsgYNbV56Xdy01XvYPZX8ZXBc
IV is added at the end of byte array just before creating base64 output. When decrypting I'm reading IV from end of input string and using it to decrypt.
I need to ensure I can encrypt/decrypt utf-8 strings.
This is not an answer but added as an answer because of necessary formatting and length:
Provided by the OP:
Encryption input:
test key is: zjPUcCp9Jn7k8RtEzxTRePjn984LqwyN
test data as plain text: zażółć geślą jaźń (not used, see below)
test data as base64: emHFvMOzxYLEhyBnZcWbbMSFIGphxbrFhA== (used)
Sample output for both encryption functions:
Rijndael: 4gD/tt3I3hqYToLnwxI/HJ37EHfXrd1uxchIOjuxSuZl0Kyvxb+S6h4gG3cWKJTbj0wDSH1zvbeSvHd9Wu1VaA==
AES: B0dKdL4k9J6CeqlAekaXM+eh/zDqd5B4sKK2p6DFsgYNbV56Xdy01XvYPZX8ZXBc
Provided data displayed as hex for consistency, spaces added for legibility:
RijndaelExpected: e200ffb6 ddc8de1a 984e82e7 c3123f1c 9dfb1077 d7addd6e c5c8483a 3bb14ae6 65d0acaf c5bf92ea 1e201b77 162894db 8f4c0348 7d73bdb7 92bc777d 5aed5568
AESExpected: 07474a74 be24f49e 827aa940 7a469733 e7a1ff30 ea779078 b0a2b6a7 a0c5b206 0d6d5e7a 5ddcb4d5 7bd83d95 fc65705c
testData: 7a61c5bc c3b3c582 c4872067 65c59b6c c485206a 61c5bac5 84
testKey: 7a6a5055 63437039 4a6e376b 38527445 7a785452 65506a6e 3938344c 7177794e
testIV: 8f4c0348 7d73bdb7 92bc777d 5aed5568 (from RijndaelExpected trailing bytes).
The above is what one would hope for in a question.
Assumptions: PKCS#7 padding, CBC mode.
Based on the data 7-bytes of padding is expected so the encrypted data should be 32-bytes.
The RijndaelExpected output is 64-bytes, minus 16-bytes for the appended IV is 48-bytes which is incorrect.
The AESExpected output is 48-bytes. If the IV is appended it does not match RijndaelExpected, it the IV is not appended it is the wrong length.
My calculated AES output without an appended IV is (Note an IV generally prefixes the encrypted data):
CryptData: 1a6ec05d 00a6e61b 8196e7f2 879e2f59 25d3b7e2 c103f7e6 41c8c93f 70b32de5
Which does not agree with either expected output.
Also see this online AES calculator Note that PKCS#7 padding has been manually added.
For completness only, my test code:
NSData *testData = [[NSData alloc] initWithBase64EncodedString:#"emHFvMOzxYLEhyBnZcWbbMSFIGphxbrFhA==" options:0];
NSData *testKey = [#"zjPUcCp9Jn7k8RtEzxTRePjn984LqwyN" dataUsingEncoding:NSUTF8StringEncoding];
NSData *testIV = [[NSData alloc] initWithBase64EncodedString:#"j0wDSH1zvbeSvHd9Wu1VaA==" options:0];
size_t movedBytes = 0;
NSMutableData *cryptData = [NSMutableData dataWithLength: testData.length + kCCBlockSizeAES128];
CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
kCCOptionPKCS7Padding, // CBC mode is the default
testKey.bytes, kCCKeySizeAES256,
testIV.bytes,
testData.bytes, testData.length,
cryptData.mutableBytes, cryptData.length,
&movedBytes);
cryptData.length = movedBytes;
Display(#"CryptData: %#", cryptData);
Encryption/Decryption won't work in cross platform.
I have used this link to encrypt/decrypt text using bouncy castle AES cipher within codename one.
AES Encryption/Decryption with Bouncycastle Example in J2ME
While from server side (.net) , i am using this link to implement same method.
http://zenu.wordpress.com/2011/09/21/aes-128bit-cross-platform-java-and-c-encryption-compatibility/
now i am not getting any error but encrypted from codename one will not getting fully decrypted on server side and vice a versa.
any one please help me out on this.
Code from Codename one:
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.encoders.Base64;
public class Test
{
private static PaddedBufferedBlockCipher cipher = null;
public static void main(String[] args)
{
try
{
byte key[] = "MAKV2SPBNI992122".getBytes("UTF-8");
byte[] iv = new byte[16];
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(
new AESEngine()) );
//Encryption
String plainText = "Hello How are you !2#&*()% 123456#";
byte[] plainData = plainText.getBytes("UTF-8");
KeyParameter keyParam = new KeyParameter(key);
CipherParameters ivAndKey = new ParametersWithIV(keyParam, iv);
cipher.init(true, ivAndKey);
byte[] ciptherBytes = cipherData(plainData); //48
String cipherText = new String(Base64.encode(ciptherBytes), "UTF-8");//FileUtil.getStringFromByteArray(Base64.encode(ciptherBytes));
System.out.println("encrypted >> "+cipherText);
//Decryption
byte[] cipherData = Base64.decode(cipherText);
ivAndKey = new ParametersWithIV(keyParam, iv);
cipher.init(false, ivAndKey);
plainText = new String(cipherData(cipherData), "UTF-8");//FileUtil.getStringFromByteArray(cipherData(cipherData));
System.out.println("decrypted >> "+plainText);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private static byte[] cipherData(byte[] data)
throws CryptoException
{
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
return result;
}
Code from .net:
public static RijndaelManaged GetRijndaelManaged(String secretKey)
{
var keyBytes = new byte[16];
var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));
return new RijndaelManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
KeySize = 128,
BlockSize = 128,
Key = keyBytes,
IV = keyBytes
};
}
public static byte[] EncryptCBC(byte[] plainBytes, RijndaelManaged rijndaelManaged)
{
return rijndaelManaged.CreateEncryptor()
.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
public static byte[] DecryptCBC(byte[] encryptedData, RijndaelManaged rijndaelManaged)
{
return rijndaelManaged.CreateDecryptor()
.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
}
public static String EncryptCBCStr(String plainText, String key)
{
var plainBytes = Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(EncryptCBC(plainBytes, GetRijndaelManaged(key)));
}
public static String DecryptCBCStr(String encryptedText, String key)
{
var encryptedBytes = Convert.FromBase64String(encryptedText);
return Encoding.UTF8.GetString(DecryptCBC(encryptedBytes, GetRijndaelManaged(key)));
}
// call
var PlainText = "Hello How are you !2#&*()% 123456#";
var EncryptionKey = "MAKV2SPBNI992122";
var cypherCBC = EncryptCBCStr(PlainText, EncryptionKey);
var decryptCBC = DecryptCBCStr(cypherCBC, EncryptionKey);
Thanks in adv.
This issue has been fixed...it is just key/IV bytes issue.as in .net there is same key and IV when in java i have used different IV.
correction in java code:
instead of this
byte key[] = "MAKV2SPBNI992122".getBytes("UTF-8");
byte[] iv = new byte[16];
use this.
byte key[] = "MAKV2SPBNI992122".getBytes("UTF-8");
byte[] iv = "MAKV2SPBNI992122".getBytes("UTF-8");
I am using symmetric TripleDES encryption from the class TripleDESCryptoServiceProvider (.Net 2.0) to encrypt the contents of a file.
The data gets encrypted perfectly but during decryption it throws the CryptographyException: Bad data
I am using key from current date time and IV from the randomly generated value by .Net class. Then I pass the same key and IV to the decryption method but it fails for some reason.
Here is my code :
static void Main(string[] args){
string fileName = "input.exe";
string newFileName = fileName + "crypted.exe";
byte[] iv;
var fileToEncrypt = File.ReadAllBytes(fileName);
var encryptionKey = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(DateTime.Now.ToString("ddMMyyHmmss")));
File.WriteAllBytes(newFileName, EncryptTripleDES(fileToEncrypt, encryptionKey, out iv));
File.WriteAllBytes(fileName + "decrypted.exe", DecryptTripleDES(File.ReadAllBytes(newFileName), encryptionKey,iv));
}
public static byte[] EncryptTripleDES(byte[] dataToEncrypt, byte[] key, out byte[] iv){
byte[] result;
var tdes = new TripleDESCryptoServiceProvider { Key = key, KeySize = 128, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 };
iv = tdes.IV;
using(ICryptoTransform cTransform = tdes.CreateEncryptor()){
result = cTransform.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
tdes.Clear();
}
return result;
}
public static byte[] DecryptTripleDES(byte[] dataToDecrypt, byte[] key, byte[] iv){
byte[] result;
var tdes = new TripleDESCryptoServiceProvider { Key = key, KeySize = 128, Mode = CipherMode.CBC,IV = iv,Padding = PaddingMode.PKCS7 };
using (ICryptoTransform cTransform = tdes.CreateDecryptor()){
result = cTransform.TransformFinalBlock(dataToDecrypt, 0, dataToDecrypt.Length);
tdes.Clear();
}
return result;
}
UPDATE:
1. I have checked the value of IV being passed is valid and same as used in encryption.
2. Changing the padding to zero or none doesn't raise the exception but then the data isn't decrypted correctly. It comes out to be different than original.
The problem is in the way that you're constructing the TripleDESCryptoServiceProviders using an initializer. The Key is set first in the initializer, but then you set the KeySize, which causes the Key to be reset to a new (randomly generated) key, as a result, you're encrypting and decrypting with different keys (neither of which are the key you generate).
You can fix this by re-ordering the initializer so that KeySize is set first, or perhaps move the setting of the Key outside the initializer entirely to avoid any ambiguity:
public static byte[] EncryptTripleDES(byte[] dataToEncrypt, byte[] key, out byte[] iv){
byte[] result;
var tdes = new TripleDESCryptoServiceProvider { KeySize = 128, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 };
// Key explicitly set here, not in the initializer:
tdes.Key = key;
iv = tdes.IV;
using(ICryptoTransform cTransform = tdes.CreateEncryptor()){
result = cTransform.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
tdes.Clear();
}
return result;
}
public static byte[] DecryptTripleDES(byte[] dataToDecrypt, byte[] key, byte[] iv){
byte[] result;
var tdes = new TripleDESCryptoServiceProvider { KeySize = 128, Mode = CipherMode.CBC,IV = iv,Padding = PaddingMode.PKCS7 };
// Key explicitly set here, not in the initializer:
tdes.Key = key;
using (ICryptoTransform cTransform = tdes.CreateDecryptor()){
result = cTransform.TransformFinalBlock(dataToDecrypt, 0, dataToDecrypt.Length);
tdes.Clear();
}
return result;
}