解码 Base64urlUInt 编码值

Decoding Base64urlUInt-encoded value

我通常尝试做的是验证从 OpenID Connect 提供商(例如 Google)获得的 id_token 值。使用 RSA 算法对令牌进行签名,并从 JWK 格式的 Discovery document (the jwks_uri parameter). For example, Google keys are available here 中读取 public 密钥:

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

我将使用 RSACryptoServiceProvider class for decoding the signature. To initialize it, I have to provide RSAParameters with the Modulus and Exponent values. These values are read from the above JWK as n and e correspondingly. According to the specification,这些值是 Base64urlUInt 编码的值:

The representation of a positive or zero integer value as the base64url encoding of the value's unsigned big-endian representation as an octet sequence. The octet sequence MUST utilize the minimum number of octets needed to represent the value. Zero is represented as BASE64URL(single zero-valued octet), which is "AA".

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

The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

RFC 7515 像这样定义 base64url 编码:

Base64 encoding using the URL- and filename-safe character set defined in Section 5 of RFC 4648, with all trailing '=' characters omitted (as permitted by Section 3.2) and without the inclusion of any line breaks, whitespace, or other additional characters. Note that the base64url encoding of the empty octet sequence is the empty string. (See Appendix C for notes on implementing base64url encoding without padding.)

RFC 4648 将 "Base 64 Encoding with URL and Filename Safe Alphabet" 定义为常规 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);
}

可能此代码已存在于框架中的某处,但我不知道。

谁曾从Java来到这里:java.util.Base64有两种方法:

  • getDecoder()
  • getUrlDecoder()

正如您可能假设的那样:使用第二个字符已经为您完成了所有字符替换。