# JSON Web Encryption

JSON Web Encryption (JWE) provides encrypted content using JSON-based data structures. JWE is specified in RFC 7516, JSON Web Encryption. The code below shows you how to arrive at the known answers from the test vectors provided in RFC 7516, Appendix A, JWE Examples.

A message is encrypted under JWE using a Content Encryption Key (CEK). The CEK is a symmetric key and used for bulk encryption. The CEK is also encrypted under the recipient's public RSA key and sent with the message so the receiver can decrypt the message.

If you are using JSON Web Objects, then see Critical vulnerabilities in JSON Web Token libraries. The advisory shows several ways an attacker can manipulate JSON Web Signatures.

A related article is JSON Web Signature, which shows how to calculate HMACs and sign messages using RSA and ECDSA.

## AES/GCM

A message is encrypted using a Content Encryption Key (CEK). The code that follows performs the authenticated encryption and arrives at the expected result from Appendix A.1.6, Content Encryption.

The cipher text is a concatenation of the confidential data and the authentication tag. If you want them as separate items, then you have to spit the byte array. Also see AuthenticatedEncryptionFilter on the wiki.

$cat test.cxx #include "cryptlib.h" #include "aes.h" #include "gcm.h" #include "sha.h" #include "files.h" #include "base64.h" #include <iostream> #include <string> int main (int argc, char* argv[]) { using namespace CryptoPP; // A.1.2. Content Encryption Key (CEK) const byte cek[] = { 177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154, 212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122, 234, 64, 252 }; // A.1.4. Initialization Vector const byte iv[] = { 227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219 }; // A.1.5. Additional Authenticated Data const byte aad[] = { 101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69, 116, 84, 48, 70, 70, 85, 67, 73, 115, 73, 109, 86, 117, 89, 121, 73, 54, 73, 107, 69, 121, 78, 84, 90, 72, 81, 48, 48, 105, 102, 81 }; // A.1. Plain text message const byte pdata[] = "The true sign of intelligence is not knowledge but imagination."; ByteQueue temp; GCM<AES>::Encryption encryptor; encryptor.SetKeyWithIV(cek, sizeof(cek), iv, sizeof(iv)); AuthenticatedEncryptionFilter filter(encryptor, new Redirector(temp)); filter.ChannelPut(AAD_CHANNEL, aad, sizeof(aad)); filter.ChannelMessageEnd(AAD_CHANNEL); filter.ChannelPut(DEFAULT_CHANNEL, pdata, sizeof(pdata)-1); // strip the C-string NULL filter.ChannelMessageEnd(DEFAULT_CHANNEL); // ByteQueue temp is 'confidential data || authentication tag' std::string cdata, atag; size_t len = temp.MaxRetrievable(); // This separates confidential data and authentication tag temp.TransferTo(StringSink(cdata).Ref(), len-16); temp.TransferTo(StringSink(atag).Ref(), 16); std::cout << "Encrypted data: "; StringSource (cdata, true, new Base64URLEncoder(new FileSink(std::cout))); std::cout << std::endl; std::cout << "Auth tag: "; StringSource (atag, true, new Base64URLEncoder(new FileSink(std::cout))); std::cout << std::endl; return 0; } Running the program results in the following. $ g++ -Wall test.cxx ./libcryptopp.a -o test.exe
$./test.exe Encrypted data: 5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A Auth tag: XFBoMYUZodetZdvTiFvSkQ If you want to use a std::string instead of a ByteQueue then use the following code. std::string temp; GCM<AES>::Encryption encryptor; encryptor.SetKeyWithIV(cek, sizeof(cek), iv, sizeof(iv)); AuthenticatedEncryptionFilter filter(encryptor, new StringSink(temp)); filter.ChannelPut(AAD_CHANNEL, aad, sizeof(aad)); filter.ChannelMessageEnd(AAD_CHANNEL); filter.ChannelPut(DEFAULT_CHANNEL, pdata, sizeof(pdata)-1); // strip the C-string NULL filter.ChannelMessageEnd(DEFAULT_CHANNEL); // std::string temp is 'confidential data || tag' std::string cdata, atag; cdata = temp.substr(0, temp.length() - 16); atag = temp.substr(temp.length() - 16); std::cout << "Encrypted data: "; StringSource (cdata, true, new Base64URLEncoder(new FileSink(std::cout))); std::cout << std::endl; std::cout << "Auth tag: "; StringSource (atag, true, new Base64URLEncoder(new FileSink(std::cout))); std::cout << std::endl; ## RSAES-OAEP The Content Encryption Key (CEK) is encrypted with the receiver's public key. The code that follows performs the encryption of the CEK. #include "cryptlib.h" #include "oaep.h" #include "rsa.h" #include "sha.h" #include "osrng.h" #include "files.h" #include "pubkey.h" #include "base64.h" #include <iostream> #include <string> int main (int argc, char* argv[]) { using namespace CryptoPP; // A.1.2. Content Encryption Key (CEK) const byte cek[] = { 177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154, 212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122, 234, 64, 252 }; // A.1.3. Key Encryption std::string nz = "oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW" "cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S" "psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a" "sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS" "tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj" "YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw"; std::string ez = "AQAB"; StringSource ssN(nz, true, new Base64URLDecoder); StringSource ssE(ez, true, new Base64URLDecoder); Integer n(ssN, (size_t)ssN.MaxRetrievable()); Integer e(ssE, (size_t)ssE.MaxRetrievable()); RSAES<OAEP<SHA256> >::Encryptor encryptor; encryptor.AccessKey().Initialize (n, e); AutoSeededRandomPool prng; std::string ekey; StringSource (cek, sizeof(cek), true, new PK_EncryptorFilter(prng, encryptor, new StringSink(ekey))); std::cout << "JWE Encrypted Key: "; StringSource (ekey, true, new Base64URLEncoder(new FileSink(std::cout))); std::cout << std::endl; return 0; } OAEP uses randomized padding, so different runs of the protocol results in different cipher text. $ ./test.exe | fold -w 80
JWE Encrypted Key: TsdyyuMutCN7NsgY1g7Bbru6hG6ghj_1c4OT4w88bdR6Bejcf0wDSaYBCFjEf
o7X_m9t35NFyXQq-6AxJIi4-vyEdNz6smj44L_Ofc01_jdy7kIA1jqqBuT4Rdgw__sjE1711D25c1_45
dmf2BbXojKH7o9pEGeGNKxM2CJAe1cWpf1LhQDg3u13ectHFPbCK_JdyGyjMPZQud79QIJicBEz-3SBd
aU8pg9T8N8qXaKDS0XG4ID-3cwtcXeFTSVxkBLM-7OZA200sC6xN130TGCmNkB_uHoogZWI-7KbePHmG
Yfd4jvWIQuHDLy2qJr6Nt2pRAcX8ZB4MlFTNk3xkg

\$ ./test.exe | fold -w 80
JWE Encrypted Key: BqOMwOz9ZcSb54Z-vZfxc_o-9W-B0_8sTUYhkxR1muiVF3DUQ9LrylOOws2PI
-NGoEOibB1pXd8G7qfqW9xI_Hyp51Y80zvb2XNfTZ6UnJC8zZ0_By1u_AA3-UI_iDOjFkzX_gHYmTrlK
7moqBmzYgfMoogjrJXj5ALceRg3VrX09OvsuasG-g