当前位置: 首页 > news >正文

3DES加解密的算法Java Python Golang

前言

最近做项目,发现一些报文需要加密,就简单研究了一些加密算法,包括国密和国际算法,顺便写了一个简单的对称加密算法应用,简单说明原理。实际工作中肯定更复杂,甚至需要专门的硬件配合才行。初步统计的国密和国际加密算法。

  • 国密算法

        SM1、SM2SM3SM4SM7SM9ZUC

        常用的SM2(非对称加密) SM3(摘要算法) SM4(对称加密)

  • 非国密

        RSA、ECC、DH(非对称)MD5、SHA(摘要算法) AES、DES、RC4(对称加密)

准备

一般而言,绝大多数报文和文件加密都是对称加密,毕竟计算资源消耗是非常恐怖的,而且可以通过其他方式增强安全性,比如非对称加密交换对称加密秘钥,秘钥随会话变化而变化,这不就是TLS的设计思想。

Java demo

以DES对称加密为例,但是DES加密的8位秘钥较容易被暴力破解,所以使用3DES加密为例,实际生产一般使用AES或者SM4等。

以外网的一个案例为例,笔者已经找不到最开始从哪里来的了

package com.feng.demo;import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;/*** SecretUtils {3DES加密解密的工具类 }* @author William* @date 2013-04-19*/
public class SecretUtils {public static void main(String[] args) {String originStr = "abc";String resultStr = Base64.getEncoder().encodeToString(encryptMode(originStr.getBytes(StandardCharsets.UTF_8)));System.out.println(resultStr);}//定义加密算法,有DES、DESede(即3DES)、Blowfishprivate static final String Algorithm = "DESede";
//    private static final String PASSWORD_CRYPT_KEY = "2012";private static final String PASSWORD_CRYPT_KEY = "2012PinganVitality075522628888ForShenZhenBelter075561869839";/*** 加密方法* @param src 源数据的字节数组* @return*/public static byte[] encryptMode(byte[] src) {try {SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);    //生成密钥Cipher c1 = Cipher.getInstance(Algorithm);    //实例化负责加密/解密的Cipher工具类c1.init(Cipher.ENCRYPT_MODE, deskey);    //初始化为加密模式return c1.doFinal(src);} catch (Exception e3) {e3.printStackTrace();}return null;}/*** 解密函数* @param src 密文的字节数组* @return*/public static byte[] decryptMode(byte[] src) {try {SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);Cipher c1 = Cipher.getInstance(Algorithm);c1.init(Cipher.DECRYPT_MODE, deskey);    //初始化为解密模式return c1.doFinal(src);} catch (Exception e3) {e3.printStackTrace();}return null;}/** 根据字符串生成密钥字节数组* @param keyStr 密钥字符串* @return* @throws UnsupportedEncodingException*/public static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException{byte[] key = new byte[24];    //声明一个24位的字节数组,默认里面都是0byte[] temp = keyStr.getBytes("UTF-8");    //将字符串转成字节数组/** 执行数组拷贝* System.arraycopy(源数组,从源数组哪里开始拷贝,目标数组,拷贝多少位)*///如果temp不够24位,则拷贝temp数组整个长度的内容到key数组中//如果temp大于24位,则拷贝temp数组24个长度的内容到key数组中System.arraycopy(temp, 0, key, 0, Math.min(key.length, temp.length));return key;}
}

简单优化了一下代码,简单说明

1. 构建24字节长度的秘钥,3DES刚好是DES的3倍秘钥

2. 传入加密算法和偏移量,这里使用ECB模式,没有偏移量,如果使用CBC模式需要传入IV偏移量

3. 通过base64转为字符串

运行后:

这里有个注意事项,内容和结果必须为block块的整数倍长度,如果不够必须填充,只不过Java包装了,见com.sun.crypto.provider.CipherCore.

prepareInputBuffer

这个Math方法写的看不懂

然后可以看到是通过数组填充

Python demo

其实刚刚的代码运行的好好的,但是,毕竟有Python客户端,甚至有C go等语言,怎么办,自己再写一遍实现,正是这一次重写,发现Java封装了好的隐藏逻辑,比如秘钥一定要大于16位,太短了补0,Java可以运行,但是Python不可以。

简单Python字符串和字节数组处理:

#正常字符串使用''或""表示
# 字符串前b,表示是字节数组  
b = b"aaa"
# 单引号
b = b'aaa'  # str to bytes  
bytes('abc', encoding = 'utf8')  
# an alternative method  
str.encode('abc')  # bytes to str  
str(b, encoding = 'utf-8')  
bytes.decode(b)  

安装des3加密包

pip install pycryptodome

然后根据3DES的规则编写代码

import base64
import sysfrom Crypto.Cipher import DES3#PASSWORD_CRYPT_KEY = '2012'
PASSWORD_CRYPT_KEY = b'2012PinganVitality075522628888ForShenZhenBelter075561869839'def build_3des_key(key_str, key_len=24) -> bytes:length = len(key_str)if length < key_len:key = key_str + chr(0) * (key_len - length)return bytes(key, 'utf-8')else:return key_str[:key_len]def build_src_fixed_len(src) -> str:delivery_len = 8 - len(src) % 8if delivery_len != 0:return src + chr(delivery_len) * delivery_lenreturn srcdef encrypt_mode(src) -> bytes:cipher = DES3.new(build_3des_key(PASSWORD_CRYPT_KEY), DES3.MODE_ECB)return cipher.encrypt(src)def decrypt_mode(src):cipher = DES3.new(build_3des_key(PASSWORD_CRYPT_KEY), DES3.MODE_ECB)return cipher.decrypt(src)args = sys.argv
print(args)
if args[1] == 'e':src = build_src_fixed_len(args[2])bytes_src = bytes(src, 'utf-8')bytes_res = encrypt_mode(bytes_src)bytes_res = base64.encodebytes(bytes_res)print(str(bytes_res, encoding = 'utf-8'))
else:bytes_src = base64.decodebytes(bytes(args[2], 'utf-8'))bytes_res = decrypt_mode(bytes_src)print(str(bytes_res, encoding = 'utf-8'))

