NOTE

1.4 Encryption

Symmetric encryption, block modes, asymmetric encryption, RSA, and basic implementation.

SecurityCreated Updated 4 min readhistorical

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 of A^e / N is R, the calculated R is the ciphertext
  • Decryption uses the private key x
    • Suppose the ciphertext is R. According to R^x = A (mod N), meaning that the remainder of R^x / N is A, the calculated A is the plaintext
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) and R^x = A (mod N), it can be seen that A^e and R^x are congruent. In other words, A^e / R has remainder N and R^x / A has 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

Discussion

Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub