Java 使用BouncyCastle';加密/解密字节数组的最简单方法是什么;什么是分组密码?

Java 使用BouncyCastle';加密/解密字节数组的最简单方法是什么;什么是分组密码?,java,encryption,bouncycastle,Java,Encryption,Bouncycastle,如果我有一个BlockCipher和一个byte[]是从包含秘密消息的String中获得的,那么获得加密消息的byte[]最简单的方法是什么 在普通的JavaAPI中,我可以只执行cipher.doFinal(secretMessage),但这里似乎没有类似的操作,它只处理块 我知道我可以使用BufferedBlockCipher,但这仍然不能显著简化事情。使用此密码最简单的高级方法是什么?BouncyCastle实现了“普通Java API”,因此您可以使用cipher.doFinal(Str

如果我有一个
BlockCipher
和一个
byte[]
是从包含秘密消息的
String
中获得的,那么获得加密消息的
byte[]
最简单的方法是什么

在普通的JavaAPI中,我可以只执行
cipher.doFinal(secretMessage)
,但这里似乎没有类似的操作,它只处理块


我知道我可以使用
BufferedBlockCipher
,但这仍然不能显著简化事情。使用此密码最简单的高级方法是什么?

BouncyCastle实现了“普通Java API”,因此您可以使用
cipher.doFinal(String.getBytes())
获取密码时只需指定提供程序“BC”:
cipher.getInstance(“YourTransformation”,“BC”)
使用BouncyCastle的。它是最接近JavaAPI的东西

static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();

public static void main(String[] args) throws Exception {
    KeyGenerator kg = KeyGenerator.getInstance("Threefish-1024", PROVIDER);
    kg.init(1024);
    KeyParameter key = new KeyParameter(kg.generateKey().getEncoded());
    byte[] tweak = new byte[16];
    TweakableBlockCipherParameters params = new TweakableBlockCipherParameters(key, tweak);

    byte[] plaintext = "Hi! I'm cat!".getBytes();
    byte[] ciphertext = encrypt(params, plaintext);
    System.out.println(new String(decrypt(params, ciphertext)));
    // prints "Hi! I'm cat!"
}

static byte[] encrypt(TweakableBlockCipherParameters params, byte[] plaintext) throws Exception {
    return encryptOrDecrypt(true, params, plaintext);
}

static byte[] decrypt(TweakableBlockCipherParameters params, byte[] ciphertext) throws Exception {
    return encryptOrDecrypt(false, params, ciphertext);
}

static byte[] encryptOrDecrypt(boolean encrypt, TweakableBlockCipherParameters params, byte[] bytes) throws Exception {
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
            new CBCBlockCipher(
                    new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024)), new PKCS7Padding());
    cipher.init(encrypt, params);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    CipherOutputStream cos = new CipherOutputStream(baos, cipher);
    cos.write(bytes);
    // calling CipherOutputStream.close is mandatory
    // it acts like Cipher.doFinal
    cos.close();
    return baos.toByteArray();
}

好的,那么使用轻量级API和计数器模式,这是最简单、最现代的模式之一:

public class BouncyEncrypt {

    private static final int IV_SIZE = 16;

    public static void main(String[] args) throws Exception {
        // key should really consist of 16 random bytes
        byte[] keyData = new byte[256 / Byte.SIZE];
        KeyParameter key = new KeyParameter(keyData);

        byte[] ciphertext = encryptWithAES_CTR(key, "owlstead");
        System.out.println(decryptWithAES_CTR(key, ciphertext));
    }

    private static byte[] encryptWithAES_CTR(KeyParameter key, String in)
            throws IllegalArgumentException, UnsupportedEncodingException,
            DataLengthException {
        // iv should be unique for each encryption with the same key
        byte[] ivData = new byte[IV_SIZE];
        SecureRandom rng = new SecureRandom();
        rng.nextBytes(ivData);
        ParametersWithIV iv = new ParametersWithIV(key, ivData);

        SICBlockCipher aesCTR = new SICBlockCipher(new AESFastEngine());

        aesCTR.init(true, iv);
        byte[] plaintext = in.getBytes("UTF-8");
        byte[] ciphertext = new byte[ivData.length + plaintext.length];
        System.arraycopy(ivData, 0, ciphertext, 0, IV_SIZE);
        aesCTR.processBytes(plaintext, 0, plaintext.length, ciphertext, IV_SIZE);
        return ciphertext;
    }

    private static String decryptWithAES_CTR(KeyParameter key, byte[] ciphertext)
            throws IllegalArgumentException, UnsupportedEncodingException,
            DataLengthException {
        if (ciphertext.length < IV_SIZE) {
            throw new IllegalArgumentException("Ciphertext too short to contain IV");
        }

        ParametersWithIV iv = new ParametersWithIV(key, ciphertext, 0, IV_SIZE);

        SICBlockCipher aesCTR = new SICBlockCipher(new AESFastEngine());
        aesCTR.init(true, iv);
        byte[] plaintext = new byte[ciphertext.length - IV_SIZE];
        aesCTR.processBytes(ciphertext, IV_SIZE, plaintext.length, plaintext, 0);
        return new String(plaintext, "UTF-8");
    }
}
公共类弹跳加密{
专用静态最终int IV_尺寸=16;
公共静态void main(字符串[]args)引发异常{
//密钥实际上应该由16个随机字节组成
byte[]keyData=新字节[256/字节.SIZE];
KeyParameter key=新的KeyParameter(keyData);
byte[]ciphertext=encryptWithAES_CTR(密钥“owlstead”);
System.out.println(使用AES_CTR(密钥,密文)解密);
}
专用静态字节[]encryptWithAES\u CTR(键参数键,字符串输入)
抛出IllegalArgumentException、UnsupportedEncodingException、,
数据长度异常{
//对于使用相同密钥的每个加密,iv应该是唯一的
字节[]ivData=新字节[IV_大小];
SecureRandom rng=新的SecureRandom();
下一个字节(ivData);
参数swithiv=新参数swithiv(键,ivData);
SICBlockCipher aesCTR=新的SICBlockCipher(新的AESFastEngine());
aesCTR.init(真,iv);
字节[]明文=in.getBytes(“UTF-8”);
字节[]密文=新字节[ivData.length+明文.length];
System.arraycopy(ivData,0,密文,0,IV_大小);
aesCTR.processBytes(明文,0,明文.长度,密文,IV_大小);
返回密文;
}
使用AES_CTR(密钥参数密钥,字节[]密文)解密私有静态字符串
抛出IllegalArgumentException、UnsupportedEncodingException、,
数据长度异常{
if(密文长度
计数器模式不需要填充,并且完全在线,因此您只需调用
processBytes
。对于CBC模式,您应该查看
PaddedBufferedBlockCipher
。不过,在解密过程中,您仍然会有少量的缓冲区处理:在解密之前,您不知道存在的填充量


您可以删除IV代码和UTF-8字符解码+异常处理,但这将是不安全的,并且可能不兼容。这段代码将IV作为密文的前缀。

不幸的是,我不得不使用实际的块密码对象。我试着这样做,但我无法将TweakableBlockCipherParams与“普通Java API”一起使用。我实际上也发布了一个关于这一点的问题:不幸的是,我不能使用这个,我被BouncyCastle的实现卡住了(请参阅对其他答案的评论)。@codebreaker我已经更新了我的答案,请看。请参阅