Note that there are some explanatory texts on larger screens.

plurals
  1. POC# & OpenSSL: Differing Output for AES Encryption
    primarykey
    data
    text
    <p>I'm attempting to write a C# method that will spit out the same encrypted string (Base64) as the openssl binary does, but am having a heck of a time getting things to match up. </p> <p>Lots of terminal-output and C# to follow... :P</p> <p>We're going to use the very exciting example of encrypting the string "a" with the password "123".</p> <p><strong>First</strong> is openssl when I provide my static salt and a password (this is how the command will be ideally run, and is what I want my C# output to match to):</p> <pre><code>dev@magoo ~# echo -n a | openssl enc -aes-128-cbc -S cc77e2a591358a1c -pass pass:123 -a -p salt=CC77E2A591358A1C key=7B2AD689138A44AD32297BBAAA5B0EEE iv =EC4F0416B2E9A9B2FEEF2E66FF982159 U2FsdGVkX1/Md+KlkTWKHOtnt1ftHSKyWiz6GxkBVck= </code></pre> <p><strong>Second</strong> is openssl when I provide my static salt, and the key and iv that are derived from that salt (C+P'd from the output of the first command) but no password (since even the docs say that would be a not-good idea):</p> <pre><code>dev@magoo ~# echo -n a | openssl enc -aes-128-cbc -S cc77e2a591358a1c -K 7b2ad689138a44ad32297bbaaa5b0eee -iv ec4f0416b2e9a9b2feef2e66ff982159 -a -p salt=E85778B7FFFFFFFF key=7B2AD689138A44AD32297BBAAA5B0EEE iv =EC4F0416B2E9A9B2FEEF2E66FF982159 62e3V+0dIrJaLPobGQFVyQ== </code></pre> <p>This strikes me as odd. Adding the key and iv values from the "debug" output (-p param) in the first command to the same salt, I somehow get a different salt! (CC77E2A591358A1C vs E85778B7FFFFFFFF [the 4 bytes of 0xff here seem interesting maybe]).</p> <p><strong>Third</strong> is the output of my application:</p> <pre><code>dev@magoo ~# mono aestest.exe "a" "123" ==&gt; INPUT : a ==&gt; SECRET : 123 ==&gt; SALT : cc77e2a591358a1c ==&gt; KEY : 7b2ad689138a44ad32297bbaaa5b0eee ==&gt; IV : ec4f0416b2e9a9b2feef2e66ff982159 ==&gt; ENCRYPTED : 62e3V+0dIrJaLPobGQFVyQ== </code></pre> <p>So, the C# matches the output of the openssl command when I manually specified the key and IV myself (that then somehow generated a different salt), but that seems wrong somehow. In my mind the C# application's output should match to the first set of OpenSSL's output, shouldn't it?</p> <p>C# code:</p> <pre class="lang-cs prettyprint-override"><code>public static string EncryptString(string plainText, string password) { byte[] salt = Encryption.GetStaticSalt(); byte[] key, iv; Encryption.DeriveKeyAndIV(password, salt, out key, out iv); var amAes = new AesManaged(); amAes.Mode = CipherMode.CBC; amAes.KeySize = 128; amAes.BlockSize = 128; amAes.Key = key; amAes.IV = iv; var icTransformer = amAes.CreateEncryptor(); var msTemp = new MemoryStream(); var csEncrypt = new CryptoStream(msTemp, icTransformer, CryptoStreamMode.Write); var sw = new StreamWriter(csEncrypt); sw.Write(plainText); sw.Close(); sw.Dispose(); csEncrypt.Clear(); csEncrypt.Dispose(); byte[] bResult = msTemp.ToArray(); string sResult = Convert.ToBase64String(bResult); if (System.Diagnostics.Debugger.IsAttached) { string debugDetails = ""; debugDetails += "==&gt; INPUT : " + plainText + Environment.NewLine; debugDetails += "==&gt; SECRET : " + password + Environment.NewLine; debugDetails += "==&gt; SALT : " + Encryption.ByteArrayToHexString(salt) + Environment.NewLine; debugDetails += "==&gt; KEY : " + Encryption.ByteArrayToHexString(amAes.Key) + " (" + amAes.KeySize.ToString() + ")" + Environment.NewLine; debugDetails += "==&gt; IV : " + Encryption.ByteArrayToHexString(amAes.IV) + Environment.NewLine; debugDetails += "==&gt; ENCRYPTED : " + sResult; Console.WriteLine(debugDetails); } return sResult; } private static string ByteArrayToHexString(byte[] bytes) { StringBuilder sbHex = new StringBuilder(); foreach (byte b in bytes) sbHex.AppendFormat("{0:x2}", b); return sbHex.ToString(); } public static byte[] GetStaticSalt() { // Just random bytes. return new byte[] { 0xcc, 0x77, 0xe2, 0xa5, 0x91, 0x35, 0x8a, 0x1c }; } // largely hijacked from http://stackoverflow.com/a/8011654/97423 public static void DeriveKeyAndIV(string password, byte[] bSalt, out byte[] bKey, out byte[] bIV) { int keyLen = 16; int ivLen = 16; byte[] bPassword = Encoding.UTF8.GetBytes(password); using (var md5Gen = MD5.Create()) { List&lt;byte&gt; lstHashes = new List&lt;byte&gt;(keyLen + ivLen); byte[] currHash = new byte[0]; int preHashLength = bPassword.Length + bSalt.Length; byte[] preHash = new byte[preHashLength]; Buffer.BlockCopy(bPassword, 0, preHash, 0, bPassword.Length); Buffer.BlockCopy(bSalt, 0, preHash, bPassword.Length, bSalt.Length); currHash = md5Gen.ComputeHash(preHash); lstHashes.AddRange(currHash); while (lstHashes.Count &lt; (keyLen + ivLen)) { preHashLength = currHash.Length + password.Length + bSalt.Length; preHash = new byte[preHashLength]; Buffer.BlockCopy(currHash, 0, preHash, 0, currHash.Length); Buffer.BlockCopy(bPassword, 0, preHash, currHash.Length, password.Length); Buffer.BlockCopy(bSalt, 0, preHash, currHash.Length + password.Length, bSalt.Length); currHash = md5Gen.ComputeHash(preHash); lstHashes.AddRange(currHash); } bKey = new byte[keyLen]; bIV = new byte[ivLen]; lstHashes.CopyTo(0, bKey, 0, keyLen); lstHashes.CopyTo(keyLen, bIV, 0, ivLen); } } </code></pre> <p>Am I missing something really obvious here, or is this something more subtle? I've looked around SO and have seen a lot about C#, OpenSSL and AES, but nothing about this specific issue... so, halp? ;)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload