Decrypt RijndaelManaged in C++ (CNG) - c#

The C# code below outputs 0123456789012345678901234567890123456789:
static void Main(string[] args)
{
byte[] salt = Encoding.ASCII.GetBytes("saltycrack");
Console.WriteLine(Decrypt("NpN45cs2+bVLtEgp6ZmBmmHLH89aFdHIbDjhstTK0Vb1VMr7jBsliKD9siQGGxGS", "pass", salt));
}
public static string Decrypt(string encryptedText, string encryptionPassword, byte[] salt)
{
var algorithm = GetAlgorithm(encryptionPassword, salt);
using (ICryptoTransform decryptor = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV))
{
byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
return Encoding.UTF8.GetString(InMemoryCrypt(encryptedBytes, decryptor));
}
}
private static byte[] InMemoryCrypt(byte[] data, ICryptoTransform transform)
{
MemoryStream memory = new MemoryStream();
using (Stream stream = new CryptoStream(memory, transform, CryptoStreamMode.Write))
{
stream.Write(data, 0, data.Length);
}
return memory.ToArray();
}
private static RijndaelManaged GetAlgorithm(string encryptionPassword, byte[] salt)
{
var key = new Rfc2898DeriveBytes(encryptionPassword, salt);
var algorithm = new RijndaelManaged();
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
return algorithm;
}
I want to do the same decryption using Microsoft CNG in C++:
int main(int argc, char** argv)
{
auto salt = std::string("saltycrack");
auto pass = std::string("pass");
std::string cipher_text = base64_decode("NpN45cs2+bVLtEgp6ZmBmmHLH89aFdHIbDjhstTK0Vb1VMr7jBsliKD9siQGGxGS");
NTSTATUS bcryptResult = 0;
BCRYPT_ALG_HANDLE alg = 0;
assert(BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&alg, BCRYPT_AES_ALGORITHM, 0, 0)));
BCRYPT_ALG_HANDLE prf = NULL;
assert(BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&prf, BCRYPT_SHA1_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG)));
auto key_len = 32;
ULONGLONG iter = 1000;
ULONG kbh_len = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key_len;
BCRYPT_KEY_DATA_BLOB_HEADER* kbh = (BCRYPT_KEY_DATA_BLOB_HEADER*)malloc(kbh_len);
assert(BCRYPT_SUCCESS(BCryptDeriveKeyPBKDF2(prf, (PUCHAR)pass.data(), pass.size(), (PUCHAR)salt.data(), salt.size(), iter, (uint8_t*)(kbh + 1), key_len, 0)));
kbh->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
kbh->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
kbh->cbKeyData = key_len;
DWORD key_obj_len;
ULONG got;
assert(BCRYPT_SUCCESS(BCryptGetProperty(alg, BCRYPT_OBJECT_LENGTH, (PBYTE)&key_obj_len, sizeof(DWORD), &got, 0)));
uint8_t* key_obj = new uint8_t[key_obj_len];
BCRYPT_KEY_HANDLE key = 0;
assert(BCRYPT_SUCCESS(BCryptImportKey(alg, NULL, BCRYPT_KEY_DATA_BLOB, &key, key_obj, key_obj_len, (PUCHAR)kbh, kbh_len, 0)));
{
std::wstring mode = BCRYPT_CHAIN_MODE_CBC;
BYTE* ptr = reinterpret_cast<BYTE*>(const_cast<wchar_t*>(mode.data()));
ULONG size = static_cast<ULONG>(sizeof(wchar_t) * (mode.size() + 1));
assert(BCRYPT_SUCCESS(BCryptSetProperty(alg, BCRYPT_CHAINING_MODE, ptr, size, 0)));
}
DWORD bytes_done = 0;
DWORD block_len = 0;
assert(BCRYPT_SUCCESS(BCryptGetProperty(alg, BCRYPT_BLOCK_LENGTH, (BYTE*)&block_len, sizeof(block_len), &bytes_done, 0)));
auto iv = std::vector<uint8_t>(block_len);
ULONG bufferlen = 0;
assert(BCRYPT_SUCCESS(BCryptDecrypt(key, (PUCHAR)cipher_text.data(), cipher_text.size(), 0, (PUCHAR)iv.data(), iv.size(), 0, 0, &bufferlen, BCRYPT_BLOCK_PADDING)));
auto plaintext = std::string(bufferlen, '\0');
assert(BCRYPT_SUCCESS(BCryptDecrypt(key, (PUCHAR)cipher_text.data(), cipher_text.size(), 0, (PUCHAR)iv.data(), iv.size(), (PUCHAR)plaintext.data(), plaintext.size(), &bufferlen, BCRYPT_BLOCK_PADDING)));
std::cout << plaintext << "\n";
return 0;
}
The C++ program outputs #♂b⌡Cεk╘┴╟AÑ#├0⌠678901234567890123456789.
It looks like decryption partially succeeded which doesn't make sense.
Do I need to decode the decrypted data or is there data corruption somewhere?

