记工作中一个艰难的历程:别人的python AES加密,我的java AES解密

背景:领导用python写了个AES加密,加密后的结果写在文件中。让我写个AES解密,可以解密他的文件。
作为一个代码的搬运工,这种问题难不倒我,百度一下我就知道(不要鄙视我不用google)。
看到结果我傻眼了:搜索到的结果基本都是对着写python加解密和java加解密,这些内容虽然也让我获益匪浅,但距离实现我的目标还有一定的差距。
最终费了九牛二虎之力,发挥想象和感觉,终于在上百次的重启中找到可行的代码。
如果观看文章的你,也和我有类似的情况,希望我的文章可以给你些思路。由于加解密的设置不同结果也是完全不同的,所以简单的ctrl c,ctrl v可能没有用。
AES是什么我就不多说了,我也不懂,不能瞎说。但要进行AES加解密是要设置一些前提的,我碰到的是

  • key和iv都是确定的
  • 加解密的方式为CFB(网上最多的是CBC)
  • 字符串编码方式为gb2312(大家用的最多是utf-8)

本次主要记录的问题:

  1. python和java的数据类型不一样的,所以python加密的内容,如果只看内容,java读取的文件是乱码的。但计算机的底层都是一致的,所以用二进制数组解析文件才是对的。
  2. CFB方式加密需要设置分段的长度(segment_size),python默认是8,而jvm默认是128,所以不能用默认,由于我是后写的,所以我就按python的改成8
  3. 将文件上传类型MultipartFile类型转换成File类型

如果这些你都知道,那你基本不用看了,没啥新的了,对我最有用的文章有以下几篇,感谢这些文章的作者
https://segmentfault.com/q/1010000017486879
https://stackoverflow.com/questions/40004858/encrypt-in-python-and-decrypt-in-java-with-aes-cfb
https://blog.csdn.net/weixin_39800144/article/details/80225990
https://blog.csdn.net/qq_39699665/article/details/83081431

好了进入正题,其实python加解密和java加解密,网上都是现成的。网上的我们领导给了我python解密的代码,让我对着写java代码,代码如下

secret_key = "1234567890987654"
iv_param = '1234567890123456'

with open('D:/test.txt','rb') as file_object:
    contents = file_object.read()
    print(contents)
    aes2 = AES.new(secret_key.encode("gb2312"), AES.MODE_CFB, iv_param.encode("gb2312"))
    plain_data2 = aes2.decrypt(contents)
    print(plain_data2.decode('gb2312'))

代码中contents的类型是bytes,打印的结果类似于
b’\xa7!\xbfc\x9d\xe4\xd9\xef\x11po1\xb6\x87\xee\x1f\xfd.\xa7\xa3\xa1m$\x1e}<5=Y\xd5b\xf7\x94+Q\x93\xb2\x(我只截取了一半)
妈呀看不懂,但是没关系,只要java也能将这个文件读成这样不就行了吗,于是我找了各种流都不成功,只能读出一堆乱码的文本,这里的错误在于我以为是文本的内容编码后变成了样,所以一直在用各种流去读取文件内容,但事实上是文本本身在计算机以这种类型存储(就这个意思,可能表述不准确)
解决方案,就是用java将文件读取成二进制的byte数组,具体代码

 	String file = "D:\\test.txt";
    File myFile = new File(file);
    byte[] mybetys = BinUtil.getFileToByte(myFile);

这里涉及一个bin的工具类,就是我上文给出的第三个链接,我引用的方法的具体实现如下

public static byte[] getFileToByte(File file) {
        byte[] by = new byte[(int) file.length()];
        try {
            InputStream is = new FileInputStream(file);
            ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
            byte[] bb = new byte[2048];
            int ch;
            ch = is.read(bb);
            while (ch != -1) {
                bytestream.write(bb, 0, ch);
                ch = is.read(bb);
            }
            by = bytestream.toByteArray();
        } catch (Exception ex) {
            throw new RuntimeException("transform file into bin Array 出错",ex);
        }
        return by;
    }

强调一下,不是读取文件内容,而是文件本身,所以不是用什么字符流字节流,而是FileInputStream(我流学的不太好,理解比较片面,领会精神)
文件以正确的方式读取了,解密应该小菜一碟了,网上到处都是解密的代码,但还是上文说的问题

The Cipher Feedback (CFB) mode of operation is a family of modes. It is parametrized by the segment size (or register size). PyCrypto has a default segment size of 8 bit and Java (actually OpenJDK) has a default segment size the same as the block size (128 bit for AES).
If you want CFB-128 in pycrypto, you can use AES.new(key, AES.MODE_CFB, iv, segment_size=128). If you want CFB-8 in Java, you can use Cipher.getInstance(“AES/CFB8/NoPadding”);

Python 的 PyCrypto 模块默认使用的 segment_size 是 8, Java 则默认采用segment_size为128.
所以要使 Python 获的和 Java 一样的加密结果, 必须让 Python 和 Java 使用相同的segment_size. 假设我们让 Python 适应 Java, 使用 segment_size=128

这两段话的意思差不多,其实英文写的更明白一下,就是python默认segment_size为8,JAVA(实际上是OpenJDK)的默认segment_size是128(这个分段的尺寸必须是8的倍数)
如果你想改python,你就这样设置

AES.new(key, AES.MODE_CFB, iv, segment_size=128)

如果你想改java,你就这样设置,这个设置我找了很久,基本上没有提到的

Cipher.getInstance("AES/CFB8/NoPadding")

那后续的就很简单了,我把代码贴出来,供大家参考
首先是main函数

public static void main(String[] args)throws Exception{

        String file = "D:\\test.txt";
        File myFile = new File(file);
        byte[] mybetys = BinUtil.getFileToByte(myFile);
		String secret_key = "1234567890987654"
		String iv_param = '1234567890123456'
        String res = aesDecrypt(secret_key,iv_param,mybetys);
        System.out.println(res);
    }
