Cryptographic security theory and development Part 1—Preliminary explanation of common symmetric encryption

1 The concept of coding 

The operation of mapping something in the real world into a sequence of bits is called encoding .

The computer's operating object is not text, but a sequence of bits arranged by 0 and 1 .

Example : h converted to bit sequence 

h ->int 104 (decimal ASCII code) ->0110 1000

Send to ACSII code comparison table

G = 1024m

m = 1024kbyte

byte = 8bit

bit 0/1

The encryption process can be called encoding , and decryption is decoding .

2 DES -- Data Encryption Standard

It’s unreliable now! ! !

2.1 What is DES?

DES (Data Encryption Standard) is a symmetric encryption (FIPS46.3) adopted in the 1977 U.S. Federal Information Processing Standard (FIPS). DES has been widely used by governments and banks in the United States and other countries. However, with the advancement of computers, DES can now be cracked by brute force, and its strength is not as strong as before.

RSA Company has held a competition (DESChallenge) to break the DES key. We can take a look at the official results of the competition announced by RSA Company:

  • It took 96 days to crack the key in DES Challenge 1 in 1997

  • It took 41 days to crack the key in the 1998 DES Challenge Il-I

  • It took 56 hours to decipher the key in the 1998 DES Challenge II-2

  • It took only 22 hours and 15 minutes to crack the key in the 1999 DES ChallengeIll

Since DES ciphertext can be deciphered in a short time, we should not use DES now except to use it to decrypt previous ciphertext .

2.2 Encryption and decryption

DES is a symmetric encryption algorithm that encrypts 64-bit plaintext into 64-bit ciphertext. Its key length is 56 bits. Although DES's key length is technically 64 bits, since every 7 bits are set for error checking, the key length is actually 56 bits .

DES encrypts 64-bit plaintext (bit sequence) as a unit , and this 64-bit unit is called a packet . Generally speaking, a cryptographic algorithm that processes in groups is called a block cipher , and DES is a type of block cipher.

DES can only encrypt 64 bits of data at a time. If the plaintext to be encrypted is relatively long, the DES encryption needs to be iterated (repeatedly), and the specific method of iteration is called mode.

legend:

 Note : The DES group length is 8byte = 64bit, which is divided into 8 groups. The key length is 56bit. The extra 8bits are one error detection flag for each group.

2.3 Operation of DES in go

This algorithm is now very easy to crack. Please do not use this algorithm. The code part is used to understand the principle.

 2.3.1 Encryption and decryption implementation ideas

 2.3.2 Encryption and decryption code implementation

Packages that need to be imported to use DES in Go:

import (
	"crypto/des"
	"crypto/cipher"
	"fmt"
	"bytes"
)

 DES encryption code:

// src -> 要加密的明文
// key -> 秘钥, 大小为: 8byte
func DesEncrypt_CBC(src, key []byte) []byte{
	// 1. 创建并返回一个使用DES算法的cipher.Block接口
	block, err := des.NewCipher(key)
	// 2. 判断是否创建成功
	if err != nil{
		panic(err)
	}
	// 3. 对最后一个明文分组进行数据填充
	src = PKCS5Padding(src, block.BlockSize())
	// 4. 创建一个密码分组为链接模式的, 底层使用DES加密的BlockMode接口
	//    参数iv的长度, 必须等于b的块尺寸
	tmp := []byte("helloAAA")
	blackMode := cipher.NewCBCEncrypter(block, tmp)
	// 5. 加密连续的数据块
	dst := make([]byte, len(src))
	blackMode.CryptBlocks(dst, src)

	fmt.Println("加密之后的数据: ", dst)

	// 6. 将加密数据返回
	return dst
}

DES decryption code:

// src -> 要解密的密文
// key -> 秘钥, 和加密秘钥相同, 大小为: 8byte
func DesDecrypt_CBC(src, key []byte) []byte {
	// 1. 创建并返回一个使用DES算法的cipher.Block接口
	block, err := des.NewCipher(key)
	// 2. 判断是否创建成功
	if err != nil{
		panic(err)
	}
	// 3. 创建一个密码分组为链接模式的, 底层使用DES解密的BlockMode接口
	tmp := []byte("helloAAA")
	blockMode := cipher.NewCBCDecrypter(block, tmp)
	// 4. 解密数据
	dst := src
	blockMode.CryptBlocks(src, dst)
	// 5. 去掉最后一组填充的数据
	dst = PKCS5UnPadding(dst)

	// 6. 返回结果
	return dst
}

