前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Go 语言实现 AES 算法的加解密操作

Go 语言实现 AES 算法的加解密操作

原创
作者头像
陈明勇
修改2024-11-15 16:44:20
修改2024-11-15 16:44:20
1590
举报
文章被收录于专栏:Go 技术Go 技术Go技术干货

文章:我用Java代码模拟出了德国二战的Enigma密码机加密 评语:这篇文章通过 Java 代码实现了德国二战时期 Enigma 密码机的加密过程,结构清晰明了。从介绍背景到代码还原,逐步解析了转子组、插接板以及加密方法,并通过测试验证了实现效果。内容既有技术深度,又对 Enigma 加密的原理和设计进行了直观展示,是对历史密码学与编程技术结合的有效实践总结。

前言

AESAdvanced Encryption Standard,高级加密标准)是一种对称加密算法,即在加密和解密过程中使用同一个密钥。AES 算法属于分组加密算法,将数据按块处理,每块固定大小。AES 算法的核心思想是在多轮操作中对数据进行替换和置换,从而有效打乱数据,使其无法被破解。

本文将会介绍如何在 Go 语言里面实现 AES 算法的加解密操作。

准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。

AES 加解密操作

AES算法支持多种模式,每种模式对加密的数据结构和安全性都有不同的要求和应用场景。常见的 AES 模式包括 ECBCBCCFBOFBGCM

ECB(Electronic Codebook)模式

  • 工作原理:每个分组独立加密,直接将明文分块,然后逐块加密,每块加密结果相同。
  • 优点:简单,易于实现,支持并行处理。
  • 缺点:缺乏随机性,明文相同则密文相同,容易被模式攻击,不适合加密大量相似数据。
  • 应用场景:一般不建议用于数据加密,但可以用于简单数据结构的加密,如加密一个简单的ID或固定数据块。

代码实现

代码语言:go
复制
package main

import (
	"bytes"
	"crypto/aes"
	"fmt"
)

func pkcs7Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

func pkcs7Unpadding(data []byte) []byte {
	length := len(data)
	unpadding := int(data[length-1])
	return data[:(length - unpadding)]
}

func encryptECB(plainText, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()
	plainText = pkcs7Padding(plainText, blockSize)

	cipherText := make([]byte, len(plainText))
	for start := 0; start < len(plainText); start += blockSize {
		end := start + blockSize
		block.Encrypt(cipherText[start:end], plainText[start:end])
	}

	return cipherText, nil
}

func decryptECB(cipherText, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()
	plainText := make([]byte, len(cipherText))
	for start := 0; start < len(cipherText); start += blockSize {
		end := start + blockSize
		block.Decrypt(plainText[start:end], cipherText[start:end])
	}

	plainText = pkcs7Unpadding(plainText)
	return plainText, nil
}

func main() {
	key := []byte("1234567890123456") // 16 字节密钥
	plainText := []byte("陈明勇")

	fmt.Println("原始:", string(plainText))

	// 加密
	cipherText, err := encryptECB(plainText, key)
	if err != nil {
		fmt.Println("Error encrypting:", err)
		return
	}
	fmt.Printf("加密后 (hex): %x\n", cipherText)

	// 解密
	decryptedText, err := decryptECB(cipherText, key)
	if err != nil {
		fmt.Println("Error decrypting:", err)
		return
	}
	fmt.Println("解密后:", string(decryptedText))
}

CBC(Cipher Block Chaining)模式

  • 工作原理:每个分组依赖于前一个密文块的结果,即前一个密文块和当前明文块异或后再进行加密。第一个块则用一个初始化向量(IV)进行异或操作。
  • 优点:加入 IV 增加了随机性,能抵御模式攻击。
  • 缺点:加密时不可并行,因每个分组依赖前一个分组,解密时可以并行。
  • 应用场景:是对数据加密比较常用的模式,适用于数据完整性要求较高的场景。
代码语言:go
复制
package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
)

// PKCS#7 填充
func pkcs7Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

// 移除 PKCS#7 填充
func pkcs7Unpadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, fmt.Errorf("invalid padding size")
	}
	unpadding := int(data[length-1])
	if unpadding > length {
		return nil, fmt.Errorf("invalid padding size")
	}
	return data[:(length - unpadding)], nil
}

func encryptCBC(plainText, key, iv []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()
	plainText = pkcs7Padding(plainText, blockSize)

	cipherText := make([]byte, len(plainText))
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(cipherText, plainText)

	return cipherText, nil
}

func decryptCBC(cipherText, key, iv []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()
	if len(cipherText)%blockSize != 0 {
		return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
	}

	plainText := make([]byte, len(cipherText))
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(plainText, cipherText)

	return pkcs7Unpadding(plainText)
}

