go语言实现对称加密

go语言实现对称加密

AES算法+CTR分组模式
加密思路
第一步:创建aes密码接口
  • 创建一个cipher.Block接口

func NewCipher(key []byte) (cipher.Block, error)

参数:秘钥

返回值:一个分组接口

第二步:创建分组模式ctr
  • crypto/cipher包

func NewCTR(block Block, iv []byte) Stream

参数1:填写分组接口

参数2:初始向量(大小与分组大小一致)

返回值:一个Stream接口对象

第三步:加密
  • Stream的方法

XORKeyStream(dst, src []byte)

参数1:密文空间

参数2:明文

解密思路

与加密完全一致

代码实现
//输入明文,输出密文
func aesCtrEncrypt(plainText, key []byte) ([]byte, error) {
	// 第一步:创建aes密码接口
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	//第二步:创建分组模式ctr
	// iv 要与算法长度一致,16字节
	// 使用bytes.Repeat创建一个切片,长度为blockSize(),16个字符"1"
	iv := bytes.Repeat([]byte("1"), block.BlockSize())
	stream := cipher.NewCTR(block, iv)

	//第三步:加密
	dst := make([]byte, len(plainText))
	stream.XORKeyStream(dst, plainText)

	return dst, nil
}

//输入密文,得到明文
func aesCtrDecrypt(encryptData, key []byte) ([]byte, error) {
	return aesCtrEncrypt(encryptData, key)
}

func main() {
	//明文,需要加密的数据
	src := "Stream接口代表一个流模式的加/解密器。"

	//对称秘钥,aes,16字节
	key := "1234567887654321" //16
	// key := "12345678876543210" //17, 无效的
	encryptData, err := aesCtrEncrypt([]byte(src), []byte(key))
	if err != nil {
		fmt.Println("加密出错err:", err)
		return
	}

	fmt.Printf("encryptData: %x\n", encryptData)

	//调用解密函数
	plainText, err := aesCtrDecrypt(encryptData, []byte(key))
	if err != nil {
		fmt.Println("err:", err)
		return
	}

	fmt.Printf("解密后的数据: %s\n", plainText)
}
DES算法+CBC分组模式
加密思路
第一步:创建des密码接口
  • 创建一个cipher.Block接口

func NewCipher(key []byte) (cipher.Block, error)

参数:秘钥

返回值:一个分组接口

第二步:创建分组模式cbc
  • crypto/cipher包

func NewCBCEncrypter(b Block, iv []byte) BlockMode

参数1:填写分组接口

参数2:初始向量(大小与分组大小一致)

返回值:一个BlockMode接口对象

第三步:填充

封装一个填充函数

  • 得到分组之后剩余的长度

    用数据对分组大小取余,得到分组之后的剩余长度

  • 得到需要填充的个数

    用分组大小减去剩余长度得到需要填充的个数

  • 创建一个slice,包含n(需要填充的个数)个n(需要填充的个数)

    注意要把数字转化为字符

  • 将切片追加到数据中

第四步:加密
  • BlockMode的方法

CryptBlocks(dst, src []byte)

参数1:密文空间

参数2:明文

解密思路
第一步:创建des密码接口

与加密一样

第二步:创建分组模式cbc
  • crypto/cipher包

func NewCBCDecrypter(b Block, iv []byte) BlockMode

参数1:填写分组接口

参数2:初始向量(大小与分组大小一致)

返回值:一个BlockMode接口对象

第三步:解密
  • BlockMode的方法

CryptBlocks(dst, src []byte)

参数1:明文空间

参数2:密文

第四步:去除填充

封装一个去除填充函数

  • 获取最后一个字符

  • 将字符转换为数字

  • 截取切片

代码实现
func desCBCEncrypt(plainText /*明文*/, key []byte) ([]byte, error) {
	//第一步:创建des密码接口, 输入秘钥,返回接口
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}

	//第二步:创建cbc分组
	// 返回一个密码分组链接模式的、底层用b解密的BlockMode接口
	// func NewCBCEncrypter(b Block, iv []byte) BlockMode
	blockSize := block.BlockSize()

	//创建一个8字节的初始化向量
	iv := bytes.Repeat([]byte("1"), blockSize)

	mode := cipher.NewCBCEncrypter(block, iv)

	//第三步:填充
	//TODO
	plainText, err = paddingNumber(plainText, blockSize)
	if err != nil {
		return nil, err
	}

	//第四步:加密
	// type BlockMode interface {
	// 	// 返回加密字节块的大小
	// 	BlockSize() int
	// 	// 加密或解密连续的数据块,src的尺寸必须是块大小的整数倍,src和dst可指向同一内存地址
	// 	CryptBlocks(dst, src []byte)
	// }

	//密文与明文共享空间,没有额外分配
	mode.CryptBlocks(plainText /*密文*/, plainText /*明文*/)

	return plainText, nil
}

