Twitter/XでPGPを使って(比較的)安全に情報をやり取りする

Twitter/Xにはダイレクトメッセージ(DM)という機能があります。
この機能はフォロワーと、他のユーザーに見られたくない個人的なやり取りをするのに便利です。
しかしながらこの機能には次のような問題点があります。
1. メッセージは暗号化されておらず、Twitter/X社の社員が見ることができる。
ダイレクトメッセージは基本的には送信者と受信者しか見ることができないようになっていますが、Twitter/X社の社員という例外があります。
住所や電話番号、メールアドレス、プライベートの写真等をダイレクトメッセージで共有するのは避けるべきです。

# 解決策: PGPを使う
OpenPGPという暗号化メッセージの規格があります。本記事ではこれをTwitter/Xで使う方法について説明します。

## 必要なコマンドをインストールする
``` bash:必要なコマンドをインストールする
sudo apt install gpg zbar-tools qrencode
```
* gpg: PGPの実装の1つ
* zbar-tools: QRコードをデコードするための `zbarimg` コマンドを含むパッケージ
重要！ zbarimg コマンドのバージョンは `0.23.1` 以上である必要があります。 `0.23` がインストールされてしまう場合があるため注意してください。
* qrencode: データをQRコードにするためのコマンド

## 暗号化メッセージの受け取り手の操作
### 公開鍵と秘密鍵のペアを作る
次のコマンドで公開鍵と秘密鍵のペアを作ります。
``` bash:公開鍵と秘密鍵を作るためのコマンド
gpg --gen-key
```
* 公開鍵: 公開するための鍵です。メッセージの受け取り手が送り手と共有します。
* 秘密鍵: 絶対に公開してはいけない鍵です。暗号化されたメッセージを解読するために使用します。
*
* Real name: と聞かれたら鍵の名前 (Twitter/XのユーザーIDなど) を入力しましょう。本来は本名を入力すべきだと思いますが、名前は公開鍵に含まれてしまうためTwitter/Xで使う際には避けるべきです。
* Email address: と聞かれたら何も入力せず改行しましょう。本来はメールアドレスを入力すべきだと思いますが、メールアドレスを公開したくない方が圧倒的だと思われます。

### 公開鍵を公開する
``` bash: 公開鍵一覧を表示する
gpg -k
```
``` plain:公開鍵一覧
pub   rsa3072 2022-02-21 [SC] [expires: 2024-02-21]
      D6EB291FA114CA4018A81DAA035C4D922583AAAA
uid           [ultimate] test-user # 公開鍵の名前
sub   rsa3072 2022-02-21 [E] [expires: 2024-02-21]
```

``` bash:公開鍵をQRコードにする
# 公開鍵をQRコードに埋め込んだものを /path/to/public.png に保存する
gpg --export test-user | qrencode -8 -lM -o /path/to/public.png
```
作成したQRコードはツイートしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28583/71d2b769-8e14-e99c-b67e-83bca3ef94dd.png)

### 送り手が暗号化メッセージを送ってくるのを待つ
送り手が受け取り手の公開鍵をインポートし、メッセージを暗号化してダイレクトメッセージで送ってくるまで待ちます。

### メッセージを解読する
```bash:メッセージを解読する
echo '-----BEGIN PGP MESSAGE-----

hQGMA9SZMExv7/uBAQv/QEc2gbrTPRQb+NzALsk0njptjiUFTeP2GCKow2h/a6z8
UtJH9xwfJxf0xCBTu6Tqk2+G6KE3OBDrYWGD5xUO/yVDRwrN/B+368gvvLqzK5Wb
Pt3OJMubDcZqbyrbCSs+wKVOusxzlQEkVYZBSxWTTg0rtJGgHIucJ6+hWGq7bZQ0
XgRTXr+WeSgdZpSLp64sEvPUMKf2CC8v/lhv70QqeXqRutOZx2k69iya3XZ32FBS
fCTHspbWZ/+ooQU+hKCsDXNdVe/dga4aJLtTPxuvUcDe1U9EFTwHBC4iHix2Wqw+
TdwuCqG0cSTpjfDcI7tn6jmm1/IAaUnnn5wA7q2BXFBCjcJq8eRQTzNFiPMbaDs7
gNhkgAbka4x5YmqybCMIK+UzcppFhvWtT9gcC79zpMx7m9E4UFvKcN+ZPbsWFPxg
PxJW2HzLP1C5wZ+U7ZozX8v0RXPBayqpjhCh979+pW6Z4CpZWnkYfQN5ObIVhlNv
/CdnEzifMUrOdGpGdMt10n8BbWWb9FGUtWKBVkkPOHt6Dl3eGEtKn/xBu3bLcEpg
73sFAgsPGx5y6AHRc0NPnu0c9wDXOgk+xx5yiD9wcPBYECpydy3DXbuAsRvIDEiE
tR9V0l68eEwrWnPBvP9ETo/NiSncWTQzloPNYAGna7WK2hU4Da3CqA4Bd0VnuM5z
=vFSp
-----END PGP MESSAGE-----' | gpg -d
```
```plaintext:解読されたメッセージ
受信者にしか解読できない秘密💗のメッセージ
```

