2014-03-03 50 views
2

我不知道你能否幫我理解我的解密方法爲什麼會給出奇怪的字符。具體而言,在這種情況下,我得到類似於java中AES解密的奇怪字符

�����c~�+�J*zC�iV�-��&�_l��*. 

這裏的字符是我的代碼:

import java.io.ByteArrayOutputStream; 
import java.io.UnsupportedEncodingException; 
import java.math.BigInteger; 
import java.nio.charset.Charset; 
import javax.crypto.*; 
import java.security.*; 
import java.util.Arrays; 
import javax.crypto.spec.*; 
import org.apache.commons.codec.DecoderException; 
import org.apache.commons.codec.binary.Base64; 

import org.apache.commons.codec.binary.Hex; 

public class AESCrypto2 { 

private Cipher AEScipher; 
private KeyGenerator AESgen; 
private SecretKeySpec AESkey; 
private SecretKeySpec decodeKey; 
private String hexDecodeKey; 
private String decodeKey64; 
private byte[] cipherData; 
private String msg; 
private String encMsg; 

public static void main(String[] args) { 
    try { 
     AESCrypto2 a = new AESCrypto2(); 
     a.encrypt("Hello!"); 
     try { 
      a.decrypt(a.getEncryptedMsg(), a.getDecodeKey()); 
     } catch (DecoderException ex) { 
      ex.printStackTrace(); 
     } 
    } catch (NoSuchAlgorithmException ex) { 
     ex.printStackTrace(); 
    } catch (NoSuchPaddingException ex) { 
     ex.printStackTrace(); 
    } catch (InvalidKeyException ex) { 
     ex.printStackTrace(); 
    } catch (UnsupportedEncodingException ex) { 
     ex.printStackTrace(); 
    } catch (IllegalBlockSizeException ex) { 
     ex.printStackTrace(); 
    } catch (BadPaddingException ex) { 
     ex.printStackTrace(); 
    } 

} 

public AESCrypto2() throws NoSuchAlgorithmException, NoSuchPaddingException, 
     UnsupportedEncodingException { 
    AESgen = KeyGenerator.getInstance("AES"); 
    AESgen.init(128); 
    AESkey = (SecretKeySpec) AESgen.generateKey(); 
    decodeKey = new SecretKeySpec(AESkey.getEncoded(), "AES"); 
    hexDecodeKey = keyToString(decodeKey); 
    AEScipher = Cipher.getInstance("AES/ECB/NoPadding"); 
} 

public AESCrypto2(String msg) throws NoSuchAlgorithmException, 
     NoSuchPaddingException, InvalidKeyException, 
     UnsupportedEncodingException, IllegalBlockSizeException, 
     BadPaddingException { 
    this(); 
    encrypt(msg); 
} 

public String encrypt(String msg) throws NoSuchAlgorithmException, 
     InvalidKeyException, UnsupportedEncodingException, 
     IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException { 
    AEScipher.init(Cipher.ENCRYPT_MODE, AESkey); 
    cipherData = AEScipher.doFinal(handleString(msg.getBytes("UTF-8"))); 

    this.msg = msg; 
    encMsg = stringToHex(new String(cipherData)); 
    return encMsg; 
} 

public String decrypt(String msg, String hexDecodeKey) throws 
     InvalidKeyException, IllegalBlockSizeException, 
     BadPaddingException, UnsupportedEncodingException, 
     NoSuchAlgorithmException, NoSuchPaddingException, DecoderException { 
    AEScipher.init(Cipher.DECRYPT_MODE, stringToKey(hexDecodeKey)); 
    byte[] decryptedData = AEScipher.doFinal(handleString(hexToString(msg).getBytes("UTF-8"))); 
    encMsg = msg; 
    msg = new String(decryptedData); 
    System.out.println(msg); 
    return msg; 
} 

public String getEncryptedMsg() { 
    return encMsg; 
} 

public String getDecryptedMsg() { 
    return msg; 
} 

public String getDecodeKey() { 
    return hexDecodeKey; 
} 

public SecretKeySpec getKey() { 
    return decodeKey; 
} 

//AEScipher requires that 16 divides the length of b 
public static byte[] handleString(byte[] b) throws UnsupportedEncodingException { 
    byte[] temp = b; 
    if (temp.length % 16 != 0) { 
     byte[] byteMsg = Arrays.copyOf(temp, temp.length + 16 - (temp.length % 16)); 
     return byteMsg; 
    } 
    return temp; 
} 

public static String keyToString(SecretKeySpec key) { 
    String decoded = Hex.encodeHexString(key.getEncoded()); 
    return decoded; 
} 

public static SecretKeySpec stringToKey(String key) throws DecoderException { 
    byte[] decodedKey = Hex.decodeHex(key.toCharArray()); 
    return new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); 
} 

