Created
January 13, 2025 07:25
-
-
Save okumurakengo/35e1e6bbf8487e22dad53990294b746b to your computer and use it in GitHub Desktop.
ChatGPT に作ってもらった、公開鍵のpemファイルからJWKに変換するサンプルと、JWKを使ったJWTの検証方法
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 公開鍵を指定して、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('='); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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