Skip to content

Instantly share code, notes, and snippets.

@daniiiol
Last active November 11, 2023 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daniiiol/936538cb77f80ed4640ac774b4dce193 to your computer and use it in GitHub Desktop.
Save daniiiol/936538cb77f80ed4640ac774b4dce193 to your computer and use it in GitHub Desktop.
PixelByPixel analysis of AES-CBC mode and different IV approaches
using System.Drawing;
using System.Drawing.Imaging;
using System.Security.Cryptography;
using System.Text;
internal class Program
{
private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
private static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
string inputImagePath = @$"c:\\tmp\\image.png";
if (i > 0)
{
inputImagePath = @$"c:\\tmp\\image_encrypted{i - 1}.png";
}
string outputImagePath = @$"c:\tmp\image_encrypted{i}.png";
// Load image
Bitmap bitmap = new Bitmap(inputImagePath);
Bitmap encryptedBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format24bppRgb);
// AES-CBC init
using Aes aes = Aes.Create();
var keyBytes = new byte[16];
rngCsp.GetBytes(keyBytes);
aes.Key = keyBytes;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.Zeros;
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
Color pixel = bitmap.GetPixel(x, y);
byte[] pixelBytes = { pixel.R, pixel.G, pixel.B };
// Encryption (choose one case to see the impact)
/* Case 1: Complete Random Approach (recommended)
var ivBytes = new byte[16];
rngCsp.GetBytes(ivBytes);
*/
/* Case 2: Wrong approach with cutted IV
string baseString = "myId-recieverId-" + DateTime.UtcNow.ToString("yyyyMMddHHmmss");
*/
/* Case 3: Not perfect approach with timestamp incl. milliseconds */
string baseString = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
// Convert string to byte array
byte[] bytes = Encoding.UTF8.GetBytes(baseString);
// fill or cut iv
byte[] iv = new byte[16];
Array.Copy(bytes, iv, Math.Min(16, bytes.Length));
if (bytes.Length < 16)
{
// Zero Padding if needed
for (int p = bytes.Length; p < 16; p++)
{
iv[p] = 0;
}
}
aes.IV = iv;
byte[] encryptedBytes = EncryptBytes(aes, pixelBytes);
// Convert ciphertext to a color
Color encryptedColor = Color.FromArgb(255, encryptedBytes[0], encryptedBytes[1], encryptedBytes[2]);
encryptedBitmap.SetPixel(x, y, encryptedColor);
}
}
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 100L);
myEncoderParameters.Param[0] = myEncoderParameter;
encryptedBitmap.Save(outputImagePath, jpgEncoder, myEncoderParameters);
}
}
private static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
static byte[] EncryptBytes(SymmetricAlgorithm alg, byte[] data)
{
using ICryptoTransform encryptor = alg.CreateEncryptor();
return encryptor.TransformFinalBlock(data, 0, data.Length);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment