문제

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 . I decided to use -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:

  1. 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())
    
  2. Now I have to run init() on the cipher engine

    2.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 using PBKDF2-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:

  1. What should be the size of salt? Why do most respondents here use 8 bytes, not more?
  2. 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?
  3. 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.
  4. 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!

도움이 되었습니까?

해결책

  1. I would go for 16 bytes salt length as suggested
  2. IV should be size of block size of cipher and should be random
  3. Yes you need both salt and IV because salt is used to generate key from password and IV is used to initialize block cipher
  4. Salt and IV are designed to be public. You can send them or store unencrypted, but you do not use any authentication mechanism so anyone can change IV or Salt during transport and you would not be able to detect it and decryption will get you something different. To prevent that you should use some AEAD mode and include IV and salt in authentication.

다른 팁

Is it secure? Sure, they will still need to guess the passphrase. Is it as secure? No, because you're giving the attacker information that they need to simplify the decryption process. If the only way that you can get the salt/password to the other side is via an unencrypted channel then something is better than nothing I suppose, but why can't you exchange this information using PKI/SSL?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top