private static String aesDecrypt(String key, String iv, byte[] content) {
        try {
            byte[] keyb = key.getBytes("gb2312");
            byte[] ivb = iv.getBytes("gb2312");

            Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding");
            SecretKeySpec keyspec = new SecretKeySpec(keyb, "AES");
            IvParameterSpec ivspec = new IvParameterSpec(ivb);
            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

            byte[] original = cipher.doFinal(content);
            return new String(original,"gb2312").trim();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

这样读取文件并将其解密就做好了
后来领导说,把这些功能加到文件上传就ok了,文件上传的参数类型大家都知道,是MultipartFile,我写的功能是参数是File,那只要将MultipartFile转换成File就ok了,这很简单,但我在网上找的方法,基本都不能用,很郁闷,只有上文链接中第四个链接可以用,这里贴出来,大家看一下就好
以上就是从周五下午搞到周一下午的结果(周末休了两天,想不到程序猿还能双休吧,哈哈哈)
如果你看到了这里,那就祝你工作顺利,天天进步~~~~

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 以下是使用 Python 进行 AES 加密解密的示例代码: ```python from Crypto.Cipher import AES import base64 # 加密函数 def aes_encrypt(key, data): # 将密钥和数据进行补位 key = key.encode('utf-8') data = data.encode('utf-8') key = key.ljust(16, b'\0') data = data.ljust(16, b'\0') # 创建 AES 加密aes = AES.new(key, AES.MODE_ECB) # 加密 encrypted_data = aes.encrypt(data) # 对加密结果进行 base64 编码 base64_data = base64.b64encode(encrypted_data) return base64_data.decode('utf-8') # 解密函数 def aes_decrypt(key, encrypted_data): # 将密钥和加密数据进行补位 key = key.encode('utf-8') encrypted_data = encrypted_data.encode('utf-8') key = key.ljust(16, b'\0') encrypted_data = base64.b64decode(encrypted_data) # 创建 AES 解密aes = AES.new(key, AES.MODE_ECB) # 解密 decrypted_data = aes.decrypt(encrypted_data) return decrypted_data.decode('utf-8').rstrip('\0') # 示例 key = '1234567890123456' data = 'Hello, world!' encrypted_data = aes_encrypt(key, data) decrypted_data = aes_decrypt(key, encrypted_data) print('加密前的数据:', data) print('加密后的数据:', encrypted_data) print('解密后的数据:', decrypted_data) ``` 在示例,使用了 PyCryptodome 库AES 加密解密函数来实现加密解密操作。需要注意的是,为了保证密钥和数据的长度符合 AES 加密算法的要求,需要在密钥和数据后面进行补位。在示例,采用了将字符串转换成字节数组的方式进行补位。同时,在加密操作,还对加密结果进行了 base64 编码,以便于传输和存储。 ### 回答2: Python AES加密解密是利用Python加密库来实现AES算法的加密解密操作。AES是一种常用的对称加密算法,可以对数据进行高强度的加密,并可以通过相同密钥进行解密。 在Python,我们可以使用第三方库PyCryptodome来实现AES加密解密。首先,需要安装PyCryptodome库,可以使用pip命令进行安装。 安装完成后,我们可以通过以下代码进行AES加密解密的操作: ```python from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from Crypto.Random import get_random_bytes # 生成随机的16字节密钥 key = get_random_bytes(16) # 初始化AES实例,使用ECB模式 cipher = AES.new(key, AES.MODE_ECB) # 待加密的数据 data = b'This is some data to be encrypted' # 执行加密操作 ciphertext = cipher.encrypt(pad(data, AES.block_size)) print('加密后的数据:', ciphertext) # 执行解密操作 decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size) print('解密后的数据:', decrypted_data) ``` 在上述代码,首先我们通过`get_random_bytes`函数生成了一个随机的16字节密钥。然后,使用生成的密钥以ECB模式初始化了一个AES实例。接下来,我们定义了待加密的数据,并通过`pad`函数进行填充,保证数据长度是AES块大小的整数倍。然后,调用`encrypt`函数对数据进行加密,并通过`print`函数打印出加密后的数据。 接着,我们调用`unpad`函数对加密后的数据进行解密,并通过`print`函数打印出解密后的数据。 需要注意的是,AES的安全性依赖于密钥的安全性,因此在实际应用,密钥的生成和管理需要采取相应的安全措施。 ### 回答3: Python实现AES加密解密可以使用`Crypto.Cipher`库。首先,需要安装`pycryptodome`库。可以使用以下命令安装: ``` pip install pycryptodome ``` 然后,我们可以按照下面的步骤使用AES进行加密解密: 步骤 1:导入所需库 ```python from Crypto.Cipher import AES from Crypto.Random import get_random_bytes ``` 步骤 2:生成随机密钥和初始化向量(IV) ```python key = get_random_bytes(16) # 生成16字节的密钥 iv = get_random_bytes(16) # 生成16字节的初始化向量 ``` 步骤 3:创建AES加密器和解密器,使用生成的密钥和IV ```python cipher = AES.new(key, AES.MODE_CBC, iv) decrypter = AES.new(key, AES.MODE_CBC, iv) ``` 步骤 4:对要加密的数据进行填充 ```python data = b'Hello, World!' padding_length = AES.block_size - (len(data) % AES.block_size) data += bytes([padding_length]) * padding_length ``` 步骤 5:对数据进行加密解密 ```python encrypted_data = cipher.encrypt(data) decrypted_data = decrypter.decrypt(encrypted_data) ``` 最后,我们可以打印出加密解密后的数据: ```python print("加密后的数据:", encrypted_data) print("解密后的数据:", decrypted_data) ``` 这样,我们就完成了使用AES进行加密解密的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值