Blob Blame History Raw
To: vim_dev@googlegroups.com
Subject: Patch 7.4.399
Fcc: outbox
From: Bram Moolenaar <Bram@moolenaar.net>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
------------

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@sasi.com, 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@sasi.com, 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)
      {
! 	char_u		*header;
! 	int		header_len;
  
! 	buf->b_cryptstate = crypt_create_for_writing(crypt_get_method_nr(buf),
! 					  buf->b_p_key, &header, &header_len);
! 	if (buf->b_cryptstate == NULL || header == NULL)
  	    end = 0;
  	else
  	{
! 	    /* Write magic number, so that Vim knows how this file is
! 	     * encrypted when reading it back. */
  	    write_info.bw_buf = header;
  	    write_info.bw_len = header_len;
  	    write_info.bw_flags = FIO_NOCONVERT;
***************
*** 4769,4780 ****
  	mch_set_acl(wfname, acl);
  #endif
  #ifdef FEAT_CRYPT
!     crypt_method_used = use_crypt_method;
!     if (wb_flags & FIO_ENCRYPTED)
! 	crypt_pop_state();
  #endif
  
- 
  #if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
      if (wfname != fname)
      {
--- 4693,4705 ----
  	mch_set_acl(wfname, acl);
  #endif
  #ifdef FEAT_CRYPT
!     if (buf->b_cryptstate != NULL)
!     {
! 	crypt_free_state(buf->b_cryptstate);
! 	buf->b_cryptstate = NULL;
!     }
  #endif
  
  #if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
      if (wfname != fname)
      {
***************
*** 4924,4933 ****
  #ifdef FEAT_CRYPT
  	if (wb_flags & FIO_ENCRYPTED)
  	{
! 	    if (crypt_method_used == 1)
! 		STRCAT(IObuff, _("[blowfish]"));
! 	    else
! 		STRCAT(IObuff, _("[crypted]"));
  	    c = TRUE;
  	}
  #endif
--- 4849,4855 ----
  #ifdef FEAT_CRYPT
  	if (wb_flags & FIO_ENCRYPTED)
  	{
! 	    crypt_append_msg(buf);
  	    c = TRUE;
  	}
  #endif
***************
*** 5740,5747 ****
  #endif /* FEAT_MBYTE */
  
  #ifdef FEAT_CRYPT
!     if (flags & FIO_ENCRYPTED)		/* encrypt the data */
! 	crypt_encode(buf, len, buf);
  #endif
  
      wlen = write_eintr(ip->bw_fd, buf, len);
--- 5662,5687 ----
  #endif /* FEAT_MBYTE */
  
  #ifdef FEAT_CRYPT
!     if (flags & FIO_ENCRYPTED)
!     {
! 	/* Encrypt the data. Do it in-place if possible, otherwise use an
! 	 * allocated buffer. */
! 	if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
! 	{
! 	    crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len);
! 	}
! 	else
! 	{
! 	    char_u *outbuf;
! 
! 	    len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf);
! 	    if (len == 0)
! 		return OK;  /* Crypt layer is buffering, will flush later. */
! 	    wlen = write_eintr(ip->bw_fd, outbuf, len);
! 	    vim_free(outbuf);
! 	    return (wlen < len) ? FAIL : OK;
! 	}
!     }
  #endif
  
      wlen = write_eintr(ip->bw_fd, buf, len);
*** ../vim-7.4.398/src/globals.h	2014-08-06 18:17:03.475147780 +0200
--- src/globals.h	2014-08-09 15:31:32.497356185 +0200
***************
*** 105,114 ****
  
  EXTERN int	screen_cleared INIT(= FALSE);	/* screen has been cleared */
  
- #ifdef FEAT_CRYPT
- EXTERN int      use_crypt_method INIT(= 0);
- #endif
- 
  /*
   * When '$' is included in 'cpoptions' option set:
   * When a change command is given that deletes only part of a line, a dollar
--- 105,110 ----
*** ../vim-7.4.398/src/main.c	2014-05-28 18:22:37.876225054 +0200
--- src/main.c	2014-08-09 15:31:32.497356185 +0200
***************
*** 846,853 ****
  #ifdef FEAT_CRYPT
      if (params.ask_for_key)
      {
! 	(void)blowfish_self_test();
! 	(void)get_crypt_key(TRUE, TRUE);
  	TIME_MSG("getting crypt key");
      }
  #endif
--- 846,852 ----
  #ifdef FEAT_CRYPT
      if (params.ask_for_key)
      {
! 	(void)crypt_get_key(TRUE, TRUE);
  	TIME_MSG("getting crypt key");
      }
  #endif
*** ../vim-7.4.398/src/memline.c	2014-03-23 16:03:56.171311627 +0100
--- src/memline.c	2014-08-09 15:39:22.629352806 +0200
***************
*** 63,68 ****
--- 63,77 ----
  #define BLOCK0_ID1     '0'		    /* block 0 id 1 */
  #define BLOCK0_ID1_C0  'c'		    /* block 0 id 1 'cm' 0 */
  #define BLOCK0_ID1_C1  'C'		    /* block 0 id 1 'cm' 1 */
+ #define BLOCK0_ID1_C2  'd'		    /* block 0 id 1 'cm' 2 */
+ 
+ #if defined(FEAT_CRYPT)
+ static int id1_codes[] = {
+     BLOCK0_ID1_C0,  /* CRYPT_M_ZIP */
+     BLOCK0_ID1_C1,  /* CRYPT_M_BF */
+     BLOCK0_ID1_C2,  /* CRYPT_M_BF2 */
+ };
+ #endif
  
  /*
   * pointer to a block, used in a pointer block
***************
*** 151,157 ****
  struct block0
  {
      char_u	b0_id[2];	/* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
! 				 * BLOCK0_ID1_C0, BLOCK0_ID1_C1 */
      char_u	b0_version[10];	/* Vim version string */
      char_u	b0_page_size[4];/* number of bytes per page */
      char_u	b0_mtime[4];	/* last modification time of file */
--- 160,166 ----
  struct block0
  {
      char_u	b0_id[2];	/* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
! 				 * BLOCK0_ID1_C0, BLOCK0_ID1_C1, etc. */
      char_u	b0_version[10];	/* Vim version string */
      char_u	b0_page_size[4];/* number of bytes per page */
      char_u	b0_mtime[4];	/* last modification time of file */
***************
*** 256,262 ****
  static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
  #endif
  #ifdef FEAT_CRYPT
! static void ml_crypt_prepare __ARGS((memfile_T *mfp, off_t offset, int reading));
  #endif
  #ifdef FEAT_BYTEOFF
  static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
--- 265,271 ----
  static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
  #endif
  #ifdef FEAT_CRYPT
! static cryptstate_T *ml_crypt_prepare __ARGS((memfile_T *mfp, off_t offset, int reading));
  #endif
  #ifdef FEAT_BYTEOFF
  static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
***************
*** 359,366 ****
  	b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
  	long_to_char(mch_get_pid(), b0p->b0_pid);
  #ifdef FEAT_CRYPT
! 	if (*buf->b_p_key != NUL)
! 	    ml_set_b0_crypt(buf, b0p);
  #endif
      }
  
--- 368,374 ----
  	b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
  	long_to_char(mch_get_pid(), b0p->b0_pid);
  #ifdef FEAT_CRYPT
! 	ml_set_b0_crypt(buf, b0p);
  #endif
      }
  
***************
*** 436,446 ****
  	b0p->b0_id[1] = BLOCK0_ID1;
      else
      {
! 	if (get_crypt_method(buf) == 0)
! 	    b0p->b0_id[1] = BLOCK0_ID1_C0;
! 	else
  	{
- 	    b0p->b0_id[1] = BLOCK0_ID1_C1;
  	    /* Generate a seed and store it in block 0 and in the memfile. */
  	    sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
  	    mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
--- 444,454 ----
  	b0p->b0_id[1] = BLOCK0_ID1;
      else
      {
! 	int method_nr = crypt_get_method_nr(buf);
! 
! 	b0p->b0_id[1] = id1_codes[method_nr];
! 	if (method_nr > CRYPT_M_ZIP)
  	{
  	    /* Generate a seed and store it in block 0 and in the memfile. */
  	    sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
  	    mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
***************
*** 887,893 ****
      if (b0p->b0_id[0] != BLOCK0_ID0
  	    || (b0p->b0_id[1] != BLOCK0_ID1
  		&& b0p->b0_id[1] != BLOCK0_ID1_C0
! 		&& b0p->b0_id[1] != BLOCK0_ID1_C1)
  	    )
  	return FAIL;
      return OK;
--- 895,902 ----
      if (b0p->b0_id[0] != BLOCK0_ID0
  	    || (b0p->b0_id[1] != BLOCK0_ID1
  		&& b0p->b0_id[1] != BLOCK0_ID1_C0
! 		&& b0p->b0_id[1] != BLOCK0_ID1_C1
! 		&& b0p->b0_id[1] != BLOCK0_ID1_C2)
  	    )
  	return FAIL;
      return OK;
***************
*** 1255,1268 ****
      }
  
  #ifdef FEAT_CRYPT
!     if (b0p->b0_id[1] == BLOCK0_ID1_C0)
! 	b0_cm = 0;
!     else if (b0p->b0_id[1] == BLOCK0_ID1_C1)
!     {
! 	b0_cm = 1;
  	mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
!     }
!     set_crypt_method(buf, b0_cm);
  #else
      if (b0p->b0_id[1] != BLOCK0_ID1)
      {
--- 1264,1275 ----
      }
  
  #ifdef FEAT_CRYPT
!     for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i)
! 	if (id1_codes[i] == b0p->b0_id[1])
! 	    b0_cm = i;
!     if (b0_cm > 0)
  	mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
!     crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm);
  #else
      if (b0p->b0_id[1] != BLOCK0_ID1)
      {
***************
*** 1389,1395 ****
  	}
  	else
  	    smsg((char_u *)_(need_key_msg), fname_used);
! 	buf->b_p_key = get_crypt_key(FALSE, FALSE);
  	if (buf->b_p_key == NULL)
  	    buf->b_p_key = curbuf->b_p_key;
  	else if (*buf->b_p_key == NUL)
--- 1396,1402 ----
  	}
  	else
  	    smsg((char_u *)_(need_key_msg), fname_used);
! 	buf->b_p_key = crypt_get_key(FALSE, FALSE);
  	if (buf->b_p_key == NULL)
  	    buf->b_p_key = curbuf->b_p_key;
  	else if (*buf->b_p_key == NUL)
***************
*** 4816,4821 ****
--- 4823,4829 ----
      char_u	*text_start;
      char_u	*new_data;
      int		text_len;
+     cryptstate_T *state;
  
      if (dp->db_id != DATA_ID)
  	return data;
***************
*** 4831,4840 ****
      mch_memmove(new_data, dp, head_end - (char_u *)dp);
  
      /* Encrypt the text. */
!     crypt_push_state();
!     ml_crypt_prepare(mfp, offset, FALSE);
!     crypt_encode(text_start, text_len, new_data + dp->db_txt_start);
!     crypt_pop_state();
  
      /* Clear the gap. */
      if (head_end < text_start)
--- 4839,4847 ----
      mch_memmove(new_data, dp, head_end - (char_u *)dp);
  
      /* Encrypt the text. */
!     state = ml_crypt_prepare(mfp, offset, FALSE);
!     crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
!     crypt_free_state(state);
  
      /* Clear the gap. */
      if (head_end < text_start)
***************
*** 4857,4862 ****
--- 4864,4870 ----
      char_u	*head_end;
      char_u	*text_start;
      int		text_len;
+     cryptstate_T *state;
  
      if (dp->db_id == DATA_ID)
      {
***************
*** 4869,4885 ****
  	    return;  /* data was messed up */
  
  	/* Decrypt the text in place. */
! 	crypt_push_state();
! 	ml_crypt_prepare(mfp, offset, TRUE);
! 	crypt_decode(text_start, text_len);
! 	crypt_pop_state();
      }
  }
  
  /*
   * Prepare for encryption/decryption, using the key, seed and offset.
   */
