Java 中的密码学

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11707976/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 06:06:53  来源:igfitidea点击:

Cryptography in Java

javacryptographysizeblock

提问by user568021

I'm making an app that encrypts some files. I want to use gnu's cryptix library. It says it is no longer developed since 2005, but I guess it has everything I need... should I use something else?

我正在制作一个加密一些文件的应用程序。我想使用 gnu 的 cryptix 库。它说它自 2005 年以来不再开发,但我想它拥有我需要的一切......我应该使用其他东西吗?

And I have a question about encrypting a single file. Right now I do it with a loop like this:

我有一个关于加密单个文件的问题。现在我用这样的循环来做:

for(int i=0; i+block_size < bdata.length; i += block_size)
    cipher.encryptBlock(bdata, i, cdata, i);

So my question is how to encrypt the last block that may not have the same size as the block_size. I was thinking maybe a should add some extra data to the last block, but than I don't know how to decrypt that...

所以我的问题是如何加密最后一个可能与 block_size 不同的块。我在想也许应该在最后一个块中添加一些额外的数据,但我不知道如何解密......

回答by David Kroukamp

I would strongly suggest using AES encryption and it too comes with the JAVA SDK. Have a look at: Using AES with Java Technologywhich will give you some great example. To read up more on AES see: Advanced Encryption Standard - Wikipedia.

我强烈建议使用 AES 加密,它也随 JAVA SDK 一起提供。看一看:将 AES 与 Java 技术结合使用,这将为您提供一些很好的示例。要阅读有关 AES 的更多信息,请参阅:高级加密标准 - 维基百科

Never use your own encryption scheme or an older form of an encryption scheme. AES has been tried and tested by people with far greater knowledge in that field then us, so you know it will work. Where as with your own or an old encryption scheme we might miss a fatal loop hole that will leave our data open to attacks.

切勿使用您自己的加密方案或旧形式的加密方案。AES 已经由在该领域拥有更多知识的人进行了尝试和测试,所以您知道它会起作用。与您自己的或旧的加密方案一样,我们可能会错过一个致命的漏洞,这将使我们的数据容易受到攻击。

See this question here to see the difference in the encryption schemes: Comparison of DES, Triple DES, AES, blowfish encryption for data

在此处查看此问题以了解加密方案的差异:比较 DES、Triple DES、AES、blowfish 加密数据

Addendum:

附录:

AES in java will work flawlessly for 192 and 256bit keys but you will have to install the newer JCE Policy Files. See hereand here. You should also place the files in your JDK or else it wont work when executed from your IDE.

Java 中的 AES 可以完美地用于 192 位和 256 位密钥,但您必须安装较新的 JCE 策略文件。请参阅此处此处。您还应该将文件放在 JDK 中,否则从 IDE 执行时它将无法工作。

Note: Make sure you download the correct JCE policy files, depending on your Java version i.e 1.4, 1.5 1.6 or 7.

注意:确保下载正确的 JCE 策略文件,具体取决于您的 Java 版本,即 1.4、1.5、1.6 或 7。

However if you use 128bit keys no need to install the newer JCE files.

但是,如果您使用 128 位密钥,则无需安装较新的 JCE 文件。

Here is a template of some secure AES usage in java it use CBC/AES/PKCS5Paddingand a random IV using RandomSecure.

这是 Java 中一些安全 AES 用法的模板,它使用CBC/AES/PKCS5Padding和使用RandomSecure.

Noteyou need both the key and IV for decrypting:

请注意,您需要密钥和 IV 才能解密:

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * This program generates a AES key, retrieves its raw bytes, and then
 * reinstantiates a AES key from the key bytes. The reinstantiated key is used
 * to initialize a AES cipher for encryption and decryption.
 */
public class AES {

    /**
     * Encrypt a sample message using AES in CBC mode with a random IV genrated
     * using SecyreRandom.
     *
     */
    public static void main(String[] args) {
        try {
            String message = "This string contains a secret message.";
            System.out.println("Plaintext: " + message + "\n");

            // generate a key
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            keygen.init(128);  // To use 256 bit keys, you need the "unlimited strength" encryption policy files from Sun.
            byte[] key = keygen.generateKey().getEncoded();
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

            // build the initialization vector (randomly).
            SecureRandom random = new SecureRandom();
            byte iv[] = new byte[16];//generate random 16 byte IV AES is always 16bytes
            random.nextBytes(iv);
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            // initialize the cipher for encrypt mode
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);

            System.out.println("Key: " + new String(key, "utf-8") + " This is important when decrypting");
            System.out.println("IV: " + new String(iv, "utf-8") + " This is important when decrypting");
            System.out.println();

            // encrypt the message
            byte[] encrypted = cipher.doFinal(message.getBytes());
            System.out.println("Ciphertext: " + asHex(encrypted) + "\n");

            // reinitialize the cipher for decryption
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);

            // decrypt the message
            byte[] decrypted = cipher.doFinal(encrypted);
            System.out.println("Plaintext: " + new String(decrypted) + "\n");
        } catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Turns array of bytes into string
     *
     * @param buf   Array of bytes to convert to hex string
     * @return  Generated hex string
     */
    public static String asHex(byte buf[]) {
        StringBuilder strbuf = new StringBuilder(buf.length * 2);
        int i;
        for (i = 0; i < buf.length; i++) {
            if (((int) buf[i] & 0xff) < 0x10) {
                strbuf.append("0");
            }
            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
        }
        return strbuf.toString();
    }
}