public static String stringToHex(String msg) throws UnsupportedEncodingException { 
    return Hex.encodeHexString(msg.getBytes("UTF-8")); 
} 

public static String hexToString(String msg) throws DecoderException { 
    return new String(Hex.decodeHex(msg.toCharArray())); 
} 

}

+1

你是從哪裏複製粘貼的?這在很多層面上都是錯誤的... – ntoskrnl

+0

我沒有複製一些作品,但不是全部。 – Kortlek

+1

-1沒有適當地研究您試圖執行安全相關操作的庫的基本用法。雖然這是一個問答論壇,並且您的問題是有效的,但在您提出問題之前,還需要進行一定程度的調查和故障排除。由於您的問題沒有得到充分研究,並且有一個簡單的錯誤,因此解決方案不太可能對那些偶然發現您的問題並響應其搜索查詢的用戶有用。這個問題幾乎屬於我認爲的「簡單印刷錯誤」標準。 –

回答

4

解密

還只需刪除密文的UTF8轉換即可解除解密問題,只需使用純字節數組即可。在使用二進制字符串時,UTF-8編碼+解碼並不能保證得到相同的結果,事實上它更可能不會回來,並且解密往往會因爲位錯誤而皺眉。

public static String byteArrayToHex(byte[] bytes) throws UnsupportedEncodingException { 
    return Hex.encodeHexString(bytes); 
} 

public static byte[] hexToByteArray(String hex) throws DecoderException { 
    return Hex.decodeHex(hex.toCharArray()); 
} 

public String encrypt(String msg) throws NoSuchAlgorithmException, 
     InvalidKeyException, UnsupportedEncodingException, 
     IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException { 
    AEScipher.init(Cipher.ENCRYPT_MODE, AESkey); 
    cipherData = AEScipher.doFinal(handleString(msg.getBytes("UTF-8"))); 

    this.msg = msg; 
    encMsg = byteArrayToHex(cipherData); 
    return encMsg; 
} 

public String decrypt(String msg, String hexDecodeKey) throws 
     InvalidKeyException, IllegalBlockSizeException, 
     BadPaddingException, UnsupportedEncodingException, 
     NoSuchAlgorithmException, NoSuchPaddingException, DecoderException { 
    SecretKeySpec key = stringToKey(hexDecodeKey); 
    AEScipher.init(Cipher.DECRYPT_MODE, key); 
    byte[] decryptedData = AEScipher.doFinal(handleString(hexToByteArray(msg))); 
    encMsg = msg; 
    msg = new String(decryptedData); 
    System.out.println(msg); 
    return msg; 
} 

它也可能是一個好主意,使用一些標準的填充,如AES/ECB/PKCS5Padding

+0

+1提醒他們應該使用標準填充。但是,請記住,PKCS#7填充是現在人們應該使用的任何密碼,主要是因爲使用可能具有較大塊大小的任意密碼時,它不太容易出錯。 –

+0

@ MichaelJ.Gray:請記住,在Java算法規範中,PKCS5Padding和PKCS7Padding是等效的,即它們都執行PKCS7填充。 –

+0

@GregS SunJCE提供程序不支持「PKCS7Padding」,因此在任何情況下都必須使用「PKCS5Padding」。 :) – ntoskrnl

2

嗯......莫名其妙的加密應輸出字節數組...

