I'm trying to implement secure encryption of the files to be sent over insecure channel or stored in an insecure place. I use bouncy castle framework, my code is written in scala. I decided to use aes-256 (to be more specific - Rinjael with 256 bit block size, here is why). And it seems like I can use Rinjael with any (128|160|192|256) block length.
I cannot understand the whole process overview correctly. Here is one of good answers, in this question there is some useful code specific to bouncy castle. But both leaving some questions unanswered for me (questions below).
So this is how I understand the workflow:
For creating a block cipher instance I have to get an instance of padded block cipher with some output feedback:
// create an instance of the engine val engine = new RijndaelEngine(bitLength) // wrap engine with some feedback-blocking cipher mode engine val ofb = new OFBBlockCipher(engine , bitLength) // wrap this with some padded-blocking cipher mode val cipher = new PaddedBufferedBlockCipher(ofb, new PKCS7Padding())
Now I have to run
init()
on the cipher engine2.1. first generate a key, to do this the best solution suggested here was to use
Scrypt
to derive a secret from password instead of usingPBKDF2-HMAC-xxx
. In russian wikipedia article on Scrypt it is said that the recommended parameters for Scrypt are as follows:N = 16384, r = 8, p = 1
So I'we wrirtten this code to generate the password:SCrypt.generate(password.getBytes(encoding), salt, 16384, 8, 1, bitLength / 8)
2.2. This leads to that I need a salt. Salt should be an array of random bytes. Most answers here use 8 bytes. So I do
// helper method to get a bunch of random bytes def getRandomBytes(size: Int) = { val bytes = Array.ofDim[Byte](size) val rnd = new SecureRandom() rnd.nextBytes(bytes) bytes } // generate salt val salt = getRandomBytes(8)
2.3. For cipher to initialize we need an initialization vector (please take a look at my question (2) below).
val iv = getRandomBytes(bitLength / 8)
2.4. Now we are ready to initialize the cipher.
cipher.init(mode, params(password, salt, iv, bitLength))
Questions:
- What should be the size of salt? Why do most respondents here use
8
bytes, not more? - What should be the size of IV? Is it correct that it should be the same size as cipher block size? Is it preferred to be fetched from cipher like here:
cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
or to be just random as i did? - Is it correct that I need both the salt and IV or I can use just one of these? For example use random IV as a salt.
- And the main question: I have to pass salt and IV to the other side or else it would be not possible to decrypt the message. I need to somehow pass both over unencrypted channel. Is it secure to just add both before an encrypted message (as a header)?
Thanks in advance!