如何在 golang 中将 65537 转换为 AQAB
How to convert 65537 to AQAB in golang
我正在围绕 JWT 创建和验证编写一些单元和集成测试。我正在使用我用 openssl 创建的真实(良好的自签名)证书拼凑一个快速的 JWKS 页面,并且我一直在做饭,直到我遇到这个非常简单的问题:
“E”值为 65537,但在 JWKS 中它假定为 AQAB。在墙上敲了很久脑袋,终于在纸上想通了。
https://www.rfc-editor.org/rfc/rfc7518#section-6.3.1.2
65537 是
0000 0001: 0000 0000 : 0000 0001
如果你将它转换为 6 位的 base64,你会得到
000000 010000 000000 000001
哪个是A Q A B
https://en.wikipedia.org/wiki/Base64#Base64_table
所以我尝试编写一些快速代码。但它证明非常不快。我在想,一定有更简单的方法。我尝试过的所有 base64 编码都超过 3 个字节。
任何有自尊的编码员都会做的事情也是如此...我看到每个人都使用 65537,所以我对那个傻瓜进行了硬编码并继续前进,但它一直在唠叨我。我讨厌让我烦恼的问题。
我得到的最接近的是:
bs := make([]byte, 4)
binary.BigEndian.PutUint32(bs, 65537)
fmt.Println(bs)
fmt.Println(base64.URLEncoding.EncodeToString(bs))
产生了:
[0 1 0 1]
AAEAAQ==
根据我的快速数学计算,base64 输出是超过 3 个字节的原因 :D
你正在用 base64 编码 4 个二进制字节:
bs := make([]byte, 4) // `AAEAAQ==`
这将产生 6 (4*8/6
) 个 base64 字符 - 加上 ==
填充。
您想编码 三个 个二进制字节 - 这将产生 4 (3*8/6
) 个 base64 字符。
bs := []byte{1, 0, 1}
fmt.Println(bs)
fmt.Println(base64.URLEncoding.EncodeToString(bs)) // `AQAB`
https://play.golang.org/p/gDviu06pftR
编辑
所以你只需要 lower-significant 3 个字节(如果使用 BigEndian,则在最后)。
所以你可以使用你的原始代码:
bs := make([]byte, 4)
binary.BigEndian.PutUint32(bs, 65537)
bs = bs[1:] // drop most significant byte - leaving least-significant 3-bytes
fmt.Println(base64.URLEncoding.EncodeToString(bs)) // `AQAB`
或者如果您查看 binary.BigEndian.PutUint32 的源代码,您可以看到它如何从 uint32
中提取 4 个字节 - 并对 3 个字节执行相同的操作:
bs := make([]byte, 3)
v := 65537
bs[0] = byte(v >> 16)
bs[1] = byte(v >> 8)
bs[2] = byte(v)
fmt.Println(base64.URLEncoding.EncodeToString(bs)) // `AQAB`
我正在围绕 JWT 创建和验证编写一些单元和集成测试。我正在使用我用 openssl 创建的真实(良好的自签名)证书拼凑一个快速的 JWKS 页面,并且我一直在做饭,直到我遇到这个非常简单的问题:
“E”值为 65537,但在 JWKS 中它假定为 AQAB。在墙上敲了很久脑袋,终于在纸上想通了。
https://www.rfc-editor.org/rfc/rfc7518#section-6.3.1.2
65537 是 0000 0001: 0000 0000 : 0000 0001
如果你将它转换为 6 位的 base64,你会得到
000000 010000 000000 000001
哪个是A Q A B
https://en.wikipedia.org/wiki/Base64#Base64_table
所以我尝试编写一些快速代码。但它证明非常不快。我在想,一定有更简单的方法。我尝试过的所有 base64 编码都超过 3 个字节。
任何有自尊的编码员都会做的事情也是如此...我看到每个人都使用 65537,所以我对那个傻瓜进行了硬编码并继续前进,但它一直在唠叨我。我讨厌让我烦恼的问题。
我得到的最接近的是:
bs := make([]byte, 4)
binary.BigEndian.PutUint32(bs, 65537)
fmt.Println(bs)
fmt.Println(base64.URLEncoding.EncodeToString(bs))
产生了:
[0 1 0 1]
AAEAAQ==
根据我的快速数学计算,base64 输出是超过 3 个字节的原因 :D
你正在用 base64 编码 4 个二进制字节:
bs := make([]byte, 4) // `AAEAAQ==`
这将产生 6 (4*8/6
) 个 base64 字符 - 加上 ==
填充。
您想编码 三个 个二进制字节 - 这将产生 4 (3*8/6
) 个 base64 字符。
bs := []byte{1, 0, 1}
fmt.Println(bs)
fmt.Println(base64.URLEncoding.EncodeToString(bs)) // `AQAB`
https://play.golang.org/p/gDviu06pftR
编辑
所以你只需要 lower-significant 3 个字节(如果使用 BigEndian,则在最后)。
所以你可以使用你的原始代码:
bs := make([]byte, 4)
binary.BigEndian.PutUint32(bs, 65537)
bs = bs[1:] // drop most significant byte - leaving least-significant 3-bytes
fmt.Println(base64.URLEncoding.EncodeToString(bs)) // `AQAB`
或者如果您查看 binary.BigEndian.PutUint32 的源代码,您可以看到它如何从 uint32
中提取 4 个字节 - 并对 3 个字节执行相同的操作:
bs := make([]byte, 3)
v := 65537
bs[0] = byte(v >> 16)
bs[1] = byte(v >> 8)
bs[2] = byte(v)
fmt.Println(base64.URLEncoding.EncodeToString(bs)) // `AQAB`