华硕zenfone5 t00j AES 256解密问题

问题描述:

我正在处理移动应用程序和客户端,我们在服务器端使用JavaScript(kony)它的Java。对于除intel芯片组设备(华硕Zenfone)之外的所有其他设备,此工作正常。 PFB加密华硕zenfone5 t00j AES 256解密问题

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

JS代码这里创建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*..) 

,当我试图加密字符串“Test”我得到“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) 

下面是我已经用于解密

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 = "ABCDEF".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(); 
     } 
    } 
} 
+0

Artjom,我已经更新了我用来重现问题的示例代码。你能帮我理解为什么发生这种情况 – Kris

CryptoJS的JAVA代码假定

  • 其被作为字符串传递密钥实际上是一个密码,并且将随机生成的盐一起再次散列,或它会使用密钥作为-是,如果它是一个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方案完成。

+0

Artjom,我已经作为字符串传递的Key&iv已经在做一个cryptoJS.enc.hex。仅用于测试目的,我已经硬编码了这个值。 – Kris

+0

当我尝试使用上述代码时,我将encText设置为null。 – Kris

+0

对不起,应该是'CryptJS.enc.Hex.parse'而不是'CryptJS.enc.Hex'。我得到密文7b9UNDI4IWNITNAQlYNP8w == –