当前位置: 首页 > 知识库问答 >
问题:

Java AES加解密

束雅达
2023-03-14

我想加密和解密密码使用128位AES加密与16字节的密钥。在解密值时,我得到javax.crypto.BadPaddingException错误。我在解密的时候漏掉了什么吗?

public static void main(String args[]) {
    Test t = new Test();
    String encrypt = new String(t.encrypt("mypassword"));
    System.out.println("decrypted value:" + t.decrypt("ThisIsASecretKey", encrypt));
}

public String encrypt(String value) {
    try {
        byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        System.out.println("encrypted string:" + (new String(encrypted)));
        return new String(skeySpec.getEncoded());
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalBlockSizeException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BadPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

public String decrypt(String key, String encrypted) {
    try {
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(skeySpec.getEncoded(), "AES"));
        //getting error here
        byte[] original = cipher.doFinal(encrypted.getBytes());
        return new String(original);
    } catch (IllegalBlockSizeException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BadPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}  

错误信息

encrypted string:�Bj�.�Ntk�F�`�
encrypted key:ThisIsASecretKey
decrypted value:null
May 25, 2012 12:54:02 PM bean.Test decrypt
SEVERE: null
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at bean.Test.decrypt(Test.java:55)
at bean.Test.main(Test.java:24)
public class Test {

public String encryptionKey;

public static void main(String args[]) {
    Test t = new Test();
    String encrypt = t.encrypt("mypassword");
    System.out.println("decrypted value:" + t.decrypt(t.encryptionKey, encrypt));
}

public String encrypt(String value) {
    try {
        // Get the KeyGenerator
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(256);
        // Generate the secret key specs.
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        String key = new Base64().encodeAsString(raw);
        this.encryptionKey = key;
        System.out.println("------------------Key------------------");
        System.out.println(key);
        System.out.println("--------------End of Key---------------");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        String encrypt = (new Base64()).encodeAsString(cipher.doFinal(value.getBytes()));
        System.out.println("encrypted string:" + encrypt);
        return encrypt;
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalBlockSizeException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BadPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

public String decrypt(String key, String encrypted) {
    try {
        Key k = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.DECRYPT_MODE, k);
        byte[] decodedValue = Base64.getDecoder().decode(encrypted);
        byte[] decValue = c.doFinal(decodedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    } catch (IllegalBlockSizeException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BadPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchPaddingException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

}

共有1个答案

欧阳智志
2023-03-14

如果对于分组密码,您不打算使用包含填充方案的cipher转换,则需要使明文中的字节数是密码块大小的整数倍。

因此,要么将明文填充到16字节的倍数(这是AES块大小),要么在创建cipher对象时指定填充方案。例如,您可以使用:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

除非您有充分的理由不这样做,否则请使用JCE实现中已经包含的填充方案。他们已经想出了许多微妙的情况和角落,你必须意识到和处理自己否则。

String s = new String(someBytes);
byte[] retrievedBytes = s.getBytes();

SomeBytesRetrievedBytes不会相同。

如果您希望/必须将密文保存在字符串中,那么base64首先对密文字节进行编码,然后从base64编码的字节构造字符串。然后在解密时,您将getBytes()字符串中获取base64编码的字节,然后base64-decode它们以获得真正的密文,然后对其进行解密。

这个问题的原因是大多数(全部?)字符编码不能将任意字节映射到有效字符。因此,当您从密文创建字符串时,string构造函数(应用字符编码将字节转换为字符)实际上必须丢弃一些字节,因为它对这些字节没有意义。因此,当您从字符串中获得字节时,它们与您放入字符串的字节不同。

在Java中(以及一般的现代编程中),您不能假设一个字符=一个字节,除非您完全知道您处理的是ASCII。这就是为什么如果要从任意字节构建字符串,就需要使用base64(或类似的东西)。

 类似资料:
  • 我有一个应用程序,需要在配置文件中存储一些秘密密码,如数据库和ftp密码/详细信息。我环顾四周,发现了许多使用AES的加密/解密解决方案,但我似乎不知道如何在不改变密钥的情况下使其工作。这意味着我可以加密和解密(使用相同的秘密密钥),但在重启等过程中保持持久性。我似乎无法让秘密钥匙保持不变。下面的示例显示了我的工作方法: 到目前为止还不错。然而,如果我运行它一次,我可能会得到'2Vhht/L80U

  • 以下示例有什么问题? 问题是解密字符串的第一部分是无意义的。不过,其余的都很好,我明白了...

  • BK.Crypt 加解密模块 可以对字符串或byte数组进行MD5、HMAC-MD5、SHA1、HMAC-SHA1加密操作,结果以十六进制字符串或Base64字符串返回。 异步接口 md5ToHex(object) 将字符串进行md5 hash操作,结果以16进制字符串返回。 手Q版本:无版本要求 函数参数object: 属性名 类型 是否必填 说明 data string或Array\ 是 类型

  • 我们封装了一个RSA 加解密的工具放在 extends 中。首先看看它的文件结构 rsa |-- RSACrypt 加解密主程序 |-- RSACryptBigData 大数据加解密 |-- SignUtil 签名类 |-- rsa_public_key.pem 公钥 |-- rsa_private_key.pem 私钥 RSACrypt API RSAC

  • 加解密算法 算法类型 特点 优势 缺陷 代表算法 对称加密 加解密密钥相同或可推算 计算效率高,加密强度高 需提前共享密钥;易泄露 DES、3DES、AES、IDEA 非对称加密 加解密密钥不相关 无需提前共享密钥 计算效率低,仍存在中间人攻击可能 RSA、ElGamal、椭圆曲线系列算法 算法体系 现代加密算法的典型组件包括:加解密算法、加密密钥、解密密钥。其中,加解密算法自身是固定不变的,一般

  • 配置 在使用 Lumens 的加解密前,你应该先把 .env 文件中的 APP_KEY 选项设置为 32 位随机字符串。如果没有适当地设置这个值,所有被 Lumen 加密的值都将是不安全的。 基本用法 加密一个值 你可以使用 Crypt 门面来加密一个值。所有的加密值都使用 OpenSSL 和 AES-256-CBC 来进行加密。 此外, 所有加密过的值都会使用消息认证码 (MAC)来进行签名,以