使用OpenSSL和C 来验证JWT的确切基本64 URL解码规则和实现



我是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('.'));

最新更新