Java加解密中IV和salt的处理

2024-06-28

所以我试图在方法中解密消息,但它不起作用,因为我需要这样做cipher.init(Cipher.ENCRYPT_MODE, secret)在我尝试添加之前new IvParameterSpec(iv) to cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));。否则,它只会返回一个 NullPointerException 我想知道是否可以在方法中执行此操作,而不是一直编写它。我真的想不出解决方案,所以这就是我来这里的原因。加密工作正常,但解密不行。

项目运行: JRE 7

加密代码:

public static String encrypt(String str) {
    try {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(str.toCharArray(), salt, 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret); //<--- Need to do this before writing IvPerameterSpec,
        // But I think that it's not possible if I have it in another method.
        byte[] encryptedText = cipher.doFinal(str.getBytes("UTF-8"));

        return new String(encryptedText);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

解密代码:

public static String decrypt(String str) {
    try {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(str.toCharArray(), salt, 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        AlgorithmParameters params = cipher.getParameters();
        byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
        //                                                ^^^ Returns NullPointerException

        byte[] ciphertext = cipher.doFinal(str.getBytes("UTF-8"));
        String decryptedText = new String(cipher.doFinal(ciphertext), "UTF-8");

        return new String(decryptedText);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

例外:

java.lang.NullPointerException
        at me.Sansanvi.Encryption.api.ComputerAPI.decrypt(ComputerAPI.java:149)
        at me.Sansanvi.Encryption.EncryptionMain.initializeFiles(EncryptionMain.java:46)
        at me.Sansanvi.Encryption.EncryptionMain.<init>(EncryptionMain.java:36)
        at me.Sansanvi.Encryption.EncryptionMain$1.run(EncryptionMain.java:23)
        at java.awt.event.InvocationEvent.dispatch(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$200(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)

我将方法更改为以下并且它们有效:

private static final String ALGORITHM = "AES";
    public static byte[] encrypt(byte[] str) {
    try {
        SecretKeySpec secretKey = new SecretKeySpec("MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        return cipher.doFinal(str);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
public static byte[] decrypt(byte[] str) {
    try {
        SecretKeySpec secretKey = new SecretKeySpec("MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        return cipher.doFinal(str);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

我不再收到任何错误/异常,但当我关闭应用程序时,我在控制台中收到此消息:

[0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64)
[0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64)
[0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64)
[0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64)
[0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64)
[0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64)
[0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64)
[0x7FFC837C7430] ANOMALY: use of REX.w is meaningless (default operand size is 64)

您至少有四个问题,而您只发现了其中之一。

  1. IV 是在期间生成的en加密并使用。期间需要使用完全相同的 IVde加密。 IV 不应该是秘密的。您只需将其与密文一起发送/存储即可。通常,IV 存储在密文之前,并在解密之前将其切掉。
    对于 CBC 模式,它只需要是不可预测的(读:随机)。对于 CTR 模式,它需要是唯一的(当使用相同的密钥时)。

  2. 随机盐需要以与 IV 完全相同的方式处理:它不是秘密的,可以写在密文前面。

  3. String不是二进制数据的容器。当你使用new String(encryptedText),您可能会丢失一些无法打印的字节,这会破坏您的密文并使明文无法恢复。您需要使用 Base64 或 Hex 编码之类的东西将二进制数据表示为可打印文本。

  4. If you encrypt something, you need two things: a plaintext and a password (used for key derivation). You also need to two things during decryption: a ciphertext and a password (key). You're using the same string value during encryption. The ciphertext is then mangled in such a way that you would need the original string value during decryption. And that would defeat the purpose of encrypting it in the first place. Your encryption method is basically a hash function.
    Thanks to wittyameta https://stackoverflow.com/users/4746692/wittyameta for pointing this out.

因此,生成的代码将类似于以下内容:

public static String encrypt(String str, String password) {
    try {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = cipher.getParameters();
        byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        byte[] encryptedText = cipher.doFinal(str.getBytes("UTF-8"));

        // concatenate salt + iv + ciphertext
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        outputStream.write(salt);
        outputStream.write(iv);
        outputStream.write(encryptedText);

        // properly encode the complete ciphertext
        return DatatypeConverter.printBase64Binary(outputStream.toByteArray());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

public static String decrypt(String str, String password) {
    try {
        byte[] ciphertext = DatatypeConverter.parseBase64Binary(str);
        if (ciphertext.length < 48) {
            return null;
        }
        byte[] salt = Arrays.copyOfRange(ciphertext, 0, 16);
        byte[] iv = Arrays.copyOfRange(ciphertext, 16, 32);
        byte[] ct = Arrays.copyOfRange(ciphertext, 32, ciphertext.length);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
        byte[] plaintext = cipher.doFinal(ct);

        return new String(plaintext, "UTF-8");
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

我用过this https://stackoverflow.com/a/2054226/1816580用于 Java 7 兼容的 Base64 编码/解码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java加解密中IV和salt的处理 的相关文章

随机推荐

  • Scala 中的逆变和协变

    abstract class Bhanu A val m List A gives error contravariant type A occurs in covariant position in type gt List A of v
  • VSS 到 Subversion

    我正在研究从 SourceSafe 到 Subversion 的潜在迁移 并且我们正在努力解决编辑 合并 提交与签出 更新 签入范例 主要关心的是您如何知道哪些文件已被 Subversion 检出 以及检出给谁 VSS 中是否有相当于 状态
  • 正则表达式删除文件扩展名

    我需要一个可以删除文件名扩展名的正则表达式 仅返回文件名 以下是一些输入和输出的示例 myfile png gt myfile myfile png jpg gt myfile png 显然我可以手动执行此操作 即删除最后一个点中的所有内容
  • Haskell 中将函数与类型关联起来

    假设您有一个序列化器 反序列化器类型类 class SerDes a where ser a gt ByteString des ByteString gt a 事实证明 为每种类型提供一个特殊的辅助函数至关重要a e g compress
  • 用户打字时自动删除输入框中的某些字符

    我正在尝试验证表单 并且我正在处理的输入框应该只包含数字 如果用户开始输入任何字母 我希望他们自动删除 显然如果他们输入数字 则不应删除 这是我的js var defaultValue 10 document ready function
  • 为什么我不能在初始化中使用 attr_accessor ?

    我正在尝试做一个instance eval随后是一个attr accessor inside initialize 我不断收到这样的消息 初始化 未定义的方法 attr accessor 为什么这不起作用 代码看起来有点像这样 class
  • 有没有办法找到 .NET 中嵌入资源的最后修改日期?

    有人知道这样做的方法 在运行时 吗 我不确定我能在描述中详细阐述比标题中已经给出的更多信息 但如果您觉得我错过了某些内容 请说出来 resx 文件本身应该有一个与之关联的修改日期 但您将无法获取该文件中各个资源的修改日期
  • 如何让 Chai 使用 toString() 显示实际值和预期值

    我最近从 should js 切换到 chai js 因为我发现前者在基于浏览器的测试中造成了障碍 该更改不需要对我的测试套件进行任何更改 因为语法受支持 但我发现失败测试的输出不再以有用的方式显示实际值和预期值 AssertionErro
  • 绑定到布尔值的可见性的 TargetNullValue

    我有一个Grid whose Visibility使用以下方法将属性绑定到某个模型的布尔属性Converter
  • iscroll 问题与二维(水平+垂直)滚动、可滚动是否相关?

    问题简述 我有一段有效的二维滚动代码 这样的滚动效果很好 滚动可以在任何方向上完成 不像在 ti e 时仅限于水平或仅限垂直 但有两个问题 向顶部和左侧滚动超出可见区域 不会反弹可滚动区域 向右滚动 底部会弹回来 问题演示 http jsf
  • 自定义 ContentProvider 的 fillWindow() 方法中该怎么做?

    我正在编写一个自定义 ContentProvider 它提供由单个常量字符串组成的内容 我将其表示为具有列 id 0 和 value SomeString 的单行表 该字符串不存储在数据库中 因此我开发了 CrossProcessCurso
  • 如何用CSS制作一个等宽的表格?

    我有一个包含这样的表格的文档 table tr td Word td td Definition td tr tr td Word td td Definition td tr tr td Word td td Definition td
  • 为 IronPython 安装 numpy

    我想使用 c 在 IronPython 中运行一些代码 在此代码中我需要使用 numpy 所以我尝试使用以下命令安装它 ipy X Frames m pip install U numpy 不幸的是 我收到一个错误和一条返回消息 告诉我安装
  • 尝试以编程方式在 Equinox 中安装包时出现 nullPointerException

    我正在尝试做一个简单的演示 在其中启动 Equinox 框架 然后加载创建的教程包 通过教程 我不断得到NullPointerExceptions这是堆栈跟踪 Exception in thread main java lang NullP
  • 如何通过删除移动物体来从多张图像中获取背景?

    我用固定相机拍摄了同一场景的多张图像 其中有移动的物体 我不明白如何在 Python 中使用这些图像通过删除所有移动对象来检索背景图像 任何帮助 将不胜感激 谢谢 下面附有图片 在这种情况下 我希望最终的图像没有任何人参与其中 image1
  • mockito:有没有办法捕获存根方法的返回值?

    如果我模拟一个方法来返回某个对象的新实例 如何捕获返回的实例 E g when mock someMethod anyString thenAnswer new Answer Object answer InvocationOnMock i
  • 如何在 Mathematica 中格式化列中的两个单独列表,而不是行?

    这看起来应该是小菜一碟 但我还没有在 Mathematica 的文档中找到答案 假设我有两个单独的列表 例如 x 1 2 3 4 5 和 y 1 4 9 16 25 我想将这些列表格式化为表格 每个列表作为一列 如下所示 x y 1 1 2
  • 带图案的图片有时会显示得很奇怪

    我的网站是一家服装店 我的合作伙伴抱怨了以下问题 The pictures of clothing with more complex patterns checkerboard for example displays like this
  • .htaccess,正确重写同名目录和文件

    到目前为止 我的网站有一些静态页面 其中之一是 portfolio 除此之外 我的 htaccess 隐藏了 html 扩展名 我想添加一个投资组合目录 但我不想将现有的投资组合页面移动到投资组合目录中作为默认索引文件 我的 portfol
  • Java加解密中IV和salt的处理

    所以我试图在方法中解密消息 但它不起作用 因为我需要这样做cipher init Cipher ENCRYPT MODE secret 在我尝试添加之前new IvParameterSpec iv to cipher init Cipher