前言

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

3DES加密或解密弱密钥

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

  1. public static string DesEncrypt(string input, string key)
  2. {
  3. byte[] inputArray = Encoding.UTF8.GetBytes(input);
  4. var tripleDES = TripleDES.Create();
  5. var byteKey = Encoding.UTF8.GetBytes(key);
  6. byte[] allKey = new byte[];
  7. Buffer.BlockCopy(byteKey, , allKey, , );
  8. Buffer.BlockCopy(byteKey, , allKey, , );
  9. tripleDES.Key = allKey;
  10. tripleDES.Mode = CipherMode.ECB;
  11. tripleDES.Padding = PaddingMode.PKCS7;
  12. ICryptoTransform cTransform = tripleDES.CreateEncryptor();
  13. byte[] resultArray = cTransform.TransformFinalBlock(inputArray, , inputArray.Length);
  14. return Convert.ToBase64String(resultArray, , resultArray.Length);
  15. }
  16.  
  17. public static string DesDecrypt(string input, string key)
  18. {
  19. byte[] inputArray = Convert.FromBase64String(input);
  20. var tripleDES = TripleDES.Create();
  21. var byteKey = Encoding.UTF8.GetBytes(key);
  22. byte[] allKey = new byte[];
  23. Buffer.BlockCopy(byteKey, , allKey, , );
  24. Buffer.BlockCopy(byteKey, , allKey, , );
  25. tripleDES.Key = byteKey;
  26. tripleDES.Mode = CipherMode.ECB;
  27. tripleDES.Padding = PaddingMode.PKCS7;
  28. ICryptoTransform cTransform = tripleDES.CreateDecryptor();
  29. byte[] resultArray = cTransform.TransformFinalBlock(inputArray, , inputArray.Length);
  30. return Encoding.UTF8.GetString(resultArray);
  31. }

接下来我们调用上述加密方法对数据进行加密,当然这里的密钥很简单为16位1,NET Framework中对弱密钥的具体判断逻辑这里不做深入分析,如下:

  1. var desEncryptData = DesEncrypt("Jeffcky", "");

