解码Base64urlUInt编码的值

时间:2015-12-15 08:58:13

标签: c# base64 rsa openid-connect jwk

我通常尝试做的是验证从OpenID Connect提供商(例如Google)获得的 id_token 值。令牌使用RSA算法进行签名,并从Discovery文档( jwks_uri 参数)中读取公钥。例如,Google密钥以JWK格式提供here

{
  kty: "RSA",
  alg: "RS256",
  use: "sig",
  kid: "38d516cbe31d4345819b786d4d227e3075df02fc",
  n: "4fQxF6dFabDqsz9a9-XgVhDaadTBO4yBZkpUyUKrS98ZtpKIQRMLoph3bK9Cua828wwDZ9HHhUxOcbcUiNDUbubtsDz1AirWpCVRRauxRdRInejbGSqHMbg1bxWYfquKKQwF7WnrrSbgdInUZPv5xcHEjQ6q_Kbcsts1Nnc__8YRdmIGrtdTAcm1Ga8LfwroeyiF-2xn0mtWDnU7rblQI4qaXCwM8Zm-lUrpSUkO6E1RTJ1L0vRx8ieyLLOBzJNwxpIBNFolMK8-DYXDSX0SdR7gslInKCn8Ihd9mpI2QBuT-KFUi88t8TW4LsoWHAwlgXCRGP5cYB4r30NQ1wMiuQ",
  e: "AQAB"
}

我将使用RSACryptoServiceProvider类来解码签名。要初始化它,我必须为RSAParameters提供模数和指数值。这些值相应地从上面的JWK读取为 n e 。根据{{​​3}},这些值是Base64urlUInt编码的值:

  

表示正整数或零整数值   base64url编码值的无符号大端表示   作为八位字节序列。八位位组序列必须使用最小值   表示该值所需的八位字节数。代表零   as BASE64URL(单个零值八位字节),即" AA"。

所以,我的问题是如何解码这些值以将它们放到RSAParameters中?我尝试将它们解码为常见的Base64url字符串(Convert.FromBase64String(modulusRaw)),但这显然不起作用并生成此错误:

  

输入不是有效的Base-64字符串,因为它包含非基数64   字符,两个以上的填充字符或非法字符   在填充字符中。

2 个答案:

答案 0 :(得分:4)

RFC 7515定义了base64url编码,如下所示:

  

使用URL和文件名安全字符集的Base64编码   在RFC 4648的第5节中定义,所有尾随' ='   省略字符(如第3.2节所允许)并且没有   包含任何换行符,空格或其他附加内容   字符。注意空八位字节的base64url编码   sequence是空字符串。 (有关说明,请参阅附录C.   在没有填充的情况下实现base64url编码。)

RFC 4648定义" Base 64编码,带有URL和文件名安全字母"作为常规base64,但是:

  • 可以省略填充(就像在这里一样)
  • 使用-代替+_代替/

因此,要使用常规Convert.FromBase64String,您只需要撤消该过程:

static byte[] FromBase64Url(string base64Url)
{
    string padded = base64Url.Length % 4 == 0
        ? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
    string base64 = padded.Replace("_", "/")
                          .Replace("-", "+");
    return Convert.FromBase64String(base64);
}

这个代码可能已经存在于框架中的某个地方,但我并不知道它。

答案 1 :(得分:0)

谁从Java来的:java.util.Base64中有两种方法:

  • getDecoder()
  • getUrlDecoder()

您可能已经猜到了:第二个已经为您完成了所有字符替换。