Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将字节[]解密回字符串而不丢失数据_Java_Security_Encryption_Cryptography - Fatal编程技术网

Java 将字节[]解密回字符串而不丢失数据

Java 将字节[]解密回字符串而不丢失数据,java,security,encryption,cryptography,Java,Security,Encryption,Cryptography,我已经编写了一个使用AES加密和解密字符串的小应用程序。代码如下: import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import java.security.NoSuchAlgorithmExcep

我已经编写了一个使用AES加密和解密字符串的小应用程序。代码如下:

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class AesEncryptionTest {
    static IvParameterSpec initialisationVector = generateInitialisationVector();
    static SecretKey encryptionKey = generateKey();
    static String plainText = "test text 123\0\0\0";

    public static void main(String [] args) {
        try {
            System.out.println("Initial Plain Text = " + plainText);

            byte[] encryptedText = encrypt(plainText, encryptionKey);
            System.out.println("Encrypted Text     = " + encryptedText);

            String decryptedText = decrypt(encryptedText, encryptionKey);
            System.out.println("Decrypted Text     = " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static byte[] encrypt(String plainText, SecretKey encryptionKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
        cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, initialisationVector);
        return cipher.doFinal(plainText.getBytes("UTF-8"));
    }

    public static String decrypt(byte[] encryptedText, SecretKey encryptionKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
        cipher.init(Cipher.DECRYPT_MODE, encryptionKey, initialisationVector);
        return new String(cipher.doFinal(encryptedText),"UTF-8");
    }

    public static SecretKey generateKey() {
        SecretKey secretKey = null;
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);
            secretKey = keyGenerator.generateKey();
        } catch (NoSuchAlgorithmException ex) {
           // Whine a little
        }
        return secretKey;
    }

    public static IvParameterSpec generateInitialisationVector() {
        byte[] initVector = new byte[16];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(initVector);

        return new IvParameterSpec(initVector);
   }
}
输出:

