Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AES265 Python to C# conversion failed

I'm trying to convert few lines Python code into C# code. I'm facing an error where I don't know which line cuases that error. I have no idea about Python at all. I think I have made mistake of slicing sub array or decryption process then I rewrite with different ways such as Buffer.BlockCopy but no luck.

Python source

#Example grabbing JPEG instead of MP4
mediaurl = "url"
mediakey="UdoT3mfVvt3kMp0+MAybMlgVrnEyVAdxSamXQ+qbRog="
salt = "WhatsApp Image Keys"

mediaKeyExpanded = HKDF(base64.b64decode(mediakey),112,salt)
iv = mediaKeyExpanded[:16]
cipherKey = mediaKeyExpanded[16:48]
macKey = mediaKeyExpanded[48:80]

mediaData = urllib2.urlopen(mediaurl).read()
file = mediaData[:-10]
mac = mediaData[-10:]


decryptor = AES.new(cipherKey, AES.MODE_CBC, iv)
imgdata=AESUnpad(decryptor.decrypt(file))

with open('rob.jpg', 'wb') as f:
    f.write(imgdata)

print("file written to rob.jpg")

C# code Hkdf

var hkdf = new Hkdf(System.Security.Cryptography.HashAlgorithmName.SHA256);

var mediakey = Convert.FromBase64String("UdoT3mfVvt3kMp0+MAybMlgVrnEyVAdxSamXQ+qbRog=");
var salt = Encoding.UTF8.GetBytes("WhatsApp Image Keys");

var mediaKeyExpanded = hkdf.Expand(mediakey, 112, salt); //HKDF(base64.b64decode(mediakey), 112, salt)
var length = mediaKeyExpanded.Length;

var iv = mediaKeyExpanded.Skip(0).Take(16).ToArray(); //mediaKeyExpanded[:16]
var cipherKey = mediaKeyExpanded.Skip(16).Take(32).ToArray(); //mediaKeyExpanded[16:48]
var macKey = mediaKeyExpanded.Skip(48).Take(32).ToArray(); //mediaKeyExpanded[48:80]

var mediaData = File.ReadAllBytes("file.enc");
    length = mediaData.Length;
var fileLength = length - 10;
var file = mediaData.Take(fileLength).ToArray(); //mediaData[:-10]
var mac = mediaData.Skip(fileLength).Take(10).ToArray();//mediaData[-10:]

//decryptor = AES.new(cipherKey, AES.MODE_CBC, iv)
//imgdata = AESUnpad(decryptor.decrypt(file))

using (var rijndaelManaged = new RijndaelManaged { 
    Key = cipherKey, IV = iv, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128
})
{
    rijndaelManaged.Padding = PaddingMode.Zeros;
    using (var memoryStream = new MemoryStream(file))
    using (var cryptoStream = new CryptoStream(memoryStream, rijndaelManaged.CreateDecryptor(cipherKey, iv), CryptoStreamMode.Read))
    using (var fsOut = new FileStream(@"C:\Users\Name\Desktop\file_decrypted.jpg", FileMode.Create))
    {
        int data;
        while ((data = cryptoStream.ReadByte()) != -1)
            fsOut.WriteByte((byte)data);
    }
}

This is the file I'm trying to decrypt.

Edit: The image file is successfully created but cannot be open by any image viewer due to bad or unsupported format.

like image 774
derodevil Avatar asked Oct 30 '25 15:10

derodevil


1 Answers

As already noted by Artjom B., there is a bug in the C# code when determining the MAC, which is meanwhile fixed in the posted code.

The explicit setting of the key size to 256 bits or the block size to 128 bits, however, makes no difference, since these values are used by RijndaelManaged by default. This corresponds to AES, so it could also be applied e.g. AesManaged.

Apart from the bug in the MAC determination, there are two more bugs in the C# code:

  • The counterpart to HKDF() from the Python code for the C# code is:

    var mediaKeyExtracted = hkdf.Extract(mediakey, null);        
    var mediaKeyExpanded = hkdf.Expand(mediaKeyExtracted, 112, salt); 
    

    This returns a value for mediaKeyExpanded that corresponds to the one determined in the Python code, that is (hex encoded):

    a02b98bd6ce9575c95cc938e39bb782ba5d6478c98c0e356ea7ee70b4900f3861db9528cd4490ca02789410b3c3aba4489ebcce2c153a015f213a331d147ba515450edd55f8ff03d8fce4760825351f16b2a23d371e30846c0492e259cabb263d63bc6e098280002cb125fc807a03a2b
    

    which gives the following values

      iv:        a02b98bd6ce9575c95cc938e39bb782b
      cipherKey: a5d6478c98c0e356ea7ee70b4900f3861db9528cd4490ca02789410b3c3aba44
      macKey:    89ebcce2c153a015f213a331d147ba515450edd55f8ff03d8fce4760825351f1
    

    Note that the variable called salt is actually not the salt but the info parameter (see RFC 5869, section 2).

  • From the Python code, i.e. the functions AESUnpad() and AESPad() it can be determined that the Python code uses PKCS7 padding. Therefore instead of Zero padding, PKCS7 padding must be applied in the C# code, otherwise the PKCS7 padding from the encryption will not be removed:

    rijndaelManaged.Padding = PaddingMode.PKCS7;
    

    Note that PKCS7 does not actually need to be specified explicitly as it is the default. But then you have to remove the line that explicitly specifies Zero padding.

With these changes the linked file can be decrypted using the mediaKey UdoT3mfVvt3kMp0+MAybMlgVrnEyVAdxSamXQ+qbRog= and the appInfo WhatsApp Image Keys with the C# code (see also here). The decrypted file is identical in content to the file decrypted with the Python code.


By the way: With the variables file, iv, macKey and mac from the C# code, the file can be validated according to the instructions (see here) as follows:

HMACSHA256 hmac = new HMACSHA256(macKey);

byte[] ivFile = new byte[iv.Length + file.Length];
Array.Copy(iv, 0, ivFile, 0, iv.Length);
Array.Copy(file, 0, ivFile, iv.Length, file.Length);

byte[] macCalc = hmac.ComputeHash(ivFile);

byte[] macCalc10 = new byte[10];
Array.Copy(macCalc, 0, macCalc10, 0, 10);

bool verified =  macCalc10.SequenceEqual(mac);

Since the file to be verified and the data from which the keys (cipherKey, macKey) and the IV are generated are downloaded from the same place (as a rar file, see here) this is rather a low protection.

like image 132
Topaco Avatar answered Nov 01 '25 05:11

Topaco



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!