The last group adds padding data and removes the adding data code:

// 使用pks5的方式填充
func PKCS5Padding(ciphertext []byte, blockSize int) []byte{
	// 1. 计算最后一个分组缺多少个字节
	padding := blockSize - (len(ciphertext)%blockSize)
	// 2. 创建一个大小为padding的切片, 每个字节的值为padding
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	// 3. 将padText添加到原始数据的后边, 将最后一个分组缺少的字节数补齐
	newText := append(ciphertext, padText...)
	return newText
}

// 删除pks5填充的尾部数据
func PKCS5UnPadding(origData []byte) []byte{
	// 1. 计算数据的总长度
	length := len(origData)
	// 2. 根据填充的字节值得到填充的次数
	number := int(origData[length-1])
	// 3. 将尾部填充的number个字节去掉
	return origData[:(length-number)]
}

 Test function:

func DESText() {
	// 加密
	key := []byte("11111111")
	result := DesEncrypt_CBC([]byte("床前明月光, 疑是地上霜. 举头望明月, 低头思故乡."), key)
	fmt.Println(base64.StdEncoding.EncodeToString(result))
	// 解密
	result = DesDecrypt_CBC(result, key)
	fmt.Println("解密之后的数据: ", string(result))
}

 3 Triple DES

Now that DES can be brute-forced in real time, we need a block cipher to replace DES. Triple DES was developed for this purpose.

Triple-DES is a cryptographic algorithm obtained by repeating DES three times in order to increase the strength of DES. It is usually abbreviated as 3DES .

3.1 Encryption and decryption mechanism

The plaintext undergoes three DES processes to become the final ciphertext. Since the length of the DES key is essentially 56 bits , the key length of triple DES is 56×3=168 bits, plus the flag bit 8x3 for error detection. , a total of 192 bits .

From the picture above, we can find that triple DES is not a triple DES encryption (encryption-->encryption-->encryption), but a process of encryption-->decryption-->encryption . It feels incredible to add a decryption operation to the encryption algorithm. In fact, this method was designed by IBM to make Triple DES compatible with ordinary DES.

When all keys in triple DES are the same, triple DES is equivalent to ordinary DES . This is because after the first two steps of encryption-->decryption, the original plaintext is obtained. Therefore, ciphertext previously encrypted with DES can be decrypted with triple DES in this way. In other words, Triple DES is backward compatible with DES.

If key 1 and key 3 use the same key, and key 2 uses a different key (that is, only two DES keys are used), this triple DES is called DES-EDE2. EDE represents the process of Encryption --> Decryption --> Encryption.

Triple DES in which key 1, key 2, and key 3 all use different bit sequences is called DES-EDE3.

Although Triple DES is still used by banks and other institutions, its processing speed is not high, and some problems have gradually emerged in terms of security.

Note: 3des is secure, but inefficient and not recommended. It is a block cipher. Its block length is 8 bytes, and the key length is 24 bytes, which will be divided into 3 equal parts within the algorithm. 

 3.2 Operation of 3DES in go

package main

import (
	"bytes"
	"crypto/cipher"
	"crypto/des"
	"encoding/base64"
	"fmt"
)
func main()  {
	key := []byte("1234567a1234567b1234567c")
	result := TripleDESEncrypt([]byte("知识就是力量!"), key)
	fmt.Println(base64.StdEncoding.EncodeToString(result))
	result =TripleDESDecrypt(result,key)
	fmt.Println(string(result))
}
// 3DES加密
func TripleDESEncrypt(src, key []byte) []byte {
	// 1. 创建并返回一个使用3DES算法的cipher.Block接口
	block, err := des.NewTripleDESCipher(key)
	if err != nil{
		panic(err)
	}
	// 2. 对最后一组明文进行填充
	src = PKCS5Padding(src, block.BlockSize())
	// 3. 创建一个密码分组为链接模式, 底层使用3DES加密的BlockMode模型
	blockMode := cipher.NewCBCEncrypter(block, key[:8])
	// 4. 加密数据
	dst := src
	blockMode.CryptBlocks(dst, src)
	return dst
}
// 3DES解密
func TripleDESDecrypt(src, key []byte) []byte {
	// 1. 创建3DES算法的Block接口对象
	block, err := des.NewTripleDESCipher(key)
	if err != nil{
		panic(err)
	}
	// 2. 创建密码分组为链接模式, 底层使用3DES解密的BlockMode模型
	blockMode := cipher.NewCBCDecrypter(block, key[:8])
	// 3. 解密
	dst := src
	blockMode.CryptBlocks(dst, src)
	// 4. 去掉尾部填充的数据
	dst = PKCS5UnPadding(dst)
	return dst
}
// 使用pks5的方式填充
func PKCS5Padding(ciphertext []byte, blockSize int) []byte{
	// 1. 计算最后一个分组缺多少个字节
	padding := blockSize - (len(ciphertext)%blockSize)
	// 2. 创建一个大小为padding的切片, 每个字节的值为padding
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	// 3. 将padText添加到原始数据的后边, 将最后一个分组缺少的字节数补齐
	newText := append(ciphertext, padText...)
	return newText
}

