<?php
$iv = "1234567890abcdef";
$key = "abcdef1234567890";
//使用OPENSSL_RAW_DATA,多一次转换,方便说明白通讯过程
echo base64_encode(openssl_encrypt("hello world", "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv));
结果
CtqXZg7SH5ACIK7gWwOu4w==
go解密部分
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func main() {
originData , _ := base64.StdEncoding.DecodeString( "CtqXZg7SH5ACIK7gWwOu4w==" )
iv := []byte("1234567890abcdef")
keyByteString := "abcdef1234567890"
cipherBlock, err := aes.NewCipher([]byte(keyByteString))
if err != nil{
fmt.Println(err)
}
cipher.NewCBCDecrypter(cipherBlock, iv).CryptBlocks(originData, originData)
fmt.Println(string(PKCS5UnPadding(originData)))
}
//这个方法是直接找的网上的实现
func PKCS5UnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
if length - unpadding < 0 {
return []byte("")
}
return src[:(length - unpadding)]
}
解密结果
hello world
Process finished with exit code 0
说明在AES-128-CBC的时候keyByteString是16个字符这个是固定的
再看下AES-256-CBC的时候
<?php
$iv = "1234567890abcdef";
$key = "abcdef12345678901234567890abcdef";
echo base64_encode(openssl_encrypt("hello world", "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv));
结果
RxpbfHR/FnUo5Mh9NRtudQ==
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func main() {
originData , _ := base64.StdEncoding.DecodeString( "RxpbfHR/FnUo5Mh9NRtudQ==" )
iv := []byte("1234567890abcdef")
keyByteString := "abcdef12345678901234567890abcdef"
cipherBlock, err := aes.NewCipher([]byte(keyByteString))
if err != nil{
fmt.Println(err)
}
cipher.NewCBCDecrypter(cipherBlock, iv).CryptBlocks(originData, originData)
fmt.Println(string(PKCS5UnPadding(originData)))
}
//这个方法是直接找的网上的实现
func PKCS5UnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
if length - unpadding < 0 {
return []byte("")
}
return src[:(length - unpadding)]
}
结果
hello world
Process finished with exit code 0
其中iv是固定16位,而keyByteString则变为了32位
以上这几种情况都比较简单,而比较坑的是啥呢,
1.php在key的长度不满足要求的时候也可以加密成功!
2.go则必须要求keyByteString的长度满足要求!!!
所以这几涉及到了key在php中到底是怎处理的
先看下php的源码
PHP_FUNCTION(openssl_decrypt)
{
//省略无关代码
//注意这里这里有对参数的初始化处理,那么我们就可以猜测这里有对key的处理
if (php_openssl_cipher_init(cipher_type, cipher_ctx, &mode,
&password, &password_len, &free_password,
&iv, &iv_len, &free_iv, tag, tag_len, options, 0) == FAILURE ||
php_openssl_cipher_update(cipher_type, cipher_ctx, &mode, &outbuf, &outlen,
data, data_len, aad, aad_len, 0) == FAILURE) {
RETVAL_FALSE;
}
//省略好多
}
//再来看php_openssl_cipher_init方法
static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type,
EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode,
char **ppassword, size_t *ppassword_len, zend_bool *free_password,
char **piv, size_t *piv_len, zend_bool *free_iv,
char *tag, int tag_len, zend_long options, int enc) /* {
{
{ */
{
//又省略好多
/* check and set key */
password_len = (int) *ppassword_len;
key_len = EVP_CIPHER_key_length(cipher_type);
//就是这里了这里PHP在key的长度不满足要求的长度时会自动重新填充一个新的key出来!而go中不支持这种操作!!!这就比较坑了,而解决的办法就是通过go实现key的填充
if (key_len > password_len) {
if ((OPENSSL_DONT_ZERO_PAD_KEY & options) && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) {
php_openssl_store_errors();
php_error_docref(NULL, E_WARNING, "Key length cannot be set for the cipher method");
return FAILURE;
}
key = emalloc(key_len);
memset(key, 0, key_len);
memcpy(key, *ppassword, password_len);
*ppassword = (char *) key;
*ppassword_len = key_len;
*free_password = 1;
}
//省略好多
}
那么如何解决这个问题呢
直接看看代码吧
<?php
$iv = "1234567890abcdef";
$key = "abc";
echo base64_encode(openssl_encrypt("hello world", "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv));
结果
7s3/y57WmZt+f1Pz5KzXlg==
go 的解密处理方法
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func main() {
originData , _ := base64.StdEncoding.DecodeString( "7s3/y57WmZt+f1Pz5KzXlg==" )
iv := []byte("1234567890abcdef")
//key为abc
key := "abc"
//初始化一个空的字节数组,这里的16为AES-128-CBC的要求的key的长度
keyByte := [16]byte{
}
//转换key为字节数组
keyByteTemp := []byte(key)
//依次赋值,这里的3为key的len
for i := 0; i < 3; i++ {
keyByte[i] = keyByteTemp[i]
}
fmt.Println(keyByteTemp,keyByte)
//转换依次得到的keyByteString
keyByteString := string(keyByte[:])
//解密
cipherBlock, err := aes.NewCipher([]byte(keyByteString))
if err != nil{
fmt.Println(err)
}
cipher.NewCBCDecrypter(cipherBlock, iv).CryptBlocks(originData, originData)
fmt.Println(string(PKCS5UnPadding(originData)))
}
func PKCS5UnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
if length - unpadding < 0 {
return []byte("")
}
return src[:(length - unpadding)]
}
结果
[97 98 99] [97 98 99 0 0 0 0 0 0 0 0 0 0 0 0 0]
hello world
Process finished with exit code 0
好了这里是针对AES-128-CBC的在key的长度不满足的情况做的处理
留给读者思考的问题
1.AES-256-CBC的key不满足长度的情况怎处理
2.在AES-128-CBC的情况iv不满足长度又要怎么处理呢
文章浏览阅读482次。基于魔搭平台快速搭建自己的baichuan大模型demo,简单快速一键部署_from modelscope import snapshot_download
文章浏览阅读2.7k次。索引存储结构索引存储结构=数据表+索引表索引表(index blocked table)中的每一项称为索引项,索引项的一般形式:(关键字,地址)举个例子:分块查找的基本思想分块查找又称分块索引查找(index blocked search)是一种介于顺序查找和二分查找之间的查找方法。其基本思想是:(1)将数据表str[0…n-1]均分为b块,前b-1块中记录个数为s=n/b,最后一块即第b块的记录数小于等于s;(2)每一块中的关键字不一定有序,但前一块中的最大关键字必须小于后一块中的最小关键_索引存储结构举例
文章浏览阅读413次。试题链接点我进入代码提交OJ学习笔记-高效排序算法( O(nlogn)时间复杂度 )算法介绍归并排序主要思路• 归并排序,是把待排序的序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序的序列。• 归并排序的算法核心步骤分为两个部分:分解,合并:• 首先,把n 个元素分解为n 个长度为1的有序子表;• 然后,进行两两归并使元素的关键字有序,得到n/2 个长度为2 的有序子表;• 重复上述合并步骤,直到所有元素合并成一个长度为n的有序表 为止。算法图解算法代_icpc2021寒假冬令营第五天
文章浏览阅读1.7k次。安装ffmpeg使用brew首先安装brew:/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"出现这个:==> Installation successful!安装成功....No changes to formulae...._installing ffmpeg dependency: imath ==> pouring imath-3.1.4.catalina.bottle.
文章浏览阅读731次。老顾最近一直在玩 csdn 周赛,没啥想法,就是想票点小玩意,之前从第四十一期开始,题型进行了扩展,增加了填空、判断、单选。扩展题型的周赛,目前是三期,分别是四十一,四十四,四十五。连续三期,老顾的填空题一分没拿到过,嗯,尽管41期是老顾提交的bug,自己给自己扣的分。
文章浏览阅读990次。本文目录1.下载以太坊2.开始安装 3. 开启以太坊挖矿 以太坊(Ethereum)是一个运行智能合约的去中心化平台(Platform for Smart Contract),平台上的应用按程序设定运行,不存在停机、审查、欺诈、第三方人为干预的可能。以太坊平台由Golang、C++、Python 等多种编程语言实现。前段时间的The DAO事件让以太坊平台损失惨重,以太坊也分裂成ETC和ETH,..._window.ethereum详解
文章浏览阅读585次,点赞15次,收藏8次。java常用排序算法——二分查找(折半查找)概述
文章浏览阅读108次。1.unplugTo unplug a PDB, you first close it and then generate an XML manifest file. The XML file contains information about the names and the full paths of the tablespaces, as we..._pluggable database is not closed
文章浏览阅读265次。10月10日,某大型电商平台上一家名为“长虹厨房电器旗舰店”的商家公告称,因为某推广机构的恶意欺骗,标价60多元的电热水壶,被不到10元钱买下拍了20万单。由此产生巨大的损失,甚至有破产倒闭风险,恳请消费者退款。有网友认为“薅羊毛”不能薅秃了羊,决定申请退款;也有网友观点认为,消费者并无过错,商家理应为自己的行为负责,营销活动中出现了问题不应该将责任推给消费者,电商平台应该加强没有契约精神的商家加强监管。这并非电商平台上首次因“薅羊毛”造成电商损失的情况。2019年1月,有网友称拼多多存在重大Bug_长虹电器失败风险的原因
文章浏览阅读7.8k次,点赞4次,收藏13次。一、实验目的 1、加深对计算机中运算器的基本概念、运算方法和基本原理的理解。 2、提高学生对计算机编程语言掌握的熟练程度。二、实验内容 运用一种编程语言实现计算器的基本功能。 思考: 1、计算机中数据是如何表示的? 2、计算机中二进制数的加、减、乘、除四则运算如何实现? 3、运算器的基本结构和功能有哪些?三.实验结果分析 计算器运行结果: 1: 计算机中数据是如何表示的?计算机_计算机组成原理编写代码完成累加器和寄存器的内容相减
文章浏览阅读1.5k次,点赞51次,收藏31次。C语言基础知识:输入输出、运算符、算数运算符、赋值运算符、比较运算符、位运算符、类型转换、控制语句 if语句、if...else语句 、三目运算符、else...if 语句、switch语句、跳转关键字、break、continue、goto.
文章浏览阅读795次。格式输入、格式输出、宏常量、静态局部变量,静态全局变量,bool类型变量,_c语言输出行列式分析和注意