华硕zenfone5 t00j AES 256解密问题

时间:2017-02-22 09:26:52

标签: javascript android encryption cryptojs badpaddingexception

我正在研究移动应用程序和客户端,我们在服务器端使用JavaScript(kony)它的java。这适用于除intel芯片组设备(ASUS Zenfone)之外的所有其他设备。 PFB JS加密代码

function encryptDataModeCBC() 
{
    var encData = "Test";
    try 
    {
        var encText = CryptoJS.AES.encrypt(encData, "3f4c57006f7d2d9528de3c46b626df06cdc405cb0243b10ca7612d967c688744", {
            iv: "31fd1ae51454cd55db81f1fa60a343ed",
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        }).ciphertext.toString(CryptoJS.enc.Base64); 
        alert ("encText => "+encText);    
        kony.print("$$$$ encText => "+encText);    
    } 
    catch (e) 
    {
        alert(kony.i18n.getLocalizedString("technicalError"));      
    }
}

在这里创造IV&密钥使用sha256& sha512哈希算法。

PFB我们在服务器端用于解密加密字符串的代码片段

密钥生成代码

private SecretKeySpec getKey(String mode, String msgDigest, String encryptionKey, boolean is256) throws Exception {
    byte[] key = encryptionKey.getBytes("UTF-8");
    MessageDigest sha = MessageDigest.getInstance(msgDigest); // This is SHA-256
    key = sha.digest(key);
    if (is256) {  // This is true in our case.
      key = Arrays.copyOf(key, 32);
      this.logger.debug("Secret Key " + DigestUtils.sha256Hex(encryptionKey).substring(0, 32));
    } else {
      key = Arrays.copyOf(key, 16);
      this.logger.debug("Secret Key " + DigestUtils.sha256Hex(encryptionKey).substring(0, 16));
    }
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
    String modeStr = mode.equals("ECB") ? "AES/ECB/PKCS5Padding" : "AES/CBC/PKCS5Padding";
    cipher = Cipher.getInstance(modeStr);
    return secretKeySpec;
}

服务器端的IV生成

private IvParameterSpec getIV(String uid, String pin) throws Exception {
  String ivValue = new StringBuilder(uid).reverse().toString() + new StringBuilder(pin).reverse();
  byte[] key = ivValue.getBytes("UTF-8");
  MessageDigest sha = MessageDigest.getInstance("SHA-256");
  key = sha.digest(key);
  key = Arrays.copyOf(key, 16);
  IvParameterSpec iv = new IvParameterSpec(key);
  return iv;
}

正如我上面提到的,这在intel芯片组设备中失败了。这是我在解密字符串时得到的例外

javax.crypto.BadPaddingException: Given final block not properly padded
  at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
  at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
  at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
  at javax.crypto.Cipher.doFinal(DashoA13*..)

当我尝试加密字符串"测试"我得到" Tn2SzI8dmgCmEvQrzdqLxw =="我在下面的java代码中使用的加密字符串,并试图解密我收到以下错误的地方

enc text => 7b9UNDI4IWNITNAQlYNP8w==
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.ust.Encryptor.decrypt(Encryptor.java:92)
at com.ust.Encryptor.main(Encryptor.java:113)

这是我用于解密的JAVA代码

package com.ust;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;    
import org.apache.commons.codec.digest.DigestUtils;

public class Encryptor {
    private static final String AES_PASS = "0ca763dc6b05b5230e44beb6b90e346440204b6d334b09623eafd3fcfbad6a302faca28b0994872e3fd782e7353026684b7ac9385662144e0ed1e2a8e3e14fab79059929681e3794eb97271328ecccda6dbfb3a7991ea1324615cf5908fabdf6"; // Hashed into an AES key later
    private SecretKeySpec keyObj;
    private Cipher cipher;
    private IvParameterSpec ivObj;
    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();


