对称加密算法和分组密码的模式

  • 对称加密算法,即加密和解密使用一样的密钥的加解密算法。
  • 分组密码(block cipher),是每次只能处理特定长度的一块(block)数据的一类加解密算法。
  • 目前常见的对称加密算法DES、3DES、AES都是属于分组密码。

DES

  • DES,全称Data Encryption Standard,是上一代标准对称加密算法,现已不推荐使用
  • 密钥:DES是一种将64bit的明文加密成64bit的密文的对称密码算法,它的密钥长度是64bit(每隔7bit会设置一个用于错误检查的bit,因此实际使用密钥长度56bit)。
  • 分组:DES是以64bit的明文作为一个单位来进行加密的,这64bit的单位称为分组。一般来说,以分组为单位进行处理的密码算法称为分组密码(block cipher),DES就是分组密码中的一种。DES每次只能加密64比特的数据,如果要加密的明文比较长,就需要对DES加密进行迭代。

DES加密

DES解密

3DES

  • 3DES,即triple-DES,简单地说就是3次DES加解密的组合。现已不推荐使用。
  • 加密:cipthertext = E(k3, D(k2, E(k1, plaintext)))
  • 解密:plaintext = D(k1, E(k2, D(k3, ciphertext)))
  • 特点:如果三个密钥都一样,拿刚好和DES一样。

注:E表示Encrypt,D表示Decrypt。

3DES加密

3DES解密

AES

  • AES, Advanced Encryption Standard,是现行的对称加密标准。目前(2017)如果使用对称加密,应该使用AES。当然,只能说当前AES算法是安全的,不能保证AES永远都是安全的。
  • 分组:128bit。
  • 密钥:128bit、192bit、256bit。

分组密码的模式

分组密码简介

  • 分组密码(block cipher),是每次只能处理特定长度的一块数据的一类密码算法,这里的“一块”就称为分组(block)。一个分组的比特数就称为分组长度(block length)。
  • 流密码(stream cipher),是对数据流进行连续处理的一类密码算法。
  • DES、3DES、AES等大多数对称密码算法都属于分组密码。

ECB模式

  • 全称Electronic CodeBook mode,电子密码本模式。
  • 分组方式:将明文分组加密之后的结果直接称为密文分组。
  • 优点:
    • 一个分组损坏不影响其它分组。
    • 可以并行加解密。
  • 缺点:
    • 相同的明文分组会转换为相同的密文分组。
    • 无需破译密码就能操纵明文(每个分组独立且前后文无关,直接增加或删除一个分组不影响其它分组解密过程的正确性)。

ECB加密

ECB解密

CBC模式

  • 全称Cipher Block Chaining mode,密码分组链接模式。
  • 分组方式:将明文分组与前一个密文分组进行XOR运算,然后再进行加密。每个分组的加解密都依赖于前一个分组。而第一个分组没有前一个分组,因此需要一个初始化向量(initialization vector)。
  • 优点:
    • 加密结果与前文相关,有利于提高加密结果的随机性。
    • 可并行解密。
  • 缺点
    • 无法并行加密。
    • 一个分组损坏,如果密文长度不变,则两个分组受影响。
    • 一个分组损坏,如果密文长度改变,则后面所有分组受影响。

CBC加密

CBC解密

CFB模式

  • 全称Cipher FeedBack mode,密文反馈模式。
  • 分组方式:前一个密文分组会被送回到密码算法的输入端(具体见下图)。
  • 在CBC和EBC模式中,明文分组都是通过密码算法进行加密的。而在CFB模式中,明文分组并没有通过加密算法直接进行加密,明文分组和密文分组之间只有一个XOR。
  • CFB模式是通过将“明文分组”与“密码算法的输出”进行XOR运行生成“密文分组”。CFB模式中由密码算法生成的比特序列称为密钥流(key stream)。密码算法相当于密钥流的伪随机数生成器,而初始化向量相当于伪随机数生成器的种子。(CFB模式有点类似一次性密码本。)
  • 优点:
    • 支持并行解密。
    • 不需要填充(padding)。
  • 缺点:
    • 不能抵御重放攻击(replay attack)。
    • 不支持并行加密。

CFB加密

CFB解密

