使用OpenSSL和C 来验证JWT的确切基本64 URL解码规则和实现
What are the exact base64 url decoding rules and implementation using openssl and C++ to validate JWT
我是openssl接口和基本64解码规则的新手通过C 的OpenSL键,但我的示例JWT无法验证。
我只没有base64 URL解码函数,因此我在调用我的base64解码函数之前手动执行了步骤,我替换了' - ' - '>' ''和_'_'' ->'/'。为了获得适当的签名长度,我还必须手动添加填充('='(。Base64 URL解码我是否缺少某些规则,或者是首先以任何方式替换符号的方法?
我首先尝试使用rsa_verify,但错误是相同的。
使用Python和在线JWT验证验证相同的令牌和密钥,因此应该可以。我在GDB上的十六进制和python上的urlsafe_b64decode之后打印了签名,并且值是相同的(除了python版本中的某些符号外(,这甚至是更替代的策略应该是更替代的策略工作。
// This is the original token
static constexpr const char* buffer_token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYXBpLXJlc291cmNlIl0sInNjb3BlIjpbInJlYWQiXSwiZXhwIjoxNTYzNDUwODkzLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiMzVhYmVjZDEtNjcxMi00M2M3LWE4MDItZjg3MGYzMTY4MmI0IiwiY2xpZW50X2lkIjoidGVzdCJ9.ZCXtI2nN-d0Cn5dgb3K9JMI41nrEaK_AVSMRG9c5cyZqXpnMQETfGcDEs0jPzmRh-jDc-Kuq53naOtjkItMcR_vYPn72dKZ4Fpp8mvOAZXypkVCLzof3Lsxrtqq9G3V4LNTuOHiXW_q-9mEu51zWg1HDr1-rSt3YXkFFSWp5e4MWS2TNP1MB7lBbZC-kdMZ_GqZ9lrfNo2YqJR7tqcHOrfOmFTzqxVivEB8s-A0iEv_MwdlS6LpJBKU9-d94i1P9Lsqzlg7b_0ekRoYJEG4DXeNp2zxxBxZ1u3FBlIbyJoOGDmX-EU4A5eh2RlDdEvG1YF_zcMARpP1bFV86WTSOuQ";
// This is token with replaced symbols that I am testing before writing the method for url decode
static constexpr const char* buffer_token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYXBpLXJlc291cmNlIl0sInNjb3BlIjpbInJlYWQiXSwiZXhwIjoxNTYzNDUwODkzLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiMzVhYmVjZDEtNjcxMi00M2M3LWE4MDItZjg3MGYzMTY4MmI0IiwiY2xpZW50X2lkIjoidGVzdCJ9.ZCXtI2nN+d0Cn5dgb3K9JMI41nrEaK/AVSMRG9c5cyZqXpnMQETfGcDEs0jPzmRh+jDc+Kuq53naOtjkItMcR/vYPn72dKZ4Fpp8mvOAZXypkVCLzof3Lsxrtqq9G3V4LNTuOHiXW/q+9mEu51zWg1HDr1+rSt3YXkFFSWp5e4MWS2TNP1MB7lBbZC+kdMZ/GqZ9lrfNo2YqJR7tqcHOrfOmFTzqxVivEB8s+A0iEv/MwdlS6LpJBKU9+d94i1P9Lsqzlg7b/0ekRoYJEG4DXeNp2zxxBxZ1u3FBlIbyJoOGDmX+EU4A5eh2RlDdEvG1YF/zcMARpP1bFV86WTSOuQ==";
// this is how I create the RSA from a key, hopefully successfully because a key is returned with no error
RSA* create_public_rsa(const unsigned char* p_key)
{
BIO *keybio = BIO_new_mem_buf(p_key, -1); // -1: assume string is null terminated
if (!keybio)
{
return nullptr;
}
RSA* l_res = nullptr;
l_res = PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL);
BIO_free(keybio);
return l_res;
}
bool RSAVerifySignature(RSA* rsa, std::string const& token)
{
auto pub_key_handle = std::shared_ptr<EVP_PKEY>(EVP_PKEY_new(), EVP_PKEY_free);
if (!pub_key_handle)
{
return false;
}
RSA_up_ref(rsa);
EVP_PKEY_assign_RSA(pub_key_handle.get(), rsa);
std::string decoded_header(token, 0, token.find('.'));
std::string decoded_body;
decoded_body.append(token.begin()+ token.find('.')+1, token.begin() + token.rfind('.')-1);
std::string sig;
sig.append(token.begin() + token.rfind('.') + 1, token.end());
std::string sig_decoded;
base64_decode(sig.c_str(), sig.size(), sig_decoded);
EVP_MD_CTX* l_ctx = EVP_MD_CTX_create();
EVP_MD_CTX_init(l_ctx);
EVP_PKEY_CTX *pctx;
if (1 != EVP_DigestVerifyInit(l_ctx, /*&pctx*/nullptr,
EVP_sha256(), nullptr, pub_key_handle.get())) return false;
//pub_key_handle.reset();
if (1 != EVP_DigestVerifyUpdate(l_ctx, reinterpret_cast<const unsigned char*>(decoded_header.data()), decoded_header.length())) return false;
if (1 != EVP_DigestVerifyUpdate(l_ctx, ".", 1)) return false;
if (1 != EVP_DigestVerifyUpdate(l_ctx, reinterpret_cast<const unsigned char*>(decoded_body.data()), decoded_body.length())) return false;
if(1 == EVP_DigestVerifyFinal(l_ctx, reinterpret_cast<const unsigned char*>(sig_decoded.data()), sig_decoded.length())) return true;
// ERR_print_errors_fp(stdout);
ERR_load_crypto_strings();
char err[130];
while(auto e = ERR_get_error())
{
ERR_error_string(e, err);
fprintf(stderr, "Error verifying message: %sn", err);
}
return false;
}
错误是:
header: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
body: eyJhdWQiOlsiYXBpLXJlc291cmNlIl0sInNjb3BlIjpbInJlYWQiXSwiZXhwIjoxNTYzNDUwODkzLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiMzVhYmVjZDEtNjcxMi00M2M3LWE4MDItZjg3MGYzMTY4MmI0IiwiY2xpZW50X2lkIjoidGVzdCJ
sig: ZCXtI2nN+d0Cn5dgb3K9JMI41nrEaK/AVSMRG9c5cyZqXpnMQETfGcDEs0jPzmRh+jDc+Kuq53naOtjkItMcR/vYPn72dKZ4Fpp8mvOAZXypkVCLzof3Lsxrtqq9G3V4LNTuOHiXW/q+9mEu51zWg1HDr1+rSt3YXkFFSWp5e4MWS2TNP1MB7lBbZC+kdMZ/GqZ9lrfNo2YqJR7tqcHOrfOmFTzqxVivEB8s+A0iEv/MwdlS6LpJBKU9+d94i1P9Lsqzlg7b/0ekRoYJEG4DXeNp2zxxBxZ1u3FBlIbyJoOGDmX+EU4A5eh2RlDdEvG1YF/zcMARpP1bFV86WTSOuQ==
Error verifying message: error:04091068:rsa routines:INT_RSA_VERIFY:bad signature
error:04091068:rsa routines:INT_RSA_VERIFY:bad signature
这是我使用的base64_url_decode。我没有写它,但找不到我从哪里得到的。
使用以下代码,您仍然有问题吗?
/*
Base64 translates 24 bits into 4 ASCII characters at a time. First,
3 8-bit bytes are treated as 4 6-bit groups. Those 4 groups are
translated into ASCII characters. That is, each 6-bit number is treated
as an index into the ASCII character array.
If the final set of bits is less 8 or 16 instead of 24, traditional base64
would add a padding character. However, if the length of the data is
known, then padding can be eliminated.
One difference between the "standard" Base64 is two characters are different.
See RFC 4648 for details.
This is how we end up with the Base64 URL encoding.
*/
const char base64_url_alphabet[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
std::string base64_url_encode(const std::string & in) {
std::string out;
int val =0, valb=-6;
size_t len = in.length();
unsigned int i = 0;
for (i = 0; i < len; i++) {
unsigned char c = in[i];
val = (val<<8) + c;
valb += 8;
while (valb >= 0) {
out.push_back(base64_url_alphabet[(val>>valb)&0x3F]);
valb -= 6;
}
}
if (valb > -6) {
out.push_back(base64_url_alphabet[((val<<8)>>(valb+8))&0x3F]);
}
return out;
}
std::string base64_url_decode(const std::string & in) {
std::string out;
std::vector<int> T(256, -1);
unsigned int i;
for (i =0; i < 64; i++) T[base64_url_alphabet[i]] = i;
int val = 0, valb = -8;
for (i = 0; i < in.length(); i++) {
unsigned char c = in[i];
if (T[c] == -1) break;
val = (val<<6) + T[c];
valb += 6;
if (valb >= 0) {
out.push_back(char((val>>valb)&0xFF));
valb -= 8;
}
}
return out;
}
更新:
您的问题不是base64解码,而是这一行:
decoded_body.append(token.begin()+ token.find('.')+1, token.begin() + token.rfind('.')-1);
你是一个人。解码器丢失了最后一个字符。如果将其更改为以下内容,则可以正常工作:
decoded_body.append(token.begin()+ token.find('.')+1, token.begin() + token.rfind('.'));
相关文章:
- 无法解码base64+deflate数据
- 如何使用url确定网站协议
- 下载URL中的所有文件
- 使用libcurl提交批量url的正确BING Api POST url是什么
- 正在解码MSVC 32位版本的程序集(作业).没有手术做什么
- 使用已使用 java 编码的 openssl 解码数据
- 如何使用 OpenCV 解码在两个 UWP 应用之间发送的图像字节?
- 错误:(-210:不支持的格式或格式组合)功能'create'中的硬件视频解码器不支持视频源
- 从原始字节解码协议缓冲区(以 C++为单位)
- 将所有 URL 组织在类中的一个位置
- FFmpeg——使用硬件加速进行视频解码
- 如何从WIC解码器确定自上而下/自下而上?
- 使用OpenSSL和C 来验证JWT的确切基本64 URL解码规则和实现
- 如何在C 服务器中解码卷曲URL编码的字符串
- C URL用UTF8字符错误解码
- 用C++对URl进行编码/解码
- 解码编码的俄罗斯字符从url到实际字符在BHO
- QMessageBox - url编码/解码
- C++中的URL编码和nodejs中的解码
- 帮助我理解此URL解码器: