【问题标题】:sun.misc.BASE64 to apache commonssun.misc.BASE64 到 apache commons
【发布时间】:2013-02-19 19:31:14
【问题描述】:

我这里有一个简单的代码,代码使用了 Eclipse Java 7.0 中不可用的 sun.misc.BASE64Encoder 和 sun.misc.BASE64Decoder,我想让代码使用 Apache commons base 64并且仍然做同样的事情,

变量

private static final String ALGORITHM = "AES";
private static final byte[] keyValue = "2H5a1r5i6s3h8C1h".getBytes();

原始代码

public static String AESencrypt(String valueToEnc) throws Exception {
    Key key = new SecretKeySpec(keyValue, ALGORITHM);
    Cipher c = Cipher.getInstance(ALGORITHM);
    c.init(Cipher.ENCRYPT_MODE, key);
    byte[] encValue = c.doFinal(valueToEnc.getBytes());
    String encryptedValue = new BASE64Encoder().encode(encValue);
    return encryptedValue;
}

public static String AESdecrypt(String encryptedValue) throws Exception {
    Key key = new SecretKeySpec(keyValue, ALGORITHM);
    Cipher c = Cipher.getInstance(ALGORITHM);
    c.init(Cipher.DECRYPT_MODE, key);
    byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
    byte[] decValue = c.doFinal(decordedValue);
    String decryptedValue = new String(decValue);
    return decryptedValue;
}

尝试修改为 apache commons 代码

public static String AESencrypt(String valueToEnc) throws Exception {
    Key key = new SecretKeySpec(keyValue, ALGORITHM);
    Cipher c = Cipher.getInstance(ALGORITHM);
    c.init(Cipher.ENCRYPT_MODE, key);
    byte[] encValue = c.doFinal(valueToEnc.getBytes());
    String encryptedValue = new Base64().encodeBase64(encValue).toString();
    return encryptedValue;
}

public static String AESdecrypt(String encryptedValue) throws Exception {
    Key key = new SecretKeySpec(keyValue, ALGORITHM);
    Cipher c = Cipher.getInstance(ALGORITHM);
    c.init(Cipher.DECRYPT_MODE, key);
    byte[] decordedValue = new Base64().decodeBase64(encryptedValue);
    byte[] decValue = c.doFinal(decordedValue);
    String decryptedValue = new String(decValue);
    return decryptedValue;
}

原代码运行正常,新代码抛出如下异常,

线程“主”javax.crypto.IllegalBlockSizeException 中的异常: 使用填充密码解密时,输入长度必须是 16 的倍数 在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750) 在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676) 在 com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313) 在 javax.crypto.Cipher.doFinal(Cipher.java:2087) 在 trial2.encrypt.AESdecrypt(encrypt.java:28) 在 trial2.encrypt.main(encrypt.java:37) Java 结果:1

如何在不过多更改初始代码的情况下解决此问题,这里和那里的几行就可以了。是否可以完全消除 Base64 编码步骤并使其仅使用如下密码:

public static String AESencrypt(String valueToEnc) throws Exception {
    Key key = new SecretKeySpec(keyValue, ALGORITHM);
    Cipher c = Cipher.getInstance(ALGORITHM);
    c.init(Cipher.ENCRYPT_MODE, key);
    byte[] encValue = c.doFinal(valueToEnc.getBytes());
    return encValue.toString();
}

public static String AESdecrypt(String encryptedValue) throws Exception {
    Key key = new SecretKeySpec(keyValue, ALGORITHM);
    Cipher c = Cipher.getInstance(ALGORITHM);
    c.init(Cipher.DECRYPT_MODE, key);
    byte[] decValue = c.doFinal(encryptedValue.getBytes());
    String decryptedValue = new String(decValue);
    return decryptedValue;
}

上面的代码和第二个代码有类似的异常:

线程“主”javax.crypto.IllegalBlockSizeException 中的异常: 使用填充密码解密时,输入长度必须是 16 的倍数 在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750) 在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676) 在 com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313) 在 javax.crypto.Cipher.doFinal(Cipher.java:2087) 在 trial2.encrypt.AESdecrypt(encrypt.java:26) 在 trial2.encrypt.main(encrypt.java:35) Java 结果:1

请帮助和 TYVM

【问题讨论】:

  • 建议:去掉加密并做一些测试。它们是否产生相同的值等。这应该是可以解决的!
  • 永远不要永远使用 Sun 内部类,它们可能会在没有警告的情况下被删除或更改。它们不是官方 Java API 的一部分。请注意,如果您选择特定的 JRE 或 JDK 而不是运行时环境,这些类将再次可用(同样,因为运行时环境仅将这些类用于实现目的,而不是作为 API)
  • 永远不要只指定“AES”作为算法,因为它可能会为特定的提供者返回不同的默认值。 Sun/Oracle 默认返回“AES/ECB/PKCS5Padding”,使用起来不安全(保密所需的最低模式是 CBC 模式)。
  • 切勿在未指定编码的情况下使用 getBytes()String 构造函数。在 Java 7 中,您可以改用 String.getBytes(StandardCharsets.UTF8)。如果你不介意,我会让你猜测构造函数调用。
  • 永远不要直接使用String 值作为密钥,如果您想使用密码,您应该使用 KDF,例如 PBKDF2(搜索此站点),或者您应该使用安全的随机二进制密钥用于加密/解密。

标签: java base64 aes apache-commons


【解决方案1】:

错误在于您的加密方法。以下代码错误:

byte[] encValue = c.doFinal(valueToEnc.getBytes());
String encryptedValue = new Base64().encodeBase64(encValue).toString();

你在一个字节数组上调用toString(),它不会做你想要的!相反,请尝试:

byte[] encValue = c.doFinal(valueToEnc.getBytes());
String encryptedValue = Base64.encodeBase64String(encValue);

这应该可以正常工作。

【讨论】:

  • 这似乎可行,是否有必要进行 base64 编码步骤?我的意思是我不明白它的作用。
  • 如果您希望将密文存储为字符串,base64 编码步骤是您可用的选项之一。另一个常用的选项是 base16(又名十六进制)。根据您的用例,您可以将密文保留为字节数组。通常,转换为字符串仅用于数据传输,尤其是在 Web 环境中。
  • ty 寻求帮助,猜猜我需要这样做才能保存到数据库。
猜你喜欢
  • 2020-09-03
  • 2011-01-21
  • 2023-03-30
  • 2018-04-04
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 2011-06-08
  • 2011-01-13
相关资源
最近更新 更多