【问题标题】:TripleDES. Specified padding mode is not valid for this algorithm三重DES。指定的填充模式对此算法无效
【发布时间】:2017-04-07 23:30:15
【问题描述】:

我有一个使用 core1.1 的 net core 应用程序将 cript/decript 模块从旧的 .NET4.6 迁移到 net core 时,它​​无法正常工作

第一个 TripleDES 不再(过去)支持 128 位密钥,并且已使用 192 位密钥进行修复,尝试更改它会导致错误。

其次,在尝试解密这个字符串时:

/Tk0ydguv3HauCVUWDK3Tr6U8c9BBaaRwtSt5q4/uHg=

TripleDES 使用 PKCS7 填充启动错误,显示“指定的填充模式对此算法无效。”这很奇怪,因为 ti 是它默认的填充。

我的项目.json:

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.1.0",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Diagnostics": "1.1.0",
    "Microsoft.AspNetCore.Mvc": "1.0.1",
    "Microsoft.AspNetCore.Razor.Tools": {
      "version": "1.0.0-preview2-final",
      "type": "build"
    },
    "Microsoft.AspNetCore.Routing": "1.0.1",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Logging": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Extensions.Logging.Debug": "1.0.0",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
    "Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
    "Microsoft.EntityFrameworkCore.Design": "1.0.0-preview2-final",
    "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.1",
    "Microsoft.AspNetCore.Mvc.WebApiCompatShim": "1.0.1",
    "Microsoft.AspNetCore.Session": "1.0.0",
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
  },

    "tools": {
        "BundlerMinifier.Core": "2.0.238",
        "Microsoft.EntityFrameworkCore.Tools.DotNet": "1.0.0-preview3-final",
        "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
        "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
    },

  "frameworks": {
    "netcoreapp1.1": {
        "imports": [
            "portable-net461+win8"
        ]
    }
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "**/*.cshtml",
      "appsettings.json",
      "web.config"
    ]
  },

  "scripts": {
    "prepublish": [ "bower install", "dotnet bundle" ],
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

我的代码:

using System;
using System.Security.Cryptography;
using System.Text;
namespace WebApp.Class
{
    public class Md5
    {
        private static readonly byte[] IV = { 240, 3, 45, 29, 0, 76, 173, 59 };

        const int NumCryptokey = 6;
        const int NumExtraClave = 8;
        const int NumsKey = 7;


        public static string Generate(int KeyChars)
        {
            int i_key = 0;
            float Random1 = 0;
            Int16 arrIndex = default(Int16);
            StringBuilder sb = new StringBuilder();
            char RandomLetter;

            string KeyLetters = "abcdefghijklmnopqrstuvwxyz";
            string KeyNumbers = "0123456789";

            char[] LettersArray = null;
            char[] NumbersArray = null;

            LettersArray = KeyLetters.ToCharArray();
            NumbersArray = KeyNumbers.ToCharArray();

            for (i_key = 1; i_key <= KeyChars; i_key++)
            {
                Random random = new Random();
                Random1 = random.Next();

                arrIndex = -1;
                if ((Convert.ToInt32(Random1 * 111)) % 2 == 0)
                {
                    while (arrIndex < 0)
                    {
                        arrIndex = Convert.ToInt16(LettersArray.GetUpperBound(0) * Random1);
                    }
                    RandomLetter = LettersArray[arrIndex];
                    if ((Convert.ToInt32(arrIndex * Random1 * 99)) % 2 != 0)
                    {
                        RandomLetter = LettersArray[arrIndex];
                        RandomLetter = char.ToUpper(RandomLetter);
                    }
                    sb.Append(RandomLetter);
                }
                else
                {
                    while (arrIndex < 0)
                    {
                        arrIndex = Convert.ToInt16(NumbersArray.GetUpperBound(0) * Random1);
                    }
                    sb.Append(NumbersArray[arrIndex]);
                }
            }
            return sb.ToString();
        }

        public static string Encriptar(string serializedQueryString)
        {
            string functionReturnValue = null;
            string sRetorno = null;
            try
            {
                string cryptokey = "";
                string ExtraClave = "";
                string sKey = "";

                cryptokey = Generate(NumCryptokey);
                ExtraClave = Generate(NumExtraClave);
                sKey = Generate(NumsKey);

                byte[] buffer = Encoding.ASCII.GetBytes(serializedQueryString + ExtraClave);
                var des = TripleDES.Create();
                var MD5 = System.Security.Cryptography.MD5.Create();
                des.Key = MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(sKey + cryptokey));
                des.IV = IV;

                sRetorno = cryptokey + ExtraClave + sKey + Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length));

                functionReturnValue = sRetorno;
            }
            catch (Exception ex)
            {
                functionReturnValue = "";
            }
            return functionReturnValue;

        }

        public static string Desencriptar(string encryptedQueryString)
        {
            string functionReturnValue = null;
            byte[] buffer = null;
            var DES = System.Security.Cryptography.TripleDES.Create();
            var Md5 = MD5.Create();
            string sRetorno = null;

            string cryptokey = "";
            string ExtraClave = "";
            string sKey = "";

            cryptokey = encryptedQueryString.Substring(0,NumCryptokey);
            ExtraClave = encryptedQueryString.Substring(NumCryptokey, NumExtraClave);
            sKey = encryptedQueryString.Substring(NumCryptokey + NumExtraClave, NumsKey);

            encryptedQueryString = encryptedQueryString.Substring(NumCryptokey + NumExtraClave + NumsKey, encryptedQueryString.Length-(NumCryptokey + NumExtraClave + NumsKey));

            try
            {
                buffer = Convert.FromBase64String(encryptedQueryString);
            byte[] by = new byte[24];
                by = Md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(sKey + cryptokey));
            Array.Resize(ref by, 24);
                DES.Key = by;
                DES.IV = IV;

                sRetorno = Encoding.ASCII.GetString(DES.CreateDecryptor().TransformFinalBlock(buffer, 0, buffer.Length)).Replace(ExtraClave, "");
                functionReturnValue = sRetorno;
            }
            catch (Exception ex)
            {
                functionReturnValue = "";
            }
            return functionReturnValue;

        }
    }
}