    public Encryptor() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException {
        // A constant IV, since CBC requires an IV but we don't really need one

        String ivValue = new StringBuilder("astring").reverse().toString() + new StringBuilder("0ca763dc6b05b5230e44beb6b90e346440204b6d334b09623eafd3fcfbad6a302faca28b0994872e3fd782e7353026684b7ac9385662144e0ed1e2a8e3e14fab").reverse();
        System.out.println("ivValue => "+ivValue);
        try {
            byte[] ivkey = ivValue.getBytes("UTF-8");
            MessageDigest shaIv = MessageDigest.getInstance("SHA-256");
            ivkey = shaIv.digest(ivkey);
            ivkey = Arrays.copyOf(ivkey, 16);
            System.out.println("IV => "+bytesToHex(ivkey));
            this.ivObj = new IvParameterSpec(ivkey);
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // Create an SHA-256 256-bit hash of the key
        byte[] key = AES_PASS.getBytes();
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        key = sha.digest(key);
        key = Arrays.copyOf(key, 32); // Use only first 256 bit
        System.out.println("SEC KEY => "+bytesToHex(key));
        this.keyObj = new SecretKeySpec(key, "AES");

        // Create a Cipher by specifying the following parameters
        //  a. Algorithm name - here it is AES 
        //  b. Mode - here it is CBC mode 
        //  c. Padding - e.g. PKCS7 or PKCS5
        this.cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    }

    public String encrypt(String strDataToEncrypt) throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException {
        String strCipherText = new String();

        this.cipher.init(Cipher.ENCRYPT_MODE, this.keyObj, this.ivObj);

        // Encrypt the Data 
        //  a. Declare / Initialize the Data. Here the data is of type String 
        //  b. Convert the Input Text to Bytes 
        //  c. Encrypt the bytes using doFinal method
        byte[] byteDataToEncrypt = strDataToEncrypt.getBytes();

        byte[] byteCipherText = this.cipher.doFinal(byteDataToEncrypt);

        // b64 is done differently on Android
        strCipherText = Base64.encodeBase64String(byteCipherText);

        return strCipherText;
    }

    public String decrypt(String strCipherText) throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException {
        String strDecryptedText = new String();

        // Initialize the Cipher for Encryption
        this.cipher.init(Cipher.DECRYPT_MODE, this.keyObj, this.ivObj);

        // Decode the Base64 text
        byte[] cipherBytes = Base64.decodeBase64(strCipherText);

        // Decrypt the Data
        //  a. Initialize a new instance of Cipher for Decryption (normally don't reuse the same object)
        //     Be sure to obtain the same IV bytes for CBC mode.
        //  b. Decrypt the cipher bytes using doFinal method
        byte[] byteDecryptedText = this.cipher.doFinal(cipherBytes);
        strDecryptedText = new String(byteDecryptedText);

        return strDecryptedText;
    }
    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        int v;
        for ( int j = 0; j < bytes.length; j++ ) {
            v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static void main (String args[]) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException{
        Encryptor aesCipher = new Encryptor();
        try {
            String encText = aesCipher.encrypt("Test");
            System.out.println("enc text => "+encText);
            String plaintext = aesCipher.decrypt("Tn2SzI8dmgCmEvQrzdqLxw==");//("eat6f1uCCXVqJgTNUA8BCqXSA4kG4GhKajXdkyV0TewK+jgDkbQ/lPVaevv4rW3XdSmtVyOKLVJjPw9Akeblrh+ejIv9u48n7PkRKniwfxq/URuPU7lhS/sO5JMiJ7+ufgKFvJapxhSfftCtigtDc8F6Y2lJIPEUeQeQKOVc1noeLqPFggz55hWjWvDtpYh/sG76MwLlWDM7cj+uu6ru3ImmDA7qoM4tJOWBBkfng8u20R1ZcF3gM45TgDLUdL912AE1WO+grGBGjqzTXlK2/jgu3OOsLVI0jndB49K5q3/oKJc7JEoIZb0eZJcuZ80A");
            System.out.println("plain text => "+plaintext);
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

1 个答案:

答案 0 :(得分:2)

CryptoJS假设

  • 作为字符串传递的密钥实际上是一个密码,并且会随着随机生成的盐再次哈希,或者如果它是WordArray则会按原样使用密钥
  • IV应该是WordArray

WordArray是CryptoJS的内部二进制数据表示。

代码应为:

try {
    var key = CryptoJS.enc.Hex.parse("3f4c57006f7d2d9528de3c46b626df06cdc405cb0243b10ca7612d967c688744");
    var iv = CryptoJS.enc.Hex.parse("31fd1ae51454cd55db81f1fa60a343ed44");
    var encText = CryptoJS.AES.encrypt(encData, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).ciphertext.toString(CryptoJS.enc.Base64); 
    alert ("encText => "+encText);    
    kony.print("$$$$ encText => "+encText);    
} 
catch (e) 
{
    alert(kony.i18n.getLocalizedString("technicalError"));
}

要考虑的事情:

  • 如果您将对称密钥从服务器发送到客户端,那么任何可能正在监听的人都将获得密钥并可以解密您发送的密文。此解决方案不提供安全性,而是提供混淆。你应该使用TLS来使连接真正安全。

  • IV必须是不可预测的(读:随机)。不要使用静态IV,因为这会使密码具有确定性,因此在语义上不安全。观察密文的攻击者可以确定何时发送相同的消息前缀。 IV不是秘密,因此您可以将其与密文一起发送。通常,它只是在密文之前加上密码并在解密前切掉。

  • 最好对您的密文进行身份验证,以便像padding oracle attack这样的攻击是不可能的。这可以使用经过验证的模式(如GCM或EAX)或encrypt-then-MAC方案来完成。

相关问题