!     static void
  ml_crypt_prepare(mfp, offset, reading)
      memfile_T	*mfp;
      off_t	offset;
--- 4877,4893 ----
  	    return;  /* data was messed up */
  
  	/* Decrypt the text in place. */
! 	state = ml_crypt_prepare(mfp, offset, TRUE);
! 	crypt_decode_inplace(state, text_start, text_len);
! 	crypt_free_state(state);
      }
  }
  
  /*
   * Prepare for encryption/decryption, using the key, seed and offset.
+  * Return an allocated cryptstate_T *.
   */
!     static cryptstate_T *
  ml_crypt_prepare(mfp, offset, reading)
      memfile_T	*mfp;
      off_t	offset;
***************
*** 4887,4924 ****
  {
      buf_T	*buf = mfp->mf_buffer;
      char_u	salt[50];
!     int		method;
      char_u	*key;
      char_u	*seed;
  
      if (reading && mfp->mf_old_key != NULL)
      {
  	/* Reading back blocks with the previous key/method/seed. */
! 	method = mfp->mf_old_cm;
  	key = mfp->mf_old_key;
  	seed = mfp->mf_old_seed;
      }
      else
      {
! 	method = get_crypt_method(buf);
  	key = buf->b_p_key;
  	seed = mfp->mf_seed;
      }
  
!     use_crypt_method = method;  /* select pkzip or blowfish */
!     if (method == 0)
      {
  	vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
! 	crypt_init_keys(salt);
!     }
!     else
!     {
! 	/* Using blowfish, add salt and seed. We use the byte offset of the
! 	 * block for the salt. */
! 	vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
! 	bf_key_init(key, salt, (int)STRLEN(salt));
! 	bf_cfb_init(seed, MF_SEED_LEN);
      }
  }
  
  #endif
--- 4895,4931 ----
  {
      buf_T	*buf = mfp->mf_buffer;
      char_u	salt[50];
!     int		method_nr;
      char_u	*key;
      char_u	*seed;
  
      if (reading && mfp->mf_old_key != NULL)
      {
  	/* Reading back blocks with the previous key/method/seed. */
! 	method_nr = mfp->mf_old_cm;
  	key = mfp->mf_old_key;
  	seed = mfp->mf_old_seed;
      }
      else
      {
! 	method_nr = crypt_get_method_nr(buf);
  	key = buf->b_p_key;
  	seed = mfp->mf_seed;
      }
  
!     if (method_nr == CRYPT_M_ZIP)
      {
+ 	/* For PKzip: Append the offset to the key, so that we use a different
+ 	 * key for every block. */
  	vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
! 	return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
      }
+ 
+     /* Using blowfish or better: add salt and seed. We use the byte offset
+      * of the block for the salt. */
+     vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
+     return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
+ 							   seed, MF_SEED_LEN);
  }
  
  #endif
*** ../vim-7.4.398/src/misc2.c	2014-06-25 14:39:35.106348584 +0200
--- src/misc2.c	2014-08-09 15:31:32.501356185 +0200
***************
*** 3803,4124 ****
  #endif /* CURSOR_SHAPE */
  
  
- #ifdef FEAT_CRYPT
- /*
-  * Optional encryption support.
-  * Mohsin Ahmed, mosh@sasi.com, 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.
-  *
-  * 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.
-  */
- 
- /* from zip.h */
- 
- typedef unsigned short ush;	/* unsigned 16-bit value */
- typedef unsigned long  ulg;	/* unsigned 32-bit value */
- 
- static void make_crc_tab __ARGS((void));
- 
- static ulg crc_32_tab[256];
- 
- /*
-  * Fill the CRC table.
-  */
-     static void
- make_crc_tab()
- {
-     ulg		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) * (ulg)0xedb88320L);
- 	crc_32_tab[t] = v;
-     }
-     done = TRUE;
- }
- 
- #define CRC32(c, b) (crc_32_tab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
- 
- static ulg keys[3]; /* keys defining the pseudo-random sequence */
- 
- /*
-  * Return the next byte in the pseudo-random sequence.
-  */
- #define DECRYPT_BYTE_ZIP(t) { \
-     ush temp; \
-  \
-     temp = (ush)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(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)); \
- }
- 
- static int crypt_busy = 0;
- static ulg saved_keys[3];
- static int saved_crypt_method;
- 
- /*
-  * Return int value for crypt method string:
-  * 0 for "zip", the old method.  Also for any non-valid value.
-  * 1 for "blowfish".
-  */
-     int
- crypt_method_from_string(s)
-     char_u  *s;
- {
-     return *s == 'b' ? 1 : 0;
- }
- 
- /*
-  * Get the crypt method for buffer "buf" as a number.
-  */
-     int
- get_crypt_method(buf)
-     buf_T *buf;
- {
-     return crypt_method_from_string(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
- }
- 
- /*
-  * Set the crypt method for buffer "buf" to "method" using the int value as
-  * returned by crypt_method_from_string().
-  */
-     void
- set_crypt_method(buf, method)
-     buf_T   *buf;
-     int	    method;
- {
-     free_string_option(buf->b_p_cm);
-     buf->b_p_cm = vim_strsave((char_u *)(method == 0 ? "zip" : "blowfish"));
- }
- 
- /*
-  * Prepare for initializing encryption.  If already doing encryption then save
-  * the state.
-  * Must always be called symmetrically with crypt_pop_state().
-  */
-     void
- crypt_push_state()
- {
-     if (crypt_busy == 1)
-     {
- 	/* save the state */
- 	if (use_crypt_method == 0)
- 	{
- 	    saved_keys[0] = keys[0];
- 	    saved_keys[1] = keys[1];
- 	    saved_keys[2] = keys[2];
- 	}
- 	else
- 	    bf_crypt_save();
- 	saved_crypt_method = use_crypt_method;
-     }
-     else if (crypt_busy > 1)
- 	EMSG2(_(e_intern2), "crypt_push_state()");
-     ++crypt_busy;
- }
- 
- /*
-  * End encryption.  If doing encryption before crypt_push_state() then restore
-  * the saved state.
-  * Must always be called symmetrically with crypt_push_state().
-  */
-     void
- crypt_pop_state()
- {
-     --crypt_busy;
-     if (crypt_busy == 1)
-     {
- 	use_crypt_method = saved_crypt_method;
- 	if (use_crypt_method == 0)
- 	{
- 	    keys[0] = saved_keys[0];
- 	    keys[1] = saved_keys[1];
- 	    keys[2] = saved_keys[2];
- 	}
- 	else
- 	    bf_crypt_restore();
-     }
- }
- 
- /*
-  * Encrypt "from[len]" into "to[len]".
-  * "from" and "to" can be equal to encrypt in place.
-  */
-     void
- crypt_encode(from, len, to)
-     char_u	*from;
-     size_t	len;
-     char_u	*to;
- {
-     size_t	i;
-     int		ztemp, t;
- 
-     if (use_crypt_method == 0)
- 	for (i = 0; i < len; ++i)
- 	{
- 	    ztemp = from[i];
- 	    DECRYPT_BYTE_ZIP(t);
- 	    UPDATE_KEYS_ZIP(ztemp);
- 	    to[i] = t ^ ztemp;
- 	}
-     else
- 	bf_crypt_encode(from, len, to);
- }
- 
- /*
-  * Decrypt "ptr[len]" in place.
-  */
-     void
- crypt_decode(ptr, len)
-     char_u	*ptr;
-     long	len;
- {
-     char_u *p;
- 
-     if (use_crypt_method == 0)
- 	for (p = ptr; p < ptr + len; ++p)
- 	{
- 	    ush temp;
- 
- 	    temp = (ush)keys[2] | 2;
- 	    temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff);
- 	    UPDATE_KEYS_ZIP(*p ^= temp);
- 	}
-     else
- 	bf_crypt_decode(ptr, len);
- }
- 
- /*
-  * Initialize the encryption keys and the random header according to
-  * the given password.
-  * If "passwd" is NULL or empty, don't do anything.
-  */
-     void
- crypt_init_keys(passwd)
-     char_u *passwd;		/* password string with which to modify keys */
- {
-     if (passwd != NULL && *passwd != NUL)
-     {
- 	if (use_crypt_method == 0)
- 	{
- 	    char_u *p;
- 
- 	    make_crc_tab();
- 	    keys[0] = 305419896L;
- 	    keys[1] = 591751049L;
- 	    keys[2] = 878082192L;
- 	    for (p = passwd; *p!= NUL; ++p)
- 	    {
- 		UPDATE_KEYS_ZIP((int)*p);
- 	    }
- 	}
- 	else
- 	    bf_crypt_init_keys(passwd);
-     }
- }
- 
- /*
-  * Free an allocated crypt key.  Clear the text to make sure it doesn't stay
-  * in memory anywhere.
-  */
-     void
- free_crypt_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 *
- get_crypt_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!"));
- 		free_crypt_key(p1);
- 		free_crypt_key(p2);
- 		p2 = NULL;
- 		round = -1;		/* do it again */
- 		continue;
- 	    }
- 
- 	    if (store)
- 	    {
- 		set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
- 		free_crypt_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;
- 
-     free_crypt_key(p2);
-     return p1;
- }
- 
- #endif /* FEAT_CRYPT */
- 
  /* TODO: make some #ifdef for this */
  /*--------[ file searching ]-------------------------------------------------*/
  /*
--- 3803,3808 ----
***************
*** 6588,6595 ****
--- 6272,6294 ----
      FILE	*fd;
      time_t	the_time;
  {
+     char_u	buf[8];
+ 
+     time_to_bytes(the_time, buf);
+     fwrite(buf, (size_t)8, (size_t)1, fd);
+ }
+ 
+ /*
+  * Write time_t to "buf[8]".
+  */
+     void
+ time_to_bytes(the_time, buf)
+     time_t	the_time;
+     char_u	*buf;
+ {
      int		c;
      int		i;
+     int		bi = 0;
      time_t	wtime = the_time;
  
      /* time_t can be up to 8 bytes in size, more than long_u, thus we
***************
*** 6603,6609 ****
      {
  	if (i + 1 > (int)sizeof(time_t))
  	    /* ">>" doesn't work well when shifting more bits than avail */
! 	    putc(0, fd);
  	else
  	{
  #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
--- 6302,6308 ----
      {
  	if (i + 1 > (int)sizeof(time_t))
  	    /* ">>" doesn't work well when shifting more bits than avail */
! 	    buf[bi++] = 0;
  	else
  	{
  #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
***************
*** 6611,6617 ****
  #else
  	    c = (int)((long_u)wtime >> (i * 8));
  #endif
! 	    putc(c, fd);
  	}
      }
  }
--- 6310,6316 ----
  #else
  	    c = (int)((long_u)wtime >> (i * 8));
  #endif
! 	    buf[bi++] = c;
  	}
      }
  }
*** ../vim-7.4.398/src/option.c	2014-08-06 14:52:05.047236174 +0200
--- src/option.c	2014-08-09 15:39:29.741352755 +0200
***************
*** 2989,2995 ****
  static char *(p_nf_values[]) = {"octal", "hex", "alpha", NULL};
  static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
  #ifdef FEAT_CRYPT
! static char *(p_cm_values[]) = {"zip", "blowfish", NULL};
  #endif
  #ifdef FEAT_CMDL_COMPL
  static char *(p_wop_values[]) = {"tagfile", NULL};
--- 2989,2995 ----
  static char *(p_nf_values[]) = {"octal", "hex", "alpha", NULL};
  static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
  #ifdef FEAT_CRYPT
! static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2", NULL};
  #endif
  #ifdef FEAT_CMDL_COMPL
  static char *(p_wop_values[]) = {"tagfile", NULL};
***************
*** 6140,6146 ****
  # endif
  	if (STRCMP(curbuf->b_p_key, oldval) != 0)
  	    /* Need to update the swapfile. */
! 	    ml_set_crypt_key(curbuf, oldval, get_crypt_method(curbuf));
      }
  
      else if (gvarp == &p_cm)
--- 6140,6146 ----
  # endif
  	if (STRCMP(curbuf->b_p_key, oldval) != 0)
  	    /* Need to update the swapfile. */
! 	    ml_set_crypt_key(curbuf, oldval, crypt_get_method_nr(curbuf));
      }
  
      else if (gvarp == &p_cm)
***************
*** 6151,6157 ****
  	    p = p_cm;
  	if (check_opt_strings(p, p_cm_values, TRUE) != OK)
  	    errmsg = e_invarg;
! 	else if (get_crypt_method(curbuf) > 0 && blowfish_self_test() == FAIL)
  	    errmsg = e_invarg;
  	else
  	{
--- 6151,6157 ----
  	    p = p_cm;
  	if (check_opt_strings(p, p_cm_values, TRUE) != OK)
  	    errmsg = e_invarg;
! 	else if (crypt_self_test() == FAIL)
  	    errmsg = e_invarg;
  	else
  	{
***************
*** 6177,6183 ****
  		p = curbuf->b_p_cm;
  	    if (STRCMP(s, p) != 0)
  		ml_set_crypt_key(curbuf, curbuf->b_p_key,
! 						 crypt_method_from_string(s));
  
  	    /* If the global value changes need to update the swapfile for all
  	     * buffers using that value. */
--- 6177,6183 ----
  		p = curbuf->b_p_cm;
  	    if (STRCMP(s, p) != 0)
  		ml_set_crypt_key(curbuf, curbuf->b_p_key,
! 						crypt_method_nr_from_name(s));
  
  	    /* If the global value changes need to update the swapfile for all
  	     * buffers using that value. */
***************
*** 6188,6194 ****
  		for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  		    if (buf != curbuf && *buf->b_p_cm == NUL)
  			ml_set_crypt_key(buf, buf->b_p_key,
! 					    crypt_method_from_string(oldval));
  	    }
  	}
      }
--- 6188,6194 ----
  		for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  		    if (buf != curbuf && *buf->b_p_cm == NUL)
  			ml_set_crypt_key(buf, buf->b_p_key,
! 					   crypt_method_nr_from_name(oldval));
  	    }
  	}
      }
*** ../vim-7.4.398/src/proto.h	2013-02-26 14:18:19.000000000 +0100
--- src/proto.h	2014-08-09 15:39:39.333352686 +0200
***************
*** 70,75 ****
--- 70,77 ----
  
  # ifdef FEAT_CRYPT
  #  include "blowfish.pro"
+ #  include "crypt.pro"
+ #  include "crypt_zip.pro"
  # endif
  # include "buffer.pro"
  # include "charset.pro"
*** ../vim-7.4.398/src/proto/blowfish.pro	2014-02-11 15:23:27.938123631 +0100
--- src/proto/blowfish.pro	2014-08-09 15:31:32.501356185 +0200
***************
*** 1,10 ****
  /* blowfish.c */
! void bf_key_init __ARGS((char_u *password, char_u *salt, int salt_len));
! void bf_cfb_init __ARGS((char_u *iv, int iv_len));
! void bf_crypt_encode __ARGS((char_u *from, size_t len, char_u *to));
! void bf_crypt_decode __ARGS((char_u *ptr, long len));
! void bf_crypt_init_keys __ARGS((char_u *passwd));
! void bf_crypt_save __ARGS((void));
! void bf_crypt_restore __ARGS((void));
  int blowfish_self_test __ARGS((void));
  /* vim: set ft=c : */
--- 1,6 ----
  /* blowfish.c */
! void crypt_blowfish_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
! void crypt_blowfish_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
! void crypt_blowfish_init __ARGS((cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
  int blowfish_self_test __ARGS((void));
  /* vim: set ft=c : */
*** ../vim-7.4.398/src/proto/crypt.pro	2014-08-10 13:30:43.880787293 +0200
--- src/proto/crypt.pro	2014-08-09 15:31:32.501356185 +0200
***************
*** 0 ****
--- 1,24 ----
+ /* crypt.c */
+ int crypt_method_nr_from_name __ARGS((char_u *name));
+ int crypt_method_nr_from_magic __ARGS((char *ptr, int len));
+ int crypt_works_inplace __ARGS((cryptstate_T *state));
+ int crypt_get_method_nr __ARGS((buf_T *buf));
+ int crypt_whole_undofile __ARGS((int method_nr));
+ int crypt_get_header_len __ARGS((int method_nr));
+ void crypt_set_cm_option __ARGS((buf_T *buf, int method_nr));
+ int crypt_self_test __ARGS((void));
+ cryptstate_T *crypt_create __ARGS((int method_nr, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
+ cryptstate_T *crypt_create_from_header __ARGS((int method_nr, char_u *key, char_u *header));
+ cryptstate_T *crypt_create_from_file __ARGS((FILE *fp, char_u *key));
+ cryptstate_T *crypt_create_for_writing __ARGS((int method_nr, char_u *key, char_u **header, int *header_len));
+ void crypt_free_state __ARGS((cryptstate_T *state));
+ long crypt_encode_alloc __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u **newptr));
+ long crypt_decode_alloc __ARGS((cryptstate_T *state, char_u *ptr, long len, char_u **newptr));
+ void crypt_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
+ void crypt_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
+ void crypt_encode_inplace __ARGS((cryptstate_T *state, char_u *buf, size_t len));
+ void crypt_decode_inplace __ARGS((cryptstate_T *state, char_u *buf, size_t len));
+ void crypt_free_key __ARGS((char_u *key));
+ char_u *crypt_get_key __ARGS((int store, int twice));
+ void crypt_append_msg __ARGS((buf_T *buf));
+ /* vim: set ft=c : */
*** ../vim-7.4.398/src/proto/crypt_zip.pro	2014-08-10 13:30:43.884787293 +0200
--- src/proto/crypt_zip.pro	2014-08-09 15:31:32.501356185 +0200
***************
*** 0 ****
--- 1,5 ----
+ /* crypt_zip.c */
+ void crypt_zip_init __ARGS((cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
+ void crypt_zip_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
+ void crypt_zip_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
+ /* vim: set ft=c : */
*** ../vim-7.4.398/src/proto/fileio.pro	2013-08-10 13:37:11.000000000 +0200
--- src/proto/fileio.pro	2014-08-09 15:31:32.501356185 +0200
***************
*** 4,11 ****
  int prep_exarg __ARGS((exarg_T *eap, buf_T *buf));
  void set_file_options __ARGS((int set_options, exarg_T *eap));
  void set_forced_fenc __ARGS((exarg_T *eap));
- int prepare_crypt_read __ARGS((FILE *fp));
- char_u *prepare_crypt_write __ARGS((buf_T *buf, int *lenp));
  int check_file_readonly __ARGS((char_u *fname, int perm));
  int buf_write __ARGS((buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering));
  void msg_add_fname __ARGS((buf_T *buf, char_u *fname));
--- 4,9 ----
*** ../vim-7.4.398/src/proto/misc2.pro	2014-05-07 18:35:25.669216052 +0200
--- src/proto/misc2.pro	2014-08-09 15:31:32.501356185 +0200
***************
*** 84,99 ****
  char_u *parse_shape_opt __ARGS((int what));
  int get_shape_idx __ARGS((int mouse));
  void update_mouseshape __ARGS((int shape_idx));
- int crypt_method_from_string __ARGS((char_u *s));
- int get_crypt_method __ARGS((buf_T *buf));
- void set_crypt_method __ARGS((buf_T *buf, int method));
- void crypt_push_state __ARGS((void));
- void crypt_pop_state __ARGS((void));
- void crypt_encode __ARGS((char_u *from, size_t len, char_u *to));
- void crypt_decode __ARGS((char_u *ptr, long len));
- void crypt_init_keys __ARGS((char_u *passwd));
- void free_crypt_key __ARGS((char_u *key));
- char_u *get_crypt_key __ARGS((int store, int twice));
  void *vim_findfile_init __ARGS((char_u *path, char_u *filename, char_u *stopdirs, int level, int free_visited, int find_what, void *search_ctx_arg, int tagfile, char_u *rel_fname));
  char_u *vim_findfile_stopdir __ARGS((char_u *buf));
  void vim_findfile_cleanup __ARGS((void *ctx));
--- 84,89 ----
***************
*** 116,120 ****
--- 106,111 ----
  char_u *read_string __ARGS((FILE *fd, int cnt));
  int put_bytes __ARGS((FILE *fd, long_u nr, int len));
  void put_time __ARGS((FILE *fd, time_t the_time));
+ void time_to_bytes __ARGS((time_t the_time, char_u *buf));
  int has_non_ascii __ARGS((char_u *s));
  /* vim: set ft=c : */
*** ../vim-7.4.398/src/structs.h	2014-06-25 14:39:35.110348584 +0200
--- src/structs.h	2014-08-09 15:40:08.501352476 +0200
***************
*** 1251,1256 ****
--- 1251,1274 ----
  } syn_time_T;
  #endif
  
+ #ifdef FEAT_CRYPT
+ /*
+  * Structure to hold the type of encryption and the state of encryption or
+  * decryption.
+  */
+ typedef struct {
+     int	    method_nr;
+     void    *method_state;  /* method-specific state information */
+ } cryptstate_T;
+ 
+ /* values for method_nr */
+ # define CRYPT_M_ZIP	0
+ # define CRYPT_M_BF	1
+ # define CRYPT_M_BF2	2
+ # define CRYPT_M_COUNT	3 /* number of crypt methods */
+ #endif
+ 
+ 
  /*
   * These are items normally related to a buffer.  But when using ":ownsyntax"
   * a window may have its own instance.
***************
*** 1778,1784 ****
      int		b_was_netbeans_file;/* TRUE if b_netbeans_file was once set */
  #endif
  
! };
  
  
  #ifdef FEAT_DIFF
--- 1796,1807 ----
      int		b_was_netbeans_file;/* TRUE if b_netbeans_file was once set */
  #endif
  
! #ifdef FEAT_CRYPT
!     cryptstate_T *b_cryptstate;	/* Encryption state while reading or writing
! 				 * the file. NULL when not using encryption. */
! #endif
! 
! }; /* file_buffer */
  
  
  #ifdef FEAT_DIFF
*** ../vim-7.4.398/src/undo.c	2014-04-02 14:05:33.999887839 +0200
--- src/undo.c	2014-08-09 16:55:40.541319903 +0200
***************
*** 81,88 ****
--- 81,105 ----
  #define UH_MAGIC 0x18dade	/* value for uh_magic when in use */
  #define UE_MAGIC 0xabc123	/* value for ue_magic when in use */
  
+ /* Size of buffer used for encryption. */
+ #define CRYPT_BUF_SIZE 8192
+ 
  #include "vim.h"
  
+ /* Structure passed around between functions.
+  * Avoids passing cryptstate_T when encryption not available. */
+ typedef struct {
+     buf_T	*bi_buf;
+     FILE	*bi_fp;
+ #ifdef FEAT_CRYPT
+     cryptstate_T *bi_state;
+     char_u	*bi_buffer; /* CRYPT_BUF_SIZE, NULL when not buffering */
+     size_t	bi_used;    /* bytes written to/read from bi_buffer */
+     size_t	bi_avail;   /* bytes available in bi_buffer */
+ #endif
+ } bufinfo_T;
+ 
+ 
  static long get_undolevel __ARGS((void));
  static void u_unch_branch __ARGS((u_header_T *uhp));
  static u_entry_T *u_get_headentry __ARGS((void));
***************
*** 98,115 ****
  #ifdef FEAT_PERSISTENT_UNDO
  static void corruption_error __ARGS((char *mesg, char_u *file_name));
  static void u_free_uhp __ARGS((u_header_T *uhp));
! static size_t fwrite_crypt __ARGS((buf_T *buf UNUSED, char_u *ptr, size_t len, FILE *fp));
! static char_u *read_string_decrypt __ARGS((buf_T *buf UNUSED, FILE *fd, int len));
! static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash));
! static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp));
! static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name));
! static int serialize_uep __ARGS((FILE *fp, buf_T *buf, u_entry_T *uep));
! static u_entry_T *unserialize_uep __ARGS((FILE *fp, int *error, char_u *file_name));
! static void serialize_pos __ARGS((pos_T pos, FILE *fp));
! static void unserialize_pos __ARGS((pos_T *pos, FILE *fp));
! static void serialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp));
! static void unserialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp));
! static void put_header_ptr __ARGS((FILE	*fp, u_header_T *uhp));
  #endif
  
  #define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE)
