8

私はかなり初心者の C++ プログラマーです (私はまだ大学生なので、一般的にかなり初心者のプログラマーだと思います)。C++ で JWT を生成しようとしています。ヘッダーとペイロードを生成してエンコードすることはできますが、openssl の hmac ライブラリを使用して生成した署名は、jwt.io で確認すると無効のようです。これは、私が見ていない微妙な間違いによるものだと感じています。私のバグを見つけていただければ幸いです。私のコードを一般的に改善する方法についての提案もあれば、それもいただければ幸いです。json には openssl と boost を使用する必要があることに注意してください。

****アップデート****

余分な新しい行が追加されており、これが認証中にエラーを引き起こしていることがわかりました。現在、私は 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());
}
4

1 に答える 1

8

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) Base64 出力を URL セーフにする場合は、「+」を「-」に、「/」を「_」に置き換える必要があります。あなたのコードは逆です。そう:

case '+':
    ss << '-';
    break;
case '/':
    ss << '_';
    break;
于 2015-12-28T00:12:41.413 に答える