当前位置: 首页 > 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.xdnf.cn/news/1407259.html

相关文章:

  • CVPR上的多模态检索+视频理解,LLM助力提效翻倍
  • 8.1【Q】VMware相关
  • 吴恩达机器学习作业十一:异常检测
  • 大模型——利用RAG构建智能问答平台实战
  • 在Ubuntu服务器上安装KingbaseES V009R002C012(Orable兼容版)数据库过程详细记录
  • Qwen3_moe模型代码解析
  • FreeRTOS实战:任务创建与调度详解
  • 【MySQL自学】SQL语法全解(上篇)
  • 【PS实战】逐步打造静物的艺术色调(大学作业)
  • 从零开始搭建使用 TDengine:新用户快速上手指南
  • windows docker 中的mysql 无法被外部浏览器访问如何解决
  • 自动驾驶中的传感器技术37——Lidar(12)
  • Ansible 临时命令与常用模块实操指南
  • 【人工智能99问】LLaMA中的RoPE是什么?(35/99)
  • Paimon——官网阅读:Spark 引擎
  • Spark内存管理
  • Nginx 502 Bad Gateway:从 upstream 日志到 FastCGI 超时复盘
  • 腾讯浑元最新技术:具有表征对齐的多模态扩散,用于高保真拟音音频生成
  • 【嵌入式DIY实例】-空中鼠标
  • LeetCode算法日记 - Day 27: 计算右侧小于当前元素的个数、翻转对
  • 高校心理教育辅导系统的设计与实现|基于SpringBoot高校心理教育辅导系统的设计与实现
  • USB虚拟化应用5:VirtualFIDO2 虚拟硬件安全密钥,智能卡,yubico,支持X,FB,GITHUB等各种网站双重认证,让你的账户登录绝对安全
  • 在集群级别应用 Pod 安全标准
  • opencv 梯度提取
  • 数据化管理是什么意思?企业该如何进行数据化管理
  • 《SVA断言系统学习之路》【01】即时断言概览
  • 北京博乐科技有限公司2025届程序技术类笔试题
  • 性能测试工具-SkyWalking
  • 元宇宙与旅游产业:虚实融合的文旅新体验
  • Python毕业设计推荐:基于Django+MySQL的养老社区服务管理系统