【问题讨论】:

  • 改用 PKCS5 填充。从技术上讲,PKCS#7 是为 128 位密码定义的,而 PKCS#5 是为 64 位密码定义的,如 DES。你的实现可能很挑剔。
  • @rossum:实际上,与 PKCS#5 不同,PKCS#7 对块大小没有任何假设。
  • 好的,谢谢指正。
  • 3DES 有一个 168 位密钥(不使用每个字节的 lsb,这说明密钥是 24 字节。一些(但不是全部)实现将允许 16 字节密钥通过重新使用前 8 个字节作为后 8 个字节。
  • @rossum 请考虑删除不正确的 cmets。

标签: encryption asp.net-core md5 tripledes


【解决方案1】:

找到了!

    public static string Encriptar(string serializedQueryString)
    {
        string functionReturnValue = null;
        string sRetorno = null;
        try
        {
            string cryptokey = "";
            string ExtraClave = "";
            string sKey = "";

            cryptokey = Generate(NumCryptokey);
            ExtraClave = Generate(NumExtraClave);
            sKey = Generate(NumsKey);

            byte[] buffer = Encoding.ASCII.GetBytes(serializedQueryString + ExtraClave);
            var des = TripleDES.Create();
            var Md5 = MD5.Create();

            byte[] by = new byte[24];
            by = Md5.ComputeHash(Encoding.ASCII.GetBytes(sKey + cryptokey));
            Array.Resize(ref by, 24);
            Array.Copy(by, 0, by, 16, 8);
            des.Key = by;
            des.IV = IV;
            //es.Padding = PaddingMode.None;
            sRetorno = cryptokey + ExtraClave + sKey + Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length));

            functionReturnValue = sRetorno;

        }
        catch (Exception ex)
        {
            functionReturnValue = "";
        }
        return functionReturnValue;
    }

【讨论】:

    【解决方案2】:

    我在 ASP.NET Core 中遇到了同样的问题。但是,我没有指定任何 IV。

    我刚刚在指定密钥后加密和解密时添加了这一行。

    DES3.IV = new byte[DES3.BlockSize / 8];
    

    如果没有这一行,我会收到上述错误。

    根据https://msdn.microsoft.com/en-us/library/system.security.cryptography.symmetricalgorithm.iv(v=vs.110).aspx 的文档

    IV 属性会自动设置为一个新的随机值 您创建 SymmetricAlgorithm 类之一的新实例或 当您手动调用 GenerateIV 方法时。

    但是,我仍然不明白为什么这会奏效,因为即使我尝试为 IV 提供静态值(就像你的问题一样)并且即使在那时它也失败了。

    【讨论】:

    • 使用随机IV,只需在加密数据前加上IV用于解密即可,不需要不保密。否则相同的消息或具有相同开头的消息将具有相同的加密数据并且信息将被泄露。还解释了为什么这样做会使答案更有用。
    • @zaph 我曾尝试使用静态 IV,但它失败了。我仍然不知道为什么会这样!!
    • 如果使用自动生成的随机IV,则必须将其检索并用于后续解密。处理 IV 的一种方法是在加密数据前加上 IV 以用于解密,它不需要不保密。
    • 不接受使用不懂的方法。在这种情况下,使用固定 IV 可以修复一个错误,但会产生另一个错误:加密不安全。
    猜你喜欢
    • 1970-01-01
    • 2018-03-13
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多