--- 115,140 ----
  #ifdef FEAT_PERSISTENT_UNDO
  static void corruption_error __ARGS((char *mesg, char_u *file_name));
  static void u_free_uhp __ARGS((u_header_T *uhp));
! static int undo_write __ARGS((bufinfo_T *bi, char_u *ptr, size_t len));
! static int undo_flush __ARGS((bufinfo_T *bi));
! static int fwrite_crypt __ARGS((bufinfo_T *bi, char_u *ptr, size_t len));
! static int undo_write_bytes __ARGS((bufinfo_T *bi, long_u nr, int len));
! static void put_header_ptr __ARGS((bufinfo_T *bi, u_header_T *uhp));
! static int undo_read_4c __ARGS((bufinfo_T *bi));
! static int undo_read_2c __ARGS((bufinfo_T *bi));
! static int undo_read_byte __ARGS((bufinfo_T *bi));
! static time_t undo_read_time __ARGS((bufinfo_T *bi));
! static int undo_read __ARGS((bufinfo_T *bi, char_u *buffer, size_t size));
! static char_u *read_string_decrypt __ARGS((bufinfo_T *bi, int len));
! static int serialize_header __ARGS((bufinfo_T *bi, char_u *hash));
! static int serialize_uhp __ARGS((bufinfo_T *bi, u_header_T *uhp));
! static u_header_T *unserialize_uhp __ARGS((bufinfo_T *bi, char_u *file_name));
! static int serialize_uep __ARGS((bufinfo_T *bi, u_entry_T *uep));
! static u_entry_T *unserialize_uep __ARGS((bufinfo_T *bi, int *error, char_u *file_name));
! static void serialize_pos __ARGS((bufinfo_T *bi, pos_T pos));
! static void unserialize_pos __ARGS((bufinfo_T *bi, pos_T *pos));
! static void serialize_visualinfo __ARGS((bufinfo_T *bi, visualinfo_T *info));
! static void unserialize_visualinfo __ARGS((bufinfo_T *bi, visualinfo_T *info));
  #endif
  
  #define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE)
***************
*** 859,926 ****
  }
  
  /*
!  * Like fwrite() but crypt the bytes when 'key' is set.
!  * Returns 1 if successful.
   */
!     static size_t
! fwrite_crypt(buf, ptr, len, fp)
!     buf_T	*buf UNUSED;
      char_u	*ptr;
      size_t	len;
-     FILE	*fp;
  {
  #ifdef FEAT_CRYPT
      char_u  *copy;
      char_u  small_buf[100];
      size_t  i;
  
!     if (*buf->b_p_key == NUL)
! 	return fwrite(ptr, len, (size_t)1, fp);
!     if (len < 100)
! 	copy = small_buf;  /* no malloc()/free() for short strings */
!     else
      {
! 	copy = lalloc(len, FALSE);
! 	if (copy == NULL)
! 	    return 0;
!     }
!     crypt_encode(ptr, len, copy);
!     i = fwrite(copy, len, (size_t)1, fp);
!     if (copy != small_buf)
! 	vim_free(copy);
!     return i;
! #else
!     return fwrite(ptr, len, (size_t)1, fp);
  #endif
  }
  
  /*
!  * Read a string of length "len" from "fd".
!  * When 'key' is set decrypt the bytes.
   */
!     static char_u *
! read_string_decrypt(buf, fd, len)
!     buf_T   *buf UNUSED;
!     FILE    *fd;
      int	    len;
  {
!     char_u  *ptr;
  
!     ptr = read_string(fd, len);
  #ifdef FEAT_CRYPT
!     if (ptr != NULL && *buf->b_p_key != NUL)
! 	crypt_decode(ptr, len);
  #endif
      return ptr;
  }
  
      static int
! serialize_header(fp, buf, hash)
!     FILE	*fp;
!     buf_T	*buf;
      char_u	*hash;
  {
!     int len;
  
      /* Start writing, first the magic marker and undo info version. */
      if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1)
--- 884,1177 ----
  }
  
  /*
!  * Write a sequence of bytes to the undo file.
!  * Buffers and encrypts as needed.
!  * Returns OK or FAIL.
   */
!     static int
! undo_write(bi, ptr, len)
!     bufinfo_T	*bi;
!     char_u	*ptr;
!     size_t	len;
! {
! #ifdef FEAT_CRYPT
!     if (bi->bi_buffer != NULL)
!     {
! 	size_t	len_todo = len;
! 	char_u  *p = ptr;
! 
! 	while (bi->bi_used + len_todo >= CRYPT_BUF_SIZE)
! 	{
! 	    size_t	n = CRYPT_BUF_SIZE - bi->bi_used;
! 
! 	    mch_memmove(bi->bi_buffer + bi->bi_used, p, n);
! 	    len_todo -= n;
! 	    p += n;
! 	    bi->bi_used = CRYPT_BUF_SIZE;
! 	    if (undo_flush(bi) == FAIL)
! 		return FAIL;
! 	}
! 	if (len_todo > 0)
! 	{
! 	    mch_memmove(bi->bi_buffer + bi->bi_used, p, len_todo);
! 	    bi->bi_used += len_todo;
! 	}
! 	return OK;
!     }
! #endif
!     if (fwrite(ptr, len, (size_t)1, bi->bi_fp) != 1)
! 	return FAIL;
!     return OK;
! }
! 
! #ifdef FEAT_CRYPT
!     static int
! undo_flush(bi)
!     bufinfo_T	*bi;
! {
!     if (bi->bi_used > 0)
!     {
! 	crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used);
! 	if (fwrite(bi->bi_buffer, bi->bi_used, (size_t)1, bi->bi_fp) != 1)
! 	    return FAIL;
! 	bi->bi_used = 0;
!     }
!     return OK;
! }
! #endif
! 
! /*
!  * Write "ptr[len]" and crypt the bytes when needed.
!  * Returns OK or FAIL.
!  */
!     static int
! fwrite_crypt(bi, ptr, len)
!     bufinfo_T	*bi;
      char_u	*ptr;
      size_t	len;
  {
  #ifdef FEAT_CRYPT
      char_u  *copy;
      char_u  small_buf[100];
      size_t  i;
  
!     if (bi->bi_state != NULL && bi->bi_buffer == NULL)
      {
! 	/* crypting every piece of text separately */
! 	if (len < 100)
! 	    copy = small_buf;  /* no malloc()/free() for short strings */
! 	else
! 	{
! 	    copy = lalloc(len, FALSE);
! 	    if (copy == NULL)
! 		return 0;
! 	}
! 	crypt_encode(bi->bi_state, ptr, len, copy);
! 	i = fwrite(copy, len, (size_t)1, bi->bi_fp);
! 	if (copy != small_buf)
! 	    vim_free(copy);
! 	return i == 1 ? OK : FAIL;
!     }
  #endif
+     return undo_write(bi, ptr, len);
  }
  
  /*
!  * Write a number, MSB first, in "len" bytes.
!  * Must match with undo_read_?c() functions.
!  * Returns OK or FAIL.
   */
!     static int
! undo_write_bytes(bi, nr, len)
!     bufinfo_T *bi;
!     long_u  nr;
      int	    len;
  {
!     char_u  buf[8];
!     int	    i;
!     int	    bufi = 0;
! 
!     for (i = len - 1; i >= 0; --i)
! 	buf[bufi++] = nr >> (i * 8);
!     return undo_write(bi, buf, (size_t)len);
! }
! 
! /*
!  * Write the pointer to an undo header.  Instead of writing the pointer itself
!  * we use the sequence number of the header.  This is converted back to
!  * pointers when reading. */
!     static void
! put_header_ptr(bi, uhp)
!     bufinfo_T	*bi;
!     u_header_T	*uhp;
! {
!     undo_write_bytes(bi, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
! }
! 
!     static int
! undo_read_4c(bi)
!     bufinfo_T	*bi;
! {
! #ifdef FEAT_CRYPT
!     if (bi->bi_buffer != NULL)
!     {
! 	char_u  buf[4];
! 	int	n;
! 
! 	undo_read(bi, buf, (size_t)4);
! 	n = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
! 	return n;
!     }
! #endif
!     return get4c(bi->bi_fp);
! }
! 
!     static int
! undo_read_2c(bi)
!     bufinfo_T	*bi;
! {
! #ifdef FEAT_CRYPT
!     if (bi->bi_buffer != NULL)
!     {
! 	char_u  buf[2];
! 	int	n;
! 
! 	undo_read(bi, buf, (size_t)2);
! 	n = (buf[0] << 8) + buf[1];
! 	return n;
!     }
! #endif
!     return get2c(bi->bi_fp);
! }
! 
!     static int
! undo_read_byte(bi)
!     bufinfo_T	*bi;
! {
! #ifdef FEAT_CRYPT
!     if (bi->bi_buffer != NULL)
!     {
! 	char_u  buf[1];
! 
! 	undo_read(bi, buf, (size_t)1);
! 	return buf[0];
!     }
! #endif
!     return getc(bi->bi_fp);
! }
! 
!     static time_t
! undo_read_time(bi)
!     bufinfo_T	*bi;
! {
! #ifdef FEAT_CRYPT
!     if (bi->bi_buffer != NULL)
!     {
! 	char_u  buf[8];
! 	time_t	n = 0;
! 	int	i;
! 
! 	undo_read(bi, buf, (size_t)8);
! 	for (i = 0; i < 8; ++i)
! 	    n = (n << 8) + buf[i];
! 	return n;
!     }
! #endif
!     return get8ctime(bi->bi_fp);
! }
! 
! /*
!  * Read "buffer[size]" from the undo file.
!  * Return OK or FAIL.
!  */
!     static int
! undo_read(bi, buffer, size)
!     bufinfo_T   *bi;
!     char_u	*buffer;
!     size_t	size;
! {
! #ifdef FEAT_CRYPT
!     if (bi->bi_buffer != NULL)
!     {
! 	int	size_todo = size;
! 	char_u	*p = buffer;
! 
! 	while (size_todo > 0)
! 	{
! 	    size_t n;
! 
! 	    if (bi->bi_used >= bi->bi_avail)
! 	    {
! 		n = fread(bi->bi_buffer, 1, (size_t)CRYPT_BUF_SIZE, bi->bi_fp);
! 		if (n <= 0)
! 		{
! 		    /* Error may be checked for only later.  Fill with zeros,
! 		     * so that the reader won't use garbage. */
! 		    vim_memset(p, 0, size_todo);
! 		    return FAIL;
! 		}
! 		bi->bi_avail = n;
! 		bi->bi_used = 0;
! 		crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail);
! 	    }
! 	    n = size_todo;
! 	    if (n > bi->bi_avail - bi->bi_used)
! 		n = bi->bi_avail - bi->bi_used;
! 	    mch_memmove(p, bi->bi_buffer + bi->bi_used, n);
! 	    bi->bi_used += n;
! 	    size_todo -= n;
! 	    p += n;
! 	}
! 	return OK;
!     }
! #endif
!     if (fread(buffer, (size_t)size, 1, bi->bi_fp) != 1)
! 	return FAIL;
!     return OK;
! }
! 
! /*
!  * Read a string of length "len" from "bi->bi_fd".
!  * "len" can be zero to allocate an empty line.
!  * Decrypt the bytes if needed.
!  * Append a NUL.
!  * Returns a pointer to allocated memory or NULL for failure.
!  */
!     static char_u *
! read_string_decrypt(bi, len)
!     bufinfo_T	*bi;
!     int		len;
! {
!     char_u  *ptr = alloc((unsigned)len + 1);
  
!     if (ptr != NULL)
!     {
! 	if (len > 0 && undo_read(bi, ptr, len) == FAIL)
! 	{
! 	    vim_free(ptr);
! 	    return NULL;
! 	}
! 	ptr[len] = NUL;
  #ifdef FEAT_CRYPT
! 	if (bi->bi_state != NULL && bi->bi_buffer == NULL)
! 	    crypt_decode_inplace(bi->bi_state, ptr, len);
  #endif
+     }
      return ptr;
  }
  
+ /*
+  * Writes the (not encrypted) header and initializes encryption if needed.
+  */
      static int
! serialize_header(bi, hash)
!     bufinfo_T	*bi;
      char_u	*hash;
  {
!     int		len;
!     buf_T	*buf = bi->bi_buf;
!     FILE	*fp = bi->bi_fp;
!     char_u	time_buf[8];
  
      /* Start writing, first the magic marker and undo info version. */
      if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1)
***************
*** 934,1041 ****
  	char_u *header;
  	int    header_len;
  
! 	put_bytes(fp, (long_u)UF_VERSION_CRYPT, 2);
! 	header = prepare_crypt_write(buf, &header_len);
! 	if (header == NULL)
  	    return FAIL;
  	len = (int)fwrite(header, (size_t)header_len, (size_t)1, fp);
  	vim_free(header);
  	if (len != 1)
  	{
! 	    crypt_pop_state();
  	    return FAIL;
  	}
      }
      else
  #endif
! 	put_bytes(fp, (long_u)UF_VERSION, 2);
  
  
      /* Write a hash of the buffer text, so that we can verify it is still the
       * same when reading the buffer text. */
!     if (fwrite(hash, (size_t)UNDO_HASH_SIZE, (size_t)1, fp) != 1)
  	return FAIL;
  
      /* buffer-specific data */
!     put_bytes(fp, (long_u)buf->b_ml.ml_line_count, 4);
      len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0;
!     put_bytes(fp, (long_u)len, 4);
!     if (len > 0 && fwrite_crypt(buf, buf->b_u_line_ptr, (size_t)len, fp) != 1)
  	return FAIL;
!     put_bytes(fp, (long_u)buf->b_u_line_lnum, 4);
!     put_bytes(fp, (long_u)buf->b_u_line_colnr, 4);
  
      /* Undo structures header data */
!     put_header_ptr(fp, buf->b_u_oldhead);
!     put_header_ptr(fp, buf->b_u_newhead);
!     put_header_ptr(fp, buf->b_u_curhead);
! 
!     put_bytes(fp, (long_u)buf->b_u_numhead, 4);
!     put_bytes(fp, (long_u)buf->b_u_seq_last, 4);
!     put_bytes(fp, (long_u)buf->b_u_seq_cur, 4);
!     put_time(fp, buf->b_u_time_cur);
  
      /* Optional fields. */
!     putc(4, fp);
!     putc(UF_LAST_SAVE_NR, fp);
!     put_bytes(fp, (long_u)buf->b_u_save_nr_last, 4);
  
!     putc(0, fp);  /* end marker */
  
      return OK;
  }
  
      static int
! serialize_uhp(fp, buf, uhp)
!     FILE	*fp;
!     buf_T	*buf;
      u_header_T	*uhp;
  {
      int		i;
      u_entry_T	*uep;
  
!     if (put_bytes(fp, (long_u)UF_HEADER_MAGIC, 2) == FAIL)
  	return FAIL;
  
!     put_header_ptr(fp, uhp->uh_next.ptr);
!     put_header_ptr(fp, uhp->uh_prev.ptr);
!     put_header_ptr(fp, uhp->uh_alt_next.ptr);
!     put_header_ptr(fp, uhp->uh_alt_prev.ptr);
!     put_bytes(fp, uhp->uh_seq, 4);
!     serialize_pos(uhp->uh_cursor, fp);
  #ifdef FEAT_VIRTUALEDIT
!     put_bytes(fp, (long_u)uhp->uh_cursor_vcol, 4);
  #else
!     put_bytes(fp, (long_u)0, 4);
  #endif
!     put_bytes(fp, (long_u)uhp->uh_flags, 2);
      /* Assume NMARKS will stay the same. */
      for (i = 0; i < NMARKS; ++i)
! 	serialize_pos(uhp->uh_namedm[i], fp);
!     serialize_visualinfo(&uhp->uh_visual, fp);
!     put_time(fp, uhp->uh_time);
  
      /* Optional fields. */
!     putc(4, fp);
!     putc(UHP_SAVE_NR, fp);
!     put_bytes(fp, (long_u)uhp->uh_save_nr, 4);
  
!     putc(0, fp);  /* end marker */
  
      /* Write all the entries. */
      for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
      {
! 	put_bytes(fp, (long_u)UF_ENTRY_MAGIC, 2);
! 	if (serialize_uep(fp, buf, uep) == FAIL)
  	    return FAIL;
      }
!     put_bytes(fp, (long_u)UF_ENTRY_END_MAGIC, 2);
      return OK;
  }
  
      static u_header_T *
! unserialize_uhp(fp, file_name)
!     FILE	*fp;
      char_u	*file_name;
  {
      u_header_T	*uhp;
--- 1185,1308 ----
  	char_u *header;
  	int    header_len;
  
! 	undo_write_bytes(bi, (long_u)UF_VERSION_CRYPT, 2);
! 	bi->bi_state = crypt_create_for_writing(crypt_get_method_nr(buf),
! 					  buf->b_p_key, &header, &header_len);
! 	if (bi->bi_state == NULL)
  	    return FAIL;
  	len = (int)fwrite(header, (size_t)header_len, (size_t)1, fp);
  	vim_free(header);
  	if (len != 1)
  	{
! 	    crypt_free_state(bi->bi_state);
! 	    bi->bi_state = NULL;
  	    return FAIL;
  	}
+ 
+ 	if (crypt_whole_undofile(crypt_get_method_nr(buf)))
+ 	{
+ 	    bi->bi_buffer = alloc(CRYPT_BUF_SIZE);
+ 	    if (bi->bi_buffer == NULL)
+ 	    {
+ 		crypt_free_state(bi->bi_state);
+ 		bi->bi_state = NULL;
+ 		return FAIL;
+ 	    }
+ 	    bi->bi_used = 0;
+ 	}
      }
      else
  #endif
