0

I have Java based Web API which receives AES encrypt user credentials and let the user get the session token. This is working fine with AES encryption on client side with CryptoJS. But the same throws bad padding exception while trying to access this API from Python.

In Java I've used PKCS5Padding padding. I have tried this with NoPadding as well, but in that case the de-crypted text is simply empty. Also, when trying with NoPadding, CryptoJS code is not working properly. As, this API should work for any client side program (Later I'm planning to expand this to PHP, .Net and R as well), I want to have a common, working mechnism for encryption of passwords thru AES. I'm pretty new to python and I have tried various programs provided in stack overflow as well as in other blogs on this subject.

Here is the java part

public String decrypto(String cipherText, String secret) {
        byte[] cipherData = java.util.Base64.getDecoder().decode(cipherText);
        byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);
        String decryptedText = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");

            final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes(StandardCharsets.UTF_8),
                    md5);
            SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");
            IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);

            byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);
            Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
            aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
            byte[] decryptedData = aesCBC.doFinal(encrypted);
            decryptedText = new String(decryptedData, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decryptedText;
    }

And this line send the encrypted password from CrptoJS without any issues which gets de-crypted properly in Java

encKey = CryptoJS.AES.encrypt(this.logingrp.value['loginpass'], this.localPublicKey).toString();
      this.localLogin(encKey);

LocalLogin is an AJAX function to call the API

Python code is below. I'm using Pycryptodome

import requests, json
import base64

from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto import Random
from urllib.parse import urlencode
from urllib.request import Request, urlopen
from hashlib import sha256



BS = 16
pad = lambda s: bytes(s + (BS - len(s) % BS) * chr(BS - len(s) % BS), 'utf-8')
unpad = lambda s : s[0:-ord(s[-1:])]

class AESCipher:

    def __init__( self, key ):
        self.key = bytes(key, 'utf-8')

    def encrypt( self, raw ):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new(self.key, AES.MODE_CBC )
        return base64.b64encode( iv + cipher.encrypt( raw ) )

    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        iv = enc[:16]
        cipher = AES.new(self.key, AES.MODE_CBC, iv )
        return unpad(cipher.decrypt( enc[16:] )).decode('utf8')

header = {"Content-type": "application/json",
          "Authorization": "Bearer CT9797"
          } 

password = 'stone@123'
keyphrase = '9DA538D0HMQXQRGI';

cipher = AESCipher(keyphrase)
encrypted = cipher.encrypt(password).decode('utf8')


payload={'userId':'CT9797','userData':encrypted,'encKey':''}
response_decoded_json = requests.post(url=_base_URL+'eLogin', data=json.dumps(payload), headers=header)
print(response_decoded_json.status_code)

The below exception occurs while trying the above program on java side

javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
    at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
    at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:10

Appreciate your time in reading and helping me out.

Jerokdeep
  • 121
  • 13
  • So it's working in Javascript with cryptojs but *not* working in either Java or python? – President James K. Polk Aug 12 '19 at 14:31
  • 1
    Why not just use TLS/SSL to securely communicate with the server and skip all the ad-hoc crypto? – President James K. Polk Aug 12 '19 at 14:55
  • @James - It works from Java too. Requests can be from anything (Like Java, PHP, .NET, Python and JS). The destination is Java based Rest API. Its an API based trading application and can not use anything else as its mandated by exchange. – Jerokdeep Aug 12 '19 at 15:24
  • It looks like a lot of important code is in `GenerateKeyAndIV(...)` which is missing. – President James K. Polk Aug 12 '19 at 15:29
  • @JamesKPolk+ in general yes, but that Java is _clearly_ implementing [the OpenSSL (below 1.1.0) defacto 'standard'](https://crypto.stackexchange.com/questions/3298/is-there-a-standard-for-openssl-interoperable-aes-encryption) -- which cryptojs also does for typeof key == 'string'. That makes this dupe https://stackoverflow.com/questions/13907841/implement-openssl-aes-encryption-in-python and https://stackoverflow.com/questions/16761458/how-to-decrypt-openssl-aes-encrypted-files-in-python (second Q asks only for python decrypt but _answers_ include python encrypt). – dave_thompson_085 Aug 12 '19 at 16:55
  • 1
    When you encrypt on one system and decrypt on another you cannot rely on system defaults as they are likely to be different, so the decryption will fail. Explicitly specify *everything*: encryption mode, key, IV, character encoding etc. To troubleshoot, compare everything bit-by-bit to ensure that they match on both systems. – rossum Aug 13 '19 at 08:59

0 Answers0