回答by Phil Rice

I always use BouncyCastle

我总是使用BouncyCastle

I also use the streaming framework instead of the for loop you were describing: it deals with the issue raised. Mostly I use that because when it comes to cryptography (and threading) I rarely trust my own code, I trust the people that live eat and breath it. Here is the code I use when I want "gash" cryptography. i.e. I have no particular threat model, and just want something "a little secure".

我还使用流框架而不是您描述的 for 循环:它处理提出的问题。我主要使用它是因为当涉及到密码学(和线程)时,我很少相信我自己的代码,我相信活着的人吃和呼吸它。这是我想要“gash”加密时使用的代码。即我没有特定的威胁模型,只是想要一些“有点安全”的东西。

The hex encoding of the keys makes them much easier to manipulate / store and so on. I use "makeKey" to ... well ... make a key, then I can use the key in the encrypt and decrypt methods. You can obviously go back to using byte[]instead of hex strings for the keys.

密钥的十六进制编码使它们更容易操作/存储等。我使用“makeKey”来......好吧......制作一个密钥,然后我可以在加密和解密方法中使用该密钥。您显然可以重新使用byte[]而不是十六进制字符串作为键。

    private static boolean initialised;
    private static void init() {
      if (initialised)
        return;
      Security.addProvider(new BouncyCastleProvider());
      initialised = true;
    }
    public static String makeKey() {
        init();
        KeyGenerator generator = KeyGenerator.getInstance(algorithm, provider);
        generator.init(keySize);
        Key key = generator.generateKey();
        byte[] encoded = key.getEncoded();
        return Strings.toHex(encoded);
}

public static String aesDecrypt(String hexKey, String hexCoded) {
        init();
        SecretKeySpec key = new SecretKeySpec(Strings.fromHex(hexKey), algorithm);
        Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding", provider);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] codedBytes = Strings.fromHex(hexCoded);
        CipherInputStream inputStream = new CipherInputStream(new ByteArrayInputStream(codedBytes), cipher);
        byte[] bytes = getBytes(inputStream, 256);
        String result = new String(bytes, "UTF-8");
        return result;
}

public static String aesEncrypt(String hexKey, String input) {
        init();
        SecretKeySpec key = new SecretKeySpec(Strings.fromHex(hexKey), algorithm);

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(input.length());
        CipherOutputStream outputStream = new CipherOutputStream(byteArrayOutputStream, cipher);
        setText(outputStream, input);
        byte[] outputBytes = byteArrayOutputStream.toByteArray();
        String output = new String(Strings.toHex(outputBytes));
        return output;
}
public static void setText(OutputStream outputStream, String text, String encoding) {
    try {
        outputStream.write(text.getBytes(encoding));
        outputStream.flush();
    } finally {
            outputStream.close();
    }
}
public static byte[] getBytes(InputStream inputStream, int bufferSize) {
    try {
        List<ByteArrayAndLength> list = Lists.newList();
        while (true) {
            byte[] buffer = new byte[bufferSize];
            int count = inputStream.read(buffer);
            if (count == -1) {
                byte[] result = new byte[ByteArrayAndLength.length(list)];
                int index = 0;
                for (ByteArrayAndLength byteArrayAndLength : list) {
                    System.arraycopy(byteArrayAndLength.bytes, 0, result, index, byteArrayAndLength.length);
                    index += byteArrayAndLength.length;
                }
                assert index == result.length;
                return result;
            }
            list.add(new ByteArrayAndLength(buffer, count));
        }
    } finally {
            inputStream.close();
    }
}
    static class ByteArrayAndLength {
    byte[] bytes;
    int length;

    public ByteArrayAndLength(byte[] bytes, int length) {
        super();
        this.bytes = bytes;
        this.length = length;
    }

    static int length(List<ByteArrayAndLength> list) {
        int result = 0;
        for (ByteArrayAndLength byteArrayAndLength : list) {
            result += byteArrayAndLength.length;
        }
        return result;
    }
}

I've taken out some of the exception catching to reduce the size of the code, and Strings.fromHexturns the string back into a byte[]

我去掉了一些异常捕获以减少代码的大小,并将Strings.fromHex字符串变回byte[]

回答by Mark Bramnik

Maybe you should consider using a javax.cryptopackage. Here is an example of how to use Ciphers:

也许你应该考虑使用一个javax.crypto包。以下是如何使用密码的示例:

DES encryption

DES加密

Hope this helps

希望这可以帮助

回答by fvu

I would seriously think twice before going this route. The development of the software was halted because standard alternatives exist, and have a look at the mailing list, there's been no significant activity since 2009. In my book that means that the software is abandoned, and abandoned software means you're more or less on your own.

在走这条路之前,我会认真考虑再三。由于存在标准替代品,软件的开发停止了,看看邮件列表,自 2009 年以来没有任何重大活动。在我的书中,这意味着该软件已被放弃,而被放弃的软件意味着您或多或少靠你自己。

Have a look here on SO, there are several questions and answers that may help you like this one. An at first sight interesting package that could simplify things for you (but still using the standard JCE infrastructure) is jasypt

看看这里的 SO,有几个问题和答案可能会帮助你喜欢这个jasypt一个乍一看很有趣的包,它可以为您简化事情(但仍然使用标准的 JCE 基础架构)