## 暗号化メッセージの送り手の操作
### 公開鍵をインポートする
```bash:公開鍵をインポートする
# curlに指定するURLは受け取り手の公開鍵のQRコードのURLに置換すること。
curl https://pbs.twimg.com/media/AbCdEfGhIjK?format=png | \
/usr/local/bin/zbarimg --raw -S binary - | \
gpg --import
```
### 送りたいメッセージを暗号化する
```bash:公開鍵一覧を表示する
gpg -k
```
``` plaintext:公開鍵一覧
pub   rsa3072 2022-02-21 [SC] [expires: 2024-02-21]
      D6EB291FA114CA4018A81DAA035C4D922583AAAA
uid           [ultimate] test-user
sub   rsa3072 2022-02-21 [E] [expires: 2024-02-21]

pub   rsa3072 2022-03-22 [SC] [expires: 2024-03-21]
      6CB1753710C76310F05095CC1CE8E753B692A9EE
uid           [ultimate] recipient # 受信者の公開鍵の名前
sub   rsa3072 2022-03-22 [E] [expires: 2024-03-21]
```
```bash:メッセージを暗号化する
echo '受信者にしか解読できない秘密💗のメッセージ' | gpg -a -e -r recipient
```
* `-a` オプション: コマンドの結果 (暗号化メッセージ) テキスト形式で出力する。
* `-e` オプション: ファイルまたは標準入力のデータを暗号化する。
* `-r <recipient>` オプション: メッセージの受け取り手を指定する
```plaintext: 暗号化されたメッセージ
-----BEGIN PGP MESSAGE-----

hQGMA9SZMExv7/uBAQv/QEc2gbrTPRQb+NzALsk0njptjiUFTeP2GCKow2h/a6z8
UtJH9xwfJxf0xCBTu6Tqk2+G6KE3OBDrYWGD5xUO/yVDRwrN/B+368gvvLqzK5Wb
Pt3OJMubDcZqbyrbCSs+wKVOusxzlQEkVYZBSxWTTg0rtJGgHIucJ6+hWGq7bZQ0
XgRTXr+WeSgdZpSLp64sEvPUMKf2CC8v/lhv70QqeXqRutOZx2k69iya3XZ32FBS
fCTHspbWZ/+ooQU+hKCsDXNdVe/dga4aJLtTPxuvUcDe1U9EFTwHBC4iHix2Wqw+
TdwuCqG0cSTpjfDcI7tn6jmm1/IAaUnnn5wA7q2BXFBCjcJq8eRQTzNFiPMbaDs7
gNhkgAbka4x5YmqybCMIK+UzcppFhvWtT9gcC79zpMx7m9E4UFvKcN+ZPbsWFPxg
PxJW2HzLP1C5wZ+U7ZozX8v0RXPBayqpjhCh979+pW6Z4CpZWnkYfQN5ObIVhlNv
/CdnEzifMUrOdGpGdMt10n8BbWWb9FGUtWKBVkkPOHt6Dl3eGEtKn/xBu3bLcEpg
73sFAgsPGx5y6AHRc0NPnu0c9wDXOgk+xx5yiD9wcPBYECpydy3DXbuAsRvIDEiE
tR9V0l68eEwrWnPBvP9ETo/NiSncWTQzloPNYAGna7WK2hU4Da3CqA4Bd0VnuM5z
=vFSp
-----END PGP MESSAGE-----
```

### 暗号化メッセージをダイレクトメッセージとして送信する
先のコマンドで作成した暗号化メッセージ ( `-----BEGIN PGP MESSAGE-----` で始まるもの) をコピペしダイレクトメッセージとして送信します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28583/bae828c6-79a4-54a0-64e3-e831f4b2feef.png)
ここまで行ったら、受け取り手に暗号化メッセージを解読してもらいます。

## 課題
### 中間者攻撃に弱い
この手法は中間者攻撃に脆弱です。ここでいう中間者とはTwitter/X社あるいはTwitter/Xのサーバを指します。
たとえば、Twitter/Xが「ユーザが公開鍵QRコードをアップロードしたことを検知し、こっそり偽の公開鍵QRコードに差し替えた」とすると、
メッセージの送信者は本来とは違う受け取り手が解読できる暗号化メッセージを作成してしまうことになります。

# 参考文献
* https://shkspr.mobi/blog/2015/09/pgp-encrypt-twitter-dms-with-keybase/