然后执行命令:python secure_demo.py e 'abc'

可以看到跟Java结果一模一样,解密同理:

这里python有2个注意点,是Java封装后看不出来的:

1. 内容字符串长度必须是8的整数倍

2. 秘钥字符串长度必须超过16位,否则封装的内容是不对的

判断长度,前8位和中间8位;反转判断,如果一样则认为是DES加解密,这个在Java里面封装了处理逻辑,所以可以正常运行

3. 如果不够block的内容,怎么填充呢,是block-长度%block(定义为8)

当然也可以使用class特性,使用main方法运行,各种语言开始趋同进化了。

golang demo

仿照python和Java

package secureimport ("crypto/des"
)const PASSWORD_CRYPT_KEY string = "2012PinganVitality075522628888ForShenZhenBelter075561869839"func buildSecureKey(key string) []byte {bytes := make([]byte, 24)copy(bytes, []byte(key))//fmt.Println(string(bytes))return bytes
}func BuildSrcBytes(src []byte) []byte {length := len(src)deliveryLength := des.BlockSize - length%des.BlockSizeif deliveryLength != 0 {deliverySlice := make([]byte, deliveryLength)for i := 0; i < deliveryLength; i++ {deliverySlice[i] = byte(deliveryLength)}bytes := append(src, deliverySlice...)//fmt.Println(string(bytes))return bytes}//fmt.Println(string(src))return src
}func EncryptMode(src []byte) []byte {cipher, _ := des.NewTripleDESCipher(buildSecureKey(PASSWORD_CRYPT_KEY))bytesOut := make([]byte, len(src))//fmt.Println(src)cipher.Encrypt(bytesOut, src)//fmt.Println(bytesOut)return bytesOut
}func DecryptMode(src []byte) []byte {cipher, _ := des.NewTripleDESCipher(buildSecureKey(PASSWORD_CRYPT_KEY))bytesOut := make([]byte, len(src))//fmt.Println(src)cipher.Decrypt(bytesOut, src)return bytesOut
}

然后写个main方法

package mainimport ("demo/secure""encoding/base64""fmt"
)func main() {originStr := "abc"src := secure.BuildSrcBytes([]byte(originStr))result := secure.EncryptMode(src)fmt.Println(base64.StdEncoding.EncodeToString(result))srcBase64 := "dRQLaDw5udI="bytes, _ := base64.StdEncoding.DecodeString(srcBase64)resOrigin := secure.DecryptMode(bytes)fmt.Println(string(resOrigin))
}

执行后跟其他语言一致

总结

实际上仅仅是对称加密,实际上并不安全,不仅面临碰撞攻击,还面临着秘钥保存的问题,根据HTTPS的TLS密码设计,应该动态生成对称加密密钥,使用非对称加密算法交换密钥,根据会话动态变化。但是没有绝对的安全,实际上是加密和性能的取舍问题。非对称加密非常消耗计算性能,但是安全等级很高,对称加密对性能消耗较低,但是安全等级较低。

以TLSv1.2为例,先通过非对称加密(证书)交换对称加密的秘钥,加密回话报文。

http://www.dtcms.com/a/359405.html

相关文章:

  • 【大模型面试宝典之微调篇】(一)
  • 算法之链表
  • Windows中如何将Docker安装在E盘并将Docker的镜像和容器存储在E盘的安装目录下
  • 四数之和的一些判断怎么记忆
  • 《哲思:生命与宇宙的终极意义》
  • 分治思想与分治算法的区别
  • C6.7:输入电阻的负载效应及其CE负反馈放大器
  • 【线性代数基础 | 那忘算9】基尔霍夫(拉普拉斯)矩阵 矩阵—树定理证明 [详细推导]
  • ICode总线原理
  • Playwright Python 教程:高级篇
  • JDK 22 Windows 64位安装教程(含环境变量配置+验证步骤+附安装包下载)
  • Qwen3_moe模型代码解析
  • 数据结构与算法:线段树(三):维护更多信息
  • 运筹说 第141期 | 启发式算法:用简单规则、破解复杂问题
  • WEB漏洞挖掘篇(一) 基本概念、十大常見WEB漏洞
  • 自底向上了解CPU的运算
  • Google 的 Agent2Agent 协议 (A2A):带示例的指南
  • 「日拱一码」068 机器学习——迁移学习TL
  • SIEPIC工具和PDK安装
  • C#语言入门详解(17)字段、属性、索引器、常量
  • 云计算与服务器
  • 【C#】在一个任意旋转的矩形(由四个顶点定义)内绘制一个内切椭圆
  • 在AlmaLinux或CentOS 8上编译安装ZLMediaKit流媒体服务器
  • Mysql中事务隔离级别有哪些?
  • 【行业洞察】多智能体的风口浪尖--微软MagenticOne/UI
  • android中常见布局及其约束
  • 鸿蒙创新赛活动——Mac提交压缩失败后续
  • [linux仓库]解剖Linux内核:文件描述符(fd)的‘前世今生’与内核数据结构探秘
  • 如何绕过 disable-devtool.js 打开控制台
  • mac Monterey 安装erlang23