为解决这个问题我们下载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中翻译过来,如下:

  1. static IBufferedCipher CreateCipher(bool forEncryption, string key,
  2. string cipMode = "DESede/ECB/PKCS5Padding")
  3. {
  4. var algorithmName = cipMode;
  5. if (cipMode.IndexOf('/') >= )
  6. {
  7. algorithmName = cipMode.Substring(, cipMode.IndexOf('/'));
  8. }
  9.  
  10. var cipher = CipherUtilities.GetCipher(cipMode);
  11.  
  12. var keyBytes = Encoding.UTF8.GetBytes(key);
  13.  
  14. var keyParameter = ParameterUtilities.CreateKeyParameter(algorithmName, keyBytes);
  15.  
  16. cipher.Init(forEncryption, keyParameter);
  17.  
  18. return cipher;
  19. }

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

  1. static string EncryptData(string input, string key)
  2. {
  3. var inCipher = CreateCipher(true, key);
  4.  
  5. var inputArray = Encoding.UTF8.GetBytes(input);
  6.  
  7. byte[] cipherData = inCipher.DoFinal(inputArray);
  8.  
  9. return Convert.ToBase64String(cipherData);
  10. }
  11.  
  12. static string DecryptData(string input, string key)
  13. {
  14. var inputArrary = Convert.FromBase64String(input);
  15.  
  16. var outCipher = CreateCipher(false, key);
  17.  
  18. var encryptedDataStream = new MemoryStream(inputArrary, false);
  19.  
  20. var dataStream = new MemoryStream();
  21.  
  22. var outCipherStream = new CipherStream(dataStream, null, outCipher);
  23.  
  24. int ch;
  25. while ((ch = encryptedDataStream.ReadByte()) >= )
  26. {
  27. outCipherStream.WriteByte((byte)ch);
  28. }
  29.  
  30. outCipherStream.Close();
  31. encryptedDataStream.Close();
  32.  
  33. var dataBytes = dataStream.ToArray();
  34.  
  35. return Encoding.UTF8.GetString(dataBytes);
  36. }

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

  1. var data = EncryptData("Jeffcky", "");
  2.  
  3. var decryptData = DecryptData(data, "");

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

  1. public const int DesKeyLength = ;
  2.  
  3. private const int N_DES_WEAK_KEYS = ;
  4.  
  5. //基于Schneier pp281的弱和半弱键表
  6. private static readonly byte[] DES_weak_keys =
  7. {
  8. /* 弱键 */
  9. (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,
  10. (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e,
  11. (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1,
  12. (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe,
  13.  
  14. /* 半弱键 */
  15. (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe,
  16. (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1,
  17. (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1,
  18. (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe,
  19. (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e,
  20. (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe,
  21. (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01,
  22. (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e,
  23. (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01,
  24. (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e,
  25. (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01,
  26. (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1
  27. };
  28.  
  29. public static bool IsWeakKey(byte[] key, int offset)
  30. {
  31. if (key.Length - offset < DesKeyLength)
  32. throw new ArgumentException("key material too short.");
  33.  
  34. //nextkey:
  35. for (int i = ; i < N_DES_WEAK_KEYS; i++)
  36. {
  37. bool unmatch = false;
  38. for (int j = ; j < DesKeyLength; j++)
  39. {
  40. if (key[j + offset] != DES_weak_keys[i * DesKeyLength + j])
  41. {
  42. //continue nextkey;
  43. unmatch = true;
  44. break;
  45. }
  46. }
  47.  
  48. if (!unmatch)
  49. {
  50. return true;
  51. }
  52. }
  53.  
  54. return false;
  55. }

如果第三方为Java,当利用.NET Core实在走投无路无法进行解密时,那就使用上述提供的解密方法进行解密,理论上都可以解密,不能解密的情况大多出现于对C#和Java实现原理不了解导致,如下:

总结

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

探讨NET Core数据进行3DES加密或解密弱密钥问题的更多相关文章

  1. 探讨.NET Core数据进行3DES加密和解密问题

    前言 一直困扰着我关于数据加密这一块,24号晚上用了接近3个小时去完成一项任务,本以为立马能解决,但是为了保证数据的安全性,我们开始去对数据进行加密,然后接下来3个小时专门去研究加密这一块,然而用着用 ...

  2. 探讨.NET Core中实现AES加密和解密以及.NET Core为我们提供了什么方便!

    前言 对于数据加密和解密每次我都是从网上拷贝一份,无需有太多了解,由于在.net core中对加密和解密目前全部是统一了接口,只是做具体的实现,由于遇到过问题,所以将打算基本了解下其原理,知其然足矣, ...

  3. 探讨数据进行AES加密和解密以及.NET Core对加密和解密为我们提供了什么?

    前言 对于数据加密和解密每次我都是从网上拷贝一份,无需有太多了解,由于在.net core中对加密和解密目前全部是统一了接口,只是做具体的实现,由于遇到过问题,所以将打算基本了解下其原理,知其然足矣, ...

  4. [Swift通天遁地]七、数据与安全-(17)使用Swift实现原生的3DES加密和解密

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  5. 3DES加密及.NET弱密钥处理

    背景 智能pos机开发项目需要指定Key加密某些关键字符串.商定采用3DES加密算法. 实践 网海中很多.NET C#编写3DES加密的函数.采集一段简明.成熟的代码,归置于常用程序集.但当指定Key ...

  6. 使用crypto-js对数据进行AES加密、解密

    前段时间做项目有用到数据加密,前端加密,后端解密(前端也可以解密),话不多说进入正题: 第一步: npm i crypto-js -S 第二步: 在需要加密或解密的地方引入crypto-js: imp ...

  7. 对接https数据(3des加密)

    private void checkThread() { Urls urls = new Urls(type);//根据唯一识别类型初始化参数,可根据实际情况修改此构造函数 //访问国家平台接口,取出 ...

  8. 探讨.NET Core数据加密和解密问题

    前言 一直困扰着我关于数据加密这一块,24号晚上用了接近3个小时去完成一项任务,本以为立马能解决,但是为了保证数据的安全性,我们开始去对数据进行加密,然后接下来3个小时专门去研究加密这一块,然而用着用 ...

  9. JAVA和C# 3DES加密解密

    最近 一个项目.net 要调用JAVA的WEB SERVICE,数据采用3DES加密,涉及到两种语言3DES一致性的问题, 下面分享一下, 这里的KEY采用Base64编码,便用分发,因为Java的B ...

随机推荐

  1. Java实现 LeetCode 131 分割回文串

    131. 分割回文串 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回 s 所有可能的分割方案. 示例: 输入: "aab" 输出: [ ["aa ...

  2. Java实现 LeetCode 56 合并区间

    56. 合并区间 给出一个区间的集合,请合并所有重叠的区间. 示例 1: 输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: ...

  3. TZOJ 公交车

    描述 公交车在一条笔直的道路(道路宽度忽略,设为X轴)上行驶,按顺序路上有若干个站点(X坐标值),crq的家也在道路旁某个位置h(X坐标值),现在crq想知道哪个站点下车离家最近. 输入 输入数据的第 ...

  4. 08_提升方法_AdaBoost算法

    今天是2020年2月24日星期一.一个又一个意外因素串连起2020这不平凡的一年,多么希望时间能够倒退.曾经觉得电视上科比的画面多么熟悉,现在全成了陌生和追忆. GitHub:https://gith ...

  5. Netty源码学习系列之4-ServerBootstrap的bind方法

    前言 今天研究ServerBootstrap的bind方法,该方法可以说是netty的重中之重.核心中的核心.前两节的NioEventLoopGroup和ServerBootstrap的初始化就是为b ...

  6. nginx功能介绍和基本安装

    一.简介 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:nginx可以作为一个HTTP服务器进行网站的发布处理,另外ngi ...

  7. Debian安装无线网卡Ralink RL5390驱动

    惠普一体机用的无线网卡是Ralink的 RL5390,安装Debian10以后没有驱动,网上下载firmware-misc-nonfree_20190114-2_all.deb 和firmware-r ...

  8. 如何从二进制文件中读取int型序列

    使用的主要函数是int.from_bytes 代码如下: f = open('./T26.dat', 'rb') for i in range(20): A = f.read(2) A = int.f ...

  9. Android学习笔记基于回调的事件处理

    流程: 常见的回调方法: 代码示例: @Override public boolean onTouchEvent(MotionEvent event) { Toast.makeText(getAppl ...

  10. 001.OpenShift介绍

    一 OpenShift特性 1.1 OpenShift概述 Red Hat OpenShijft Container Platform (OpenShift)是一个容器应用程序平台,它为开发人员和IT ...