【问题标题】:TripleDES Length of the data to encrypt is invalidTripleDES 要加密的数据长度无效
【发布时间】:2017-12-11 10:02:16
【问题描述】:

我有以下代码:

public static string Encrypt3Des(string cipherString)
{
    string result = "";

    byte[] keyArray;
    byte[] ivArray;

    byte[] toEncryptArray = Enc3DesPerChar(cipherString);
    //string toEncryptString = ByteArrayToString(toEncryptArray);

    // Get the key from config file
    System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
    string key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
    string iv = (string)settingsReader.GetValue("InitializationVector", typeof(String));

    keyArray = StringToByteArray(key);
    ivArray = StringToByteArray(iv);

    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
    //set the secret key for the tripleDES algorithm

    tdes.Key = keyArray;
    tdes.IV = ivArray;

    //ChiperMode
    tdes.Mode = CipherMode.CBC;

    //PaddingMode(if any extra byte added)
    tdes.Padding = PaddingMode.None;

    ICryptoTransform cTransform = tdes.CreateEncryptor();
    //transform the specified region of bytes array to resultArray
    byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

    //Release resources held by TripleDes Encryptor
    tdes.Clear();

    result = ByteArrayToString(resultArray);

    return result;
}

这是我的方法:

protected static string ByteArrayToString(byte[] ba)
{
    StringBuilder hex = new StringBuilder(ba.Length * 2);
    foreach (byte b in ba)
        hex.AppendFormat("{0:x2}", b);
    return hex.ToString();
}

protected static byte[] StringToByteArray(String hex)
{
    int NumberChars = hex.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    return bytes;
}

protected static byte[] Enc3DesPerChar(String toEncrypt)
{
    string toAsciiString = ByteArrayToString(Encoding.ASCII.GetBytes(toEncrypt));

    string toRoll = toAsciiString;

    int NumberChars = toRoll.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(toRoll.Substring(i, 2), 16);
    }
    return bytes;
}

上述方法一切正常,直到我发现该方法不能接受少于 8 个字符。

引发错误的代码块:

byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

错误信息:

要加密的数据长度无效。

示例输入:

Encrypt3Des("14022000"); // return encrypt because 8 character or more

Encrypt3Des("1402200"); // return error because 7 character

有人知道为什么会这样或者我该如何解决吗? (我不知道它是否来自我的加密方法,但我知道一个 Web 应用程序使用完全相同的东西来加密字符串并且它确实有效。)

编辑: 我用于手动加密的工具:3des

选项必须:

  • 文本输入类型
  • 纯文本输入文本
  • 3DES 函数
  • CBC 模式
  • 固定键十六进制
  • 固定初始向量

【问题讨论】:

  • 您必须在此模式 (CBC) 下为此密码使用填充。
  • 3DES是分组密码,在CB​​C模式下它只能加密8字节的倍数,如果你想用它来加密长度不是8字节的倍数的数据,那么您必须使用填充,但需要注意的是,您的加密数据可能比您的输入数据长最多 8 个字节。
  • 不要在新工作中使用 3DES,它不如 AES 安全,并且只有 112 位安全性和三重密钥,而是使用 AES(高级加密标准)它支持 128,192 和 256 位的密钥大小。
  • 你把你的字符串变成字节(好)把它变成十六进制(嗯?)再把它变成字节(?!)。那里的第二步和第三步可以被删除。但随后您尝试一次对一个角色执行 3DES。这真是太奇怪了。您想要 PKCS7 填充并将整个字节数组扔到TransformFinalBlock。它会变成 ((inputBytes.Length + 15) / 8) * 8)` 字节。 (0 -> 8, 7 -> 8, 8 -> 16, 15 -> 16, 16 -> 24, 等等)
  • 这是我用于手动加密的工具 link ,该应用程序没有显示任何 Padding 选项,我的客户端使用此工具使用 PHP CI 语言进行加密。那么我应该如何修改我的代码并且结果可以与工具相同?选项必须是Plain Input Text、3des function、CBC mode、fixed Hex Key、fixed IV。

标签: c# encryption 3des tripledes


【解决方案1】:

您正在使用填充作为无。将填充模式设置为PKCS7。

【讨论】:

  • 如果我对 PKCS7 使用填充模式,结果总是会比我预期的更多返回给我的加密字符串。
  • 是的,加密后的数据最多会多出一个块,对于 DES/3DES 是 8 个字节。
【解决方案2】:

好的,我想刚刚找到了解决方案(我的客户告诉我如何),我需要在循环之前用 null 填充字符。 null 可以用“00”转换为ASCII。所以我决定用 '0' 到 16 个字符对 ascii 结果进行 PadRight,所以我的一种方法变成了:

protected static byte[] Enc3DesPerChar(String toEncrypt)
{
    string toAsciiString = ByteArrayToString(Encoding.ASCII.GetBytes(toEncrypt));

    string toRoll = toAsciiString.PadRight(16,'0');

    int NumberChars = toRoll.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(toRoll.Substring(i, 2), 16);
    }
    return bytes;
}

【讨论】:

  • 使用空填充是个坏主意。
  • 如果你想使用这个填充,只需将 PaddingMode 更改为 Zeros 会更容易。但是零填充不能被解密器删除,由接收者来理解尾随的零是否是语义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-05
  • 2020-12-19
相关资源
最近更新 更多