最近有一个业务需求,需要前端传递一个密码到后端,期间要对传递的密码通过进行对称加密,我们约定使用成熟的AES加密方法。

前端使用php,后端用python,但是发现前端兄弟加密后的字符串,在python端解密后末尾总会有16字节长度的\x10字符内容,通过python的ord('\x10')输出可知,这就是数字16的Unicode code。

众所周知,在使用AES进行对称加密之前,需要将加密的内容长度补全至16的倍数。如果前端兄弟无法解决加密内容中总有额外的16字节\x10字符的问题,那么后端就要考虑多余的处理逻辑,看起来奇奇怪怪的。

于是我百度了下php的openssl_encrypt函数,发现其中option选项有4个:

- 0
- OPENSSL_RAW_DATA=1
- OPENSSL_ZERO_PADDING=2
- OPENSSL_NO_PADDING=3

其中赫然写着OPENSSL_NO_PADDING,字面意思很好理解了,应该就是就是不会自动追加(补全)的意思,再看前端兄弟用的是OPENSSL_RAW_DATA。于是替换为OPENSSL_NO_PADDING后,果然没有了\x10的内容,问题暂时解决了。

然后我又回头想了一想,为什么OPENSSL_RAW_DATA会自动追加一个16字节的\x10呢,这肯定是有原因的。

因为在之前的测试中,我们在调用php的openssl_encrypt函数之前,已经手动对加密的字符进行了补全,保证其长度是16的倍数。如果不补全会怎样?

我手动试了一下:

<?php
$str = '1234567890'
$add_data_zero_padding = openssl_encrypt($str, 'AES-128-CBC', $key, $options=OPENSSL_ZERO_PADDING, $iv);
$add_data_no_padding = openssl_encrypt($str, 'AES-128-CBC', $key, $options=OPENSSL_NO_PADDING, $iv);
$add_data_raw_data = openssl_encrypt($add_str, 'AES-128-CBC', 'eNg6geeCinee0kee', $options=OPENSSL_RAW_DATA, 'nesejeiP6du0quie'); var_dump($add_data_zero_padding);
var_dump($add_data_no_padding);
var_dump($add_data_raw_data); echo "base64 encode:\n";
var_dump(base64_encode($add_data_raw_data));
?>

然后输出结果就是:

bool(false)
bool(false)
string(32) "�q$B�7��*���vE0�+��J.8t�[Bt�"
base64 encode:
string(44) "jHEkQrs3hBG+DiqE/4B2RTCUK6wE5r1KLjh03VtCdPs="

果然,如果没有补全,那么OPENSSL_ZERO_PADDINGOPENSSL_NO_PADDING会加密失败。而OPENSSL_RAW_DATA加密的内容,解密后的字节内容是:

b'NulhIKidvmW6jaFK4T9uqJyuwrlEo\x03\x03\x03'

如此一来,其实不用去细看文档也能推理出OPENSSL_RAW_DATA自动补全的含义了,因为补全的内容最后还需要还原为原始字符串,怎么知道哪些字符是补全上去的,哪些字符是原始字符呢?

php逻辑是这样的,我补全的长度至少是1,最长是16,代表这个长度的数字,正好都可以用一个Unicode字符表示,比如1就是\x01,16就是\x10

如果加密的内容长度是15字节,那么就在最后补全一个\x01,还原的时候,只需要读取最后一个字节内容,转换为数字,得到1,就知道加密前只追加了1个字节,那么就把末尾的1个字节内容去掉即可。

如果加密的内容长度正好是16字节呢,为了还原,那么就必须要在末尾追加16\x10,还原的时候读取最后一个字节并转换为数字,就知道加密时候追加了16字节,那么把末尾的16个字节去掉即可。

其实用python代码表示这个补全和还原的逻辑如下:

BLOCK_SIZE = 16  # 16 Bytes
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE) # 至少会追加16字节的内容
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

chrord 含义如下:

chr(i, /)
Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff. ord(c, /)
Return the Unicode code point for a one-character string.

