What is the simplest way to encrypt/ decrypt a byte array using BouncyCastle's block cipher?

走远了吗. 提交于 2019-12-13 02:31:31

问题


If I have a BlockCipher and a byte[] that I got from a String containing a secret message, what's the easiest way to get a byte[] of the message encrypted?

In the normal Java API, I could just do cipher.doFinal(secretMessage), but there doesn't seem to be anything like that here, it only processes blocks.

I know I can use a BufferedBlockCipher, but this still doesn't simplify things significantly. What's the easiest high-level way to use this cipher?


回答1:


OK, so using the lightweight API and counter mode, which is one of the easiest and modern modes you would get:

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");
    }
}

Counter mode does not require padding and is fully online, so you only have to call processBytes. For CBC mode you should look at PaddedBufferedBlockCipher. Still you would have slightly a tiny amount of buffer handling during decryption: before decryption you don't know the amount of padding that is present.

You could remove the IV code and the UTF-8 character decoding + exception handling, but you would be insecure and possibly incompatible. This code prefixes the IV to the ciphertext.




回答2:


BouncyCastle implements the "normal Java API" so you can use Cipher.doFinal(String.getBytes()) you just have to specify the Provider "BC" when getting the Cipher: Cipher.getInstance("YourTransformation", "BC")




回答3:


Use Bouncy Castle's CipherOutputStream. It's the closest thing to the Java API.

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();
}

Link to my answer to a similar and related question.



来源:https://stackoverflow.com/questions/30511903/what-is-the-simplest-way-to-encrypt-decrypt-a-byte-array-using-bouncycastles-b

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!