An introduction to GnuPG

G(nu)pg

PGP vs GPG
PGP 是最早先的加密商业软件
一般现在提起PGP是指PGP协议
G(nu)pg is for Gnu Privacy Guard
GPG是GNU下的PGP实现

GPG采用主私钥 + 若干子密钥设计

平时一般使用子密钥来进行具体操作。主密钥只用来进行签发新的子密钥,或对密钥进行修改。可以认为主密钥是你在网上的主要身份凭证,如果因此要保护好,一般因为泄漏或者丢失而不得不对其进行revoke将会使你失去身份。所以在所有设置都正常的情况下,日常使用不需要用到Primary key,应该将其保存在一个安全的地方,隔离与电脑的设备,甚至是纸张。

一些常见缩写含义

密钥能力
Abb Ability
[C] Certifitating 认证,用于签发子密钥
[S] Signing 签名
[E] Encrypting 加密
[A] Authenticating 身份验证
密钥缩写含义
Abb Explain
pub Public Key
sec Secret Key
sub Public SubKey
ssb Secret Subkey

一些命令

生成主密钥

gpg --gen-key

本地密钥保护密码

生成密钥时会同时让你设定一个用于保护本地密钥的密码,每个主密钥的保护密码是相互独立的,在不同设备上密码是独立,也就是说这个密钥是gpg的本地设置,与钥匙串无关,所以在你修改了密码手动save的话,系统会告诉你钥匙串没有更新,没有save的必要。

1
2
gpg --edit-key userId
> passwd
list keys
1
2
3
4
gpg --list-keys (简写 -k)
gpg --list-serect-keys (简写 -K)
gpg -k --keyid-format long (显示sub keyid)
gpg -k --fingerprint (指纹)
edit key 撤销密钥/修改密钥有效期/删除密钥
1
2
3
4
5
6
7
gpg --edit-key --keyid-format long uid (进入edit交互)
> key 1 选择第(1)个subkey(不选择key会默认对整个primary key所包含的所有key进行操作)
> key 2 选择第(2)个subkey
> expire 将会对key1 / key2 (进行过期日期设置)
> revkey 吊销key1 / key2 (已经revoke的key仍然可以加解密,他只是一个标记,告诉你使用这个的人已经不会再继续使用它)
> delkey (删除key1 / key2)
> save (不保存修改无法生效)
uid编辑

修改uid,uid只作为你的信息,对加密没有影响。uid只能添加,和删除,不能修改

1
2
3
4
gpg --edit-key
> adduid 新增按提示操作
> uid 1 (与key类似,uid 1 表示选中了uid 1
> deluid 删除uid
设置信任
1
2
3
4
gpg --edit-key uid
> trust
> 0…5(选择信任度)
> save(其实不需要保存,信任是本地gpg的设置,并没有改变此uid的任何属性)
导出密钥
1
2
gpg -ao public-key.txt --export <UserId>
gpg -ao encrypt-subkey --export-secret-subkeys <keyId>

注意,在keyId后面加上!可以强指定此id而不会全部导出子密钥。

导入密钥
1
2
3
# you can cp the file from the source to local using scp, then import key from the file.
scp @192.168.199.105:/Users/Alex/encrypt-subkey .
gpg --import encrypt-subkey
删除密钥 按userID删除key(不进入交互)
1
2
gpg --delete-secret-keys <UserId>  # 删除私钥,UID 也可以替换成子密钥ID, 主密钥Key ID
gpg --delete-keys <UserId> # 删除公钥
加解密

对称加解密,不带密码缓存,每次都输入的方法
gpg -c --no-symkey-cache test.txt.gpg
非对称加密
-r 参数 指定接受者id 会使用这个id下的一个公钥来加密,需要对方有这个公钥对应的密钥才能解密。
gpg -e -r uesrId test.txt

修改私钥读取提示需要密码的时间(秒)
1
2
3
~/.gnupg/gpg-agent.conf
default-cache-ttl 600
max-cache-ttl 7200

一些解释

revoke和delte的区别

revoke相当于打上吊销标记,delete才是删除。
revoke还有个作用就是通过send-key到key-server,让keyserver同步状态来声明revoke

Expire

已经过期的key仍然可以解密。但是不能进行新的加密,会给你过期的提示。

1
2
> gpg: CF12434DC!: skipped: Unusable public key
> gpg: test.txt: encryption failed: Unusable public key

但是我们随时可以设置密钥的有效期,所以即使过期了想继续用的话重新设置有效期即可。其实过期日期主要还是声名给通讯的对方来知晓的,如果只是单机使用直接设个永不过期也无所谓。

对于revoke 解释

由于pgp是针对传输的加密,对于密钥丢失/泄漏的情况,一般流程是,用户revoke密钥后作出声名,上传revoke过后的key到key server,大家更新之后之后就会知道此key已经revoke,接下来不会再继续使用。但是你不能控制用户是否去更新你的key设置。如果用户没有去更新,然后删掉这个公钥,那么他手上的公钥依然可以解密已revoke的key之前加密过的文件。

关于密钥指定

在GPG中密钥一般是由系统自动选择的,比如根据你填写的UserId或者当前要进行的动作(Sign/Ecrypt)来自动选择名下最新的一个公钥来进行加密。不过也可以在keyId后加上!来强制指定,当你有多个key时这个做法很有效。
gpg -e -r CF12434DC! test.txt

Appendix

一些想法

其实非对称加密比较适用于通信加密,只要文件在远离密钥的地方,目前来说几乎是不可解密的;但是假如攻击者获取了存有密钥的设备,对于本地文件的加密,就只剩下本地对于密钥的对称加密保护这一道防线了。这时候就需要一个强密码保护,但是强密码保护很难用人脑记住,肯定存放于某个保存密钥的app甚至是文件内,而这个app的保护密码设定又是一个难题,肯定是人脑能记住的,相对容易输入的,相对不太复杂,这种密码被攻破的概率也很大。
如果能随时更改这个密码的话就好了,于是想到一个方案:在一个云端存放子密钥,每端在想要加解密gpg文件前下载gpg子密钥,使用完之后删除。这样,如果设备遗失了第一时间删除网络上的子密钥,设备上的内容就无法读取了。前提是攻击者不会提前知道这个网址,不过提前知道的概率不大,因为只有进入了设备才能知道,网址的存在,但是一旦设备遗失我们已经将网址内的密钥清除了。
其实除了算法加密,通过改变加密流程,加密思路,乃至社工的办法,都是算是一种加密,只要能保护文件内容的方法就是好方法。