博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
探讨NET Core数据进行3DES加密或解密弱密钥问题
阅读量:4033 次
发布时间:2019-05-24

本文共 6203 字,大约阅读时间需要 20 分钟。

【导读】之前写过一篇《探讨.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包,此包有针对基本所有加密算法实现,你会发现通过该包实现和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实现原理不了解导致,如下:

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

转载地址:http://dnzdi.baihongyu.com/

你可能感兴趣的文章
Android之AsyncTask的使用
查看>>
Android之WebView
查看>>
IMSI与IMEI的区别
查看>>
Android SDK代理资源收集
查看>>
收起虚拟键盘
查看>>
AndroidStudio常用快捷键(持续更新,用一个记一个)
查看>>
Android获取本地图片、视频缩略图
查看>>
Android实现沉浸式状态栏
查看>>
AbAndroidStudio报错“unable to create debug bridge:ubable to start adb server”
查看>>
AAPT err... ERROR: Unable to open PNG file的解决方案
查看>>
Android ToolBar使用
查看>>
Android MediaPlayer --播放音频
查看>>
Dialog(一)系统自带功能
查看>>
CSDN博客添加浮动窗口的方法
查看>>
Homebrew指令集
查看>>
React Native(一):搭建开发环境、出Hello World
查看>>
React Native(二):属性、状态
查看>>
JSX使用总结
查看>>
React Native(五):Image的各种姿势
查看>>
React Native(四):布局(使用Flexbox)
查看>>