Go语言实现AES-CBC加密并编写命令行工具passctl

陈默
陈默
发布时间:2026-10-15| 7人浏览过
原创

掌握Go语言中的AES加密标准,利用原生标准库实现CBC模式下的数据块加密,并结合PKCS7填充处理变长数据。本文将深入解析加解密核心逻辑,最终提供一个可直接编译运行的命令行工具 passctl,用于便捷的字符串加密与解密操作,确保数据传输与存储的安全性。

AES加密原理与Go标准库基础

高级加密标准(Advanced Encryption Standard,简称AES),即Rijndael加密法,是当前应用最广泛的区块加密标准之一。在Go语言中,crypto/aes 包提供了完整的AES实现,配合 crypto/cipher 包可轻松处理不同工作模式(如CBC、CTR等)。

在实际应用中,简单的AES块加密无法满足任意长度数据的加密需求,因此通常结合以下技术:

  • CBC(Cipher Block Chaining,密码分组链接)模式:每个明文块先与前一个密文块进行异或运算,再进行加密,保证相同明文每次加密结果不同。
  • PKCS7填充:当数据长度不是块大小(AES为16字节)的整数倍时,进行补齐。
  • Base64编码:将二进制密文转换为可打印字符串,便于在命令行或配置文件中传输。

核心加解密模块实现

首先,我们需要构建可复用的加密和解密函数。关键点在于处理密钥长度(AES要求16、24或32字节)、初始化向量(IV)以及填充/解填充逻辑。在CBC模式中,IV通常直接使用密钥的前16位作为简化处理,但生产环境建议生成随机IV并随密文一起存储。

第1步:实现PKCS7填充与解填充

目的:确保输入数据长度符合AES 16字节块大小的倍数。

入口:bytes 和 errors 包。

动作:填充函数计算剩余空间,追加相应数量的字节值;解填充函数读取最后一个字节的值作为长度,截断多余部分。

package main

import (
	"bytes"
	"errors"
)

// pkcs7Padding 对数据进行PKCS7填充
func pkcs7Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

// pkcs7UnPadding 去除PKCS7填充
func pkcs7UnPadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, errors.New("empty data")
	}
	unPadding := int(data[length-1])
	if unPadding > length {
		return nil, errors.New("invalid padding")
	}
	return data[:(length - unPadding)], nil
}

第2步:封装AES加密与解密函数

目的:整合Cipher创建、CBC模式设置及Base64转换。

参数:EncKey 需为固定长度(示例使用16字节)。加密输出Base64字符串,解密输入Base64字符串。

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"fmt"
)

var EncKey = []byte("QAZWSXEDCRFVTGBY") // 16位密钥

// AesEncrypt AES加密,返回Base64字符串
func AesEncrypt(plaintext []byte) (string, error) {
	block, err := aes.NewCipher(EncKey)
	if err != nil {
		return "", err
	}
	blockSize := block.BlockSize()
	encryptBytes := pkcs7Padding(plaintext, blockSize)
	crypted := make([]byte, len(encryptBytes))
	// CBC模式需要IV,此处简单复用Key的前16字节作为IV
	blockMode := cipher.NewCBCEncrypter(block, EncKey[:blockSize])
	blockMode.CryptBlocks(crypted, encryptBytes)
	return base64.StdEncoding.EncodeToString(crypted), nil
}

// AesDecrypt 解密Base64字符串,返回原始明文
func AesDecrypt(base64Ciphertext string) ([]byte, error) {
	dataByte, err := base64.StdEncoding.DecodeString(base64Ciphertext)
	if err != nil {
		return nil, err
	}
	block, err := aes.NewCipher(EncKey)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	crypted := make([]byte, len(dataByte))
	blockMode := cipher.NewCBCDecrypter(block, EncKey[:blockSize])
	blockMode.CryptBlocks(crypted, dataByte)
	crypted, err = pkcs7UnPadding(crypted)
	if err != nil {
		return nil, err
	}
	return crypted, nil
}

构建命令行应用程序 passctl

为了在终端中便捷地使用上述功能,我们将代码封装为一个命令行工具。该工具接受三个主要参数:-h(帮助)、-e(加密)、-d(解密)。我们使用Go标准库 os 解析参数,避免引入第三方依赖,保持程序轻量。

第3步:完整命令行实现代码

入口:main 函数,读取 os.Args。

重要参数:os.Args[0] 为程序名,os.Args[1] 为命令开关,os.Args[2] 为待处理字符串。

package main

import (
	"fmt"
	"os"
)

const helpMsg = `
Usage: passctl [option] "string"
Options:
  -h, --help    Show this help message
  -e, --enc     Encrypt a plaintext string
  -d, --dec     Decrypt a ciphertext string

Examples:
  passctl -e "password123"
  passctl -d "encrypted_string_base64"
`

func main() {
	if len(os.Args) < 2 {
		fmt.Println(helpMsg)
		return
	}

	action := os.Args[1]
	inputStr := ""
	if len(os.Args) > 2 {
		inputStr = os.Args[2]
	}

	switch action {
	case "-h", "--help":
		fmt.Print(helpMsg)
	case "-e", "--enc":
		if inputStr == "" {
			fmt.Println("Error: missing input string for encryption")
			return
		}
		res, err := AesEncrypt([]byte(inputStr))
		if err != nil {
			fmt.Printf("Encryption failed: %v\n", err)
			return
		}
		fmt.Println(res)
	case "-d", "--dec":
		if inputStr == "" {
			fmt.Println("Error: missing input string for decryption")
			return
		}
		res, err := AesDecrypt(inputStr)
		if err != nil {
			fmt.Printf("Decryption failed: %v\n", err)
			return
		}
		fmt.Println(string(res))
	default:
		fmt.Println("Invalid option. Use -h for help.")
	}
}

第4步:编译与测试运行

目的:将Go源码编译为静态二进制文件,以便在其他无Go环境的机器上使用。

操作:使用 go build 命令,指定输出文件名 passctl。

# 编译Linux 64位二进制文件
GOOS=linux GOARCH=amd64 go build -o passctl main.go

# 添加执行权限
chmod +x passctl

执行测试:

# 查看帮助
$ ./passctl -h

# 加密明文 "abc123456"
$ ./passctl -e "abc123456"
nGi3ls+2yghdv7o8Ly2Z+A==

# 解密上述密文
$ ./passctl -d "nGi3ls+2yghdv7o8Ly2Z+A=="
abc123456

通过上述步骤,我们成功实现了基于AES-CBC模式的字符串加解密,并将其打包为独立的命令行工具。该方法不依赖任何第三方库,适合嵌入式系统或资源受限的环境。需要注意的是,当前实现简化了IV的处理,在生产环境中建议使用随机生成的IV并将其附加在密文前一同传输或存储,以提高安全性。

以上就是Go语言实现AES加密并编写一个命令行应用程序 passctl 的详细内容,更多关于Go语言AES加密实战的资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。