Yanyg - SAN Software Engineer

加密工具 - GPG入门

目录

近期产品中需要导入一个组件锁定策略。使用到GnuPG,记录如下:

1 GPG是什么

GPGGnuPG(the GNU Privacy Guard, GNU加密保护),是一款开源加密软件,遵循 RFC4880(OpenPGP标准)。如下是主页介绍:

GnuPG is a complete and free implementation of the OpenPGP standard as defined by RFC4880 (also known as PGP). GnuPG allows you to encrypt and sign your data and communications; it features a versatile(通用的) key management system, along with access modules for all kinds of public key directories. GnuPG, also known as GPG, is a command line tool with features for easy integration with other applications. A wealth of frontend applications and libraries are available. GnuPG also provides support for S/MIME and Secure Shell (ssh).

Since its introduction in 1997, GnuPG is Free Software (meaning that it respects your freedom). It can be freely used, modified and distributed under the terms of the GNU General Public License.

The current version of GnuPG is 2.2.8. See the download page for other maintained versions.

Gpg4win is a Windows version of GnuPG featuring a context menu tool, a crypto manager, and an Outlook plugin to send and receive standard PGP/MIME mails. The current version of Gpg4win is 3.1.1.

2 安装

2.1 Debian

~$ sudo apt-get install gnupg

2.2 msys

~$ pacman -S gnupg
# or you can search candidates includes key gnupg by command:
~$ pacman -Ss gnupg

2.3 源码安装

使用Git获取源码:

~$ git clone git://git.gnupg.org/gnupg.git

或者下载源码包:https://gnupg.org/download/index.html

编译安装:

~$ ./autogen.sh
*** Activating trailing whitespace git pre-commit hook. ***
    For more information see this thread:
      https://mail.gnome.org/archives/desktop-devel-list/2009-May/msg00084.html
    To deactivate this pre-commit hook again move .git/hooks/pre-commit
    and .git/hooks/pre-commit.sample out of the way.
‘.git/hooks/pre-commit.sample’ -> ‘.git/hooks/pre-commit’
autogen.sh: *** Adding GIT filter.cleanpo.clean configuration.
*** Activating commit log message check hook. ***
‘build-aux/git-hooks/commit-msg’ -> ‘.git/hooks/commit-msg’
autogen.sh: Running aclocal -I m4 ...
autogen.sh: Running autoheader...
autogen.sh: Running automake --gnu ...
autogen.sh: Running autoconf ...
autogen.sh: You may now run:
  ./configure --sysconfdir=/etc --enable-maintainer-mode  && make
~$ ./configure --sysconfdir=/etc --enable-maintainer-mode  && make
~$ sudo make install

如果系统太老,库版本兼容性不满足报错,建议直接安装二进制,或下载较老版本gnupg,或者尝试升级操作系统。例如:

~$ ./configure --sysconfdir=/etc --enable-maintainer-mode  && make
...
configure:
***
*** You need libassuan to build this program.
*** This library is for example available at
***   https://gnupg.org/ftp/gcrypt/libassuan/
*** (at least version 2.5.0 (API 2) is required).
configure: error:
***
*** Required libraries not found. Please consult the above messages
*** and install them before running configure again.
***

3 使用介绍

3.1 生成密钥

~$ gpg --gen-key

Linux下版本\texttt{--gen-key}部分参数是默认的,使用如下命令对所有选项进行设置:

~$ gpg --full-generate-key

示例:

~$ gpg --full-generate-key
gpg (GnuPG) 2.1.18; Copyright (C) 2017 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.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

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

Real name: test
Name must be at least 5 characters long
Real name: gpgtest
Email address: [email protected]
Comment: GPG test for blog
You selected this USER-ID:
    "gpgtest (GPG test for blog) <[email protected]>"