! 	undo_write_bytes(bi, (long_u)UF_VERSION, 2);
  
  
      /* Write a hash of the buffer text, so that we can verify it is still the
       * same when reading the buffer text. */
!     if (undo_write(bi, hash, (size_t)UNDO_HASH_SIZE) == FAIL)
  	return FAIL;
  
      /* buffer-specific data */
!     undo_write_bytes(bi, (long_u)buf->b_ml.ml_line_count, 4);
      len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0;
!     undo_write_bytes(bi, (long_u)len, 4);
!     if (len > 0 && fwrite_crypt(bi, buf->b_u_line_ptr, (size_t)len) == FAIL)
  	return FAIL;
!     undo_write_bytes(bi, (long_u)buf->b_u_line_lnum, 4);
!     undo_write_bytes(bi, (long_u)buf->b_u_line_colnr, 4);
  
      /* Undo structures header data */
!     put_header_ptr(bi, buf->b_u_oldhead);
!     put_header_ptr(bi, buf->b_u_newhead);
!     put_header_ptr(bi, buf->b_u_curhead);
! 
!     undo_write_bytes(bi, (long_u)buf->b_u_numhead, 4);
!     undo_write_bytes(bi, (long_u)buf->b_u_seq_last, 4);
!     undo_write_bytes(bi, (long_u)buf->b_u_seq_cur, 4);
!     time_to_bytes(buf->b_u_time_cur, time_buf);
!     undo_write(bi, time_buf, 8);
  
      /* Optional fields. */
!     undo_write_bytes(bi, 4, 1);
!     undo_write_bytes(bi, UF_LAST_SAVE_NR, 1);
!     undo_write_bytes(bi, (long_u)buf->b_u_save_nr_last, 4);
  
!     undo_write_bytes(bi, 0, 1);  /* end marker */
  
      return OK;
  }
  
      static int
! serialize_uhp(bi, uhp)
!     bufinfo_T	*bi;
      u_header_T	*uhp;
  {
      int		i;
      u_entry_T	*uep;
+     char_u	time_buf[8];
  
!     if (undo_write_bytes(bi, (long_u)UF_HEADER_MAGIC, 2) == FAIL)
  	return FAIL;
  
!     put_header_ptr(bi, uhp->uh_next.ptr);
!     put_header_ptr(bi, uhp->uh_prev.ptr);
!     put_header_ptr(bi, uhp->uh_alt_next.ptr);
!     put_header_ptr(bi, uhp->uh_alt_prev.ptr);
!     undo_write_bytes(bi, uhp->uh_seq, 4);
!     serialize_pos(bi, uhp->uh_cursor);
  #ifdef FEAT_VIRTUALEDIT
!     undo_write_bytes(bi, (long_u)uhp->uh_cursor_vcol, 4);
  #else
!     undo_write_bytes(bi, (long_u)0, 4);
  #endif
!     undo_write_bytes(bi, (long_u)uhp->uh_flags, 2);
      /* Assume NMARKS will stay the same. */
      for (i = 0; i < NMARKS; ++i)
! 	serialize_pos(bi, uhp->uh_namedm[i]);
!     serialize_visualinfo(bi, &uhp->uh_visual);
!     time_to_bytes(uhp->uh_time, time_buf);
!     undo_write(bi, time_buf, 8);
  
      /* Optional fields. */
!     undo_write_bytes(bi, 4, 1);
!     undo_write_bytes(bi, UHP_SAVE_NR, 1);
!     undo_write_bytes(bi, (long_u)uhp->uh_save_nr, 4);
  
!     undo_write_bytes(bi, 0, 1);  /* end marker */
  
      /* Write all the entries. */
      for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
      {
! 	undo_write_bytes(bi, (long_u)UF_ENTRY_MAGIC, 2);
! 	if (serialize_uep(bi, uep) == FAIL)
  	    return FAIL;
      }
!     undo_write_bytes(bi, (long_u)UF_ENTRY_END_MAGIC, 2);
      return OK;
  }
  
      static u_header_T *