//输入密文,得到明文
func desCBCDecrypt(encryptData, key []byte) ([]byte, error) {
	//TODO
	//第一步:创建des密码接口
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}

	//第二步:创建cbc分组
	iv := bytes.Repeat([]byte("1"), block.BlockSize())
	mode := cipher.NewCBCDecrypter(block, iv)

	//第三步:解密
	mode.CryptBlocks(encryptData /*明文*/, encryptData /*密文*/)

	//第四步: 去除填充
	//TODO
	encryptData, err = unPaddingNumber(encryptData)
	if err != nil {
		return nil, err
	}

	// return []byte("Hello world"), nil
	return encryptData, nil
}

//填充数据
func paddingNumber(src []byte, blockSize int) ([]byte, error) {

	if src == nil {
		return nil, errors.New("src长度不能小于0")
	}

	fmt.Println("调用paddingNumber")
	//1. 得到分组之后剩余的长度 5
	leftNumber := len(src) % blockSize //5

	//2. 得到需要填充的个数 8 - 5 = 3
	needNumber := blockSize - leftNumber //3

	//3. 创建一个slice,包含3个3
	b := byte(needNumber)
	newSlice := bytes.Repeat([]byte{b}, needNumber) //newSlice  ==》 []byte{3,3,3}

	fmt.Printf("newSclie : %v\n", newSlice)
	//4. 将新切片追加到src
	src = append(src, newSlice...)

	return src, nil
}

//解密后去除填充数据
func unPaddingNumber(src []byte) ([]byte, error) {
	fmt.Println("调用unPaddingNumber")
	//1. 获取最后一个字符
	lastChar := src[len(src)-1] //byte(3)

	//2. 将字符转换为数字
	num := int(lastChar) //int(3)

	//3. 截取切片(左闭右开)

	return src[:len(src)-num], nil
}

func main() {
	src := "一行白鹭上青天"  //明文
	key := "12345678" //秘钥

	//加密处理
	encryptData, err := desCBCEncrypt([]byte(src), []byte(key))
	if err != nil {
		fmt.Println("err:", err)
		return
	}

	fmt.Printf("encryptData: %x\n", encryptData)

	key = "12345678" //秘钥
	//调用解密函数
	plainText, err := desCBCDecrypt(encryptData, []byte(key))
	if err != nil {
		fmt.Println("err:", err)
		return
	}

	fmt.Printf("解密后的数据: %s\n", plainText)
	fmt.Printf("解密后的数据 hex : %x\n", plainText)
}
是的,对称加密算法可以在不同的编程语言中实现,并且可以实现相同的加密解密结果。下面是一个使用Go、Java和JavaScript实现AES对称加密算法的示例代码: Go: ```go package main import ( "crypto/aes" "crypto/cipher" "encoding/base64" "fmt" ) func main() { key := []byte("1234567890123456") plaintext := []byte("Hello, world!") block, _ := aes.NewCipher(key) ciphertext := make([]byte, aes.BlockSize+len(plaintext)) iv := ciphertext[:aes.BlockSize] if _, err := rand.Read(iv); err != nil { panic(err) } stream := cipher.NewCFBEncrypter(block, iv) stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) fmt.Printf("Encrypted: %v\n", base64.URLEncoding.EncodeToString(ciphertext)) } ``` Java: ```java import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class Main { public static void main(String[] args) throws Exception { byte[] key = "1234567890123456".getBytes(); byte[] plaintext = "Hello, world!".getBytes(); KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(128, new SecureRandom(key)); byte[] iv = new byte[16]; SecureRandom random = new SecureRandom(); random.nextBytes(iv); SecretKeySpec secretKeySpec = new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(iv)); byte[] ciphertext = cipher.doFinal(plaintext); System.out.printf("Encrypted: %s\n", Base64.getEncoder().encodeToString(ciphertext)); } } ``` JavaScript: ```javascript const crypto = require('crypto'); const key = Buffer.from('1234567890123456'); const plaintext = Buffer.from('Hello, world!'); const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-128-cbc', key, iv); let ciphertext = cipher.update(plaintext); ciphertext = Buffer.concat([ciphertext, cipher.final()]); console.log(`Encrypted: ${ciphertext.toString('base64')}`); ``` 这三段代码实现了相同的AES对称加密算法,并且输出的加密结果相同。如果需要解密,可以使用相同的密钥和IV值,以及相同的算法和模式进行解密。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值