Initial Plain Text = test text 123
Encrypted Text     = [B@407dcb32
Decrypted Text     = test text 123
我主要关注的领域是加密到字节数组中,然后解密回字符串。我知道这会导致意外行为和数据丢失。虽然在我的测试中没有观察到这一点,但有人能提出任何有助于解决这一问题的改变吗?我想我已经通过确保UTF-8的两种使用方式涵盖了这一点

如果有人看到我的代码中有任何其他危险信号,以及我是如何做到这一点的,我愿意接受批评/建议

非常感谢

您正在调用字节[]上的toString,这绝不是一个好主意。基本上它不会给你任何有用的信息

如果您想将任意二进制数据转换为字符串,我建议使用十六进制或base64,这两种格式在其他地方都有介绍。没有迹象表明您在加密/解密过程中丢失了任何信息-问题在于您显示的加密数据。只要你不试图把它当作简单的编码文本数据,因为它不是你应该很好。特别是,您的代码已经将UTF-8指定为从原始文本到未加密二进制数据的转换,反之亦然,所以这是安全的

如果不需要将字节数组转换为字符串,那么最简单的方法是首先避免这样做。例如,您可以非常简单地将其写入一个仍然以二进制形式存在的文件,然后稍后将其加载回字节数组。

您调用的是在字节[]上字符串,这绝不是一个好主意。基本上它不会给你任何有用的信息

如果您想将任意二进制数据转换为字符串,我建议使用十六进制或base64,这两种格式在其他地方都有介绍。没有迹象表明您在加密/解密过程中丢失了任何信息-问题在于您显示的加密数据。只要你不试图把它当作简单的编码文本数据,因为它不是你应该很好。特别是,您的代码已经将UTF-8指定为从原始文本到未加密二进制数据的转换,反之亦然,所以这是安全的


如果不需要将字节数组转换为字符串,那么最简单的方法是首先避免这样做。例如,您可以非常简单地将其写入仍为二进制格式的文件,然后稍后将其加载回字节数组。

确保转换不会丢失的方法是在来回转换时使用与您相同的字符集

然而,创建一个加密数据字符串对于进一步使用是不安全的;它可以包含任何和所有字节序列,并且可能不适合您最初使用的任何字符集。您没有犯这个错误,只是指出了它


您还在代码中间打印字节[]的哈希代码,而不是单个字节。

确保转换不会丢失的方法是在来回转换时使用相同的字符集

然而,创建一个加密数据字符串对于进一步使用是不安全的;它可以包含任何和所有字节序列,并且可能不适合您最初使用的任何字符集。您没有犯这个错误,只是指出了它


您还将在代码中间打印字节[]的哈希代码,而不是单个字节。

您要求其他红色标志,因此我将给您一些有关加密的提示:

通常,在使用算法名称时,不必提供提供者名称。指定提供程序会降低代码的可移植性

最好使用标准化的填充模式,例如/pkcs5p,在Java中添加与PKCS7填充相同的内容。如果要使用当前填充模式,可以配置Bouncy Castle提供程序并指定/ZeroBytePadding。对于以零值字节结尾的纯文本,此填充模式无法正常工作

将IV存储在与键相同的类变量中。我知道这只是测试代码,但通常需要在两侧发送或建立IV。在两侧使用同一密钥的最常见方法是在密文前面加上IV

IV的大小取决于密码。AES的值始终为16,但您可能希望配置IV大小或使用Cipher.getBlockSize方法

如果您还需要真实性/完整性和针对oracle攻击的保护,请使用1.8加密后可用的GCM模式

您应该为每个加密使用一个新的、随机的IV,而不是只生成一次IV


您要求提供其他危险信号,因此我将给您一些有关加密的提示:

通常,在使用算法名称时,不必提供提供者名称。指定提供程序会降低代码的可移植性

最好使用标准化的填充模式,例如/pkcs5p,在Java中添加与PKCS7填充相同的内容。如果你愿意 要使用当前填充模式,可以配置Bouncy Castle提供程序并指定/ZeroBytePadding。对于以零值字节结尾的纯文本,此填充模式无法正常工作

将IV存储在与键相同的类变量中。我知道这只是测试代码,但通常需要在两侧发送或建立IV。在两侧使用同一密钥的最常见方法是在密文前面加上IV

IV的大小取决于密码。AES的值始终为16,但您可能希望配置IV大小或使用Cipher.getBlockSize方法

如果您还需要真实性/完整性和针对oracle攻击的保护,请使用1.8加密后可用的GCM模式

您应该为每个加密使用一个新的、随机的IV,而不是只生成一次IV


回答得好,但我认为第一段是多余的/不正确的,或者充其量是令人困惑的。谢谢你的回答!啊,我没有意识到这是我正在显示的字节[]的哈希代码。谢谢你指出这一点。回答得好,但我认为第一段是多余的/不正确的,或者充其量是令人困惑的。谢谢你的回答!啊,我没有意识到这是我正在显示的字节[]的哈希代码。感谢您指出out.GCM仅在Java 8之后才可用。静态IV是一个危险信号。谢谢这些,非常好的观点。除了第5点之外,我已经将所有这些添加到了我的代码中。我只将IV的生成移到encrypt方法中,并将其作为ciper.init方法中的附加参数传递。然后我使用cipher.getParameters在decrypt方法中检索它@ntoskrnl,这个更改是否修复了红旗?谢谢@ntoskrnl,我会将其更改为1.8。静电IV在哪里?GenerateInitializationVector方法在我看来很随机…@owlstead很公平,这可能只是一个测试。主要问题是IV重用。确保同一个IV在生产环境中不用于多个加密操作。@ntoskrnl啊,是的,现在我明白了,它是随机的,很像,我甚至没有注意到:GCM只在Java 8之后才可用。静态IV是一个危险信号。谢谢这些,非常好的观点。除了第5点之外,我已经将所有这些添加到了我的代码中。我只将IV的生成移到encrypt方法中,并将其作为ciper.init方法中的附加参数传递。然后我使用cipher.getParameters在decrypt方法中检索它@ntoskrnl,这个更改是否修复了红旗?谢谢@ntoskrnl,我会将其更改为1.8。静电IV在哪里?GenerateInitializationVector方法在我看来很随机…@owlstead很公平,这可能只是一个测试。主要问题是IV重用。确保同一个IV在生产环境中不用于多个加密操作。@ntoskrnl啊,是的,现在我明白了,它是随机的,就像,我甚至没有注意到:谢谢你的回答!不幸的是,我必须有一个编码文本数据的表示,这是一个糟糕的设计,我被告知必须保留,并且散列不够强大。某些字符串需要进行编码和存储以供以后使用,然后需要进一步解码。我真的不觉得有必要,但是嘿。将原始字节[]数据再次编码为hex/base64并存储此表示,而不是原始二进制数据,这会有用吗?或者这会转移问题吗?您有一个编码文本数据的表示:它是字节数组。如果愿意,您可以使用base64将其转换为字符串,但不能只调用字节数组上的toString。谢谢您的回答!不幸的是,我必须有一个编码文本数据的表示,这是一个糟糕的设计,我被告知必须保留,并且散列不够强大。某些字符串需要进行编码和存储以供以后使用,然后需要进一步解码。我真的不觉得有必要,但是嘿。将原始字节[]数据再次编码为hex/base64并存储此表示,而不是原始二进制数据,这会有用吗?或者这会转移问题吗?您有一个编码文本数据的表示:它是字节数组。如果愿意,可以使用base64将其转换为字符串,但不能只调用字节数组上的toString。