Kotlinで公開鍵暗号方式の鍵を扱うときの備忘録とかJWTの生成とか
目的
KotlinでJWTを生成したい。
実際はKtorでサーバー書いてJWT返す処理を書いたけど、そこは割愛。
準備
opensslで秘密鍵の生成。
$ openssl genrsa -out private.key 2048
JavaのPKCS8EncodedKeySpecで秘密鍵のインスタンスを作るのに秘密鍵を PKCS 8 形式にしておく。
$ openssl pkcs8 -in private.key -topk8 -nocrypt -out private.key.pk8
公開鍵は特別なことはせず作成。
$ openssl rsa -in private.key -pubout -out public.key
鍵、どうやって扱おう
鍵ファイルをそのまま扱うのは正直面倒なので、環境変数に格納して扱いたい。
ただ、ファイルの内容をそのまま環境変数に入れようとしても改行が入っているのでそのまま扱うのは避けたい。
扱えないわけではないけど、改行コードの扱いだったりDotenvのアレコレでハマるのも嫌なので改行なしの文字列として扱えるようにしてしまう。
以下のような感じでソイヤっとBase64エンコードしちゃう。で、それを環境変数だったり.envに設定する。
そもそも鍵の中身自体Base64エンコードされていてマトリョーシカ感あるけどソレはソレ。
$ base64 -i private.key.pk8 $ base64 -i public.key
作った鍵を使ってJWTを生成する
JWTの生成は以下を利用。
鍵の文字列からそれぞれのKeySpecをつくるところは、そのまま以下のブログを参考にした。
PemReader.readFirstSectionAndClose
を使いたいがために以下を入れてしまっているので、気になる人は自分で書いても良いと思う。
private val dotenv = dotenv { ignoreIfMissing = true } private val privateKeyString = Base64.getDecoder().decode(dotenv.get("RSA_PRIVATE_KEY")).decodeToString() private val publicKeyString = Base64.getDecoder().decode(dotenv.get("RSA_PUBLIC_KEY")).decodeToString() private val keyFactory: KeyFactory = KeyFactory.getInstance("RSA") private val privateKey = keyFactory.generatePrivate(privateKeyString.fromPKCS8toKeySpec()) as RSAPrivateKey private val publicKey = keyFactory.generatePublic(publicKeyString.fromX509toKeySpec()) as RSAPublicKey private val algorithm: Algorithm = Algorithm.RSA256(publicKey, privateKey) fun create(contract: PostContract): String { return JWT.create() .withIssuer("hogehoge") .withExpiresAt(Date.from(ZonedDateTime.now(ZoneOffset.UTC).plusDays(1L).toInstant())) .withIssuedAt(Date.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant())) .sign(algorithm) } private fun String.fromPKCS8toKeySpec(): PKCS8EncodedKeySpec { return PKCS8EncodedKeySpec(PemReader.readFirstSectionAndClose(StringReader(this)).base64DecodedBytes) } private fun String.fromX509toKeySpec(): X509EncodedKeySpec { return X509EncodedKeySpec(PemReader.readFirstSectionAndClose(StringReader(this)).base64DecodedBytes) }