Java中AES解密中的奇怪字符

时间:2014-03-03 20:31:34

标签: java cryptography

我想知道你是否可以帮助我理解为什么我的解密方法会给出奇怪的字符。具体来说,在这种情况下,我得到的字符类似于

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

}

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

嗯......不知怎的,加密应输出一个字节数组......

解密应该将其转换回字节数组,必须将其解释为UTF-8 - 使用新字符串对字符串进行编码(UTF_encoded string

然后你在这里做一些字符串魔术:

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

}