Take the 2-minute tour ×
Cryptography Stack Exchange is a question and answer site for software developers, mathematicians and others interested in cryptography. It's 100% free, no registration required.

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.

share|improve this question
2  
If you're using proper encryption (with a per-message IV) you don't need to pad the message. –  CodesInChaos Jun 4 at 13:13
    
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. –  otus Jun 4 at 13:22

2 Answers 2

up vote 4 down vote accepted

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).

share|improve this answer
    
Thanks for the thorough answer. Yeah, the idea was to do signing as well. Question just focused on crypto part. –  aross Jun 4 at 15:41
    
I'd rather use asymmetric encryption though, not AES. –  aross Jun 4 at 15:44
    
@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. –  Gilles Jun 4 at 15:55

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")
share|improve this answer
    
I'm encrypting the entire string representation of the JSON object. Not just the values. –  aross Jun 4 at 14:06
    
@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. –  otus Jun 4 at 14:32
2  
Or use a fixed-width number format like 0x00000007 and 0x0000007B –  bmm6o Jun 4 at 15:10
    
@otus, right... that's an idea –  aross Jun 4 at 15:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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