华硕Zenfone5 T00J AES 256解密问题



我在移动应用程序和客户端工作,我们在服务器端使用JavaScript(Kony)。除了英特尔芯片组设备(华硕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;
}

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

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();
        }
    }
}

cryptojs假设

  • 作为字符串实际上传递的密钥实际上是一个密码,并将其与随机生成的盐一起再次将其放置,或者如果是WordArray,则将使用键AS,并且
  • 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不是秘密,因此您可以将其与密文一起发送。通常,它只是将其简单地添加到密文中,并在解密前切割。

  • 最好对您的密文进行身份验证,以便无法进行攻击之类的攻击。这可以使用经过身份验证的模式(例如GCM或EAX),也可以使用加密 - 然后使用MAC方案。

相关内容

  • 没有找到相关文章

最新更新