美文网首页
对称加密算法以及使用方法

对称加密算法以及使用方法

作者: Winnifred_ | 来源:发表于2018-10-09 19:08 被阅读0次

    加密的原因:保证数据安全

    加密必备要素:1、明文/密文    2、秘钥    3、算法

    秘钥:在密码学中是一个定长的字符串、需要根据加密算法确定其长度

    加密算法解密算法一般互逆、也可能相同

    常用的两种加密方式:

    对称加密:秘钥:加密解密使用同一个密钥、数据的机密性双向保证、加密效率高、适合加密于大数据大文件、加密强度不高(相对于非对称加密)

    非对称加密:秘钥:加密解密使用的不同秘钥、有两个密钥、需要使用密钥生成算法生成两个秘钥、数据的机密性只能单向加密、如果想解决这个问题、双向都需要各自有一对秘钥、加密效率低、加密强度高

                        公钥:可以公开出来的密钥、公钥加密私钥解密

                        私钥:需要自己妥善保管、不能公开、私钥加密公钥解密

    安全程度高:多次加密

    按位异或运算

    凯撒密码:加密方式    通过将铭文所使用的字母表按照一定的字数平移来进行加密

    加密为向右平移三个字符 算法为

    mod:取余

    加密三要素:明文/密文(字母)、秘钥(3)、算法(向右平移3/-3)

    安全常识:不要使用自己研发的算法、不要钻牛角尖、没必要研究底层实现、了解怎么应用;低强度的密码比不进行任何加密更危险;任何密码都会被破解;密码只是信息安全的一部分

    保证数据的机密性、完整性、认证、不可否认性

    计算机操作对象不是文字、而是由0或1排列而成的比特序列、程序存储在磁盘是二进制的字符串、为比特序列、将现实的东西映射为比特序列的操作称为编码、加密又称之为编码、解密称之为解码、根据ASCII对照表找到对应的数字、转换成二进制

    三种对称加密算法:DES\3DES\ AES  

    DES:已经被破解、除了用它来解密以前的明文、不再使用

    密钥长度为56bit/8、为7byte、每隔7个bit会设置一个用于错误检查的比特、因此实际上是64bit

    分组密码(以组为单位进行处理):加密时是按照一个单位进行加密(8个字节/64bit为一组)、每一组结合秘钥通过加密算法得到密文、加密后的长度不变

    3DES:三重DES为了增加DES的强度、将DES重复三次所得到的一种加密算法   密钥长度24byte、分成三份  加密--解密--加密 目的:为了兼容DES、秘钥1秘钥2相同==三个秘钥相同  ---加密一次        密钥1秘钥3相同--加密三次    三个密钥不相同最好、此时解密相当于加密、中间的一次解密是为了有三个密钥相同的情况

    此时的解密操作与加密操作互逆,安全、效率低

    数据先解密后加密可以么?可以、解密相当于加密、加密解密说的是算法

    AES:(首选推荐)底层算法为Rijndael   分组长度为128bit、密钥长度为128bit到256bit范围内就可以   但是在AES中、密钥长度只有128bit\192bit\256bit     在go提供的接口中、只能是16字节(128bit)、其他语言中秘钥可以选择

    目前为止最安全的、效率高

    底层算法

    分组密码的模式:

    按位异或、对数据进行位运算、先将数据转换成二进制、按位异或操作符^、相同为真、不同为假、非0为假    按位异或一次为加密操作、按位异或两次为解密操作:a和b按位异或一次、结果再和b按位异或

    ECB : 如果明文有规律、加密后的密文有规律不安全、go里不提供该接口、明文分组分成固定大小的块、如果最后一个分组不满足分组长度、则需要补位

    CBC:密码链

    问题:如何对字符串进行按位异或?解决了ECB的规律可查缺点、但是他不能并行处理、最后一个明文分组也需要填充 、初始化向量长度与分组长度相同

    CFB:密文反馈模式

    不需要填充最后一个分组、对密文进行加密

    OFB:

    不需要对最后一组进行填充

    CTR计数器:

    不需要对最后一组进行填充、不需要初始化向量     

    Go中的实现

    官方文档中:

    在创建aes或者是des接口时都是调用如下的方法、返回的block为一个接口

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

    type Block interface {

        // 返回加密字节块的大小

        BlockSize() int

        // 加密src的第一块数据并写入dst,src和dst可指向同一内存地址

        Encrypt(dst, src []byte)

        // 解密src的第一块数据并写入dst,src和dst可指向同一内存地址

        Decrypt(dst, src []byte)

    }

    Block接口代表一个使用特定密钥的底层块加/解密器。它提供了加密和解密独立数据块的能力。

    Block的Encrypt/Decrypt也能进行加密、但是只能加密第一组、因为aes的密钥长度为16、所以进行操作的第一组数据长度也是16

    如果分组模式选择的是cbc

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

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

    加密解密都调用同一个方法CryptBlocks()

    并且cbc分组模式都会遇到明文最后一个分组的补充、所以会用到加密字节的大小

    返回一个密码分组链接模式的、底层用b加密的BlockMode接口,初始向量iv的长度必须等于b的块尺寸。iv自己定义

    返回的BlockMode同样也是一个接口类型

    type BlockMode interface {

        // 返回加密字节块的大小

        BlockSize() int

        // 加密或解密连续的数据块,src的尺寸必须是块大小的整数倍,src和dst可指向同一内存地址

        CryptBlocks(dst, src []byte)

    }

    BlockMode接口代表一个工作在块模式(如CBC、ECB等)的加/解密器

    返回的BlockMode其实是一个cbc的指针类型中的b和iv

    # 加密流程: 

    1. 创建一个底层使用des/3des/aes的密码接口 "crypto/des" func NewCipher(key []byte) (cipher.Block, error) # -- des func NewTripleDESCipher(key []byte) (cipher.Block, error) # -- 3des "crypto/aes" func NewCipher(key []byte) (cipher.Block, error) # == aes 

    2. 如果使用的是cbc/ecb分组模式需要对明文分组进行填充

    3. 创建一个密码分组模式的接口对象 - cbc func NewCBCEncrypter(b Block, iv []byte) BlockMode # 加密 - cfb func NewCFBEncrypter(block Block, iv []byte) Stream # 加密 - ofb - ctr

     4. 加密, 得到密文

    流程:

    填充明文:

    先求出最后一组中的字节数、创建新切片、长度为新切片、值也为切片的长度、然后利用bytes.Reapet将长度换成字节切片、追加到原明文中

    //明文补充

    func padPlaintText(plaintText []byte,blockSize int)[]byte{

        //1、求出需要填充的个数

        padNum := blockSize-len(plaintText) % blockSize

        //2、对填充的个数进行操作、与原明文进行合并

        newPadding := []byte{byte(padNum)}

        newPlain := bytes.Repeat(newPadding,padNum)

        plaintText = append(plaintText,newPlain...)

        return plaintText

    }

    去掉填充数据:

    拿去切片中的最后一个字节、得到尾部填充的字节个数、截取返回

    //解密后的明文曲调补充的地方

    func createPlaintText(plaintText []byte,blockSize int)[]byte{

        //1、得到最后一个字节、并将字节转换成数字、去掉明文中此数字大小的字节

        padNum := int(plaintText[len(plaintText)-1])

        newPadding := plaintText[:len(plaintText)-padNum]

        return newPadding

    }

    des加密:

    1、创建一个底层使用des的密码接口、参数为秘钥、返回一个接口

    2、对明文进行填充

    3、创建一个cbc模式的接口、需要创建iv初始化向量、返回一个blockmode对象

    4、加密、调用blockmode中的cryptBlock函数进行加密、参数为目标参数和源参数

    //des利用分组模式cbc进行加密

    func EncryptoText(plaintText []byte,key []byte)[]byte{

        //1、创建des对象

        cipherBlock,err := des.NewCipher(key)

        if err != nil {

            panic(err)

        }

        //2、对明文进行填充

        newText := padPlaintText(plaintText,cipherBlock.BlockSize())

        //3、选择分组模式、其中向量的长度必须与分组长度相同

        iv := make([]byte,cipherBlock.BlockSize())

        blockMode := cipher.NewCBCEncrypter(cipherBlock,iv)

        //4、加密

        blockMode.CryptBlocks(newText,newText)

        return newText

    }

    des解密:

    1、创建一个底层使用des的密码接口、参数为秘钥、返回一个接口

    2、创建一个cbc模式的接口、需要创建iv初始化向量,返回一个blockmode对象

    3、加密、调用blockmode中的cryptBlock函数进行解密、参数为目标参数和源参数

    4、调用去掉填充数据的方法

    //des利用分组模式cbc进行解密

    func DecryptoText(cipherText []byte, key []byte)[]byte{

        //1、创建des对象

        cipherBlock,err := des.NewCipher(key)

        if err != nil {

            panic(err)

        }

        //2、创建cbc分组模式接口

        iv := []byte("12345678")

        blockMode := cipher.NewCBCDecrypter(cipherBlock,iv)

        //3、解密

        blockMode.CryptBlocks(cipherText,cipherText)

        //4、将解密后的数据进行去除填充的数据

        newText := clearPlaintText(cipherText,cipherBlock.BlockSize())

        return newText

    }

    Main函数调用

    func main(){

        //需要进行加密的明文

        plaintText := []byte("CBC--密文没有规律、经常使用的加密方式,最后一个分组需要填充,需要初始化向量" +

            "(一个数组、数组的长度与明文分组相等、数据来源:负责加密的人提供,加解密使用的初始化向量必须相同)")

        //密钥Key的长度需要与分组长度相同、且加密解密的密钥相同

        key := []byte("1234abcd")

        //调用加密函数

        cipherText := EncryptoText(plaintText,key)

        newPlaintText := DecryptoText(cipherText,key)

        fmt.Println(string(newPlaintText))

    }

    AES加密解密相同、所以只需要调用一次方法就可以加密、调用两次则解密

    推荐是用分组模式:cbc、ctr

    aes利用分组模式cbc进行加密

    //对明文进行补充

    func paddingPlaintText(plaintText []byte , blockSize int ) []byte {

        //1、求出分组余数

        padNum := blockSize - len(plaintText) % blockSize

        //2、将余数转换为字节切片、然后利用bytes.Repeat得出有该余数的大小的字节切片

        padByte := bytes.Repeat([]byte{byte(padNum)},padNum)

        //3、将补充的字节切片添加到原明文中

        plaintText = append(plaintText,padByte...)

        return plaintText

    }

    //aes加密

    func encryptionText(plaintText []byte, key []byte) []byte {

        //1、创建aes对象

        block,err := aes.NewCipher(key)

        if err != nil {

            panic(err)

        }

        //2、明文补充

        newText := paddingPlaintText(plaintText,block.BlockSize())

        //3、创建cbc对象

        iv := []byte("12345678abcdefgh")

        blockMode := cipher.NewCBCEncrypter(block,iv)

        //4、加密

        blockMode.CryptBlocks(newText,newText)

        return newText

    }

    //解密后的去尾

    func clearplaintText(plaintText []byte, blockSize int) []byte {

        //1、得到最后一个字节、并转换成整型数据

        padNum := int(plaintText[len(plaintText)-1])

        //2、截取明文字节中去掉得到的整型数据之前的数据、此处出错、没有用len-padNum

        newText := plaintText[:len(plaintText)-padNum]

        return newText

    }

    //aes解密

    func deCryptionText(crypherText []byte, key []byte ) []byte {

        //1、创建aes对象

        block, err := aes.NewCipher(key)

        if err != nil {

            panic(err)

        }

        //2、创建cbc对象

        iv := []byte("12345678abcdefgh")

        blockMode := cipher.NewCBCDecrypter(block,iv)

        //3、解密

        blockMode.CryptBlocks(crypherText,crypherText)

        //4、去尾

        newText := clearplaintText(crypherText,block.BlockSize())

        return newText

    }

    func main(){

        //需要进行加密的明文

        plaintText := []byte("CBC--密文没有规律、经常使用的加密方式,最后一个分组需要填充,需要初始化向量")

        //密钥Key的长度需要与分组长度相同、且加密解密的密钥相同

        key := []byte("12345678abcdefgh")

        //调用加密函数

        cipherText := encryptionText(plaintText,key)

        //调用解密函数

        newPlaintText := deCryptionText(cipherText,key)

        fmt.Println("解密后",string(newPlaintText))

    }

    //aes--ctr加密

    func encryptionCtrText(plaintText []byte, key []byte) []byte {

        //1、创建aes对象

        block,err := aes.NewCipher(key)

        if err != nil {

            panic(err)

        }

        //2、创建ctr对象,虽然ctr模式不需要iv,但是go中使用ctr时还是需要iv

        iv := []byte("12345678abcdefgh")

        stream := cipher.NewCTR(block,iv)

        stream.XORKeyStream(plaintText,plaintText)

        return plaintText

    }

    func main() {

    //aes--ctr加密解密、调用两次即为解密、因为加密解密函数相同stream.XORKeyStream

        ctrcipherText := encryptionCtrText(plaintText, key)

        ctrPlaintText := encryptionCtrText(ctrcipherText,key)

        fmt.Println("aes解密后", string(ctrPlaintText))

    }

    英文单词:

    明文:plaintext     密文:ciphertext   填充:padding/fill    去掉clear  加密Encryption  解密Decryption

    相关文章

      网友评论

          本文标题:对称加密算法以及使用方法

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