@@ -21,109 +21,130 @@ foreach ((string mode, (string modeCode, CipherMode? bclMode)) in modes)
2121{
2222 foreach (int keySize in new int[] { 128, 192, 256 })
2323 {
24- foreach (int inputLength in new int[] { 16, 32 , 64 })
24+ foreach (int inputLength in new int[] { 16, 35 , 64 })
2525 {
26- byte[] input = new byte[inputLength];
27- random.NextBytes(input);
26+ foreach (bool pad in new bool[] { false, true })
27+ {
28+ // It is not allowed to use no padding on non-block lengths
29+ // It makes sense in cfb, ctr and ofb modes
30+ if (!pad && inputLength % 16 != 0 && mode is not "cfb" or "ctr" or "ofb")
31+ {
32+ continue;
33+ }
2834
29- byte[] key = new byte[keySize / 8];
30- random.NextBytes(key);
35+ // It does not make sense to test padding for stream cipher modes
36+ // (and the OpenSSL, BCL implementations differ)
37+ if (pad && mode is "cfb" or "ctr" or "ofb")
38+ {
39+ continue;
40+ }
3141
32- byte[] iv = new byte[16 ];
33- random.NextBytes(iv );
42+ byte[] input = new byte[inputLength ];
43+ random.NextBytes(input );
3444
35- StringBuilder openSslCmd = new();
45+ byte[] key = new byte[keySize / 8];
46+ random.NextBytes(key);
3647
37- openSslCmd.Append($"echo -n -e '{string.Join("", input.Select(b => $"\\x{b:x2}"))}' |");
38- openSslCmd.Append($" openssl enc -e -aes-{keySize}-{mode}");
39- openSslCmd.Append($" -K {Convert.ToHexString(key)}");
40- if (mode != "ecb")
41- {
42- openSslCmd.Append($" -iv {Convert.ToHexString(iv)}");
43- }
44- openSslCmd.Append(" -nopad");
48+ byte[] iv = new byte[16];
49+ random.NextBytes(iv);
4550
46- ProcessStartInfo pi = new("wsl", openSslCmd.ToString())
47- {
48- RedirectStandardOutput = true,
49- RedirectStandardError = true,
50- };
51+ StringBuilder openSslCmd = new();
5152
52- byte[] expected;
53- string error;
53+ openSslCmd.Append($"echo -n -e '{string.Join("", input.Select(b => $"\\x{b:x2}"))}' |");
54+ openSslCmd.Append($" openssl enc -e -aes-{keySize}-{mode}");
55+ openSslCmd.Append($" -K {Convert.ToHexString(key)}");
56+ if (mode != "ecb")
57+ {
58+ openSslCmd.Append($" -iv {Convert.ToHexString(iv)}");
59+ }
5460
55- using (MemoryStream ms = new())
56- {
57- var p = Process.Start(pi);
58- p.StandardOutput.BaseStream.CopyTo(ms);
59- error = p.StandardError.ReadToEnd();
61+ if (!pad)
62+ {
63+ openSslCmd.Append(" -nopad");
64+ }
6065
61- p.WaitForExit();
66+ ProcessStartInfo pi = new("wsl", openSslCmd.ToString())
67+ {
68+ RedirectStandardOutput = true,
69+ RedirectStandardError = true,
70+ };
6271
63- expected = ms.ToArray() ;
64- }
72+ byte[] expected ;
73+ string error;
6574
66- tw.WriteLine("[TestMethod]");
67- tw.WriteLine($"public void AES_{mode.ToUpper()}_{keySize}_Length{inputLength}()");
68- tw.WriteLine("{");
69- tw.Indent++;
75+ using (MemoryStream ms = new())
76+ {
77+ var p = Process.Start(pi);
78+ p.StandardOutput.BaseStream.CopyTo(ms);
79+ error = p.StandardError.ReadToEnd();
7080
71- WriteBytes(input);
72- WriteBytes(key);
73- if (mode != "ecb")
74- {
75- WriteBytes(iv);
76- }
77- tw.WriteLine();
81+ p.WaitForExit();
7882
79- if (!string.IsNullOrWhiteSpace(error))
80- {
81- tw.WriteLine($"// {openSslCmd}");
82- tw.WriteLine($"Assert.Fail(@\"{error}\");");
83+ expected = ms.ToArray();
84+ }
8385
84- tw.Indent--;
85- tw.WriteLine("}");
86- tw.WriteLine();
87- continue;
88- }
86+ tw.WriteLine("[TestMethod]");
87+ tw.WriteLine($"public void AES_{mode.ToUpper()}_{keySize}_Length{inputLength}_{(pad ? "Pad" : "NoPad")}()");
88+ tw.WriteLine("{");
89+ tw.Indent++;
8990
90- tw.WriteLine($"// {openSslCmd} | hd"); // pipe to hexdump
91- WriteBytes(expected);
92- tw.WriteLine();
93- tw.WriteLine($"var actual = new AesCipher(key, {modeCode}, pkcs7Padding: false).Encrypt(input);");
94- tw.WriteLine();
95- tw.WriteLine($"CollectionAssert.AreEqual(expected, actual);");
91+ WriteBytes(input);
92+ WriteBytes(key);
93+ if (mode != "ecb")
94+ {
95+ WriteBytes(iv);
96+ }
97+ tw.WriteLine();
9698
97- if (bclMode is not null and not CipherMode.OFB)
98- {
99- // Verify the OpenSSL result is the same as the .NET BCL, just to be sure
100- Aes bcl = Aes.Create();
101- bcl.Key = key;
102- bcl.IV = iv;
103- bcl.Mode = bclMode.Value;
104- bcl.Padding = PaddingMode.None;
105- bcl.FeedbackSize = 128; // .NET is CFB8 by default, OpenSSL is CFB128
106- byte[] bclBytes = bcl.CreateEncryptor().TransformFinalBlock(input, 0, input.Length);
107-
108- if (!bclBytes.AsSpan().SequenceEqual(expected))
99+ if (!string.IsNullOrWhiteSpace(error))
109100 {
110- tw.WriteLine();
111- tw.WriteLine(@"Assert.Inconclusive(@""OpenSSL does not match the .NET BCL");
112- tw.Indent++;
113- tw.WriteLine($@"OpenSSL: {Convert.ToHexString(expected)}");
114- tw.WriteLine($@"BCL: {Convert.ToHexString(bclBytes)}"");");
101+ tw.WriteLine($"// {openSslCmd}");
102+ tw.WriteLine($"Assert.Fail(@\"{error}\");");
103+
115104 tw.Indent--;
105+ tw.WriteLine("}");
106+ tw.WriteLine();
107+ continue;
116108 }
117- }
118109
119- tw.WriteLine();
120- tw.WriteLine($"var decrypted = new AesCipher(key, {modeCode}, pkcs7Padding: false).Decrypt(actual);");
121- tw.WriteLine();
122- tw.WriteLine($"CollectionAssert.AreEqual(input, decrypted);");
110+ tw.WriteLine($"// {openSslCmd} | hd"); // pipe to hexdump
111+ WriteBytes(expected);
112+ tw.WriteLine();
113+ tw.WriteLine($"var actual = new AesCipher(key, {modeCode}, pkcs7Padding: {(pad ? "true" : "false")}).Encrypt(input);");
114+ tw.WriteLine();
115+ tw.WriteLine($"CollectionAssert.AreEqual(expected, actual);");
116+
117+ if (bclMode is not null and not CipherMode.OFB and not CipherMode.CFB)
118+ {
119+ // Verify the OpenSSL result is the same as the .NET BCL, just to be sure
120+ Aes bcl = Aes.Create();
121+ bcl.Key = key;
122+ bcl.IV = iv;
123+ bcl.Mode = bclMode.Value;
124+ bcl.Padding = pad ? PaddingMode.PKCS7 : PaddingMode.None;
125+ bcl.FeedbackSize = 128; // .NET is CFB8 by default, OpenSSL is CFB128
126+ byte[] bclBytes = bcl.CreateEncryptor().TransformFinalBlock(input, 0, input.Length);
127+
128+ if (!bclBytes.AsSpan().SequenceEqual(expected))
129+ {
130+ tw.WriteLine();
131+ tw.WriteLine(@"Assert.Inconclusive(@""OpenSSL does not match the .NET BCL");
132+ tw.Indent++;
133+ tw.WriteLine($@"OpenSSL: {Convert.ToHexString(expected)}");
134+ tw.WriteLine($@"BCL: {Convert.ToHexString(bclBytes)}"");");
135+ tw.Indent--;
136+ }
137+ }
123138
124- tw.Indent--;
125- tw.WriteLine("}");
126- tw.WriteLine();
139+ tw.WriteLine();
140+ tw.WriteLine($"var decrypted = new AesCipher(key, {modeCode}, pkcs7Padding: {(pad ? "true" : "false")}).Decrypt(actual);");
141+ tw.WriteLine();
142+ tw.WriteLine($"CollectionAssert.AreEqual(input, decrypted);");
143+
144+ tw.Indent--;
145+ tw.WriteLine("}");
146+ tw.WriteLine();
147+ }
127148 }
128149 }
129150}
0 commit comments