Related

calculate the MAC with S-MAC to sign the data with `single DES plus final triple DES`

I want calculate the MAC with S-MAC to sign the plain with single DES plus final triple DES in Secure Channel. I tried as follows but is not worked.
Can anyone help me? Thanks.
byte[] mac_iv = ToHexBytes("0000000000000000");
byte[] mac_key = ToHexBytes("C6713F31B8DC1F8905DFECB4065CB81E"); // S-MAC
byte[] mac_plain = BytesAppend(ToHexBytes("8482000010"), ToHexBytes("1122334455667788"));
byte[] mac_cipher = DES_MAC8_ISO9797_M2_ALG3_Encrypt(mac_iv, mac_key, mac_plain);
Debug.Print("\nmac_cipher: " + ToHexString(mac_cipher));
//
private byte[] DES_MAC8_ISO9797_M2_ALG3_Encrypt(byte[] iv, byte[] key, byte[] plain)
{
try
{
// split the 16 byte key into key A and key B
var key1 = new byte[8];
Buffer.BlockCopy(key, 0, key1, 0, key1.Length);
var key2 = new byte[8];
Buffer.BlockCopy(key, 8, key2, 0, key2.Length);
// init DES CBC encryption with key A and an all-zero IV of 8 bytes
DES des = new DESCryptoServiceProvider();
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.None;
MemoryStream streamOut = new MemoryStream();
CryptoStream streamCrypto = new CryptoStream(streamOut, des.CreateEncryptor(key1, iv), CryptoStreamMode.Write);
// iterate over all full blocks within the message & for each block perform CBC encryption,
// throwing away the result (using the same cipher instance, you need to keep the state after all)
int fullBlocks = plain.Length / 8;
for (int i = 0; i < fullBlocks; i++) {
int off = i * 8;
byte[] block = new byte[off + 8];
Buffer.BlockCopy(plain, off, block, off, block.Length);
streamCrypto.Write(block, 0, block.Length);
streamCrypto.FlushFinalBlock();
}
// create a final block and copy the left over bytes from the message into it
byte[] final_block = new byte[8];
int left = plain.Length % 8;
Buffer.BlockCopy(plain, left, final_block, left, final_block.Length);
// at the next position add the initial padding indicator byte
// ???
// finalize the CBC encryption by encrypting the final block, and keep the result
streamCrypto.Write(final_block, 0, final_block.Length);
streamCrypto.FlushFinalBlock();
byte[] res = streamOut.ToArray();
// perform DES ECB decryption over the result with key B, replacing the result
des.Mode = CipherMode.ECB;
streamCrypto = new CryptoStream(streamOut, des.CreateDecryptor(key2, iv), CryptoStreamMode.Write);
streamCrypto.Write(res, 0, res.Length);
res = streamOut.ToArray();
// peform DES ECB encryption over the result with key A, replacing the result
des.Mode = CipherMode.ECB;
streamCrypto = new CryptoStream(streamOut, des.CreateDecryptor(key1, iv), CryptoStreamMode.Write);
streamCrypto.Write(res, 0, res.Length);
res = streamOut.ToArray();
return res;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return new byte[0];
}
I resolved my problem with answer from #Jeff2022 in C# Implementation of Retail MAC Calculation (ISOIEC 9797-1 MAC algorithm 3) Thanks.
private static byte[] getCC_MACNbytes(string Key_MAC, byte[] eIFD, string Init_Vec)
{
byte[] Kmac = StringToByteArray(Key_MAC);
// Split the 16 byte MAC key into two keys
byte[] key1 = new byte[8];
Array.Copy(Kmac, 0, key1, 0, 8);
byte[] key2 = new byte[8];
Array.Copy(Kmac, 8, key2, 0, 8);
DES des1 = DES.Create();
des1.BlockSize = 64;
des1.Key = key1;
des1.Mode = CipherMode.CBC;
des1.Padding = PaddingMode.None;
des1.IV = new byte[8];
DES des2 = DES.Create();
des2.BlockSize = 64;
des2.Key = key2;
des2.Mode = CipherMode.CBC;
des2.Padding = PaddingMode.None;
des2.IV = new byte[8];
// Padd the data with Padding Method 2 (Bit Padding)
System.IO.MemoryStream out_Renamed = new System.IO.MemoryStream();
out_Renamed.Write(eIFD, 0, eIFD.Length);
out_Renamed.WriteByte((byte)(0x80));
while (out_Renamed.Length % 8 != 0)
{
out_Renamed.WriteByte((byte)0x00);
}
byte[] eIfd_padded = out_Renamed.ToArray();
int N_bytes = eIfd_padded.Length/8; // Number of Bytes
byte[] d1 = new byte[8];
byte[] dN = new byte[8];
byte[] hN = new byte[8];
byte[] intN = new byte[8];
// MAC Algorithm 3
// Initial Transformation 1
Array.Copy(eIfd_padded, 0, d1, 0, 8);
hN = des1.CreateEncryptor().TransformFinalBlock(d1, 0, 8);
// Split the blocks
// Iteration on the rest of blocks
for (int j = 1; j<N_bytes; j++)
{
Array.Copy(eIfd_padded, (8*j), dN, 0, 8);
// XOR
for (int i = 0; i < 8; i++)
intN[i] = (byte)(hN[i] ^ dN[i]);
// Encrypt
hN = des1.CreateEncryptor().TransformFinalBlock(intN, 0, 8);
}
// Output Transformation 3
byte[] hNdecrypt = des2.CreateDecryptor().TransformFinalBlock(hN, 0, 8);
byte[] mIfd = des1.CreateEncryptor().TransformFinalBlock(hNdecrypt, 0, 8);
// Get check Sum CC
return mIfd;
}

TripleDES Length of the data to encrypt is invalid

I have the following code :
public static string Encrypt3Des(string cipherString)
{
string result = "";
byte[] keyArray;
byte[] ivArray;
byte[] toEncryptArray = Enc3DesPerChar(cipherString);
//string toEncryptString = ByteArrayToString(toEncryptArray);
// Get the key from config file
System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
string key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
string iv = (string)settingsReader.GetValue("InitializationVector", typeof(String));
keyArray = StringToByteArray(key);
ivArray = StringToByteArray(iv);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
tdes.IV = ivArray;
//ChiperMode
tdes.Mode = CipherMode.CBC;
//PaddingMode(if any extra byte added)
tdes.Padding = PaddingMode.None;
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();
result = ByteArrayToString(resultArray);
return result;
}
And this is my method :
protected static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
protected static byte[] StringToByteArray(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;
}
protected static byte[] Enc3DesPerChar(String toEncrypt)
{
string toAsciiString = ByteArrayToString(Encoding.ASCII.GetBytes(toEncrypt));
string toRoll = toAsciiString;
int NumberChars = toRoll.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(toRoll.Substring(i, 2), 16);
}
return bytes;
}
Everything works fine with the above method until I found that the method cannot accept less than 8 character.
The block code that raise an error :
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
Error message :
Length of the data to encrypt is invalid.
Example input :
Encrypt3Des("14022000"); // return encrypt because 8 character or more
Encrypt3Des("1402200"); // return error because 7 character
Does anybody know why this is or how I can fix it? (I don't know if it comes from my encrypting method, but I know a web app which uses the exact same thing to encrypt strings and that one does work.)
EDIT :
The tool that I used for manual encrypt : 3des
The option must :
Text input type
Plaintext input text
3DES function
CBC mode
Fixed Key Hex
Fixed Init Vector
You are using padding as none. Set the padding mode to PKCS7.
Ok, I think just found the solution (my client told me how), I need to fill up the character with null before the loop. null can be converted to ascii with "00". so I decide to PadRight to the ascii result with '0' to 16 character, so one of my method become :
protected static byte[] Enc3DesPerChar(String toEncrypt)
{
string toAsciiString = ByteArrayToString(Encoding.ASCII.GetBytes(toEncrypt));
string toRoll = toAsciiString.PadRight(16,'0');
int NumberChars = toRoll.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(toRoll.Substring(i, 2), 16);
}
return bytes;
}

