2014-03-03 54 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