// 删除pks5填充的尾部数据
func PKCS5UnPadding(origData []byte) []byte{
	// 1. 计算数据的总长度
	length := len(origData)
	// 2. 根据填充的字节值得到填充的次数
	number := int(origData[length-1])
	// 3. 将尾部填充的number个字节去掉
	return origData[:(length-number)]
}


Output:

  

4 AES-Rijndael

AES (Advanced Encryption Standard) is a symmetric encryption algorithm that replaced its predecessor standard (DES) and became the new standard. Companies and cryptographers around the world submitted multiple symmetric cryptographic algorithms as candidates for AES. Finally, in 2000, a symmetric cryptographic algorithm called Rijndael was selected from these candidate algorithms and determined to be AES.

Rijndael is a block cipher algorithm designed by Belgian cryptographers Joan Daemen and Vincent Rijmen. In the future, more and more cryptographic software will support this algorithm.

Rijndael's block length is 128 bits , and the key length can be selected in 32-bit units from 128 bits to 256 bits (however, in the AES specification, the key length is only 128 (16 bytes), 192 (24 byte) and 256 (32 bytes) bit three ).

Note: AES is safe, efficient and recommended. It is a block cipher, the block length is 128 bits (16 bytes), and the key lengths are 16, 24, and 256 bytes, but in the interface provided by go, the key length can only be 16 bytes.

4.1 Encryption and decryption

Like DES, the AES algorithm is also composed of multiple rounds. The following figure shows the approximate calculation steps of each round. DES uses the Feistel network as its basic structure, while AES does not use the Feistel network, but uses SPN Rijndael's input packet is 128 bits, which is 16 bytes. First, the 16-byte input data needs to be SubBytes processed byte by byte. The so-called SubBytes is the process of using the value of each byte (any value from 0 to 255) as an index to find the corresponding value from a substitution table (S-Box) with 256 values. In other words, the Replaces a 1-byte value with another 1-byte value.

SubBytes needs to be processed by ShiftRows, that is, the output of SubBytes is shuffled in bytes. From the lines in the figure below, we can see that this kind of disruption is regular.

After ShiftRows, MixCo1umns processing is required, that is, bit operations are performed on a 4-byte value to change it into another 4-byte value.

Finally, the output of MixColumns needs to be XORed with the round key, that is, AddRoundKey processing. At this point, the round of AES is over. In fact, 10~14 rounds of calculations need to be repeated in AES.

Through the above structure we can find that all bits input will be encrypted in one round. Compared with the Feistel network, which only encrypts half of the input bits in each round, the advantage of this method is that fewer rounds of encryption are required. In addition, this method also has the advantage that SubBytes, ShiftRows and MixColumns can be calculated in parallel in units of bytes, rows and columns respectively.

SubBytes -- byte substitution

ShiftRows -- row shift substitution

MixColumns -- Column confusion

   AddRoundKey -- round key addition

The figure below shows the decryption process in one round of AES. From the figure, we can see that SubBytes, ShiftRows, and MixColumns have reverse operations InvSubBytes, InvShiftRows, and InvMixColumns respectively. This is because AES cannot use the same structure to implement encryption and decryption like the Feistel network.

InvSubBytes -- inverse byte substitution

InvShiftRows -- Retrograde shift

   InvMixColumns -- reverse column confusion

4.2 AES operation in go

Encryption and decryption code implementation (CBC grouping mode):

package main

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

)

