加密

加密解密相关常用概念 :

  • Plain Text : 明文,可以被人类或者激情理解的内容
  • Ciphertext : 密文,加密后的内容,一般不能直接被人类或者机器所理解,需要解密
  • Encryption : 将 Plain Text 转换为 Ciphertext 的过程,通常使用一种加密算法(Encrypt Algorithm)
  • Decryption : 解密,将 Ciphertext 转换为 Plain Text 的过程,通常使用和加密算法(Encrypt Algorithm)相对应的解密算法(Decrypt Algorithms)
  • Cipher : 加密和解密过程中算法使用的密码。
  • Block Cipher : 在对数据进行加密之前,需要首先将其分割成块(Block)
  • Stream Cipher : 加密过程中无需将其分割成块(Block)
  • Key : 通常值密钥对(公钥/私钥)

以下是一些较为经典的加密算法

Algorithm Description
AES
Advanced Encryption Standard, also called Rijndael
- Symmetric Cryptography
- Block Cipher 。encrypting data in 128- , 192- , 256- , 512- bit, blocks using a 128- , 192- , 256 , or 512 -bit key
Blowfish - Symmetric Cryptography
- Block Cipher 。encrypting data in 64-bit blocks using the same 32-bit to 448-bit keys for encrypting/decrypting.
CAST5 - Symmetric Cryptography
- Block Cipher 。 encrypting data in 64-bit blocks using the same up to 128-bit key for encrypting/decrypting.
DES
Data Encryption Standard
已经被认为是不安全的
- Symmetric Cryptography
- Block Cipher 。encrypting data in 64-bit blocks using the same 56-bit key for encrypting/decrypting.
3DES 增强的 DES 加密算法
- Symmetric Cryptography
Data is encrypted up to 48 times with three different 56-bit keys before the encryption process is completed.
IDEA - Symmetric Cryptography
- Block Cipher 。 encrypting data in 64-bit blocks using the same 128-bit key for encrypting/decrypting
RC5 - Symmetric Cryptography
- Block Cipher 。 encrypting data in 32- , 64-``, or 128- bit blocks ,using the same up to 2,048-bit keys for encrypting/decrypting
RC6 - Symmetric Cryptography
Same as RC5, but slightly faster
EI Gamal - Asymmetric Cryptography
Uses two keys derived from a logarithm algorithm
Elliptic Curve Cryptosystems - Asymmetric Cryptography
Uses two keys derived from an algorithm containing two randomly chosen points on an elliptic curve.
RC4
also called ArcFour or ARC4
- Stream Cipher
encrypting data in 64-bit blocks using a variable key size for encrypting/decrypting.
RSA 最流行的非对称加密算法,使用 Public/Private Key 进行加解密
- Asymmetric Cryptography

Symmetric Cryptography

Symmetric Cryptography : 对称加密,也叫 密码加密(Secret Key) 或者 私钥加密(Private Key) ,它使用一个 密码(Key) 对 Plain Text 进行加密(Encrypt),在解密时需要使用同样的 密码(Key) 对 Ciphertext 进行解密,它的优势是 加解密速度快(性能优势) ,缺点是 密码(Key)要在加密和解密时共享,容易泄漏

Linux 上流行的 Symmetric Cryptography 工具是 OpenPGP,由包 gnupg2 提供了命令 gpg2 (GNU Privacy Guard)。RHEL 系列一般默认安装了 gnupg2 ,Ubuntu 可以使用命令 apt install gnupg2 进行安装

以下示例使用 gpg2 对文件进行加密:

# tar -cvzf /tmp/backup.tar.gz /etc
# gpg2 -c --force-mdc \
-o /tmp/backup.tar.gz.gpg /tmp/backup.tar.gz
Enter passphrase: ******
Repeat passphrase: ******
# cd /tmp ; file backup*
/tmp/enc/backup.tar.gz: gzip compressed data, last modified: Thu
Jan 30 02:36:48 2020, from Unix, original size modulo 2^32
49121280
/tmp/enc/backup.tar.gz.gpg: GPG symmetrically encrypted data
(CAST5 cipher)


以下示例对文件进行解密:

$ gpg2 -d --force-mdc /tmp/backup.tar.gz.gpg > /tmp/backup.tar.gz
<A pop-up window asks for your passphrase>
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
...

Asymmetric Cryptography

Asymmetric Cryptography 也称作 Private/public Key Cryptography ,它使用一对密钥(Key Pair),由 Public Key 和 Private Key 组成,其中 Public Key 是可以公开的,而 Private Key 必须私密保存(不公开)

Private/public Key Cryptography 有以下特性:

  • 通常情况下, Public Key 用来对数据进行加密, Private Key 用来对数据解密
  • Public Key 加密的数据,只有对应 Key Pair 中的 Private Key 才能解密
  • Private Key 也可以用于数据加密,对应 Key Pair 中的 Public Key 才能解密,这通常用于数字签名(Digital Signatures)
  • 高度安全
  • 相对于 Symmetric Cryptography ,性能上较差,且公私钥管理较为复杂

