0

0

如何在Golang中实现文件加密与解密_Golang crypto与文件操作实践

P粉602998670

P粉602998670

发布时间:2026-01-23 10:59:19

|

159人浏览过

|

来源于php中文网

原创

必须先读16字节IV,再读全部剩余数据作为密文+tag,用aesgcm.Open解密时需传入正确长度的dst切片,认证失败会返回cipher.ErrAuthFailed而非panic。

如何在golang中实现文件加密与解密_golang crypto与文件操作实践

加密前必须确认的三个前提

Go 的 crypto/aescrypto/cipher 不提供开箱即用的“文件加密函数”,所有安全实现都依赖你自己组合底层原语。这意味着:密钥管理、IV 生成、填充方式、认证机制(如 GCM)必须手动处理,漏掉任一环节都可能让加密形同虚设。

  • 密钥不能硬编码或复用——每次加密应使用 crypto/rand.Read 生成新密钥(或派生自密码的密钥)
  • IV(初始化向量)必须随机且唯一,长度需匹配块大小(AES 是 16 字节),且必须随密文一起保存(但无需保密)
  • 单纯 CBC 模式不防篡改——若需完整性校验,必须用 aes.NewGCM,否则攻击者可翻转密文导致解密出可控明文

用 AES-GCM 安全加密大文件的正确姿势

直接读整个文件进内存再加密会爆内存,必须流式处理。GCM 模式下无法像 CBC 那样分块加密后拼接——GCM 的认证标签(tag)只能在全部加密完成后生成,所以得先写密文,最后追加 tag;解密时则需先读完整密文+tag,再一次性验证解密。

实际做法是:把 IV(16 字节)+ 密文 + tag(16 字节)按固定顺序写入文件。解密时先读前 16 字节为 IV,剩余末尾 16 字节为 tag,中间为密文。

func encryptFile(src, dst string, key []byte) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()

	block, _ := aes.NewCipher(key)
	aesgcm, _ := cipher.NewGCM(block)
	nonce := make([]byte, aesgcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return err
	}

	// 先写 IV
	if _, err := out.Write(nonce); err != nil {
		return err
	}

	// 加密并写入密文(流式)
	writer := aesgcm.Seal(nonce[:0], nonce, nil, nil)
	// 注意:writer 是一个切片,后续 Write 会追加到它后面
	if _, err := io.Copy(writer, f); err != nil {
		return err
	}
	// writer 现在包含:nonce(已覆盖)+ 密文 + tag
	// 但我们只写了 nonce(16字节),密文+tag 还在 writer 底层 buffer 中
	// 所以要跳过前 aesgcm.NonceSize() 字节,写剩余部分
	if _, err := out.Write(writer[aesgcm.NonceSize():]); err != nil {
		return err
	}
	return nil
}

解密时最容易踩的坑:IV 长度、tag 位置、错误处理

常见错误包括:把 IV 当作密文一部分传给 aesgcm.Open、没预留足够空间读取 tag、忽略 aesgcm.Open 返回的 error(它会在认证失败时返回 cipher.ErrAuthFailed 而不是 panic)。

Sora
Sora

Sora是OpenAI发布的一种文生视频AI大模型,可以根据文本指令创建现实和富有想象力的场景。

下载

立即学习go语言免费学习笔记(深入)”;

  • aesgcm.Open 的第一个参数是 dst 切片,必须至少和密文等长(它会把解密结果 copy 进去)
  • IV 必须和加密时完全一致(长度、内容),且不能从密文中间任意截取
  • 如果密文被截断或 tag 损坏,aesgcm.Open 会返回 cipher.ErrAuthFailed,此时绝不能继续使用解密结果
func decryptFile(src, dst string, key []byte) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()

	// 读 IV(前 16 字节)
	nonce := make([]byte, 16)
	if _, err := io.ReadFull(f, nonce); err != nil {
		return err
	}

	// 读剩余全部内容(密文 + tag)
	all, err := io.ReadAll(f)
	if err != nil {
		return err
	}
	if len(all) < 16 {
		return errors.New("ciphertext too short")
	}

	ciphertext := all[:len(all)-16]
	tag := all[len(all)-16:]

	block, _ := aes.NewCipher(key)
	aesgcm, _ := cipher.NewGCM(block)

	plaintext, err := aesgcm.Open(nil, nonce, append(ciphertext, tag...), nil)
	if err != nil {
		return err // 注意:这里 err 可能是 cipher.ErrAuthFailed
	}

	_, err = out.Write(plaintext)
	return err
}

密码派生密钥(PBKDF2)比直接用字符串更安全

用户输入的密码通常太短、熵太低,不能直接当 AES 密钥用。必须用 crypto/rand 生成 salt,并通过 crypto/pbkdf2 派生出 32 字节密钥(AES-256)。

  • salt 必须随机且唯一,长度建议 ≥ 16 字节,和 IV 一样需随密文保存
  • 迭代次数建议 ≥ 100000(Go 1.19+ 默认是 100000,旧版本需显式指定)
  • 派生出的密钥长度必须匹配 AES 模式(256 位 → 32 字节)

这意味着加密文件结构变成:salt(16) + iv(16) + ciphertext + tag(16),解密时先读 salt,再用它和用户密码重新派生密钥。

密钥派生和文件结构耦合是多数人忽略的复杂点——一旦 salt 丢失或误读,密钥就无法重建,文件彻底不可恢复。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

180

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

340

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

209

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

393

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

197

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

191

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

253

2025.06.17

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

8

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.1万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号