Я довольно новичок в программировании на С ++ (я все еще учусь в колледже, поэтому я полагаю, что я довольно начинающий программист в целом), и я пытаюсь сгенерировать JWT на С ++. Я могу генерировать и кодировать заголовок и полезную нагрузку, но подпись, которую я генерирую с помощью библиотеки hmac от openssl, кажется, неверна, когда я проверяю ее на jwt.io. У меня такое ощущение, что это из-за какой-то нюансовой ошибки, которую я просто не вижу. Если вы можете найти мою ошибку, я буду очень признателен. Если у вас также есть предложения по улучшению моего кода в целом, это также будет оценено. Примечание: я должен использовать openssl и boost для json.
****ОБНОВИТЬ****
Я обнаружил, что добавляются дополнительные новые строки, и это вызывает ошибки во время аутентификации. В настоящее время я звоню str.erase, чтобы удалить их, но если бы кто-то мог сообщить мне, куда они идут, я был бы признателен, чтобы избежать необходимости манипулировать строкой
char* Auth::genJWT()
{
ptree pt;
std::stringstream jwt;
//Make and encode header
pt.put("typ","JWT");
pt.put("alg","HS256");
std::ostringstream buf;
write_json(buf, pt, false);
std::string header = buf.str();
jwt << base64_encode((unsigned char*)header.c_str(), (int) header.length());
//clear buffer
pt.clear();
buf.clear();
buf.str("");
//make pay load
pt.put("org_guid", Config::organization_guid);
pt.put("agent_guid", Config::agent_guid);
write_json(buf, pt, false);
std::string payload = buf.str();
jwt << '.' << base64_encode((unsigned char*)payload.c_str(), (int) payload.length());
//sign data
std::string signed_data = signToken(jwt.str());
jwt << '.' << base64_encode((unsigned char*) signed_data.c_str(), (int) signed_data.length());
//jwt made
std::cout << "JWT Token: " << jwt.str() << std::endl;
//Note I am testing by copying the token into an online debugger
//returning "" is not my bug
return "";
}
Это метод, который я использую подписать токен
std::string Auth::signToken(std::string to_sign)
{
//std::string key = Config::secret;
std::string key = "foo";
unsigned int len = 32;
unsigned char signed_data[32];
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, &key[0], (int) key.length(), EVP_sha256(), NULL);
HMAC_Update(&ctx, (unsigned char*)&to_sign[0], to_sign.length());
HMAC_Final(&ctx, signed_data, &len);
HMAC_CTX_cleanup(&ctx);
std::stringstream ss;
ss << std::setfill('0');
for(unsigned int i = 0; i < len; i++)
{
ss << signed_data[i];
}
return (ss.str());
}
Вот как я кодирую данные в base64Url
std::string Auth::base64_encode(const unsigned char* input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
std::stringstream ss;
//make URL safe
for(unsigned int i = 0; i < bptr->length - 1; i++)
{
switch(bptr->data[i])
{
case '+':
ss << '_';
break;
case '/':
ss << '-';
break;
case '=':
//don't add in padding
break;
default:
ss << bptr->data[i];
break;
}
}
BIO_free_all(b64);
return (ss.str());
}
OpenSSL вставляет символ новой строки после каждого 64-го символа, вы можете отключить это, используя:
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
Увидеть документация Вот.
При тестировании вашего кода я также обнаружил следующие 2 проблемы:
1) Вы пропускаете последний символ буфера, когда делаете его URL-безопасным. Вы должны удалить — 1.
for(unsigned int i = 0; i < bptr->length ; i++)
2) При обеспечении безопасности URL-адреса Base64 необходимо заменить «+» на «-» и «/» на «_». ваш код имел это наоборот. Так:
case '+':
ss << '-';
break;
case '/':
ss << '_';
break;