解密應該將其轉換回字節數組,它必須被解釋爲UTF-8 - 使用Snew字符串編碼字符串(UTF_編碼字符串

那麼你做一些字符串魔術在這裏:

encMsg = stringToHex(new String(cipherData)); 

爲什麼???你不需要那個!

msg = new String(decryptedData); 

你需要給相同的編碼加密:

msg = new String(decryptedData, "UTF-8"); 

一個嘗試清理和修復你的代碼:

import java.io.UnsupportedEncodingException; 
import javax.crypto.*; 
import java.security.*; 
import java.util.Arrays; 
import javax.crypto.spec.*; 

public class AESCrypto2 { 

    private Cipher AEScipher; 
    private KeyGenerator AESgen; 
    private SecretKeySpec AESkey; 
    private SecretKeySpec decodeKey; 
    private byte[] cipherData; 
    private String msg; 

    public static void main(String[] args) { 
     try { 
      AESCrypto2 a = new AESCrypto2(); 
      a.encrypt("Hello!"); 
      a.decrypt(a.getCipherData(), a.getKey()); 
     } catch (NoSuchAlgorithmException ex) { 
      ex.printStackTrace(); 
     } catch (NoSuchPaddingException ex) { 
      ex.printStackTrace(); 
     } catch (InvalidKeyException ex) { 
      ex.printStackTrace(); 
     } catch (UnsupportedEncodingException ex) { 
      ex.printStackTrace(); 
     } catch (IllegalBlockSizeException ex) { 
      ex.printStackTrace(); 
     } catch (BadPaddingException ex) { 
      ex.printStackTrace(); 
     } 

    } 

    public AESCrypto2() throws NoSuchAlgorithmException, 
      NoSuchPaddingException, UnsupportedEncodingException { 
     AESgen = KeyGenerator.getInstance("AES"); 
     AESgen.init(128); 
     AESkey = (SecretKeySpec) AESgen.generateKey(); 
     decodeKey = new SecretKeySpec(AESkey.getEncoded(), "AES"); 
     AEScipher = Cipher.getInstance("AES/ECB/NoPadding"); 
    } 

    public AESCrypto2(String msg) throws NoSuchAlgorithmException, 
      NoSuchPaddingException, InvalidKeyException, 
      UnsupportedEncodingException, IllegalBlockSizeException, 
      BadPaddingException { 
     this(); 
     encrypt(msg); 
    } 

    public byte[] encrypt(String msg) throws NoSuchAlgorithmException, 
      InvalidKeyException, UnsupportedEncodingException, 
      IllegalBlockSizeException, BadPaddingException, 
      NoSuchPaddingException { 
     AEScipher.init(Cipher.ENCRYPT_MODE, AESkey); 
     cipherData = AEScipher.doFinal(handleString(msg.getBytes("UTF-8"))); 

     this.msg = msg; 
     return cipherData; 
    } 

    public String decrypt(byte[] enocdedData, SecretKeySpec decodeKey) 
      throws InvalidKeyException, IllegalBlockSizeException, 
      BadPaddingException, UnsupportedEncodingException, 
      NoSuchAlgorithmException, NoSuchPaddingException { 
     AEScipher.init(Cipher.DECRYPT_MODE, decodeKey); 
     byte[] decryptedData = AEScipher.doFinal(enocdedData); 
     String result = new String(decryptedData, "UTF-8"); 
     System.out.println(result); 
     return result; 
    } 

    public byte[] getCipherData() { 
     return cipherData; 
    } 

    public String getDecryptedMsg() { 
     return msg; 
    } 


    public SecretKeySpec getKey() { 
     return decodeKey; 
    } 

    // AEScipher requires that 16 divides the length of b 
    public static byte[] handleString(byte[] b) 
      throws UnsupportedEncodingException { 
     byte[] temp = b; 
     if (temp.length % 16 != 0) { 
      byte[] byteMsg = Arrays.copyOf(temp, temp.length + 16 
        - (temp.length % 16)); 
      return byteMsg; 
     } 
     return temp; 
    } 

    public static String byteToHex(byte[] msg) throws UnsupportedEncodingException { 
     return Hex.encodeHexString(msg); 
    } 

    public static byte[] hexToByte(String msg) throws DecoderException { 
     return Hex.decodeHex(msg); 
    } 

} 
+0

我希望所有的加密都是十六進制的。我嘗試了你的其他建議,並得到了相同的結果。 – Kortlek

+0

您不能將密文等二進制數據視爲UTF-8。 – ntoskrnl

+0

所以你在中間的主要問題是將字節[]轉換爲十六進制字符串,並返回 – RobbySherwood