OFB模式

  • Output FeedBack mode 输出反馈模式
  • 密码算法的输出会反馈到密码算法的输入中(具体见下图)。
  • OFB模式中,XOR所需的比特序列(密钥流)可以事先通过密码算法生成,和明文分组无关。只需要提前准备好所需的密钥流,然后进行XOR运算就可以了。

OFB加密

OFB解密

分组模式小结

推荐使用CBC模式。

填充

  • 为什么要填充? ECB和CBC模式要求明文数据必须填充至长度为分组长度的整数倍。
  • 填充的两个问题。
    • 填充多少字节?
    • 填充什么内容?
  • 填充多少字节? 需要填充的字节数为:paddingSize = blockSize - textLength % blockSize
  • 填充什么内容?(这里列举的三种方式本质上是一致的)
    • ANSI X.923:填充序列的最后一个字节填paddingSize,其它填0。
    • ISO 10126:填充序列的最后一个字节填paddingSize, 其它填随机数。
    • PKCS7:填充序列的每个字节都填paddingSize

示例

这里用golang写一个AES加密的例子。

由于加密出来的数据很可能有很多不可见字符,因此这里会将加密后的结果进行一次Base64Encode。

这里采用CBC模式+PKCS7填充方式。

package main

import (
    "bytes"
    "crypto/cipher"
    "crypto/aes"
    "encoding/base64"
    "fmt"
)

func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext) % blockSize
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

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

func AesEncrypt(origData, key []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    blockSize := block.BlockSize()
    origData = PKCS7Padding(origData, blockSize)
    blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
    crypted := make([]byte, len(origData))
    blockMode.CryptBlocks(crypted, origData)
    return crypted, nil
}

func AesDecrypt(crypted, key []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    blockSize := block.BlockSize()
    blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
    origData := make([]byte, len(crypted))
    blockMode.CryptBlocks(origData, crypted)
    origData = PKCS7UnPadding(origData)
    return origData, nil
}

func main() {
    key := []byte("0123456789abcdef")
    result, err := AesEncrypt([]byte("hello world"), key)
    if err != nil {
        panic(err)
    }
    fmt.Println(base64.StdEncoding.EncodeToString(result))
    origData, err := AesDecrypt(result, key)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(origData))
}

参考文档

  • 《图解密码学》
  • 维基百科

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏linjinhe的专栏

密码学工具箱

对称加密算法(Symmetric-key_algorithm)是指在加密和解密时使用同一密钥的方式,如AES。

26030
来自专栏V站

php中常用的Rc4/Des/AuthCode可逆加密函数

首先是AuthCode可逆加密函数,在dz论坛等各大程序的数据传输和登陆验证都有用到。

30850
来自专栏杨逸轩 ' sBlog

Java实现微信跳一跳抓包修改分数

43260
来自专栏IT笔记

JAVA版微信小程序用户数据的签名验证和加解密

签名验证和加解密 数据签名校验 为了确保 开放接口 返回用户数据的安全性,微信会对明文数据进行签名。开发者可以根据业务需要对数据包进行签名校验,确保数据的完整性...

69650
来自专栏Scott_Mr 个人专栏

RxSwift 系列(五) -- Filtering and Conditional Operators

36370
来自专栏Python疯子

python hashlib模块

hashlib主要提供字符加密功能,将md5和sha模块整合到了一起,支持md5,sha1, sha224, sha256, sha384, sha512等算法

15020
来自专栏安恒网络空间安全讲武堂

学习分享 | Flipped Ciphertext Bits

0x00前言 这次蓝盾杯线上赛遇到了一题类似于NJCTF的CBC翻转攻击的题目,不过题目被改简单了,省去了最开始的Padding Oracle攻击部分,直接给出...

38680
来自专栏Java技术栈

常用加密算法解析

今天介绍下工作当中常用的加密算法、分类、应用。 1、对称加密算法 所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过...

75170
来自专栏安恒网络空间安全讲武堂

学习分享 | Padding Oracle

0x00前言 之前写CBC翻转攻击的时候就在想什么时候能遇到Padding Oracle的题目hhhhh 想不到这么快就遇到了hhhhh ------- 0x0...

24380
来自专栏葡萄城控件技术团队

Silverlight中非对称加密及数字签名RSA算法的实现

RSA算法是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。它的安全性是基于大整数素因子分解的困难性,而大整数因子分解问题是数学上的著...

24980

扫码关注云+社区

领取腾讯云代金券