使用php的openssl_encrypt和python的pycrypt进行跨语言的对称加密和解密问题的更多相关文章

  1. JAVA中AES对称加密和解密以及与Python兼容

    引言:本文主要解决Java中用AES加密及解密,同时可通过Python脚本对Java加密后的字符进行解密的操作. 由于近期工作中用到需要使用Java对一串密钥进行加密,并且后台通过Python语言读取 ...

  2. C#, Java, PHP, Python和Javascript几种语言的AES加密解密实现[转载]

    原文:http://outofmemory.cn/code-snippet/35524/AES-with-javascript-java-csharp-python-or-php c#里面的AES加密 ...

  3. C#, Java, PHP, Python和Javascript几种语言的AES加密解密实现

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  4. Python开发【模块】:M2Crypto RSA加密、解密

    M2Crypto 模块 快速安装: # 环境centos7.0,提前装好openssl(自行百度安装),windows装不上,暂不考虑了 [root@localhost ~]# pip install ...

  5. Golang、Php、Python、Java基于Thrift0.9.1实现跨语言调用

    目录: 一.什么是Thrift? 1) Thrift内部框架一瞥 2) 支持的数据传输格式.数据传输方式和服务模型 3) Thrift IDL 二.Thrift的官方网站在哪里? 三.在哪里下载?需要 ...

  6. (二)Python是一门什么样的语言?

    在学习python是一门什么样的语言之前首先需要知道什么是编译和解释? 编译器是把源程序的每一条语句都编译成机器语言,并保存成二进制文件,这样运行时计算机可以直接以机器语言来运行此程序,速度很快; 而 ...

  7. 跨语言学习的基本思路及python的基础学习

    笔者是C#出身,大学四年主修C#,工作三年也是C#语言开发.但在学校里其他的语言也有相应的课程,eg:Java,Php,C++都学过,当然只是学了皮毛(大学嘛,你懂得),严格来说未必入门,但这些语言的 ...

  8. Python pycrypto 加密与解密

    参考: python 使用 pycrypto‎ 实现 AES 加密解密 参考: 分组对称加密模式:ECB/CBC/CFB/OFB 代码示例 : import hashlib from Crypto.C ...

  9. Python面试题之python是一种什么语言及优缺点

    1.说说python是一种什么语言? 参考答案:python是一门动态解释性的强类型定义语言 编译型vs解释型 编译型优点:编译器一般会有预编译的过程对代码进行优化.因为编译只做一次,运行时不需要编译 ...

  10. 【Python】 基于秘钥的对称加密

    [Crypto] 关于用python进行信息的加密,类似的解决方案有很多比如用base64编码进行encode,再或者是hashlib来进行hash.但是还缺少一种明明场景很简单的解决方案,就是把利用 ...

随机推荐

  1. 【软件开发】Git 概念与常用命令

    [软件开发]Git 概念与常用命令 Git 概念 存储方式 Git 是分布式存储,每一个 clone 下来的仓库都可以看成独立的个体,只是 Git 有提供同步功能,因此 Git 支持离线使用,因为本质 ...

  2. C# List应用 Lambda 表达式

    参考链接 : https://blog.csdn.net/wori/article/details/113144580 首先 => 翻译为{ } 然后没有然后 主要基于我工作中常用的几种情况,写 ...

  3. 深度研究JDK的各种技术细节

    打算建立一个JDK网站,将目前JDK的各种重要特性都深入分析一下.希望JDK中各种技术实现细节都可以在这个网站上查到.相关的模块以及阅读顺序如下图所示. 没有将一些内容规划进来,Java语言基本语法太 ...

  4. 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误

    大家好,我是小康.今天我们来聊一个藏在C++标准库中的"定时炸弹",它看起来人畜无害,但却坑了无数C++程序员. 前言:当你以为自己用的是vector,结果却不是 嘿,各位码农兄弟 ...

  5. 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理

    在 AI 编程领域国内外有一堆能叫的上号的应用: Cursor Windsurf Trae 阿里的「通义灵码」 百度的「文心快码」 字节跳动的「MarsCode」 科大讯飞的「iFlyCode」 Gi ...

  6. Selenium IDE工具:火狐浏览器实例讲解IDE命令

    在本文中,通过Firefox浏览器上的示例学习Selenium IDE: 我们将使用的网址是"https://accounts.google.com"作为测试程序,通过本文你会 了 ...

  7. mysql安装以及2059 - Authentication plugin 'caching_sha2_password' cannot be loaded:报错的解决办法

    2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_ ...

  8. FastAPI 错误处理与自定义错误消息完全指南:构建健壮的 API 应用 🛠️

    title: FastAPI 错误处理与自定义错误消息完全指南:构建健壮的 API 应用 ️ date: 2025/3/12 updated: 2025/3/12 author: cmdragon e ...

  9. js回忆录(2) -- 逻辑表达式,条件语句

    之所以要把逻辑表达式和条件语句放一块写一下,完全是因为二者的联系太过紧密,逻辑运算产生布尔值的结果,而条件语句则根据布尔值决定走那个分支. 逻辑与: &&, 首先逻辑与有逻辑与运算功能 ...

  10. How to use the Ubuntu

    How to use the Ubuntu Introduction ‍ As far as I have noted, I will force myself to write all my blo ...