概要
cscの作法、調べてみた。
jwtをデコードしてみた。
サンプルコード
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LitJson;
public enum JwtHashAlgorithm {
RS256,
HS384,
HS512
}
public class jwt {
private static Dictionary<JwtHashAlgorithm, Func<byte[], byte[], byte[]>> HashAlgorithms;
static jwt() {
HashAlgorithms = new Dictionary<JwtHashAlgorithm, Func<byte[], byte[], byte[]>> {
{
JwtHashAlgorithm.RS256, (key, value) => {
using (var sha = new HMACSHA256(key))
{
return sha.ComputeHash(value);
}
}
}, {
JwtHashAlgorithm.HS384, (key, value) => {
using (var sha = new HMACSHA384(key))
{
return sha.ComputeHash(value);
}
}
}, {
JwtHashAlgorithm.HS512, (key, value) => {
using (var sha = new HMACSHA512(key))
{
return sha.ComputeHash(value);
}
}
}
};
}
public static string Encode(object payload, string key, JwtHashAlgorithm algorithm) {
return Encode(payload, Encoding.UTF8.GetBytes(key), algorithm);
}
public static string Encode(object payload, byte[] keyBytes, JwtHashAlgorithm algorithm) {
var segments = new List<string>();
var header = new {
alg = algorithm.ToString(),
typ = "JWT"
};
byte[] headerBytes = Encoding.UTF8.GetBytes(LitJson.JsonMapper.ToJson(header));
byte[] payloadBytes = Encoding.UTF8.GetBytes(LitJson.JsonMapper.ToJson(payload));
segments.Add(Base64UrlEncode(headerBytes));
segments.Add(Base64UrlEncode(payloadBytes));
var stringToSign = string.Join(".", segments.ToArray());
var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
byte[] signature = HashAlgorithms[algorithm](keyBytes, bytesToSign);
segments.Add(Base64UrlEncode(signature));
return string.Join(".", segments.ToArray());
}
public static string Decode(string token, string key) {
return Decode(token, key, true);
}
public static string Decode(string token, string key, bool verify) {
var parts = token.Split('.');
var header = parts[0];
var payload = parts[1];
byte[] crypto = Base64UrlDecode(parts[2]);
var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
var headerData = LitJson.JsonMapper.ToObject(headerJson);
var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
var payloadData = LitJson.JsonMapper.ToObject(payloadJson);
if (verify)
{
var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
var keyBytes = Encoding.UTF8.GetBytes(key);
var algorithm = (string) headerData["alg"];
var signature = HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign);
var decodedCrypto = Convert.ToBase64String(crypto);
var decodedSignature = Convert.ToBase64String(signature);
if (decodedCrypto != decodedSignature)
{
throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
}
}
return payloadData.ToString();
}
private static JwtHashAlgorithm GetHashAlgorithm(string algorithm) {
switch (algorithm)
{
case "RS256":
return JwtHashAlgorithm.RS256;
case "HS384":
return JwtHashAlgorithm.HS384;
case "HS512":
return JwtHashAlgorithm.HS512;
default:
throw new InvalidOperationException("Algorithm not supported.");
}
}
public static string Base64UrlEncode(byte[] input) {
var output = Convert.ToBase64String(input);
output = output.Split('=')[0];
output = output.Replace('+', '-');
output = output.Replace('/', '_');
return output;
}
public static byte[] Base64UrlDecode(string input) {
var output = input;
output = output.Replace('-', '+');
output = output.Replace('_', '/');
switch (output.Length % 4)
{
case 0:
break;
case 2:
output += "==";
break;
case 3:
output += "=";
break;
default:
throw new System.Exception("Illegal base64url string!");
}
var converted = Convert.FromBase64String(output);
return converted;
}
}
public class test0 {
static void Main() {
string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
var parts = token.Split('.');
var header = parts[0];
var payload = parts[1];
byte[] crypto = jwt.Base64UrlDecode(parts[2]);
var headerJson = Encoding.UTF8.GetString(jwt.Base64UrlDecode(header));
Console.WriteLine(headerJson);
var headerData = LitJson.JsonMapper.ToObject(headerJson);
var payloadJson = Encoding.UTF8.GetString(jwt.Base64UrlDecode(payload));
Console.WriteLine(payloadJson);
var payloadData = LitJson.JsonMapper.ToObject(payloadJson);
var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
var algorithm = (string) headerData["alg"];
var decodedCrypto = Convert.ToBase64String(crypto);
Console.WriteLine("ok");
}
}
実行結果
>jwt0
{"alg":"HS256","typ":"JWT"}
{"sub":"1234567890","name":"John Doe","iat":1516239022}
ok
以上。