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

Patch 7.4.399

Expand Messages
  • Bram Moolenaar
    Patch 7.4.399 Problem: Encryption implementation is messy. Blowfish encryption has a weakness. Solution: Refactor the encryption, store the state in an
    Message 1 of 8 , Aug 10, 2014
    • 0 Attachment
      Patch 7.4.399
      Problem: Encryption implementation is messy. Blowfish encryption has a
      weakness.
      Solution: Refactor the encryption, store the state in an allocated struct
      instead of using a save/restore mechanism. Introduce the
      "blowfish2" method, which does not have the weakness and encrypts
      the whole undo file. (largely by David Leadbeater)
      Files: runtime/doc/editing.txt, runtime/doc/options.txt, src/Makefile,
      src/blowfish.c, src/crypt.c, src/crypt_zip.c, src/ex_docmd.c,
      src/fileio.c, src/globals.h, src/main.c, src/memline.c,
      src/misc2.c, src/option.c, src/proto.h, src/proto/blowfish.pro,
      src/proto/crypt.pro, src/proto/crypt_zip.pro,
      src/proto/fileio.pro, src/proto/misc2.pro, src/structs.h,
      src/undo.c, src/testdir/test71.in, src/testdir/test71.ok,
      src/testdir/test71a.in, src/testdir/test72.in,
      src/testdir/test72.ok


      *** ../vim-7.4.398/runtime/doc/editing.txt 2013-08-10 13:24:53.000000000 +0200
      --- runtime/doc/editing.txt 2014-08-09 15:35:40.101354406 +0200
      ***************
      *** 1361,1371 ****
      {only available when compiled with the |+cryptv| feature} *E833*

      The text in the swap file and the undo file is also encrypted. *E843*

      Note: The text in memory is not encrypted. A system administrator may be able
      to see your text while you are editing it. When filtering text with
      ! ":!filter" or using ":w !command" the text is not encrypted, this may reveal
      ! it to others. The 'viminfo' file is not encrypted.

      WARNING: If you make a typo when entering the key and then write the file and
      exit, the text will be lost!
      --- 1362,1382 ----
      {only available when compiled with the |+cryptv| feature} *E833*

      The text in the swap file and the undo file is also encrypted. *E843*
      + However, this is done block-by-block and may reduce the time needed to crack a
      + password. You can disable the swap file, but then a crash will cause you to
      + lose your work. The undo file can be disabled without much disadvantage. >
      + :set noundofile
      + :noswapfile edit secrets

      Note: The text in memory is not encrypted. A system administrator may be able
      to see your text while you are editing it. When filtering text with
      ! ":!filter" or using ":w !command" the text is also not encrypted, this may
      ! reveal it to others. The 'viminfo' file is not encrypted.
      !
      ! You could do this to edit very secret text: >
      ! :set noundofile viminfo=
      ! :noswapfile edit secrets.txt
      ! Keep in mind that without a swap file you risk loosing your work in a crash.

      WARNING: If you make a typo when entering the key and then write the file and
      exit, the text will be lost!
      ***************
      *** 1392,1409 ****
      :set key=

      You can use the 'cryptmethod' option to select the type of encryption, use one
      ! of these two: >
      ! :setlocal cm=zip " weak method, backwards compatible
      ! :setlocal cm=blowfish " strong method
      Do this before writing the file. When reading an encrypted file it will be
      set automatically to the method used when that file was written. You can
      change 'cryptmethod' before writing that file to change the method.
      To set the default method, used for new files, use one of these in your
      |vimrc| file: >
      set cm=zip
      ! set cm=blowfish
      The message given for reading and writing a file will show "[crypted]" when
      ! using zip, "[blowfish]" when using blowfish.

      When writing an undo file, the same key and method will be used for the text
      in the undo file. |persistent-undo|.
      --- 1403,1427 ----
      :set key=

      You can use the 'cryptmethod' option to select the type of encryption, use one
      ! of these: >
      ! :setlocal cm=zip " weak method, backwards compatible
      ! :setlocal cm=blowfish " method with flaws
      ! :setlocal cm=blowfish2 " medium strong method
      !
      Do this before writing the file. When reading an encrypted file it will be
      set automatically to the method used when that file was written. You can
      change 'cryptmethod' before writing that file to change the method.
      +
      To set the default method, used for new files, use one of these in your
      |vimrc| file: >
      set cm=zip
      ! set cm=blowfish2
      ! Use the first one if you need to be compatible with Vim 7.2 and older. Using
      ! "blowfish2" is highly recommended if you can use a Vim version that supports
      ! it.
      !
      The message given for reading and writing a file will show "[crypted]" when
      ! using zip, "[blowfish]" when using blowfish, etc.

      When writing an undo file, the same key and method will be used for the text
      in the undo file. |persistent-undo|.
      ***************
      *** 1438,1444 ****
      0 string VimCrypt~ Vim encrypted file
      >9 string 01 - "zip" cryptmethod
      >9 string 02 - "blowfish" cryptmethod
      !

      Notes:
      - Encryption is not possible when doing conversion with 'charconvert'.
      --- 1456,1462 ----
      0 string VimCrypt~ Vim encrypted file
      >9 string 01 - "zip" cryptmethod
      >9 string 02 - "blowfish" cryptmethod
      ! >9 string 03 - "blowfish2" cryptmethod

      Notes:
      - Encryption is not possible when doing conversion with 'charconvert'.
      ***************
      *** 1462,1481 ****
      - Pkzip uses the same encryption as 'cryptmethod' "zip", and US Govt has no
      objection to its export. Pkzip's public file APPNOTE.TXT describes this
      algorithm in detail.
      - Vim originates from the Netherlands. That is where the sources come from.
      Thus the encryption code is not exported from the USA.

      ==============================================================================
      10. Timestamps *timestamp* *timestamps*

      ! Vim remembers the modification timestamp of a file when you begin editing it.
      ! This is used to avoid that you have two different versions of the same file
      ! (without you knowing this).
      !
      ! After a shell command is run (|:!cmd| |suspend| |:read!| |K|) timestamps are
      ! compared for all buffers in a window. Vim will run any associated
      ! |FileChangedShell| autocommands or display a warning for any files that have
      ! changed. In the GUI this happens when Vim regains input focus.

      *E321* *E462*
      If you want to automatically reload a file when it has been changed outside of
      --- 1480,1504 ----
      - Pkzip uses the same encryption as 'cryptmethod' "zip", and US Govt has no
      objection to its export. Pkzip's public file APPNOTE.TXT describes this
      algorithm in detail.
      + - The implmentation of 'cryptmethod' "blowfish" has a flaw. It is possible to
      + crack the first 64 bytes of a file and in some circumstances more of the
      + file. Use of it is not recommended, but it's still the strongest method
      + supported by Vim 7.3 and 7.4. The "zip" method is even weaker.
      - Vim originates from the Netherlands. That is where the sources come from.
      Thus the encryption code is not exported from the USA.

      ==============================================================================
      10. Timestamps *timestamp* *timestamps*

      ! Vim remembers the modification timestamp, mode and size of a file when you
      ! begin editing it. This is used to avoid that you have two different versions
      ! of the same file (without you knowing this).
      !
      ! After a shell command is run (|:!cmd| |suspend| |:read!| |K|) timestamps,
      ! file modes and file sizes are compared for all buffers in a window. Vim will
      ! run any associated |FileChangedShell| autocommands or display a warning for
      ! any files that have changed. In the GUI this happens when Vim regains input
      ! focus.

      *E321* *E462*
      If you want to automatically reload a file when it has been changed outside of
      *** ../vim-7.4.398/runtime/doc/options.txt 2014-08-06 14:52:05.039236174 +0200
      --- runtime/doc/options.txt 2014-08-09 15:36:48.165353916 +0200
      ***************
      *** 2229,2238 ****
      zip PkZip compatible method. A weak kind of encryption.
      Backwards compatible with Vim 7.2 and older.
      *blowfish*
      ! blowfish Blowfish method. Strong encryption. Requires Vim 7.3
      ! or later, files can NOT be read by Vim 7.2 and older.
      ! This adds a "seed" to the file, every time you write
      ! the file the encrypted bytes will be different.

      When reading an encrypted file 'cryptmethod' will be set automatically
      to the detected method of the file being read. Thus if you write it
      --- 2229,2246 ----
      zip PkZip compatible method. A weak kind of encryption.
      Backwards compatible with Vim 7.2 and older.
      *blowfish*
      ! blowfish Blowfish method. Medium strong encryption but it has
      ! an implementation flaw. Requires Vim 7.3 or later,
      ! files can NOT be read by Vim 7.2 and older. This adds
      ! a "seed" to the file, every time you write the file
      ! the encrypted bytes will be different.
      ! *blowfish2*
      ! blowfish2 Blowfish method. Medium strong encryption. Requires
      ! Vim 7.4.399 or later, files can NOT be read by Vim 7.3
      ! and older. This adds a "seed" to the file, every time
      ! you write the file the encrypted bytes will be
      ! different. The whole undo file is encrypted, not just
      ! the pieces of text.

      When reading an encrypted file 'cryptmethod' will be set automatically
      to the detected method of the file being read. Thus if you write it
      *** ../vim-7.4.398/src/Makefile 2014-05-22 14:54:22.850468654 +0200
      --- src/Makefile 2014-08-09 15:37:19.689353690 +0200
      ***************
      *** 1431,1436 ****
      --- 1431,1438 ----
      blowfish.c \
      buffer.c \
      charset.c \
      + crypt.c \
      + crypt_zip.c \
      diff.c \
      digraph.c \
      edit.c \
      ***************
      *** 1520,1525 ****
      --- 1522,1529 ----
      objects/buffer.o \
      objects/blowfish.o \
      objects/charset.o \
      + objects/crypt.o \
      + objects/crypt_zip.o \
      objects/diff.o \
      objects/digraph.o \
      objects/edit.o \
      ***************
      *** 1589,1594 ****
      --- 1593,1600 ----
      blowfish.pro \
      buffer.pro \
      charset.pro \
      + crypt.pro \
      + crypt_zip.pro \
      diff.pro \
      digraph.pro \
      edit.pro \
      ***************
      *** 1753,1762 ****
      languages:
      @if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
      cd $(PODIR); \
      ! CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix); \
      fi
      -@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
      ! cd $(PODIR); CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) converted; \
      fi

      # Update the *.po files for changes in the sources. Only run manually.
      --- 1759,1769 ----
      languages:
      @if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
      cd $(PODIR); \
      ! CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix); \
      fi
      -@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
      ! cd $(PODIR); \
      ! CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) converted; \
      fi

      # Update the *.po files for changes in the sources. Only run manually.
      ***************
      *** 1883,1890 ****
      --- 1890,1903 ----
      # Run individual test, assuming that Vim was already compiled.
      test1 test2 test3 test4 test5 test6 test7 test8 test9 \
      test_autoformat_join \
      + test_breakindent \
      + test_changelist \
      test_eval \
      + test_insertcount \
      + test_listlbr \
      + test_listlbr_utf8 \
      test_options \
      + test_qf_title \
      test10 test11 test12 test13 test14 test15 test16 test17 test18 test19 \
      test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \
      test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 \
      ***************
      *** 2506,2511 ****
      --- 2519,2530 ----
      objects/charset.o: charset.c
      $(CCC) -o $@ charset.c

      + objects/crypt.o: crypt.c
      + $(CCC) -o $@ crypt.c
      +
      + objects/crypt_zip.o: crypt_zip.c
      + $(CCC) -o $@ crypt_zip.c
      +
      objects/diff.o: diff.c
      $(CCC) -o $@ diff.c

      ***************
      *** 2855,2860 ****
      --- 2874,2887 ----
      ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
      gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
      arabic.h
      + objects/crypt.o: crypt.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
      + ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
      + gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
      + arabic.h
      + objects/crypt_zip.o: crypt_zip.c vim.h auto/config.h feature.h os_unix.h \
      + auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
      + regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
      + globals.h farsi.h arabic.h
      objects/diff.o: diff.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
      ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
      gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
      *** ../vim-7.4.398/src/blowfish.c 2014-02-11 15:23:27.930123631 +0100
      --- src/blowfish.c 2014-08-09 15:31:32.493356185 +0200
      ***************
      *** 9,25 ****
      * Blowfish encryption for Vim; in Blowfish cipher feedback mode.
      * Contributed by Mohsin Ahmed, http://www.cs.albany.edu/~mosh
      * Based on http://www.schneier.com/blowfish.html by Bruce Schneier.
      */

      #include "vim.h"

      ! #if defined(FEAT_CRYPT)

      #define ARRAY_LENGTH(A) (sizeof(A)/sizeof(A[0]))

      #define BF_BLOCK 8
      #define BF_BLOCK_MASK 7
      ! #define BF_CFB_LEN (8*(BF_BLOCK))

      typedef union {
      UINT32_T ul[2];
      --- 9,33 ----
      * Blowfish encryption for Vim; in Blowfish cipher feedback mode.
      * Contributed by Mohsin Ahmed, http://www.cs.albany.edu/~mosh
      * Based on http://www.schneier.com/blowfish.html by Bruce Schneier.
      + *
      + * There are two variants:
      + * - The old one "blowfish" has a flaw which makes it much easier to crack the
      + * key. To see this, make a text file with one line of 1000 "x" characters
      + * and write it encrypted. Use "xxd" to inspect the bytes in the file. You
      + * will see that a block of 8 bytes repeats 8 times.
      + * - The new one "blowfish2" is better. It uses an 8 byte CFB to avoid the
      + * repeats.
      */

      #include "vim.h"

      ! #if defined(FEAT_CRYPT) || defined(PROTO)

      #define ARRAY_LENGTH(A) (sizeof(A)/sizeof(A[0]))

      #define BF_BLOCK 8
      #define BF_BLOCK_MASK 7
      ! #define BF_MAX_CFB_LEN (8 * BF_BLOCK)

      typedef union {
      UINT32_T ul[2];
      ***************
      *** 37,50 ****
      # endif
      #endif

      ! static void bf_e_block __ARGS((UINT32_T *p_xl, UINT32_T *p_xr));
      ! static void bf_e_cblock __ARGS((char_u *block));
      ! static int bf_check_tables __ARGS((UINT32_T a_ipa[18], UINT32_T a_sbi[4][256], UINT32_T val));
      static int bf_self_test __ARGS((void));

      /* Blowfish code */
      ! static UINT32_T pax[18];
      ! static UINT32_T ipa[18] = {
      0x243f6a88u, 0x85a308d3u, 0x13198a2eu,
      0x03707344u, 0xa4093822u, 0x299f31d0u,
      0x082efa98u, 0xec4e6c89u, 0x452821e6u,
      --- 45,70 ----
      # endif
      #endif

      ! /* The state of encryption, referenced by cryptstate_T. */
      ! typedef struct {
      ! UINT32_T pax[18]; /* P-array */
      ! UINT32_T sbx[4][256]; /* S-boxes */
      ! int randbyte_offset;
      ! int update_offset;
      ! char_u cfb_buffer[BF_MAX_CFB_LEN]; /* up to 64 bytes used */
      ! int cfb_len; /* size of cfb_buffer actually used */
      ! } bf_state_T;
      !
      !
      ! static void bf_e_block __ARGS((bf_state_T *state, UINT32_T *p_xl, UINT32_T *p_xr));
      ! static void bf_e_cblock __ARGS((bf_state_T *state, char_u *block));
      ! static int bf_check_tables __ARGS((UINT32_T pax[18], UINT32_T sbx[4][256], UINT32_T val));
      static int bf_self_test __ARGS((void));
      + static void bf_key_init __ARGS((bf_state_T *state, char_u *password, char_u *salt, int salt_len));
      + static void bf_cfb_init __ARGS((bf_state_T *state, char_u *seed, int seed_len));

      /* Blowfish code */
      ! static UINT32_T pax_init[18] = {
      0x243f6a88u, 0x85a308d3u, 0x13198a2eu,
      0x03707344u, 0xa4093822u, 0x299f31d0u,
      0x082efa98u, 0xec4e6c89u, 0x452821e6u,
      ***************
      *** 53,60 ****
      0xb5470917u, 0x9216d5d9u, 0x8979fb1bu
      };

      ! static UINT32_T sbx[4][256];
      ! static UINT32_T sbi[4][256] = {
      {0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u,
      0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u,
      0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u,
      --- 73,79 ----
      0xb5470917u, 0x9216d5d9u, 0x8979fb1bu
      };

      ! static UINT32_T sbx_init[4][256] = {
      {0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u,
      0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u,
      0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u,
      ***************
      *** 314,346 ****
      }
      };

      -
      #define F1(i) \
      ! xl ^= pax[i]; \
      ! xr ^= ((sbx[0][xl >> 24] + \
      ! sbx[1][(xl & 0xFF0000) >> 16]) ^ \
      ! sbx[2][(xl & 0xFF00) >> 8]) + \
      ! sbx[3][xl & 0xFF];

      #define F2(i) \
      ! xr ^= pax[i]; \
      ! xl ^= ((sbx[0][xr >> 24] + \
      ! sbx[1][(xr & 0xFF0000) >> 16]) ^ \
      ! sbx[2][(xr & 0xFF00) >> 8]) + \
      ! sbx[3][xr & 0xFF];
      !

      static void
      ! bf_e_block(p_xl, p_xr)
      UINT32_T *p_xl;
      UINT32_T *p_xr;
      {
      ! UINT32_T temp, xl = *p_xl, xr = *p_xr;
      !
      ! F1(0) F2(1) F1(2) F2(3) F1(4) F2(5) F1(6) F2(7)
      ! F1(8) F2(9) F1(10) F2(11) F1(12) F2(13) F1(14) F2(15)
      ! xl ^= pax[16];
      ! xr ^= pax[17];
      temp = xl;
      xl = xr;
      xr = temp;
      --- 333,372 ----
      }
      };

      #define F1(i) \
      ! xl ^= bfs->pax[i]; \
      ! xr ^= ((bfs->sbx[0][xl >> 24] + \
      ! bfs->sbx[1][(xl & 0xFF0000) >> 16]) ^ \
      ! bfs->sbx[2][(xl & 0xFF00) >> 8]) + \
      ! bfs->sbx[3][xl & 0xFF];

      #define F2(i) \
      ! xr ^= bfs->pax[i]; \
      ! xl ^= ((bfs->sbx[0][xr >> 24] + \
      ! bfs->sbx[1][(xr & 0xFF0000) >> 16]) ^ \
      ! bfs->sbx[2][(xr & 0xFF00) >> 8]) + \
      ! bfs->sbx[3][xr & 0xFF];

      static void
      ! bf_e_block(bfs, p_xl, p_xr)
      ! bf_state_T *bfs;
      UINT32_T *p_xl;
      UINT32_T *p_xr;
      {
      ! UINT32_T temp;
      ! UINT32_T xl = *p_xl;
      ! UINT32_T xr = *p_xr;
      !
      ! F1(0) F2(1)
      ! F1(2) F2(3)
      ! F1(4) F2(5)
      ! F1(6) F2(7)
      ! F1(8) F2(9)
      ! F1(10) F2(11)
      ! F1(12) F2(13)
      ! F1(14) F2(15)
      ! xl ^= bfs->pax[16];
      ! xr ^= bfs->pax[17];
      temp = xl;
      xl = xr;
      xr = temp;
      ***************
      *** 348,369 ****
      *p_xr = xr;
      }

      - #if 0 /* not used */
      - static void
      - bf_d_block(p_xl, p_xr)
      - UINT32_T *p_xl;
      - UINT32_T *p_xr;
      - {
      - UINT32_T temp, xl = *p_xl, xr = *p_xr;
      - F1(17) F2(16) F1(15) F2(14) F1(13) F2(12) F1(11) F2(10)
      - F1(9) F2(8) F1(7) F2(6) F1(5) F2(4) F1(3) F2(2)
      - xl ^= pax[1];
      - xr ^= pax[0];
      - temp = xl; xl = xr; xr = temp;
      - *p_xl = xl; *p_xr = xr;
      - }
      - #endif
      -

      #ifdef WORDS_BIGENDIAN
      # define htonl2(x) \
      --- 374,379 ----
      ***************
      *** 374,380 ****
      #endif

      static void
      ! bf_e_cblock(block)
      char_u *block;
      {
      block8 bk;
      --- 384,391 ----
      #endif

      static void
      ! bf_e_cblock(bfs, block)
      ! bf_state_T *bfs;
      char_u *block;
      {
      block8 bk;
      ***************
      *** 382,416 ****
      memcpy(bk.uc, block, 8);
      htonl2(bk.ul[0]);
      htonl2(bk.ul[1]);
      ! bf_e_block(&bk.ul[0], &bk.ul[1]);
      htonl2(bk.ul[0]);
      htonl2(bk.ul[1]);
      memcpy(block, bk.uc, 8);
      }

      - #if 0 /* not used */
      - void
      - bf_d_cblock(block)
      - char_u *block;
      - {
      - block8 bk;
      - memcpy(bk.uc, block, 8);
      - htonl2(bk.ul[0]); htonl2(bk.ul[1]);
      - bf_d_block(&bk.ul[0], &bk.ul[1]);
      - htonl2(bk.ul[0]); htonl2(bk.ul[1]);
      - memcpy(block, bk.uc, 8);
      - }
      - #endif
      -
      /*
      * Initialize the crypt method using "password" as the encryption key and
      * "salt[salt_len]" as the salt.
      */
      ! void
      ! bf_key_init(password, salt, salt_len)
      ! char_u *password;
      ! char_u *salt;
      ! int salt_len;
      {
      int i, j, keypos = 0;
      unsigned u;
      --- 393,414 ----
      memcpy(bk.uc, block, 8);
      htonl2(bk.ul[0]);
      htonl2(bk.ul[1]);
      ! bf_e_block(bfs, &bk.ul[0], &bk.ul[1]);
      htonl2(bk.ul[0]);
      htonl2(bk.ul[1]);
      memcpy(block, bk.uc, 8);
      }

      /*
      * Initialize the crypt method using "password" as the encryption key and
      * "salt[salt_len]" as the salt.
      */
      ! static void
      ! bf_key_init(bfs, password, salt, salt_len)
      ! bf_state_T *bfs;
      ! char_u *password;
      ! char_u *salt;
      ! int salt_len;
      {
      int i, j, keypos = 0;
      unsigned u;
      ***************
      *** 418,424 ****
      char_u *key;
      int keylen;

      ! /* Process the key 1000 times.
      * See http://en.wikipedia.org/wiki/Key_strengthening. */
      key = sha256_key(password, salt, salt_len);
      for (i = 0; i < 1000; i++)
      --- 416,422 ----
      char_u *key;
      int keylen;

      ! /* Process the key 1001 times.
      * See http://en.wikipedia.org/wiki/Key_strengthening. */
      key = sha256_key(password, salt, salt_len);
      for (i = 0; i < 1000; i++)
      ***************
      *** 437,488 ****
      key[i] = u;
      }

      ! mch_memmove(sbx, sbi, 4 * 4 * 256);

      for (i = 0; i < 18; ++i)
      {
      val = 0;
      for (j = 0; j < 4; ++j)
      val = (val << 8) | key[keypos++ % keylen];
      ! pax[i] = ipa[i] ^ val;
      }

      data_l = data_r = 0;
      for (i = 0; i < 18; i += 2)
      {
      ! bf_e_block(&data_l, &data_r);
      ! pax[i + 0] = data_l;
      ! pax[i + 1] = data_r;
      }

      for (i = 0; i < 4; ++i)
      {
      for (j = 0; j < 256; j += 2)
      {
      ! bf_e_block(&data_l, &data_r);
      ! sbx[i][j + 0] = data_l;
      ! sbx[i][j + 1] = data_r;
      }
      }
      }

      /*
      ! * BF Self test for corrupted tables or instructions
      */
      static int
      ! bf_check_tables(a_ipa, a_sbi, val)
      ! UINT32_T a_ipa[18];
      ! UINT32_T a_sbi[4][256];
      UINT32_T val;
      {
      int i, j;
      UINT32_T c = 0;

      for (i = 0; i < 18; i++)
      ! c ^= a_ipa[i];
      for (i = 0; i < 4; i++)
      for (j = 0; j < 256; j++)
      ! c ^= a_sbi[i][j];
      return c == val;
      }

      --- 435,488 ----
      key[i] = u;
      }

      ! /* Use "key" to initialize the P-array ("pax") and S-boxes ("sbx") of
      ! * Blowfish. */
      ! mch_memmove(bfs->sbx, sbx_init, 4 * 4 * 256);

      for (i = 0; i < 18; ++i)
      {
      val = 0;
      for (j = 0; j < 4; ++j)
      val = (val << 8) | key[keypos++ % keylen];
      ! bfs->pax[i] = pax_init[i] ^ val;
      }

      data_l = data_r = 0;
      for (i = 0; i < 18; i += 2)
      {
      ! bf_e_block(bfs, &data_l, &data_r);
      ! bfs->pax[i + 0] = data_l;
      ! bfs->pax[i + 1] = data_r;
      }

      for (i = 0; i < 4; ++i)
      {
      for (j = 0; j < 256; j += 2)
      {
      ! bf_e_block(bfs, &data_l, &data_r);
      ! bfs->sbx[i][j + 0] = data_l;
      ! bfs->sbx[i][j + 1] = data_r;
      }
      }
      }

      /*
      ! * Blowfish self-test for corrupted tables or instructions.
      */
      static int
      ! bf_check_tables(pax, sbx, val)
      ! UINT32_T pax[18];
      ! UINT32_T sbx[4][256];
      UINT32_T val;
      {
      int i, j;
      UINT32_T c = 0;

      for (i = 0; i < 18; i++)
      ! c ^= pax[i];
      for (i = 0; i < 4; i++)
      for (j = 0; j < 256; j++)
      ! c ^= sbx[i][j];
      return c == val;
      }

      ***************
      *** 520,525 ****
      --- 520,529 ----
      int err = 0;
      block8 bk;
      UINT32_T ui = 0xffffffffUL;
      + bf_state_T state;
      +
      + vim_memset(&state, 0, sizeof(bf_state_T));
      + state.cfb_len = BF_MAX_CFB_LEN;

      /* We can't simply use sizeof(UINT32_T), it would generate a compiler
      * warning. */
      ***************
      *** 528,548 ****
      EMSG(_("E820: sizeof(uint32_t) != 4"));
      }

      ! if (!bf_check_tables(ipa, sbi, 0x6ffa520a))
      err++;

      bn = ARRAY_LENGTH(bf_test_data);
      for (i = 0; i < bn; i++)
      {
      ! bf_key_init((char_u *)(bf_test_data[i].password),
      bf_test_data[i].salt,
      (int)STRLEN(bf_test_data[i].salt));
      ! if (!bf_check_tables(pax, sbx, bf_test_data[i].keysum))
      err++;

      /* Don't modify bf_test_data[i].plaintxt, self test is idempotent. */
      memcpy(bk.uc, bf_test_data[i].plaintxt, 8);
      ! bf_e_cblock(bk.uc);
      if (memcmp(bk.uc, bf_test_data[i].cryptxt, 8) != 0)
      {
      if (err == 0 && memcmp(bk.uc, bf_test_data[i].badcryptxt, 8) == 0)
      --- 532,552 ----
      EMSG(_("E820: sizeof(uint32_t) != 4"));
      }

      ! if (!bf_check_tables(pax_init, sbx_init, 0x6ffa520a))
      err++;

      bn = ARRAY_LENGTH(bf_test_data);
      for (i = 0; i < bn; i++)
      {
      ! bf_key_init(&state, (char_u *)(bf_test_data[i].password),
      bf_test_data[i].salt,
      (int)STRLEN(bf_test_data[i].salt));
      ! if (!bf_check_tables(state.pax, state.sbx, bf_test_data[i].keysum))
      err++;

      /* Don't modify bf_test_data[i].plaintxt, self test is idempotent. */
      memcpy(bk.uc, bf_test_data[i].plaintxt, 8);
      ! bf_e_cblock(&state, bk.uc);
      if (memcmp(bk.uc, bf_test_data[i].cryptxt, 8) != 0)
      {
      if (err == 0 && memcmp(bk.uc, bf_test_data[i].badcryptxt, 8) == 0)
      ***************
      *** 554,596 ****
      return err > 0 ? FAIL : OK;
      }

      ! /* Cipher feedback mode. */
      ! static int randbyte_offset = 0;
      ! static int update_offset = 0;
      ! static char_u cfb_buffer[BF_CFB_LEN]; /* 64 bytes */

      /*
      ! * Initialize with seed "iv[iv_len]".
      */
      ! void
      ! bf_cfb_init(iv, iv_len)
      ! char_u *iv;
      ! int iv_len;
      {
      int i, mi;

      ! randbyte_offset = update_offset = 0;
      ! vim_memset(cfb_buffer, 0, BF_CFB_LEN);
      ! if (iv_len > 0)
      {
      ! mi = iv_len > BF_CFB_LEN ? iv_len : BF_CFB_LEN;
      for (i = 0; i < mi; i++)
      ! cfb_buffer[i % BF_CFB_LEN] ^= iv[i % iv_len];
      }
      }

      ! #define BF_CFB_UPDATE(c) { \
      ! cfb_buffer[update_offset] ^= (char_u)c; \
      ! if (++update_offset == BF_CFB_LEN) \
      ! update_offset = 0; \
      }

      ! #define BF_RANBYTE(t) { \
      ! if ((randbyte_offset & BF_BLOCK_MASK) == 0) \
      ! bf_e_cblock(&cfb_buffer[randbyte_offset]); \
      ! t = cfb_buffer[randbyte_offset]; \
      ! if (++randbyte_offset == BF_CFB_LEN) \
      ! randbyte_offset = 0; \
      }

      /*
      --- 558,600 ----
      return err > 0 ? FAIL : OK;
      }

      ! /*
      ! * CFB: Cipher Feedback Mode.
      ! */

      /*
      ! * Initialize with seed "seed[seed_len]".
      */
      ! static void
      ! bf_cfb_init(bfs, seed, seed_len)
      ! bf_state_T *bfs;
      ! char_u *seed;
      ! int seed_len;
      {
      int i, mi;

      ! bfs->randbyte_offset = bfs->update_offset = 0;
      ! vim_memset(bfs->cfb_buffer, 0, bfs->cfb_len);
      ! if (seed_len > 0)
      {
      ! mi = seed_len > bfs->cfb_len ? seed_len : bfs->cfb_len;
      for (i = 0; i < mi; i++)
      ! bfs->cfb_buffer[i % bfs->cfb_len] ^= seed[i % seed_len];
      }
      }

      ! #define BF_CFB_UPDATE(bfs, c) { \
      ! bfs->cfb_buffer[bfs->update_offset] ^= (char_u)c; \
      ! if (++bfs->update_offset == bfs->cfb_len) \
      ! bfs->update_offset = 0; \
      }

      ! #define BF_RANBYTE(bfs, t) { \
      ! if ((bfs->randbyte_offset & BF_BLOCK_MASK) == 0) \
      ! bf_e_cblock(bfs, &(bfs->cfb_buffer[bfs->randbyte_offset])); \
      ! t = bfs->cfb_buffer[bfs->randbyte_offset]; \
      ! if (++bfs->randbyte_offset == bfs->cfb_len) \
      ! bfs->randbyte_offset = 0; \
      }

      /*
      ***************
      *** 598,687 ****
      * "from" and "to" can be equal to encrypt in place.
      */
      void
      ! bf_crypt_encode(from, len, to)
      char_u *from;
      size_t len;
      char_u *to;
      {
      size_t i;
      int ztemp, t;

      for (i = 0; i < len; ++i)
      {
      ztemp = from[i];
      ! BF_RANBYTE(t);
      ! BF_CFB_UPDATE(ztemp);
      to[i] = t ^ ztemp;
      }
      }

      /*
      ! * Decrypt "ptr[len]" in place.
      */
      void
      ! bf_crypt_decode(ptr, len)
      ! char_u *ptr;
      ! long len;
      {
      ! char_u *p;
      int t;

      ! for (p = ptr; p < ptr + len; ++p)
      {
      ! BF_RANBYTE(t);
      ! *p ^= t;
      ! BF_CFB_UPDATE(*p);
      }
      }

      - /*
      - * Initialize the encryption keys and the random header according to
      - * the given password.
      - */
      void
      ! bf_crypt_init_keys(passwd)
      ! char_u *passwd; /* password string with which to modify keys */
      ! {
      ! char_u *p;
      !
      ! for (p = passwd; *p != NUL; ++p)
      ! {
      ! BF_CFB_UPDATE(*p);
      ! }
      ! }

      ! static int save_randbyte_offset;
      ! static int save_update_offset;
      ! static char_u save_cfb_buffer[BF_CFB_LEN];
      ! static UINT32_T save_pax[18];
      ! static UINT32_T save_sbx[4][256];
      !
      ! /*
      ! * Save the current crypt state. Can only be used once before
      ! * bf_crypt_restore().
      ! */
      ! void
      ! bf_crypt_save()
      ! {
      ! save_randbyte_offset = randbyte_offset;
      ! save_update_offset = update_offset;
      ! mch_memmove(save_cfb_buffer, cfb_buffer, BF_CFB_LEN);
      ! mch_memmove(save_pax, pax, 4 * 18);
      ! mch_memmove(save_sbx, sbx, 4 * 4 * 256);
      ! }

      ! /*
      ! * Restore the current crypt state. Can only be used after
      ! * bf_crypt_save().
      ! */
      ! void
      ! bf_crypt_restore()
      ! {
      ! randbyte_offset = save_randbyte_offset;
      ! update_offset = save_update_offset;
      ! mch_memmove(cfb_buffer, save_cfb_buffer, BF_CFB_LEN);
      ! mch_memmove(pax, save_pax, 4 * 18);
      ! mch_memmove(sbx, save_sbx, 4 * 4 * 256);
      }

      /*
      --- 602,670 ----
      * "from" and "to" can be equal to encrypt in place.
      */
      void
      ! crypt_blowfish_encode(state, from, len, to)
      ! cryptstate_T *state;
      char_u *from;
      size_t len;
      char_u *to;
      {
      + bf_state_T *bfs = state->method_state;
      size_t i;
      int ztemp, t;

      for (i = 0; i < len; ++i)
      {
      ztemp = from[i];
      ! BF_RANBYTE(bfs, t);
      ! BF_CFB_UPDATE(bfs, ztemp);
      to[i] = t ^ ztemp;
      }
      }

      /*
      ! * Decrypt "from[len]" into "to[len]".
      */
      void
      ! crypt_blowfish_decode(state, from, len, to)
      ! cryptstate_T *state;
      ! char_u *from;
      ! size_t len;
      ! char_u *to;
      {
      ! bf_state_T *bfs = state->method_state;
      ! size_t i;
      int t;

      ! for (i = 0; i < len; ++i)
      {
      ! BF_RANBYTE(bfs, t);
      ! to[i] = from[i] ^ t;
      ! BF_CFB_UPDATE(bfs, to[i]);
      }
      }

      void
      ! crypt_blowfish_init(state, key, salt, salt_len, seed, seed_len)
      ! cryptstate_T *state;
      ! char_u* key;
      ! char_u* salt;
      ! int salt_len;
      ! char_u* seed;
      ! int seed_len;
      ! {
      ! bf_state_T *bfs = (bf_state_T *)alloc_clear(sizeof(bf_state_T));
      !
      ! state->method_state = bfs;
      !
      ! /* "blowfish" uses a 64 byte buffer, causing it to repeat 8 byte groups 8
      ! * times. "blowfish2" uses a 8 byte buffer to avoid repeating. */
      ! bfs->cfb_len = state->method_nr == CRYPT_M_BF ? BF_MAX_CFB_LEN : BF_BLOCK;

      ! if (blowfish_self_test() == FAIL)
      ! return;

      ! bf_key_init(bfs, key, salt, salt_len);
      ! bf_cfb_init(bfs, seed, seed_len);
      }

      /*
      *** ../vim-7.4.398/src/crypt.c 2014-08-10 13:30:43.816787293 +0200
      --- src/crypt.c 2014-08-09 15:37:46.189353499 +0200
      ***************
      *** 0 ****
      --- 1,585 ----
      + /* vi:set ts=8 sts=4 sw=4:
      + *
      + * VIM - Vi IMproved by Bram Moolenaar
      + *
      + * Do ":help uganda" in Vim to read copying and usage conditions.
      + * Do ":help credits" in Vim to see a list of people who contributed.
      + * See README.txt for an overview of the Vim source code.
      + */
      +
      + /*
      + * crypt.c: Generic encryption support.
      + */
      + #include "vim.h"
      +
      + #if defined(FEAT_CRYPT) || defined(PROTO)
      + /*
      + * Optional encryption support.
      + * Mohsin Ahmed, mosh@..., 1998-09-24
      + * Based on zip/crypt sources.
      + * Refactored by David Leadbeater, 2014.
      + *
      + * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
      + * most countries. There are a few exceptions, but that still should not be a
      + * problem since this code was originally created in Europe and India.
      + *
      + * Blowfish addition originally made by Mohsin Ahmed,
      + * http://www.cs.albany.edu/~mosh 2010-03-14
      + * Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
      + * and sha256 by Christophe Devine.
      + */
      +
      + typedef struct {
      + char *name; /* encryption name as used in 'cryptmethod' */
      + char *magic; /* magic bytes stored in file header */
      + int salt_len; /* length of salt, or 0 when not using salt */
      + int seed_len; /* length of seed, or 0 when not using salt */
      + int works_inplace; /* encryption/decryption can be done in-place */
      + int whole_undofile; /* whole undo file is encrypted */
      +
      + /* Optional function pointer for a self-test. */
      + int (* self_test_fn)();
      +
      + /* Function pointer for initializing encryption/decription. */
      + void (* init_fn)(cryptstate_T *state, char_u *key,
      + char_u *salt, int salt_len, char_u *seed, int seed_len);
      +
      + /* Function pointers for encoding/decoding from one buffer into another.
      + * Optional, however, these or the _buffer ones should be configured. */
      + void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
      + char_u *to);
      + void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
      + char_u *to);
      +
      + /* Function pointers for encoding and decoding, can buffer data if needed.
      + * Optional (however, these or the above should be configured). */
      + long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
      + char_u **newptr);
      + long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
      + char_u **newptr);
      +
      + /* Function pointers for in-place encoding and decoding, used for
      + * crypt_*_inplace(). "from" and "to" arguments will be equal.
      + * These may be the same as decode_fn and encode_fn above, however an
      + * algorithm may implement them in a way that is not interchangeable with
      + * the crypt_(en|de)code() interface (for example because it wishes to add
      + * padding to files).
      + * This method is used for swap and undo files which have a rigid format.
      + */
      + void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
      + char_u *p2);
      + void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
      + char_u *p2);
      + } cryptmethod_T;
      +
      + /* index is method_nr of cryptstate_T, CRYPT_M_* */
      + static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
      + /* PK_Zip; very weak */
      + {
      + "zip",
      + "VimCrypt~01!",
      + 0,
      + 0,
      + TRUE,
      + FALSE,
      + NULL,
      + crypt_zip_init,
      + crypt_zip_encode, crypt_zip_decode,
      + NULL, NULL,
      + crypt_zip_encode, crypt_zip_decode,
      + },
      +
      + /* Blowfish/CFB + SHA-256 custom key derivation; implementation issues. */
      + {
      + "blowfish",
      + "VimCrypt~02!",
      + 8,
      + 8,
      + TRUE,
      + FALSE,
      + blowfish_self_test,
      + crypt_blowfish_init,
      + crypt_blowfish_encode, crypt_blowfish_decode,
      + NULL, NULL,
      + crypt_blowfish_encode, crypt_blowfish_decode,
      + },
      +
      + /* Blowfish/CFB + SHA-256 custom key derivation; fixed. */
      + {
      + "blowfish2",
      + "VimCrypt~03!",
      + 8,
      + 8,
      + TRUE,
      + TRUE,
      + blowfish_self_test,
      + crypt_blowfish_init,
      + crypt_blowfish_encode, crypt_blowfish_decode,
      + NULL, NULL,
      + crypt_blowfish_encode, crypt_blowfish_decode,
      + },
      + };
      +
      + #define CRYPT_MAGIC_LEN 12 /* cannot change */
      + static char crypt_magic_head[] = "VimCrypt~";
      +
      + /*
      + * Return int value for crypt method name.
      + * 0 for "zip", the old method. Also for any non-valid value.
      + * 1 for "blowfish".
      + * 2 for "blowfish2".
      + */
      + int
      + crypt_method_nr_from_name(name)
      + char_u *name;
      + {
      + int i;
      +
      + for (i = 0; i < CRYPT_M_COUNT; ++i)
      + if (STRCMP(name, cryptmethods[i].name) == 0)
      + return i;
      + return 0;
      + }
      +
      + /*
      + * Get the crypt method used for a file from "ptr[len]", the magic text at the
      + * start of the file.
      + * Returns -1 when no encryption used.
      + */
      + int
      + crypt_method_nr_from_magic(ptr, len)
      + char *ptr;
      + int len;
      + {
      + int i;
      +
      + if (len < CRYPT_MAGIC_LEN)
      + return -1;
      +
      + for (i = 0; i < CRYPT_M_COUNT; i++)
      + if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
      + return i;
      +
      + i = (int)STRLEN(crypt_magic_head);
      + if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
      + EMSG(_("E821: File is encrypted with unknown method"));
      +
      + return -1;
      + }
      +
      + /*
      + * Return TRUE if the crypt method for "method_nr" can be done in-place.
      + */
      + int
      + crypt_works_inplace(state)
      + cryptstate_T *state;
      + {
      + return cryptmethods[state->method_nr].works_inplace;
      + }
      +
      + /*
      + * Get the crypt method for buffer "buf" as a number.
      + */
      + int
      + crypt_get_method_nr(buf)
      + buf_T *buf;
      + {
      + return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
      + }
      +
      + /*
      + * Return TRUE when the buffer uses an encryption method that encrypts the
      + * whole undo file, not only the text.
      + */
      + int
      + crypt_whole_undofile(method_nr)
      + int method_nr;
      + {
      + return cryptmethods[method_nr].whole_undofile;
      + }
      +
      + /*
      + * Get crypt method specifc length of the file header in bytes.
      + */
      + int
      + crypt_get_header_len(method_nr)
      + int method_nr;
      + {
      + return CRYPT_MAGIC_LEN
      + + cryptmethods[method_nr].salt_len
      + + cryptmethods[method_nr].seed_len;
      + }
      +
      + /*
      + * Set the crypt method for buffer "buf" to "method_nr" using the int value as
      + * returned by crypt_method_nr_from_name().
      + */
      + void
      + crypt_set_cm_option(buf, method_nr)
      + buf_T *buf;
      + int method_nr;
      + {
      + free_string_option(buf->b_p_cm);
      + buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
      + }
      +
      + /*
      + * If the crypt method for the current buffer has a self-test, run it and
      + * return OK/FAIL.
      + */
      + int
      + crypt_self_test()
      + {
      + int method_nr = crypt_get_method_nr(curbuf);
      +
      + if (cryptmethods[method_nr].self_test_fn == NULL)
      + return OK;
      + return cryptmethods[method_nr].self_test_fn();
      + }
      +
      + /*
      + * Allocate a crypt state and initialize it.
      + */
      + cryptstate_T *
      + crypt_create(method_nr, key, salt, salt_len, seed, seed_len)
      + int method_nr;
      + char_u *key;
      + char_u *salt;
      + int salt_len;
      + char_u *seed;
      + int seed_len;
      + {
      + cryptstate_T *state = (cryptstate_T *)alloc((int)sizeof(cryptstate_T));
      +
      + state->method_nr = method_nr;
      + cryptmethods[method_nr].init_fn(state, key, salt, salt_len, seed, seed_len);
      + return state;
      + }
      +
      + /*
      + * Allocate a crypt state from a file header and initialize it.
      + * Assumes that header contains at least the number of bytes that
      + * crypt_get_header_len() returns for "method_nr".
      + */
      + cryptstate_T *
      + crypt_create_from_header(method_nr, key, header)
      + int method_nr;
      + char_u *key;
      + char_u *header;
      + {
      + char_u *salt = NULL;
      + char_u *seed = NULL;
      + int salt_len = cryptmethods[method_nr].salt_len;
      + int seed_len = cryptmethods[method_nr].seed_len;
      +
      + if (salt_len > 0)
      + salt = header + CRYPT_MAGIC_LEN;
      + if (seed_len > 0)
      + seed = header + CRYPT_MAGIC_LEN + salt_len;
      +
      + return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
      + }
      +
      + /*
      + * Read the crypt method specific header data from "fp".
      + * Return an allocated cryptstate_T or NULL on error.
      + */
      + cryptstate_T *
      + crypt_create_from_file(fp, key)
      + FILE *fp;
      + char_u *key;
      + {
      + int method_nr;
      + int header_len;
      + char magic_buffer[CRYPT_MAGIC_LEN];
      + char_u *buffer;
      + cryptstate_T *state;
      +
      + if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
      + return NULL;
      + method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
      + if (method_nr < 0)
      + return NULL;
      +
      + header_len = crypt_get_header_len(method_nr);
      + if ((buffer = alloc(header_len)) == NULL)
      + return NULL;
      + mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
      + if (header_len > CRYPT_MAGIC_LEN
      + && fread(buffer + CRYPT_MAGIC_LEN,
      + header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
      + {
      + vim_free(buffer);
      + return NULL;
      + }
      +
      + state = crypt_create_from_header(method_nr, key, buffer);
      + vim_free(buffer);
      + return state;
      + }
      +
      + /*
      + * Allocate a cryptstate_T for writing and initialize it with "key".
      + * Allocates and fills in the header and stores it in "header", setting
      + * "header_len". The header may include salt and seed, depending on
      + * cryptmethod. Caller must free header.
      + * Returns the state or NULL on failure.
      + */
      + cryptstate_T *
      + crypt_create_for_writing(method_nr, key, header, header_len)
      + int method_nr;
      + char_u *key;
      + char_u **header;
      + int *header_len;
      + {
      + int len = crypt_get_header_len(method_nr);
      + char_u *salt = NULL;
      + char_u *seed = NULL;
      + int salt_len = cryptmethods[method_nr].salt_len;
      + int seed_len = cryptmethods[method_nr].seed_len;
      + cryptstate_T *state;
      +
      + *header_len = len;
      + *header = alloc(len);
      + if (*header == NULL)
      + return NULL;
      +
      + mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
      + if (salt_len > 0 || seed_len > 0)
      + {
      + if (salt_len > 0)
      + salt = *header + CRYPT_MAGIC_LEN;
      + if (seed_len > 0)
      + seed = *header + CRYPT_MAGIC_LEN + salt_len;
      +
      + /* TODO: Should this be crypt method specific? (Probably not worth
      + * it). sha2_seed is pretty bad for large amounts of entropy, so make
      + * that into something which is suitable for anything. */
      + sha2_seed(salt, salt_len, seed, seed_len);
      + }
      +
      + state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
      + if (state == NULL)
      + {
      + vim_free(*header);
      + *header = NULL;
      + }
      + return state;
      + }
      +
      + /*
      + * Free the crypt state.
      + */
      + void
      + crypt_free_state(state)
      + cryptstate_T *state;
      + {
      + vim_free(state->method_state);
      + vim_free(state);
      + }
      +
      + /*
      + * Encode "from[len]" and store the result in a newly allocated buffer, which
      + * is stored in "newptr".
      + * Return number of bytes in "newptr", 0 for need more or -1 on error.
      + */
      + long
      + crypt_encode_alloc(state, from, len, newptr)
      + cryptstate_T *state;
      + char_u *from;
      + size_t len;
      + char_u **newptr;
      + {
      + cryptmethod_T *method = &cryptmethods[state->method_nr];
      +
      + if (method->encode_buffer_fn != NULL)
      + /* Has buffer function, pass through. */
      + return method->encode_buffer_fn(state, from, len, newptr);
      + if (len == 0)
      + /* Not buffering, just return EOF. */
      + return len;
      +
      + *newptr = alloc(len);
      + if (*newptr == NULL)
      + return -1;
      + method->encode_fn(state, from, len, *newptr);
      + return len;
      + }
      +
      + /*
      + * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
      + * is stored in "newptr".
      + * Return number of bytes in "newptr", 0 for need more or -1 on error.
      + */
      + long
      + crypt_decode_alloc(state, ptr, len, newptr)
      + cryptstate_T *state;
      + char_u *ptr;
      + long len;
      + char_u **newptr;
      + {
      + cryptmethod_T *method = &cryptmethods[state->method_nr];
      +
      + if (method->decode_buffer_fn != NULL)
      + /* Has buffer function, pass through. */
      + return method->decode_buffer_fn(state, ptr, len, newptr);
      +
      + if (len == 0)
      + /* Not buffering, just return EOF. */
      + return len;
      +
      + *newptr = alloc(len);
      + if (*newptr == NULL)
      + return -1;
      + method->decode_fn(state, ptr, len, *newptr);
      + return len;
      + }
      +
      + /*
      + * Encrypting "from[len]" into "to[len]".
      + */
      + void
      + crypt_encode(state, from, len, to)
      + cryptstate_T *state;
      + char_u *from;
      + size_t len;
      + char_u *to;
      + {
      + cryptmethods[state->method_nr].encode_fn(state, from, len, to);
      + }
      +
      + /*
      + * decrypting "from[len]" into "to[len]".
      + */
      + void
      + crypt_decode(state, from, len, to)
      + cryptstate_T *state;
      + char_u *from;
      + size_t len;
      + char_u *to;
      + {
      + cryptmethods[state->method_nr].decode_fn(state, from, len, to);
      + }
      +
      + /*
      + * Simple inplace encryption, modifies "buf[len]" in place.
      + */
      + void
      + crypt_encode_inplace(state, buf, len)
      + cryptstate_T *state;
      + char_u *buf;
      + size_t len;
      + {
      + cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len, buf);
      + }
      +
      + /*
      + * Simple inplace decryption, modifies "buf[len]" in place.
      + */
      + void
      + crypt_decode_inplace(state, buf, len)
      + cryptstate_T *state;
      + char_u *buf;
      + size_t len;
      + {
      + cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len, buf);
      + }
      +
      + /*
      + * Free an allocated crypt key. Clear the text to make sure it doesn't stay
      + * in memory anywhere.
      + */
      + void
      + crypt_free_key(key)
      + char_u *key;
      + {
      + char_u *p;
      +
      + if (key != NULL)
      + {
      + for (p = key; *p != NUL; ++p)
      + *p = 0;
      + vim_free(key);
      + }
      + }
      +
      + /*
      + * Ask the user for a crypt key.
      + * When "store" is TRUE, the new key is stored in the 'key' option, and the
      + * 'key' option value is returned: Don't free it.
      + * When "store" is FALSE, the typed key is returned in allocated memory.
      + * Returns NULL on failure.
      + */
      + char_u *
      + crypt_get_key(store, twice)
      + int store;
      + int twice; /* Ask for the key twice. */
      + {
      + char_u *p1, *p2 = NULL;
      + int round;
      +
      + for (round = 0; ; ++round)
      + {
      + cmdline_star = TRUE;
      + cmdline_row = msg_row;
      + p1 = getcmdline_prompt(NUL, round == 0
      + ? (char_u *)_("Enter encryption key: ")
      + : (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
      + NULL);
      + cmdline_star = FALSE;
      +
      + if (p1 == NULL)
      + break;
      +
      + if (round == twice)
      + {
      + if (p2 != NULL && STRCMP(p1, p2) != 0)
      + {
      + MSG(_("Keys don't match!"));
      + crypt_free_key(p1);
      + crypt_free_key(p2);
      + p2 = NULL;
      + round = -1; /* do it again */
      + continue;
      + }
      +
      + if (store)
      + {
      + set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
      + crypt_free_key(p1);
      + p1 = curbuf->b_p_key;
      + }
      + break;
      + }
      + p2 = p1;
      + }
      +
      + /* since the user typed this, no need to wait for return */
      + if (msg_didout)
      + msg_putchar('\n');
      + need_wait_return = FALSE;
      + msg_didout = FALSE;
      +
      + crypt_free_key(p2);
      + return p1;
      + }
      +
      +
      + /*
      + * Append a message to IObuff for the encryption/decryption method being used.
      + */
      + void
      + crypt_append_msg(buf)
      + buf_T *buf;
      + {
      + if (crypt_get_method_nr(buf) == 0)
      + STRCAT(IObuff, _("[crypted]"));
      + else
      + {
      + STRCAT(IObuff, "[");
      + STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
      + STRCAT(IObuff, "]");
      + }
      + }
      +
      + #endif /* FEAT_CRYPT */
      *** ../vim-7.4.398/src/crypt_zip.c 2014-08-10 13:30:43.824787293 +0200
      --- src/crypt_zip.c 2014-08-09 15:31:32.493356185 +0200
      ***************
      *** 0 ****
      --- 1,158 ----
      + /* vi:set ts=8 sts=4 sw=4:
      + *
      + * VIM - Vi IMproved by Bram Moolenaar
      + *
      + * Do ":help uganda" in Vim to read copying and usage conditions.
      + * Do ":help credits" in Vim to see a list of people who contributed.
      + * See README.txt for an overview of the Vim source code.
      + */
      +
      + /*
      + * crypt_zip.c: Zip encryption support.
      + */
      + #include "vim.h"
      +
      + #if defined(FEAT_CRYPT) || defined(PROTO)
      + /*
      + * Optional encryption support.
      + * Mohsin Ahmed, mosh@..., 98-09-24
      + * Based on zip/crypt sources.
      + *
      + * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
      + * most countries. There are a few exceptions, but that still should not be a
      + * problem since this code was originally created in Europe and India.
      + */
      +
      + /* Need a type that should be 32 bits. 64 also works but wastes space. */
      + # if VIM_SIZEOF_INT >= 4
      + typedef unsigned int u32_T; /* int is at least 32 bits */
      + # else
      + typedef unsigned long u32_T; /* long should be 32 bits or more */
      + # endif
      +
      + /* The state of encryption, referenced by cryptstate_T. */
      + typedef struct {
      + u32_T keys[3];
      + } zip_state_T;
      +
      +
      + static void make_crc_tab __ARGS((void));
      +
      + static u32_T crc_32_table[256];
      +
      + /*
      + * Fill the CRC table, if not done already.
      + */
      + static void
      + make_crc_tab()
      + {
      + u32_T s, t, v;
      + static int done = FALSE;
      +
      + if (done)
      + return;
      + for (t = 0; t < 256; t++)
      + {
      + v = t;
      + for (s = 0; s < 8; s++)
      + v = (v >> 1) ^ ((v & 1) * (u32_T)0xedb88320L);
      + crc_32_table[t] = v;
      + }
      + done = TRUE;
      + }
      +
      + #define CRC32(c, b) (crc_32_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
      +
      + /*
      + * Return the next byte in the pseudo-random sequence.
      + */
      + #define DECRYPT_BYTE_ZIP(keys, t) { \
      + short_u temp = (short_u)keys[2] | 2; \
      + t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \
      + }
      +
      + /*
      + * Update the encryption keys with the next byte of plain text.
      + */
      + #define UPDATE_KEYS_ZIP(keys, c) { \
      + keys[0] = CRC32(keys[0], (c)); \
      + keys[1] += keys[0] & 0xff; \
      + keys[1] = keys[1] * 134775813L + 1; \
      + keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \
      + }
      +
      + /*
      + * Initialize for encryption/decryption.
      + */
      + void
      + crypt_zip_init(state, key, salt, salt_len, seed, seed_len)
      + cryptstate_T *state;
      + char_u *key;
      + char_u *salt UNUSED;
      + int salt_len UNUSED;
      + char_u *seed UNUSED;
      + int seed_len UNUSED;
      + {
      + char_u *p;
      + zip_state_T *zs;
      +
      + zs = (zip_state_T *)alloc(sizeof(zip_state_T));
      + state->method_state = zs;
      +
      + make_crc_tab();
      + zs->keys[0] = 305419896L;
      + zs->keys[1] = 591751049L;
      + zs->keys[2] = 878082192L;
      + for (p = key; *p != NUL; ++p)
      + {
      + UPDATE_KEYS_ZIP(zs->keys, (int)*p);
      + }
      + }
      +
      + /*
      + * Encrypt "from[len]" into "to[len]".
      + * "from" and "to" can be equal to encrypt in place.
      + */
      + void
      + crypt_zip_encode(state, from, len, to)
      + cryptstate_T *state;
      + char_u *from;
      + size_t len;
      + char_u *to;
      + {
      + zip_state_T *zs = state->method_state;
      + size_t i;
      + int ztemp, t;
      +
      + for (i = 0; i < len; ++i)
      + {
      + ztemp = from[i];
      + DECRYPT_BYTE_ZIP(zs->keys, t);
      + UPDATE_KEYS_ZIP(zs->keys, ztemp);
      + to[i] = t ^ ztemp;
      + }
      + }
      +
      + /*
      + * Decrypt "from[len]" into "to[len]".
      + */
      + void
      + crypt_zip_decode(state, from, len, to)
      + cryptstate_T *state;
      + char_u *from;
      + size_t len;
      + char_u *to;
      + {
      + zip_state_T *zs = state->method_state;
      + size_t i;
      + short_u temp;
      +
      + for (i = 0; i < len; ++i)
      + {
      + temp = (short_u)zs->keys[2] | 2;
      + temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff);
      + UPDATE_KEYS_ZIP(zs->keys, to[i] = from[i] ^ temp);
      + }
      + }
      +
      + #endif /* FEAT_CRYPT */
      *** ../vim-7.4.398/src/ex_docmd.c 2014-08-06 18:17:03.475147780 +0200
      --- src/ex_docmd.c 2014-08-09 15:31:32.493356185 +0200
      ***************
      *** 11506,11513 ****
      ex_X(eap)
      exarg_T *eap UNUSED;
      {
      ! if (get_crypt_method(curbuf) == 0 || blowfish_self_test() == OK)
      ! (void)get_crypt_key(TRUE, TRUE);
      }
      #endif

      --- 11506,11512 ----
      ex_X(eap)
      exarg_T *eap UNUSED;
      {
      ! (void)crypt_get_key(TRUE, TRUE);
      }
      #endif

      *** ../vim-7.4.398/src/fileio.c 2014-06-12 14:01:27.575769788 +0200
      --- src/fileio.c 2014-08-09 15:31:32.497356185 +0200
      ***************
      *** 24,43 ****
      #define BUFSIZE 8192 /* size of normal write buffer */
      #define SMBUFSIZE 256 /* size of emergency write buffer */

      - #ifdef FEAT_CRYPT
      - /* crypt_magic[0] is pkzip crypt, crypt_magic[1] is sha2+blowfish */
      - static char *crypt_magic[] = {"VimCrypt~01!", "VimCrypt~02!"};
      - static char crypt_magic_head[] = "VimCrypt~";
      - # define CRYPT_MAGIC_LEN 12 /* must be multiple of 4! */
      -
      - /* For blowfish, after the magic header, we store 8 bytes of salt and then 8
      - * bytes of seed (initialisation vector). */
      - static int crypt_salt_len[] = {0, 8};
      - static int crypt_seed_len[] = {0, 8};
      - #define CRYPT_SALT_LEN_MAX 8
      - #define CRYPT_SEED_LEN_MAX 8
      - #endif
      -
      /* Is there any system that doesn't have access()? */
      #define USE_MCH_ACCESS

      --- 24,29 ----
      ***************
      *** 55,61 ****
      static void check_marks_read __ARGS((void));
      #endif
      #ifdef FEAT_CRYPT
      - static int crypt_method_from_magic __ARGS((char *ptr, int len));
      static char_u *check_for_cryptkey __ARGS((char_u *cryptkey, char_u *ptr, long *sizep, off_t *filesizep, int newfile, char_u *fname, int *did_ask));
      #endif
      #ifdef UNIX
      --- 41,46 ----
      ***************
      *** 116,121 ****
      --- 101,109 ----
      #ifdef HAS_BW_FLAGS
      int bw_flags; /* FIO_ flags */
      #endif
      + #ifdef FEAT_CRYPT
      + buf_T *bw_buffer; /* buffer being written */
      + #endif
      #ifdef FEAT_MBYTE
      char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */
      int bw_restlen; /* nr of bytes in bw_rest[] */
      ***************
      *** 250,256 ****
      #ifdef FEAT_CRYPT
      char_u *cryptkey = NULL;
      int did_ask_for_key = FALSE;
      - int crypt_method_used;
      #endif
      #ifdef FEAT_PERSISTENT_UNDO
      context_sha256_T sha_ctx;
      --- 238,243 ----
      ***************
      *** 966,978 ****
      #endif
      }

      - #ifdef FEAT_CRYPT
      - if (cryptkey != NULL)
      - /* Need to reset the state, but keep the key, don't want to ask for it
      - * again. */
      - crypt_pop_state();
      - #endif
      -
      /*
      * When retrying with another "fenc" and the first time "fileformat"
      * will be reset.
      --- 953,958 ----
      ***************
      *** 1175,1180 ****
      --- 1155,1169 ----
      if (read_undo_file)
      sha256_start(&sha_ctx);
      #endif
      + #ifdef FEAT_CRYPT
      + if (curbuf->b_cryptstate != NULL)
      + {
      + /* Need to free the state, but keep the key, don't want to ask for
      + * it again. */
      + crypt_free_state(curbuf->b_cryptstate);
      + curbuf->b_cryptstate = NULL;
      + }
      + #endif
      }

      while (!error && !got_int)
      ***************
      *** 1339,1344 ****
      --- 1328,1403 ----
      size = read_eintr(fd, ptr, size);
      }

      + #ifdef FEAT_CRYPT
      + /*
      + * At start of file: Check for magic number of encryption.
      + */
      + if (filesize == 0 && size > 0)
      + cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
      + &filesize, newfile, sfname,
      + &did_ask_for_key);
      + /*
      + * Decrypt the read bytes. This is done before checking for
      + * EOF because the crypt layer may be buffering.
      + */
      + if (cryptkey != NULL && size > 0)
      + {
      + if (crypt_works_inplace(curbuf->b_cryptstate))
      + {
      + crypt_decode_inplace(curbuf->b_cryptstate, ptr, size);
      + }
      + else
      + {
      + char_u *newptr = NULL;
      + int decrypted_size;
      +
      + decrypted_size = crypt_decode_alloc(
      + curbuf->b_cryptstate, ptr, size, &newptr);
      +
      + /* If the crypt layer is buffering, not producing
      + * anything yet, need to read more. */
      + if (size > 0 && decrypted_size == 0)
      + continue;
      +
      + if (linerest == 0)
      + {
      + /* Simple case: reuse returned buffer (may be
      + * NULL, checked later). */
      + new_buffer = newptr;
      + }
      + else
      + {
      + long_u new_size;
      +
      + /* Need new buffer to add bytes carried over. */
      + new_size = (long_u)(decrypted_size + linerest + 1);
      + new_buffer = lalloc(new_size, FALSE);
      + if (new_buffer == NULL)
      + {
      + do_outofmem_msg(new_size);
      + error = TRUE;
      + break;
      + }
      +
      + mch_memmove(new_buffer, buffer, linerest);
      + if (newptr != NULL)
      + mch_memmove(new_buffer + linerest, newptr,
      + decrypted_size);
      + }
      +
      + if (new_buffer != NULL)
      + {
      + vim_free(buffer);
      + buffer = new_buffer;
      + new_buffer = NULL;
      + line_start = buffer;
      + ptr = buffer + linerest;
      + }
      + size = decrypted_size;
      + }
      + }
      + #endif
      +
      if (size <= 0)
      {
      if (size < 0) /* read error */
      ***************
      *** 1403,1423 ****
      }
      #endif
      }
      -
      - #ifdef FEAT_CRYPT
      - /*
      - * At start of file: Check for magic number of encryption.
      - */
      - if (filesize == 0)
      - cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
      - &filesize, newfile, sfname,
      - &did_ask_for_key);
      - /*
      - * Decrypt the read bytes.
      - */
      - if (cryptkey != NULL && size > 0)
      - crypt_decode(ptr, size);
      - #endif
      }
      skip_read = FALSE;

      --- 1462,1467 ----
      ***************
      *** 1430,1439 ****
      */
      if ((filesize == 0
      # ifdef FEAT_CRYPT
      ! || (filesize == (CRYPT_MAGIC_LEN
      ! + crypt_salt_len[use_crypt_method]
      ! + crypt_seed_len[use_crypt_method])
      ! && cryptkey != NULL)
      # endif
      )
      && (fio_flags == FIO_UCSBOM
      --- 1474,1482 ----
      */
      if ((filesize == 0
      # ifdef FEAT_CRYPT
      ! || (cryptkey != NULL
      ! && filesize == crypt_get_header_len(
      ! crypt_get_method_nr(curbuf)))
      # endif
      )
      && (fio_flags == FIO_UCSBOM
      ***************
      *** 2262,2276 ****
      save_file_ff(curbuf); /* remember the current file format */

      #ifdef FEAT_CRYPT
      ! crypt_method_used = use_crypt_method;
      ! if (cryptkey != NULL)
      {
      ! crypt_pop_state();
      ! if (cryptkey != curbuf->b_p_key)
      ! free_crypt_key(cryptkey);
      ! /* don't set cryptkey to NULL, it's used below as a flag that
      ! * encryption was used */
      }
      #endif

      #ifdef FEAT_MBYTE
      --- 2305,2319 ----
      save_file_ff(curbuf); /* remember the current file format */

      #ifdef FEAT_CRYPT
      ! if (curbuf->b_cryptstate != NULL)
      {
      ! crypt_free_state(curbuf->b_cryptstate);
      ! curbuf->b_cryptstate = NULL;
      }
      + if (cryptkey != NULL && cryptkey != curbuf->b_p_key)
      + crypt_free_key(cryptkey);
      + /* Don't set cryptkey to NULL, it's used below as a flag that
      + * encryption was used. */
      #endif

      #ifdef FEAT_MBYTE
      ***************
      *** 2457,2466 ****
      #ifdef FEAT_CRYPT
      if (cryptkey != NULL)
      {
      ! if (crypt_method_used == 1)
      ! STRCAT(IObuff, _("[blowfish]"));
      ! else
      ! STRCAT(IObuff, _("[crypted]"));
      c = TRUE;
      }
      #endif
      --- 2500,2506 ----
      #ifdef FEAT_CRYPT
      if (cryptkey != NULL)
      {
      ! crypt_append_msg(curbuf);
      c = TRUE;
      }
      #endif
      ***************
      *** 2489,2497 ****
      #ifdef FEAT_CRYPT
      if (cryptkey != NULL)
      msg_add_lines(c, (long)linecnt, filesize
      ! - CRYPT_MAGIC_LEN
      ! - crypt_salt_len[use_crypt_method]
      ! - crypt_seed_len[use_crypt_method]);
      else
      #endif
      msg_add_lines(c, (long)linecnt, filesize);
      --- 2529,2535 ----
      #ifdef FEAT_CRYPT
      if (cryptkey != NULL)
      msg_add_lines(c, (long)linecnt, filesize
      ! - crypt_get_header_len(crypt_get_method_nr(curbuf)));
      else
      #endif
      msg_add_lines(c, (long)linecnt, filesize);
      ***************
      *** 2882,2914 ****

      #if defined(FEAT_CRYPT) || defined(PROTO)
      /*
      - * Get the crypt method used for a file from "ptr[len]", the magic text at the
      - * start of the file.
      - * Returns -1 when no encryption used.
      - */
      - static int
      - crypt_method_from_magic(ptr, len)
      - char *ptr;
      - int len;
      - {
      - int i;
      -
      - for (i = 0; i < (int)(sizeof(crypt_magic) / sizeof(crypt_magic[0])); i++)
      - {
      - if (len < (CRYPT_MAGIC_LEN + crypt_salt_len[i] + crypt_seed_len[i]))
      - continue;
      - if (memcmp(ptr, crypt_magic[i], CRYPT_MAGIC_LEN) == 0)
      - return i;
      - }
      -
      - i = (int)STRLEN(crypt_magic_head);
      - if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
      - EMSG(_("E821: File is encrypted with unknown method"));
      -
      - return -1;
      - }
      -
      - /*
      * Check for magic number used for encryption. Applies to the current buffer.
      * If found, the magic number is removed from ptr[*sizep] and *sizep and
      * *filesizep are updated.
      --- 2920,2925 ----
      ***************
      *** 2924,2930 ****
      char_u *fname; /* file name to display */
      int *did_ask; /* flag: whether already asked for key */
      {
      ! int method = crypt_method_from_magic((char *)ptr, *sizep);
      int b_p_ro = curbuf->b_p_ro;

      if (method >= 0)
      --- 2935,2941 ----
      char_u *fname; /* file name to display */
      int *did_ask; /* flag: whether already asked for key */
      {
      ! int method = crypt_method_nr_from_magic((char *)ptr, *sizep);
      int b_p_ro = curbuf->b_p_ro;

      if (method >= 0)
      ***************
      *** 2933,2941 ****
      * Avoids accidentally overwriting the file with garbage. */
      curbuf->b_p_ro = TRUE;

      ! set_crypt_method(curbuf, method);
      ! if (method > 0)
      ! (void)blowfish_self_test();
      if (cryptkey == NULL && !*did_ask)
      {
      if (*curbuf->b_p_key)
      --- 2944,2950 ----
      * Avoids accidentally overwriting the file with garbage. */
      curbuf->b_p_ro = TRUE;

      ! crypt_set_cm_option(curbuf, method);
      if (cryptkey == NULL && !*did_ask)
      {
      if (*curbuf->b_p_key)
      ***************
      *** 2948,2954 ****
      * Happens when retrying to detect encoding. */
      smsg((char_u *)_(need_key_msg), fname);
      msg_scroll = TRUE;
      ! cryptkey = get_crypt_key(newfile, FALSE);
      *did_ask = TRUE;

      /* check if empty key entered */
      --- 2957,2963 ----
      * Happens when retrying to detect encoding. */
      smsg((char_u *)_(need_key_msg), fname);
      msg_scroll = TRUE;
      ! cryptkey = crypt_get_key(newfile, FALSE);
      *did_ask = TRUE;

      /* check if empty key entered */
      ***************
      *** 2963,2986 ****

      if (cryptkey != NULL)
      {
      ! int seed_len = crypt_seed_len[method];
      ! int salt_len = crypt_salt_len[method];

      ! crypt_push_state();
      ! use_crypt_method = method;
      ! if (method == 0)
      ! crypt_init_keys(cryptkey);
      ! else
      ! {
      ! bf_key_init(cryptkey, ptr + CRYPT_MAGIC_LEN, salt_len);
      ! bf_cfb_init(ptr + CRYPT_MAGIC_LEN + salt_len, seed_len);
      ! }

      - /* Remove magic number from the text */
      - *filesizep += CRYPT_MAGIC_LEN + salt_len + seed_len;
      - *sizep -= CRYPT_MAGIC_LEN + salt_len + seed_len;
      - mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN + salt_len + seed_len,
      - (size_t)*sizep);
      /* Restore the read-only flag. */
      curbuf->b_p_ro = b_p_ro;
      }
      --- 2972,2989 ----

      if (cryptkey != NULL)
      {
      ! int header_len;

      ! curbuf->b_cryptstate = crypt_create_from_header(
      ! method, cryptkey, ptr);
      ! crypt_set_cm_option(curbuf, method);
      !
      ! /* Remove cryptmethod specific header from the text. */
      ! header_len = crypt_get_header_len(method);
      ! *filesizep += header_len;
      ! *sizep -= header_len;
      ! mch_memmove(ptr, ptr + header_len, (size_t)*sizep);

      /* Restore the read-only flag. */
      curbuf->b_p_ro = b_p_ro;
      }
      ***************
      *** 2992,3076 ****

      return cryptkey;
      }
      -
      - /*
      - * Check for magic number used for encryption. Applies to the current buffer.
      - * If found and decryption is possible returns OK;
      - */
      - int
      - prepare_crypt_read(fp)
      - FILE *fp;
      - {
      - int method;
      - char_u buffer[CRYPT_MAGIC_LEN + CRYPT_SALT_LEN_MAX
      - + CRYPT_SEED_LEN_MAX + 2];
      -
      - if (fread(buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
      - return FAIL;
      - method = crypt_method_from_magic((char *)buffer,
      - CRYPT_MAGIC_LEN +
      - CRYPT_SEED_LEN_MAX +
      - CRYPT_SALT_LEN_MAX);
      - if (method < 0 || method != get_crypt_method(curbuf))
      - return FAIL;
      -
      - crypt_push_state();
      - if (method == 0)
      - crypt_init_keys(curbuf->b_p_key);
      - else
      - {
      - int salt_len = crypt_salt_len[method];
      - int seed_len = crypt_seed_len[method];
      -
      - if (fread(buffer, salt_len + seed_len, 1, fp) != 1)
      - return FAIL;
      - bf_key_init(curbuf->b_p_key, buffer, salt_len);
      - bf_cfb_init(buffer + salt_len, seed_len);
      - }
      - return OK;
      - }
      -
      - /*
      - * Prepare for writing encrypted bytes for buffer "buf".
      - * Returns a pointer to an allocated header of length "*lenp".
      - * When out of memory returns NULL.
      - * Otherwise calls crypt_push_state(), call crypt_pop_state() later.
      - */
      - char_u *
      - prepare_crypt_write(buf, lenp)
      - buf_T *buf;
      - int *lenp;
      - {
      - char_u *header;
      - int seed_len = crypt_seed_len[get_crypt_method(buf)];
      - int salt_len = crypt_salt_len[get_crypt_method(buf)];
      - char_u *salt;
      - char_u *seed;
      -
      - header = alloc_clear(CRYPT_MAGIC_LEN + CRYPT_SALT_LEN_MAX
      - + CRYPT_SEED_LEN_MAX + 2);
      - if (header != NULL)
      - {
      - crypt_push_state();
      - use_crypt_method = get_crypt_method(buf); /* select zip or blowfish */
      - vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
      - CRYPT_MAGIC_LEN);
      - if (use_crypt_method == 0)
      - crypt_init_keys(buf->b_p_key);
      - else
      - {
      - /* Using blowfish, add salt and seed. */
      - salt = header + CRYPT_MAGIC_LEN;
      - seed = salt + salt_len;
      - sha2_seed(salt, salt_len, seed, seed_len);
      - bf_key_init(buf->b_p_key, salt, salt_len);
      - bf_cfb_init(seed, seed_len);
      - }
      - }
      - *lenp = CRYPT_MAGIC_LEN + salt_len + seed_len;
      - return header;
      - }
      -
      #endif /* FEAT_CRYPT */

      #ifdef UNIX
      --- 2995,3000 ----
      ***************
      *** 3224,3232 ****
      int write_undo_file = FALSE;
      context_sha256_T sha_ctx;
      #endif
      - #ifdef FEAT_CRYPT
      - int crypt_method_used;
      - #endif

      if (fname == NULL || *fname == NUL) /* safety check */
      return FAIL;
      --- 3148,3153 ----
      ***************
      *** 3262,3267 ****
      --- 3183,3191 ----
      write_info.bw_iconv_fd = (iconv_t)-1;
      # endif
      #endif
      + #ifdef FEAT_CRYPT
      + write_info.bw_buffer = buf;
      + #endif

      /* After writing a file changedtick changes but we don't want to display
      * the line. */
      ***************
      *** 4505,4521 ****
      #ifdef FEAT_CRYPT
      if (*buf->b_p_key != NUL && !filtering)
      {
      ! char_u *header;
      ! int header_len;

      ! header = prepare_crypt_write(buf, &header_len);
      ! if (header == NULL)
      end = 0;
      else
      {
      ! /* Write magic number, so that Vim knows that this file is
      ! * encrypted when reading it again. This also undergoes utf-8 to
      ! * ucs-2/4 conversion when needed. */
      write_info.bw_buf = header;
      write_info.bw_len = header_len;
      write_info.bw_flags = FIO_NOCONVERT;
      --- 4429,4445 ----
      #ifdef FEAT_CRYPT
      if (*buf->b_p_key != NUL && !filtering)
      <br/><br/>(Message over 64 KB, truncated)
    • tux.
      I get a pretty lot of unresolved symbols with this build. (MSVC 2010) ... -- -- You received this message from the vim_dev maillist. Do not top-post! Type
      Message 2 of 8 , Aug 10, 2014
      • 0 Attachment
        I get a pretty lot of unresolved symbols with this build.
        (MSVC 2010)

        > ex_docmd.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_get_key".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_encode_alloc".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_free_key".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_free_state".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_encode_inplace".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_set_cm_option".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_works_inplace".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_decode_alloc".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_get_method_nr".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_decode_inplace".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_append_msg".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_method_nr_from_magic".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_create_from_header".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_create_for_writing".
        > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_get_header_len".
        > memline.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_encode".
        > memline.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_create".
        > option.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_method_nr_from_name".
        > option.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_self_test".
        > undo.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_whole_undofile".
        > undo.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_create_from_file".
        > gvim.exe : fatal error LNK1120: 21 nicht aufgelöste externe Verweise.

        --
        --
        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

        ---
        You received this message because you are subscribed to the Google Groups "vim_dev" group.
        To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscribe@....
        For more options, visit https://groups.google.com/d/optout.
      • Bram Moolenaar
        ... Sorry, I forgot to update all the Makefiles to include the newly added files. -- hundred-and-one symptoms of being an internet addict: 19. All of your
        Message 3 of 8 , Aug 10, 2014
        • 0 Attachment
          Zeug wrote:

          > I get a pretty lot of unresolved symbols with this build.
          > (MSVC 2010)
          >
          > > ex_docmd.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_get_key".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_encode_alloc".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_free_key".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_free_state".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_encode_inplace".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_set_cm_option".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_works_inplace".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_decode_alloc".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_get_method_nr".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_decode_inplace".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_append_msg".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_method_nr_from_magic".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_create_from_header".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_create_for_writing".
          > > fileio.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_get_header_len".
          > > memline.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_encode".
          > > memline.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_create".
          > > option.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_method_nr_from_name".
          > > option.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_self_test".
          > > undo.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_whole_undofile".
          > > undo.obj : error LNK2001: Nicht aufgelöstes externes Symbol "_crypt_create_from_file".
          > > gvim.exe : fatal error LNK1120: 21 nicht aufgelöste externe Verweise.

          Sorry, I forgot to update all the Makefiles to include the newly added
          files.

          --
          hundred-and-one symptoms of being an internet addict:
          19. All of your friends have an @ in their names.

          /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
          /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
          \\\ an exciting new programming language -- http://www.Zimbu.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

          ---
          You received this message because you are subscribed to the Google Groups "vim_dev" group.
          To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscribe@....
          For more options, visit https://groups.google.com/d/optout.
        • Bram Moolenaar
          ... Sorry! ... I think the structure should be initialized to zeroes to avoid surprises. ... We don t want these complications, to clearing it completely is
          Message 4 of 8 , Aug 11, 2014
          • 0 Attachment
            Kazunobu Kuriyama wrote:

            > >
            > > Patch 7.4.399
            > > Problem: Encryption implementation is messy. Blowfish encryption has a
            > > weakness.
            > > Solution: Refactor the encryption, store the state in an allocated struct
            > > instead of using a save/restore mechanism. Introduce the
            > > "blowfish2" method, which does not have the weakness and encrypts
            > > the whole undo file. (largely by David Leadbeater)
            > > Files: runtime/doc/editing.txt, runtime/doc/options.txt, src/Makefile,
            > > src/blowfish.c, src/crypt.c, src/crypt_zip.c, src/ex_docmd.c,
            > > src/fileio.c, src/globals.h, src/main.c, src/memline.c,
            > > src/misc2.c, src/option.c, src/proto.h, src/proto/blowfish.pro,
            > > src/proto/crypt.pro, src/proto/cr
            > > src/proto/fileio.pro, src/proto/misc2.pro, src/structs.h,
            > > src/undo.c, src/testdir/test71.in, src/testdir/test71.ok,
            > > src/testdir/test71a.in, src/testdir/test72.in,
            > > src/testdir/test72.ok
            >
            > Hi,
            >
            > On Mac OS X (10.9.4), test72 fails due to a segmentation fault.

            Sorry!

            > Looking into the failure, I found that it was caused by passing
            > uninitialized bi.bi_buffer to undo_flush() at undo.c:1785, then
            > undo_flush() invoking fwrite() with a null-valued first argument.
            >
            > While non-null checks against bi_buffer are done here and there in
            > undo.c, there is no such a check around undo.c:1785.
            >
            > Hopefully, the attached patch fixes the issue.

            I think the structure should be initialized to zeroes to avoid
            surprises.

            > Regards,
            > Kazunobu Kuriyama
            >
            > FYI, the OS X environment doesn’t define both HAVE_SELINUX and
            > HAVE_SMACK. I guess that is a cause of bi_buffer’s uninitialization.

            We don't want these complications, to clearing it completely is better.


            --
            hundred-and-one symptoms of being an internet addict:
            26. You check your mail. It says "no new messages." So you check it again.

            /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
            /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
            \\\ an exciting new programming language -- http://www.Zimbu.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

            ---
            You received this message because you are subscribed to the Google Groups "vim_dev" group.
            To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscribe@....
            For more options, visit https://groups.google.com/d/optout.
          • Kazunobu Kuriyama
            ... a ... ct ... , ... I should admit my previous post was misleading. The problem has nothing to do with the initialisation. Rather, I should have said
            Message 5 of 8 , Aug 11, 2014
            • 0 Attachment
              ----- Original Message -----
              >To: Kazunobu Kuriyama <kazunobu.kuriyama@...>
              >Subject: Re: Patch 7.4.399
              >Cc: vim_dev@...
              >From: Bram Moolenaar <Bram@...>
              >Date: Mon, 11 Aug 2014 10:51:31 +0200
              >
              >
              >
              >Kazunobu Kuriyama wrote:
              >
              >> >
              >> > Patch 7.4.399
              >> > Problem: Encryption implementation is messy. Blowfish encryption has
              a
              >> > weakness.
              >> > Solution: Refactor the encryption, store the state in an allocated stru
              ct
              >> > instead of using a save/restore mechanism. Introduce the
              >> > "blowfish2" method, which does not have the weakness and encrypts
              >> > the whole undo file. (largely by David Leadbeater)
              >> > Files: runtime/doc/editing.txt, runtime/doc/options.txt, src/Makefile
              ,
              >> > src/blowfish.c, src/crypt.c, src/crypt_zip.c, src/ex_docmd.c,
              >> > src/fileio.c, src/globals.h, src/main.c, src/memline.c,
              >> > src/misc2.c, src/option.c, src/proto.h, src/proto/blowfish.pro,
              >> > src/proto/crypt.pro, src/proto/cr
              >> > src/proto/fileio.pro, src/proto/misc2.pro, src/structs.h,
              >> > src/undo.c, src/testdir/test71.in, src/testdir/test71.ok,
              >> > src/testdir/test71a.in, src/testdir/test72.in,
              >> > src/testdir/test72.ok
              >>
              >> Hi,
              >>
              >> On Mac OS X (10.9.4), test72 fails due to a segmentation fault.
              >
              >Sorry!
              >
              >> Looking into the failure, I found that it was caused by passing
              >> uninitialized bi.bi_buffer to undo_flush() at undo.c:1785, then
              >> undo_flush() invoking fwrite() with a null-valued first argument.
              >>
              >> While non-null checks against bi_buffer are done here and there in
              >> undo.c, there is no such a check around undo.c:1785.
              >>
              >> Hopefully, the attached patch fixes the issue.
              >
              >I think the structure should be initialized to zeroes to avoid
              >surprises.

              I should admit my previous post was misleading. The problem has nothing to do
              with the initialisation. Rather, I should have said 'allocation': For Mac OS X
              , the field variable bi_buffer which had set to null at the beginning of u_wri
              te_undo(), was not made a valid pointer before passing it to undo_flush(). The
              null-valued bi_buffer caused a segfault at fwrite() invoked in undo_flush().

              >
              >> Regards,
              >> Kazunobu Kuriyama
              >>
              >> FYI, the OS X environment doesn't define both HAVE_SELINUX and
              >> HAVE_SMACK. I guess that is a cause of bi_buffer's uninitialization.
              >
              >We don't want these complications, to clearing it completely is better.

              I don't intend to ask anyone for doing anything with it. I only wanted to say
              that the code relevant to selinux or smack cannot be checked on my side in cas
              e the proposed patch goes wrong.

              >
              >
              >--
              >hundred-and-one symptoms of being an internet addict:
              >26. You check your mail. It says "no new messages." So you check it again.
              >
              > /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net ¥¥¥
              >/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ¥¥¥
              >¥¥¥ an exciting new programming language -- http://www.Zimbu.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
              >
              >---
              >You received this message because you are subscribed to the Google Groups "vi
              m_dev" group.
              >To unsubscribe from this group and stop receiving emails from it, send an ema
              il to vim_dev+unsubscribe@....
              >For more options, visit https://groups.google.com/d/optout.

              --
              --
              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

              ---
              You received this message because you are subscribed to the Google Groups "vim_dev" group.
              To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscribe@....
              For more options, visit https://groups.google.com/d/optout.
            • Christian Brabandt
              ... Perhaps, we should disallow to set the encryption method to the old/weak blowfish algorithm (or at least issue an error message here)? That should allow to
              Message 6 of 8 , Aug 14, 2014
              • 0 Attachment
                On So, 10 Aug 2014, Bram Moolenaar wrote:

                > Patch 7.4.399
                > Problem: Encryption implementation is messy. Blowfish encryption has a
                > weakness.
                > Solution: Refactor the encryption, store the state in an allocated struct
                > instead of using a save/restore mechanism. Introduce the
                > "blowfish2" method, which does not have the weakness and encrypts
                > the whole undo file. (largely by David Leadbeater)

                Perhaps, we should disallow to set the encryption method to the old/weak
                blowfish algorithm (or at least issue an error message here)? That
                should allow to still read old files, but should encourage users to use
                the new method.

                Best,
                Christian
                --
                Es steht uns nicht frei, den Völkern Afrikas Wohltaten zu erweisen
                oder nicht zu erweisen. Es ist unsere Pflicht. Alles, was wir ihnen
                geben, ist keine Wohltat, sondern eine Sühne.
                -- Albert Schweitzer

                --
                --
                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

                ---
                You received this message because you are subscribed to the Google Groups "vim_dev" group.
                To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscribe@....
                For more options, visit https://groups.google.com/d/optout.
              • Bram Moolenaar
                ... It s a bit tricky. When sharing a file between different computers some may not have the new Vim version yet. Perhaps after a year or so we could
                Message 7 of 8 , Aug 14, 2014
                • 0 Attachment
                  Christian Brabandt wrote:

                  > On So, 10 Aug 2014, Bram Moolenaar wrote:
                  >
                  > > Patch 7.4.399
                  > > Problem: Encryption implementation is messy. Blowfish encryption has a
                  > > weakness.
                  > > Solution: Refactor the encryption, store the state in an allocated struct
                  > > instead of using a save/restore mechanism. Introduce the
                  > > "blowfish2" method, which does not have the weakness and encrypts
                  > > the whole undo file. (largely by David Leadbeater)
                  >
                  > Perhaps, we should disallow to set the encryption method to the old/weak
                  > blowfish algorithm (or at least issue an error message here)? That
                  > should allow to still read old files, but should encourage users to use
                  > the new method.

                  It's a bit tricky. When sharing a file between different computers some
                  may not have the new Vim version yet. Perhaps after a year or so we
                  could discourage writing with the old blowfish method.

                  We also still support the very old "zip" encryption, should we disable
                  writing with that now? Or discourage it, e.g. by prompting for
                  confirmation (would break scripts though).

                  --
                  In many of the more relaxed civilizations on the Outer Eastern Rim of the
                  Galaxy, "The Hitchhiker's Guide to the Galaxy" has already supplanted the
                  great "Encyclopedia Galactica" as the standard repository of all knowledge
                  and wisdom, for though it has many omissions and contains much that is
                  apocryphal, or at least wildly inaccurate, it scores over the older, more
                  pedestrian work in two important respects.
                  First, it is slightly cheaper; and second, it has the words "DON'T PANIC"
                  inscribed in large friendly letters on its cover.
                  -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy"

                  /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
                  /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
                  \\\ an exciting new programming language -- http://www.Zimbu.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

                  ---
                  You received this message because you are subscribed to the Google Groups "vim_dev" group.
                  To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscribe@....
                  For more options, visit https://groups.google.com/d/optout.
                • Christian Brabandt
                  ... Well, github shows currently 1070 results for ... https://github.com/search?q=set+cm%3Dblowfish&ref=cmdform&type=Code&utf8=%E2%9C%93 (looks like most of
                  Message 8 of 8 , Aug 15, 2014
                  • 0 Attachment
                    On Do, 14 Aug 2014, Bram Moolenaar wrote:

                    > Christian Brabandt wrote:
                    >
                    > > On So, 10 Aug 2014, Bram Moolenaar wrote:
                    > >
                    > > > Patch 7.4.399
                    > > > Problem: Encryption implementation is messy. Blowfish encryption has a
                    > > > weakness.
                    > > > Solution: Refactor the encryption, store the state in an allocated struct
                    > > > instead of using a save/restore mechanism. Introduce the
                    > > > "blowfish2" method, which does not have the weakness and encrypts
                    > > > the whole undo file. (largely by David Leadbeater)
                    > >
                    > > Perhaps, we should disallow to set the encryption method to the old/weak
                    > > blowfish algorithm (or at least issue an error message here)? That
                    > > should allow to still read old files, but should encourage users to use
                    > > the new method.
                    >
                    > It's a bit tricky. When sharing a file between different computers some
                    > may not have the new Vim version yet. Perhaps after a year or so we
                    > could discourage writing with the old blowfish method.

                    Well, github shows currently 1070 results for
                    :set cm=blowfish
                    https://github.com/search?q=set+cm%3Dblowfish&ref=cmdform&type=Code&utf8=%E2%9C%93
                    (looks like most of them are in dotfiles).

                    There are only a couple of references to
                    :set cm=blowfish2
                    (all of which are either test71.in or the vim help files)

                    That means, we leave all those users with the old and weak cipher.

                    I see 2 possible solutions:

                    1) use the name blowfish for the new encryption and blowfish2 for the
                    weak one and if Vim reads a file with the old encryption give a warning
                    to use the blowfish2 encryption method.

                    2) make blowfish an alias for blowfish2 (so when a user sets blowfish,
                    it really uses the strong encryption) and do not allow to use the
                    weak encryption anymore (but allow to still read the weak method, but
                    writing will use blowfish2).
                    That has the disadvantage, that newly written files can't use the
                    old weak encryption anymore and thus won't be able to be read by
                    older Vims, but do we really want that?)

                    Both methods should allow to be able to still use files, that have been
                    encrypted with a vim version smaller than 7.4.399

                    In fact, if this is really a security issue, you might want to think
                    about releasing a new Vim version 7.5 or at least have a new windows
                    binary available.

                    > We also still support the very old "zip" encryption, should we disable
                    > writing with that now? Or discourage it, e.g. by prompting for
                    > confirmation (would break scripts though).

                    I would say, discourage it, by giving at least a warning (which could be
                    made silent, if a user really wants that).

                    In fact, I would probably disallow to set cm=zip manually (while still
                    being able to read zip encrypted files).

                    Best,
                    Christian
                    --
                    Im Idealen kommt alles auf die élans, im Realen auf die
                    Beharrlichkeit an.
                    -- Goethe, Maximen und Reflektionen, Nr. 701

                    --
                    --
                    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

                    ---
                    You received this message because you are subscribed to the Google Groups "vim_dev" group.
                    To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscribe@....
                    For more options, visit https://groups.google.com/d/optout.
                  Your message has been successfully submitted and would be delivered to recipients shortly.