I am trying to encrypt a byte[] using the following methods but when I decrypt it my byte[] is bigger than when I started and I think its to do with padding but I am not sure how to solve it.
The method isnt finished yet (I know its bad to append the key + iv like my example but its for testing purpose to get it working before I move on).
So when I try to open the file afterwards (tested with MS Word file) I get a message saying the file is damaged and would I like to repair it.
Encrypt Method
public byte[] Encrypt(byte[] dataToEncrypt) {
// Check arguments.
if (dataToEncrypt == null || dataToEncrypt.Length <= 0) {
throw new ArgumentNullException("dataToEncrypt");
}
byte[] encryptedData;
byte[] key;
byte[] iv;
// Create an Aes object
using (Aes aesAlg = Aes.Create()) {
key = aesAlg.Key;
iv = aesAlg.IV;
// Create a encrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream memoryStream = new MemoryStream()) {
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) {
cryptoStream.Write(dataToEncrypt, 0, dataToEncrypt.Length);
cryptoStream.FlushFinalBlock();
encryptedData = memoryStream.ToArray();
}
}
}
byte[] result = new byte[encryptedData.Length + KEY_SIZE + IV_SIZE];
Buffer.BlockCopy(key, 0, result, 0, KEY_SIZE);
Buffer.BlockCopy(iv, 0, result, KEY_SIZE, IV_SIZE);
Buffer.BlockCopy(encryptedData, 0, result, KEY_SIZE + IV_SIZE, encryptedData.Length);
return result;
}
Decrypt Method
public byte[] Decrypt(byte[] encryptedData) {
// Check arguments.
if (encryptedData == null || encryptedData.Length <= 0) {
throw new ArgumentNullException("encryptedData");
}
byte[] storedKey = new byte[KEY_SIZE];
byte[] storedIV = new byte[IV_SIZE];
byte[] dataToDecrypt = new byte[encryptedData.Length - (KEY_SIZE + IV_SIZE)];
Buffer.BlockCopy(encryptedData, 0, storedKey, 0, KEY_SIZE);
Buffer.BlockCopy(encryptedData, KEY_SIZE, storedIV, 0, IV_SIZE);
Buffer.BlockCopy(encryptedData, KEY_SIZE + IV_SIZE, dataToDecrypt, 0, encryptedData.Length - (KEY_SIZE + IV_SIZE));
byte[] decryptedData = null;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create()) {
aesAlg.Key = storedKey;
aesAlg.IV = storedIV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream memoryStream = new MemoryStream(dataToDecrypt)) {
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) {
cryptoStream.Read(dataToDecrypt, 0, dataToDecrypt.Length);
decryptedData = memoryStream.ToArray();
}
}
}
return decryptedData;
}
You are assuming that the entire buffer is plaintext data as well. You should only return that part of the buffer that contains the plaintext data (using the response of Read to see how much bytes are returned). The encrypted data is usually larger because of the padding.
As a single read method isn't good practice with regards to stream handling. You need to read until the end of the stream is reached. Otherwise you may go from having too much data to having too little.
Related
public static string Encrypt(string toEncrypt, string secretKey)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
var md5Serv = System.Security.Cryptography.MD5.Create();
keyArray = md5Serv.ComputeHash(UTF8Encoding.UTF8.GetBytes(secretKey));
md5Serv.Dispose();
var tdes = System.Security.Cryptography.TripleDES.Create();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
//transform the specified region of bytes array to resultArray
byte[] resultArray =
cTransform.TransformFinalBlock(toEncryptArray, 0,
toEncryptArray.Length);
//Release resources held by TripleDes Encryptor
tdes.Dispose();
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
secretkey = 16 character of string
in this line :
tdes.Key = keyArray;
i get this error:
Message = "Specified key is not a valid size for this algorithm."
error Message screen shot
how to solved this problem in asp.net core 1.1.0?
how to convert byte[16] to byte[24]?
Updated Post
thanks For Help :) but!
I use this code in .Net Framework 4.6.2 for encrypt:
public static string Encrypt(string toEncrypt, string secretKey)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(secretKey));
hashmd5.Clear();
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
//transform the specified region of bytes array to resultArray
byte[] resultArray =
cTransform.TransformFinalBlock(toEncryptArray, 0,
toEncryptArray.Length);
//Release resources held by TripleDes Encryptor
tdes.Clear();
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
and Use this in .Net Core 1.1 :
public static string Encrypt(string toEncrypt, string secretKey)
{
byte[] keyArray;
byte[] resultArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
using (var md5Serv = System.Security.Cryptography.MD5.Create())
{
keyArray = md5Serv.ComputeHash(UTF8Encoding.Unicode.GetBytes(secretKey));
if(keyArray.Length==16)
{
byte[] tmp = new byte[24];
Buffer.BlockCopy(keyArray, 0, tmp, 0, keyArray.Length);
Buffer.BlockCopy(keyArray, 0, tmp, keyArray.Length, 8);
keyArray = tmp;
}
}
using (var tdes = System.Security.Cryptography.TripleDES.Create())
{
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
//transform the specified region of bytes array to resultArray
resultArray =
cTransform.TransformFinalBlock(toEncryptArray, 0,
toEncryptArray.Length);
}
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
but i don't know why this methods give me different result?!
if (key.Length == 16)
{
byte[] tmp = new byte[24];
Buffer.BlockCopy(key, 0, tmp, 0, key.Length);
Buffer.BlockCopy(key, 0, tmp, key.Length, 8);
key = tmp;
}
That will turn your 2DES key (k1, k2) into the 3DES key (k1, k2, k1). FWIW, this has been fixed for .NET Core 2.0 (https://github.com/dotnet/corefx/issues/9966).
So, now your code will work again. Though, as others have pointed out in comments, there's a lot going on in your code which is not considered cryptologically sound by modern standards. You should strongly consider taking this as an opportunity to enhance your encryption. (If you can't "because then it can't work with already existing data" then you should take this opportunity to add crypto-agility to your data, to permit you to move to different key schemes and/or algorithms over time.)
Recently I began developing a new MVC app and needed to take an older existing asp.net membership database and convert it into the new(er) Identity system.
If you've found yourself in a similar situation, then likely you've come upon this helpful post from microsoft which gives you great guidance and scripts on converting the database over to the new schema, including the passwords.
To handle the differences in hashing/encryption of passwords between the two systems, they include a custom password hasher, SqlPasswordHasher, which parses the password field (which has been combined into Password|PasswordFormat|Salt) and attempts to duplicate the logic found inside SqlMembershipProvider to compare the incoming password with the stored version.
However, as I (and another commenter on that post) noticed, this handy hasher they provided doesn't handle Encrypted passwords (despite the confusing lingo they use in the post that seems to indicate that it does). It seems like it should, considering they do bring across the password format into the database, but then curiously the code doesn't use it, instead having
int passwordformat = 1;
which is for hashed passwords. What I needed was one that would handle my scenario which is encrypted passwords using the System.Web/MachineKey configuration element's decryptionKey.
If you also are in such a predicament, and are using the AES algorithm (as defined in the decryption property of the machineKey) then my answer below should come to your rescue.
First, let's talk real quick about what the SqlMembershipProvider is doing under the hood. The provider combines the salt, converted to a byte[] with the password, encoded as a unicode byte array, into a single larger byte array, by concatenating the two together. Pretty straightforward. Then it passes this off, through an abstraction (MembershipAdapter) to the MachineKeySection where the real work is done.
The important part about that handoff is that it instructs the MachineKeySection to use an empty IV (intialization vector) and also to perform no signing. That empty IV is the real lynchpin, because the machineKey element has no IV property, so if you've scratched your head and wondered how the providers were handling this aspect, that's how. Once you know that (from digging around the source code) then you can distill down the encryption code in the MachineKeySection code and combine it with the membership provider's code to arrive at a more complete hasher. Full source:
public class SQLPasswordHasher : PasswordHasher
{
public override string HashPassword(string password)
{
return base.HashPassword(password);
}
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
string[] passwordProperties = hashedPassword.Split('|');
if (passwordProperties.Length != 3)
{
return base.VerifyHashedPassword(hashedPassword, providedPassword);
}
else
{
string passwordHash = passwordProperties[0];
int passwordformat = int.Parse(passwordProperties[1]);
string salt = passwordProperties[2];
if (String.Equals(EncryptPassword(providedPassword, passwordformat, salt), passwordHash, StringComparison.CurrentCultureIgnoreCase))
{
return PasswordVerificationResult.SuccessRehashNeeded;
}
else
{
return PasswordVerificationResult.Failed;
}
}
}
//This is copied from the existing SQL providers and is provided only for back-compat.
private string EncryptPassword(string pass, int passwordFormat, string salt)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bRet = null;
if (passwordFormat == 1)
{ // MembershipPasswordFormat.Hashed
HashAlgorithm hm = HashAlgorithm.Create("SHA1");
if (hm is KeyedHashAlgorithm)
{
KeyedHashAlgorithm kha = (KeyedHashAlgorithm)hm;
if (kha.Key.Length == bSalt.Length)
{
kha.Key = bSalt;
}
else if (kha.Key.Length < bSalt.Length)
{
byte[] bKey = new byte[kha.Key.Length];
Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
kha.Key = bKey;
}
else
{
byte[] bKey = new byte[kha.Key.Length];
for (int iter = 0; iter < bKey.Length;)
{
int len = Math.Min(bSalt.Length, bKey.Length - iter);
Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
iter += len;
}
kha.Key = bKey;
}
bRet = kha.ComputeHash(bIn);
}
else
{
byte[] bAll = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
bRet = hm.ComputeHash(bAll);
}
}
else //MembershipPasswordFormat.Encrypted, aka 2
{
byte[] bEncrypt = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bEncrypt, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bEncrypt, bSalt.Length, bIn.Length);
// Distilled from MachineKeyConfigSection EncryptOrDecryptData function, assuming AES algo and paswordCompatMode=Framework20 (the default)
using (var stream = new MemoryStream())
{
var aes = new AesCryptoServiceProvider();
aes.Key = HexStringToByteArray(MachineKey.DecryptionKey);
aes.GenerateIV();
aes.IV = new byte[aes.IV.Length];
using (var transform = aes.CreateEncryptor())
{
using (var stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
stream2.Write(bEncrypt, 0, bEncrypt.Length);
stream2.FlushFinalBlock();
bRet = stream.ToArray();
}
}
}
}
return Convert.ToBase64String(bRet);
}
public static byte[] HexStringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
private static MachineKeySection MachineKey
{
get
{
//Get encryption and decryption key information from the configuration.
System.Configuration.Configuration cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
return cfg.GetSection("system.web/machineKey") as MachineKeySection;
}
}
}
If you have a different algorithm, then the steps will be very close to the same, but you may want to first dive into the source for MachineKeySection and carefully walkthrough how they're initializing things. Happy Coding!
I like to make sure I got the encrypting part right in my app. I plan to open source this code. You can get the two related files at: https://gist.github.com/lameguy7quick/1e998aad673354d2661b.
Have I made any mistakes? I know I didn't understand HMAC at the time of writing.
The idea is simple. I load the recipient public key. Encrypt a randomly made AES key. Encode the message with said AES then stuff it into a tcp connection. It seems to work correctly have I overlooked anything? I have a feeling maybe the aes should have a randomly made IV but the key itself is randomly generated so maybe I don't need to?
I also use SHA1CryptoServiceProvider I think I should use SHA512CryptoServiceProvider.
Did I sign correctly? It says it is signed but I'm not sure if there is an attack on it
public byte[] SendMessage(byte[] recipient_pubkey, byte[] replyTo, string txt, byte[] prvkey, byte[] pubkey)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
var msgid = new byte[16];
rng.GetBytes(msgid);
using (var aes = new RijndaelManaged())
{
byte[] rsa_aes_key;
RSAParameters recipient_rsap;
Shared.LoadKey2(Shared.pubToPem(recipient_pubkey), null, out recipient_rsap);
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(recipient_rsap);
rsa_aes_key = rsa.Encrypt(aes.Key, false);
}
var aesmsg = EncodeMessage(recipient_pubkey, msgid, replyTo, txt, prvkey, pubkey, aes.Key, Shared.FixedIV_16bytes);
if (rsa_aes_key.Length + aesmsg.Length > 1024 * 15) throw new Exception();
sw.WriteByte((byte)ClientServerCmd.SendMessage);
sw.WriteShort((short)recipient_pubkey.Length);
sw.Write(recipient_pubkey, 0, recipient_pubkey.Length);
sw.WriteShort(rsa_aes_key.Length + aesmsg.Length);
sw.Write(rsa_aes_key, 0, rsa_aes_key.Length);
sw.Write(aesmsg, 0, aesmsg.Length);
sw.Flush();
var resp = sr.ReadByte();
if (resp != (byte)ClientServerCmd.KeyLenOk)
throw new Exception();
resp = sr.ReadByte();
if (resp == (byte)ClientServerCmd.NotRegistered)
throw new MyException("User you're writing to does not exist");
if (resp != (byte)ClientServerCmd.Success)
throw new Exception();
}
return msgid;
}
byte[] EncodeMessage(byte[] recipient_pubkey, byte[]msgid, byte[] replyTo, string txt, byte[] prvkey, byte[] pubkey, byte[] aes_key, byte[] aes_iv)
{
if (replyTo == null)
{
replyTo = new byte[16];
}
var txtbuf = Encoding.UTF8.GetBytes(txt);
var SignMessage = prvkey != null;
byte[] hash = null;
if (SignMessage)
{
using (var rsa = new RSACryptoServiceProvider())
{
RSAParameters rsap;
Shared.LoadKey2(Shared.prvToPem(prvkey), null, out rsap);
rsa.ImportParameters(rsap);
using (var ms = new MemoryStream()) //sign
{
ms.Write(msgid, 0, msgid.Length);
ms.Write(replyTo, 0, replyTo.Length);
ms.WriteShort((short)txtbuf.Length);
ms.Write(txtbuf, 0, txtbuf.Length);
ms.WriteShort((short)pubkey.Length);
ms.Write(pubkey, 0, pubkey.Length);
ms.WriteShort((short)recipient_pubkey.Length);
ms.Write(recipient_pubkey, 0, recipient_pubkey.Length);
ms.Position = 0;
hash = rsa.SignData(ms, new SHA1CryptoServiceProvider());
}
}
}
byte[] c1;
using (var ms1 = new MemoryStream())
using (var ms = new BZip2OutputStream(ms1))
{
ms.Write(txtbuf, 0, txtbuf.Length);
ms.Close();
c1 = ms1.ToArray();
}
var compressText = c1.Length < txtbuf.Length;
byte[] aesmsg;
byte[] aeskey;
using (var aes = new RijndaelManaged())
{
aeskey = aes.Key;
aes.IV = Shared.FixedIV_16bytes;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (var encryptor = aes.CreateEncryptor(aes_key, aes_iv))
using (CryptoStream sw2 = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
sw2.WriteByte((Byte)((compressText ? 1 : 0) | (SignMessage ? 2 : 0)));
sw2.Write(msgid, 0, msgid.Length);
sw2.Write(replyTo, 0, replyTo.Length);
if (compressText)
{
sw2.WriteShort((short)c1.Length);
sw2.Write(c1, 0, c1.Length);
}
else
{
sw2.WriteShort((short)txtbuf.Length);
sw2.Write(txtbuf, 0, txtbuf.Length);
}
if (SignMessage)
{
sw2.WriteShort((short)pubkey.Length);
sw2.Write(pubkey, 0, pubkey.Length);
sw2.WriteShort((short)hash.Length);
sw2.Write(hash, 0, hash.Length);
}
}
msEncrypt.Flush();
aesmsg = msEncrypt.ToArray();
}
}
return aesmsg;
}
Fixed IV is a certainly not right.
IV for AES CBC should not be predictable. Typically you make it random and include it with the ciphertext.
A mac is important to avoid chosen ciphertext attacks, you are reading and writing your own format you have to worry about manipulation of your ciphertext allowing something to be exposed, your aes code likely will throw a padding exception that could be used to recover the plaintext by sending modified ciphertext to your receiver.
It's good that your code will be open source, opening it up to analysis and patches, but you should be aware the applying cryptography correctly is difficult and easy to make mistakes.
If you can adapt a high level library, like Keyczar (I ported it to c#), you'll be in better shape, though nothing's perfect.
I am learning about encryption and using crypto-js I have made a Js & c# version.
What I am trying to accomplish is that the JS or c# version will be able to decode each other messages.
For testing I have kept the IV and KEY , paddding and mode the same in both the JS and C# instance.
I have them both decrypting and encrypting data respectivly but what I have yet to accomplish is providing an encrypted from JS be able to decode using c#.
JS
var key = CryptoJS.enc.Base64.parse('7061737323313233');
var iv = CryptoJS.enc.Base64.parse('7061737323313233');
var encrypted = CryptoJS.AES.encrypt("It works", key,
{ keySize: 128 / 8, iv: iv, mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7 });
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
keySize: 128 / 8, iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
document.write('Encrypted :' + encrypted + '<br>');
document.write('Key :' + encrypted.key + '<br>');
document.write('Salt :' + encrypted.salt + '<br>');
document.write('iv :' + encrypted.iv + '<br>');
document.write('Decrypted : ' + decrypted + '<br>');
document.write('utf8 = ' + decrypted.toString(CryptoJS.enc.Utf8) + '<br>');
C#
public void startEncryption(string original )
{
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
//Settings
myRijndael.Mode = CipherMode.CBC;
myRijndael.Padding = PaddingMode.PKCS7;
myRijndael.FeedbackSize = 128;
keybytes = Encoding.UTF8.GetBytes("7061737323313233");
//Should be made unique for each message!. TODO
iv = Encoding.UTF8.GetBytes("7061737323313233");
// Encrypt the string to an array of bytes.
encrypted = EncryptStringToBytes(original, keybytes, iv);
//Show Encrypted data
txt_Output.Text = Convert.ToBase64String(encrypted);
// Decrypt the bytes to a string.
string roundtrip = DecryptStringFromBytes(encrypted, keybytes, iv);
//Display the original data and the decrypted data.
Console.WriteLine("Original: {0}", original);
Console.WriteLine("Round Trip: {0}", roundtrip);
}
}
Where the problem arises in decryption.
private void btn_Decrypt_Click(object sender, EventArgs e)
{
Console.WriteLine("Decrypting..");
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
//Settings
myRijndael.Mode = CipherMode.CBC;
myRijndael.Padding = PaddingMode.PKCS7;
myRijndael.FeedbackSize = 128;
keybytes = Encoding.UTF8.GetBytes("7061737323313233");
//Should be made unique for each message!. TODO
iv = Encoding.UTF8.GetBytes("7061737323313233");
// Decrypt the bytes to a string.
string roundtrip = DecryptToString(txt_Output.Text);
txt_Output.Text = roundtrip;
//Display the original data and the decrypted data.
}
}
public string DecryptToString(string TextValue)
{
return DecryptStringFromBytes(Convert.FromBase64String(TextValue), keybytes, iv);
}
static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
rijAlg.Padding = PaddingMode.PKCS7;
rijAlg.Mode = CipherMode.CBC;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt =
new CryptoStream(msDecrypt,decryptor,CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
I am producing different encrypted size strings:
JS:MhAP11fHa+fUfRzSw2UHVQ==
C#:+Ijpt1GDVgM4MqMAQUwf0Q==
I get Padding is invalid and cannot be removed, when trying to decrypt the JS string in c#
Where have I got wrong?.
Basically you run into encoding issues. First of all, you parse your IV using Base64 decoding in one implementation and one using direct character encoding in the other. Your Base64 strings don't look like Base64 strings either.
Furthermore, many libraries (incorrectly) allow that incorrect key and IV sizes are used. This is however confusing as there is no generic way for key or IV expansion. So you should make sure that the binary representations of the key and IV are correct for the specific algorithm.
For AES you should use a key size of 128, 192 or 256 bits and an IV size identical to the block size, 128 bits. The IV should be randomly generated and communicated to the other side, e.g. by prefixing the IV to the ciphertext.
I have given a task in which I need to encrypt an user's ID using AES encryption, what they want is I need to pass in a parameter in a website just like this.
URL : http://www.site.com/event/sample.jce
Parameter : ?param= encrypted text
aside from that there was an attched php sample that they want me to follow to encrypt but I don't have an idea on how to convert this one in .NET
function getEncrypt($sStr, $sKey, $sIV){
$sCipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $sKey, $sStr, MCRYPT_MODE_CFB, $sIV);
return bin2hex($sCipher);
}
$sStr = "13410##13";
$sKey = "mediaservice1234";
$sKey = "kjcemsdev3jangho"; // Do not change
$sIV = "fs0tjwkdgh0akstp"; // Do not change
$tmp= getEncrypt($sStr, $sKey, $sIV);
Could somebody help me to understand this codes? or better if they could help me to convert this one on .NEt code? Thanks. :)
Try this, you need to set the FeedbackSize and Padding:
public static string Encrypt(string plaintext)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
//RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.FeedbackSize = 8;
rijndaelCipher.Mode = CipherMode.CFB;
rijndaelCipher.KeySize = 128;
// rijndaelCipher.BlockSize = 128;
rijndaelCipher.BlockSize = 128;
rijndaelCipher.Padding = PaddingMode.Zeros;
byte[] plaintextByte = System.Text.Encoding.ASCII.GetBytes(plaintext);
//Rfc2898DeriveBytes
ASCIIEncoding textConverter = new ASCIIEncoding();
rijndaelCipher.Key = textConverter.GetBytes(PRIVATEKEY); ;
rijndaelCipher.IV = Convert.FromBase64String(PRIVATEIV);
ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor();
//http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(VS.80).aspx
//Encrypt the data.
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
//Convert the data to a byte array.
byte[] toEncrypt = textConverter.GetBytes(plaintext);
//Write all data to the crypto stream and flush it.
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
byte[] encrypted = new byte[16];
//Get encrypted array of bytes.
encrypted = msEncrypt.ToArray();
return Convert.ToBase64String(encrypted);
}
Here you can find some more information about using the AES encryption in .net:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged%28VS.80%29.aspx
The code is pretty straight forward.