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

标签 java encryption

我想知道是否可以仅通过解密方法来重现加密过程?

换句话说,我已经获得了此代码,并且我想返回加密。

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

最佳答案

由于这是使用 AES 的对称加密,因此加密器实际上保持不变。我怀疑您不明白该行后面有附加代码的原因

decrypted = cipher.doFinal(hexToBytes(code));

这是实际的解密。

CBC 模式下的 AES 仅适用于 block 大小的倍数,即 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

此代码使用了 new byte[x] 实际上用 0x00 初始化所有字节的事实,因此无需显式写入填充字节。

<小时/>

其他注意事项:

  • 此处使用的零填充只能用于字符串数据或一般不能以 0x00 字节结束的数据。如果要加密任意数据,则需要使用Cipher.getInstance("AES/CBC/PKCS5Padding")

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

  • AES key 应该由任意字节组成。如果将 key 空间限制为可打印字符(String),则暴力破解会更容易。 (并不是说一开始就很容易)

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

关于java - 如果我只有解密方法,如何重新创建 AES 加密方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32786457/

相关文章:

java - 如何在 java6 中支持 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

C语言凯撒密码——加密与解密

java - 错误填充异常 - pkcs11 中的 RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING

java - 我有以下 JSON,如何将其捕捉到 Road Android Google Maps

Java继承困惑,父类(super class)和子类成员变量同名

java - 如何让 JTable 上的 MouseListener 正常工作

java - 错误 Selenium 无法检索文档状态已断开 : received Inspector. 分离事件

Java:搜索错误编码的字符串而不修改它

encryption - 用户如何证明特定帐户有权访问 BigQuery? (AEAD 加密和授权 View )

c# - C# 中的 RC4 128 位加密