Java 如果我只有解密方法,如何重新创建AES加密方法

Java 如果我只有解密方法,如何重新创建AES加密方法,java,encryption,Java,Encryption,我想知道是否有可能仅仅通过解密方法来重新生成加密过程 换句话说,我有了这个代码,我想回到加密 public class Encrypter { private String iv = "qj839.SkW@a#pPsX"; private String SecretKey = "!D&@DKmq81-CClo"; String keyphrase = "SomeWords"; private IvParameterSpec iv

我想知道是否有可能仅仅通过解密方法来重新生成加密过程

换句话说,我有了这个代码,我想回到加密

public class Encrypter {
    private String iv           = "qj839.SkW@a#pPsX";
    private String SecretKey    = "!D&@DKmq81-CClo";
    String keyphrase = "SomeWords";

    private IvParameterSpec ivspec;
    private SecretKeySpec keyspec;
    private Cipher cipher;

    public Encrypter() {
        SecretKey = Hash.getMD5(keyphrase).substring(4, 20);
        ivspec = new IvParameterSpec(iv.getBytes());
        keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
        try {
            cipher = Cipher.getInstance("AES/CBC/NoPadding");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    public byte[] decrypt(String code) throws Exception {
        if (code == null || code.length() == 0) {
            return null;
        }

        code = code.replaceAll("-", "").toLowerCase();
        byte[] decrypted = null;
        try {
            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
            decrypted = cipher.doFinal(hexToBytes(code));
            //Remove trailing zeroes
            if (decrypted.length > 0) {
                int trim = 0;
                for (int i = decrypted.length - 1; i >= 0; i--) {
                    if (decrypted[i] == 0) {
                        trim++;
                    }
                }

                if (trim > 0) {
                    byte[] newArray = new byte[decrypted.length - trim];
                    int length = decrypted.length - trim;
                    int srcPos = 0;
                    int destPos = 0;
                    while (length > 0) {
                        newArray[destPos] = decrypted[srcPos];
                        srcPos++;
                        destPos++;
                        length--;
                    }
                    decrypted = newArray;
                }
            }
        } catch (Exception e) {
            return null;
        }
        return decrypted;
    }

    public String decryptString(String text) throws Exception {
        byte[] temp = decrypt(text);
        if (temp == null) return null;
        return new String(temp);
    }

    public byte[] hexToBytes(String str) {
        if (str == null) {
            return null;
        } else if (str.length() < 2) {
            return null;
        } else {
            int len = str.length() / 2;
            byte[] buffer = new byte[len];
            for (int i = 0; i < len; i++) {
                buffer[i] = (byte) Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
            }
            return buffer;
        }
    }
}
公共类加密机{
私有字符串iv=“qj839。SkW@a#pPsX”;
私有字符串SecretKey=“!D&@DKmq81 CClo”;
字符串关键字短语=“SomeWords”;
私有IvParameterSpec ivspec;
私有SecretKeySpec-keyspec;
专用密码;
公共加密机(){
SecretKey=Hash.getMD5(keyphase).substring(4,20);
ivspec=新的IvParameterSpec(iv.getBytes());
keyspec=newsecretkeyspec(SecretKey.getBytes(),“AES”);
试一试{
cipher=cipher.getInstance(“AES/CBC/NoPadding”);
}捕获(无算法异常){
e、 printStackTrace();
}捕获(无此填充例外){
e、 printStackTrace();
}
}
公共字节[]解密(字符串代码)引发异常{
if(code==null | | code.length()==0){
返回null;
}
code=code.replaceAll(“-”,“”)。toLowerCase();
字节[]已解密=空;
试一试{
cipher.init(cipher.DECRYPT_模式,keyspec,ivspec);
解密=cipher.doFinal(十六字节(代码));
//删除尾随零
如果(已解密。长度>0){
int trim=0;
对于(int i=decrypted.length-1;i>=0;i--){
if(解密的[i]==0){
trim++;
}
}
如果(修剪>0){
byte[]newArray=新字节[decrypted.length-trim];
int length=解密的.length-修剪;
int srcPos=0;
int destPos=0;
而(长度>0){
newArray[destPos]=已解密的[srcPos];
srcPos++;
destPos++;
长度--;
}
解密=新数组;
}
}
}捕获(例外e){
返回null;
}
返回解密;
}
公共字符串解密字符串(字符串文本)引发异常{
字节[]临时=解密(文本);
如果(temp==null)返回null;
返回新字符串(temp);
}
公共字节[]十六字节(字符串str){
如果(str==null){
返回null;
}else if(str.length()<2){
返回null;
}否则{
int len=str.length()/2;
字节[]缓冲区=新字节[len];
对于(int i=0;i
由于这是AES对称加密,因此
加密机实际上保持不变。我怀疑您不理解为什么在这行代码后面有附加代码

decrypted = cipher.doFinal(hexToBytes(code));
这是真正的解密

CBC模式下的AES仅适用于块大小的倍数(AES为16字节)。如果要加密任意长度的明文,需要填充明文,直到达到预期长度。通常这是通过PKCS#5/PKCS#7填充完成的,但在本例中是零填充。这意味着填充实际上是0到15个尾随0x00字节

通过将填充指定为“NoPadding”,开发人员的任务是实现填充

解密代码有点笨拙和冗余,但它可以工作

代码类似于:

/**
 * TODO: add error handling
 */
public String encrypt(byte[] plaintext) {
    int bs = cipher.getBlockSize();
    int targetSize = plaintext.length + (bs - plaintext.length % bs) % bs;
    byte[] plaintextPadded = new byte[targetSize];
    System.arraycopy(plaintext, 0, plaintextPadded, 0, plaintext.length);

    cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
    byte[] encrypted = cipher.doFinal(plaintextPadded);
    return bytesToHex(encrypted);
}

// TODO: add bytesToHex implementation
这段代码使用了一个事实,即
newbyte[x]
实际上使用0x00初始化所有字节,因此不需要显式写入填充字节


其他考虑:
  • 此处使用的零填充只能用于字符串数据或通常不能以0x00字节结尾的数据。如果要加密任意数据,需要使用
    Cipher.getInstance(“AES/CBC/PKCS5Padding”)

  • 切勿使用静态IV。它应在同一密钥下为每次加密随机生成。因为它不必是秘密的,所以您可以简单地将其预先添加到密文中,以便在解密过程中将其切掉

  • AES密钥应该由任意字节组成。如果将密钥空间限制为可打印字符(
    String
    ),则更容易使用暴力。(一开始并不容易)

  • 您正在使用
    新字符串(byte[])
    String.getBytes()
    而无需其他参数。为了指定字符编码,如“UTF-8”,您需要向这两者传递一个附加参数。如果不这样做,则在尝试解密在不同系统上使用不同默认字符集加密的密文时可能会遇到问题


由于这是AES对称加密,因此
加密机实际上保持不变。我怀疑您不理解为什么在这行代码后面有附加代码

decrypted = cipher.doFinal(hexToBytes(code));
这是真正的解密

CBC模式下的AES仅适用于块大小的倍数(AES为16字节)。如果要加密任意长度的明文,需要填充明文,直到达到预期长度。通常这是通过PKCS#5/PKCS#7填充完成的,但在本例中是零填充。这意味着填充实际上是0到15个尾随0x00字节

通过将填充指定为“NoPadding”,开发人员的任务是实现填充

解密代码有点笨拙和冗余,但它可以工作

代码类似于:

/**
 * TODO: add error handling
 */
public String encrypt(byte[] plaintext) {
    int bs = cipher.getBlockSize();
    int targetSize = plaintext.length + (bs - plaintext.length % bs) % bs;
    byte[] plaintextPadded = new byte[targetSize];
    System.arraycopy(plaintext, 0, plaintextPadded, 0, plaintext.length);

    cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
    byte[] encrypted = cipher.doFinal(plaintextPadded);
    return bytesToHex(encrypted);
}

// TODO: add bytesToHex implementation
此代码使用的事实是
新字节[x]
实际上使用0x00初始化所有字节,因此不需要