二段階認証で必要になったのでGolangでOTPクライアントを実装してみました。
以下をかなり非常に参考させてもらいました。
package otp
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base32"
"encoding/binary"
"time"
)
func TRUNCATE(hs []byte) int {
offset := int(hs[len(hs)-1] & 0x0F)
p := hs[offset : offset+4]
return (int(binary.BigEndian.Uint32(p)) & 0x7FFFFFFF) % 1000000
}
func HMACSHA1(k []byte, c uint64) []byte {
cb := make([]byte, 8)
binary.BigEndian.PutUint64(cb, c)
mac := hmac.New(sha1.New, k)
mac.Write(cb)
return mac.Sum(nil)
}
func TOTP(k string, x uint64) int {
key, err := base32.StdEncoding.DecodeString(k)
if err != nil {
return 0
}
return HOTP(key, T(0, x))
}
func HOTP(k []byte, c uint64) int {
return TRUNCATE(HMACSHA1(k, c))
}
func T(t0, x uint64) uint64 {
return (uint64(time.Now().Unix()) - t0) / x
}
// func main() {
// fmt.Println(TOTP("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF", 30)) // 30秒
// }
雰囲気で関数が全部大文字なってるけど HOTP/TOTP だけでよかった感。
本記事とは関係ないですが、Golang素晴らしいですね。
Javaで作っていたいくつかのAppEngineアプリを2nd Genにアップグレードしたら、Spring Bootで環境変数の一覧返すだけのWeb APIをF1インスタンス(メモリ256MB)にデプロイしたら、2回に1回メモリが溢れて落ちてしまい、全く使い物にならなかった...Google公式サイトにもJavaはオーバーヘッドが大きいとの記載があってJavaをやめる決断をしました。
勉強時間と教科書代と移行時間は結構かかってしまいましたが、代わりに全部Goに書き換えたら、メモリの使用量は1/10、実行速度はゴルーチンのおかげで3倍になり、Javaより非常に安く運用できそうです。
I/O待ちを軽量スレッド(goroutine)の仕組みを簡単に用いて潰せるのは非常にスケールさせやすいですね。GOMAXPROCSが1のGAE環境でも他サービスとの連携、DB/Storage/Datasotre/Firestore等への読み書き等を行っている間に処理を進めることでJavaよりかなり高速に実装し直せたのでとても驚きました。
とりあえず、Javaを今後使うことはないでしょう...さらばJava...