! unserialize_uhp(bi, file_name)
!     bufinfo_T	*bi;
      char_u	*file_name;
  {
      u_header_T	*uhp;
***************
*** 1051,1106 ****
  #ifdef U_DEBUG
      uhp->uh_magic = UH_MAGIC;
  #endif
!     uhp->uh_next.seq = get4c(fp);
!     uhp->uh_prev.seq = get4c(fp);
!     uhp->uh_alt_next.seq = get4c(fp);
!     uhp->uh_alt_prev.seq = get4c(fp);
!     uhp->uh_seq = get4c(fp);
      if (uhp->uh_seq <= 0)
      {
  	corruption_error("uh_seq", file_name);
  	vim_free(uhp);
  	return NULL;
      }
!     unserialize_pos(&uhp->uh_cursor, fp);
  #ifdef FEAT_VIRTUALEDIT
!     uhp->uh_cursor_vcol = get4c(fp);
  #else
!     (void)get4c(fp);
  #endif
!     uhp->uh_flags = get2c(fp);
      for (i = 0; i < NMARKS; ++i)
! 	unserialize_pos(&uhp->uh_namedm[i], fp);
!     unserialize_visualinfo(&uhp->uh_visual, fp);
!     uhp->uh_time = get8ctime(fp);
  
      /* Optional fields. */
      for (;;)
      {
! 	int len = getc(fp);
  	int what;
  
  	if (len == 0)
  	    break;
! 	what = getc(fp);
  	switch (what)
  	{
  	    case UHP_SAVE_NR:
! 		uhp->uh_save_nr = get4c(fp);
  		break;
  	    default:
  		/* field not supported, skip */
  		while (--len >= 0)
! 		    (void)getc(fp);
  	}
      }
  
      /* Unserialize the uep list. */
      last_uep = NULL;
!     while ((c = get2c(fp)) == UF_ENTRY_MAGIC)
      {
  	error = FALSE;
! 	uep = unserialize_uep(fp, &error, file_name);
  	if (last_uep == NULL)
  	    uhp->uh_entry = uep;
  	else
--- 1318,1373 ----
  #ifdef U_DEBUG
      uhp->uh_magic = UH_MAGIC;
  #endif
!     uhp->uh_next.seq = undo_read_4c(bi);
!     uhp->uh_prev.seq = undo_read_4c(bi);
!     uhp->uh_alt_next.seq = undo_read_4c(bi);
!     uhp->uh_alt_prev.seq = undo_read_4c(bi);
!     uhp->uh_seq = undo_read_4c(bi);
      if (uhp->uh_seq <= 0)
      {
  	corruption_error("uh_seq", file_name);
  	vim_free(uhp);
  	return NULL;
      }
!     unserialize_pos(bi, &uhp->uh_cursor);
  #ifdef FEAT_VIRTUALEDIT
!     uhp->uh_cursor_vcol = undo_read_4c(bi);
  #else
!     (void)undo_read_4c(bi);
  #endif
!     uhp->uh_flags = undo_read_2c(bi);
      for (i = 0; i < NMARKS; ++i)
! 	unserialize_pos(bi, &uhp->uh_namedm[i]);
!     unserialize_visualinfo(bi, &uhp->uh_visual);
!     uhp->uh_time = undo_read_time(bi);
  
      /* Optional fields. */
      for (;;)
      {
! 	int len = undo_read_byte(bi);
  	int what;
  
  	if (len == 0)
  	    break;
! 	what = undo_read_byte(bi);
  	switch (what)
  	{
  	    case UHP_SAVE_NR:
! 		uhp->uh_save_nr = undo_read_4c(bi);
  		break;
  	    default:
  		/* field not supported, skip */
  		while (--len >= 0)
! 		    (void)undo_read_byte(bi);
  	}
      }
  
      /* Unserialize the uep list. */
      last_uep = NULL;
!     while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC)
      {
  	error = FALSE;
! 	uep = unserialize_uep(bi, &error, file_name);
  	if (last_uep == NULL)
  	    uhp->uh_entry = uep;
  	else
***************
*** 1123,1157 ****
  }
  
  /*
!  * Serialize "uep" to "fp".
   */
      static int
! serialize_uep(fp, buf, uep)
!     FILE	*fp;
!     buf_T	*buf;
      u_entry_T	*uep;
  {
      int		i;
      size_t	len;
  
!     put_bytes(fp, (long_u)uep->ue_top, 4);
!     put_bytes(fp, (long_u)uep->ue_bot, 4);
!     put_bytes(fp, (long_u)uep->ue_lcount, 4);
!     put_bytes(fp, (long_u)uep->ue_size, 4);
      for (i = 0; i < uep->ue_size; ++i)
      {
  	len = STRLEN(uep->ue_array[i]);
! 	if (put_bytes(fp, (long_u)len, 4) == FAIL)
  	    return FAIL;
! 	if (len > 0 && fwrite_crypt(buf, uep->ue_array[i], len, fp) != 1)
  	    return FAIL;
      }
      return OK;
  }
  
      static u_entry_T *
! unserialize_uep(fp, error, file_name)
!     FILE	*fp;
      int		*error;
      char_u	*file_name;
  {
--- 1390,1423 ----
  }
  
  /*
!  * Serialize "uep".
   */
      static int
! serialize_uep(bi, uep)
!     bufinfo_T	*bi;
      u_entry_T	*uep;
  {
      int		i;
      size_t	len;
  
!     undo_write_bytes(bi, (long_u)uep->ue_top, 4);
!     undo_write_bytes(bi, (long_u)uep->ue_bot, 4);
!     undo_write_bytes(bi, (long_u)uep->ue_lcount, 4);
!     undo_write_bytes(bi, (long_u)uep->ue_size, 4);
      for (i = 0; i < uep->ue_size; ++i)
      {
  	len = STRLEN(uep->ue_array[i]);
! 	if (undo_write_bytes(bi, (long_u)len, 4) == FAIL)
  	    return FAIL;
! 	if (len > 0 && fwrite_crypt(bi, uep->ue_array[i], len) == FAIL)
  	    return FAIL;
      }
      return OK;
  }
  
      static u_entry_T *
! unserialize_uep(bi, error, file_name)
!     bufinfo_T	*bi;
      int		*error;
      char_u	*file_name;
  {
***************
*** 1168,1177 ****
  #ifdef U_DEBUG
      uep->ue_magic = UE_MAGIC;
  #endif
!     uep->ue_top = get4c(fp);
!     uep->ue_bot = get4c(fp);
!     uep->ue_lcount = get4c(fp);
!     uep->ue_size = get4c(fp);
      if (uep->ue_size > 0)
      {
  	array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size);
--- 1434,1443 ----
  #ifdef U_DEBUG
      uep->ue_magic = UE_MAGIC;
  #endif
!     uep->ue_top = undo_read_4c(bi);
!     uep->ue_bot = undo_read_4c(bi);
!     uep->ue_lcount = undo_read_4c(bi);
!     uep->ue_size = undo_read_4c(bi);
      if (uep->ue_size > 0)
      {
  	array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size);
***************
*** 1188,1196 ****
  
      for (i = 0; i < uep->ue_size; ++i)
      {
! 	line_len = get4c(fp);
  	if (line_len >= 0)
! 	    line = read_string_decrypt(curbuf, fp, line_len);
  	else
  	{
  	    line = NULL;
--- 1454,1462 ----
  
      for (i = 0; i < uep->ue_size; ++i)
      {
! 	line_len = undo_read_4c(bi);
  	if (line_len >= 0)
! 	    line = read_string_decrypt(bi, line_len);
  	else
  	{
  	    line = NULL;
***************
*** 1207,1289 ****
  }
  
  /*
!  * Serialize "pos" to "fp".
   */
      static void
! serialize_pos(pos, fp)
      pos_T pos;
-     FILE  *fp;
  {
!     put_bytes(fp, (long_u)pos.lnum, 4);
!     put_bytes(fp, (long_u)pos.col, 4);
  #ifdef FEAT_VIRTUALEDIT
!     put_bytes(fp, (long_u)pos.coladd, 4);
  #else
!     put_bytes(fp, (long_u)0, 4);
  #endif
  }
  
  /*
!  * Unserialize the pos_T at the current position in fp.
   */
      static void
! unserialize_pos(pos, fp)
      pos_T *pos;
-     FILE  *fp;
  {
!     pos->lnum = get4c(fp);
      if (pos->lnum < 0)
  	pos->lnum = 0;
!     pos->col = get4c(fp);
      if (pos->col < 0)
  	pos->col = 0;
  #ifdef FEAT_VIRTUALEDIT
!     pos->coladd = get4c(fp);
      if (pos->coladd < 0)
  	pos->coladd = 0;
  #else
!     (void)get4c(fp);
  #endif
  }
  
  /*
!  * Serialize "info" to "fp".
   */
      static void
! serialize_visualinfo(info, fp)
      visualinfo_T    *info;
-     FILE	    *fp;
  {
!     serialize_pos(info->vi_start, fp);
!     serialize_pos(info->vi_end, fp);
!     put_bytes(fp, (long_u)info->vi_mode, 4);
!     put_bytes(fp, (long_u)info->vi_curswant, 4);
  }
  
  /*
!  * Unserialize the visualinfo_T at the current position in fp.
   */
      static void
! unserialize_visualinfo(info, fp)
      visualinfo_T    *info;
-     FILE	    *fp;
- {
-     unserialize_pos(&info->vi_start, fp);
-     unserialize_pos(&info->vi_end, fp);
-     info->vi_mode = get4c(fp);
-     info->vi_curswant = get4c(fp);
- }
- 
- /*
-  * Write the pointer to an undo header.  Instead of writing the pointer itself
-  * we use the sequence number of the header.  This is converted back to
-  * pointers when reading. */
-     static void
- put_header_ptr(fp, uhp)
-     FILE	*fp;
-     u_header_T	*uhp;
  {
!     put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
  }
  
  /*
--- 1473,1543 ----
  }
  
  /*
!  * Serialize "pos".
   */
      static void
! serialize_pos(bi, pos)
!     bufinfo_T *bi;
      pos_T pos;
  {
!     undo_write_bytes(bi, (long_u)pos.lnum, 4);
!     undo_write_bytes(bi, (long_u)pos.col, 4);
  #ifdef FEAT_VIRTUALEDIT
!     undo_write_bytes(bi, (long_u)pos.coladd, 4);
  #else
!     undo_write_bytes(bi, (long_u)0, 4);
  #endif
  }
  
  /*
!  * Unserialize the pos_T at the current position.
   */
      static void
! unserialize_pos(bi, pos)
!     bufinfo_T *bi;
      pos_T *pos;
  {
!     pos->lnum = undo_read_4c(bi);
      if (pos->lnum < 0)
  	pos->lnum = 0;
!     pos->col = undo_read_4c(bi);
      if (pos->col < 0)
  	pos->col = 0;
  #ifdef FEAT_VIRTUALEDIT
!     pos->coladd = undo_read_4c(bi);
      if (pos->coladd < 0)
  	pos->coladd = 0;
  #else
!     (void)undo_read_4c(bi);
  #endif
  }
  
  /*
!  * Serialize "info".
   */
      static void
! serialize_visualinfo(bi, info)
!     bufinfo_T	    *bi;
      visualinfo_T    *info;
  {
!     serialize_pos(bi, info->vi_start);
!     serialize_pos(bi, info->vi_end);
!     undo_write_bytes(bi, (long_u)info->vi_mode, 4);
!     undo_write_bytes(bi, (long_u)info->vi_curswant, 4);
  }
  
  /*
!  * Unserialize the visualinfo_T at the current position.
   */
      static void
! unserialize_visualinfo(bi, info)
!     bufinfo_T	    *bi;
      visualinfo_T    *info;
  {
!     unserialize_pos(bi, &info->vi_start);
!     unserialize_pos(bi, &info->vi_end);
!     info->vi_mode = undo_read_4c(bi);
!     info->vi_curswant = undo_read_4c(bi);
  }
  
  /*
***************
*** 1317,1324 ****
      struct stat	st_old;
      struct stat	st_new;
  #endif
  #ifdef FEAT_CRYPT
!     int		do_crypt = FALSE;
  #endif
  
      if (name == NULL)
--- 1571,1581 ----
      struct stat	st_old;
      struct stat	st_new;
  #endif
+     bufinfo_T	bi;
+ 
  #ifdef FEAT_CRYPT
!     bi.bi_state = NULL;
!     bi.bi_buffer = NULL;
  #endif
  
      if (name == NULL)
***************
*** 1474,1487 ****
      u_sync(TRUE);
  
      /*
!      * Write the header.
       */
!     if (serialize_header(fp, buf, hash) == FAIL)
  	goto write_error;
- #ifdef FEAT_CRYPT
-     if (*buf->b_p_key != NUL)
- 	do_crypt = TRUE;
- #endif
  
      /*
       * Iteratively serialize UHPs and their UEPs from the top down.
--- 1731,1742 ----
      u_sync(TRUE);
  
      /*
!      * Write the header.  Initializes encryption, if enabled.
       */
!     bi.bi_buf = buf;
!     bi.bi_fp = fp;
!     if (serialize_header(&bi, hash) == FAIL)
  	goto write_error;
  
      /*
       * Iteratively serialize UHPs and their UEPs from the top down.
***************
*** 1497,1503 ****
  #ifdef U_DEBUG
  	    ++headers_written;
  #endif
! 	    if (serialize_uhp(fp, buf, uhp) == FAIL)
  		goto write_error;
  	}
  
--- 1752,1758 ----
  #ifdef U_DEBUG
  	    ++headers_written;
  #endif
! 	    if (serialize_uhp(&bi, uhp) == FAIL)
  		goto write_error;
  	}
  
***************
*** 1516,1522 ****
  	    uhp = uhp->uh_next.ptr;
      }
  
!     if (put_bytes(fp, (long_u)UF_HEADER_END_MAGIC, 2) == OK)
  	write_ok = TRUE;
  #ifdef U_DEBUG
      if (headers_written != buf->b_u_numhead)
--- 1771,1777 ----
  	    uhp = uhp->uh_next.ptr;
      }
  
!     if (undo_write_bytes(&bi, (long_u)UF_HEADER_END_MAGIC, 2) == OK)
  	write_ok = TRUE;
  #ifdef U_DEBUG
      if (headers_written != buf->b_u_numhead)
***************
*** 1526,1531 ****
--- 1781,1791 ----
      }
  #endif
  
+ #ifdef FEAT_CRYPT
+     if (bi.bi_state != NULL && undo_flush(&bi) == FAIL)
+ 	write_ok = FALSE;
+ #endif
+ 
  write_error:
      fclose(fp);
      if (!write_ok)
***************
*** 1551,1558 ****
  
  theend:
  #ifdef FEAT_CRYPT
!     if (do_crypt)
! 	crypt_pop_state();
  #endif
      if (file_name != name)
  	vim_free(file_name);
--- 1811,1819 ----
  
  theend:
  #ifdef FEAT_CRYPT
!     if (bi.bi_state != NULL)
! 	crypt_free_state(bi.bi_state);
!     vim_free(bi.bi_buffer);
  #endif
      if (file_name != name)
  	vim_free(file_name);
***************
*** 1598,1606 ****
      struct stat	st_orig;
      struct stat	st_undo;
  #endif
! #ifdef FEAT_CRYPT
!     int		do_decrypt = FALSE;
! #endif
  
      if (name == NULL)
      {
--- 1859,1865 ----
      struct stat	st_orig;
      struct stat	st_undo;
  #endif
!     bufinfo_T	bi;
  
      if (name == NULL)
      {
***************
*** 1644,1649 ****
--- 1903,1914 ----
  	    EMSG2(_("E822: Cannot open undo file for reading: %s"), file_name);
  	goto error;
      }
+     bi.bi_buf = curbuf;
+     bi.bi_fp = fp;
+ #ifdef FEAT_CRYPT
+     bi.bi_state = NULL;
+     bi.bi_buffer = NULL;
+ #endif
  
      /*
       * Read the undo file header.
***************
*** 1664,1675 ****
  								   file_name);
  	    goto error;
  	}
! 	if (prepare_crypt_read(fp) == FAIL)
  	{
  	    EMSG2(_("E826: Undo file decryption failed: %s"), file_name);
  	    goto error;
  	}
! 	do_decrypt = TRUE;
  #else
  	EMSG2(_("E827: Undo file is encrypted: %s"), file_name);
  	goto error;
--- 1929,1952 ----
  								   file_name);
  	    goto error;
  	}
! 	bi.bi_state = crypt_create_from_file(fp, curbuf->b_p_key);
! 	if (bi.bi_state == NULL)
  	{
  	    EMSG2(_("E826: Undo file decryption failed: %s"), file_name);
  	    goto error;
  	}
! 	if (crypt_whole_undofile(bi.bi_state->method_nr))
! 	{
! 	    bi.bi_buffer = alloc(CRYPT_BUF_SIZE);
! 	    if (bi.bi_buffer == NULL)
! 	    {
! 		crypt_free_state(bi.bi_state);
! 		bi.bi_state = NULL;
! 		goto error;
! 	    }
! 	    bi.bi_avail = 0;
! 	    bi.bi_used = 0;
! 	}
  #else
  	EMSG2(_("E827: Undo file is encrypted: %s"), file_name);
  	goto error;
***************
*** 1681,1692 ****
  	goto error;
      }
  
!     if (fread(read_hash, UNDO_HASH_SIZE, 1, fp) != 1)
      {
  	corruption_error("hash", file_name);
  	goto error;
      }
!     line_count = (linenr_T)get4c(fp);
      if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
  				  || line_count != curbuf->b_ml.ml_line_count)
      {
--- 1958,1969 ----
  	goto error;
      }
  
!     if (undo_read(&bi, read_hash, (size_t)UNDO_HASH_SIZE) == FAIL)
      {
  	corruption_error("hash", file_name);
  	goto error;
      }
!     line_count = (linenr_T)undo_read_4c(&bi);
      if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
  				  || line_count != curbuf->b_ml.ml_line_count)
      {
***************
*** 1703,1715 ****
      }
  
      /* Read undo data for "U" command. */
!     str_len = get4c(fp);
      if (str_len < 0)
  	goto error;
      if (str_len > 0)
! 	line_ptr = read_string_decrypt(curbuf, fp, str_len);
!     line_lnum = (linenr_T)get4c(fp);
!     line_colnr = (colnr_T)get4c(fp);
      if (line_lnum < 0 || line_colnr < 0)
      {
  	corruption_error("line lnum/col", file_name);
--- 1980,1992 ----
      }
  
      /* Read undo data for "U" command. */
!     str_len = undo_read_4c(&bi);
      if (str_len < 0)
  	goto error;
      if (str_len > 0)
! 	line_ptr = read_string_decrypt(&bi, str_len);
!     line_lnum = (linenr_T)undo_read_4c(&bi);
!     line_colnr = (colnr_T)undo_read_4c(&bi);
      if (line_lnum < 0 || line_colnr < 0)
      {
  	corruption_error("line lnum/col", file_name);
***************
*** 1717,1748 ****
      }
  
      /* Begin general undo data */
!     old_header_seq = get4c(fp);
!     new_header_seq = get4c(fp);
!     cur_header_seq = get4c(fp);
!     num_head = get4c(fp);
!     seq_last = get4c(fp);
!     seq_cur = get4c(fp);
!     seq_time = get8ctime(fp);
  
      /* Optional header fields. */
      for (;;)
      {
! 	int len = getc(fp);
  	int what;
  
  	if (len == 0 || len == EOF)
  	    break;
! 	what = getc(fp);
  	switch (what)
  	{
  	    case UF_LAST_SAVE_NR:
! 		last_save_nr = get4c(fp);
  		break;
  	    default:
  		/* field not supported, skip */
  		while (--len >= 0)
! 		    (void)getc(fp);
  	}
      }
  
--- 1994,2025 ----
      }
  
      /* Begin general undo data */
!     old_header_seq = undo_read_4c(&bi);
!     new_header_seq = undo_read_4c(&bi);
!     cur_header_seq = undo_read_4c(&bi);
!     num_head = undo_read_4c(&bi);
!     seq_last = undo_read_4c(&bi);
!     seq_cur = undo_read_4c(&bi);
!     seq_time = undo_read_time(&bi);
  
      /* Optional header fields. */
      for (;;)
      {
! 	int len = undo_read_byte(&bi);
  	int what;
  
  	if (len == 0 || len == EOF)
  	    break;
! 	what = undo_read_byte(&bi);
  	switch (what)
  	{
  	    case UF_LAST_SAVE_NR:
! 		last_save_nr = undo_read_4c(&bi);
  		break;
  	    default:
  		/* field not supported, skip */
  		while (--len >= 0)
! 		    (void)undo_read_byte(&bi);
  	}
      }
  
***************
*** 1758,1764 ****
  	    goto error;
      }
  
!     while ((c = get2c(fp)) == UF_HEADER_MAGIC)
      {
  	if (num_read_uhps >= num_head)
  	{
--- 2035,2041 ----
  	    goto error;
      }
  
!     while ((c = undo_read_2c(&bi)) == UF_HEADER_MAGIC)
      {
  	if (num_read_uhps >= num_head)
  	{
***************
*** 1766,1772 ****
  	    goto error;
  	}
  
! 	uhp = unserialize_uhp(fp, file_name);
  	if (uhp == NULL)
  	    goto error;
  	uhp_table[num_read_uhps++] = uhp;
--- 2043,2049 ----
  	    goto error;
  	}
  
! 	uhp = unserialize_uhp(&bi, file_name);
  	if (uhp == NULL)
  	    goto error;
  	uhp_table[num_read_uhps++] = uhp;
***************
*** 1898,1905 ****
  
  theend:
  #ifdef FEAT_CRYPT
!     if (do_decrypt)
! 	crypt_pop_state();
  #endif
      if (fp != NULL)
  	fclose(fp);
--- 2175,2183 ----
  
  theend:
  #ifdef FEAT_CRYPT
!     if (bi.bi_state != NULL)
! 	crypt_free_state(bi.bi_state);
!     vim_free(bi.bi_buffer);
  #endif
      if (fp != NULL)
  	fclose(fp);
*** ../vim-7.4.398/src/testdir/test71.in	2013-07-01 20:47:58.000000000 +0200
--- src/testdir/test71.in	2014-08-09 15:12:57.997364196 +0200
***************
*** 13,18 ****
--- 13,20 ----
  :let cm0_bytes = getline('.', '.')
  :/^start of cm=blowfish bytes/+1
  :let cm1_bytes = getline('.', '.')
+ :/^start of cm=blowfish2 bytes/+1
+ :let cm2_bytes = getline('.', '.')
  :bwipe!
  :call append(0, text_lines)
  :$d
***************
*** 36,41 ****
--- 38,55 ----
  :e Xtestfile
  barfoo
  :let cm1_read_back = getline('.', '$')
+ :set key=
+ :set cryptmethod=blowfish2
+ :" If the blowfish test fails 'cryptmethod' will be 'zip' now.
+ :%s/^/\=&cryptmethod == 'blowfish2' ? "OK " : "blowfish test failed "/
+ :X
+ bar2foo
+ bar2foo
+ :w! Xtestfile
+ :bwipe!
+ :e Xtestfile
+ bar2foo
+ :let cm2_read_back = getline('.', '$')
  :bwipe!
  :set bin noeol key=
  :call append(0, cm0_bytes)
***************
*** 57,63 ****
--- 71,90 ----
  :set nobin
  :e Xtestfile
  barbar
+ :let cm1_read_bin = getline('.', '$')
+ :bwipe!
+ :set bin noeol key=
+ :call append(0, cm2_bytes)
+ :$d
+ :set fenc=latin1
+ :w! Xtestfile
+ :bwipe!
+ :set nobin
+ :e Xtestfile
+ barburp
+ :call append(0, cm1_read_bin)
  :call append(0, cm0_read_bin)
+ :call append(0, cm2_read_back)
  :call append(0, cm1_read_back)
  :call append(0, cm0_read_back)
  :set key= fenc=latin1
*** ../vim-7.4.398/src/testdir/test72.in	2014-03-12 16:51:35.060792541 +0100
--- src/testdir/test72.in	2014-08-09 15:12:58.001364196 +0200
***************
*** 81,86 ****
--- 81,87 ----
  :"
  :" With encryption, cryptmethod=blowfish
  :e! Xtestfile
+ rubbish
  :set undofile cm=blowfish
  ggdGijan
  feb
***************
*** 100,105 ****
--- 101,132 ----
  :set key=
  /bar
  :.w >>test.out
+ u:.w >>test.out
+ u:.w >>test.out
+ u:.w >>test.out
+ :"
+ :" With encryption, cryptmethod=blowfish2
+ :e! Xtestfile
+ rubbish
+ :set undofile cm=blowfish2
+ ggdGijan
+ feb
+ mar
+ apr
+ jun:set ul=100
+ kk0ifoo :set ul=100
+ dd:set ul=100
+ ibar :set ul=100
+ :X
+ foo2bar
+ foo2bar
+ :w!
+ :bwipe!
+ :e Xtestfile
+ foo2bar
+ :set key=
+ /bar
+ :.w >>test.out
  u:.w >>test.out
  u:.w >>test.out
  u:.w >>test.out
*** ../vim-7.4.398/src/testdir/test72.ok	2012-01-04 19:04:17.000000000 +0100
--- src/testdir/test72.ok	2014-08-09 15:12:58.001364196 +0200
***************
*** 25,27 ****
--- 25,31 ----
  apr
  foo mar
  mar
+ bar apr
+ apr
+ foo mar
+ mar
diff -up src/testdir/test71.ok.kh src/testdir/test71.ok
--- src/testdir/test71.ok.kh	2014-08-12 14:21:33.301002125 +0200
+++ src/testdir/test71.ok	2014-08-12 14:21:06.140002788 +0200
@@ -4,7 +4,12 @@ line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 OK 01234567890123456789012345678901234567
 OK line 2  foo bar blah
 OK line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+OK OK 01234567890123456789012345678901234567
+OK OK line 2  foo bar blah
+OK OK line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 1234567890
 aábbccddeëff
 asdfasdfasdf
 0001112223333
+abcdefghijklmnopqrstuvwxyz
+!@#$%^&*()_+=-`~
diff -up src/testdir/test71a.in.kh src/testdir/test71a.in
--- src/testdir/test71a.in.kh	2014-08-12 14:27:34.429993316 +0200
+++ src/testdir/test71a.in	2014-08-12 14:26:40.114994641 +0200
@@ -12,3 +12,7 @@ end of cm=zip bytes
 start of cm=blowfish bytes
 VimCrypt~02!k)¾—#İSœõ=ºàÈ#¥M´†JÃAÍ¥M´†!€›õáÒ‚˜÷
Ú
 end of cm=blowfish bytes
+
+start of cm=blowfish2 bytes
+VimCrypt~03!ÑNã;ÓÀ ^C)÷.¶«FSà‹6Ò[T˧…ؾ92Q³Ì@—ߚ­Ivª.ØÉîž`½$¯%Ð
+end of cm=blowfish2 bytes
*** ../vim-7.4.398/src/version.c	2014-08-07 13:55:05.898639758 +0200
--- src/version.c	2014-08-09 15:11:28.665364838 +0200
***************
*** 743,744 ****
--- 743,746 ----
  {   /* Add new patch number below this line */
+ /**/
+     399,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
16. You step out of your room and realize that your parents have moved and
    you don't have a clue when it happened.

 /// Bram Moolenaar -- Bram@Moolenaar.net -- 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    ///