func generateIV(blockSize int) ([]byte, error) {
	iv := make([]byte, blockSize)
	_, err := io.ReadFull(rand.Reader, iv)
	if err != nil {
		return nil, err
	}
	return iv, nil
}

func main() {
	key := []byte("1234567890123456") // 16 字节密钥
	plainText := []byte("陈明勇")

	fmt.Println("原始:", string(plainText))

	// 生成随机 IV
	iv, err := generateIV(aes.BlockSize)
	if err != nil {
		fmt.Println("Error generating IV:", err)
		return
	}
	fmt.Printf("IV (hex): %x\n", iv)

	// 加密
	cipherText, err := encryptCBC(plainText, key, iv)
	if err != nil {
		fmt.Println("Error encrypting:", err)
		return
	}
	fmt.Printf("加密后 (hex): %x\n", cipherText)

	// 解密
	decryptedText, err := decryptCBC(cipherText, key, iv)
	if err != nil {
		fmt.Println("Error decrypting:", err)
		return
	}
	fmt.Println("解密后:", string(decryptedText))
}

CFB(Cipher Feedback)模式

  • 工作原理:先对上一个密文块进行加密,然后将加密结果与当前明文块异或以生成密文块。
  • 优点:可以加密小于块长度的数据,可以作为流加密使用。
  • 缺点:密文错误会在下一个密文块传播。
  • 应用场景:适用于流式数据加密,如网络通信、实时数据流等。
代码语言:go
复制
package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
)

func encryptCFB(plainText, key, iv []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	cipherText := make([]byte, len(plainText))
	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(cipherText, plainText)

	return cipherText, nil
}

func decryptCFB(cipherText, key, iv []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	plainText := make([]byte, len(cipherText))
	stream := cipher.NewCFBDecrypter(block, iv)
	stream.XORKeyStream(plainText, cipherText)

	return plainText, nil
}

func generateIV(blockSize int) ([]byte, error) {
	iv := make([]byte, blockSize)
	_, err := io.ReadFull(rand.Reader, iv)
	if err != nil {
		return nil, err
	}
	return iv, nil
}

func main() {
	key := []byte("1234567890123456") // 16 字节密钥
	plainText := []byte("陈明勇")

	fmt.Println("原始:", string(plainText))

	// 生成随机 IV
	iv, err := generateIV(aes.BlockSize)
	if err != nil {
		fmt.Println("Error generating IV:", err)
		return
	}
	fmt.Printf("IV (hex): %x\n", iv)

	// 加密
	cipherText, err := encryptCFB(plainText, key, iv)
	if err != nil {
		fmt.Println("Error encrypting:", err)
		return
	}
	fmt.Printf("加密后 (hex): %x\n", cipherText)

	// 解密
	decryptedText, err := decryptCFB(cipherText, key, iv)
	if err != nil {
		fmt.Println("Error decrypting:", err)
		return
	}
	fmt.Println("加密:", string(decryptedText))
}

OFB(Output Feedback)模式

  • 工作原理:先生成一个密钥流,每次对 IV 或上一个密钥流块加密得到一个新的密钥块,然后将其与明文异或生成密文。
  • 优点:与 CFB 类似,可用作流加密,且不会在密文中传播错误。
  • 缺点:模式攻击可能较为容易。
  • 应用场景:适用于流加密且要求错误不传播的场景。
代码语言:go
复制
package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
)

func encryptOFB(plainText, key, iv []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	cipherText := make([]byte, len(plainText))
	stream := cipher.NewOFB(block, iv)
	stream.XORKeyStream(cipherText, plainText)

	return cipherText, nil
}

func decryptOFB(cipherText, key, iv []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	plainText := make([]byte, len(cipherText))
	stream := cipher.NewOFB(block, iv)
	stream.XORKeyStream(plainText, cipherText)

	return plainText, nil
}

func generateIV(blockSize int) ([]byte, error) {
	iv := make([]byte, blockSize)
	_, err := io.ReadFull(rand.Reader, iv)
	if err != nil {
		return nil, err
	}
	return iv, nil
}

func main() {
	key := []byte("1234567890123456") // 16 字节密钥
	plainText := []byte("陈明勇")

	fmt.Println("原始:", string(plainText))

	// 生成随机 IV
	iv, err := generateIV(aes.BlockSize)
	if err != nil {
		fmt.Println("Error generating IV:", err)
		return
	}
	fmt.Printf("IV (hex): %x\n", iv)

	// 加密
	cipherText, err := encryptOFB(plainText, key, iv)
	if err != nil {
		fmt.Println("Error encrypting:", err)
		return
	}
	fmt.Printf("加密后 (hex): %x\n", cipherText)

	// 解密
	decryptedText, err := decryptOFB(cipherText, key, iv)
	if err != nil {
		fmt.Println("Error decrypting:", err)
		return
	}
	fmt.Println("加密:", string(decryptedText))
}

