0

I have a problem for converting c#' AES logic to javascript frontend and java spring backend.

The purpose is Using C#, Javascript and Java together.

I need to follow c#'s AES Logic which is using currently and then act like C# AES Logic.

I have done for C# and Java AES Logic with the same encrypt and decrypt.

so the remain is only Javascript AES Logic.

First, below is javascript logic which will use password encoding later.

// Javascript code in angular
import * as CryptoJS from 'crypto-js';
ngOnInit() {
    const message = '123456';
    console.log('original: ' + message);
    const cipherData = this.encrypt(message);
    console.log('cipherData: ' + cipherData);
    const decData = this.decrypt(cipherData);
    console.log('decData1: ' + decData);
    const decData2 = this.decrypt('maCLeNHh+u3A3pi0S31klRQ==');
    console.log('decData2: ' + decData2);
    const decData3 = this.decrypt('ssxlu1wcvG9lBxi3qDxUaOg==');
    console.log('decData3: ' + decData3);
    console.log('============');
    console.log('ssxlu1wcvG9lBxi3qDxUaOg==');
    console.log('MeM+72EBZ1WtB+RMmh1aL0g==');
    const db1 = this.decrypt('MeM+72EBZ1WtB+RMmh1aL0g==');
    if (db1.length > 0) {
      alert('sucess!');
    }
    console.log('db1: ' + db1);
  }

  encrypt(message: string) {
    const AES_CRYPT_KEY = '1234567890abcdefghijklmnopqrstu';
    const charRandom = this.utils.getRandomValue(1);

    let key =  AES_CRYPT_KEY + charRandom;
    // let iv = '0000000000000000';
    let iv  = new Int8Array(16);
    for (let i = 0; i < iv.length; i++) {
      iv[i] = 0;
    }

    key = CryptoJS.enc.Base64.parse(key);
    iv = CryptoJS.enc.Base64.parse(iv.toString());

    const enc = CryptoJS.AES.encrypt(message, key, {
      iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
     });
    const cipherData = charRandom + enc;
    return cipherData;
  }

  decrypt(message: string) {
    const AES_CRYPT_KEY = '1234567890abcdefghijklmnopqrstu';
    const charRandom = message.charAt(0);

    let key = AES_CRYPT_KEY + charRandom;
    // let iv = '0000000000000000';
    let iv  = new Int8Array(16);
    for (let i = 0; i < iv.length; i++) {
      iv[i] = 0;
    }

    key = CryptoJS.enc.Base64.parse(key);
    iv = CryptoJS.enc.Base64.parse(iv.toString());

    const decString = message.substring(1);
    const dec = CryptoJS.AES.decrypt(decString, key, {
      iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    }).toString(CryptoJS.enc.Utf8);
    return dec;
  }

and the output is below.

db1's encryption data is real data that c# made with simple password '123456'.

db1 has nothing after decryption.

db1 encryption data is used by C# AES Logic and javascript must encrypt and decrypt like C# and Java.

original: 123456
cipherData: ghzSXfMUvMtXIexsQ/yphJA==
decData1: 123456
decData2: 123456
decData3: 123456
============
ssxlu1wcvG9lBxi3qDxUaOg==
MeM+72EBZ1WtB+RMmh1aL0g==
db1: 

and below is Java code for backend.

// AES256Cipher.java
public class AES256Cipher {

    private static final String AES_CRYPT_KEY = "1234567890abcdefghijklmnopqrstu"; // 32bit

    public String AES_Encode(String str)
            throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        String charRandom = RandomStringUtils.randomAlphabetic(1);
        String secretKey = AES_CRYPT_KEY + charRandom;
        byte[] keyData = secretKey.getBytes();

        SecretKey secureKey = new SecretKeySpec(keyData, "AES");
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.ENCRYPT_MODE, secureKey, new IvParameterSpec(IV));

        byte[] encrypted = c.doFinal(str.getBytes("UTF-8"));
        String enStr = charRandom + new String(Base64.encodeBase64(encrypted));

        return enStr;
    }

    public String AES_Decode(String str)
            throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        String charRandom = String.valueOf(str.charAt(0));
        String secretKey = AES_CRYPT_KEY + charRandom;
        str = str.substring(1);

        byte[] keyData = secretKey.getBytes();
        SecretKey secureKey = new SecretKeySpec(keyData, "AES");
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");

        c.init(Cipher.DECRYPT_MODE, secureKey, new IvParameterSpec(IV));
        byte[] byteStr = Base64.decodeBase64(str.getBytes());

        return new String(c.doFinal(byteStr), "UTF-8");
    }
}

// AES256Cipher.java
public class CryptoTest {

    public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, GeneralSecurityException {
        AES256Cipher a256 = new AES256Cipher();

        String original = "123456";
        System.out.println(original);

        String enc = a256.AES_Encode(original);
        System.out.println(enc);

        String dec = a256.AES_Decode(enc);
        System.out.println("result1 " + dec);
        String dec2 = a256.AES_Decode("HtH2FwgxvXtPooDM5PPFRVg==");
        System.out.println("result2 " + dec2);
        String dec3 = a256.AES_Decode("p0ODGY9kHu4ttsryh2vW2Sw==");
        System.out.println("result3 " + dec3);

        System.out.println("=====================");
        String db1 = a256.AES_Decode("MeM+72EBZ1WtB+RMmh1aL0g==");
        System.out.println("db1 " + db1);

        System.out.println("=====================");
        String test1 = a256.AES_Decode("ssxlu1wcvG9lBxi3qDxUaOg==");
        System.out.println("test1 " + test1);
    }
}

and the output is below. Java logic can decrypt db's real encryption password which made by C# before

123456
fZYLxfQxDHIxdSZdSbVH2Hg==
result1 123456
result2 123456
result3 123456
=====================
db1 123456
=====================
Exception in thread "main" 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:1056)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2164)
    at com.neoslon.base.common.AES256Cipher.AES_Decode(AES256Cipher.java:72)
    at CryptoTest.main(CryptoTest.java:30)

When I tried to decrypt javascript's encryption on Java, I have the error Exception in thread "**main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption**.

I thought iv in javascript is the root case.

I tried let iv = '0000000000000000'; let iv = '0 0 0 0 0 0 0 0 0 0 0 0 0 0 00'; and so on...

How can I solve this problem in javascript not Java?

Yang Jae Lee
  • 33
  • 1
  • 7

1 Answers1

0

You have used PKCS7 padding in your JavaScript (CryptoJS.pad.Pkcs7), but expects PKCS5 padding in your Java code (AES/CBC/PKCS5Padding).

So the exception message "javax.crypto.BadPaddingException: Given final block not properly padded." is to be expected.

The two paddings supports different block sizes: https://crypto.stackexchange.com/questions/9043/what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding

KC Wong
  • 2,410
  • 1
  • 18
  • 26
  • C# 's padding setting is Pkcs7 and in JAVA'S Pkcs5 is the same https://stackoverflow.com/questions/10193567/java-security-nosuchalgorithmexceptioncannot-find-any-provider-supporting-aes-e So I can do the same AES work both C# and Java. – Yang Jae Lee Aug 01 '19 at 01:40