联博统计:探讨NET Core数据举行3DES加密或解密弱密钥问题

admin 3个月前 (07-05) 科技 45 0

前言

之前写过一篇《探讨.NET Core数据举行3DES加密和解密问题》,最近看到有人提出弱密钥问题,换个强密钥不就完了吗,预测可能是与第三方对接导致很无奈不能替换密钥,以是发生本文解决.NET Core中3DES弱密钥问题,写下本文,希望对碰到此问题的童鞋有所辅助。

3DES加密或解密弱密钥

在基于.NET Framework中,我们可以使用反射获取到TripledESCryptoServiceProvider的“_NewEncryptor”私有方式,从而规避判断弱秘钥问题,但在.NET Core中没有这个方式,我们首先来看看问题的发生,如下为.NET Core中加密和解密的方式实现

public static string DesEncrypt(string input, string key)
{
    byte[] inputArray = Encoding.UTF8.GetBytes(input);
    var tripleDES = TripleDES.Create();
    var byteKey = Encoding.UTF8.GetBytes(key);
    byte[] allKey = new byte[24];
    Buffer.BlockCopy(byteKey, 0, allKey, 0, 16);
    Buffer.BlockCopy(byteKey, 0, allKey, 16, 8);
    tripleDES.Key = allKey;
    tripleDES.Mode = CipherMode.ECB;
    tripleDES.Padding = PaddingMode.PKCS7;
    ICryptoTransform cTransform = tripleDES.CreateEncryptor();
    byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
    return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

public static string DesDecrypt(string input, string key)
{
    byte[] inputArray = Convert.FromBase64String(input);
    var tripleDES = TripleDES.Create();
    var byteKey = Encoding.UTF8.GetBytes(key);
    byte[] allKey = new byte[24];
    Buffer.BlockCopy(byteKey, 0, allKey, 0, 16);
    Buffer.BlockCopy(byteKey, 0, allKey, 16, 8);
    tripleDES.Key = byteKey;
    tripleDES.Mode = CipherMode.ECB;
    tripleDES.Padding = PaddingMode.PKCS7;
    ICryptoTransform cTransform = tripleDES.CreateDecryptor();
    byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
    return Encoding.UTF8.GetString(resultArray);
}

接下来我们挪用上述加密方式对数据举行加密,固然这里的密钥很简单为16位1,NET Framework中对弱密钥的详细判断逻辑这里不做深入分析,如下:

var desEncryptData = DesEncrypt("Jeffcky", "1111111111111111");

为解决这个问题我们下载BouncyCastle.NetCore包(https://github.com/chrIShaly/bc-csharp),此包有针对基本所有加密算法实现,你会发现通过该包实现和Java中加密算法实现异常相似,若与第三方Java对接,对方所传数据可能行使.NET Core无法解密或通过加密导致对方无法解密,由于无论是C#照样Java对于算法的实现照样有所差异,行使此包可以举行互作。

在C#中3DES名称界说为TripleDES,而在Java中名称则是DESede,同时C#中的填充模式PKCS7对应Java中的PKCS5Padding,接下来你将看到如下C#代码险些就是从Java中翻译过来,如下:

static IBuffereDCipher CreateCipher(bool forEncryption, string key,
            string cipMode = "DESede/ECB/PKCS5Padding")
{
    var algorithmName = cipMode;
    if (cipMode.IndEXOf('/') >= 0)
    {
        algorithmName = cipMode.Substring(0, cipMode.IndexOf('/'));
    }

    var cipher = CipherUtilities.GetCipher(cipMode);

    var keyBytes = Encoding.UTF8.GetBytes(key);

    var keyParameter = ParameterUtilities.CreateKeyParameter(algorithmName, keyBytes);

    cipher.Init(forEncryption, keyParameter);

    return cipher;
}

如上主要是建立加密算法接口(默以为3DES),若forEncryption为true示意加密,否则解密,详细细节这里就不再详细注释,有兴趣的童鞋可自行研究。接下来我们实现加密和解密方式:

static string EncryptData(string input, string key)
{
    var inCipher = CreateCipher(true, key);

    var inputArray = Encoding.UTF8.GetBytes(input);

    byte[] cipherData = inCipher.DoFinal(inputArray);

    return Convert.ToBase64String(cipherData);
}

static string DecryptData(string input, string key)
{
    var inputArrary = Convert.FromBase64String(input);

    var outCipher = CreateCipher(false, key);

    var encryptedDataStream = new MemoryStream(inputArrary, false);

    var dataStream = new MemoryStream();

    var outCipherStream = new CipherStream(dataStream, null, outCipher);

    int ch;
    while ((ch = encryptedDataStream.ReadByte()) >= 0)
    {
        outCipherStream.WriteByte((byte)ch);
    }

    outCipherStream.Close();
    encryptedDataStream.Close();

    var dataBytes = dataStream.ToArray();

    return Encoding.UTF8.GetString(dataBytes);
}

虽然密钥是16位,但在内置详细实现时也会如.NET Core中一样填充到24位,接下来我们再来挪用上述加密和解密方式,看看数据加密和解密是否准确

var data = EncryptData("Jeffcky", "1111111111111111");

var decryptData = DecryptData(data, "1111111111111111");

那么问题来了,为何在C#中会抛出弱密钥异常,但是在这个包中却没能抛出异常呢?内置是基于Schneier pp281的弱和半弱键表举行查找可能与C#实现逻辑有所不同(小我私家预测),如下:

public const int DesKeyLength = 8;

prIVate const int N_DES_WEAK_KEYS = 16;

//基于Schneier pp281的弱和半弱键表
private static readonly byte[] DES_weak_keys =
{
    /* 弱键 */
    (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,
    (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e,
    (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1,
    (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe,

    /* 半弱键 */
    (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe,
    (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1,
    (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1,
    (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe,
    (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e,
    (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe,
    (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01,
    (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e,
    (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01,
    (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e,
    (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01,
    (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1
};


public static bool IsWeakKey(byte[]    key, int offset)
{
    if (key.Length - offset < DesKeyLength)
        throw new ArgumentException("key material too short.");

    //nextkey:
    for (int i = 0; i < N_DES_WEAK_KEYS; i++)
    {
        bool unmatch = false;
        for (int j = 0; j < DesKeyLength; j++)
        {
            if (key[j + offset] != DES_weak_keys[i * DesKeyLength + j])
            {
                //continue nextkey;
                unmatch = true;
                break;
            }
        }

        if (!unmatch)
        {
            return true;
        }
    }

    return false;
}

若是第三方为Java,当行使.NET Core着实走投无路无法举行解密时,那就使用上述提供的解密方式举行解密,理论上都可以解密,不能解密的情形大泛起于对C#和Java实现原理不领会导致,如下:

&NBsp;

总结

本文重点在于解决.NET Core中3DES弱密钥问题,同时和第三方对接时着实懒得去明白各语言实现加密算法原理,可实验接纳上述包来举行互操作,看到有几位童鞋在文章下提出这个问题而苦于没找到解决方案,这里提供一种可选择的方案,都已封装好,拿去用吧。

,

欧博亚洲网址

欢迎进入欧博亚洲网址(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

Sunbet声明:该文看法仅代表作者自己,与本平台无关。转载请注明:联博统计:探讨NET Core数据举行3DES加密或解密弱密钥问题

网友评论

  • (*)

最新评论

站点信息

  • 文章总数:621
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1120
  • 评论总数:255
  • 浏览总数:6874