NOTE
1.4 Encryption
Symmetric encryption, block modes, asymmetric encryption, RSA, and basic implementation.
This is a historical learning note and may contain outdated or incomplete understanding.
1. What Is Encryption
2. Encryption Property
Confidentiality
3. Three Elements of Encryption
3.1. Encryption
- Plaintext
- Key
- Encryption algorithm
3.2. Decryption
- Ciphertext
- Key
- Decryption algorithm: it may be different from the encryption algorithm
4. Categories of Encryption Algorithms
4.1. Symmetric Encryption
4.1.1. What It Is
- There is only one key, and both parties use the same key
- Advantage: high encryption efficiency
- Disadvantage: transmitting the key is insecure
4.1.2. Caesar Cipher

4.1.3. DES
Not recommended.
- Encryption

- Decryption

- Key Length: 8 bytes
- Block 8 bytes
4.1.4. 3DES
Triple DES
-
Encryption The decryption operation in the middle is used for compatibility with the earlier DES.

-
Decryption

-
Key Each key is 8 bytes long. There are 3 keys in total, so the total length is 24 bytes. If key 1 and key 2 are the same, or key 2 and key 3 are the same, it becomes DES.
-
Block 8 bytes
4.1.5. AES
Recommended for use
- Key Optional lengths: 16, 24, or 32 bytes
- Block 16 bytes
4.2. Block Modes
DES, 3DES, and AES are all block ciphers. That is, each operation can process only one block of a specific length. If the plaintext to be encrypted is relatively long, encryption needs to be iterated over multiple blocks.
4.2.1. Relationship Between Blocks and Symmetric Encryption

4.2.2. ECB
- Data needs to be divided into blocks, and the block length depends on the algorithm
- Padding is required after the data is divided into blocks
- Encryption is efficient, but the encryption is not thorough
- If one block is cracked, then all blocks will be cracked
- Encryption and decryption can be parallelized

4.2.3. CBC
- Data needs to be divided into blocks, and the block length depends on the algorithm
- Padding is required after the data is divided into blocks
- An initialization vector needs to be provided
- Each ciphertext block is used as input for the next encryption operation
- Encryption cannot be parallelized; decryption can be parallelized

4.2.4. CFB
- Data needs to be divided into blocks, and the block length depends on the algorithm
- Plaintext blocks are not encrypted directly, so padding is not required
- An initialization vector needs to be provided
- The initialization vector is encrypted, and the result is then XORed with the plaintext
- Parallel decryption is supported; parallel encryption is not supported

4.2.5. OFB
- Data needs to be divided into blocks, and the block length depends on the algorithm
- Plaintext blocks are not encrypted directly, so padding is not required
- The result derived from the initialization vector is repeatedly encrypted and used as the data source for the next encryption step


4.2.6. CTR
- Data needs to be divided into blocks, and the block length depends on the algorithm
- Plaintext blocks are not encrypted directly, so padding is not required
- Encryption and decryption can be parallelized

4.3. Asymmetric Encryption
4.3.1. What It Is
- There are two keys: anyone can hold the public key, while only the owner can hold the private key
- Signing and verification: sign with the private key and verify with the public key, with the purpose of preventing tampering
- Encryption and decryption: encrypt with the public key and decrypt with the private key. The purpose is to prevent information from being intercepted and eavesdropped on by a third party
- Disadvantage: encryption and decryption efficiency is very low
- Advantage: key transmission is secure

4.3.2. RSA Algorithm

