I have an API to call where I have to encrypt my data using RSA/ECB/PKCS1 Padding & AES/CBC/PKCS5PADDING.

Sample Data: {"KEY":"VALUE"}

Step.1:

I have to generate a random number of 16 digit. eg: '1234567890123456'

Step.2:

Do RSA/ECB/PKCS1Padding to random number and base64Encode the result. we get "encrypted_key"

Step.3:

Concatenate random number & data:
DATA = 1234567890123456{"KEY":"VALUE"}

Step.4:

Do AES/CBC/PKCS5Padding on DATA (from Step 3) using random number(1234567890123456) as KEY & Base64Encoded random number as IV. we get "ENCRYPTED_DATA"

So, for Step 1 I am using JSEncrypt javascript library. for Step 4 I am using CrytoJS.AES.encrypt() function. I am pretty sure that my JSEncrypt function is running fine as the client is able to decrypt it but client is not able to decrypt my data. I feel that I am making a mistake while using CryptoJS.

Can someone guide me properly on how to use the library.

What I am doing is:

KEY =  '1234567890123456'
IV  = MTIzNDU2Nzg5MDEyMzQ1Ng==  (result of btoa('1234567890123456') )
DATA = "1234567890123456{"KEY":"VAL"}"

cryptedData = Crypto.AES.encrypt(DATA, KEY, {iv: IV, mode: CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7})

I am told to use PKCS5Padding in AES/CBC Encryption ( Step 4 ) but it seems that AES does not support PKCS5Padding but PKCS7Padding.

I think I am making a mistake in the way I am passing KEY & IV to CryptoJS.

Any help will be greatly appreciated.

1 Answers

1
gusto2 On

For the start lets see why are you doing the exercise. RSA is intended to encode only limited amout of data. So we use "hybrid encryption", where the data are encrypted using a symmetric cipher with a random key and the key itself is encrypted using RSA

Encryption works on binary data, to safely transmit binary data, the data are encoded to printable form (hex or base64)

Step.1: I have to generate a random number of 16 digit

What we see is 16 digits 0-9. That's not really safe. Generating 16 digits you will get a key of 10^16, which is equals of approx 2^53 (if I did the math wrong, please comment).

You need to generate 16 random bytes (digits 0-256 resulting in 2^128 key). That is your DEK (data encryption key).

You may encode the DEK to be in printable form, in hexadecimal encoding it will have 32 characters.

Step.2:

ok, you now get encrypted encoded_encryption_key

Step 3, Step 4

And here you should understand what are you doing.

  • encrypt DATA using DEK ( not encoded random number in binary form), you will get encrypted_data. You can encode the result to encoded_encrypted_data
  • concatenate the encrypted key and encrypted data. It. is up to you to choose if you encode it before or after encoding. I suggest you make concatenation of encoded_encryption_key and encoded_encrypted_data with some separator, because if RSA key length changes, the length of encoded_encryption_key changes too Make sure to discuss with the client what format is expected exactly.

Notes:

  • IV needs to be 16 bytes long for AES and for CryptoJS I believe it needs to be Hex encoded, so using btoa may not be the best idea. I believe the CryptoJS just trims the value to 16 bytes, but formally it is not correct.
    • CBC cipher needs some sort of integrity check, I suggest to add some HMAC or signature to the result (otherwise someone could change the ciphertext without you being able to detect the tamper)

but it seems that AES does not support PKCS5Padding but PKCS7Padding.

Indeed AES supports Pkcs7. Pkcs5 is functionally the same, but defined on 64 blocks. The designation is still used in Java as heritage from DES encryption.