当前位置 博文首页 > Golang实现AES对称加密的过程详解

    Golang实现AES对称加密的过程详解

    作者:写Golang的小张 时间:2021-05-29 17:51

    AES加密

    AES对称加密简介
    AES是一个对称密码,旨在取代DES成为广泛使用的标准。是美国联邦政府采用的一种区块加密标准。

    AES对称加密过程
    加密解密算法的输入是一个128位分组。这些分组被描述成4×4的字节方阵,这个分组被复制到数组中,并在加密和解密的每一阶段都被修改。在字节方阵中,每一格都是一个字,包含了4字节。在矩阵中字是按列排序的。
    加密由N轮构成,轮数依赖于密钥长度:16字节密钥对应10轮,24字节密钥对应12轮,32字节对应14轮。

    AES加密模式

    1.电码本模式(Electronic Codebook Book (ECB)

    ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。

    2.密码分组链接模式(Cipher Block Chaining (CBC))

    这种模式是先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。

    3.密码反馈模式(Cipher FeedBack (CFB))
    隐藏了明文模式,分组密码转化为流模式,可以及时加密传送小于分组的数据

    4.OFB(Output FeedBack,输出反馈)模式
    隐藏了明文模式;,分组密码转化为流模式,可以及时加密传送小于分组的数据

    AES填充方式
    AES支持支持几种填充:NoPadding,PKCS5Padding,ISO10126Padding,PaddingMode.Zeros,PaddingMode.PKCS7。对于AES来说PKCS5Padding和PKCS7Padding是完全一样的,不同在于PKCS5限定了块大小为8bytes而PKCS7没有限定。因此对于AES来说两者完全相同

    Golang实现AES加密解密

    下面附上Golang实现AES加密ECB模式的源码:

    package main
    import (
    	"bytes"
    	"crypto/aes"
    	"fmt"
    	"testing"
    )
    
    //ECB模式解密
    func ECBDecrypt(crypted, key []byte) ([]byte, error) {
    	if !validKey(key) {
    		return nil, fmt.Errorf("秘钥长度错误,当前传入长度为 %d",len(key))
    	}
    	if len(crypted) < 1 {
    		return nil, fmt.Errorf("源数据长度不能为0")
    	}
    	block, err := aes.NewCipher(key)
    	if err != nil {
    		return nil, err
    	}
    	if len(crypted)%block.BlockSize() != 0 {
    		return nil, fmt.Errorf("源数据长度必须是 %d 的整数倍,当前长度为:%d",block.BlockSize(), len(crypted))
    	}
    	var dst []byte
    	tmpData := make([]byte, block.BlockSize())
    
    	for index := 0; index < len(crypted); index += block.BlockSize() {
    		block.Decrypt(tmpData, crypted[index:index+block.BlockSize()])
    		dst = append(dst, tmpData...)
    	}
    	dst, err = PKCS5UnPadding(dst)
    	if err != nil {
    		return nil, err
    	}
    	return dst, nil
    }
    
    //ECB模式加密
    func ECBEncrypt(src, key []byte) ([]byte, error) {
    	if !validKey(key) {
    		return nil, fmt.Errorf("秘钥长度错误, 当前传入长度为 %d",len(key))
    	}
    	block, err := aes.NewCipher(key)
    	if err != nil {
    		return nil, err
    	}
    	if len(src) < 1 {
    		return nil, fmt.Errorf("源数据长度不能为0")
    	}
    	src = PKCS5Padding(src, block.BlockSize())
    	if len(src)%block.BlockSize() != 0 {
    		return nil, fmt.Errorf("源数据长度必须是 %d 的整数倍,当前长度为:%d",block.BlockSize(), len(src))
    	}
    	var dst []byte
    	tmpData := make([]byte, block.BlockSize())
    	for index := 0; index < len(src); index += block.BlockSize() {
    		block.Encrypt(tmpData, src[index:index+block.BlockSize()])
    		dst = append(dst, tmpData...)
    	}
    	return dst, nil
    }
    
    // PKCS5填充
    func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
    	padding := blockSize - len(ciphertext)%blockSize
    	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    	return append(ciphertext, padtext...)
    }
    
    // 去除PKCS5填充
    func PKCS5UnPadding(origData []byte) ([]byte, error) {
    	length := len(origData)
    	unpadding := int(origData[length-1])
    
    	if length < unpadding {
    		return nil, fmt.Errorf("invalid unpadding length")
    	}
    	return origData[:(length - unpadding)], nil
    }
    
    // 秘钥长度验证
    func validKey(key []byte) bool {
    	k := len(key)
    	switch k {
    	default:
    		return false
    	case 16, 24, 32:
    		return true
    	}
    }
    
    func TestAes(t *testing.T){
    	srcData := "hello world !"
    	key := []byte("abcdabcdabcdabcdabcdabcdabcdabcd")
    	//测试加密
    	encData ,err := ECBEncrypt([]byte(srcData),(key))
    	if err != nil {
    		t.Errorf(err.Error())
    		return
    	}
    
    	//测试解密
    	decData ,err := ECBDecrypt(encData,key)
    	if err != nil {
    		t.Errorf(err.Error())
    		return
    	}
    	t.Log(string(decData))
    }
    js
    下一篇:没有了