2017-02-22 106 views
2

我正在處理移動應用程序和客戶端,我們在服務器端使用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

回答

2

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 == –