Change (N)ame, (C)omment, (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 82159169CFBF69E6 marked as ultimately trusted
gpg: revocation certificate stored as '/home/yanyg/.gnupg/openpgp-revocs.d/4F2F97E03BFBF466032ADFB382159169CFBF69E6.rev'
public and secret key created and signed.

pub   rsa4096 2018-06-11 [SC]
      4F2F97E03BFBF466032ADFB382159169CFBF69E6
      4F2F97E03BFBF466032ADFB382159169CFBF69E6
uid                      gpgtest (GPG test for blog) <[email protected]>
sub   rsa4096 2018-06-11 [E]

其中需要选择/输入的内容包括:密钥种类、密钥长度、有效期、真实姓名、邮件地址等。

3.2 密钥管理

3.2.1 密钥列表

其中 gpgtest 是新生成的。

~$ gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   1  trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: depth: 1  valid:   1  signed:   0  trust: 1-, 0q, 0n, 0m, 0f, 0u
gpg: next trustdb check due at 2020-06-09
/home/yanyg/.gnupg/pubring.kbx
------------------------------
pub   rsa2048 2018-06-10 [SC] [expires: 2020-06-09]
      D01A8EDEF8F2F0A3B5C627F7531EDD4DBF9F0F5B
uid           [ultimate] yanyg <[email protected]>
sub   rsa2048 2018-06-10 [E] [expires: 2020-06-09]

pub   rsa2048 2018-06-10 [SC] [expires: 2020-06-09]
      321A80E17CFEB82B9913E30F43886FD7AC849DDB
uid           [  full  ] root1 <[email protected]>
sub   rsa2048 2018-06-10 [E] [expires: 2020-06-09]

pub   rsa4096 2018-06-11 [SC]
      4F2F97E03BFBF466032ADFB382159169CFBF69E6
uid           [ultimate] gpgtest (GPG test for blog) <[email protected]>
sub   rsa4096 2018-06-11 [E]
~$ gpg --list-keys --keyid-format short
pub   rsa4096/CFBF69E6 2018-06-11 [SC]
      4F2F97E03BFBF466032ADFB382159169CFBF69E6
uid         [ultimate] gpgtest (GPG test for blog) <[email protected]>
sub   rsa4096/2EF4FC4B 2018-06-11 [E]

3.2.2 删除密钥

~$ gpg --delete-key [UID]

/UID/可以是用户名(比如gpgtest)、邮箱(比如[email protected])、或者Hash 值(比如CFBF69E6)。

3.2.3 导出公钥

# binary pub key
~$ gpg --output gpgtest.pub --export gpgtest
# ascii pub key
~$ gpg --armor --output gpgtest.pub --export gpgtest

3.2.4 上传公钥

~$ gpg --keyserver certserver.pgp.com --send-key 82159169CFBF69E6

其中/key/不能使用UID,需要使用指纹,至少需要long格式指纹,来自下面命令:

gpg --list-key --keyid-format long gpgtest
pub   rsa4096/82159169CFBF69E6 2018-06-11 [SC]
      4F2F97E03BFBF466032ADFB382159169CFBF69E6
uid                 [ultimate] gpgtest (GPG test for blog) <[email protected]>
sub   rsa4096/9D5CD5E32EF4FC4B 2018-06-11 [E]

/man/页描述为"Fingerprints may be used instead of key IDs."

3.2.5 导入公钥

导入:

~# gpg --import gpgtest.pub
gpg: key 82159169CFBF69E6: public key "gpgtest (GPG test for blog) <[email protected]>" imported
gpg: Total number processed: 1
gpg:               imported: 1

设置可信:

~# gpg --edit-key gpgtest
gpg> help
quit        quit this menu
save        save and quit
help        show this help
fpr         show key fingerprint
grip        show the keygrip
list        list key and user IDs
uid         select user ID N
key         select subkey N
check       check signatures
sign        sign selected user IDs [* see below for related commands]
lsign       sign selected user IDs locally
tsign       sign selected user IDs with a trust signature
nrsign      sign selected user IDs with a non-revocable signature
deluid      delete selected user IDs
delkey      delete selected subkeys
delsig      delete signatures from the selected user IDs
pref        list preferences (expert)
showpref    list preferences (verbose)
trust       change the ownertrust
revsig      revoke signatures on the selected user IDs
enable      enable key
disable     disable key
showphoto   show selected photo IDs
clean       compact unusable user IDs and remove unusable signatures from key
minimize    compact unusable user IDs and remove all signatures from key

* The 'sign' command may be prefixed with an 'l' for local signatures (lsign),
  a 't' for trust signatures (tsign), an 'nr' for non-revocable signatures
  (nrsign), or any combination thereof (ltsign, tnrsign, etc.).

gpg> trust
pub  rsa4096/82159169CFBF69E6
     created: 2018-06-11  expires: never       usage: SC
     trust: unknown       validity: unknown
sub  rsa4096/9D5CD5E32EF4FC4B
     created: 2018-06-11  expires: never       usage: E
[ unknown] (1). gpgtest (GPG test for blog) <[email protected]>

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 4

pub  rsa4096/82159169CFBF69E6
     created: 2018-06-11  expires: never       usage: SC
     trust: full          validity: unknown
sub  rsa4096/9D5CD5E32EF4FC4B
     created: 2018-06-11  expires: never       usage: E
[ unknown] (1). gpgtest (GPG test for blog) <[email protected]>
Please note that the shown key validity is not necessarily correct
unless you restart the program.

gpg> save
Key not changed so no update needed.

3.2.6 导入私钥

~$ gpg --export-secret-keys gpgtest > gpgtest.priv
# Change to another account
~# gpg --allow-secret-key-import --import gpgtest.priv
# change trust to 5
gpg --edit-key gpgtest
gpg (GnuPG) 2.1.18; Copyright (C) 2017 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.

Secret key is available.

sec  rsa4096/82159169CFBF69E6
     created: 2018-06-11  expires: never       usage: SC
     trust: full          validity: unknown
ssb  rsa4096/9D5CD5E32EF4FC4B
     created: 2018-06-11  expires: never       usage: E
[ unknown] (1). gpgtest (GPG test for blog) <[email protected]>

gpg> trust
sec  rsa4096/82159169CFBF69E6
     created: 2018-06-11  expires: never       usage: SC
     trust: full          validity: unknown
ssb  rsa4096/9D5CD5E32EF4FC4B
     created: 2018-06-11  expires: never       usage: E
[ unknown] (1). gpgtest (GPG test for blog) <[email protected]>

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y
sec  rsa4096/82159169CFBF69E6
     created: 2018-06-11  expires: never       usage: SC
     trust: ultimate      validity: unknown
ssb  rsa4096/9D5CD5E32EF4FC4B
     created: 2018-06-11  expires: never       usage: E
[ unknown] (1). gpgtest (GPG test for blog) <[email protected]>
Please note that the shown key validity is not necessarily correct
unless you restart the program.

gpg> save
Key not changed so no update needed.
~# gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: next trustdb check due at 2020-06-09
/root/.gnupg/pubring.kbx
------------------------
pub   rsa2048 2018-06-10 [SC] [expires: 2020-06-09]
      321A80E17CFEB82B9913E30F43886FD7AC849DDB
uid           [ultimate] root1 <[email protected]>
sub   rsa2048 2018-06-10 [E] [expires: 2020-06-09]

pub   rsa4096 2018-06-11 [SC]
      4F2F97E03BFBF466032ADFB382159169CFBF69E6
uid           [ultimate] gpgtest (GPG test for blog) <[email protected]>
sub   rsa4096 2018-06-11 [E]

修改后信任模式从unknown改为ultimate。

3.3 签名与签名验证

对文件进行签名:

# generate test files
~$ dd if=/dev/urandom of=test.data bs=1K count=4
~$ ls -lh test.data
-rw-r--r-- 1 yanyg yanyg 4.0K Jun 11 14:32 test.data
~$ gpg --local-user gpgtest --sign test.data
~$ ls -lh test.data*
-rw-r--r-- 1 yanyg yanyg 4.0K Jun 11 14:32 test.data
-rw-r--r-- 1 yanyg yanyg 4.7K Jun 11 14:34 test.data.gpg
gpg --verify test.data.gpg
gpg: Signature made Mon 11 Jun 2018 02:34:03 PM CST
gpg:                using RSA key 4F2F97E03BFBF466032ADFB382159169CFBF69E6
gpg:                issuer "[email protected]"
gpg: Good signature from "gpgtest (GPG test for blog) <[email protected]>" [ultimate]
~$ echo $?
0

针对特定 key 进行签名验证:

~$ gpg --output gpgtest.gpg --export gpgtest
~$ gpg --no-default-keyring --keyring $PWD/gpgtest.gpg --verify test.data.gpg
gpg: Signature made Mon 11 Jun 2018 02:34:03 PM CST
gpg:                using RSA key 4F2F97E03BFBF466032ADFB382159169CFBF69E6
gpg:                issuer "[email protected]"
gpg: Good signature from "gpgtest (GPG test for blog) <[email protected]>" [ultimate]
~$ echo $?
0
~$ gpg --no-default-keyring --keyring $PWD/yanyg.gpg --verify test.data.gpg
gpg: Signature made Mon 11 Jun 2018 02:34:03 PM CST
gpg:                using RSA key 4F2F97E03BFBF466032ADFB382159169CFBF69E6
gpg:                issuer "[email protected]"
gpg: Can't check signature: No public key
~$ echo $?
2

–keyring 参数需要使用绝对路径,否则报告找不到密钥。

–sign 签名采用二进制存储,如果想保存为纯文本,使用参数 –cleansign

~$ echo "plain text" >> test.txt
~$ gpg --clearsign test.txt
~$ ls -lh test.txt*
-rw-r--r-- 1 yanyg yanyg  11 Jun 11 14:45 test.txt
-rw-r--r-- 1 yanyg yanyg 548 Jun 11 14:45 test.txt.asc
~$ cat test.txt.asc
cat test.txt.asc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

plain text
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE0BqO3vjy8KO1xif3Ux7dTb+fD1sFAlseGooACgkQUx7dTb+f
D1v/DQgAnn75lyOmcX4TJFMj2FV8J2JVjY8Hbp71jMO68x9j1Kao8pemvMMXC87w
zi80ZfQbiMImpRZG90ObF/8NHkDT/uqcg4yqHnTbfpmMvlTvUcX6AbOBqINC4WG9
89P8JelyfiA/3x5asow3iL2HBITtCEVoYKtwrMJSgfFHd9q/CJjdAx67O0hakzEZ
i1E94rBslfguzO8mRlqvj7b8vEWdGJpXtCPTLhgNKg1Grx9vOhAfhLHl3Vgb+PKB
bVl1EZ2CTBuVk4ruNWBlS0FUo5+gAolicYoNT4v4uDy7AXjKY6dIs9qsbmKBbNN0
lXAROEL0pBiIOtYkx531LfwfX69bkg==
=VsDH
-----END PGP SIGNATURE-----

一般建议签名与文件分离:

~$ gpg --local-user gpgtest --detach-sign test.data
~$ ls -lh test.data*
-rw-r--r-- 1 yanyg yanyg 4.0K Jun 11 14:32 test.data
-rw-r--r-- 1 yanyg yanyg 4.7K Jun 11 14:34 test.data.gpg
-rw-r--r-- 1 yanyg yanyg  585 Jun 11 14:47 test.data.sig
~$ gpg --verify test.data.sig test.data
gpg: Signature made Mon 11 Jun 2018 02:47:22 PM CST
gpg:                using RSA key 4F2F97E03BFBF466032ADFB382159169CFBF69E6
gpg:                issuer "[email protected]"
gpg: Good signature from "gpgtest (GPG test for blog) <[email protected]>" [ultimate]
# Give wrong file:
~$ gpg --verify test.data.sig  test.txt
gpg: Signature made Mon 11 Jun 2018 02:47:22 PM CST
gpg:                using RSA key 4F2F97E03BFBF466032ADFB382159169CFBF69E6
gpg:                issuer "[email protected]mail.com"
gpg: BAD signature from "gpgtest (GPG test for blog) <[email protected]>" [ultimate]

ASCII格式签名分离:

~$ gpg --armor --detach-sign test.txt
File 'test.txt.asc' exists. Overwrite? (y/N) y
[email protected]:~/org$ cat test.txt.asc
-----BEGIN PGP SIGNATURE-----

iQEzBAABCAAdFiEE0BqO3vjy8KO1xif3Ux7dTb+fD1sFAlseG20ACgkQUx7dTb+f
D1sCpgf/d7gh5oaQ50K6CeL6VnFNL54olDcVIaGd6Trjz0smCYuszmVZ2s2j7C0d
ScZkNVQW9yGHj7QURF8HiFfHU44bLvSSkE7H7sS4lhPI1x1EFRNziyeyL4tCQVNj
/muhyDMgAEJ+I8YBsTew5bAT3c7+EyvKACOP0HUqN0ePJFHBeN4hjzeQ+L2Tr6k4
rUETZPmRmYbEKS0Sn85J2ztQbKbHQr5VQ11UmdIsGHIM4tZuf57BBXoD0QCzPzJg
OQBs4tQZfPsC1rfVZgg8GgxhVcfCRRNOO/vtz+aiVgzIf+IIRAQnnVvj2lkpVi2E
IuSb+9CDA/f4W2VFUka8xFg/h2EBvw==
=YAAi
-----END PGP SIGNATURE-----
~$ gpg --verify test.txt.asc test.txt
gpg: Signature made Mon 11 Jun 2018 02:49:17 PM CST
gpg:                using RSA key D01A8EDEF8F2F0A3B5C627F7531EDD4DBF9F0F5B
gpg: Good signature from "yanyg <[email protected]>" [ultimate]
~$ gpg --verify test.txt.asc test.data
gpg: Signature made Mon 11 Jun 2018 02:49:17 PM CST
gpg:                using RSA key D01A8EDEF8F2F0A3B5C627F7531EDD4DBF9F0F5B
gpg: BAD signature from "yanyg <[email protected]>" [ultimate]

3.4 加密解密

使用 –encrypt 参数加密, –decrypt 参数解密:

~$ gpg --recipient gpgtest --output test.txt.enc --encrypt test.txt
~$ ls -lh test.txt test.txt.enc
-rw-r--r-- 1 yanyg yanyg  11 Jun 11 14:45 test.txt
-rw-r--r-- 1 yanyg yanyg 607 Jun 11 14:53 test.txt.enc
~$ gpg --decrypt test.txt.enc
gpg: encrypted with 4096-bit RSA key, ID 9D5CD5E32EF4FC4B, created 2018-06-11
      "gpgtest (GPG test for blog) <[email protected]>"
plain text
~$ gpg --quiet --decrypt test.txt.enc
plain text

在当前版本中, –secret-keyring 已经标记为废弃的,私钥必须导入之后才可使用:

man: –secret-keyring file This is an obsolete option and ignored. All secret keys are stored in the ‘private-keys-v1.d’ directory below the GnuPG home directory.

~$ gpg --export-secret-keys gpgtest > gpgtest.priv
# change to root
~# gpg --allow-secret-key-import --import gpgtest.priv
gpg: key 82159169CFBF69E6: public key "gpgtest (GPG test for blog) <[email protected]>" imported
gpg: key 82159169CFBF69E6: secret key imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1
~# gpg --quiet --decrypt test.txt.enc
plain text

3.5 加密同时签名

使用本地私钥签名,使用接收者公钥加密:

~$ gpg --local-user gpgtest --recipient root1 --output my.enc --sign --encrypt my.txt
# Change to root to verify & decrypt
~# gpg --quiet --decrypt my.enc

接收者需要有发送者的公钥进行签名验证,私钥进行解密。可能会发生告警,此时需要设置 key 为可信的。

加密同时采用分离签名(–detach-sign),无法进行解密验证。或者我未找到正确组合参数。

4 其他

4.1 私钥备份保护

  • 没有完美的方法
  • 设置健壮的密码
  • 保存到本地GIT或拷贝到安全、私有介质上

5 References