You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang AES-CBC-128解密后二进制数据如何正确保存为tar.gz归档文件

问题修复方案

已知错误点梳理

  • 初始版本核心错误1:密钥处理逻辑错误,aes.NewCipher需要传入16字节长度的原始二进制密钥,你写的key := hex.EncodeToString(decryptedKey)会把原始密钥转为32字符的十六进制字符串,传入后解密逻辑完全失效。
  • 初始版本核心错误2:错误切掉密文前16字节,代码中f = f[aes.BlockSize:]直接删除了密文第一块数据,而你使用的OpenSSL命令是显式传IV、没有把IV存在密文开头,这步操作直接导致解密内容从根源错误。
  • 第二版本核心错误1:循环起始偏移错误,初始ReadProg设为16相当于直接跳过了文件前16字节密文,解密后文件天然少16字节内容。
  • 第二版本核心错误2:填充处理不严谨,仅读取最后一个字节作为填充长度,没有做1-16区间的合法性校验,异常情况下会多删有效数据,你遇到的少20字节报错就是填充计算错误导致。
  • 第二版本核心错误3:未处理Read方法的有效返回字节数,os.File.Read不保证每次都读满16字节,直接用整块缓冲区解密会引入无效数据。

完整正确实现

对应你给出的OpenSSL命令逻辑,适配AES-128-CBC解密、PKCS7填充的完整代码如下:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/hex"
	"log"
	"os"
	"path/filepath"
)

// PKCS7Unpadding 移除PKCS7填充,适配OpenSSL enc默认填充规则
func PKCS7Unpadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, nil
	}
	padLen := int(data[length-1])
	// 校验填充长度合法性
	if padLen < 1 || padLen > aes.BlockSize {
		return data, nil
	}
	// 校验所有填充字节是否等于填充长度,可选校验逻辑,增强兼容性
	for i := length - padLen; i < length; i++ {
		if data[i] != byte(padLen) {
			return data, nil
		}
	}
	return data[:length-padLen], nil
}

func main() {
	// 替换为你实际的参数值
	hexKey := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" // AES-128对应32位十六进制字符串
	hexIV := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"  // IV固定为32位十六进制字符串
	encryptedFilePath := "foo.tar.gz.enc"
	outputPath := filepath.Join(".", "foo.tar.gz")

	// 1. 十六进制密钥、IV转二进制
	key, err := hex.DecodeString(hexKey)
	if err != nil {
		log.Fatalf("密钥解码失败: %s", err)
	}
	iv, err := hex.DecodeString(hexIV)
	if err != nil {
		log.Fatalf("IV解码失败: %s", err)
	}

	// 2. 读取加密文件内容,大文件可自行修改为流式读写逻辑
	encData, err := os.ReadFile(encryptedFilePath)
	if err != nil {
		log.Fatalf("读取加密文件失败: %s", err)
	}

	// 3. 初始化AES解密器
	block, err := aes.NewCipher(key)
	if err != nil {
		log.Fatalf("初始化AES失败: %s", err)
	}

	// 4. CBC模式解密
	mode := cipher.NewCBCDecrypter(block, iv)
	plainData := make([]byte, len(encData))
	mode.CryptBlocks(plainData, encData)

	// 5. 移除填充
	plainData, err = PKCS7Unpadding(plainData)
	if err != nil {
		log.Fatalf("去填充失败: %s", err)
	}

	// 6. 输出最终tar.gz文件
	err = os.WriteFile(outputPath, plainData, 0644)
	if err != nil {
		log.Fatalf("写入输出文件失败: %s", err)
	}

	log.Println("解密完成,输出文件路径:", outputPath)
}

内容的提问来源于stack exchange,提问作者TempestBreach

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 16:30:00