CTR(Counter)模式

  • 工作原理:每次加密时,用一个计数器(Counter)值加密生成密钥流,与明文块异或得到密文。
  • 优点:支持并行加密和解密,性能高。
  • 缺点:计数器必须唯一且不可重复,否则会降低安全性。
  • 应用场景:高性能要求的场景,适合需要并行化的数据加密。
代码语言:go
复制
package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
)

func encryptCTR(plainText, key, nonce []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	cipherText := make([]byte, len(plainText))
	stream := cipher.NewCTR(block, nonce)
	stream.XORKeyStream(cipherText, plainText)

	return cipherText, nil
}

func generateNonce(blockSize int) ([]byte, error) {
	nonce := make([]byte, blockSize)
	_, err := io.ReadFull(rand.Reader, nonce)
	if err != nil {
		return nil, err
	}
	return nonce, nil
}

func main() {
	key := []byte("1234567890123456") // 16 字节密钥
	plainText := []byte("陈明勇")

	fmt.Println("原始:", string(plainText))

	// 生成随机 Nonce
	nonce, err := generateNonce(aes.BlockSize)
	if err != nil {
		fmt.Println("Error generating nonce:", err)
		return
	}
	fmt.Printf("Nonce (hex): %x\n", nonce)

	// 加密
	cipherText, err := encryptCTR(plainText, key, nonce)
	if err != nil {
		fmt.Println("Error encrypting:", err)
		return
	}
	fmt.Printf("加密后 (hex): %x\n", cipherText)

	// 解密
	decryptedText, err := encryptCTR(cipherText, key, nonce) // CTR 解密与加密相同
	if err != nil {
		fmt.Println("Error decrypting:", err)
		return
	}
	fmt.Println("解密:", string(decryptedText))
}

GCM(Galois/Counter Mode)模式

  • 工作原理:在 CTR 模式基础上加入认证功能,通过加密和认证来确保数据的机密性和完整性。
  • 优点:具有认证功能,能同时保证加密数据的完整性和安全性。
  • 缺点:实现复杂度高。
  • 应用场景:适用于需要认证和加密的场景,如 HTTPSVPN。
代码语言:go
复制
package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
)

func encryptGCM(plainText, key, nonce, aad []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	cipherText := gcm.Seal(nil, nonce, plainText, aad)

	return cipherText, nil
}

func decryptGCM(cipherText, key, nonce, aad []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	plainText, err := gcm.Open(nil, nonce, cipherText, aad)
	if err != nil {
		return nil, err
	}

	return plainText, nil
}

func generateNonce(size int) ([]byte, error) {
	nonce := make([]byte, size)
	_, err := io.ReadFull(rand.Reader, nonce)
	if err != nil {
		return nil, err
	}
	return nonce, nil
}

func main() {
	key := []byte("1234567890123456") // 16 字节密钥
	plainText := []byte("陈明勇")
	aad := []byte("Additional Data") // 附加认证数据(可选)

	fmt.Println("原始:", string(plainText))

	// 生成随机 Nonce
	nonce, err := generateNonce(12) // GCM 推荐使用 12 字节 Nonce
	if err != nil {
		fmt.Println("Error generating nonce:", err)
		return
	}
	fmt.Printf("Nonce (hex): %x\n", nonce)

	// 加密
	cipherText, err := encryptGCM(plainText, key, nonce, aad)
	if err != nil {
		fmt.Println("Error encrypting:", err)
		return
	}
	fmt.Printf("加密后 (hex): %x\n", cipherText)

	// 解密
	decryptedText, err := decryptGCM(cipherText, key, nonce, aad)
	if err != nil {
		fmt.Println("Error decrypting:", err)
		return
	}
	fmt.Println("解密:", string(decryptedText))
}

小结

本文简要介绍了 AES 算法的多种加密模式,并提供了对应的加解密实现代码,涵盖了以下模式:

  • ECB(电子密码本模式)
  • CBC(密码块链接模式)
  • CFB(密文反馈模式)
  • OFB(输出反馈模式)
  • CTR(计数器模式)
  • GCM(加洛伊计数器模式,支持认证)

每种模式各有特点,适用于不同的应用场景。选择加密模式时,应根据具体需求考虑性能、安全性、错误容忍度以及是否需要认证功能,合理选用适配的加密模式以满足实际需求。

你好,我是陈明勇,一名热爱技术、乐于分享的开发者,同时也是开源爱好者。

成功的路上并不拥挤,有没有兴趣结个伴?

关注我,加我好友,一起学习一起进步!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • AES 加解密操作
  • ECB(Electronic Codebook)模式
  • CBC(Cipher Block Chaining)模式
  • CFB(Cipher Feedback)模式
  • OFB(Output Feedback)模式
  • CTR(Counter)模式
  • GCM(Galois/Counter Mode)模式
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档