代码无法解密时如何防止异常?

时间:2016-04-27 17:14:35

标签: c# encryption aes

我有一个服务正在调用的公共Web挂钩,以便发送我的网站通知。在这个Web钩子中,我期待一个加密的令牌。当我获得令牌时,我使用预定义的密钥对其进行解密,并检查令牌是否是我期望的。这很好。

当未加密或坏的令牌传递到函数中时,解密当然会失败。这没关系,但是当发生这种情况时我不希望生成异常。如果某个黑客在一秒内对我的Web挂钩创建了1,000,000个错误请求,并且每个请求需要1秒来处理一个巨大的异常,它将使我的服务器崩溃。

到目前为止,这是我的解密代码:

public static string Decrypt(string cipherText, string key)
    {
        string EncryptionKey = key;
        cipherText = cipherText.Replace(" ", "+");

        //I added this to prevent exception when trying to Convert.FromBase64String()
        if (cipherText.Length % 4 != 0)
        {
            //cipherText must be a length that is a multiple of 4, otherwise it will fail
            return null;
        }

        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();  //currently giving exception HERE
                }
                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }
        return cipherText;
    }

当我故意传入一个非加密字符串时,它在cs.Close()The input data is not a complete block给了我一个例外。我不确定这里究竟检查了什么,所以我不知道如何防止它。

如何重构此代码,以便在无法解密字符串时,它不会引发异常?

2 个答案:

答案 0 :(得分:3)

您可以catch例外,并根据需要进行操作。 (记录,重新路由,忽略等)。可在此处找到Try / catch文档:https://msdn.microsoft.com/en-us/library/0yd65esw.aspx

答案 1 :(得分:0)

当您使用像CBC这样的非身份验证模式解密密文时,填充错误可以检测到错误的密钥或错误的最终块,概率大约是256次的255次。当最后一个块损坏并且找不到有效的填充时会发生这种情况。 <{3}}默认使用,它有一个可以验证的特殊结构。

您可以请求解密者不要以任何方式尝试取消填充:

encryptor.Padding = PaddingMode.None;

但是你需要自己解压缩(对于AES,填充字节只能在1到16的范围内):

var ctBytes = ms.ToArray();
var last = ctBytes[ctBytes.Length-1];
if (last < 17 && last > 0) {
    cipherText = Encoding.Unicode.GetString(ctBytes.Take(ctBytes.Length - last));
} else {
    ciphertext = null;
}