0.前言
在使用repo下载android源码和git下载kernel源码里会使用到gpg,那gpg是什么?该如何使用?这里说到的GPG是GnuPG,是Gnu Privacy Guard的缩写,它提供钥匙管理、加解密和数字签名等功能,其涉及到非对称加密算法,在学习每一项新技术时都先学会用再去深究其实现,故而我们在这里简说原理后立马学习如何用,品尝非对称加密算法应用下的GPG味道。
非对称加密算法使用公钥和密钥两个配对的钥匙,公钥加密,密钥解密,公钥加密后的信息只能由配对的密钥来解密还原信息,而对称加密算法则只有一个钥匙,加解密用同一把很不安全。数字签名一般是在发送的信息后面添加签名(即一堆处理后的字符),该签名是根据发送方的密钥和信息内容进行处理得出,而接收方在收到信息后使用发送方的公钥就可以验证接收到的信息的正确性,确认有没有被篡改过。
我们使用的环境是:Ubuntu13.10(64位,Kernel:3.13.6)
sudo apt-get install gnupg
一般Ubuntu都安装好了。
gpg --gen-key
运行该命令后有如下提示内容需确认:
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?
这里采用默认的RSA就可以,直接回车后有如下内容:
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
这里是配置产生的KEY的位数,在1024到4096之间,我们采用默认的2048即可(KEY的位数越多越安全,但加解密的速度则会越慢),直接回车后有如下内容:
Please specify how long the key should be valid.
0 = key does not expire
= key expires in n days
w = key expires in n weeks
m = key expires in n months
y = key expires in n years
Key is valid for? (0)
这里配置产生的KEY的使用期限,这里使用默认0永不超期,直接回车后有如下内容:
Key does not expire at all
Is this correct? (y/N)
这里输入y后回车,有如下内容:
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter)"
Real name:
这里输入自己的名字,我使用guochongxin,回车后有如下内容:
Email address:
这里输入自己的邮箱地址,我使用[email protected],回车后有如下内容:
Comment:
这里输入一些说明,我使用gpg key of guochongxin,回车后有如下内容:
You selected this USER-ID:
"guochongxin (gpg key of guochongxin)"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
这里是确认上面的信息,确认无误后输入O回车,有如下内容:
You need a Passphrase to protect your secret key.
gpg: gpg-agent is not available in this session
Enter passphrase:
这里要求输入密码来保护KEY,请根据实际输入自己想用的密码吧,这里就不给参考了,不然就泄密了。输入密码回车后会显示Repeat passphrase:要求再次输入,再次输入后回车有如下内容:
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.
Not enough random bytes available. Please do some other work to give
the OS a chance to collect more entropy! (Need 185 more bytes)
类似的提示会再次出现,不需要管它,1分多钟后(视实际机器配置而定)有如下内容输出:
gpg: key C638479D marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 2048R/C638479D 2014-04-30
Key fingerprint = A83D 1FAF 37EA 959D 5793 706D CF0F ACA3 C638 479D
uid guochongxin (gpg key of guochongxin)
sub 2048R/EA71B83D 2014-04-30
至此,公钥和密钥(私钥)就生成好了,接下来不看如何玩转这KEY了。
gpg --list-keys
gpg -k
gpg --list-public-keys
上面3条命令都是列出本机公钥的,可任用一条,我本机情况如下:
xinu@slam:~$ gpg -k
/home/xinu/.gnupg/pubring.gpg
-----------------------------
pub 1024D/9AB10E78 2009-04-16
uid The Android Open Source Project
sub 2048g/8BE34426 2009-04-16
pub 2048R/C638479D 2014-04-30
uid guochongxin (gpg key of guochongxin)
sub 2048R/EA71B83D 2014-04-30
从上面可以看到公钥的文件位于/home/xinu/.gnupg/pubring.gpg,每项均以pub打头,2048R是我们使用的加密方式是2048位的RSA,C638479D是该KEY的ID,而guochongxin一行则是UID信息。
gpg -K
gpg --list-secret-keys
上面2条命令都是列出本机密钥的,可作用一条,我本机的情况如下:
xinu@slam:~$ gpg -K
/home/xinu/.gnupg/secring.gpg
-----------------------------
sec 2048R/C638479D 2014-04-30
uid guochongxin (gpg key of guochongxin)
ssb 2048R/EA71B83D 2014-04-30
从上面可以看到对应的密钥文件位于/home/xinu/.gnupg/secring.gpg ,并且以sec打头。同时我们看到公钥比密钥多了一个,因为公钥除了自己生成的那个,还导入了其他人的。
上面的公钥pubring.gpg和密钥secring.gpg文件均是二进制的,而我们要导出ASCII格式的。
gpg -a --output public-key.txt --export guochongxin
其中guochongxin是我们这上的UID,该命令执行后会在当前目录下生成public-key.txt文件,可以打开来看。
gpg --armor --output private-key.txt --export-secret-keys C638479D
gpg --keyserver hkp://subkeys.pgp.net --send-keys C638479D
其中C638479D为UID是guochongxin的ID,hkp://subkeys.pgp.net是公钥服务器,只要上传到一个公钥服务器,通过交换机制,其他的所有公钥服务器均会共享到。
查到可用的KEY服务器有:hkp://keys.gnupg.net、keyserver.ubuntu.com、 hkp://subkeys.pgp.net。
gpg --import public-key.txt
gpg --keyserver hkp://subkeys.pgp.net --search-keys guochongxin
gpg --keyserver hkp://subkeys.pgp.net --recv-keys C638479D
第一个命令是在KEY服务器上搜索指定UID的公钥并导入,这会比较慢,第二个命令是导入指定ID的公钥,这不需要搜索,很快就可以导入。
由于UID相同的公钥在公钥服务器上是可能存在的,还有我们发送公钥文件的过程可能出错(传输过程被篡改等),那导入公钥后如何确认这是我们所要导入的公钥呢?
在每个公钥里都有相应的指纹值,可使用gpg --fingerprint guochongxin查看UID为guochongxin的公钥指纹:
xinu@slam:~$ gpg --fingerprint guochongxin
pub 2048R/C638479D 2014-04-30
Key fingerprint = A83D 1FAF 37EA 959D 5793 706D CF0F ACA3 C638 479D
uid guochongxin (gpg key of guochongxin)
sub 2048R/EA71B83D 2014-04-30
其中Key fingerprint一行就是指纹值了,只需与对方确认是否一致就对了,看到这,你从服务器上导入我的公钥后就可以确认正确性了,确认无误后再使用gpg --sign-key guochongxin确认签收,其会提示确认指纹值,确认后输入y并回车即可,如果发现不是我们要的,那么使用gpg --delete-keys guochongxin将其删除即可。
gpg -a --recipient guochongxin --output endemo.txt --encrypt demo.txt
将demo.txt使用UID为guochongxin的公钥加密成ASCII码的endemo.txt文件。
其中-a表示输出ASCII码格式的文件,不加该参数则默认生成二进制文件。
gpg --output dedemo.txt --decrypt endemo.txt
将上面加密后的endemo.txt文件(使用UID为guochongxin的私钥)解密还原为dedemo.txt文件(此时会要求我们输入在生成KEY时输入的密码)。
二进制文件:gpg --sign demo.txt,会生成demo.txt.gpg文件;
ASCII码文件:gpg --clearsign demo.txt,会生成demo.txt.asc文件。
二进制文件:gpg --detach-sign demo.txt,会生成demo.txt.sig文件;
ASCII码文件:gpg -a --detach-sign demo.txt,会生成demo.txt.asc文件。
下述方法均与上面c对应。
当前目录下只有二进制文件demo.txt.gpg或demo.txt.asc时使用gpg --verify demo.txt.gpg或gpg --verify demo.txt.asc命令验证,会有如下内容输出:
gpg: Signature made Wed 30 Apr 2014 07:22:21 PM CST using RSA key ID C638479D
gpg: Good signature from "guochongxin (gpg key of guochongxin)"
或
gpg: Signature made Wed 30 Apr 2014 07:30:38 PM CST using RSA key ID C638479D
gpg: Good signature from "guochongxin (gpg key of guochongxin)"
二进制和ASCII签名在验证时没区别,只要看到Good signature表示签名正确。
注:如想把签名后的文件提取源文件内容,可使用如下命令:
gpg -o orig-demo1.txt -d demo.txt.gpg
gpg -o orig-demo2.txt -d demo.txt.asc
此时会分别把二进制和ASCII对应的文件提取为orig-demo1.txt和orig-demo2.txt文件。
验证命令与方法1一样,都使用“gpg --verify [签名文件]”命令来验证*.sig和*.asc文件,但要注意的是必须保证源文件与签名文件在同一目录下。
除了对文件的加解密、签名验证外,还有repo、git版本管理时也使用到GPG,其实还有在邮件加密、签名等相关场景会使用到,更多可参考“参考网址”里最后一条网址。