ssh用の公開鍵で文字を暗号化する。osx

[最新版はこちら gist ](https://gist.github.com/shgeta/d91a4a2a15fbe39f716c)

# Open SSH用の公開鍵( ssh-rsa )で文字列を暗号化する。 Mac OS X 
### 概要
ssh-keygenで作ったopenssh用のrsa公開鍵( ssh-rsa )で文字列を暗号化するもの。コマンドラインで使う。
chatworkなどでちょっとしたパスワードを送る時などに、暗号化して貼り付けたら便利。
githubなど使っている人は、ssh接続用の公開鍵秘密鍵のセットを持っているはずだ。
暗号化は公開鍵があればopensslコマンドで

```sh
openssl rsautl -encrypt -pubin -inkey $_file_path_to_pubkey >/tmp/tekitou
```

こんな感じで行えるが、openssh用の公開鍵に対応していない。なので、これを使える形に変換して暗号化する。
復号には対の秘密鍵がそのまま使える。githubに登録された公開鍵は https://github.com/<ユーザー名>.keys から入手できる。

相手に ~/.ssh/id_rsa （秘密鍵）と ~/.ssh/id_rsa.pub （公開鍵）のセットがあるものとしてつくったので、違う場合は適当に代える。

[openssh用のrsa公開鍵をopensslで使える形に変換したいだけの人はこちら](https://gist.github.com/shgeta/b81d936eb10be7e0a0e8)

### 制限
* あまり長い文字列は暗号化できない。それは別の方法で


### TODO
* 他人でテストする
* 別に「長い文字列」「同報通信」「githubアカウントを指定して」に対応したものを作りたい。


### 使い方
functionのコードをターミナルに貼り付ける。(この時点では何も起きない。)
それから下のように rsaencrypt コマンドを打つ

```
usage: 
  echo "some message" | rsaencrypt <ssh-rsa から始まるssh接続用公開鍵文字列 pathではない>
  or
  rsaencrypt <ssh-rsa から始まるssh接続用公開鍵文字列 pathではない>
  <input message>
  (入力が終わったら)ctrl+d
  
(例)
echo "some message" | rsaencrypt ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNckEuuAeiPesx99s/ivWoXQGdJIMKRl0I0HiSLMCdK/dUrXy5ycyy51cEtv0t/AGQCkAxqiYBCWiVhLV/1qpZuONL9UT8cTa4TO749lFVaucxLNN7nvUtbtA4InKqRjsjqK27vCzyWxiMVIMX0jNpD0rPCwkTK2Ja6knCRN7kA2c3UyNmX4IoQ0xqT0vaUNuxtOe9SkmT3DLizDMbYByzJWVgotbZfOu1QbbClpLt/TbDd5l3fcGNsRzT8Cnd8zdvXk5ZsiUDKKhynvA4Tt/LN9LjZgxTyoEYJewYzf51E8gH057A9zXguBTTAiHMgD8xgeGzh4AVEEFJ1ZO6oCft Guest@shigeta-no-MacBook-Pro.local
  
  
  * ssh接続用公開鍵は ~/.ssh/id_rsa.pub の中身をもらうか、https://github.com/<ユーザー名>.keys
  から取得しておく。
result:
( echo '<encrypted string>' | base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa )

出力例 :
( echo YqCHiz6jJc7mdooIXquP9pqx7VdUorq2HKy4W/vAd9zETVCd0BpGVY9+SfdOQU7m9bs0ec4ZJ6DeFITXxU43zzO7JTSyNrgCT5gXzu3/wKG6+hGmqkYdxme9lPvTTZ+z8w5biU9gEbOuTXy63bBli9IKRS62KYEiF30gF4GBUaB1ISFBNTVqu1rB3FFa78vpUT7MaeYJ4lsZBWuP+fFx40CSCsrub9CfFfNJgqEIInUTVrU4/Fit4FId88uZgogjZIAyQiKtpeg1rZFkfezL1x1vUpi6KpBdeINPZ17m8bYYg9w8W1zwqo4gn4sDmeGMj07f8Lxh2zbB/aYB5JunhA== | base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa )

decrypt:
  * 結果はshellスクリプトなので実行してもらう。(必要に応じて ~/.ssh/id_rsa の場所を変更する。)
 
```


### shell function (貼り付けて使う)
opensshのインストールが不要なバージョン
(あまりヘビーでないzshユーザに張り付けてもらうときは setopt INTERACTIVE_COMMENTS を教えてあげるとよい。)

```sh
# 使われ方の想定
# 相手のっssh-rsa公開鍵を入手する。(githubなどに公開されてるでしょ？)
# 公開鍵を指定して文字列を暗号化する
# >結果(暗号化+base64されたもの)をchatworkとかに貼る
# >結果はshellスクリプトなので実行してもらう。(中級者以上だと~/.ssh/id_rsaの場所がgithub用のものは違うかもしれない。)
# >勝手に見てもらう
 
# やっていること。ssh接続用の公開鍵をopensslで使える形式に変換して、opensslのrsautlをつかって暗号化します。
# 注意:実際の使いごこちはまだ試せていない。
# 感想: 秘密鍵を簡単に外に持ち出せない仕組みか自分も簡単に読めない仕組みが必要だなあと思う 
 
function rsaencrypt ()
{
  if test $# -eq 0 -o "$(echo $1 | cut -d' ' -f1)" != "ssh-rsa"
    then
    if "$(echo $1 | cut -d' ' -f1)" != "ssh-rsa"
      then
      echo "注意！　ssh接続用の公開鍵の中身を貼り付けます。ssh-rsaで始まる文字列です。"
    fi
    
cat <<EOF
usage: 
  echo "some message" | rsaencrypt <ssh-rsa から始まるssh接続用公開鍵文字列 pathではない>
  or
  rsaencrypt <ssh-rsa から始まるssh接続用公開鍵文字列 pathではない>
  <input message>
  (入力が終わったら)ctrl+d
  * ssh接続用公開鍵は ~/.ssh/id_rsa.pub の中身をもらうか、https://github.com/<ユーザー名>.keys
  から取得しておく。
result:
  > <base64 encoded string>
decrypt:
  * 結果はshellスクリプトなので実行してもらう。(中級者以上だと~/.ssh/id_rsaの場所がgithub用のものは違うかもしれない。入手した公開鍵と合わせる。)
 echo '<encrypted string>' | base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa
EOF
    return 1
  fi
  echo "pubkey=$1"
  echo
_encrypted=$(
(
PUB_KEY="$@"
#~/.ssh/id_rsa.pub

_file_pubkey=$(mktemp -t pubkey)
_file_decd_tmp=$(mktemp -t decd)
#ssh-rsaからx.509pemに変換
sshpubkey2pem "$PUB_KEY" >$_file_pubkey || return 1
openssl rsautl -encrypt -pubin -inkey $_file_pubkey >$_file_decd_tmp
cat $_file_decd_tmp | base64
rm $_file_decd_tmp || return 1
rm $_file_pubkey || return 1
) )
if test $? -eq 0
then
  echo "##ここから下渡す"
  echo "( echo $_encrypted | base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa )"
fi
} 

# 詳細 : https://gist.github.com/shgeta/b81d936eb10be7e0a0e8
# ssh-rsa 形式の公開鍵を opensslで使える形式、x509のPEMにする。
# エディターの都合上インデントなしで勘弁。
# usageもまだ。sshpubkey2pem $(cat ~/.ssh/id_rsa.pub )　こんな感じでつかって！
function sshpubkey2pem () 
{
(
PUBKEY="$@"
NUMBER_BYTE_SIZE=4
_head=0
_file_tmp_files=$(mktemp -t convrsa) ; echo $_file_tmp_files >>$_file_tmp_files

_file_binnakami=$(mktemp -t convrsa) ; echo $_file_binnakami >>$_file_tmp_files
_file_e=$(mktemp -t convrsa) ; echo $_file_e >>$_file_tmp_files
_file_n=$(mktemp -t convrsa) ; echo $_file_n >>$_file_tmp_files
_file_pkcs1_bin=$(mktemp -t convrsa) ; echo $_file_pkcs1_bin >>$_file_tmp_files
_file_x509_nakami=$(mktemp -t convrsa) ; echo $_file_x509_nakami >>$_file_tmp_files
_file_x509_bin=$(mktemp -t convrsa) ; echo $_file_x509_bin >>$_file_tmp_files

echo $PUBKEY | cut -d" " -f2 | base64 -D >>$_file_binnakami

{
#ssh-rsa 解析
{
#ssh-rsaの文字列の長さ
_type_string_size=$(printf "%d" $( cat $_file_binnakami | dd bs=1 skip=$_head count=$NUMBER_BYTE_SIZE | od -t x1 | head -n1 | sed -e's/^0000000 *\(..\) *\(..\) *\(..\) *\(..\)/0x\1\2\3\4/')
)
_head=$(expr $NUMBER_BYTE_SIZE  + $_head)
_head=$(expr $_head + $_type_string_size)

#eのバイト数
_e_length=$(printf "%d" $( cat $_file_binnakami | dd bs=1 skip=$_head count=$NUMBER_BYTE_SIZE | od -t x1 | head -n1 | sed -e's/^0000000 *\(..\) *\(..\) *\(..\) *\(..\)/0x\1\2\3\4/')
)
_head=$(expr $NUMBER_BYTE_SIZE  + $_head)

#eの値
cat $_file_binnakami |dd bs=1 skip=$_head count=$_e_length >$_file_e
_head=$(expr $_e_length + $_head)

#nのバイト数 
_n_length=$(printf "%d" $( cat $_file_binnakami | dd bs=1 skip=$_head count=$NUMBER_BYTE_SIZE | od -t x1 | head -n1 | cut -d" " -f2- | tr -d " " | sed -e's/^/0x/' )
)
_head=$(expr $NUMBER_BYTE_SIZE + $_head)

#nの値
cat $_file_binnakami | dd bs=1 skip=$_head count=$_n_length >$_file_n
_head=$(expr $_n_length + $_head)

} 2>/dev/null

# PKCS1の中身作成
{
_seq_len=$(expr $_n_length + $_e_length + 6)
(
printf "%b" "\x30"
printf "%b" "\x82"

printf "%b" "\x$(printf '%04x' $_seq_len | cut -b1-2)"
printf "%b" "\x$(printf '%04x' $_seq_len | cut -b3-4)"

{
printf "%b" "\x02"
printf "%b" "\x82"

printf "%b" "\x$(printf '%04x' $_n_length | cut -b1-2)"
printf "%b" "\x$(printf '%04x' $_n_length | cut -b3-4)"

cat $_file_n
}

{
printf "%b" "\x02"

printf "%b" "\x$(printf '%02x' $_e_length)"

cat $_file_e

}

) >$_file_pkcs1_bin

}

#PKCS1部のバイト数
_bytes_pkcs1=$(echo $(wc -c $_file_pkcs1_bin | tr -s " ") | cut -f1 -d " ")


#x509バイナリ作成
{
{
printf "%b" "\x30"
printf "%b" "\x0d"
printf "%b" "\x06"
printf "%b" "\x09"

(
for _char in 2a 86 48 86 f7 0d 01 01 01
do
printf "%b" "\x"$_char
done
)

printf "%b" "\x05"
printf "%b" "\x00"
printf "%b" "\x03"
printf "%b" "\x82"

#ビットのあまり指定部を長さに含む
printf "%b" "\x$(printf '%04x' $(expr $_bytes_pkcs1 + 1 ) | cut -b1-2)"
printf "%b" "\x$(printf '%04x' $(expr $_bytes_pkcs1 + 1 ) | cut -b3-4)"

#ビットのあまり指定部
printf "%b" "\x00"
}

{
cat $_file_pkcs1_bin
}

} >$_file_x509_nakami
_bytes_x509_nakami=$(echo $(wc -c $_file_x509_nakami | tr -s " ") | cut -f1 -d " ")

{
{
printf "%b" "\x30"
printf "%b" "\x82"
printf "%b" "\x$(printf '%04x' $_bytes_x509_nakami | cut -b1-2)"
printf "%b" "\x$(printf '%04x' $_bytes_x509_nakami | cut -b3-4)"
:
}
{
cat $_file_x509_nakami
}
} >$_file_x509_bin


}

#PEMに
{
echo "-----BEGIN PUBLIC KEY-----"
cat $_file_x509_bin | base64 -b 64
echo "-----END PUBLIC KEY-----"

}

for _file_tmp in $(cat $_file_tmp_files)
do
rm $_file_tmp; 
done

)
}
```

-

最新のopensshのインストールが必要なバージョン

```sh
# 暗号化する人はbrew install openssh などで最新のを入れておくこと。
# 使われ方の想定
# 相手のっssh-rsa公開鍵を入手する。(githubなどに公開されてるでしょ？)
# 公開鍵を指定して文字列を暗号化する
# >結果(暗号化+base64されたもの)をchatworkとかに貼る
# >結果はshellスクリプトなので実行してもらう。(中級者以上だと~/.ssh/id_rsaの場所がgithub用のものは違うかもしれない。)
# >勝手に見てもらう
 
# やっていること。ssh接続用の公開鍵をopensslで使える形式に変換して、opensslのrsautlをつかって暗号化します。
# 注意:実際の使いごこちはまだ試せていない。
# 感想: 秘密鍵を簡単に外に持ち出せない仕組みか自分も簡単に読めない仕組みが必要だなあと思う 
 
function rsaencrypt ()
{
  if test $# -eq 0 -o "$(echo $1 | cut -d' ' -f1)" != "ssh-rsa"
    then
    if "$(echo $1 | cut -d' ' -f1)" != "ssh-rsa"
      then
      echo "注意！　ssh接続用の公開鍵の中身を貼り付けます。ssh-rsaで始まる文字列です。"
    fi
    
cat <<EOF
usage: 
  echo "some message" | rsaencrypt <ssh-rsa から始まるssh接続用公開鍵文字列 pathではない>
  or
  rsaencrypt <ssh-rsa から始まるssh接続用公開鍵文字列 pathではない>
  <input message>
  (入力が終わったら)ctrl+d
  * ssh接続用公開鍵は cat =~/.ssh/id_rsa.pub の中身をもらうか、https://github.com/<ユーザー名>.keys
  から取得しておく。
result:
  > <base64 encoded string>
decrypt:
  * 結果はshellスクリプトなので実行してもらう。(中級者以上だと~/.ssh/id_rsaの場所がgithub用のものは違うかもしれない。入手した公開鍵と合わせる。)
 echo '<encrypted string>' | base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa
EOF
    return 1
  fi
  echo "pubkey=$1"
  echo
_encrypted=$(
(
PUB_KEY="$@"
#~/.ssh/id_rsa.pub
_file_pubkey_ssh=$(mktemp -t pubkey_ssh)
echo $PUB_KEY >$_file_pubkey_ssh
_file_pubkey=$(mktemp -t pubkey)
_file_decd_tmp=$(mktemp -t decd)
#ssh-rsaから普通のPKCS8に変換
ssh-keygen -e -m PKCS8 -f $_file_pubkey_ssh >$_file_pubkey || return 1
#echo $_file_pubkey
rm $_file_pubkey_ssh

openssl rsautl -encrypt -pubin -inkey $_file_pubkey >$_file_decd_tmp
cat $_file_decd_tmp | base64
rm $_file_decd_tmp || return 1
rm $_file_pubkey || return 1


#openssl rsautl -decrypt -inkey ~/.ssh/id_rsa <$_file_decd_tmp

) )
if test $? -eq 0
then
  echo "##ここから下渡す"
  echo "( echo $_encrypted | base64 -D | openssl rsautl -decrypt -inkey ~/.ssh/id_rsa )"
fi
} 
```