func main()  {
	key := []byte("1234567a1234567b1234567c")
	result := AESEncrypt([]byte("知识就是力量!"), key)
	fmt.Println(base64.StdEncoding.EncodeToString(result))
	result =AESDecrypt(result,key)
	fmt.Println(string(result))
}
// AES加密
func AESEncrypt(src, key []byte) []byte{
	// 1. 创建一个使用AES加密的块对象
	block, err := aes.NewCipher(key)
	if err != nil{
		panic(err)
	}
	// 2. 最后一个分组进行数据填充
	src = PKCS5Padding(src, block.BlockSize())
	// 3. 创建一个分组为链接模式, 底层使用AES加密的块模型对象
	blockMode := cipher.NewCBCEncrypter(block, key[:block.BlockSize()])
	// 4. 加密
	dst := src
	blockMode.CryptBlocks(dst, src)
	return dst
}
// AES解密
func AESDecrypt(src, key []byte) []byte{
	// 1. 创建一个使用AES解密的块对象
	block, err := aes.NewCipher(key)
	if err != nil{
		panic(err)
	}
	// 2. 创建分组为链接模式, 底层使用AES的解密模型对象
	blockMode := cipher.NewCBCDecrypter(block, key[:block.BlockSize()])
	// 3. 解密
	dst := src
	blockMode.CryptBlocks(dst, src)
	// 4. 去掉尾部填充的字
	dst = PKCS5UnPadding(dst)
	return dst
}
// 使用pks5的方式填充
func PKCS5Padding(ciphertext []byte, blockSize int) []byte{
	// 1. 计算最后一个分组缺多少个字节
	padding := blockSize - (len(ciphertext)%blockSize)
	// 2. 创建一个大小为padding的切片, 每个字节的值为padding
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	// 3. 将padText添加到原始数据的后边, 将最后一个分组缺少的字节数补齐
	newText := append(ciphertext, padText...)
	return newText
}

// 删除pks5填充的尾部数据
func PKCS5UnPadding(origData []byte) []byte{
	// 1. 计算数据的总长度
	length := len(origData)
	// 2. 根据填充的字节值得到填充的次数
	number := int(origData[length-1])
	// 3. 将尾部填充的number个字节去掉
	return origData[:(length-number)]
}

 Output:

Encryption and decryption code implementation (CTR grouping mode):

package main

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

func main()  {
	key := []byte("1234567812345678")
	str := []byte("你好!")
	cipherText := aesEncrypt(str,key)
	fmt.Println(base64.StdEncoding.EncodeToString(cipherText))
	fmt.Println(string(aesDecrypt(cipherText,key)))
}
//aes加密,分组模式CTR
func aesEncrypt(plainText []byte,key []byte) []byte {
	//建立一个底层使用aes的密码接口
	block,err := aes.NewCipher(key)
	if err!=nil{
		panic(err)
	}
	//创建一个使用CTR分组模式的加密接口
	iv := []byte("1234567812345678")
	stream := cipher.NewCTR(block,iv)
	//加密
	dst := plainText
	stream.XORKeyStream(dst,plainText)
	return dst
}
//aes解密
func aesDecrypt(cipherText []byte,key []byte) []byte  {
	block,err := aes.NewCipher(key)
	if err!=nil {
		panic(err)
	}
	//创建一个使用CTR分组模式的加密接口
	iv := []byte("1234567812345678")
	stream := cipher.NewCTR(block,iv)
	plainText := cipherText
	stream.XORKeyStream(plainText,cipherText)
	return plainText
}

Output:

In fact, CTR mode uses XOR operation. The encryption and decryption algorithm codes are the same, so you can use one.

Demo:

package main

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

func main()  {
	key := []byte("1234567812345678")
	str := []byte("我只使用了一个函数喔!!")
	cipherText := aesEncryptAndDecrypt(str,key)
	fmt.Println(base64.StdEncoding.EncodeToString(cipherText))
	fmt.Println(string(aesEncryptAndDecrypt(cipherText,key)))
}
//aes加密解密公用,分组模式CTR
func aesEncryptAndDecrypt(src []byte,key []byte) []byte {
	//建立一个底层使用aes的密码接口
	block,err := aes.NewCipher(key)
	if err!=nil{
		panic(err)
	}
	//创建一个使用CTR分组模式的加密接口
	iv := []byte("1234567812345678")
	stream := cipher.NewCTR(block,iv)
	//加密
	dst := src
	stream.XORKeyStream(dst,src)
	return dst
}


 

 

Guess you like

Origin blog.csdn.net/weixin_41551445/article/details/126361767