blog.yuzu441.com

web crypto apiでjwkから公開鍵を取得する

tags: javascript

最近oauth, oidcを勉強していて、jwkから公開鍵を生成する方法を調べた所、nodejsのcryptoモジュールを使う方法は紹介されていてweb crypto apiを使うパターンが気になって調べた。

web crypto api とは

Web Crypto API は、暗号化を使用してシステムを構築するためにスクリプトが暗号化プリミティブを使用することを可能にするインターフェイスです。

https://developer.mozilla.org/ja/docs/Web/API/Web_Crypto_API

テスト用の公開鍵を用意してjwkを生成する

公開鍵の生成にはopenssl、jwkの生成にはnodejsのpem-jwkライブラリを利用する

pem-jwk - npm

# 鍵の生成
openssl genrsa 2048 > private.pem
openssl rsa -pubout -in private.pem -out public.pem

# jwkの生成
pem-jwk public.pem

pem-jwkコマンドを実行して表示されるjwkをコピーしておく

jwkから公開鍵を取得する

本題のweb crypto apiでjwkから公開鍵を取得する。最終的には元のpublic.pemと同じになれば良い

// 表示されたjwkの内容を貼り付ける
const jwk = {
  kty: 'RSA',
  n: 'rvrWRLsp6Z~', // 省略
  e: 'AQAB',
}

const arrayBufferToBase64Multiline = (arrayBuffer) => {
  const bytes = new Uint8Array(arrayBuffer)
  let binary = ''
  for (let i = 0; i < bytes.length; i++) {
    binary += String.fromCharCode(bytes[i])
  }
  // btoaでBase64エンコード → 見やすいように64文字ごとに改行
  return btoa(binary).replace(/(.{64})(?!$)/g, '$1\n')
}

const spkiToPem = (spkiBuffer) => {
  const base64 = arrayBufferToBase64Multiline(spkiBuffer)
  return '-----BEGIN PUBLIC KEY-----\n' + base64 + '\n-----END PUBLIC KEY-----\n'
}

const pubKey = await crypto.subtle.importKey(
  'jwk',
  jwk,
  { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } },
  true,
  ['verify'],
)
const spki = await crypto.subtle.exportKey('spki', pubKey)
const pemPublicKey = spkiToPem(spki)
console.log(pemPublicKey)

実行

node --experimental-default-type=module index.js

これでcatコマンドなので確認するとpublic.pemと同じ内容が表示されるはず

まとめ

とりあえずjwkから公開鍵を取得することはできた。次はこの公開鍵を使ってjwtの検証をしてみようと思うんだけど、SubtleCrypto - Web API | MDN のドキュメントを見る限りは digest() メソッド を使えば検証できそう

参考