美文网首页Go进阶系列
6 Go 密码学(三)对称加密 DES、TDES、AES

6 Go 密码学(三)对称加密 DES、TDES、AES

作者: GoFuncChan | 来源:发表于2019-07-09 00:52 被阅读0次

    一、对称加密概述

    我们在开发中常会遇到这种需求:通信的两端需要传输安全级别较高的数据,这需要我们传输的加密数据既要难以破解,又要可逆的解密过程。哈希算法虽难以破解,但并非适用于通信中的加解密传输。这就需要基于秘钥管理的加密技术了。对称加密是最简单快速的加密方式,所谓对称加密,即加解密双方都掌握相同的秘钥,通过同一秘钥完成加解密操作。常用的对称加密算法有:

    • DES:Data Encryption Standard,即数据加密标准;
    • TDES(TripleDES) :三重DES;
    • AES:Rijndael加密法,Advanced Encryption Standard高级加密标准。

    Go标准库中的加密相关包都有相应的支持,下面我们来逐一演示:

    二、DES对称加密

    DES算法原理:明文按64位进行分组,密钥长64位,密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位, 使得每个密钥都有奇数个1)分组后的明文组和56位的密钥按位替代或交换的方法形成密文组的加密方法。

    所以要实现DES加密需要准备如下要求:

    • ==准备一个8字节(64Bit)的秘钥==;
    • 原文需要按8字节(64Bit)长度进行分组,共有五种分组模式,此处我们不具体展开,我们用常用的CBC(密码分组链接模式),这种模式需要一个与分组长度相同的初始化向量,有兴趣的可搜索了解其他模式;
    • 对末尾的未够8字节的数据进行填充,把原文转为64Bit的整数倍;
    • ==实现加密时的未位分组填充算法和解密时的删除密文末尾分组算法。==

    以上,秘钥和初始化向量值需要自己管理,末尾分组的填充算法和删除算法需要自己实现。下面我们实现一个填充算法和删除算法:

    //填充明文最后一个分组工具方法
    //src - 原始数据
    //blockSize - 每个分组的数据长度
    func paddingBytes(src []byte, blockSize int) []byte {
        //1.求出最后一个分组要填充多个字节
        padding := blockSize - len(src)%blockSize
        //2.创建新的切片,切片的字节数为填充的字节数,并初始化化,每个字节的值为填充的字节数
        padBytes := bytes.Repeat([]byte{byte(padding)}, padding)
        //3.将创建出的新切片和原始数据进行连接
        newBytes := append(src, padBytes...)
    
        //4.返回新的字符串
        return newBytes
    }
    
    //删除密文末尾分组填充的工具方法
    func unPaddingBytes(src []byte) []byte {
        //1.求出要处理的切片的长度
        l := len(src)
        //2.取出最后一个字符,得到其整型值
        n := int(src[l-1])
    
        //3.将切片末尾的number个字节删除
        return src[:l-n]
    }
    
    

    以上实现思路为:计算出最后一个分组需要填充的字节数(1-8),并把这个数作为需要填充的占位符,再把填充后的分组与源数据拼接就得到待加密的字符串。

    Go通过crypto/des包支持DES加密算法:

    
    import (
        "bytes"
        "crypto/cipher"
        "crypto/des"
    )
    
    const (
        MYKEY = "abcdefgh" //八字节密匙
        IV    = "aaaabbbb" //CBC模式的初始化向量
    )
    
    
    
    //使用des进行对称加密
    func EncryptDES(src, key []byte) []byte {
        //1. 创建并返回一个使用DES算法的cipher.Block接口
        block, err := des.NewCipher([]byte(key))
        if err != nil {
            panic(err)
        }
        //2. 对最后一个明文分组进行数据填充
        src = paddingBytes(src, block.BlockSize())
        //3. 创建一个密码分组为链接模式的,底层使用DES加密的BlockMode接口
        cbcDecrypter := cipher.NewCBCEncrypter(block, []byte(IV))
        //4. 加密连续的数据并返回
        dst := make([]byte, len(src))
        cbcDecrypter.CryptBlocks(dst, src)
    
        return dst
    }
    
    //使用des进行解密
    func DecryptDES(src, key []byte) []byte {
        //1. 创建并返回一个使用DES算法的cipher.Block接口
        block, err := des.NewCipher(key)
        if err != nil {
            panic(err)
        }
        //2. 创建一个密码分组为链接模式的,底层使用DES解密的BlockMode接口
        cbcDecrypter := cipher.NewCBCDecrypter(block, []byte(IV))
        //3. 数据块解密
        dst := make([]byte, len(src))
        cbcDecrypter.CryptBlocks(dst, src)
        //4. 去掉最后一组填充数据
        newBytes := unPaddingBytes(dst)
        return newBytes
    }
    
    

    使用以上加解密方法:

    //测试DES加解密算法
    func TestDES() {
        fmt.Println("测试DES对称加密:")
        srcString := "GO 密码学 —— DES对称加密实现"
        //加密
        cryptBytes := myDES.EncryptDES([]byte(srcString), []byte(myDES.MYKEY))
        fmt.Println("加密效果:")
        fmt.Println("src :", hex.EncodeToString([]byte(srcString)), "[]byte长度:", len([]byte(srcString)))
        fmt.Println("dst :", hex.EncodeToString(cryptBytes), "[]byte长度:", len(cryptBytes))
        fmt.Println()
    
        //解密
        deCryptBytes := myDES.DecryptDES(cryptBytes, []byte(myDES.MYKEY))
        fmt.Println("解密效果:")
        fmt.Println("src :", hex.EncodeToString(cryptBytes), "[]byte长度:", len(cryptBytes))
        fmt.Println("dst :", hex.EncodeToString(deCryptBytes), "[]byte长度:", len(deCryptBytes))
    
        fmt.Println()
        fmt.Println("原字串为:" + srcString)
        fmt.Println("解密字符为:" + string(deCryptBytes))
    }
    
    //OUTPUT:
    测试DES对称加密:
    加密效果:
    src : 474f20e5af86e7a081e5ada620e28094e2809420444553e5afb9e7a7b0e58aa0e5af86e5ae9ee78eb0 []byte长度: 41
    dst : e50636c0545eb031b3b36d363c050deb0640806475b04da4e5b54641eb635b1394d70f86c12f4119319904475235d441 []byte长度: 48
    
    解密效果:
    src : e50636c0545eb031b3b36d363c050deb0640806475b04da4e5b54641eb635b1394d70f86c12f4119319904475235d441 []byte长度: 48
    dst : 474f20e5af86e7a081e5ada620e28094e2809420444553e5afb9e7a7b0e58aa0e5af86e5ae9ee78eb0 []byte长度: 41
    
    原字串为:GO 密码学 —— DES对称加密实现
    解密字符为:GO 密码学 —— DES对称加密实现
    
    

    以上就是Go 中DES的加解密实现,可见其加密的安全性依赖于秘钥的管理,而且其只有64Bit的秘钥长度在算力越来越高的现在已经不够安全了,这也是对称加密的弱点,在实际的网络项目中,秘钥的分发需要依赖其他方式的配合。

    三、TDES(TripleDES)对称加密

    对于DES秘钥较弱的问题做了一些改进,这就是三重DES加密算法,其原理与DES类似,唯一不同的是秘钥从一组八字节变成三组二十四字节(192Bit)。其加密强度也和秘钥设置相关,此处演示我们也用CBC分组模式,三重加密执行顺序分别为,加密->解密->加密。

    为了兼容DES,只有当秘钥一组和秘钥二组相同时,3DES其加密安全性和DES相同,其余秘钥的分组设置都是三重DES加密。

    import (
        "bytes"
        "crypto/cipher"
        "crypto/des"
    )
    
    const (
        MYKEY = "abcdefgh12345678ABCDEFGH" //三组八字节密匙,即24字节
        IV    = "aaaabbbb"                 //CBC模式的初始化向量,8字节
    )
    
    //使用3des进行对称加密
    func EncryptTDES(src, key []byte) []byte {
        //1. 创建并返回一个使用DES算法的cipher.Block接口
        block, err := des.NewTripleDESCipher([]byte(key))
        if err != nil {
            panic(err)
        }
        //2. 对最后一个明文分组进行数据填充,和DES的算法一样
        src = paddingBytes(src, block.BlockSize())
        //3. 创建一个密码分组为链接模式的,底层使用DES加密的BlockMode接口
        cbcDecrypter := cipher.NewCBCEncrypter(block, []byte(IV))
        //4. 加密连续的数据并返回
        dst := make([]byte, len(src))
        cbcDecrypter.CryptBlocks(dst, src)
    
        return dst
    }
    
    //使用3des进行解密
    func DecryptTDES(src, key []byte) []byte {
        //1. 创建并返回一个使用DES算法的cipher.Block接口
        block, err := des.NewTripleDESCipher(key)
        if err != nil {
            panic(err)
        }
        //2. 创建一个密码分组为链接模式的,底层使用DES解密的BlockMode接口
        cbcDecrypter := cipher.NewCBCDecrypter(block, []byte(IV))
        //3. 数据块解密
        dst := make([]byte, len(src))
        cbcDecrypter.CryptBlocks(dst, src)
        //4. 去掉最后一组填充数据,和DES的删除算法一样
        newBytes := unPaddingBytes(dst)
        return newBytes
    }
    
    

    使用以上加解密方法:

    //测试三重DES对称加密算法
    func TestTDES() {
        fmt.Println("测试TDES对称加密:")
        srcString := "GO 密码学 —— TDES对称加密实现"
        //加密
        cryptBytes := myTDES.EncryptTDES([]byte(srcString), []byte(myTDES.MYKEY))
        fmt.Println("加密效果:")
        fmt.Println("src :", hex.EncodeToString([]byte(srcString)), "[]byte长度:", len([]byte(srcString)))
        fmt.Println("dst :", hex.EncodeToString(cryptBytes), "[]byte长度:", len(cryptBytes))
        fmt.Println()
    
        //解密
        deCryptBytes := myTDES.DecryptTDES(cryptBytes, []byte(my3DES.MYKEY))
        fmt.Println("解密效果:")
        fmt.Println("src bytes:", hex.EncodeToString(cryptBytes), "[]byte长度:", len(cryptBytes))
        fmt.Println("dst bytes:", hex.EncodeToString(deCryptBytes), "[]byte长度:", len(deCryptBytes))
    
        fmt.Println()
        fmt.Println("原字串为:" + srcString)
        fmt.Println("解密字符为:" + string(deCryptBytes))
    }
    
    //OUTPUT:
    测试TDES对称加密:
    加密效果:
    src : 474f20e5af86e7a081e5ada620e28094e280942033444553e5afb9e7a7b0e58aa0e5af86e5ae9ee78eb0 []byte长度: 42
    dst : 41da5be3a5b9f05438c2896173d141f43c7b12168e80ef299b35a46b76799ab0d3c573f1fc544a6ec3a135f4d5b912ba []byte长度: 48
    
    解密效果:
    src bytes: 41da5be3a5b9f05438c2896173d141f43c7b12168e80ef299b35a46b76799ab0d3c573f1fc544a6ec3a135f4d5b912ba []byte长度: 48
    dst bytes: 474f20e5af86e7a081e5ada620e28094e280942033444553e5afb9e7a7b0e58aa0e5af86e5ae9ee78eb0 []byte长度: 42
    
    原字串为:GO 密码学 —— TDES对称加密实现
    解密字符为:GO 密码学 —— TDES对称加密实现
    
    

    四、AES对称加密

    随着时代的发展,DES和3DES于现今的算力和性能要求来说已经逐渐落伍,为了适应更高的安全性和性能需要,业界采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。这就是AES对称加密算法,在现今的项目开发中,建议使用这种加密方式。

    AES的基本要求是,采用对称分组密码体制,密钥的长度最少支持为128、192、256,分组长度128位。

    所以要实现AES加密需要准备如下要求:

    • ==准备一个十六字节(128Bit)的秘钥==;
    • 原文需要按十六字节(128Bit)长度进行分组,采用常用的CBC(密码分组链接模式),准备十六字节(128Bit)长度的初始化向量值;
    • ==实现加密时的未位分组填充算法和解密时的删除密文末尾分组算法。这里的填充和删除算法和DES相同,不再赘述==

    Go通过crypto/aes包支持DES加密算法:

    
    import (
        "bytes"
        "crypto/aes"
        "crypto/cipher"
    )
    
    const (
        MYKEY = "abcdefgh12345678" //十六字节密匙
        IV    = "aaaabbbb12345678" //CBC模式的初始化向量:与key等长:十六字节
    )
    
    
    
    //使用aes进行对称加密
    func EncryptAES(src, key []byte) []byte {
        //1. 创建并返回一个使用DES算法的cipher.Block接口
        block, err := aes.NewCipher([]byte(key))
        if err != nil {
            panic(err)
        }
        //2. 对最后一个明文分组进行数据填充
        src = paddingBytes(src, block.BlockSize())
        //3. 创建一个密码分组为链接模式的,底层使用DES加密的BlockMode接口
        cbcDecrypter := cipher.NewCBCEncrypter(block, []byte(IV))
        //4. 加密连续的数据并返回
        dst := make([]byte, len(src))
        cbcDecrypter.CryptBlocks(dst, src)
    
        return dst
    }
    
    //使用aes进行解密
    func DecryptAES(src, key []byte) []byte {
        //1. 创建并返回一个使用DES算法的cipher.Block接口
        block, err := aes.NewCipher(key)
        if err != nil {
            panic(err)
        }
        //2. 创建一个密码分组为链接模式的,底层使用DES解密的BlockMode接口
        cbcDecrypter := cipher.NewCBCDecrypter(block, []byte(IV))
        //3. 数据块解密
        dst := make([]byte, len(src))
        cbcDecrypter.CryptBlocks(dst, src)
        //4. 去掉最后一组填充数据
        newBytes := unPaddingBytes(dst)
        return newBytes
    }
    

    以上,其用法和DES差不多,只不过秘钥管理稍微不同而已。

    //测试AES对称加密算法
    func TestAES() {
        fmt.Println("测试AES对称加密:")
        srcString := "GO 密码学 —— AES对称加密实现"
        //加密
        cryptBytes := myAES.EncryptAES([]byte(srcString), []byte(myAES.MYKEY))
        fmt.Println("加密效果:")
        fmt.Println("src :", hex.EncodeToString([]byte(srcString)), "[]byte长度:", len([]byte(srcString)))
        fmt.Println("dst :", hex.EncodeToString(cryptBytes), "[]byte长度:", len(cryptBytes))
        fmt.Println()
    
        //解密
        deCryptBytes := myAES.DecryptAES(cryptBytes, []byte(myAES.MYKEY))
        fmt.Println("解密效果:")
        fmt.Println("src bytes:", hex.EncodeToString(cryptBytes), "[]byte长度:", len(cryptBytes))
        fmt.Println("dst bytes:", hex.EncodeToString(deCryptBytes), "[]byte长度:", len(deCryptBytes))
    
        fmt.Println()
        fmt.Println("原字串为:" + srcString)
        fmt.Println("解密字符为:" + string(deCryptBytes))
    }
    
    //OUTPUT:
    测试AES对称加密:
    加密效果:
    src : 474f20e5af86e7a081e5ada620e28094e2809420414553e5afb9e7a7b0e58aa0e5af86e5ae9ee78eb0 []byte长度: 41
    dst : 07a22e3059c8e9da2a3c1db2801b478a18f3ca7b33ace2f19931d2100a792681c61ac7ff3a61e0973be91638b3e9b1e1 []byte长度: 48
    
    解密效果:
    src bytes: 07a22e3059c8e9da2a3c1db2801b478a18f3ca7b33ace2f19931d2100a792681c61ac7ff3a61e0973be91638b3e9b1e1 []byte长度: 48
    dst bytes: 474f20e5af86e7a081e5ada620e28094e2809420414553e5afb9e7a7b0e58aa0e5af86e5ae9ee78eb0 []byte长度: 41
    
    原字串为:GO 密码学 —— AES对称加密实现
    解密字符为:GO 密码学 —— AES对称加密实现
    

    相关文章

      网友评论

        本文标题:6 Go 密码学(三)对称加密 DES、TDES、AES

        本文链接:https://www.haomeiwen.com/subject/gmazhctx.html