2016-11-12 38 views
2

我想驗證一個JSON Web Tokens (JWT)與OpenSSL,但我無法驗證成功。下面是一個使用令牌和密鑰我的代碼Verifying JWT signed with the RS256 algorithm using public key in C#如何使用OpenSSL驗證JSON Web令牌?

QByteArray token  = "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAsCiAiY19oYXNoIjogIkxEa3RLZG9RYWszUGswY25YeENsdEEiCn0.XW6uhdrkBgcGx6zVIrCiROpWURs-4goO1sKA4m9jhJIImiGg5muPUcNegx6sSv43c5DSn37sxCRrDZZm4ZPBKKgtYASMcE20SDgvYJdJS0cyuFw7Ijp_7WnIjcrl6B5cmoM6ylCvsLMwkoQAxVublMwH10oAxjzD6NEFsu9nipkszWhsPePf_rM4eMpkmCbTzume-fzZIi5VjdWGGEmzTg32h3jiex-r5WTHbj-u5HL7u_KP3rmbdYNzlzd1xWRYTUs4E8nOTgzAUwvwXkIQhOh5TPcSMBYy6X3E7-_gr9Ue6n4ND7hTFhtjYs3cjNKIA08qm5cpVYFMFMG6PkhzLQ); 
QByteArray rsaModulus = QByteArray::fromBase64("w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ"); 
QByteArray rsaExponent = QByteArray::fromBase64("AQAB"); 

QList<QByteArray> tokenParts = token.split('.'); 
QByteArray header = tokenParts[0]; 
QByteArray body = tokenParts[1]; 
QByteArray sig = tokenParts[2]; 

QByteArray pad = sig.length() % 4 ? "" : QByteArray("====").left(4 - (sig.length() % 4)); 
QByteArray decodedSig = QByteArray::fromBase64(sig.replace('_', '/').replace('-', '+') + pad); 

BIGNUM *rsaModulusBn = BN_bin2bn((unsigned char *)rsaModulus.data(), rsaModulus.length(), NULL); 
BIGNUM *rsaExponentBn = BN_bin2bn((unsigned char *)rsaExponent.data(), rsaExponent.length(), NULL); 

RSA *rsa = RSA_new(); 
if (rsa == NULL) printf("cannot allocate RSA\n"); 
rsa->n = rsaModulusBn; 
rsa->e = rsaExponentBn; 

EVP_PKEY *key = EVP_PKEY_new(); 
if (1 != EVP_PKEY_set1_RSA(key, rsa)) ERR_print_errors_fp(stdout); 

EVP_MD_CTX *ctx = EVP_MD_CTX_create(); 
if (ctx == NULL) printf("cannot allocate MD CTX\n"); 

if (1 != EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, key)) ERR_print_errors_fp(stdout); 
if (1 != EVP_DigestVerifyUpdate(ctx, (unsigned char *)header.data(), header.length())) ERR_print_errors_fp(stdout); 
if (1 != EVP_DigestVerifyUpdate(ctx, ".", 1)) ERR_print_errors_fp(stdout); 
if (1 != EVP_DigestVerifyUpdate(ctx, (unsigned char *)body.data(), body.length())) ERR_print_errors_fp(stdout); 
if (1 != EVP_DigestVerifyFinal(ctx, (unsigned char *)decodedSig.data(), decodedSig.length())) 
{ 
    printf("failure\n"); 
    ERR_print_errors_fp(stdout); 
} 
else 
{ 
    printf("success\n"); 
} 

if (ctx) EVP_MD_CTX_destroy(ctx); 
if (key) EVP_PKEY_free(key); 
if (rsa) RSA_free(rsa); 

萬一它有助於node jwt-to-pem說,在PEM格式上面的關鍵是:

-----BEGIN RSA PUBLIC KEY----- 
MIIBCgKCAQEAw7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajv 
WE4VhfJAjEsOcwYzay7XGN0b+X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ip 
n/aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy/xPn6oV/TYOfQ9fZdbE5HGxJUzeku 
GcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8 
JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7 
gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQIDAQAB 
-----END RSA PUBLIC KEY----- 

驗證失敗:

10857314492266413637:error:04091077:rsa routines:INT_RSA_VERIFY:wrong signature length:rsa_sign.c:186: 

