GnuPG의 기본적인 사용법을 살펴보고 이를 기반으로 SSH, Mutt 등 개발자의 일상 생활에서 생각하는 보안에 대해서 짚어볼 수 있는 좋은 시리즈입니다. 원문 번역에 충실했으며, 제가 사용하는 GPG 버전과 원문에 있는 콘솔 출력 내용이 다르기 때문에, 제가 사용하는 버전에 맞추어 다시 쓴 것임을 알립니다. 본래 콘솔 내용은 당연히 원문에서 볼 수 있습니다.



2. GnuPG 사용법

원문 링크

이전 글에서 private key와 public key를 생성하고 저장했으니, 이제 인터넷과 같이 신뢰할 수 없는 곳에 파일을 배포하기 위한 서명(sign), 증명(verify), 암호화(encrypt), 암호 해독(decrypt)를 하기 위한 GnuPG의 몇 기능들을 사용해보자.


텍스트 파일이나 메세지에 서명하기

--clearsign 옵션을 사용해서 간단한 텍스트 파일부터 서명해보도록 하자.이 기능은 메세지에 서명(signature)를 추가시키는데, 아래는 서명하고자 하는 메세지 message.txt의 내용이다.

This is a public message from Donggun Kim.

새로 생성한 private key를 사용해서 아래와 같이 서명할 수 있다.

$ gpg --clearsign message.txt

Private key를 사용하므로 passphrase를 입력하라고 뜬다.

You need a passphrase to unlock the secret key for
user: "Donggun Kim (Test Key Only) <dgkimdev@gmail.com>"

Passphrase를 제대로 입력하고 나면 message.txt.asc 파일이 생성되고, PGP 섹션과 plaintext ASCII 형식의 서명이 적혀져있다.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

This is a public message from Donggun Kim.
-----BEGIN PGP SIGNATURE-----

iQJHBAEBCAAxFiEEIr9jFLN2TvPg4CM+HmiUfge6r24FAlxDGKwTHGRna2ltZGV2
QGdtYWlsLmNvbQAKCRAeaJR+B7qvbnn2EADqgLdrLIyZvXXQJGdL1VLTgI3ppc14
8gc2XHN8csCdW0Pa30czhoGKINvu9KWU9628DLcOdPgA55jU0C1gpaYKy09mM/NC
CB8vH2/MZNbRO4SXRfNtzGK5VsZVFfX+NIk1GrCbxH/zD/Gz+DMe4wneKW4vrM6m
l9Q/2n80dwLpgp10mWVc6kdyj6PHMQvACahFz7mJk9cy5Tb49Upny4fZ/7lvCXpk
7gxHSUXfaHATym9l2Si4oTJyZp/KBLYDA70Kjl/CJsG1LKbEgcXOZunA6+LXI3qS
n2eyUJWf48gHsMDhR3jQcWi5dBwtZYLgNDmqfws7tOujr6/IhBk9+Tx0zeI6yfDQ
73Vxp7piIrfJncVpuFQo5h5z7wpDgf3X5uafa4J2aztnteyEiYN8Yjtzn+i6BJfe
U0pm3jFz4MhAK8rRiLnD5AFvnXH67PmqQlNcY/B254uG2VBCjwNChkShTHIj5B4I
lkjVv4I5ohBosPQKHatx+1F8j2LjmP2s8iZhYTNAgPtlNkHcDa3OaDOWYAwtXIwL
aYy652H0YwCj10lAYa3HgpAuFa6cdVE/uNwU2LyfcoYqqAgnZXeq5jKmmq+n+Vmh
OO5LZN+B5gyLszIapNbvPcLvc5bN+QLYc5042EoipMQYedMOyuoEfaBGxRUPJbiL
QvDScMrMj7scTA==
=YFM7
-----END PGP SIGNATURE-----

여기서 메세지 자체는 암호화되지 않았기 때문에 그대로 읽을 수 있는 상태라는 것을 알아두자. 여기서 서명이라는 것은 그저 파일이 어떤 특정 사람이 썼고, 그 이후에 수정되지 않았음을 증명할 뿐이다.

이제 누군가 자신의 keyring에 우리의 public key를 등록해두었다면, 그 사람은 그 파일이 정말로 그 key의 주인이 썼다는 것을 증명할 수 있다.

gpg: Signature made Sat 19 Jan 2019 09:56:21 PM KST
gpg:                using RSA key 22BF6314B3764EF3E0E0233E1E68947E07BAAF6E
gpg:                issuer "dgkimdev@gmail.com"
gpg: Good signature from "Donggun Kim (Test Key Only) <dgkimdev@gmail.com>" [ultimate]
gpg: WARNING: not a detached signature; file 'message.txt' was NOT verified!

(역자 추가 내용) 마지막 줄의 경고는 위에서 언급했던 내용을 다시 확인시켜준다. 해당 서명은 증명이 되었지만 실제 원본 message.txt 파일 자체는 아무 해당이 없다는 말이다.

만약 누군가가 이 메세지 message.txt.asc에서 온점을 없앤다든지 뭔가를 오염시킨다면, 증명은 아래처럼 실패한다.

gpg: Signature made Sat 19 Jan 2019 09:56:21 PM KST
gpg:                using RSA key 22BF6314B3764EF3E0E0233E1E68947E07BAAF6E
gpg:                issuer "dgkimdev@gmail.com"
gpg: BAD signature from "Donggun Kim (Test Key Only) <dgkimdev@gmail.com>" [ultimate]


Binary 파일을 서명하고 증명하기

텍스트가 아닌 다른 형식의 파일의 경우 분리된 서명 (detached signature) 파일을 생성하고 싶을 수가 있다.

$ gpg --armor --detach-sign archive.tar.gz

그러면 서명 파일 archive.tar.gz.asc이 해당 디렉토리에 만들어진다. --armor 옵션을 주면 서명 파일이 ASCII 형식이 되도록 설정해서, 파일 내용이 좀 길어지지만 온라인으로 배포하기에 좀 더 쉽도록 할 수 있다.

이제 증명을 위해서는 원본 파일과 서명 파일 둘 다 필요하다. 아래 명령처럼 서명 파일을 먼저 넣고 그 다음에 원본 파일을 넣으면 된다.

$ gpg --verify archive.tar.gz.asc archive.tar.gz

이 방법은 Apache HTTPD 개발팀과 같이 신뢰할 수 있는 원천에서 다운로드 받는 소프트웨어를 증명하는 데에도 똑같이 쓰일 수 있다. 우선 그 사람들의 public key를 받는 법을 찾아서 우리 keyring에 등록한다 (역자 주: Apache 링크에서 설명하는 방법을 따랐고, 이는 원문과 다름을 알립니다).

$ gpg --keyserver pgp.mit.edu --recv-key 791485A8
gpg: key 153D75AC791485A8: 32 signatures not checked due to missing keys
gpg: key 153D75AC791485A8: public key "Jim Jagielski (Release Signing Key) <jim@apache.org>" imported
gpg: key 34EA76E6791485A8: 165 signatures not checked due to missing keys
gpg: key 34EA76E6791485A8: public key "Jim Jagielski (Release Signing Key) <jim@apache.org>" imported
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 2019-03-09
gpg: Total number processed: 2
gpg:               imported: 2

이제 Apache HTTPD 배포판과 이에 일치하는 서명 파일을 다운로드 받는다. 배포 다운로드는 아무 미러에서나 받아도 된다.

$ wget https://archive.apache.org/dist/httpd/httpd-2.4.18.tar.gz
$ wget https://archive.apache.org/dist/httpd/httpd-2.4.18.tar.gz.asc

다운로드 받은 HTTPD 배포판이 실제 개발자들이 서명한 본 파일이 맞는지, 오염되진 않았는지 HTTPD 개발자들의 key와 서명 파일을 사용해서 확인할 수 있다 (역자가 원문과 다르게 HTTPD 페이지가 안내하는 방법으로 시도했음을 알린다).

gpg: Signature made Wed 09 Dec 2015 05:32:07 AM KST
gpg:                using RSA key 34EA76E6791485A8
gpg: Good signature from "Jim Jagielski (Release Signing Key) <jim@apache.org>" [unknown]
gpg:                 aka "Jim Jagielski <jim@jimjag.com>" [unknown]
gpg:                 aka "Jim Jagielski <jim@jaguNET.com>" [unknown]
gpg:                 aka "Jim Jagielski <jimjag@gmail.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: A93D 62EC C3C8 EA12 DB22  0EC9 34EA 76E6 7914 85A8

gpg 출력물에서 경고하길, 다운받은 HTTPD 배포판이 실제로 Jim Jagielski로부터 만들어진 것인지에 대해서 완벽하게 보장하지 못한다고 한다. 왜냐하면 우리가 그 사람을 실제로 만나본 적도 없고 이 public key가 진짜로 그 사람의 것이라고 장담할 수가 없기 때문이다. 공적인 key 서버에서 Jim이란 사람의 키를 가져왔고, 다른 많은 Apache 개발자들이 그의 키를 서명한 것을 보니 괜찮아 보이긴 하지만, 우리는 그들 이 실제로 누군지 모른다.

실제 개발자의 신원에 대해 완벽한 보장을 받을 수는 없지만 key와 서명 파일이 Apache에서 공식적으로 제공한다는 전제 하에서는, 그래도 아무 증명 과정도 없이 다운 받아서 사용하는 것보다는 훨씬 낫다 (그리고 악용당하기 훨씬 어려워진다).

어떤 사람의 public key가 실제로 그 사람의 것이 맞는지를 어떻게 확신하는가의 문제는 각자 스스로 결정해야 하는 일이다. 극단적인 예로, 이를 확신하기 위해서 그 사람을 직접 만나서 그의 주민등록증을 확인하는 약속을 잡을 수도 있을 것이다.


파일 암호화

우리가 원하는 사람들만 해독해서 파일을 읽을 수 있도록 암호화해보자. 여기서는 우리 소유의 private key를 사용하지 않고 받는 사람의 public key를 사용해서 암호화하려고 한다. 그러면 받는 사람의 private key를 사용해서 파일을 해독할 수 있다.

아래는 secret-message.txt의 내용이다.

This is a secret message from Tom Ryder.

이 메세지를 받을 사람이 최소 한 명이 필요하다. 이 메세지는 내 친구 John Public이라는 사람을 위한 메세지라고 소설을 시작해보겠다. 그 친구는 그의 public key를 john-public.asc 파일의 형태로 USB 드라이브에 담아 나에게 직접 건네주었고, 그와 함께 그의 주민등록증과 운전면허증까지 보여주어서 자기 자신이 맞음을 확실하게 증명했다 (그는 내가 네 살일 때부터 친구였기 때문에, 다소 과한 증명 절차이긴 하다).

아무튼 그의 key를 나의 keychain에 등록하겠다.

$ gpg --import john-public.asc
gpg: key 695195A5: public key "John Public (Main key) <johnpublic@example.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

이제 오직 John만이 읽을 수 있도록 메세지를 암호화할 수 있다. --recipient 옵션에 친구의 public key에 해당하는 8자리 hex 코드를 입력하면 된다. 이 hex code는 바로 위 출력에서도 볼 수 있고, gpg --list-keys를 통해서도 확인할 수 있다.

$ gpg --armor --recipient 695195A5 --encrypt secret-message.txt

암호화된 내용은 secret-message.txt.asc 파일에 쓰여진다.

