加密

加密解密相关常用概念

  • 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 KeyPrivate 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 对最终的文件加密