Skip to content

Files

Latest commit

 

History

History
101 lines (69 loc) · 10 KB

json_web_token_jws_ps256_signature.md

File metadata and controls

101 lines (69 loc) · 10 KB

Cross-platform cryptography

JSON web signature JWS with algorithm PS256 [RSA with RSASSA-PSS + MGF1 with SHA-256 padding and SHA-256 hashing]

The standard signature algorithm is RSA using a (RSA) Private-/ Public key pair. The signature is generated with the Private key of the signer. For the verification the Public Key of the signer is used - so in a typical environment the Public Key is provided to the recipient(s) of the signed data and the recipient is been able to check = verify the signature.

To understand how a JWS token is constructed I strongly recommend my article JSON web token (JWT) structure because in this article I'm focusing on the algorithm part.

In total there are 12 signature algorithms "allowed", but from all of them I'm focusing on the PS256 algorithm, that means a RSA private/public key based signature with a RSASSA PSS + MGF1 with SHA-256 padding using a SHA-256 hash. The other algorithms will use different hashes ("SHA-256", "SHA-384" and "SHA-512" are in use), other padding ("RSASSA-PKCS1-v1_5") or keys based on an elliptic curve ("ECDSA using P-256 curve"). The last allowed signature type is constructed with a "HMAC" based on a symmetric key.

As the RSASSA-PSS + MGF1 is named as "more secure as the RSASSA PKCS1 v1.5 padding" I recommend to use the PS256 signature algorithm.

For a better understanding of the signature process itself I recommend my article RSA signature of a string.

A note about the programs in the different frameworks

I tried to provide solutions that provide an exchangeable output but the verification part will look like different and give different outputs. One important parameter in my payloads (the data inside the JSON token) is a timestamp with an expire date. This prohibits from use the token after the expiration date but that needs to get checked individually (depending on the library/implementation in use). Some libraries check the expiration parameter when verifying the signature, others need to start this part individually.

Key generation:

Usually a JWT will use a JWK or JSON web key named key pair but in the end the are just other representations of a RSA private and public key. All of my sample programs will accept my well known RSA private and public key pair in PEM format. If you are interested in the JWK-format visit my article JSON Web JWK keys.

All examples use pre-generated keys that are described on the page RSA sample keys. If you want to see how my keys got generated visit the page RSA key generation.

Secure key management

One note about the key management in my programs: usually the keys are (securely) stored in files or a key store and may have additional password protection. Both scenarios are unhandy in demonstration programs running in an online compiler. That's why I'm using static, hard-coded keys in my programs - please do not do this in production environment! Never ever store a Private Key in the source! The minimum is to load the keys from a secured device.

steps in the program

The program follows the usual sequence:

  1. generate a RSA key pair - here we are using a static, hard-coded key pair in form of a PEM encoded string
  2. build a payload object
  3. start the signature process
  4. load the Private Key
  5. set the signature parameters in the JWT header
  6. sign the payload and show the result ("jwtToken") in Base64Url encoding
  7. start the verification process
  8. load the Public Key
  9. read the jwtToken header to get the signature algorithm needed for verification
  10. set the verification parameters (same as used for signing, see 9)
  11. verify the signature against the payload and show the result.
  12. check the (possible) expiration of the signature

I do not provide a "verification only" program as all program parts are available in the main program (except for Webcrypto programs, they have are "sign only" and "verification only").

⚠️ Security warning ⚠️

This is a serious warning regarding the security of the programs shown in these article series. Always keep in mind my disclaimer regarding my programs: All programs are for educational purposes and are not intended to use in production or any other programs where a secure solution is needed. The programs do not have proper exceptional/error handling and in some cases they use insecure key lengths or other methods that are insecure. Never ever use the programs in real life unless checked by a qualified professional cryptographer.

The following links provide the solutions in code and an online compile that runs the code.

Language available Online-compiler
Java *) repl.it CpcJavaJwsPs256Signature
PHP *) repl.it CpcPhpJwsPs256Signature
C# dotnetfiddle.net CpcCsharpJwsPs256Signature
Javascript CryptoJs kindly use the pure nodeJs implementation
NodeJS Crypto *) repl.it CpcNodeJsJwsPs256Signature
NodeJS forge kindly use the pure nodeJs implementation
Webcrypto sign only your browser WebcryptoJwsPs256Sign.html
Webcrypto verify only your browser WebcryptoJwsPs256Verify.html
Python *) repl.it CpcPythonJwsPs256Signature
Go *) repl.it CpcGoJwsPs256Signature

*) you need an external library

This is an output (Java version):

JWT JWS PS256 RSA with RSASSA-PSS + MGF1 with SHA-256 padding and SHA-256 hashing

* * * sign the payload object with the RSA private key * * *
jwtClaimsSet: {"sub":"JWT PS256 signature","iss":"https:\/\/java-crypto.github.io\/cross_platform_crypto\/","exp":1613998119,"iat":1613997999}
privateKey in jwk format:
{"p":"_8atV5DmNxFrxF1PODDjdJPNb9pzNrDF03TiFBZWS4Q-2JazyLGjZzhg5Vv9RJ7VcIjPAbMy2Cy5BUffEFE-8ryKVWfdpPxpPYOwHCJSw4Bqqdj0Pmp_xw928ebrnUoCzdkUqYYpRWx0T7YVRoA9RiBfQiVHhuJBSDPYJPoP34k","kty":"RSA","q":"8H9wLE5L8raUn4NYYRuUVMa-1k4Q1N3XBixm5cccc_Ja4LVvrnWqmFOmfFgpVd8BcTGaPSsqfA4j_oEQp7tmjZqggVFqiM2mJ2YEv18cY_5kiDUVYR7VWSkpqVOkgiX3lK3UkIngnVMGGFnoIBlfBFF9uo02rZpC5o5zebaDIms","d":"hXGYfOMFzXX_vds8HYQZpISDlSF3NmbTCdyZkIsHjndcGoSOTyeEOxV93MggxIRUSjAeKNjPVzikyr2ixdHbp4fAKnjsAjvcfnOOjBp09WW4QCi3_GCfUh0w39uhRGZKPjiqIj8NzBitN06LaoYD6MPg_CtSXiezGIlFn_Hs-MuEzNFu8PFDj9DhOFhfCgQaIgEEr-IHdnl5HuUVrwTnIBrEzZA_08Q0Gv86qQZctZWoD9hPGzeAC-RSMyGVJw6Ls8zBFf0eysB4spsu4LUom_WnZMdS1ls4eqsAX-7AdqPKBRuUVpr8FNyRM3s8pJUiGns6KFsPThtJGuH6c6KVwQ","e":"AQAB","qi":"BtiIiTnpBkd6hkqJnHLh6JxBLSxUopFvbhlR37Thw1JN94i65dmtgnjwluvR_OMgzcR8e8uCH2sBn5od78vzgiDXsqITF76rJgeO639ILTA4MO3Mz-O2umrJhrkmgSk8hpRKA-5Mf9aE7dwOzHrc8hbj8J102zyYJIE6pOehrGE","dp":"BPXecL9Pp6u_0kwY-DcCgkVHi67J4zqka4htxgP04nwLF_o8PF0tlRfj0S7qh4UpEIimsxq9lrGvWOne6psYxG5hpGxiQQvgIqBGLxV_U2lPKEIb4oYAOmUTYnefBCrmSQW3v93pOP50dwNKAFcGWTDRiB_e9j-3EmZm_7iVzDk","dq":"rBWkAC_uLDf01Ma5AJMpahfkCZhGdupdp68x2YzFkTmDSXLJ_P15GhIQ-Lxkp2swrvwdL1OpzKaZnsxfTIXNddmEq8PEBSuRjnNzRjQaLnqjGMtTBvF3G5tWkjClb_MW2q4fgWUG8cusetQqQn2k_YQKAOh2jXXqFOstOZQc9Q0","n":"8EmWJUZ_Osz4vXtUU2S-0M4BP9-s423gjMjoX-qP1iCnlcRcFWxthQGN2CWSMZwR_vY9V0un_nsIxhZSWOH9iKzqUtZD4jt35jqOTeJ3PCSr48JirVDNLet7hRT37Ovfu5iieMN7ZNpkjeIG_CfT_QQl7R-kO_EnTmL3QjLKQNV_HhEbHS2_44x7PPoHqSqkOvl8GW0qtL39gTLWgAe801_w5PmcQ38CKG0oT2gdJmJqIxNmAEHkatYGHcMDtXRBpOhOSdraFj6SmPyHEmLBishaq7Jm8NPPNK9QcEQ3q-ERa5M6eM72PpF93g2p5cjKgyzzfoIV09Zb_LJ2aW2gQw"}
signed jwsToken:
eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvamF2YS1jcnlwdG8uZ2l0aHViLmlvXC9jcm9zc19wbGF0Zm9ybV9jcnlwdG9cLyIsInN1YiI6IkpXVCBQUzI1NiBzaWduYXR1cmUiLCJleHAiOjE2MTM5OTgxMTksImlhdCI6MTYxMzk5Nzk5OX0.YN4DdCC6WBnst6hPsVdX9cS2I-_Cg65xf-M6KxFjIFAY0SvTCSMLquLW-L2ouayXNSFuV_aSgtQPdn5ZX5n74ytxj8uq_K2KP-GZpbOIjVnvdnwNVDeIabmfufseK3C3t4WmsrU5Sj3-0xj0BN8bKhfEupsTIWuW2HqjsC81cDH89ehV3vamI_Xd2VRpLhSE0vqgF_cJOaMTaUseAYm20JO89pQ1U05BfTOhTsDh9_bRlBx0Du4nR-eRfNK3hJGfxrWDRMtLN4Q9FoTaxtzC6v2Sz1fu0Au3lv5CEctcziF_Gs2Vyv0kY49OcahghChOnyvnrPbEBY8KppnBZnI0Ig

* * * verify the jwsToken with the RSA public key * * *
publicKey in jwk format:
{"kty":"RSA","e":"AQAB","n":"8EmWJUZ_Osz4vXtUU2S-0M4BP9-s423gjMjoX-qP1iCnlcRcFWxthQGN2CWSMZwR_vY9V0un_nsIxhZSWOH9iKzqUtZD4jt35jqOTeJ3PCSr48JirVDNLet7hRT37Ovfu5iieMN7ZNpkjeIG_CfT_QQl7R-kO_EnTmL3QjLKQNV_HhEbHS2_44x7PPoHqSqkOvl8GW0qtL39gTLWgAe801_w5PmcQ38CKG0oT2gdJmJqIxNmAEHkatYGHcMDtXRBpOhOSdraFj6SmPyHEmLBishaq7Jm8NPPNK9QcEQ3q-ERa5M6eM72PpF93g2p5cjKgyzzfoIV09Zb_LJ2aW2gQw"}
payloadObject: {sub=JWT PS256 signature, iss=https://java-crypto.github.io/cross_platform_crypto/, exp=1613998119, iat=1613997999}

check signature with matching public key
the token's signature is verified: true

check signature with not matching public key
the token's signature is verified: false

check expiration that is valid
the token is valid and not expired: true

check expiration that is invalid
the token is valid and not expired: false

Last update: Apr. 28th 2021

Back to the main page: readme.md or back to the JSON web token overview page.