Linux 中, gpg2 工具也可以生成和管理 Private/public Key Pair 。

数据加密

在加密数据的使用场景中,通常 Public Key 用来对数据进行加密, Private Key 用来对数据解密。以下示例演示 gpg2 工具生成和管理 Private/public Key Pair 并使用其加密解密数据

  • 生成公私钥对(Public/Private Key Pair)

    # gpg2 --gen-key 
    gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.

    Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

    GnuPG needs to construct a user ID to identify your key.

    Real name: John Doe
    Email address: johndoe@gmail.com
    You selected this USER-ID:
    "John Doe <johndoe@gmail.com>"

    Change (N)ame, (E)mail, or (O)kay/(Q)uit? O
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    gpg: key 2FDB1F0E9153C27A marked as ultimately trusted
    gpg: directory '/root/.gnupg/openpgp-revocs.d' created
    gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/2B4BD545D2016AED3B7175DF2FDB1F0E9153C27A.rev'
    public and secret key created and signed.

    pub rsa3072 2024-10-28 [SC] [expires: 2026-10-28]
    2B4BD545D2016AED3B7175DF2FDB1F0E9153C27A
    uid John Doe <johndoe@gmail.com>
    sub rsa3072 2024-10-28 [E] [expires: 2026-10-28]


    以上命令 gpg2 --gen-key 会针对指定的用户( John Doe <johndoe@gmail.com> ) 生成 公私钥对(Public/Private Key Pair) ,生成过程中,根据提示输入以下信息

    • 用户名 和 邮箱 , 用户名和邮箱用来标识密钥对
    • 可以提供一个密码用来保护密钥对

    为指定的用户生成密钥对的同时,会生成一个 key ring 用来存储密钥对

  • 查看系统上的密钥对 ,使用命令 gpg2 --list-keys

    # gpg2 --list-keys
    gpg: checking the trustdb
    gpg: marginals needed: 3 completes needed: 1 trust model: pgp
    gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
    gpg: next trustdb check due at 2026-10-28
    /root/.gnupg/pubring.kbx
    ------------------------
    pub rsa4096 2017-10-10 [SC]
    A6BF651A1797E7C4A825CA2FBEB35010ADB332E7
    uid [ unknown] Amazon WorkSpaces Master Key
    sub rsa4096 2017-10-10 [E]
    sub rsa4096 2018-05-17 [S]

    pub rsa4096 2017-11-06 [SC]
    916CDB3FE99FE5E457519536A90BEB6A5CD8866F
    uid [ unknown] Amazon WorkSpaces RPM Signing Key

    pub rsa3072 2024-10-28 [SC] [expires: 2026-10-28]
    2B4BD545D2016AED3B7175DF2FDB1F0E9153C27A
    uid [ultimate] John Doe <johndoe@gmail.com>
    sub rsa3072 2024-10-28 [E] [expires: 2026-10-28]

  • 使用密钥对加解密数据

    创建密钥对以及 key ring 后,即可使用此密钥对对数据进行加密。

    • 提取公钥(Public Key) ,使用命令 gpg2 --gen 产生的密钥对保存在 key ring 中,要让其他用户使用 公钥(Public Key) 加密数据,首先需要从 key ring 中提取出公钥

      # gpg2 --export John Doe > JohnDoe.pub

      使用 file 命令查看文件类型

      # file JohnDoe.pub 
      JohnDoe.pub: OpenPGP Public Key Version 4, Created Mon Oct 28 02:10:24 2024, RSA (Encrypt or Sign, 3072 bits); User ID; Signature; OpenPGP Certificate

    • 导入公钥(Public Key) ,将 公钥(Public Key) 共享给其他人,假设其他人需要用此 公钥(Public Key) 加密数据,其首先需要将此 公钥(Public Key) 导入到他的 key ring 中

      # gpg2 --list-keys
      gpg: directory `/root/.gnupg' created
      gpg: new configuration file `/root/.gnupg/gpg.conf' created
      gpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this run
      gpg: keyring `/root/.gnupg/pubring.gpg' created
      gpg: /root/.gnupg/trustdb.gpg: trustdb created


      # gpg2 --import JohnDoe.pub
      gpg: keyring `/root/.gnupg/secring.gpg' created
      gpg: key 9153C27A: public key "John Doe <johndoe@gmail.com>" imported
      gpg: Total number processed: 1
      gpg: imported: 1 (RSA: 1)


      # gpg2 --list-keys
      /root/.gnupg/pubring.gpg
      ------------------------
      pub 3072R/9153C27A 2024-10-28 [expires: 2026-10-28]
      uid John Doe <johndoe@gmail.com>
      sub 3072R/6597BB46 2024-10-28 [expires: 2026-10-28]

      如以上代码所示,使用命令 gpg2 --import JohnDoe.pub 将用户 John Doe <johndoe@gmail.com> 的 公钥(Public Key) 导入自己的系统中,使用命令 gpg2 --list-keys 检查,可以看到其已经导入

    • 加密数据 。在已经有指定用户( John Doe <johndoe@gmail.com> )的 公钥(Public Key) 后,使用其公钥对数据加密

      # echo "This is a test data to 'John Doe <johndoe@gmail.com>', it is encrypted by his public key." > encrypted_data_2_JohnDoe

      # cat encrypted_data_2_JohnDoe
      This is a test data to 'John Doe <johndoe@gmail.com>', it is encrypted by his public key.

      # gpg2 --out encrypted_data_2_JohnDoe.enc --recipient "John Doe" --encrypt encrypted_data_2_JohnDoe
      gpg: 6597BB46: There is no assurance this key belongs to the named user

      pub 3072R/6597BB46 2024-10-28 John Doe <johndoe@gmail.com>
      Primary key fingerprint: 2B4B D545 D201 6AED 3B71 75DF 2FDB 1F0E 9153 C27A
      Subkey fingerprint: E3D5 1DEA 79C9 E6FA A3CA E2C1 DC4C BB58 6597 BB46

      It is NOT certain that the key belongs to the person named
      in the user ID. If you *really* know what you are doing,
      you may answer the next question with yes.

      Use this key anyway? (y/N) y

      # cat encrypted_data_2_JohnDoe.enc
      ی»Xe»F
      Q쎶X ʈ`&

      ³g>ט§Ĺћ¹£EYτ윪$½¦d桒54§¯¾]Ƞ񎹑º.D寡ܮ;ܟVͩ;䵠^ցPYҜ║H®
      ҆It4ﭭ$¡*ͳk1"·S1˝9/¨纚׆񉢣s奔鹈T½

      使用命令 gpg2 --out encrypted_data_2_JohnDoe.enc --recipient "John Doe" --encrypt encrypted_data_2_JohnDoe 对文件进行加密,从以上示例可以看到,加密后的文件已经不是明文

      需要注意加密是参数的顺序 ,如果使用以下顺序,会执行失败

      # gpg2 --encrypt encrypted_data_2_JohnDoe --out encrypted_data_2_JohnDoe.enc --recipient "John Doe"
      usage: gpg [options] --encrypt [filename]
    • 数据解密 。用户( John Doe <johndoe@gmail.com> )收到使用 它的公钥加密 后的数据,可以使用其 私钥(Private Key) 对加密数据进行解密。 --out 选项指定解密后的数据写入到指定的文件中,如果不指定,则输出到 STDOUT

      # gpg2 --out encrypted_data_2_JohnDoe --decrypt encrypted_data_2_JohnDoe.enc 
      gpg: encrypted with 3072-bit RSA key, ID DC4CBB586597BB46, created 2024-10-28
      "John Doe <johndoe@gmail.com>"

      # cat encrypted_data_2_JohnDoe
      This is a test data to 'John Doe <johndoe@gmail.com>', it is encrypted by his public key.


      # gpg2 --decrypt encrypted_data_2_JohnDoe.enc
      gpg: encrypted with 3072-bit RSA key, ID DC4CBB586597BB46, created 2024-10-28
      "John Doe <johndoe@gmail.com>"
      This is a test data to 'John Doe <johndoe@gmail.com>', it is encrypted by his public key.

      如果密钥对使用了密码保护,使用私钥(Private Key)解密数据时需要提供密码

数字签名

数字签名(Digital Signatures) 通常用于 数据验证 和 数据完整性校验 ,如发送方发送了重要数据给接收方,为了确保数据未被篡改,发送方可以给数据进行 数字签名(Digital Signature) ,和 数据加密 的过程相反, 数字签名(Digital Signatures) 的过程中, Private Key 用于加密数据,Public Key 用于解密数据 。

以下示例演示为文件进行 数字签名(Digital Signatures)

  • 对文件进行数字签名

    $ gpg2 --output JohnDoe.DS --sign MessageForJill.txt

    以上命令( --sign 选项)对文件 MessageForJill.txt 进行 数字签名(Digital Signatures) ,此 gpg2 命令主要实现了以下操作:

    1. 对目标文件 MessageForJill.txt 创建一个 消息摘要(Message Digest,比如 Hash)
    2. 对此 消息摘要(Message Digest,比如 Hash) 进行加密(使用 Private Key )
    3. (使用 Private Key )对消息内容进行加密
    4. 将加密内容输出到 --output JohnDoe.DS

    命令执行完后, --output JohnDoe.DS 中将会包含 加密的消息和数字签名(Digital Signatures)

  • 解密并校验文件完整性 ,当目标用户收到此加密文件后,可以使用以下命令检查 数字签名(Digital Signatures) 并解密文件内容

    $ gpg2 --decrypt JohnDoe.DS
    I am the real John Doe!
    gpg: Signature made Sun 27 Oct 2019 07:03:21 PM EDT
    gpg: using RSA key
    7469BCD3D05A43130F1786E0383D645D9798C173
    gpg: Good signature from "John Doe <jdoe@example.com>" [unknown]
    ...

对有 数字签名(Digital Signatures) 的文件,只要拥有其公钥,就可以查看其内容。 如果要对数据真正保密,确保只有目标用户才能查看其内容,可以使用目标用户的 Public Key 对最终的文件加密