I'm making an app which will need to encrypt a string.
I'm completely new to AES encryption.
I have to code that runs on the server to encrypt.
public static string Encrypt(string text, byte[] key, byte[] iv, int keysize = 128, int blocksize = 128, CipherMode cipher = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = blocksize;
aes.KeySize = keysize;
aes.Mode = cipher;
aes.Padding = padding;
byte[] src = Encoding.UTF8.GetBytes(text);
using (ICryptoTransform encrypt = aes.CreateEncryptor(key, iv))
{
byte[] dest = encrypt.TransformFinalBlock(src, 0, src.Length);
encrypt.Dispose();
return Convert.ToBase64String(dest);
}
}
I already have this, with a library Bouncy Castle, but I can't seem to find a simple example.
byte[] key = Encoding.UTF8.GetBytes("[SECRETKEY]");
byte[] iv = Encoding.UTF8.GetBytes("[IV]");
var cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7Padding");
cipher.Init(true, new KeyParameter(key));
If it can help I also have the code which runs an Android client.
Let me know then I can post it.
You can use the PCLCrypto library, there's a nuget package available (Install-Package PclCrypto)
From https://github.com/AArnott/PCLCrypto/wiki/Crypto-Recipes:
Perform AES encryption/decryption
byte[] keyMaterial;
byte[] data;
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
byte[] iv = null; // this is optional, but must be the same for both encrypting and decrypting
byte[] cipherText = WinRTCrypto.CryptographicEngine.Encrypt(key, data, iv);
byte[] plainText = WinRTCrypto.CryptographicEngine.Decrypt(key, cipherText, iv);
The cipherText variable is the encrypted data, plainText is the encrypted variable decrypted again
Related
Here is the C# code I'm trying to port into Node crypto, but since I don't know c# it's proving a little tricky!
public static string EncryptStringToBytes_Aes(string username, string password)
{
string encrypted = string.Empty;
byte[] clearBytes = Encoding.UTF8.GetBytes(password);
Console.WriteLine("1." + clearBytes);
using (Aes aesAlg = Aes.Create())
{
byte[] k; byte[] iv;
byte[] bytes = Encoding.UTF8.GetBytes(username);
k = SHA256.Create().ComputeHash(bytes);
iv = MD5.Create().ComputeHash(bytes);
aesAlg.Key = k;
aesAlg.IV = iv;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
csEncrypt.Write(clearBytes, 0, clearBytes.Length); }
encrypted = Convert.ToBase64String(msEncrypt.ToArray());
}
}
return encrypted;
}
C# repl:
https://repl.it/#HarryLincoln/NegligiblePoisedHexagon
Node workings:
crypto.createCipheriv() definitely looks like the way to go, but the I don't believe the c# methods (SHA256.Create() & MD5.Create()) care for the length of the key and iv - but crypto.createCipheriv() does.
The c# uses a CryptoStream: So I think some kind of Buffer is in order looking at some similar C# -> Node crypto stuff
Would really appreciate some help!
.Net Framework - AES encryption uses a 256 bit key and CBC mode and PKCS7 padding by default.
The code to port is very simple to read, it just does this:
return
BASE64 (
AES_ENCRYPT (
password,
Key: SHA256(username),
IV: MD5(username)
)
)
The same can easily be achieved on Node.
const crypto = require('crypto');
const key = crypto.createHash('sha256').update('username', 'utf8').digest();
const iv = crypto.createHash('md5').update('username', 'utf8').digest();
const encryptor = crypto.createCipheriv("aes-256-cbc", key, iv);
var crypted = Buffer.concat([encryptor.update('password', 'utf8'), encryptor.final()]);
let base64data = crypted.toString('base64');
console.log(base64data);
Python Encryption:
salt = 16 * b'\0'
keyIV = PBKDF2(Config.SECRET, salt).read(48)
key = keyIV[:32]
iv = keyIV[-16:]
aes = AES.new(key, AES.MODE_CBC, iv)
# padding
length = 16 - (len(textToEncrypt) % 16)
print(len(textToEncrypt))
textToEncrypt += length * b'\0'
encrypted = aes.encrypt(textToEncrypt)
encoded = base64.b64encode(encrypted)
return encoded
And here is my C# decryption:
textToDecrypt = textToDecrypt.Replace(" ", "+");
byte[] bytesToDecrypt = Convert.FromBase64String(textToDecrypt);
string decryptedText;
using (Aes aes = Aes.Create())
{
byte[] salt = new byte[16];
Rfc2898DeriveBytes crypto = new Rfc2898DeriveBytes(Config.SECRET, salt);
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.Key = crypto.GetBytes(32);
aes.IV = crypto.GetBytes(16);
using (MemoryStream mStream = new MemoryStream())
{
using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cStream.Write(bytesToDecrypt, 0, bytesToDecrypt.Length);
}
decryptedText = Encoding.Unicode.GetString(mStream.ToArray());
}
}
return decryptedText;
EDIT
Following #kelalaka answer, I'm now able to encrypt from C# and decrypt that string in python successfully, but not vice versa. That is, if I encrypt a string in python, and try to decrypt that encryption in C# I get an exception: "Bad PKCS7 padding. Invalid length 0". My python encryption is much shorter than what I get in C# using the same cipherText, iv, and key.
I'm working on AES encryption/decryption. I want to encrypt request from my angular app and send it to .net api and decrypt at api then encrypt the response from api side and send it to angular app and decrypt using AES.
But sometimes it gives me 'padding is invalid and cannot be removed' exception at api side.
Here is my angular typescript crypto service code:
aesEncrypt(keys: string, value: string) { // encrypt api request parameter with aes secretkey
var key = CryptoJS.enc.Utf8.parse(keys);
var iv = CryptoJS.enc.Utf8.parse(keys);
var encrypted = CryptoJS.AES.encrypt(JSON.stringify(value), key,
{
keySize: 128 / 8,
//keySize: 128,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString();
}
aesDecrypt(keys: string, value: any) { // decrypt api response parameter with aes secretkey
var key = CryptoJS.enc.Utf8.parse(keys);
var iv = CryptoJS.enc.Utf8.parse(keys);
var decrypted = CryptoJS.AES.decrypt(value, key, {
keySize: 128 / 8,
//keySize: 128,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8));
}
Here is my api crypto filter code:
Way 1:
public static string Encrypt(string key, string data)
{
byte[] encryptedBytes = new UTF8Encoding().GetBytes(data);
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform crypto = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
return Convert.ToBase64String(secret);
}
public static string Decrypt(string key, string encrypted)
{
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
return Encoding.UTF8.GetString(secret);
}
private static AesCryptoServiceProvider AesCryptoServiceProvider(string key)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
//aes.BlockSize = 128; //Not Required
//aes.KeySize = 256; //Not Required
//aes.KeySize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.UTF8.GetBytes(key); //PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0 =
aes.IV = Encoding.UTF8.GetBytes(key); //2314345645678765
return aes;
}
Way 2:
public static string Encrypt(string key, string data)
{
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform encryptor = aes.CreateEncryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
StreamWriter streamWriter = new StreamWriter(cs);
streamWriter.Write(data);
streamWriter.Flush();
cs.FlushFinalBlock();
byte[] cypherTextBytes = ms.ToArray();
ms.Close();
return Convert.ToBase64String(cypherTextBytes);
}
public static string Decrypt(string key, string encrypted)
{
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
ICryptoTransform decryptor = aes.CreateDecryptor();
byte[] plainText = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(plainText);
}
private static AesCryptoServiceProvider AesCryptoServiceProvider(string key)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
//aes.BlockSize = 128; //Not Required
//aes.KeySize = 256; //Not Required
//aes.KeySize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.UTF8.GetBytes(key); //PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0 =
aes.IV = Encoding.UTF8.GetBytes(key); //2314345645678765
return aes;
}
I tried both the ways at api level but still it is giving me padding issue (sometimes, not always)
we want to decrypt AES-128 encrypted m3u8 TS files. here is our .m3u8 file
#EXTM3U
#EXT-X-TARGETDURATION:12
#EXT-X-ALLOW-CACHE:YES
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-KEY:METHOD=AES-128,URI="enc.key?wmsAuthSign=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IjdjY2I5ZTAxZGI1YzVkM2IzMWUzMzc1NzQ3MjZjNjYwIiwiZXhwIjoxNTEzMTU4ODM5LCJpc3MiOiJTYWJhIElkZWEgR1NJRyJ9.vvYKPY9tyBnhGGnNtY-XLy_Hz5cyJx5Ma2APVv0g5dk"
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:6.000,
s-1-v1-a1.ts?wmsAuthSign=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IjdjY2I5ZTAxZGI1YzVkM2IzMWUzMzc1NzQ3MjZjNjYwIiwiZXhwIjoxNTEzMTU4ODM5LCJpc3MiOiJTYWJhIElkZWEgR1NJRyJ9.vvYKPY9tyBnhGGnNtY-XLy_Hz5cyJx5Ma2APVv0g5dk
#EXTINF:6.000,
s-2-v1-a1.ts?wmsAuthSign=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IjdjY2I5ZTAxZGI1YzVkM2IzMWUzMzc1NzQ3MjZjNjYwIiwiZXhwIjoxNTEzMTU4ODM5LCJpc3MiOiJTYWJhIElkZWEgR1NJRyJ9.vvYKPY9tyBnhGGnNtY-XLy_Hz5cyJx5Ma2APVv0g5dk
#EXTINF:6.000,
s-3-v1-a1.ts?wmsAuthSign=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IjdjY2I5ZTAxZGI1YzVkM2IzMWUzMzc1NzQ3MjZjNjYwIiwiZXhwIjoxNTEzMTU4ODM5LCJpc3MiOiJTYWJhIElkZWEgR1NJRyJ9.vvYKPY9tyBnhGGnNtY-XLy_Hz5cyJx5Ma2APVv0g5dk
#EXTINF:12.000,
s-4-v1-a1.ts?wmsAuthSign=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IjdjY2I5ZTAxZGI1YzVkM2IzMWUzMzc1NzQ3MjZjNjYwIiwiZXhwIjoxNTEzMTU4ODM5LCJpc3MiOiJTYWJhIElkZWEgR1NJRyJ9.vvYKPY9tyBnhGGnNtY-XLy_Hz5cyJx5Ma2APVv0g5dk
we have both enc.key file and the server response to 'enc.key' that is DVQpuWrxZLd2nCTTxAysIg==
we are using these C# functions for decryption but we don't know how to find salt or block size ? or basically we are doing it in correct way ?
public static void DecryptFile(string inputFile, string output,string password)
{
byte[] bytesToBeDecrypted = File.ReadAllBytes(inputFile);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);
File.Delete(inputFile);
File.WriteAllBytes(output, bytesDecrypted);
}
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 128;
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.Mode = CipherMode.CBC;
AES.Padding = PaddingMode.PKCS7;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
There was already a similar quesion here (unable to find it back)
how to find salt or block size
Look at your EXT-X-KEY header. It states AES-128, so you will have to use AES-128 (it's the key size, block size is always 128 bit).
According to the RFC by default CBC mode with Pkcs7 padding is used.
The section 4.3.2.4. EXT-X-KEY further states: the Initialization Vector (IV) attribute value or the Media Sequence Number as the IV
So the IV should be present in the EXT-X-KEY header. If not, the sequence number is used (which is terrible idea for CBC, but this is how it is).
or basically we are doing it in correct way
Basically it looks ok (except the salt and key). I am not sure what is the encryption key. The encoded response from the server has 16 bites (128 bits) so I'd assume that can be the key (that you will have to find out yourself)
Hi there i'm using this encryption method to encrypt my json value in .net side
public static string Encrypt256(string text)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.IV = Encoding.UTF8.GetBytes(AesIV256);
aes.Key = Encoding.UTF8.GetBytes(AesKey256);
aes.Mode = CipherMode.CBC;
byte[] src = Encoding.Unicode.GetBytes(text);
using (ICryptoTransform encrypt = aes.CreateEncryptor())
{
byte[] dest = encrypt.TransformFinalBlock(src, 0, src.Length);
Debug.WriteLine(Convert.ToBase64String(dest));
return Convert.ToBase64String(dest);
}
}
And im trying to decrypt it in Node Js side
var crypto = require('crypto'),
algorithm = process.env.tombalaCryptoAlgorithm,
password = process.env.tombalaHmacPass,
iv = '!QAZ2WSX#EDC4RFV'
function encrypt(text) {
var cipher = crypto.createCipheriv(algorithm, password, iv)
var encrypted = cipher.update(text, 'utf8', 'base64')
encrypted += cipher.final('base64');
return encrypted;
You are converting your text to be encrypted to Unicode which means UTF-16.
In UTF-16 every character consists of two bytes. If the second byte is not used it is null as you have observed.
I assume you want UTF-8 encoding. Therefore replace the line
byte[] src = Encoding.Unicode.GetBytes(text);
with
byte[] src = Encoding.UTF8.GetBytes(text);