【问题标题】:Encryption in Java while Decryption method is knownJava中的加密,而解密方法是已知的
【发布时间】:2019-08-08 13:05:37
【问题描述】:

我尝试在Java中制作加密和解密机制。我找到了一些用于解密的代码,但我不知道如何加密。什么样的加密方式会兼容这样的解密方式:

private byte[] padKey(byte[] key) {
        byte[] paddedKey = new byte[32];
        System.arraycopy(key, 0, paddedKey, 0, key.length);
        return paddedKey;
    }

    private byte[] unpad(byte[] data) {     
        byte[] unpaddedData = new byte[data.length - data[data.length - 1]];
        System.arraycopy(data, 0, unpaddedData, 0, unpaddedData.length);
        return unpaddedData;
    }


public String decrypt(String encodedJoinedData) throws Exception {

        // Base64-decode the joined data
        byte[] joinedData = Base64.decode(encodedJoinedData); 

        // Get IV and encrypted data
        byte[] iv = new byte[16];
        System.arraycopy(joinedData, 0, iv, 0, iv.length);
        byte[] encryptedData = new byte[joinedData.length - iv.length];
        System.arraycopy(joinedData, iv.length, encryptedData, 0, encryptedData.length);

        // Pad key
        byte[] key = padKey("SiadajerSiadajer".getBytes()); 
        Key aesKey = new SecretKeySpec(key, "AES");

        // Specify CBC-mode
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 
        cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);

        // Decrypt data
        byte[] decryptedData = cipher.doFinal(encryptedData);

        // Remove custom padding
        byte[] unpaddedData = unpad(decryptedData);         

        return new String(unpaddedData);
    }

【问题讨论】:

  • 嗯,加密和解密必须使用相同的方法,所以是Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");。所有基本信息都在@Lino 建议的链接中。
  • 尽管我强烈建议您阅读一下您在做什么。加密是一个广泛的领域,如果你不知道自己在做什么,很容易做出看起来安全但实际上并不安全的东西
  • 我是一个初学者,我还是不知道应该怎么做

标签: java encryption byte aes


【解决方案1】:

如果您正在寻找与您的decrypt-方法对应的加密,您只需在您的decrypt-方法中反转该过程。必须在encrypt-方法的主体中完成以下操作(让plainText 成为包含纯文本的String-参数):

  1. 添加自定义填充

    // Pad data (custom padding)
    byte[] paddedData = pad(plainText.getBytes(), 16);
    
  2. 加密你的纯文本

    // Pad key 
    byte[] key = padKey("SiadajerSiadajer".getBytes()); 
    Key aesKey = new SecretKeySpec(key, "AES");
    
    // Specify block-cipher (AES), mode (CBC) and padding (PKCS5)
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    
    // Create random IV
    SecureRandom secureRandom = new SecureRandom();
    byte iv[] = new byte[cipher.getBlockSize()];
    secureRandom.nextBytes(iv);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 
    
    // Encrypt data
    cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivParameterSpec);
    byte[] encryptedData = cipher.doFinal(paddedData);
    
  3. 加入 IV 和加密数据

    // Join IV and encrypted data
    byte[] joinedData = new byte[iv.length + encryptedData.length];  
    System.arraycopy(iv, 0, joinedData, 0, iv.length);
    System.arraycopy(encryptedData, 0, joinedData, iv.length, encryptedData.length);
    
  4. Base 64 编码连接的数据

    // Base64-encode data
    String encodedJoinedData = Base64.encode(joinedData, 0);
    

最后,encodedJoinedData 必须返回。

此外,您必须实现自定义填充。以下方法实现了自定义 PKCS5-Padding,并且可能与 unpad-方法对应:

private byte[] pad(byte[] data, int size) {
    byte padLength = (byte)(size - (data.length % size));
    byte[] paddedData = new byte[data.length + padLength];
    System.arraycopy(data, 0, paddedData, 0, data.length);
    for (int i = data.length; i < paddedData.length; i++)
        paddedData[i] = (byte)padLength;
    return paddedData;
}

顺便说一句,您的decrypt-方法(以及encrypt-方法)存在一些问题:

  • 您不应该使用硬编码的密钥,但这可能仅用于测试目的。要创建安全的 AES 密钥,请参见例如How to create a secure random AES key in Java?。
  • 最明显的缺陷是它在decrypt/encrypt-方法中被取消填充/填充了两次,这没有任何意义。因此,删除所选的 PKCS5-Padding(即从 AES/CBC/PKCS5Padding 更改为 AES/CBC/NoPadding)或两者中的自定义填充,decrypt- 和 encrypt- 方法(前提是在您的项目范围内是可能的) .

【讨论】:

  • 在代码的最后一部分(正好在:String encodedJoinedData = Base64.encode(joinedData, 0); 部分)编码方法带有红色下划线,因为它没有为 Base64 类型定义。建议的有 endcodeBytes()、encodeObject()、encodeToFile();我应该选择什么?
  • 当我选择其他选项时,几乎整个代码都带有红色下划线,所以也许还有其他事情要做
  • 很高兴听到它正在工作。不幸的是,发布的代码没有显示使用了哪个Base64-class,所以我不得不在这里猜测。可能我的选择不适合您使用的库。原则上可以使用任何(已建立的)实现,例如java.util.Base64 或 Appache 变体 org.apache.commons.codec.binary.Base64。当然,代码必须稍作修改。但显然你已经解决了问题。
  • 我能得到一个适合 java.util.Base64 的方法版本吗?
  • java.util.Base64 自 Java 1.8 起就存在,另请参见 here。 Base64 编码在encrypt 方法的末尾执行:String encodedJoinedData = Base64.getEncoder().encodeToString(joinedData)。 Base64 解码在decrypt 方法的开头执行:byte[] joinedData = Base64.getDecoder().decode(encodedJoinedData)。只需用这些替换现有的代码部分。
猜你喜欢
  • 1970-01-01
  • 2016-01-10
  • 2013-03-24
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
  • 2011-12-10
  • 2012-05-05
相关资源
最近更新 更多