4.3.3. Mathematical Principle
- Suppose there are two very large prime numbers: p and q
- Let their product be: N = p * q Calculating p * q is fast, but deriving p and q back from N is very expensive, and there is currently no effective formula for doing so.
- Calculate the number of natural numbers smaller than N and coprime with N: φ(n) = (p-1) * (q-1). This formula is proved by set theory.
- Find a natural number smaller than φ(n) and coprime with it, and call it e
- With e and φ(n), according to the principle of the Euclidean algorithm, x and y can be found such that e * x - φ(n) * y = 1
- Substitute φ(n) = (p-1) * (q-1) and rearrange it to get e * x = 1 + (p - 1) * (q - 1) * y
- Finally, we have N, e, and x. The public key is N and e, and the private key is x
4.3.4. Process
- Encryption uses the public key (N, e)
- Suppose the plaintext is A. According to
A^e = R (mod N), meaning that the remainder ofA^e / Nis R, the calculated R is the ciphertext
- Suppose the plaintext is A. According to
- Decryption uses the private key x
- Suppose the ciphertext is R. According to
R^x = A (mod N), meaning that the remainder ofR^x / Nis A, the calculated A is the plaintext
- Suppose the ciphertext is R. According to
4.3.4.1. Euler’s Totient Function
The principle behind the encryption and decryption process above is Euler’s totient function:
- From
A^e = R (mod N)andR^x = A (mod N), it can be seen thatA^eandR^xare congruent. In other words,A^e / Rhas remainder N andR^x / Ahas remainder N. I did not understand the substitution here. - And because
e * x - φ(n) * y = 1, that is,A^(e*x) = A^(1+φ(n) * y) = A * A^(φ(n) * y), the principle that φ(n) * y = 1 here is Euler’s totient function.
But the decrypted data is incorrect; it has been tampered with.
5. Implementation
5.1. OpenSSL
openssl
# Generate the private key
> genrsa -out rsa_private_key.pem
# Generate the public key
> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
5.2. Golang Implementation
5.2.1. AES-CTR
package main
import (
"crypto/aes"
"crypto/cipher"
"fmt"
"log"
)
const (
aesKey = "12345678abcdefgh"
aesIv = "abcdabcd12345678"
)
// Encrypt
func AesEny(plaintext []byte) []byte {
var(
block cipher.Block
err error
)
// Create AES
if block, err = aes.NewCipher([]byte(aesKey)); err != nil{
log.Fatal(err)
}
// Create CTR
stream := cipher.NewCTR(block, []byte(aesIv))
// Encrypt; src and dst may use the same memory
stream.XORKeyStream(plaintext, plaintext)
return plaintext
}
// Decrypt
func AesDec1(ciptext []byte) []byte {
var(
block cipher.Block
err error
)
// Create AES
if block, err = aes.NewCipher([]byte(aesKey)); err != nil{
log.Fatal(err)
}
// Create CTR
stream := cipher.NewCTR(block,[]byte(aesIv))
stream.XORKeyStream(ciptext, ciptext)
return ciptext
}
// Decrypt
func AesDec2(ciptext []byte) []byte {
// XOR the ciphertext again to obtain the plaintext.
// For example, 3 is 0011 in binary. XORing it with 8 (1000) gives 1011;
// XORing 1011 with 1000 again gives 0011, which is 3.
return AesEny(ciptext)
}
func main() {
plaintext := []byte("I love you")
fmt.Println("plaintext", string(plaintext))
ciptext := AesEny(plaintext)
fmt.Println("encrypted", ciptext)
//platext1 := AesDec1(ciptext)
//fmt.Println("decrypted", string(platext1))
platext2 := AesDec2(ciptext)
fmt.Println("decrypted", string(platext2))
}
6. References
- Go Symmetric Encryption Algorithm AES - Juejin
- Base64 Encoding Principle and Code Implementation - Juejin
- Symmetric Encryption Algorithms and Block Cipher Modes - Jianshu
- What Is a Message Authentication Code?
- RSA Algorithm Principle (1) - Ruan Yifeng’s Weblog
- RSA Algorithm Principle (2) - Ruan Yifeng’s Weblog
- Basic Principles, Differences, and Engineering Applications of Hash and Encrypt - T2 Phage - CNBlogs
- Common Cryptographic Techniques | Dabing Who Loves Programming
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub