Skip to content

Instantly share code, notes, and snippets.

@okumurakengo
Created January 13, 2025 07:25
Show Gist options
  • Select an option

  • Save okumurakengo/35e1e6bbf8487e22dad53990294b746b to your computer and use it in GitHub Desktop.

Select an option

Save okumurakengo/35e1e6bbf8487e22dad53990294b746b to your computer and use it in GitHub Desktop.
ChatGPT に作ってもらった、公開鍵のpemファイルからJWKに変換するサンプルと、JWKを使ったJWTの検証方法
// 公開鍵を指定して、JWK形式で出力してくれるサンプル
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text.Json;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
public class MyJwk
{
public static void Handle()
{
string publicKeyPath = "public_key.pem";
var jwk = ConvertPemToJwk(publicKeyPath);
Console.WriteLine("JWK:");
Console.WriteLine(jwk);
}
static string ConvertPemToJwk(string publicKeyPath)
{
// PEM ファイルを読み込む
string pem = File.ReadAllText(publicKeyPath);
// BouncyCastle を使って公開鍵をパース
PemReader pemReader = new PemReader(new StringReader(pem));
RsaKeyParameters rsaKey = (RsaKeyParameters)pemReader.ReadObject();
// "n" (モジュラス) と "e" (公開指数) を取得
byte[] modulusBytes = rsaKey.Modulus.ToByteArrayUnsigned();
byte[] exponentBytes = rsaKey.Exponent.ToByteArrayUnsigned();
// Base64URL エンコード
string n = Base64UrlEncode(modulusBytes);
string e = Base64UrlEncode(exponentBytes);
// JWK を JSON にシリアライズ
var jwk = new
{
kty = "RSA",
n = n,
e = e
};
return JsonSerializer.Serialize(jwk, new JsonSerializerOptions { WriteIndented = true });
}
static string Base64UrlEncode(byte[] input)
{
return Convert.ToBase64String(input)
.Replace("+", "-")
.Replace("/", "_")
.TrimEnd('=');
}
}
// JWK 情報から JWT を検証するサンプル
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
using System.Text.Json;
using Microsoft.IdentityModel.Tokens;
class Program
{
static void Main(string[] args)
{
// JWK の公開鍵情報
string jwkJson = @"
{
""kty"": ""RSA"",
""n"": ""yP98sDn-2VHGfPRDF8ecAOdGW0vkLFmNcoPGHo0YzehdBtBrC17KKig9ML63OrIZsx_RnBAGA_jXCkmB7s93I-rnLNXxNA83YTY2bqkAnbT3ULi_xDLc7p26vHYY7f7iS3Ykbz-GMZjpvK-MfLMwQG77NfpjwsimBGNeW-k7qlMwK9rNpPPLyTQMS4MsV1w_iV9v3jn8G29uJiR1Qej-fY6TTT1-8PWOWuvjV9pL9HQ2CWuas6q-nJCjXUb8oyo7Vgmhi2_yYwDGugsKvOxeweMxrcSEJDZsSUoLQFbV4ld-843y6502Yp5j8wFCWQTvRYSPHqw5BzAmbqIKIbjTmw"",
""e"": ""AQAB""
}";
// 検証対象の JWT
string jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIiwiZW1haWwiOiJ1c2VyQGV4YW1wbGUuY29tIiwianRpIjoiYTg2YjFhMjEtNmIyZC00ODg1LWI2YzUtNTI2ZGJhYTkxMDJmIiwiZXhwIjoxNzM2NzUyNzMwLCJpc3MiOiJ5b3VyLWFwcCIsImF1ZCI6InlvdXItYXVkaWVuY2UifQ.jKR9kZMBcSDCv1hNmkrNsNEAXU8Vfh6G8GLUmmpDOWPKirVpp3Ut-5dbqlu30i2qUHa3PRvPV5kCBNpbJNYzYk9KlyJKAdaPySsBfzw6TC5hBvIaKmhS3DndNF2O8CuAdWTFX-BMKXA6ofR4e6w6IJjxxegPCMRLCic6MYR0os4XqgQTXDS9NVtNm5zYU-kjo__qLTnMeTW0U1IrpOKxVYNmxqd2OuPT7TNVIIPZWO-rUbO2JtAKtevqdWSLF_hgWnHRvHO_Cb5Sba37N_EyUK0apbRAg6kiUetPRE-UL1bcQmoAKw5uf6Xlx_USnOYq1xvQ4E_37BAasuGjbClsGQ";
// JWK を使って検証
try
{
var parameters = GetRsaParametersFromJwk(jwkJson);
var rsa = RSA.Create();
rsa.ImportParameters(parameters);
var securityKey = new RsaSecurityKey(rsa);
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = false, // 必要に応じて発行者の検証を有効化
ValidateAudience = false, // 必要に応じてオーディエンスの検証を有効化
ValidateLifetime = true, // 有効期限の検証を有効化
IssuerSigningKey = securityKey
};
// JWT を検証
var principal = tokenHandler.ValidateToken(jwt, validationParameters, out var validatedToken);
Console.WriteLine("JWT is valid.");
Console.WriteLine($"Claims: {string.Join(", ", principal.Claims)}");
}
catch (Exception ex)
{
Console.WriteLine($"JWT validation failed: {ex.Message}");
}
}
static RSAParameters GetRsaParametersFromJwk(string jwkJson)
{
// JWK をパース
var jwk = JsonSerializer.Deserialize<Jwk>(jwkJson);
if (jwk == null)
throw new ArgumentException("Invalid JWK JSON.");
// Base64URL デコード
var modulus = Base64UrlDecode(jwk.n);
var exponent = Base64UrlDecode(jwk.e);
return new RSAParameters
{
Modulus = modulus,
Exponent = exponent
};
}
static byte[] Base64UrlDecode(string base64Url)
{
string padded = base64Url
.Replace('-', '+')
.Replace('_', '/')
.PadRight(base64Url.Length + (4 - base64Url.Length % 4) % 4, '=');
return Convert.FromBase64String(padded);
}
class Jwk
{
public string kty { get; set; } = string.Empty;
public string n { get; set; } = string.Empty;
public string e { get; set; } = string.Empty;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment