Last active
November 11, 2023 14:04
-
-
Save daniiiol/936538cb77f80ed4640ac774b4dce193 to your computer and use it in GitHub Desktop.
PixelByPixel analysis of AES-CBC mode and different IV approaches
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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