Encryption and decryption of XML file

I want to encrypt an XML file and decrypt the same in a different machine in c#. Please help......
I have already tried with RSA algorithm and RijndaelManaged key but not able to decrypt the file in different machine.
From the problem description, you're probably looking into symmetric encryption algorithm. This is something that should get you started:
public class Key {
public string Password { get; set; }
public byte[] Salt { get; set; }
public string Vector { get; set; }
public PaddingMode? Padding { get; set; }
}
public class AesCryptor {
private const int HASH_SIZE = 32;
private ICryptoTransform m_Decryptor;
private ICryptoTransform m_Encryptor;
private TimeSpan m_Validity;
// Methods
public AesCryptor(Key key, TimeSpan validity) {
if (key == null) {
throw new ArgumentNullException("key");
}
m_Validity = validity;
using (AesManaged aes = new AesManaged()) {
aes.Mode = CipherMode.CBC;
aes.Key = new Rfc2898DeriveBytes(key.Password, key.Salt).GetBytes(aes.KeySize / 8);
aes.IV = Encoding.ASCII.GetBytes(key.Vector);
if (key.Padding.HasValue) {
aes.Padding = key.Padding.Value;
}
m_Encryptor = aes.CreateEncryptor();
m_Decryptor = aes.CreateDecryptor();
}
}
private static bool CompareArray(byte[] first, byte[] second) {
if (first.Length != second.Length) {
return false;
}
for (int i = 0; i < first.Length; i++) {
if (first[i] != second[i]) {
return false;
}
}
return true;
}
public byte[] Decrypt(byte[] encryptedData) {
byte[] hash;
if (encryptedData == null) {
throw new ArgumentNullException("encryptedData");
}
byte[] buffer = m_Decryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
using (SHA256 sha = SHA256.Create()) {
hash = sha.ComputeHash(buffer, 0, buffer.Length - HASH_SIZE);
}
byte[] orginalHash = new byte[HASH_SIZE];
Buffer.BlockCopy(buffer, buffer.Length - HASH_SIZE, orginalHash, 0, HASH_SIZE);
if (!CompareArray(orginalHash, hash)) {
throw new Exception("Hash match failure.");
}
if (m_Validity != TimeSpan.Zero) {
DateTime timestamp = new DateTime(BitConverter.ToInt64(buffer, (buffer.Length - HASH_SIZE) - 8));
TimeSpan delta = (TimeSpan)(DateTime.Now - timestamp);
if (delta > m_Validity) {
throw new Exception("Timestamp too old.");
}
}
byte[] result = new byte[(buffer.Length - HASH_SIZE) - 8];
Buffer.BlockCopy(buffer, 0, result, 0, (buffer.Length - HASH_SIZE) - 8);
return result;
}
public byte[] Encrypt(byte[] data) {
byte[] hash;
if (data == null) {
throw new ArgumentNullException("data");
}
byte[] buffer = new byte[(data.Length + 8) + HASH_SIZE];
Buffer.BlockCopy(data, 0, buffer, 0, data.Length);
Buffer.BlockCopy(BitConverter.GetBytes(DateTime.Now.Ticks), 0, buffer, data.Length, 8);
using (SHA256 sha = SHA256.Create()) {
hash = sha.ComputeHash(buffer, 0, buffer.Length - HASH_SIZE);
}
Buffer.BlockCopy(hash, 0, buffer, buffer.Length - HASH_SIZE, HASH_SIZE);
return m_Encryptor.TransformFinalBlock(buffer, 0, buffer.Length);
}
}
Usage:
var myKey = new Key {
Password = "whatever,nevermind#$",
Vector = "Q^!#g1353hdhjs*-",
Salt = new byte[] { 0x33, 0x4d, 0x56, 0x4f, 1, 0x22, 15, 0x7f }
};
var cryptor = new AesCryptor(myKey, TimeSpan.Zero);
// this will encrypt c:\test.xml into byte array
byte[] encrypted = cryptor.Encrypt(File.ReadAllBytes(#"c:\test.xml"));
// this will persist encrypted byte array into file c:\test-encrypted.bin
File.WriteAllBytes(#"c:\test-encrypted.bin", encrypted);
// this will load & decrypt bytes from file c:\test-encrypted.bin
byte[] decrypted = cryptor.Decrypt(File.ReadAllBytes(#"c:\test-encrypted.bin"));
// this will write decrypted bytes into c:\test-decrypted.xml
File.WriteAllBytes(#"c:\test-decrypted.xml", decrypted);

Encryption in ASP.NET that can be decrypted in MySQL with AES_DECRYPT()

I would like to be able to perform application-level encryption in ASP.NET, producing an array of bytes that would then be saved to a MySQL blob column. I would then like it to be an option that, if you have the encryption key, you would be able to decrypt it using MySQL's AES_DECRYPT() function. This seems like it should be possible, since AES_DECRYPT is an implementation of AES/Rijndael.
The MySQL AES_ENCRYPT/DECRYPT functions simply take a key and the string to encrypt/decrypt as parameters. The examples i've seen for encryption in ASP.NET/C#, however, involve also specifying values for Key and IV (initialization vector). How do these affect the final, encrypted byte array, and how can they be taken into account when decrypting with AES_DECRYPT)_?
You can do that by setting RijndaelManaged to use ECB mode.
However, ECB mode is not secure and should be avoided.
In general, a database is a very bad place to perform encryption.
If you are able to encrypt your data in the database, that implies that you have both the ciphertext and the key in the same place; this defeats the purpose of encryption.
You should keep the key as far away from ciphertext storage as possible; using any sort of SQL encryption function is usually indicative of a fundamental design flaw in your encryption strategy which can have disastrous consequences.
Encryption
In Mysql use HEX(AES_ENCRYPT('unencryptedString', 'Password'))
Example
UPDATE `secrets` SET `value`=HEX(AES_ENCRYPT('unencryptedString', 'Password')) WHERE `Id` = 2;
you will see in the database there is a value similar to this D4B5E4CAD92FFB73FCAEB5ED3B31E9EDD8FA7440E9E3F582FE5A9237DB8EE013
Now the equivalent code in C# is (Original Source:link)
public static String AES_encrypt(String Input, string key)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 128;
aes.BlockSize = 128;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.PKCS7;
aes.Key = mkey(key);
aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] xBuff = null;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
{
byte[] xXml = Encoding.UTF8.GetBytes(Input);
cs.Write(xXml, 0, xXml.Length);
cs.FlushFinalBlock();
}
xBuff = ms.ToArray();
}
return xBuff.ToHexString();
}
Helper methods and extensions that used
Refernce Link
private static byte[] mkey(string skey)
{
byte[] key = Encoding.UTF8.GetBytes(skey);
byte[] k = new byte[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
for (int i = 0; i < key.Length; i++)
{
k[i % 16] = (byte)(k[i % 16] ^ key[i]);
}
return k;
}
Reference Link
public static class ByteArrayExtensions
{
public static string ToHexString(this byte[] ba)
{
return BitConverter.ToString(ba).Replace("-", "");
}
}
Decryption
in Mysql use CAST(AES_DECRYPT(UNHEX(c.value), 'Password') as char)
Example
SELECT c.*,CAST(AES_DECRYPT(UNHEX(c.`value`), 'Password') as char) FROM `secrets` as c where `Id` = 2;
Equivalent code in C# is
public static String AES_decrypt(String Input, string key)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 128;
aes.BlockSize = 128;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.PKCS7;
aes.Key = mkey(key);
aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var decrypt = aes.CreateDecryptor();
byte[] encryptedStr = Input.FromHex2ByteArray();
string Plain_Text;
using (var ms = new MemoryStream(encryptedStr))
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cs))
{
Plain_Text = reader.ReadToEnd();
}
}
}
return Plain_Text;
}
Helper methods and extensions that used
Reference Link
private static byte[] mkey(string skey)
{
byte[] key = Encoding.UTF8.GetBytes(skey);
byte[] k = new byte[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
for (int i = 0; i < key.Length; i++)
{
k[i % 16] = (byte)(k[i % 16] ^ key[i]);
}
return k;
}
Reference Link
public static byte[] FromHex2ByteArray(this string hex)
{
if (hex.Length % 2 == 1)
throw new Exception("The binary key cannot have an odd number of digits");
byte[] arr = new byte[hex.Length >> 1];
for (int i = 0; i < hex.Length >> 1; ++i)
{
arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
}
return arr;
}
private static int GetHexVal(char hex)
{
int val = (int)hex;
//For uppercase A-F letters:
//return val - (val < 58 ? 48 : 55);
//For lowercase a-f letters:
//return val - (val < 58 ? 48 : 87);
//Or the two combined, but a bit slower:
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
}

how to encrypt AES/ECB/128 messages in .Net?

Took the vectors from this site http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors#aes-ecb-128
In javascript (sjcl) have the same result
var key = [0x2b7e1516,0x28aed2a6,0xabf71588,0x09cf4f3c];
var test = [0x6bc1bee2,0x2e409f96,0xe93d7e11,0x7393172a];
aes = new sjcl.cipher.aes(key);
r = aes.encrypt(test);
console.log(r);
But I can not reach it in the C#
[TestMethod]
public void EncryptIntsToInts()
{
Int32[] key = { unchecked((Int32)0x2b7e1516), 0x28aed2a6, unchecked((Int32)0xabf71588), 0x09cf4f3c };
Int32[] test = { 0x6bc1bee2,0x2e409f96,unchecked((Int32)0xe93d7e11),0x7393172a };
Int32[] answer = { 0x3ad77bb4, 0x0d7a3660, unchecked((Int32)0xa89ecaf3), 0x2466ef97 };
var r = AES.EncryptIntsToInts(test, key.ToByteArray());
Assert.IsTrue(r.SequenceEqual(answer));
}
static byte[] zeroIV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
public static Int32[] EncryptIntsToInts(Int32[] input, byte[] key)
{
// Check arguments.
if (input == null || input.Length <= 0)
throw new ArgumentNullException("input");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
// Declare the RijndaelManaged object
// used to encrypt the data.
RijndaelManaged aesAlg = null;
byte[] bResult;
try
{
aesAlg = new RijndaelManaged
{
Key = key,
Mode = CipherMode.ECB,
Padding = PaddingMode.None,
KeySize = 128,
BlockSize = 128,
IV = zeroIV
};
ICryptoTransform encryptor = aesAlg.CreateEncryptor();
byte[] bInput = new byte[input.Length * sizeof(int)];
Buffer.BlockCopy(input, 0, bInput, 0, bInput.Length);
bResult = encryptor.TransformFinalBlock(bInput, 0, input.Length);
}
finally
{
if (aesAlg != null)
aesAlg.Clear();
}
int[] iResult = new int[bResult.Length / sizeof(int)];
Buffer.BlockCopy(bResult, 0, iResult, 0, bResult.Length);
return iResult;
}
What is my error?
========================================================
Start edit
New code in which right order of the bytes, but it does not work
[TestMethod]
public void EncryptIntsToInts()
{
byte[] key = "2b7e151628aed2a6abf7158809cf4f3c".HEX2Bytes();
byte[] test = "6bc1bee22e409f96e93d7e117393172a".HEX2Bytes();
byte[] answer = "3ad77bb40d7a3660a89ecaf32466ef97".HEX2Bytes();
RijndaelManaged aesAlg = new RijndaelManaged
{
Key = key,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7,
KeySize = 128,
BlockSize = 128,
IV = zeroIV
};
ICryptoTransform encryptor = aesAlg.CreateEncryptor();
var r = encryptor.TransformFinalBlock(test, 0, test.Length);
Assert.IsTrue(r.SequenceEqual(answer));
}
public static byte[] HEX2Bytes(this string hex)
{
if (hex.Length%2 != 0)
{
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture,
"The binary key cannot have an odd number of digits: {0}", hex));
}
byte[] HexAsBytes = new byte[hex.Length/2];
for (int index = 0; index < HexAsBytes.Length; index++)
{
string byteValue = hex.Substring(index*2, 2);
HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return HexAsBytes;
}
static byte[] zeroIV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Right code (just add a try / using):
[TestMethod]
public void EncryptIntsToInts()
{
byte[] key = "2b7e151628aed2a6abf7158809cf4f3c".HEX2Bytes();
byte[] test = "6bc1bee22e409f96e93d7e117393172a".HEX2Bytes();
byte[] answer = "3ad77bb40d7a3660a89ecaf32466ef97".HEX2Bytes();
var r = AES.Encrypt(test, key);
Assert.IsTrue(answer.SequenceEqual(r));
}
public static byte[] Encrypt(byte[] input, byte[] key)
{
var aesAlg = new AesManaged
{
KeySize = 128,
Key = key,
BlockSize = 128,
Mode = CipherMode.ECB,
Padding = PaddingMode.Zeros,
IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
return encryptor.TransformFinalBlock(input, 0, input.Length);
}
You use 32 bit integers to define the key. When you transform them to bytes, you use native endianness, which typically is little endian. So your key is 16157e2b a6... and not 2b7e1516 28....
I wouldn't use ints to represent a key in the first place. But if you really want to, write a big endian conversion function.
I also strongly recommend against ECB mode. You could use CBC together with HMAC (in an encrypt then mac construction), or use a third party lib to implement GCM.

Categories