1
$\begingroup$

Maybe this better fits, the security stackexchange...

I'm building a web API. We want to enable some relatively simple encryption, instead of going full-blown OAuth2 (which frankly, IMO, sucks). So I decided to use JWT. Anyway, it could happen for some requests that the request or response payloads are very small. Something like this for example:

{
    "order_id": 7
}

I imagine that when you encrypt something as small as this that it'd be relatively easy to brute-force. Therefore I'd like to increase the size of the payload by doing something like this:

{
    "order_id": 7,
    "padding": "kjt4J78vwzXXKEpuaodwOeTes2O5IIM5mUieNrxlRRWg1K0gXK164hstyL42QlQhKwoKCfVuA2eEJ8Pb1Sdm5tdRxXNNTl55dzrENzMBvrybGjeaHz8c7awmFmiHIsFsQ6gFKTzK2afZV483V4sjYVlYCy9C4pqU2BTK3YaonfxocG57UQwxlharNIhl8qqWbxCjEF7za9b6Sf1YfjHo2WoQ38miqSHr1aDlDWi35UZmHkYXpNVG7SoB3lfTYJ0Y"
}

This should work, unless I'm missing something. But ideally, I'd like to prevent the padding from being visible after decoding the JSON payload. I considered using a comment to that end, but JSON does not allow comments and apparently most implementations stick to the specification in that regard.

So is there a better way to do what I want, with the padding disappearing after decrypting/decoding? If anyone has an alternative for JWE, which does not involve OAUTH, I'm also all ears.

$\endgroup$
2
  • 2
    $\begingroup$ If you're using proper encryption (with a per-message IV) you don't need to pad the message. $\endgroup$ Jun 4, 2014 at 13:13
  • $\begingroup$ What is the attack you want to defend against? If it's finding the key by knowing the plaintext, you need not be worried – all the encryption algorithms JWE may use are secure against known plaintext. If it's inferring the length of plaintext from the length of ciphertext, you may want to pad them all to equal length. $\endgroup$
    – otus
    Jun 4, 2014 at 13:22

2 Answers 2

5
$\begingroup$

Encryption cannot be brute-forced: verifying a guess is as hard as decrypting. You can encrypt a 1-byte string — even a 1-bit string — and any sane encryption scheme guarantees that an adversary cannot tell which value is encrypted.

You do need to take care that the encryption algorithm is non-deterministic, in that if you encrypt the same plaintext twice, you get different ciphertexts. Otherwise an adversary could tell when you've sent the same message twice. All recommended encryption modes (i.e. anything found in typical libraries other than ECB) provide this guarantee, provided you use them correctly (e.g. using a random IV, which is necessary anyway with some modes).

An adversary can tell the length of the plaintext, or more precisely, can tell in which 16-byte interval it lies (16 bytes being the block size of AES (regardless of key size)). For example, {"order_id": 7} might encrypt to 32 bytes while {"order_id": 17} would encrypt to 48 bytes. You may want to pad all your objects to a constant size to avoid this, or at least arrange for variable-size values to be padded. The padding doesn't need to be random, you just need to manage the length. Given that you're encrypting JSON representations, adding space characters at the end should be fine.

Note that encryption only guarantees that the encrypted message remains secret. It doesn't guarantee that the message hasn't been modified in transit. For that, you need authentication. JWT offers A128CBC-HS256 (AES-128-CBC + HMAC-SHA-256) which combines encryption for confidentiality and a MAC for authenticity; if available on your implementation (it's only recommended in the standard), use the authenticated encryption mode A128GCM (AES-128-GCM).

$\endgroup$
3
  • $\begingroup$ Thanks for the thorough answer. Yeah, the idea was to do signing as well. Question just focused on crypto part. $\endgroup$
    – aross
    Jun 4, 2014 at 15:41
  • $\begingroup$ I'd rather use asymmetric encryption though, not AES. $\endgroup$
    – aross
    Jun 4, 2014 at 15:44
  • $\begingroup$ @aross Asymmetric encryption is never used for ordinary data directly — it would be technically possible but extremely slow and libraries aren't set up for it. What you do is hybrid encryption: generate a random AES key, use an AES mode to encrypt (and authenticate) the data (your JSON string), and use public-key encryption on the AES key. You can keep using the AES key as long as the other party still has it. JWT only standardizes RSAES-PKCS1-V1_5 for asymmetric encryption, which is not perfect. $\endgroup$ Jun 4, 2014 at 15:55
1
$\begingroup$

Assuming you are afraid that the attacker will find out the length of the ID – i.e. be able to narrow it down to 1-9 or 10-99, you can do the following.

I considered using a comment to that end, but JSON does not allow comments and apparently most implementations stick to the specification in that regard.

You could simply whitespace-pad the ID to a constant size: i.e. something like:

7   -> "         7" (" "*9 + "7")
123 -> "       123" (" "*29 + "123")
$\endgroup$
4
  • $\begingroup$ I'm encrypting the entire string representation of the JSON object. Not just the values. $\endgroup$
    – aross
    Jun 4, 2014 at 14:06
  • $\begingroup$ @aross, that shouldn't prevent you from placing whitespace in the JSON string. If that's problematic otherwise, you can make the ID a constant width string (encoding an int) before generating the JSON. $\endgroup$
    – otus
    Jun 4, 2014 at 14:32
  • 2
    $\begingroup$ Or use a fixed-width number format like 0x00000007 and 0x0000007B $\endgroup$
    – bmm6o
    Jun 4, 2014 at 15:10
  • $\begingroup$ @otus, right... that's an idea $\endgroup$
    – aross
    Jun 4, 2014 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.