Loading ...
Sorry, an error occurred while loading the content.

Re: patch for encryption, strengthened key with salt.

Expand Messages
  • Mosh
    ... Yes, the ascii conversion can be avoided. I wanted to do the same. The reason ascii was used, was to be make keys compatible with string passwords of vim.
    Message 1 of 9 , Jun 2, 2010
      On Wed, Jun 2, 2010 at 1:52 PM, Bram Moolenaar <Bram@...> wrote:
      > Mohsin wrote:
      >> >> >> Attaching patch7.zip encryption Key_strengthening
      >> >> >>
      >> >> >> Changes:
      >> >> >> 1 added 8 bytes salt to file header,
      >> >> >> 2. sha256_key takes password, salt, salt_len  (salt is binary, not
      >> >> >> null terminated)
      >> >> >> 3. sha256_seed also generates salt along with iv.
      >> >> >> 4. bf_key_init takes password and salt.
      >> >> >> 5. bf_key_init converts ascii hex key[64] to binary key[32] (this
      >> >> >> change is independent of the 1..4 above)
      >> >
      >> > Can we avoid the intermediate step with ascii hex?
      > No answer on this question?

      Yes, the ascii conversion can be avoided. I wanted to do the same.

      The reason ascii was used, was to be make keys compatible with string
      passwords of vim.

      Since binary keys can contain '\0' null bytes, some keys would look
      like empty password == ""
      and no encryption would take place. This will happen often (with
      probability 1/256).

      To handle null bytes case, you could track the key_length separately
      (or hardcode the len,
      and keep a bool to indicate no-password).

      >> >> >> Also attached is vc-proj.zip (contains dsp and dsw project files).
      >> >> >> The HG repository didn't have these files, so I copied them from older
      >> >> >> older source tree.
      >> >> >> Might be useful to others on this list using vc++ on windows to debug.
      >> >> >
      >> >> > Can you explain what this does, how it makes the encryption stronger,
      >> >> > and if there is any impact on performance?  A link to a page that
      >> >> > explains it would be helpful.
      >> >>
      >> >> Here is the doc for salting, this can be added to the code:
      >> >>
      >> >> http://en.wikipedia.org/wiki/Key_strengthening
      >> >>
      >> >> Its summary is:
      >> >>
      >> >> The salt is a random number concatenated to the password to create a
      >> >> one time key.
      >> >>
      >> >> This prevents someone from precomputing keys (dictionary),
      >> >> because the salt is a different in each file.
      > I thought we already did that, only it's called "seed" in fileio.c

      That 'seed' in fileio is the IV (initialization vector),
      we should rename this variable to crypt_initialization_vector or something
      to be clear.

      The doc on IV is here: http://en.wikipedia.org/wiki/Initialization_vector

      >> > We already had the seed for this.  The wiki page actually describes a
      >> > method to feed the password through an algorithm that costs time, to
      >> > increase the time needed for a brute force attack.
      >> >
      >> > Instead of using both a seed and a salt, can we use one?  Hmm, I suppose
      >> > using two different strings adds to the strength.
      >> >
      >> >> The key computation is slowed down for offline attack;
      >> >> this prevents someone with the file+salt but not the password,
      >> >> from using brute force -
      >> >> That is they feed all passwords 'a', 'aa', ... but they should NOT
      >> >> have enough time to to try all 8 char passwords.
      >> >>
      >> >> ===
      >> >> Other docs that relate to this code:
      >> >>
      >> >> http://en.wikipedia.org/wiki/Blowfish_%28cipher%29
      >> >> http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation
      >> >
      >> > OK.  I'm not sure if we really need this for Vim, or perhaps in limited
      >> > form.  I would like this to work well on slow machines.  One important
      >> > difference from many other applications of cyphers is that Vim has no
      >> > check if the correct key is used.  The attacker has to know something
      >> > that must exist in the file, literally.  That also makes attacks a lot
      >> > slower.
      >> Yes. key_strengthening is not really important.
      >> I was just going by the standard literature.
      > I did some performance measurements.  Crypting a 30 Mbyte file just
      > takes a couple of seconds, let's say 10 Mbyte/sec.  If 1 Kbyte is
      > sufficient to check for expected text, 10'000 passwords can be tried per
      > second.  If we do 1000 rounds before starting on the text, we reduce
      > this to 5'000 passwords.  Does not really help much, right?
      > It would make a difference if there was a check for correct password,
      > e.g., with a few bytes at the start of the file.  But we don't have that
      > (intentionally).
      > Well, suppose the attacker knows something about the file, e.g., that it
      > starts with the name of the company or some header, then perhaps the
      > check can be done in 20 bytes or so.  Going to 1020 bytes is then a slow
      > down of a factor 1000 / 20 = 50.  That helps, but is this significant?

      Good point,

      note: Instead of looking for a company header in the decrypted block,
      people would look for _all_ ascii chars, i.e. if all high bits are 0
      in the decrypted text, then
      it is an ascii file and the key is correct with high probability

      >> > You use a strengthen_key value of 1000.  Why not 100 or 10000?
      >> > Perhaps we should put this value in the header as well, so that we can
      >> > change it over time?
      >> Any value of similar magnitude would do; the wiki suggests 65000;
      >> Reason: Time to compute one key is feasible for a user, but
      >> time to compute for whole dictionary + salt is infeasible.
      > Let's assume an old computer is 100 times slower than mine, thus instead
      > of 10 Mbyte/sec it does 100 Kbyte/sec. 65000 is then about a second.
      > A small price to pay (keep in mind that you have to type the password,
      > this will take a few seconds).  Perhaps we can use a value of 10000.
      >> > About the code: Please, please use the Vim formatting style.
      >> I thought I did that, except that I used spaces instead of tabs.
      > In some parts spaces in expressions were missing.
      >> > Another question: I would like to also encrypt the swapfile.  The
      >> > problem is that this is written and read in blocks of 4Kbyte or more.
      >> > There is no predefined order in which to perform the I/O, thus each
      >> > block must be crypted and decrypted by itself.
      >> This can be done:
      >>   a  Use any key (password with/without salt) to init blowfish;
      >>       and then call the blowfish to encrypt/decrypt blocks
      >>      of 8 bytes of swap file.
      >>       for i = 0 ; i < 4k/8 ; i+=8
      >>          block[i*8..i*8+8] ^= bf_encrypt(integer i);  // blowfish in CTR mode.
      >>      CTR diagram is in here
      >>      http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation
      >> >
      >> > What we could do is generate a seed or salt for each block, and store
      >> > that in the pointer block that refers to the data block.  We can
      >> > generate a new seed each time a block is written.  The pointer block
      >> > must then also be written later.  We do need to restart the encryption
      >> > for each block though.  I suppose there is no safe way to store the
      >> > state of the crypter in the file so that we can continue from there.
      >> If you keep a constant salt + password, you get a session key,
      >> use that in bf_init, then you can just use the file offset:
      >>    block[i] ^= bf_encrypt(offset)
      >> So any 8byte block can be encrypted/decrypted independently.
      > The crypt_encode() and crypt_decode() functions can now be used, right?
      > I moved some code around to make it faster (avoid calling a function for
      > every byte).

      Yes, I just had a look at crypt_encode(), it looks good. It can be used.
      Just remember call bf_ofb_init(iv, iv_len) to set it up, before using
      it on different files.

      hope I covered all your questions.

      >> > Another problem is when changing the key: we would need to read back all
      >> > blocks with the old key and crypt them with the new key.
      >> Yes. Or keep a separate session key in memory for swap files.
      >> This would make it impossible to recover swap files in case of crash.
      >> Or keep the hashmap: swap -> key, and switch tp new
      >> keys lazily - during write.
      > Hmm, using a seed key, generated new for each swap file, plus the
      > password, plus the byte offset in the file.  Sounds like this would
      > work.  I suppose this does not make it easier for an attacker to guess
      > the key.
      >> About random number usage:
      >> The random number for IV is generated using sha(loop time),
      >> this is good enough in practice. For better randomness,
      >> vim could measure the time deltas between user keystrokes (like pgp).
      > I already changed it to use micro seconds instead of time().  A second
      > timestamp is too predictable.
      > - Bram
      > --
      > hundred-and-one symptoms of being an internet addict:
      > 141. You'd rather go to http://www.weather.com/ than look out your window.
      >  /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net   \\\
      > ///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
      > \\\        download, build and distribute -- http://www.A-A-P.org        ///
      >  \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

      You received this message from the "vim_dev" maillist.
      Do not top-post! Type your reply below the text you are replying to.
      For more information, visit http://www.vim.org/maillist.php
    Your message has been successfully submitted and would be delivered to recipients shortly.