Java中的密码学

use*_*021 5 java size cryptography block

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

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

for(int i=0; i+block_size < bdata.length; i += block_size)
    cipher.encryptBlock(bdata, i, cdata, i);
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*amp 7

我强烈建议使用AES加密,它也附带JAVA SDK.看看:使用AES和Java技术,它将为您提供一些很好的例子.要阅读有关AES的更多信息,请参阅:高级加密标准 - 维基百科.

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

在这里看到这个问题,看看加密方案的不同之处:DES,Triple DES,AES,数据的河豚加密的比较

附录:

java中的AES可以完美地运行192和256位密钥,但您必须安装较新的JCE策略文件.看到这里这里.您还应该将文件放在JDK中,否则从IDE执行时它不会起作用.

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

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

以下是java中使用CBC/AES/PKCS5Padding和随机IV使用的一些安全AES使用的模板RandomSecure.

请注意,您需要密钥和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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 它使用"ECB"模式和"PKCS5Padding"填充机制(默认值).虽然PKCS5Padding很好,但ECB却没有.在Cipher.getInstance(String):Cipher`期间,您至少应该使用CBC随机IV:`"AES/CBC/PKCS5Padding"或GCM模式:`"AES/GCM/NoPadding". (5认同)

Phi*_*ice 5

我总是使用BouncyCastle

我还使用流式框架而不是您描述的for循环:它处理引发的问题.大多数情况下我使用它,因为当谈到加密(和线程)时,我很少相信自己的代码,我相信那些活着的人会吃掉它.这是我想要"gash"加密时使用的代码.即我没有特别的威胁模型,只想要"有点安全"的东西.

键的十六进制编码使它们更容易操作/存储等等.我使用"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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经删除了一些异常捕获以减少代码的大小,并将Strings.fromHex字符串转换回来byte[]