Symmetric Encryption cyclic redundancy check

0

I need to encrypt some data before writing to the DB and decrypt on reading from the DB.

I've used the code available in this guide here: Encrypting and Decrypting data in an Universal Windows App

When ever I try to decrypt I get the error:

Data error (cyclic redundancy check). (Exception from HRESULT: 0x80070017)

I thought it was because the key was different as I instantiated the SymmetricEncryptionHelper object once for encrypt then again for decrypt. To combat this I changed the class to be a singleton but I still get the same error:

public class SymmetricEncryptionHelper
{
    private readonly IBuffer randomBuffer;
    private readonly IBuffer randomBufferCBC;
    private readonly CryptographicKey cryptographicKey;
    private readonly string algorithmName;
    private readonly SymmetricKeyAlgorithmProvider cryptingProvider;

    private static SymmetricEncryptionHelper _instance;

    public static SymmetricEncryptionHelper Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new SymmetricEncryptionHelper();
            }
            return _instance;
        }
    }


    /// <summary>
    /// Instantiate with a random generated buffer (not an option if
    /// you want to persist the encryption to disk)
    /// </summary>
    private SymmetricEncryptionHelper()
    {
        algorithmName = SymmetricAlgorithmNames.AesEcbPkcs7;
        cryptingProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);
        randomBuffer = CryptographicBuffer.GenerateRandom(cryptingProvider.BlockLength);
        randomBufferCBC = null;
        cryptographicKey = cryptingProvider.CreateSymmetricKey(randomBuffer);
    }

    /// <summary>
    /// Instantiate with a custom generated buffer (good for
    /// persisting the encryption to disk)
    /// </summary>
    /// <param name="randomBuffer">The custom generated buffer</param>
    private SymmetricEncryptionHelper(IBuffer randomBuffer)
        : this()
    {
        this.randomBuffer = randomBuffer;
        cryptographicKey = cryptingProvider.CreateSymmetricKey(randomBuffer);
    }
    /// <summary>
    /// Instantiate with a custom generated buffer (good for
    /// persisting the encryption to disk) and with a custom
    /// generated CBC buffer (is using CBC algorithms)
    /// </summary>
    /// <param name="randomBuffer">The custom generated buffer</param>
    /// <param name="randomBufferCBC">The custom generated CBC buffer</param>
    private SymmetricEncryptionHelper(IBuffer randomBuffer, IBuffer randomBufferCBC)
        : this(randomBuffer)
    {
        this.randomBufferCBC = randomBufferCBC;
    }

    private bool IsMultipleOfBlockLength(IBuffer binaryData)
    {
        return (binaryData.Length % cryptingProvider.BlockLength) != 0;
    }
    /// <summary>
    /// Encrypts a given string
    /// </summary>
    /// <param name="data">Data to be encrypted</param>
    /// <returns>An encrypted string in Unicode</returns>
    public string Encrypt(string data)
    {
        if (string.IsNullOrEmpty(data))
        {
            return data;
        }

        var binaryData = Encoding.Unicode.GetBytes(data).AsBuffer();
        if (!algorithmName.Contains("PKCS7") && IsMultipleOfBlockLength(binaryData))
            throw new Exception("Message buffer length must be multiple of block length !!");
        var encryptedBinaryData = CryptographicEngine.Encrypt(cryptographicKey, binaryData, randomBufferCBC);
        return Encoding.Unicode.GetString(encryptedBinaryData.ToArray());
    }
    /// <summary>
    /// Decrypts a string in Unicode
    /// </summary>
    /// <param name="encryptedData">An encrypted string in Unicode</param>
    /// <returns>The decrypted string in Unicode</returns>
    public string Decrypt(string encryptedData)
    {
        if (string.IsNullOrEmpty(encryptedData))
        {
            return encryptedData;
        }

        try
        {
            var encryptedBinaryData = Encoding.Unicode.GetBytes(encryptedData).AsBuffer();
            var decryptedData = CryptographicEngine.Decrypt(cryptographicKey, encryptedBinaryData, randomBufferCBC);
            return Encoding.Unicode.GetString(decryptedData.ToArray());
        }
        catch (Exception ex)
        {
            return null;
        }
    }

}

Can anyone see where I'm going wrong - I've googled the error but can't seem to find an answer that works for me.

Additionally - once the app is closed I'm going to lose the key, so what's the best practice here? Should I save the key in the PasswordVault?

c#
encryption
uwp
windows-10-mobile
asked on Stack Overflow Jun 3, 2017 by Percy • edited Jun 3, 2017 by Percy

1 Answer

3

Don't trust random code on the internet, period. You need to know what you're doing. ECB mode encryption is insecure for textual messages - and most other cryptographic operations really.

Your problem is directly relying on the decoding of the ciphertext generated within the encryption method (using Encoding.Unicode.GetString, the bad Microsoft name of UTF-16LE). Now a ciphertext always contains of random bytes. And pairs of these bytes don't always constitute a valid UTF-16LE encoded character. So usually those are left out from the stringyfied ciphertext or they are replaced by a substitute character.

Obviously if substitute characters have been introduced then that particular block of ciphertext will be decrypted into a block of random data, making your CRC check fail.


If you need to show the ciphertext as text for some reason then base64 encode it.

answered on Stack Overflow Jun 3, 2017 by Maarten Bodewes

User contributions licensed under CC BY-SA 3.0