-----BEGIN PGP MESSAGE-----
hQIMAwrg1YaZfw0fAQ//Rh4CkNfE2nFFLsT1BQVmKibcrAIgwG5H9QJQg8VffhiO
CIE8LzYFyXKVojfcyDC+0N5F/P5E2f+MDPyL31ytBIG8VDn/QQPkQftB3odlqNN/
y2jSApFMY6Z/2M3gkdm64+JcBHGUeZOd0/xPORp8M6N49dc3Hl68cVvYys8S6yK2
4m1sVXptGShh/k1nasZqn0FwUTnXupYrqmPpm9YS3eY3F6sOQUer7a8tWXXWPiIR
jTQHjkWkWtER6rbBe2lXgimEFxtXFTa5JMhN3YD1Ea7qzuYQ9CH05AMiOdxU2Ybx
MRAHYk8luTEDf4eOmrKA8kbyK5EeXJIOYh9UASigprvi8Q9gt2Ynxmr6l1aDX546
Hlp0xXW7J5DpQq8Cl3b7Vc2QWW2l9TX+iGltcQuHWo0CFtlgSq0orEieB286g14I
KKlu/ZGnjV4ePZVhUV1CuOsojTjx794O8L1MCsDMgPFj50WmKOvv4842JFaSATRZ
zU4gSaLybLK/noHAkcisM6fTga7se+QajuzWiL4DJmbJPJd/5RxrPSgvNMniPrtu
SRVd9kLthyGBDrQN53wxaKRxe+Zjk93gxVuqxP+frPQV2CYOhIczk7cU+t/jaClI
9IqzyS062PGOIFixWvgVuvSR2Bbukrapfn9GGrGsFfS7he1WvJMZvRG+dPReqAfS
cQElfaw4z+21MZDshpOnxy8mdg1KS8qITIp66KQHt5FZUhP4KbUZxEszqPgQo+S9
YBL87Ob3XC6Jw+j4khr1Qk3aLFfV4h1qbSgxnFGeBHp6rFksLuRsRXt6gXYIa2qj
tZctJ0VAY3dzofuG5MKd7caT
=spbs
-----END PGP MESSAGE-----

암호화할 때 받는 사람에 내가 없었기 때문에 이 내용은 나 조차도 해독할 수가 없다. 오직 John의 private key에 접근할 수 있어야 가능한 일이다.

[don@don-archpad]$ gpg --decrypt secret-message.txt.asc
gpg: encrypted with 2048-bit RSA key, ID 964AEA6E, created 2013-03-10
    "John Public (Main key) <johnpublic@example.com>"
gpg: decryption failed: secret key not available

하지만 John의 컴퓨터에서 그의 private key를 사용해서 암호를 풀어 읽을 수 있다.

john@johnbox:~$ gpg --decrypt secret-message.txt.asc
gpg: encrypted with 2048-bit RSA key, ID 964AEA6E, created 2013-03-10
    "John Public (Main key) <johnpublic@example.com>"
This is a private, secret message from Donggun Kim.

작성자인 나 또한 그 메세지를 읽도록 하고 싶다면, 암호화할 때 받는 사람에 나 자신을 또 추가하면 된다. 그러면 John과 나 각자의 private key를 통해서 (각자 독립적으로) 파일을 해독하여 읽을 수 있다.

$ gpg --recipient 695195A5 --recipient 07BAAF6E \
    --armor --encrypt secret-message.txt

좀 더 철저하게 하자면, 암호화된 메세지가 내가 한 것이 맞음을 서명할 수도 있다.

$ gpg --recipient 695195A5 --recipient 07BAAF6E \
    --armor --sign --encrypt secret-message.txt

이제 John이 --decrypt를 사용할 때에, gpg는 자동적으로 나의 서명을 증명하는 작업을 같이 해준다. 물론 나의 public key가 나의 친구의 keyring에 등록되어 있어야 가능한 일이다.

$ gpg --decrypt secret-message.txt.asc
gpg: encrypted with 2048-bit RSA key, ID 964AEA6E, created 2013-03-10
    "John Public (Main key) <johnpublic@example.com>"
gpg: encrypted with 4096-bit RSA key, ID 7FA28AF9B366E193, created 2019-01-13
      "Donggun Kim (Test Key Only) <dgkimdev@gmail.com>"
This is a secret mssage from Donggun Kim.
gpg: Signature made Sat 19 Jan 2019 11:35:54 PM KST
gpg:                using RSA key 22BF6314B3764EF3E0E0233E1E68947E07BAAF6E
gpg: Good signature from "Donggun Kim (Test Key Only) <dgkimdev@gmail.com>" [ultimate]

여기까지 많은 사람들이 유용하게 쓸 수 있는 기본적인 기능들을 알아보았다. 이 글에서는 public 서버에 key를 제출한다던지, Web Of Trust에 참여하는 내용은 제외했다. 당신의 key 설정이 문제 없이 끝나고, 실제로 당신의 key를 공표할 수 있을 때가 되면 이에 대해서 꼭 찾아보길 바란다.