我真的很感謝有經驗的人來看看我的代碼,因爲我不知道如何在沒有工作示例的情況下進行調試來進行比較。

+0

'rsa-> N = rsaModulusBn'和'rsa-> E = rsaExponentBn'會下OpnSSL 1.1.0打破,因爲你不會有機會獲得會員。對於1.1.0,您需要使用['RSA_set0_key'](https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_crt_params.html)。另請參見[錯誤:OpenSSL 1.1.0中的「使用不完整類型'RSA {aka struct rsa_st}」](http://stackoverflow.com/q/40549318)。 – jww

+0

謝謝jww。我在目標平臺的openssl中沒有這個功能。我已將評論添加到代碼庫。 – helpwithhaskell

回答

1

事實證明,RSA密鑰模數和指數也是base64 URL編碼。這裏是代碼的作品,horaay:

QByteArray token  = "eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAsCiAiY19oYXNoIjogIkxEa3RLZG9RYWszUGswY25YeENsdEEiCn0.XW6uhdrkBgcGx6zVIrCiROpWURs-4goO1sKA4m9jhJIImiGg5muPUcNegx6sSv43c5DSn37sxCRrDZZm4ZPBKKgtYASMcE20SDgvYJdJS0cyuFw7Ijp_7WnIjcrl6B5cmoM6ylCvsLMwkoQAxVublMwH10oAxjzD6NEFsu9nipkszWhsPePf_rM4eMpkmCbTzume-fzZIi5VjdWGGEmzTg32h3jiex-r5WTHbj-u5HL7u_KP3rmbdYNzlzd1xWRYTUs4E8nOTgzAUwvwXkIQhOh5TPcSMBYy6X3E7-_gr9Ue6n4ND7hTFhtjYs3cjNKIA08qm5cpVYFMFMG6PkhzLQ"; 
QByteArray rsaModulus = QByteArray::fromBase64("w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ", QByteArray::Base64UrlEncoding); 
QByteArray rsaExponent = QByteArray::fromBase64("AQAB", QByteArray::Base64UrlEncoding); 

QList<QByteArray> tokenParts = token.split('.'); 
QByteArray header = tokenParts[0]; 
QByteArray body = tokenParts[1]; 
QByteArray sig = QByteArray::fromBase64(tokenParts[2], QByteArray::Base64UrlEncoding); 

BIGNUM *rsaModulusBn = BN_bin2bn((unsigned char *)rsaModulus.data(), rsaModulus.length(), NULL); 
BIGNUM *rsaExponentBn = BN_bin2bn((unsigned char *)rsaExponent.data(), rsaExponent.length(), NULL); 

RSA *rsa = RSA_new(); 
if (rsa == NULL) printf("cannot allocate RSA\n"); 

#if defined(OPENSSL_1_1_0) 
if (1 != RSA_set0_key(rsa, rsaModulusBn, rsaExponentBn, NULL); ERR_print_errors_fp(stdout); 
#else 
rsa->n = rsaModulusBn; 
rsa->e = rsaExponentBn; 
#endif 

EVP_PKEY *key = EVP_PKEY_new(); 
if (1 != EVP_PKEY_set1_RSA(key, rsa)) ERR_print_errors_fp(stdout); 

EVP_MD_CTX *ctx = EVP_MD_CTX_create(); 
if (ctx == NULL) printf("cannot allocate MD CTX\n"); 

if (1 != EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, key)) ERR_print_errors_fp(stdout); 
if (1 != EVP_DigestVerifyUpdate(ctx, (unsigned char *)header.data(), header.length())) ERR_print_errors_fp(stdout); 
if (1 != EVP_DigestVerifyUpdate(ctx, ".", 1)) ERR_print_errors_fp(stdout); 
if (1 != EVP_DigestVerifyUpdate(ctx, (unsigned char *)body.data(), body.length())) ERR_print_errors_fp(stdout); 
if (1 != EVP_DigestVerifyFinal(ctx, (unsigned char *)sig.data(), sig.length())) 
{ 
    printf("failure\n"); 
    ERR_print_errors_fp(stdout); 
} 
else 
{ 
    printf("success\n"); 
} 

if (ctx) EVP_MD_CTX_destroy(ctx); 
if (key) EVP_PKEY_free(key); 
if (rsa) RSA_free(rsa);