SSH 公開鍵ユーティリティを Go と Python で作った

はじめに

こんにちは、 NHK 技研公開に行った所、何度も「学生さんですか?」と訊かれた yosida95 です。

タイトルのとおり、 Pure Go と Pure Python で SSH 公開鍵ユーティリティを作ったのでご案内します。

Go
yosida95/golang-sshkey
Python
yosida95/python-sshkey

SSH 公開鍵ユーティリティ

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMjH3YZMNFG8cnl98t6w6Ca152cnTsWyrZ56WYSYNkEax1grChZB3P4NcxmtqFxrN2wMXuATiqp62cNkj8wAQUIwRgUnqKkkaQTDyLEDVaTZ75RsZIE4vM/YJ5AzmbCIHK8u6YvfM8fIlv4PKzbMHIIcZvuG9ZYQ+ZEKmSIVxIKZNVfUYyoRK6RFPEMjZPGGoOFRBo8sifsJDLDIBLWOgR4Nf2rWuV+ZuySXX9wjsv42iIdp9RVJcjQXHmi7AKVifKfFJwM+6aPiQcAaWnINzvUnqQK5yrWEp5tVH49bFL92UNriT+LTozloILCj5SdqXQ+JbKp/6EobY96bWhkwyZ yosida95@yosida95

上に示したのが SSH 公開鍵で、ちなみに普段ぼくが使っているものです。 よく見るフォーマットだと思います。

この公開鍵は、目に見える通り3つのパートから成っていて、左からアルゴリズム、公開鍵、コメントとなっています。 また、2つめの公開鍵のパートは BASE64 エンコードされていて、デコードすると RSA の場合は "ssh-rsa", exponent (E), modulus (N) のように、アルゴリズムと公開鍵のパラメーターが含まれています。

今回作ったユーティリティでは、 Printable ASCII で表現される公開鍵をデコードし、コメントや鍵長を取得したり、フィンガープリント(鍵指紋)を計算したり、 golang-sshkey の場合は crypto/rsa の *rsa.PublicKey のような標準的な構造体に変換したりできます。

インストール

golang-sshkey

$ go get github.com/yosida95/golang-sshkey

python-sshkey

$ pip install sshkey

使い方

golang-sshkey

package main

import (
        "crypto"
        "crypto/rsa"
        "fmt"

        "github.com/yosida95/golang-sshkey"
)

const (
        marshaledPub = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMjH3YZMNFG8cnl98t6w6Ca152cnTsWyrZ56WYSYNkEax1grChZB3P4NcxmtqFxrN2wMXuATiqp62cNkj8wAQUIwRgUnqKkkaQTDyLEDVaTZ75RsZIE4vM/YJ5AzmbCIHK8u6YvfM8fIlv4PKzbMHIIcZvuG9ZYQ+ZEKmSIVxIKZNVfUYyoRK6RFPEMjZPGGoOFRBo8sifsJDLDIBLWOgR4Nf2rWuV+ZuySXX9wjsv42iIdp9RVJcjQXHmi7AKVifKfFJwM+6aPiQcAaWnINzvUnqQK5yrWEp5tVH49bFL92UNriT+LTozloILCj5SdqXQ+JbKp/6EobY96bWhkwyZ yosida95@yosida95"
)

func main() {
        pubkey, err := sshkey.UnmarshalPublicKey(marshaledPub)
        if err != nil {
                panic(err)
        }
        nativePub := pubkey.Public().(*rsa.PublicKey)

        fmt.Println(pubkey.Type() == sshkey.KEY_RSA)
        fmt.Println(nativePub.E)
        fmt.Println(pubkey.Length())
        fmt.Println(pubkey.Comment())

        fp, _ := sshkey.PrettyFingerprint(pubkey, crypto.MD5)
        fmt.Println(fp)

        // Output:
        // true
        // 65537
        // 2048
        // yosida95@yosida95
        // 17:59:d1:53:0a:38:33:91:ff:8c:f8:f6:16:89:ed:f0
}

python-sshkey

# -*- coding: utf-8 -*-

import sshkey.public

marshaled_pub = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMjH3YZMNFG8cnl98t6w6Ca152cnTsWyrZ56WYSYNkEax1grChZB3P4NcxmtqFxrN2wMXuATiqp62cNkj8wAQUIwRgUnqKkkaQTDyLEDVaTZ75RsZIE4vM/YJ5AzmbCIHK8u6YvfM8fIlv4PKzbMHIIcZvuG9ZYQ+ZEKmSIVxIKZNVfUYyoRK6RFPEMjZPGGoOFRBo8sifsJDLDIBLWOgR4Nf2rWuV+ZuySXX9wjsv42iIdp9RVJcjQXHmi7AKVifKfFJwM+6aPiQcAaWnINzvUnqQK5yrWEp5tVH49bFL92UNriT+LTozloILCj5SdqXQ+JbKp/6EobY96bWhkwyZ yosida95@yosida95'


def main():
    pub = sshkey.public.from_openssh(marshaled_pub)
    print(pub.type)  # => sshkey.public.SSHKeyType.RSA
    print(pub.length)  # => 2048
    print(pub.comment)  # => yosida95@yosida95
    print(pub.pretty_finger_print())  # => 17:59:d1:53:0a:38:33:91:ff:8c:f8:f6:16:89:ed:f0


if __name__ == '__main__':
    main()

実績

実は今回作ったのは golang-sshkey の方だけで、 python-sshkey の方は半年前に作って公開していたものです。 この python-sshkey にはすでに、私が所属するゲヒルンが提供する Gehirn Infrastructure ServicesRS2 Plus で使われているという実績があります。

Gehirn RS2 Plus 公開鍵の管理 [シリーズGWS]第4回 Gehirn RS2 Plus のアカウントを作り SSH でログインする

また、近々 golang-sshkey の方も同様に Gehirn RS2 Plus で利用する予定があります。

おわりに

どちらのパッケージも3条項 BSD ライセンスで公開しています。 ご活用ください。 また、コントリビュートをお待ちしています。

こちらからは以上です。