Search code examples
javascriptscalaencryptioncryptographycryptojs

Cryptojs Scala to JS encryption doesn't work, but the other way works well


Scala to Scala works well, JS to Scala works well. But it did not work for Scala to JS. However, if I encrypted a simple Json in Scala like: {"name": "dung"}, it works well.

Scala code:

  def encryptData(data: String) = {
    val saltBytes = Array[Int](0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x78, 0x90, 0x12, 0x34, 0x90, 0x12, 0x34, 0x56) map {_.asInstanceOf[Byte]}
    val ivBytes = Array[Int](0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56) map {_.asInstanceOf[Byte]}
    val ivParamSpec = new IvParameterSpec(ivBytes)
    val secretKey = genSecretKey("somekey", saltBytes)
    val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParamSpec)
    val encryptedData = cipher.doFinal(data.getBytes("UTF-8"))
    val encodedData = (new BASE64Encoder()) encodeBuffer(encryptedData)
    Json.obj(
              "salt" -> DatatypeConverter.printHexBinary(saltBytes),
              "iv" -> DatatypeConverter.printHexBinary(ivBytes),
              "data" -> encodedData
            )
  }

  def decryptData(encryptedData: EncryptedData) = {
    val saltBytes = DatatypeConverter.parseHexBinary(encryptedData.salt)
    val ivBytes = DatatypeConverter.parseHexBinary(encryptedData.iv)
    val ivParamSpec = new IvParameterSpec(ivBytes)
    val secretKey = genSecretKey("somekey", saltBytes)
    val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
    cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParamSpec)
    val decodedValue = (new BASE64Decoder()) decodeBuffer(encryptedData.data)
    val decryptedData = new String(cipher.doFinal(decodedValue))
    decryptedData
  }

Javascript code:

function encrypt(data) {
  var salt = CryptoJS.lib.WordArray.random(128/8);
  var iv = CryptoJS.lib.WordArray.random(128/8);
  var secretKey = "somekey";
  var key128Bits100Iterations = CryptoJS.PBKDF2(secretKey, salt, { keySize: 128/32, iterations: 100 });
  var encrypted = CryptoJS.AES.encrypt(JSON.stringify(data), key128Bits100Iterations, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7  });

  return {
      salt: String(salt),
      iv: String(iv),
      data: String(encrypted)
  };
}

function decrypt(obj) { 
    var salt = CryptoJS.enc.Hex.parse(obj.salt);
    var iv = CryptoJS.enc.Hex.parse(obj.iv);
    var encrypted = obj.data;
    var key = CryptoJS.PBKDF2("somekey", salt, { keySize: 128/32, iterations: 100 });
    var decrypt = CryptoJS.AES.decrypt(encrypted, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    return decrypt.toString(CryptoJS.enc.Utf8);
}

Solution

  • The issue is the encoded string has a new line character caused by this issue. Carriage return issue decoding Base64 from Java and sending to browser After switching to org.apache.commons.codec.binary.Base64 from sun's Base64Encoder, the issue is gone.