Search code examples
c#encryptionconsole-applicationaescbc-mode

C# AES decrypted output is not the same as input


I wanted to do a simple message encrypter to dip my toes into the matter but I can't make it to work. The problem is that whatever input I start with, sometimes it encrypts it but when I try to decrypt it, it just doesn't return the original string. It would be really helpful if you could tell me what I'm doing wrong or guide in the right direction.

Complete code

This are the sections in charge of encrypting and decrypting.

void Decrypt()
{
    using var crypt = Aes.Create();


    string[] input = ClipboardService.GetText()?.Split(SEPARATOR) ?? Array.Empty<string>();
    byte[] key = input[0].ToBytes();
    byte[] IV = input[^1].ToBytes();
    byte[] value = string.Join(string.Empty, input[1..^1]).ToBytes();
    
    crypt.IV = IV;
    crypt.Key = key;
    var decryptedValue = crypt.DecryptCbc(value, IV, PaddingMode.Zeros);
    string decryptedValueInText = decryptedValue.ToUnicodeString();


    ClipboardService.SetText(decryptedValueInText);
    LogInfoMessage($"{decryptedValueInText}: {decryptedValue.Length}");
    crypt.Clear();
}


void Encrypt()
{
    using var crypt = Aes.Create();
    crypt.GenerateKey();


    string value = ClipboardService.GetText() ?? string.Empty;
    var encryptedValue = crypt.EncryptCbc(value.ToBytes(), crypt.IV, PaddingMode.Zeros);
    string encryptedValueInText = $"{crypt.Key.ToUnicodeString()}{SEPARATOR}{encryptedValue.ToUnicodeString()}{SEPARATOR}{crypt.IV.ToUnicodeString()}";


    ClipboardService.SetText(encryptedValueInText);
    LogInfoMessage($"{encryptedValueInText}: {encryptedValue.Length}");
    crypt.Clear();
}

There are two extension methods:

    public static string ToUnicodeString(this byte[] bytes) => Encoding.Unicode.GetString(bytes);
    public static byte[] ToBytes(this string str) => Encoding.Unicode.GetBytes(str);

Example The input links were:

https://www.youtube.com/

https://www.youtube.com/watch?v=bSA91XTzeuA

I don't think it matters because the key and IV are autogenerated everytime anyways but still. Example image


Solution

  • Per our discussion...

    Using the clipboard to store binary data as Unicode text will fail due to invalid UTF-16 codepoints. UTF-16 uses some multi-word encoding for certain Unicode characters, using 32 bits in surrogate pairs to encode Unicode code points from the supplementary planes. There are plenty of primers on the UTF-16 encoding, but basically you have a pair of 16-bit values where the first is in the range 0xD800-0xDBFF and the second must be in the range 0xDC00-0xDFFF. Odds on your encrypted data will break this rule.

    As noted, if your encrypted binary data must be sent through a text-only transport you should encode the bytes in the encrypted block using Base64 or similar.

    I'd also like to stress that writing methods that can be called with parameters rather than directly accessing the clipboard for I/O makes it much simpler to do testing, including round-trip tests on the various parts of the problem. Proving that the codec is working without reference to the clipboard is a good test and separation of concerns helps to more readily identify the source of problems in the future.