changeset 2180:f60a0c9cbe6c vim73

Add the blowfish encryption patch from Mohsin Ahmed. Needs more work.
author Bram Moolenaar <bram@vim.org>
date Sun, 16 May 2010 22:32:54 +0200
parents c6f1aa1e9f32
children 3cb515c62e9c
files Filelist runtime/doc/editing.txt runtime/doc/options.txt runtime/doc/todo.txt src/Make_bc5.mak src/Make_ivc.mak src/Make_manx.mak src/Make_mvc.mak src/Make_sas.mak src/Makefile src/blowfish.c src/ex_docmd.c src/feature.h src/fileio.c src/globals.h src/main.c src/misc2.c src/option.c src/option.h src/proto.h src/proto/blowfish.pro src/proto/misc2.pro src/proto/sha256.pro src/sha256.c src/structs.h src/testdir/Make_dos.mak src/testdir/Make_ming.mak src/testdir/Makefile src/testdir/test71.in src/testdir/test71.ok
diffstat 30 files changed, 1309 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/Filelist
+++ b/Filelist
@@ -7,6 +7,7 @@ SRC_ALL =	\
 		src/arabic.c \
 		src/arabic.h \
 		src/ascii.h \
+		src/blowfish.c \
 		src/buffer.c \
 		src/charset.c \
 		src/diff.c \
@@ -58,6 +59,7 @@ SRC_ALL =	\
 		src/regexp.h \
 		src/screen.c \
 		src/search.c \
+		src/sha256.c \
 		src/structs.h \
 		src/spell.c \
 		src/syntax.c \
@@ -79,6 +81,7 @@ SRC_ALL =	\
 		src/testdir/test49.vim \
 		src/testdir/test60.vim \
 		src/proto.h \
+		src/proto/blowfish.pro \
 		src/proto/buffer.pro \
 		src/proto/charset.pro \
 		src/proto/diff.pro \
@@ -116,6 +119,7 @@ SRC_ALL =	\
 		src/proto/regexp.pro \
 		src/proto/screen.pro \
 		src/proto/search.pro \
+		src/proto/sha256.pro \
 		src/proto/spell.pro \
 		src/proto/syntax.pro \
 		src/proto/tag.pro \
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1361,6 +1361,11 @@ the file is encrypted.
 To disable the encryption, reset the 'key' option to an empty value: >
 	:set key=
 
+You can use the 'cryptmethod' option to select the type of encryption.  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.
+
 When reading a file that has been encrypted and this option is not empty, it
 will be used for decryption.  If the value is empty, you will be prompted to
 enter the key.  If you don't enter a key, the file is edited without being
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2049,6 +2049,19 @@ A jump table for the options with a shor
 			with system specific functions.
 
 
+						*'cryptmethod'* *'cm'*
+'cryptmethod'		number	(default 0)
+			local to buffer
+			{not in Vi}
+	Method used for encryption when the buffer is written to a file:
+		0	PkZip compatible method.  A weak kind of encryption.
+			backwards compatible with Vim 7.2 and older.
+		1	Blowfish method.  Strong encryption.  Not compatible
+			with Vim 7.2 and older.
+	When reading an encrypted file 'cryptmethod' will be set automatically
+	to detected method for the file being read.
+
+
 						*'cscopepathcomp'* *'cspc'*
 'cscopepathcomp' 'cspc'	number	(default 0)
 			global
@@ -4141,7 +4154,7 @@ A jump table for the options with a shor
 			local to buffer
 			{not in Vi}
 	The key that is used for encrypting and decrypting the current buffer.
-	See |encryption|.
+	See |encryption| and 'cryptmethod'.
 	Careful: Do not set the key value by hand, someone might see the typed
 	key.  Use the |:X| command.  But you can make 'key' empty: >
 		:set key=
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -30,6 +30,17 @@ be worked on, but only if you sponsor Vi
 							*known-bugs*
 -------------------- Known bugs and current work -----------------------
 
+check blowfish.c
+check sha256.c
+Use 'cm' option only when FEAT_CRYPT is defined.
+When not full match with magic, check for head and give warning about
+unsupported crypt method.
+if 'enc' is ucs-2, does utf-8 to ucs-2 encoding always work for seed?
+
+Crypt update:
+- move bf_self_test() and sha256_self_test() elsewhere
+- Update E000 to error number.
+
 Cursor positioning wrong with 0x200e character. (John Becket, 2010 May 6)
 
 E315 when trying to change a file in FileChangedRO autocommand event.
@@ -1082,8 +1093,6 @@ restored. (Luc St-Louis)
 
 Vim 7.3:
 Patches to include:
--   Add patch for 'relativenumber' option?  Markus Heidelberg, 2008 Jun 27.
-    Update 2010 May 2.
 -   Add blowfish encryption.  Openssl has an implementation.  Also by Paul
     Kocher (LGPL), close to original.  Mohsin also has some ideas.
     Take four bytes and turn them into unsigned to avoid byte-order problems.
--- a/src/Make_bc5.mak
+++ b/src/Make_bc5.mak
@@ -533,6 +533,7 @@ vimwinmain = \
 !endif
 
 vimobj =  \
+	$(OBJDIR)\blowfish.obj \
 	$(OBJDIR)\buffer.obj \
 	$(OBJDIR)\charset.obj \
 	$(OBJDIR)\diff.obj \
@@ -567,6 +568,7 @@ vimobj =  \
 	$(OBJDIR)\regexp.obj \
 	$(OBJDIR)\screen.obj \
 	$(OBJDIR)\search.obj \
+	$(OBJDIR)\sha256.obj \
 	$(OBJDIR)\spell.obj \
 	$(OBJDIR)\syntax.obj \
 	$(OBJDIR)\tag.obj \
--- a/src/Make_ivc.mak
+++ b/src/Make_ivc.mak
@@ -210,6 +210,7 @@ ALL : .\$(VIM).exe vimrun.exe install.ex
 
 LINK32_OBJS= \
 	$(EXTRAS) \
+	"$(INTDIR)/blowfish.obj" \
 	"$(INTDIR)/buffer.obj" \
 	"$(INTDIR)/charset.obj" \
 	"$(INTDIR)/diff.obj" \
@@ -246,6 +247,7 @@ LINK32_OBJS= \
 	"$(INTDIR)/regexp.obj" \
 	"$(INTDIR)/screen.obj" \
 	"$(INTDIR)/search.obj" \
+	"$(INTDIR)/sha256.obj" \
 	"$(INTDIR)/spell.obj" \
 	"$(INTDIR)/syntax.obj" \
 	"$(INTDIR)/tag.obj" \
--- a/src/Make_manx.mak
+++ b/src/Make_manx.mak
@@ -124,7 +124,8 @@ OBJ =	obj/buffer.o \
 	obj/window.o \
 	$(TERMLIB)
 
-PRO =	proto/buffer.pro \
+PRO =	proto/blowfish.pro \
+	proto/buffer.pro \
 	proto/charset.pro \
 	proto/diff.pro \
 	proto/digraph.pro \
@@ -159,6 +160,7 @@ PRO =	proto/buffer.pro \
 	proto/regexp.pro \
 	proto/screen.pro \
 	proto/search.pro \
+	proto/sha256.pro \
 	proto/spell.pro \
 	proto/syntax.pro \
 	proto/tag.pro \
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -453,6 +453,8 @@ INCL =	vim.h os_win32.h ascii.h feature.
 	$(NBDEBUG_INCL)
 
 OBJ = \
+	$(OUTDIR)\blowfish.obj \
+	$(OUTDIR)\sha256.obj \
 	$(OUTDIR)\buffer.obj \
 	$(OUTDIR)\charset.obj \
 	$(OUTDIR)\diff.obj \
@@ -912,6 +914,10 @@ testclean:
 
 $(OUTDIR)/buffer.obj:	$(OUTDIR) buffer.c  $(INCL)
 
+$(OUTDIR)/blowfish.obj:	$(OUTDIR) blowfish.c  $(INCL)
+
+$(OUTDIR)/sha256.obj:	$(OUTDIR) sha256.c  $(INCL)
+
 $(OUTDIR)/charset.obj:	$(OUTDIR) charset.c  $(INCL)
 
 $(OUTDIR)/diff.obj:	$(OUTDIR) diff.c  $(INCL)
@@ -1080,6 +1086,7 @@ auto:
 
 # End Custom Build
 proto.h: \
+	proto/blowfish.pro \
 	proto/buffer.pro \
 	proto/charset.pro \
 	proto/diff.pro \
@@ -1115,6 +1122,7 @@ proto.h: \
 	proto/regexp.pro \
 	proto/screen.pro \
 	proto/search.pro \
+	proto/sha256.pro \
 	proto/spell.pro \
 	proto/syntax.pro \
 	proto/tag.pro \
--- a/src/Make_sas.mak
+++ b/src/Make_sas.mak
@@ -179,6 +179,7 @@ OBJ = \
 	$(TERMLIB)
 
 PRO = \
+	proto/blowfish.pro \
 	proto/buffer.pro \
 	proto/charset.pro \
 	proto/diff.pro \
@@ -214,6 +215,7 @@ PRO = \
 	proto/regexp.pro \
 	proto/screen.pro \
 	proto/search.pro \
+	proto/sha256.pro \
 	proto/spell.pro \
 	proto/syntax.pro \
 	proto/tag.pro \
@@ -278,6 +280,8 @@ scoptions: Make_sas.mak
 	$(CC) $(CFLAGS) GPFILE=proto/$*.pro $(PROPT) $*.c
 
 # dependancies
+blowfish.o:		blowfish.c
+proto/blowfish.pro:	blowfish.c
 buffer.o:		buffer.c
 proto/buffer.pro:	buffer.c
 charset.o:		charset.c
@@ -348,6 +352,8 @@ screen.o:		screen.c
 proto/screen.pro:	screen.c
 search.o:		search.c
 proto/search.pro:	search.c
+sha256.o:		sha256.c
+proto/sha256.pro:	sha256.c
 spell.o:		spell.c
 proto/spell.pro:	spell.c
 syntax.o:		syntax.c
--- a/src/Makefile
+++ b/src/Makefile
@@ -468,7 +468,7 @@ CClink = $(CC)
 #CONF_OPT_FEAT = --with-features=small
 #CONF_OPT_FEAT = --with-features=normal
 #CONF_OPT_FEAT = --with-features=big
-#CONF_OPT_FEAT = --with-features=huge
+CONF_OPT_FEAT = --with-features=huge
 
 # COMPILED BY - For including a specific e-mail address for ":version".
 #CONF_OPT_COMPBY = "--with-compiledby=John Doe <JohnDoe@yahoo.com>"
@@ -536,9 +536,9 @@ CClink = $(CC)
 #CFLAGS = -g -O2 '-DSTARTUPTIME="vimstartup"' -fno-strength-reduce -Wall -Wmissing-prototypes
 
 # Use this with GCC to check for mistakes, unused arguments, etc.
-#CFLAGS = -g -Wall -Wextra -Wmissing-prototypes -Wunreachable-code -D_FORTIFY_SOURCE=1
-#PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers
-#MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter
+CFLAGS = -g -Wall -Wextra -Wmissing-prototypes -Wunreachable-code -D_FORTIFY_SOURCE=1
+PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers
+MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter
 
 # EFENCE - Electric-Fence malloc debugging: catches memory accesses beyond
 # allocated memory (and makes every malloc()/free() very slow).
@@ -1377,6 +1377,7 @@ DEST_MAN_RU_U = $(DEST_MAN_TOP)/ru.UTF-8
 TAGS_INCL = *.h
 
 BASIC_SRC = \
+	blowfish.c \
 	buffer.c \
 	charset.c \
 	diff.c \
@@ -1415,6 +1416,7 @@ BASIC_SRC = \
 	regexp.c \
 	screen.c \
 	search.c \
+	sha256.c \
 	spell.c \
 	syntax.c \
 	tag.c \
@@ -1449,6 +1451,7 @@ LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HAN
 
 OBJ = \
 	objects/buffer.o \
+	objects/blowfish.o \
 	objects/charset.o \
 	objects/diff.o \
 	objects/digraph.o \
@@ -1487,6 +1490,7 @@ OBJ = \
 	objects/regexp.o \
 	objects/screen.o \
 	objects/search.o \
+	objects/sha256.o \
 	objects/spell.o \
 	objects/syntax.o \
 	$(SNIFF_OBJ) \
@@ -1507,6 +1511,7 @@ OBJ = \
 	$(WSDEBUG_OBJ)
 
 PRO_AUTO = \
+	blowfish.pro \
 	buffer.pro \
 	charset.pro \
 	diff.pro \
@@ -1547,6 +1552,7 @@ PRO_AUTO = \
 	regexp.pro \
 	screen.pro \
 	search.pro \
+	sha256.pro \
 	spell.pro \
 	syntax.pro \
 	tag.pro \
@@ -2337,6 +2343,9 @@ auto/pathdef.c: Makefile auto/config.mk
 objects:
 	mkdir objects
 
+objects/blowfish.o: blowfish.c
+	$(CCC) -o $@ blowfish.c
+
 objects/buffer.o: buffer.c
 	$(CCC) -o $@ buffer.c
 
@@ -2547,6 +2556,9 @@ objects/screen.o: screen.c
 objects/search.o: search.c
 	$(CCC) -o $@ search.c
 
+objects/sha256.o: sha256.c
+	$(CCC) -o $@ sha256.c
+
 objects/spell.o: spell.c
 	$(CCC) -o $@ spell.c
 
new file mode 100644
--- /dev/null
+++ b/src/blowfish.c
@@ -0,0 +1,581 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * Blowfish encryption for vim; in Blowfish output feedback mode.
+ * GPL(C) 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_OFB_LEN  (8*(BF_BLOCK))
+
+typedef union {
+    long_u ul[2];
+    char_u uc[8];
+} block8;
+
+#ifdef __BORLANDC__
+# define LITTLE_ENDIAN
+#else
+# if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
+#  if (('1234' >> 24) == '1')
+#   define LITTLE_ENDIAN 1
+#  else
+#   if (('4321' >> 24) == '1')
+#    define BIG_ENDIAN  1
+#   endif
+#  endif
+# endif
+#endif
+
+static void bf_e_block __ARGS((long_u *p_xl, long_u *p_xr));
+static void bf_e_cblock __ARGS((char_u *block));
+static int bf_check_tables __ARGS((long_u ipa[18], long_u sbi[4][256], long_u val));
+static int bf_self_test __ARGS((void));
+
+// Blowfish code
+static long_u pax[18];
+static long_u ipa[18] = {
+    0x243f6a88u, 0x85a308d3u, 0x13198a2eu,
+    0x03707344u, 0xa4093822u, 0x299f31d0u,
+    0x082efa98u, 0xec4e6c89u, 0x452821e6u,
+    0x38d01377u, 0xbe5466cfu, 0x34e90c6cu,
+    0xc0ac29b7u, 0xc97c50ddu, 0x3f84d5b5u,
+    0xb5470917u, 0x9216d5d9u, 0x8979fb1bu
+};
+
+static long_u sbx[4][256];
+static long_u sbi[4][256] = {
+   {0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u,
+    0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u,
+    0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u,
+    0x636920d8u, 0x71574e69u, 0xa458fea3u, 0xf4933d7eu,
+    0x0d95748fu, 0x728eb658u, 0x718bcd58u, 0x82154aeeu,
+    0x7b54a41du, 0xc25a59b5u, 0x9c30d539u, 0x2af26013u,
+    0xc5d1b023u, 0x286085f0u, 0xca417918u, 0xb8db38efu,
+    0x8e79dcb0u, 0x603a180eu, 0x6c9e0e8bu, 0xb01e8a3eu,
+    0xd71577c1u, 0xbd314b27u, 0x78af2fdau, 0x55605c60u,
+    0xe65525f3u, 0xaa55ab94u, 0x57489862u, 0x63e81440u,
+    0x55ca396au, 0x2aab10b6u, 0xb4cc5c34u, 0x1141e8ceu,
+    0xa15486afu, 0x7c72e993u, 0xb3ee1411u, 0x636fbc2au,
+    0x2ba9c55du, 0x741831f6u, 0xce5c3e16u, 0x9b87931eu,
+    0xafd6ba33u, 0x6c24cf5cu, 0x7a325381u, 0x28958677u,
+    0x3b8f4898u, 0x6b4bb9afu, 0xc4bfe81bu, 0x66282193u,
+    0x61d809ccu, 0xfb21a991u, 0x487cac60u, 0x5dec8032u,
+    0xef845d5du, 0xe98575b1u, 0xdc262302u, 0xeb651b88u,
+    0x23893e81u, 0xd396acc5u, 0x0f6d6ff3u, 0x83f44239u,
+    0x2e0b4482u, 0xa4842004u, 0x69c8f04au, 0x9e1f9b5eu,
+    0x21c66842u, 0xf6e96c9au, 0x670c9c61u, 0xabd388f0u,
+    0x6a51a0d2u, 0xd8542f68u, 0x960fa728u, 0xab5133a3u,
+    0x6eef0b6cu, 0x137a3be4u, 0xba3bf050u, 0x7efb2a98u,
+    0xa1f1651du, 0x39af0176u, 0x66ca593eu, 0x82430e88u,
+    0x8cee8619u, 0x456f9fb4u, 0x7d84a5c3u, 0x3b8b5ebeu,
+    0xe06f75d8u, 0x85c12073u, 0x401a449fu, 0x56c16aa6u,
+    0x4ed3aa62u, 0x363f7706u, 0x1bfedf72u, 0x429b023du,
+    0x37d0d724u, 0xd00a1248u, 0xdb0fead3u, 0x49f1c09bu,
+    0x075372c9u, 0x80991b7bu, 0x25d479d8u, 0xf6e8def7u,
+    0xe3fe501au, 0xb6794c3bu, 0x976ce0bdu, 0x04c006bau,
+    0xc1a94fb6u, 0x409f60c4u, 0x5e5c9ec2u, 0x196a2463u,
+    0x68fb6fafu, 0x3e6c53b5u, 0x1339b2ebu, 0x3b52ec6fu,
+    0x6dfc511fu, 0x9b30952cu, 0xcc814544u, 0xaf5ebd09u,
+    0xbee3d004u, 0xde334afdu, 0x660f2807u, 0x192e4bb3u,
+    0xc0cba857u, 0x45c8740fu, 0xd20b5f39u, 0xb9d3fbdbu,
+    0x5579c0bdu, 0x1a60320au, 0xd6a100c6u, 0x402c7279u,
+    0x679f25feu, 0xfb1fa3ccu, 0x8ea5e9f8u, 0xdb3222f8u,
+    0x3c7516dfu, 0xfd616b15u, 0x2f501ec8u, 0xad0552abu,
+    0x323db5fau, 0xfd238760u, 0x53317b48u, 0x3e00df82u,
+    0x9e5c57bbu, 0xca6f8ca0u, 0x1a87562eu, 0xdf1769dbu,
+    0xd542a8f6u, 0x287effc3u, 0xac6732c6u, 0x8c4f5573u,
+    0x695b27b0u, 0xbbca58c8u, 0xe1ffa35du, 0xb8f011a0u,
+    0x10fa3d98u, 0xfd2183b8u, 0x4afcb56cu, 0x2dd1d35bu,
+    0x9a53e479u, 0xb6f84565u, 0xd28e49bcu, 0x4bfb9790u,
+    0xe1ddf2dau, 0xa4cb7e33u, 0x62fb1341u, 0xcee4c6e8u,
+    0xef20cadau, 0x36774c01u, 0xd07e9efeu, 0x2bf11fb4u,
+    0x95dbda4du, 0xae909198u, 0xeaad8e71u, 0x6b93d5a0u,
+    0xd08ed1d0u, 0xafc725e0u, 0x8e3c5b2fu, 0x8e7594b7u,
+    0x8ff6e2fbu, 0xf2122b64u, 0x8888b812u, 0x900df01cu,
+    0x4fad5ea0u, 0x688fc31cu, 0xd1cff191u, 0xb3a8c1adu,
+    0x2f2f2218u, 0xbe0e1777u, 0xea752dfeu, 0x8b021fa1u,
+    0xe5a0cc0fu, 0xb56f74e8u, 0x18acf3d6u, 0xce89e299u,
+    0xb4a84fe0u, 0xfd13e0b7u, 0x7cc43b81u, 0xd2ada8d9u,
+    0x165fa266u, 0x80957705u, 0x93cc7314u, 0x211a1477u,
+    0xe6ad2065u, 0x77b5fa86u, 0xc75442f5u, 0xfb9d35cfu,
+    0xebcdaf0cu, 0x7b3e89a0u, 0xd6411bd3u, 0xae1e7e49u,
+    0x00250e2du, 0x2071b35eu, 0x226800bbu, 0x57b8e0afu,
+    0x2464369bu, 0xf009b91eu, 0x5563911du, 0x59dfa6aau,
+    0x78c14389u, 0xd95a537fu, 0x207d5ba2u, 0x02e5b9c5u,
+    0x83260376u, 0x6295cfa9u, 0x11c81968u, 0x4e734a41u,
+    0xb3472dcau, 0x7b14a94au, 0x1b510052u, 0x9a532915u,
+    0xd60f573fu, 0xbc9bc6e4u, 0x2b60a476u, 0x81e67400u,
+    0x08ba6fb5u, 0x571be91fu, 0xf296ec6bu, 0x2a0dd915u,
+    0xb6636521u, 0xe7b9f9b6u, 0xff34052eu, 0xc5855664u,
+    0x53b02d5du, 0xa99f8fa1u, 0x08ba4799u, 0x6e85076au},
+   {0x4b7a70e9u, 0xb5b32944u, 0xdb75092eu, 0xc4192623u,
+    0xad6ea6b0u, 0x49a7df7du, 0x9cee60b8u, 0x8fedb266u,
+    0xecaa8c71u, 0x699a17ffu, 0x5664526cu, 0xc2b19ee1u,
+    0x193602a5u, 0x75094c29u, 0xa0591340u, 0xe4183a3eu,
+    0x3f54989au, 0x5b429d65u, 0x6b8fe4d6u, 0x99f73fd6u,
+    0xa1d29c07u, 0xefe830f5u, 0x4d2d38e6u, 0xf0255dc1u,
+    0x4cdd2086u, 0x8470eb26u, 0x6382e9c6u, 0x021ecc5eu,
+    0x09686b3fu, 0x3ebaefc9u, 0x3c971814u, 0x6b6a70a1u,
+    0x687f3584u, 0x52a0e286u, 0xb79c5305u, 0xaa500737u,
+    0x3e07841cu, 0x7fdeae5cu, 0x8e7d44ecu, 0x5716f2b8u,
+    0xb03ada37u, 0xf0500c0du, 0xf01c1f04u, 0x0200b3ffu,
+    0xae0cf51au, 0x3cb574b2u, 0x25837a58u, 0xdc0921bdu,
+    0xd19113f9u, 0x7ca92ff6u, 0x94324773u, 0x22f54701u,
+    0x3ae5e581u, 0x37c2dadcu, 0xc8b57634u, 0x9af3dda7u,
+    0xa9446146u, 0x0fd0030eu, 0xecc8c73eu, 0xa4751e41u,
+    0xe238cd99u, 0x3bea0e2fu, 0x3280bba1u, 0x183eb331u,
+    0x4e548b38u, 0x4f6db908u, 0x6f420d03u, 0xf60a04bfu,
+    0x2cb81290u, 0x24977c79u, 0x5679b072u, 0xbcaf89afu,
+    0xde9a771fu, 0xd9930810u, 0xb38bae12u, 0xdccf3f2eu,
+    0x5512721fu, 0x2e6b7124u, 0x501adde6u, 0x9f84cd87u,
+    0x7a584718u, 0x7408da17u, 0xbc9f9abcu, 0xe94b7d8cu,
+    0xec7aec3au, 0xdb851dfau, 0x63094366u, 0xc464c3d2u,
+    0xef1c1847u, 0x3215d908u, 0xdd433b37u, 0x24c2ba16u,
+    0x12a14d43u, 0x2a65c451u, 0x50940002u, 0x133ae4ddu,
+    0x71dff89eu, 0x10314e55u, 0x81ac77d6u, 0x5f11199bu,
+    0x043556f1u, 0xd7a3c76bu, 0x3c11183bu, 0x5924a509u,
+    0xf28fe6edu, 0x97f1fbfau, 0x9ebabf2cu, 0x1e153c6eu,
+    0x86e34570u, 0xeae96fb1u, 0x860e5e0au, 0x5a3e2ab3u,
+    0x771fe71cu, 0x4e3d06fau, 0x2965dcb9u, 0x99e71d0fu,
+    0x803e89d6u, 0x5266c825u, 0x2e4cc978u, 0x9c10b36au,
+    0xc6150ebau, 0x94e2ea78u, 0xa5fc3c53u, 0x1e0a2df4u,
+    0xf2f74ea7u, 0x361d2b3du, 0x1939260fu, 0x19c27960u,
+    0x5223a708u, 0xf71312b6u, 0xebadfe6eu, 0xeac31f66u,
+    0xe3bc4595u, 0xa67bc883u, 0xb17f37d1u, 0x018cff28u,
+    0xc332ddefu, 0xbe6c5aa5u, 0x65582185u, 0x68ab9802u,
+    0xeecea50fu, 0xdb2f953bu, 0x2aef7dadu, 0x5b6e2f84u,
+    0x1521b628u, 0x29076170u, 0xecdd4775u, 0x619f1510u,
+    0x13cca830u, 0xeb61bd96u, 0x0334fe1eu, 0xaa0363cfu,
+    0xb5735c90u, 0x4c70a239u, 0xd59e9e0bu, 0xcbaade14u,
+    0xeecc86bcu, 0x60622ca7u, 0x9cab5cabu, 0xb2f3846eu,
+    0x648b1eafu, 0x19bdf0cau, 0xa02369b9u, 0x655abb50u,
+    0x40685a32u, 0x3c2ab4b3u, 0x319ee9d5u, 0xc021b8f7u,
+    0x9b540b19u, 0x875fa099u, 0x95f7997eu, 0x623d7da8u,
+    0xf837889au, 0x97e32d77u, 0x11ed935fu, 0x16681281u,
+    0x0e358829u, 0xc7e61fd6u, 0x96dedfa1u, 0x7858ba99u,
+    0x57f584a5u, 0x1b227263u, 0x9b83c3ffu, 0x1ac24696u,
+    0xcdb30aebu, 0x532e3054u, 0x8fd948e4u, 0x6dbc3128u,
+    0x58ebf2efu, 0x34c6ffeau, 0xfe28ed61u, 0xee7c3c73u,
+    0x5d4a14d9u, 0xe864b7e3u, 0x42105d14u, 0x203e13e0u,
+    0x45eee2b6u, 0xa3aaabeau, 0xdb6c4f15u, 0xfacb4fd0u,
+    0xc742f442u, 0xef6abbb5u, 0x654f3b1du, 0x41cd2105u,
+    0xd81e799eu, 0x86854dc7u, 0xe44b476au, 0x3d816250u,
+    0xcf62a1f2u, 0x5b8d2646u, 0xfc8883a0u, 0xc1c7b6a3u,
+    0x7f1524c3u, 0x69cb7492u, 0x47848a0bu, 0x5692b285u,
+    0x095bbf00u, 0xad19489du, 0x1462b174u, 0x23820e00u,
+    0x58428d2au, 0x0c55f5eau, 0x1dadf43eu, 0x233f7061u,
+    0x3372f092u, 0x8d937e41u, 0xd65fecf1u, 0x6c223bdbu,
+    0x7cde3759u, 0xcbee7460u, 0x4085f2a7u, 0xce77326eu,
+    0xa6078084u, 0x19f8509eu, 0xe8efd855u, 0x61d99735u,
+    0xa969a7aau, 0xc50c06c2u, 0x5a04abfcu, 0x800bcadcu,
+    0x9e447a2eu, 0xc3453484u, 0xfdd56705u, 0x0e1e9ec9u,
+    0xdb73dbd3u, 0x105588cdu, 0x675fda79u, 0xe3674340u,
+    0xc5c43465u, 0x713e38d8u, 0x3d28f89eu, 0xf16dff20u,
+    0x153e21e7u, 0x8fb03d4au, 0xe6e39f2bu, 0xdb83adf7u},
+   {0xe93d5a68u, 0x948140f7u, 0xf64c261cu, 0x94692934u,
+    0x411520f7u, 0x7602d4f7u, 0xbcf46b2eu, 0xd4a20068u,
+    0xd4082471u, 0x3320f46au, 0x43b7d4b7u, 0x500061afu,
+    0x1e39f62eu, 0x97244546u, 0x14214f74u, 0xbf8b8840u,
+    0x4d95fc1du, 0x96b591afu, 0x70f4ddd3u, 0x66a02f45u,
+    0xbfbc09ecu, 0x03bd9785u, 0x7fac6dd0u, 0x31cb8504u,
+    0x96eb27b3u, 0x55fd3941u, 0xda2547e6u, 0xabca0a9au,
+    0x28507825u, 0x530429f4u, 0x0a2c86dau, 0xe9b66dfbu,
+    0x68dc1462u, 0xd7486900u, 0x680ec0a4u, 0x27a18deeu,
+    0x4f3ffea2u, 0xe887ad8cu, 0xb58ce006u, 0x7af4d6b6u,
+    0xaace1e7cu, 0xd3375fecu, 0xce78a399u, 0x406b2a42u,
+    0x20fe9e35u, 0xd9f385b9u, 0xee39d7abu, 0x3b124e8bu,
+    0x1dc9faf7u, 0x4b6d1856u, 0x26a36631u, 0xeae397b2u,
+    0x3a6efa74u, 0xdd5b4332u, 0x6841e7f7u, 0xca7820fbu,
+    0xfb0af54eu, 0xd8feb397u, 0x454056acu, 0xba489527u,
+    0x55533a3au, 0x20838d87u, 0xfe6ba9b7u, 0xd096954bu,
+    0x55a867bcu, 0xa1159a58u, 0xcca92963u, 0x99e1db33u,
+    0xa62a4a56u, 0x3f3125f9u, 0x5ef47e1cu, 0x9029317cu,
+    0xfdf8e802u, 0x04272f70u, 0x80bb155cu, 0x05282ce3u,
+    0x95c11548u, 0xe4c66d22u, 0x48c1133fu, 0xc70f86dcu,
+    0x07f9c9eeu, 0x41041f0fu, 0x404779a4u, 0x5d886e17u,
+    0x325f51ebu, 0xd59bc0d1u, 0xf2bcc18fu, 0x41113564u,
+    0x257b7834u, 0x602a9c60u, 0xdff8e8a3u, 0x1f636c1bu,
+    0x0e12b4c2u, 0x02e1329eu, 0xaf664fd1u, 0xcad18115u,
+    0x6b2395e0u, 0x333e92e1u, 0x3b240b62u, 0xeebeb922u,
+    0x85b2a20eu, 0xe6ba0d99u, 0xde720c8cu, 0x2da2f728u,
+    0xd0127845u, 0x95b794fdu, 0x647d0862u, 0xe7ccf5f0u,
+    0x5449a36fu, 0x877d48fau, 0xc39dfd27u, 0xf33e8d1eu,
+    0x0a476341u, 0x992eff74u, 0x3a6f6eabu, 0xf4f8fd37u,
+    0xa812dc60u, 0xa1ebddf8u, 0x991be14cu, 0xdb6e6b0du,
+    0xc67b5510u, 0x6d672c37u, 0x2765d43bu, 0xdcd0e804u,
+    0xf1290dc7u, 0xcc00ffa3u, 0xb5390f92u, 0x690fed0bu,
+    0x667b9ffbu, 0xcedb7d9cu, 0xa091cf0bu, 0xd9155ea3u,
+    0xbb132f88u, 0x515bad24u, 0x7b9479bfu, 0x763bd6ebu,
+    0x37392eb3u, 0xcc115979u, 0x8026e297u, 0xf42e312du,
+    0x6842ada7u, 0xc66a2b3bu, 0x12754cccu, 0x782ef11cu,
+    0x6a124237u, 0xb79251e7u, 0x06a1bbe6u, 0x4bfb6350u,
+    0x1a6b1018u, 0x11caedfau, 0x3d25bdd8u, 0xe2e1c3c9u,
+    0x44421659u, 0x0a121386u, 0xd90cec6eu, 0xd5abea2au,
+    0x64af674eu, 0xda86a85fu, 0xbebfe988u, 0x64e4c3feu,
+    0x9dbc8057u, 0xf0f7c086u, 0x60787bf8u, 0x6003604du,
+    0xd1fd8346u, 0xf6381fb0u, 0x7745ae04u, 0xd736fcccu,
+    0x83426b33u, 0xf01eab71u, 0xb0804187u, 0x3c005e5fu,
+    0x77a057beu, 0xbde8ae24u, 0x55464299u, 0xbf582e61u,
+    0x4e58f48fu, 0xf2ddfda2u, 0xf474ef38u, 0x8789bdc2u,
+    0x5366f9c3u, 0xc8b38e74u, 0xb475f255u, 0x46fcd9b9u,
+    0x7aeb2661u, 0x8b1ddf84u, 0x846a0e79u, 0x915f95e2u,
+    0x466e598eu, 0x20b45770u, 0x8cd55591u, 0xc902de4cu,
+    0xb90bace1u, 0xbb8205d0u, 0x11a86248u, 0x7574a99eu,
+    0xb77f19b6u, 0xe0a9dc09u, 0x662d09a1u, 0xc4324633u,
+    0xe85a1f02u, 0x09f0be8cu, 0x4a99a025u, 0x1d6efe10u,
+    0x1ab93d1du, 0x0ba5a4dfu, 0xa186f20fu, 0x2868f169u,
+    0xdcb7da83u, 0x573906feu, 0xa1e2ce9bu, 0x4fcd7f52u,
+    0x50115e01u, 0xa70683fau, 0xa002b5c4u, 0x0de6d027u,
+    0x9af88c27u, 0x773f8641u, 0xc3604c06u, 0x61a806b5u,
+    0xf0177a28u, 0xc0f586e0u, 0x006058aau, 0x30dc7d62u,
+    0x11e69ed7u, 0x2338ea63u, 0x53c2dd94u, 0xc2c21634u,
+    0xbbcbee56u, 0x90bcb6deu, 0xebfc7da1u, 0xce591d76u,
+    0x6f05e409u, 0x4b7c0188u, 0x39720a3du, 0x7c927c24u,
+    0x86e3725fu, 0x724d9db9u, 0x1ac15bb4u, 0xd39eb8fcu,
+    0xed545578u, 0x08fca5b5u, 0xd83d7cd3u, 0x4dad0fc4u,
+    0x1e50ef5eu, 0xb161e6f8u, 0xa28514d9u, 0x6c51133cu,
+    0x6fd5c7e7u, 0x56e14ec4u, 0x362abfceu, 0xddc6c837u,
+    0xd79a3234u, 0x92638212u, 0x670efa8eu, 0x406000e0u},
+   {0x3a39ce37u, 0xd3faf5cfu, 0xabc27737u, 0x5ac52d1bu,
+    0x5cb0679eu, 0x4fa33742u, 0xd3822740u, 0x99bc9bbeu,
+    0xd5118e9du, 0xbf0f7315u, 0xd62d1c7eu, 0xc700c47bu,
+    0xb78c1b6bu, 0x21a19045u, 0xb26eb1beu, 0x6a366eb4u,
+    0x5748ab2fu, 0xbc946e79u, 0xc6a376d2u, 0x6549c2c8u,
+    0x530ff8eeu, 0x468dde7du, 0xd5730a1du, 0x4cd04dc6u,
+    0x2939bbdbu, 0xa9ba4650u, 0xac9526e8u, 0xbe5ee304u,
+    0xa1fad5f0u, 0x6a2d519au, 0x63ef8ce2u, 0x9a86ee22u,
+    0xc089c2b8u, 0x43242ef6u, 0xa51e03aau, 0x9cf2d0a4u,
+    0x83c061bau, 0x9be96a4du, 0x8fe51550u, 0xba645bd6u,
+    0x2826a2f9u, 0xa73a3ae1u, 0x4ba99586u, 0xef5562e9u,
+    0xc72fefd3u, 0xf752f7dau, 0x3f046f69u, 0x77fa0a59u,
+    0x80e4a915u, 0x87b08601u, 0x9b09e6adu, 0x3b3ee593u,
+    0xe990fd5au, 0x9e34d797u, 0x2cf0b7d9u, 0x022b8b51u,
+    0x96d5ac3au, 0x017da67du, 0xd1cf3ed6u, 0x7c7d2d28u,
+    0x1f9f25cfu, 0xadf2b89bu, 0x5ad6b472u, 0x5a88f54cu,
+    0xe029ac71u, 0xe019a5e6u, 0x47b0acfdu, 0xed93fa9bu,
+    0xe8d3c48du, 0x283b57ccu, 0xf8d56629u, 0x79132e28u,
+    0x785f0191u, 0xed756055u, 0xf7960e44u, 0xe3d35e8cu,
+    0x15056dd4u, 0x88f46dbau, 0x03a16125u, 0x0564f0bdu,
+    0xc3eb9e15u, 0x3c9057a2u, 0x97271aecu, 0xa93a072au,
+    0x1b3f6d9bu, 0x1e6321f5u, 0xf59c66fbu, 0x26dcf319u,
+    0x7533d928u, 0xb155fdf5u, 0x03563482u, 0x8aba3cbbu,
+    0x28517711u, 0xc20ad9f8u, 0xabcc5167u, 0xccad925fu,
+    0x4de81751u, 0x3830dc8eu, 0x379d5862u, 0x9320f991u,
+    0xea7a90c2u, 0xfb3e7bceu, 0x5121ce64u, 0x774fbe32u,
+    0xa8b6e37eu, 0xc3293d46u, 0x48de5369u, 0x6413e680u,
+    0xa2ae0810u, 0xdd6db224u, 0x69852dfdu, 0x09072166u,
+    0xb39a460au, 0x6445c0ddu, 0x586cdecfu, 0x1c20c8aeu,
+    0x5bbef7ddu, 0x1b588d40u, 0xccd2017fu, 0x6bb4e3bbu,
+    0xdda26a7eu, 0x3a59ff45u, 0x3e350a44u, 0xbcb4cdd5u,
+    0x72eacea8u, 0xfa6484bbu, 0x8d6612aeu, 0xbf3c6f47u,
+    0xd29be463u, 0x542f5d9eu, 0xaec2771bu, 0xf64e6370u,
+    0x740e0d8du, 0xe75b1357u, 0xf8721671u, 0xaf537d5du,
+    0x4040cb08u, 0x4eb4e2ccu, 0x34d2466au, 0x0115af84u,
+    0xe1b00428u, 0x95983a1du, 0x06b89fb4u, 0xce6ea048u,
+    0x6f3f3b82u, 0x3520ab82u, 0x011a1d4bu, 0x277227f8u,
+    0x611560b1u, 0xe7933fdcu, 0xbb3a792bu, 0x344525bdu,
+    0xa08839e1u, 0x51ce794bu, 0x2f32c9b7u, 0xa01fbac9u,
+    0xe01cc87eu, 0xbcc7d1f6u, 0xcf0111c3u, 0xa1e8aac7u,
+    0x1a908749u, 0xd44fbd9au, 0xd0dadecbu, 0xd50ada38u,
+    0x0339c32au, 0xc6913667u, 0x8df9317cu, 0xe0b12b4fu,
+    0xf79e59b7u, 0x43f5bb3au, 0xf2d519ffu, 0x27d9459cu,
+    0xbf97222cu, 0x15e6fc2au, 0x0f91fc71u, 0x9b941525u,
+    0xfae59361u, 0xceb69cebu, 0xc2a86459u, 0x12baa8d1u,
+    0xb6c1075eu, 0xe3056a0cu, 0x10d25065u, 0xcb03a442u,
+    0xe0ec6e0eu, 0x1698db3bu, 0x4c98a0beu, 0x3278e964u,
+    0x9f1f9532u, 0xe0d392dfu, 0xd3a0342bu, 0x8971f21eu,
+    0x1b0a7441u, 0x4ba3348cu, 0xc5be7120u, 0xc37632d8u,
+    0xdf359f8du, 0x9b992f2eu, 0xe60b6f47u, 0x0fe3f11du,
+    0xe54cda54u, 0x1edad891u, 0xce6279cfu, 0xcd3e7e6fu,
+    0x1618b166u, 0xfd2c1d05u, 0x848fd2c5u, 0xf6fb2299u,
+    0xf523f357u, 0xa6327623u, 0x93a83531u, 0x56cccd02u,
+    0xacf08162u, 0x5a75ebb5u, 0x6e163697u, 0x88d273ccu,
+    0xde966292u, 0x81b949d0u, 0x4c50901bu, 0x71c65614u,
+    0xe6c6c7bdu, 0x327a140au, 0x45e1d006u, 0xc3f27b9au,
+    0xc9aa53fdu, 0x62a80f00u, 0xbb25bfe2u, 0x35bdd2f6u,
+    0x71126905u, 0xb2040222u, 0xb6cbcf7cu, 0xcd769c2bu,
+    0x53113ec0u, 0x1640e3d3u, 0x38abbd60u, 0x2547adf0u,
+    0xba38209cu, 0xf746ce76u, 0x77afa1c5u, 0x20756060u,
+    0x85cbfe4eu, 0x8ae88dd8u, 0x7aaaf9b0u, 0x4cf9aa7eu,
+    0x1948c25cu, 0x02fb8a8cu, 0x01c36ae4u, 0xd6ebe1f9u,
+    0x90d4f869u, 0xa65cdea0u, 0x3f09252du, 0xc208e69fu,
+    0xb74e6132u, 0xce77e25bu, 0x578fdfe3u, 0x3ac372e6u
+ }
+};
+
+
+#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)
+    long_u *p_xl;
+    long_u *p_xr;
+{
+    long_u 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;
+    *p_xl = xl; *p_xr = xr;
+}
+
+#if 0  /* not used */
+    static void
+bf_d_block(p_xl, p_xr)
+    long_u *p_xl;
+    long_u *p_xr;
+{
+    long_u 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 BIG_ENDIAN
+# define htonl2(x) \
+    x = ((((x) &     0xffL) << 24) | (((x) & 0xff00L)     <<  8) | \
+	 (((x) & 0xff0000L) >>  8) | (((x) & 0xff000000L) >> 24))
+#else
+# define htonl2(x)
+#endif
+
+    static void
+bf_e_cblock(block)
+    char_u *block;
+{
+    block8 bk;
+    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
+
+    void
+bf_key_init(password)
+    char_u *password;
+{
+    int    i, j, keypos = 0;
+    long_u val, data_l, data_r;
+    char   *key;
+    int    keylen;
+
+    key = sha256_key((char *)password);
+    keylen = STRLEN(key);
+    for (i = 0; i < 256; ++i)
+    {
+	sbx[0][i] = sbi[0][i];
+	sbx[1][i] = sbi[1][i];
+	sbx[2][i] = sbi[2][i];
+	sbx[3][i] = sbi[3][i];
+    }
+
+    for (i = 0; i < 18; ++i)
+    {
+	val = 0;
+	for (j = 0; j < 4; ++j)
+	    val = (val << 8) | (key[keypos++ % keylen] & 0xff);
+	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(ipa, sbi, val)
+    long_u ipa[18];
+    long_u sbi[4][256];
+    long_u val;
+{
+    int i, j;
+    long_u c = 0;
+
+    for (i = 0; i < 18; i++)
+	c ^= ipa[i];
+    for (i = 0; i < 4; i++)
+	for (j = 0; j < 256; j++)
+	    c ^= sbi[i][j];
+    return c == val;
+}
+
+typedef struct {
+    char_u password[64];
+    char_u plaintxt[8];
+    char_u cryptxt[8];
+    long_u keysum;
+} struct_bf_test_data;
+
+// Assert bf(password, plaintxt) is cryptxt.
+// Assert csum(pax sbx(password)) is keysum.
+static struct_bf_test_data bf_test_data[] = {
+  {
+      "password",
+      "plaintxt",
+#if 0  /* This value doesn't work, why??? */
+      "\x55\xca\x56\x3a\xef\xe1\x9c\x73", /* cryptxt */
+#else
+      "\x47\xd9\x67\x49\x91\xc5\x9a\x95", /* cryptxt */
+#endif
+      0x5de01bdbu, /* keysum */
+  },
+};
+
+/*
+ * Return FAIL when there is something wrong with blowfish encryption.
+ */
+    static int
+bf_self_test()
+{
+    int    i, bn;
+    int    err = 0;
+    block8 bk;
+
+    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));
+	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)
+	    err++;
+    }
+
+    return err > 0 ? FAIL : OK;
+}
+
+/* Output feedback mode. */
+static int randbyte_offset = 0;
+static int update_offset = 0;
+static char_u ofb_buffer[BF_OFB_LEN]; /* 64 bytes */
+
+/*
+ * Initialize with seed "iv[iv_len]".
+ */
+    void
+bf_ofb_init(iv, iv_len)
+    char_u *iv;
+    int    iv_len;
+{
+    int i, mi;
+
+    randbyte_offset = update_offset = 0;
+    memset(ofb_buffer, 0, BF_OFB_LEN);
+    if (iv_len > 0)
+    {
+	mi = iv_len > BF_OFB_LEN ? iv_len : BF_OFB_LEN;
+	for (i = 0; i < mi; i++)
+	    ofb_buffer[i % BF_OFB_LEN] ^= iv[i % iv_len];
+    }
+}
+
+    void
+bf_ofb_update(c)
+    int c;
+{
+    ofb_buffer[update_offset++] ^= (char_u)c;
+    if (update_offset == BF_OFB_LEN)
+	update_offset = 0;
+}
+
+    int
+bf_ranbyte()
+{
+    int current_byte = randbyte_offset++;
+    int current_block = (current_byte / BF_BLOCK) * BF_BLOCK;
+
+    if (randbyte_offset == BF_OFB_LEN)
+	randbyte_offset = 0;
+    if ((current_byte % BF_BLOCK) == 0)
+	bf_e_cblock(&ofb_buffer[current_block]);
+    return ofb_buffer[current_byte];
+}
+
+/*
+ * Run a test to check if the encryption works as expected.
+ * Give an error and return FAIL when not.
+ */
+    int
+blowfish_self_test()
+{
+    if (sha256_self_test() == FAIL)
+    {
+	EMSG2(_("E000: sha256 test failed"),"");
+	return FAIL;
+    }
+    if (bf_self_test() == FAIL)
+    {
+	EMSG2(_("E000: Blowfish test failed"),"");
+	return FAIL;
+    }
+    return OK;
+}
+
+#endif /* FEAT_CRYPT */
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -11123,7 +11123,8 @@ ex_match(eap)
 ex_X(eap)
     exarg_T	*eap UNUSED;
 {
-    (void)get_crypt_key(TRUE, TRUE);
+    if (curbuf->b_p_cm == 0 || blowfish_self_test() == OK)
+	(void)get_crypt_key(TRUE, TRUE);
 }
 #endif
 
--- a/src/feature.h
+++ b/src/feature.h
@@ -592,7 +592,7 @@
 /*
  * +cryptv		Encryption (by Mohsin Ahmed <mosh@sasi.com>).
  */
-#if defined(FEAT_NORMAL) || defined(PROTO)
+#if defined(FEAT_NORMAL) && !defined(FEAT_CRYPT) || defined(PROTO)
 # define FEAT_CRYPT
 #endif
 
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -33,8 +33,14 @@
 #define SMBUFSIZE	256	/* size of emergency write buffer */
 
 #ifdef FEAT_CRYPT
-# define CRYPT_MAGIC		"VimCrypt~01!"	/* "01" is the version nr */
+char crypt_magic_01[] = "VimCrypt~01!";
+char crypt_magic_02[] = "VimCrypt~02!";
 # define CRYPT_MAGIC_LEN	12		/* must be multiple of 4! */
+
+/* crypt_magic[0] is pkzip crypt, crypt_magic[1] is sha2+blowfish */
+static char   *crypt_magic[] = {crypt_magic_01, crypt_magic_02};
+static int    crypt_seed_len[] = {0, 8};
+#define CRYPT_SEED_LEN_MAX 8
 #endif
 
 /* Is there any system that doesn't have access()? */
@@ -54,6 +60,7 @@ static char_u *readfile_charconvert __AR
 static void check_marks_read __ARGS((void));
 #endif
 #ifdef FEAT_CRYPT
+static int get_crypt_method __ARGS((char *ptr, int len));
 static char_u *check_for_cryptkey __ARGS((char_u *cryptkey, char_u *ptr, long *sizep, long *filesizep, int newfile));
 #endif
 #ifdef UNIX
@@ -1425,7 +1432,9 @@ retry:
 	     */
 	    if ((filesize == 0
 # ifdef FEAT_CRYPT
-			|| (filesize == CRYPT_MAGIC_LEN && cryptkey != NULL)
+		   || (filesize == (CRYPT_MAGIC_LEN
+					   + crypt_seed_len[use_crypt_method])
+							  && cryptkey != NULL)
 # endif
 		       )
 		    && (fio_flags == FIO_UCSBOM
@@ -2241,7 +2250,7 @@ failed:
 
 #ifdef FEAT_CRYPT
     if (cryptkey != curbuf->b_p_key)
-	vim_free(cryptkey);
+	free_crypt_key(cryptkey);
 #endif
 
 #ifdef FEAT_MBYTE
@@ -2456,7 +2465,8 @@ failed:
 		c = TRUE;
 #ifdef FEAT_CRYPT
 	    if (cryptkey != NULL)
-		msg_add_lines(c, (long)linecnt, filesize - CRYPT_MAGIC_LEN);
+		msg_add_lines(c, (long)linecnt, filesize
+			- CRYPT_MAGIC_LEN - crypt_seed_len[use_crypt_method]);
 	    else
 #endif
 		msg_add_lines(c, (long)linecnt, filesize);
@@ -2783,7 +2793,29 @@ check_marks_read()
 
 #ifdef FEAT_CRYPT
 /*
- * Check for magic number used for encryption.
+ * 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
+get_crypt_method(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_seed_len[i]))
+	    continue;
+	if (memcmp(ptr, crypt_magic[i], CRYPT_MAGIC_LEN) == 0)
+	    return i;
+    }
+    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.
  * Return the (new) encryption key, NULL for no encryption.
@@ -2796,17 +2828,23 @@ check_for_cryptkey(cryptkey, ptr, sizep,
     long	*filesizep;	/* nr of bytes used from file */
     int		newfile;	/* editing a new buffer */
 {
-    if (*sizep >= CRYPT_MAGIC_LEN
-	    && STRNCMP(ptr, CRYPT_MAGIC, CRYPT_MAGIC_LEN) == 0)
-    {
+    int method = get_crypt_method((char *)ptr, *sizep);
+
+    if (method >= 0)
+    {
+	curbuf->b_p_cm = method;
+	use_crypt_method = method;
+	if (method > 0)
+	    (void)blowfish_self_test();
 	if (cryptkey == NULL)
 	{
 	    if (*curbuf->b_p_key)
 		cryptkey = curbuf->b_p_key;
 	    else
 	    {
-		/* When newfile is TRUE, store the typed key
-		 * in the 'key' option and don't free it. */
+		/* When newfile is TRUE, store the typed key in the 'key'
+		 * option and don't free it.  bf needs hash of the key saved.
+		 */
 		cryptkey = get_crypt_key(newfile, FALSE);
 		/* check if empty key entered */
 		if (cryptkey != NULL && *cryptkey == NUL)
@@ -2820,17 +2858,24 @@ check_for_cryptkey(cryptkey, ptr, sizep,
 
 	if (cryptkey != NULL)
 	{
-	    crypt_init_keys(cryptkey);
+	    int seed_len = crypt_seed_len[method];
+
+	    if (method == 0)
+		crypt_init_keys(cryptkey);
+	    else
+	    {
+		bf_key_init(cryptkey);
+		bf_ofb_init(ptr + CRYPT_MAGIC_LEN, seed_len);
+	    }
 
 	    /* Remove magic number from the text */
-	    *filesizep += CRYPT_MAGIC_LEN;
-	    *sizep -= CRYPT_MAGIC_LEN;
-	    mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN, (size_t)*sizep);
-	}
-    }
-    /* When starting to edit a new file which does not have
-     * encryption, clear the 'key' option, except when
-     * starting up (called with -x argument) */
+	    *filesizep += CRYPT_MAGIC_LEN + seed_len;
+	    *sizep -= CRYPT_MAGIC_LEN + seed_len;
+	    mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN + seed_len, (size_t)*sizep);
+	}
+    }
+    /* When starting to edit a new file which does not have encryption, clear
+     * the 'key' option, except when starting up (called with -x argument) */
     else if (newfile && *curbuf->b_p_key && !starting)
 	set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
 
@@ -4229,12 +4274,30 @@ restore_backup:
 #ifdef FEAT_CRYPT
     if (*buf->b_p_key && !filtering)
     {
-	crypt_init_keys(buf->b_p_key);
-	/* 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 = (char_u *)CRYPT_MAGIC;
-	write_info.bw_len = CRYPT_MAGIC_LEN;
+	char_u header[CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX + 2];
+	int seed_len = crypt_seed_len[buf->b_p_cm];
+
+	use_crypt_method = buf->b_p_cm;  /* select pkzip or blowfish */
+
+	memset(header, 0, sizeof(header));
+	vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
+							     CRYPT_MAGIC_LEN);
+
+	if (buf->b_p_cm == 0)
+	    crypt_init_keys(buf->b_p_key);
+	else
+	{
+	    /* Using blowfish, add seed. */
+	    sha2_seed(header + CRYPT_MAGIC_LEN, seed_len); /* create iv */
+	    bf_ofb_init(header + CRYPT_MAGIC_LEN, seed_len);
+	    bf_key_init(buf->b_p_key);
+	}
+
+	/* 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 = (char_u *)header;
+	write_info.bw_len = CRYPT_MAGIC_LEN + seed_len;
 	write_info.bw_flags = FIO_NOCONVERT;
 	if (buf_write_bytes(&write_info) == FAIL)
 	    end = 0;
--- a/src/globals.h
+++ b/src/globals.h
@@ -105,6 +105,10 @@ EXTERN int	exec_from_reg INIT(= FALSE);	
 
 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
--- a/src/main.c
+++ b/src/main.c
@@ -797,6 +797,7 @@ main
 #ifdef FEAT_CRYPT
     if (params.ask_for_key)
     {
+	(void)blowfish_self_test();
 	(void)get_crypt_key(TRUE, TRUE);
 	TIME_MSG("getting crypt key");
     }
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -3685,6 +3685,11 @@ update_mouseshape(shape_idx)
  * 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 */
@@ -3730,6 +3735,8 @@ decrypt_byte()
 {
     ush temp;
 
+    if (use_crypt_method > 0)
+	return bf_ranbyte();
     temp = (ush)keys[2] | 2;
     return (int)(((unsigned)(temp * (temp ^ 1)) >> 8) & 0xff);
 }
@@ -3737,15 +3744,19 @@ decrypt_byte()
 /*
  * Update the encryption keys with the next byte of plain text
  */
-    int
+    void
 update_keys(c)
     int c;			/* byte of plain text */
 {
-    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));
-    return c;
+    if (use_crypt_method > 0)
+	bf_ofb_update( (unsigned char) c);
+    else
+    {
+	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));
+    }
 }
 
 /*
@@ -3769,8 +3780,26 @@ 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 in stored in the 'key' option, and the
+ * 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.
@@ -3801,16 +3830,17 @@ get_crypt_key(store, twice)
 	    if (p2 != NULL && STRCMP(p1, p2) != 0)
 	    {
 		MSG(_("Keys don't match!"));
-		vim_free(p1);
-		vim_free(p2);
+		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);
-		vim_free(p1);
+		free_crypt_key(p1);
 		p1 = curbuf->b_p_key;
 	    }
 	    break;
@@ -3822,7 +3852,7 @@ get_crypt_key(store, twice)
     need_wait_return = FALSE;
     msg_didout = FALSE;
 
-    vim_free(p2);
+    free_crypt_key(p2);
     return p1;
 }
 
--- a/src/option.c
+++ b/src/option.c
@@ -77,6 +77,7 @@
 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
 # define PV_CINW	OPT_BUF(BV_CINW)
 #endif
+#define PV_CM		OPT_BUF(BV_CM)
 #ifdef FEAT_FOLDING
 # define PV_CMS		OPT_BUF(BV_CMS)
 #endif
@@ -277,6 +278,7 @@ static char_u	*p_cino;
 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
 static char_u	*p_cinw;
 #endif
+static long	p_cm;
 #ifdef FEAT_COMMENTS
 static char_u	*p_com;
 #endif
@@ -834,6 +836,9 @@ static struct vimoption
 			    (char_u *)&p_cpo, PV_NONE,
 			    {(char_u *)CPO_VI, (char_u *)CPO_VIM}
 			    SCRIPTID_INIT},
+    {"cryptmethod", "cm",   P_NUM|P_VI_DEF|P_VIM,
+			    (char_u *)&p_cm, PV_CM,
+			    {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
     {"cscopepathcomp", "cspc", P_NUM|P_VI_DEF|P_VIM,
 #ifdef FEAT_CSCOPE
 			    (char_u *)&p_cspc, PV_NONE,
@@ -7870,6 +7875,22 @@ set_num_option(opt_idx, varp, value, err
 
 #endif
 
+    else if (pp == &curbuf->b_p_cm)
+    {
+	if (curbuf->b_p_cm < 0)
+	{
+	    errmsg = e_positive;
+	    curbuf->b_p_cm = 0;
+	}
+	if (curbuf->b_p_cm > 1)
+	{
+	    errmsg = e_invarg;
+	    curbuf->b_p_cm = 1;
+	}
+	if (curbuf->b_p_cm > 0 && blowfish_self_test() == FAIL)
+	    curbuf->b_p_cm = 0;
+    }
+
 #ifdef FEAT_WINDOWS
     /* (re)set last window status line */
     else if (pp == &p_ls)
@@ -9286,6 +9307,7 @@ get_varp(p)
 	case PV_CINK:	return (char_u *)&(curbuf->b_p_cink);
 	case PV_CINO:	return (char_u *)&(curbuf->b_p_cino);
 #endif
+	case PV_CM:	return (char_u *)&(curbuf->b_p_cm);
 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
 	case PV_CINW:	return (char_u *)&(curbuf->b_p_cinw);
 #endif
--- a/src/option.h
+++ b/src/option.h
@@ -908,6 +908,7 @@ enum
 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
     , BV_CINW
 #endif
+    , BV_CM
 #ifdef FEAT_FOLDING
     , BV_CMS
 #endif
--- a/src/proto.h
+++ b/src/proto.h
@@ -69,6 +69,9 @@ extern int _stricoll __ARGS((char *a, ch
 #  include "os_qnx.pro"
 # endif
 
+# ifdef FEAT_CRYPT
+#  include "blowfish.pro"
+# endif
 # include "buffer.pro"
 # include "charset.pro"
 # ifdef FEAT_CSCOPE
@@ -146,6 +149,9 @@ void qsort __ARGS((void *base, size_t el
 # endif
 # include "regexp.pro"
 # include "screen.pro"
+# ifdef FEAT_CRYPT
+#  include "sha256.pro"
+# endif
 # include "search.pro"
 # include "spell.pro"
 # include "syntax.pro"
new file mode 100644
--- /dev/null
+++ b/src/proto/blowfish.pro
@@ -0,0 +1,7 @@
+/* blowfish.c */
+void bf_key_init __ARGS((char_u *password));
+void bf_ofb_init __ARGS((char_u *iv, int iv_len));
+void bf_ofb_update __ARGS((int c));
+int bf_ranbyte __ARGS((void));
+int blowfish_self_test __ARGS((void));
+/* vim: set ft=c : */
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -81,8 +81,9 @@ char_u *parse_shape_opt __ARGS((int what
 int get_shape_idx __ARGS((int mouse));
 void update_mouseshape __ARGS((int shape_idx));
 int decrypt_byte __ARGS((void));
-int update_keys __ARGS((int c));
+void update_keys __ARGS((int c));
 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));
new file mode 100644
--- /dev/null
+++ b/src/proto/sha256.pro
@@ -0,0 +1,5 @@
+/* sha256.c */
+char *sha256_key __ARGS((char *buf));
+int sha256_self_test __ARGS((void));
+void sha2_seed __ARGS((char_u header[], int header_len));
+/* vim: set ft=c : */
new file mode 100644
--- /dev/null
+++ b/src/sha256.c
@@ -0,0 +1,429 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ *  FIPS-180-2 compliant SHA-256 implementation
+ *  GPL by Christophe Devine.
+ *  Modified for md5deep, in public domain.
+ *  Modified For Vim, GPL(C) Mohsin Ahmed, http://www.cs.albany.edu/~mosh
+ *
+ *  Vim specific notes:
+ *  Functions exported by this file:
+ *   1. sha256_key() hashes the password to 64 bytes char string.
+ *   2. sha2_seed() generates a random header.
+ *   sha256_self_test() is implicitly called once.
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_CRYPT
+
+typedef unsigned long uint32_t;
+
+typedef struct {
+  uint32_t total[2];
+  uint32_t state[8];
+  char_u   buffer[64];
+} context_sha256_T;
+
+static void sha256_starts __ARGS((context_sha256_T *ctx));
+static void sha256_process __ARGS((context_sha256_T *ctx, char_u data[64]));
+static void sha256_update __ARGS((context_sha256_T *ctx, char_u *input, uint32_t length));
+static void sha256_finish __ARGS((context_sha256_T *ctx, char_u digest[32]));
+static char *sha256_bytes __ARGS((char *buf, int buflen));
+static unsigned int get_some_time __ARGS((void));
+
+
+#define GET_UINT32(n, b, i)		    \
+{					    \
+    (n) = ( (uint32_t)(b)[(i)	 ] << 24)   \
+	| ( (uint32_t)(b)[(i) + 1] << 16)   \
+	| ( (uint32_t)(b)[(i) + 2] <<  8)   \
+	| ( (uint32_t)(b)[(i) + 3]	);  \
+}
+
+#define PUT_UINT32(n,b,i)		  \
+{					  \
+    (b)[(i)    ] = (char_u)((n) >> 24);   \
+    (b)[(i) + 1] = (char_u)((n) >> 16);   \
+    (b)[(i) + 2] = (char_u)((n) >>  8);   \
+    (b)[(i) + 3] = (char_u)((n)      );   \
+}
+
+    static void
+sha256_starts(ctx)
+    context_sha256_T *ctx;
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x6A09E667;
+    ctx->state[1] = 0xBB67AE85;
+    ctx->state[2] = 0x3C6EF372;
+    ctx->state[3] = 0xA54FF53A;
+    ctx->state[4] = 0x510E527F;
+    ctx->state[5] = 0x9B05688C;
+    ctx->state[6] = 0x1F83D9AB;
+    ctx->state[7] = 0x5BE0CD19;
+}
+
+    static void
+sha256_process(ctx, data)
+    context_sha256_T *ctx;
+    char_u	     data[64];
+{
+    uint32_t temp1, temp2, W[64];
+    uint32_t A, B, C, D, E, F, G, H;
+
+    GET_UINT32(W[0],  data,  0);
+    GET_UINT32(W[1],  data,  4);
+    GET_UINT32(W[2],  data,  8);
+    GET_UINT32(W[3],  data, 12);
+    GET_UINT32(W[4],  data, 16);
+    GET_UINT32(W[5],  data, 20);
+    GET_UINT32(W[6],  data, 24);
+    GET_UINT32(W[7],  data, 28);
+    GET_UINT32(W[8],  data, 32);
+    GET_UINT32(W[9],  data, 36);
+    GET_UINT32(W[10], data, 40);
+    GET_UINT32(W[11], data, 44);
+    GET_UINT32(W[12], data, 48);
+    GET_UINT32(W[13], data, 52);
+    GET_UINT32(W[14], data, 56);
+    GET_UINT32(W[15], data, 60);
+
+#define  SHR(x, n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x, n) (SHR(x, n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^  SHR(x, 3))
+#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^  SHR(x, 10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+
+#define F0(x, y, z) ((x & y) | (z & (x | y)))
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+
+#define R(t)				\
+(					\
+    W[t] = S1(W[t -  2]) + W[t -  7] +	\
+	   S0(W[t - 15]) + W[t - 16]	\
+)
+
+#define P(a,b,c,d,e,f,g,h,x,K)		     \
+{					     \
+    temp1 = h + S3(e) + F1(e, f, g) + K + x; \
+    temp2 = S2(a) + F0(a, b, c);	     \
+    d += temp1; h = temp1 + temp2;	     \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+    F = ctx->state[5];
+    G = ctx->state[6];
+    H = ctx->state[7];
+
+    P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98);
+    P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491);
+    P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF);
+    P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5);
+    P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B);
+    P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1);
+    P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4);
+    P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5);
+    P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98);
+    P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01);
+    P( G, H, A, B, C, D, E, F, W[10], 0x243185BE);
+    P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3);
+    P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74);
+    P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE);
+    P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7);
+    P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174);
+    P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1);
+    P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786);
+    P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6);
+    P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC);
+    P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F);
+    P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA);
+    P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC);
+    P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA);
+    P( A, B, C, D, E, F, G, H, R(24), 0x983E5152);
+    P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D);
+    P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8);
+    P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7);
+    P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3);
+    P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147);
+    P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351);
+    P( B, C, D, E, F, G, H, A, R(31), 0x14292967);
+    P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85);
+    P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138);
+    P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC);
+    P( F, G, H, A, B, C, D, E, R(35), 0x53380D13);
+    P( E, F, G, H, A, B, C, D, R(36), 0x650A7354);
+    P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB);
+    P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E);
+    P( B, C, D, E, F, G, H, A, R(39), 0x92722C85);
+    P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1);
+    P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B);
+    P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70);
+    P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3);
+    P( E, F, G, H, A, B, C, D, R(44), 0xD192E819);
+    P( D, E, F, G, H, A, B, C, R(45), 0xD6990624);
+    P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585);
+    P( B, C, D, E, F, G, H, A, R(47), 0x106AA070);
+    P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116);
+    P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08);
+    P( G, H, A, B, C, D, E, F, R(50), 0x2748774C);
+    P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5);
+    P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3);
+    P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A);
+    P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F);
+    P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3);
+    P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE);
+    P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F);
+    P( G, H, A, B, C, D, E, F, R(58), 0x84C87814);
+    P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208);
+    P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA);
+    P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB);
+    P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7);
+    P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2);
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+    ctx->state[5] += F;
+    ctx->state[6] += G;
+    ctx->state[7] += H;
+}
+
+    static void
+sha256_update(ctx, input, length)
+    context_sha256_T *ctx;
+    char_u	     *input;
+    uint32_t	     length;
+{
+    uint32_t left, fill;
+
+    if (length == 0)
+	return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += length;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if (ctx->total[0] < length)
+	ctx->total[1]++;
+
+    if (left && length >= fill)
+    {
+	memcpy((void *)(ctx->buffer + left), (void *)input, fill);
+	sha256_process(ctx, ctx->buffer);
+	length -= fill;
+	input  += fill;
+	left = 0;
+    }
+
+    while (length >= 64)
+    {
+	sha256_process(ctx, input);
+	length -= 64;
+	input  += 64;
+    }
+
+    if (length)
+	memcpy((void *)(ctx->buffer + left), (void *)input, length);
+}
+
+static char_u sha256_padding[64] = {
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+    static void
+sha256_finish(ctx, digest)
+    context_sha256_T *ctx;
+    char_u           digest[32];
+{
+    uint32_t last, padn;
+    uint32_t high, low;
+    char_u   msglen[8];
+
+    high = (ctx->total[0] >> 29) | (ctx->total[1] <<  3);
+    low  = (ctx->total[0] <<  3);
+
+    PUT_UINT32(high, msglen, 0);
+    PUT_UINT32(low,  msglen, 4);
+
+    last = ctx->total[0] & 0x3F;
+    padn = (last < 56) ? (56 - last) : (120 - last);
+
+    sha256_update(ctx, sha256_padding, padn);
+    sha256_update(ctx, msglen, 8);
+
+    PUT_UINT32(ctx->state[0], digest,  0);
+    PUT_UINT32(ctx->state[1], digest,  4);
+    PUT_UINT32(ctx->state[2], digest,  8);
+    PUT_UINT32(ctx->state[3], digest, 12);
+    PUT_UINT32(ctx->state[4], digest, 16);
+    PUT_UINT32(ctx->state[5], digest, 20);
+    PUT_UINT32(ctx->state[6], digest, 24);
+    PUT_UINT32(ctx->state[7], digest, 28);
+}
+
+    static char *
+sha256_bytes(buf, buflen)
+    char *buf;
+    int  buflen;
+{
+    char_u	     sha256sum[32];
+    static char      hexit[65];
+    int		     j;
+    context_sha256_T ctx;
+
+    sha256_self_test();
+
+    sha256_starts(&ctx);
+    sha256_update(&ctx, (char_u *)buf, buflen);
+    sha256_finish(&ctx, sha256sum);
+    for (j = 0; j < 32; j++)
+	sprintf(hexit + j * 2, "%02x", sha256sum[j]);
+    hexit[sizeof(hexit) - 1] = '\0';
+    return hexit;
+}
+
+/*
+ * Returns sha256(buf) as 64 hex chars.
+ */
+    char *
+sha256_key(buf)
+    char *buf;
+{
+    static char *hexit = 0;
+    int		buflen;
+
+    /* No passwd means don't encrypt */
+    if (buf == NULL || *buf == NUL)
+	return "";
+
+    /* if password is "0", reuse previous hash, for user convienience. */
+    if (!strcmp(buf, "0") && hexit)
+	return hexit;
+
+    buflen = strlen(buf);
+    hexit = sha256_bytes(buf, buflen);
+    return hexit;
+}
+
+/*
+ * These are the standard FIPS-180-2 test vectors
+ */
+
+static char *sha_self_test_msg[] = {
+    "abc",
+    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+    NULL
+};
+
+static char *sha_self_test_vector[] = {
+    "ba7816bf8f01cfea414140de5dae2223" \
+    "b00361a396177a9cb410ff61f20015ad",
+    "248d6a61d20638b8e5c026930c3e6039" \
+    "a33ce45964ff2167f6ecedd419db06c1",
+    "cdc76e5c9914fb9281a1c7e284d73e67" \
+    "f1809a48a497200e046d39ccc7112cd0"
+};
+
+/*
+ * Perform a test on the SHA256 algorithm.
+ * Return FAIL or OK.
+ */
+    int
+sha256_self_test()
+{
+    int		     i, j;
+    char	     output[65];
+    context_sha256_T ctx;
+    char_u	     buf[1000];
+    char_u	     sha256sum[32];
+    static int	     failures = 0;
+    char	     *hexit;
+    static int	     sha256_self_tested = 0;
+
+    if (sha256_self_tested > 0)
+	return failures > 0 ? FAIL : OK;
+    sha256_self_tested = 1;
+
+    for (i = 0; i < 3; i++)
+    {
+	if (i < 2)
+	{
+	    hexit = sha256_bytes(sha_self_test_msg[i],
+						strlen(sha_self_test_msg[i]));
+	    strcpy(output, hexit);
+	}
+	else
+	{
+	    sha256_starts(&ctx);
+	    memset(buf, 'a', 1000);
+	    for (j = 0; j < 1000; j++)
+		sha256_update(&ctx, (char_u *)buf, 1000);
+	    sha256_finish(&ctx, sha256sum);
+	    for (j = 0; j < 32; j++)
+		sprintf(output + j * 2, "%02x", sha256sum[j]);
+	}
+	if (memcmp(output, sha_self_test_vector[i], 64))
+	{
+	    failures++;
+	    output[sizeof(output) - 1] = '\0';
+	    /* printf("sha256_self_test %d failed %s\n", i, output); */
+	}
+    }
+    return failures > 0 ? FAIL : OK;
+}
+
+    static unsigned int
+get_some_time()
+{
+#ifdef HAVE_GETTIMEOFDAY
+    struct timeval tv;
+
+    /* Using usec makes it less predictable. */
+    gettimeofday(&tv, NULL);
+    return (unsigned int)(tv.tv_sec + tv.tv_usec);
+#else
+    return (unsigned int)time(NULL);
+#endif
+}
+
+/*
+ * set header = sha2_seed(random_data);
+ */
+    void
+sha2_seed(header, header_len)
+    char_u header[];
+    int    header_len;
+{
+    int		     i;
+    static char_u    random_data[1000];
+    char_u	     sha256sum[32];
+    context_sha256_T ctx;
+    srand(get_some_time());
+
+    for (i = 0; i < (int)sizeof(random_data) - 1; i++)
+	random_data[i] = (char_u)((get_some_time() ^ rand()) & 0xff);
+    sha256_starts(&ctx);
+    sha256_update(&ctx, (char_u *)random_data, sizeof(random_data));
+    sha256_finish(&ctx, sha256sum);
+
+    for (i = 0; i < header_len; i++)
+	header[i] = sha256sum[i % sizeof(sha256sum)];
+}
+
+#endif /* FEAT_CRYPT */
--- a/src/structs.h
+++ b/src/structs.h
@@ -1358,6 +1358,7 @@ struct file_buffer
 #ifdef FEAT_INS_EXPAND
     char_u	*b_p_cpt;	/* 'complete' */
 #endif
+    long	b_p_cm;		/* 'cryptmethod' */
 #ifdef FEAT_COMPL_FUNC
     char_u	*b_p_cfu;	/* 'completefunc' */
     char_u	*b_p_ofu;	/* 'omnifunc' */
--- a/src/testdir/Make_dos.mak
+++ b/src/testdir/Make_dos.mak
@@ -27,7 +27,7 @@ SCRIPTS =	test3.out test4.out test5.out 
 		test30.out test31.out test32.out test33.out test34.out \
 		test37.out test38.out test39.out test40.out test41.out \
 		test42.out test52.out test65.out test66.out test67.out \
-		test68.out test69.out
+		test68.out test69.out test71.out
 
 SCRIPTS32 =	test50.out test70.out
 
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -46,7 +46,7 @@ SCRIPTS =	test3.out test4.out test5.out 
 		test30.out test31.out test32.out test33.out test34.out \
 		test37.out test38.out test39.out test40.out test41.out \
 		test42.out test52.out test65.out test66.out test67.out \
-		test68.out test69.out
+		test68.out test69.out test71.out
 
 SCRIPTS32 =	test50.out test70.out
 
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -23,7 +23,7 @@ SCRIPTS = test1.out test2.out test3.out 
 		test54.out test55.out test56.out test57.out test58.out \
 		test59.out test60.out test61.out test62.out test63.out \
 		test64.out test65.out test66.out test67.out test68.out \
-		test69.out test70.out
+		test69.out test70.out test71.out
 
 SCRIPTS_GUI = test16.out
 
@@ -69,7 +69,7 @@ test1.out: test1.in
 		  fi \
 		else echo $* NO OUTPUT >>test.log; \
 		fi"
-	-rm -rf X* test.ok viminfo
+	#-rm -rf X* test.ok viminfo
 
 test49.out: test49.vim
 
new file mode 100644
--- /dev/null
+++ b/src/testdir/test71.in
@@ -0,0 +1,37 @@
+Test for encryption.
+
+STARTTEST
+:so small.vim
+:/^start of testfile/+1
+:let lines = getline('.', '$')
+:new
+:call append(0, lines)
+:$d
+:X
+foobar
+foobar
+:w! Xtestfile
+:bwipe!
+:e Xtestfile
+foobar
+:let dec1_lines = getline('.', '$')
+:%s/^/2/
+:set key=
+:set cryptmethod=1
+:X
+barfoo
+barfoo
+:w! Xtestfile
+:bwipe!
+:e Xtestfile
+barfoo
+:call append(0, dec1_lines)
+:set key=
+:w! test.out
+:qa!
+ENDTEST
+
+start of testfile
+01234567890123456789012345678901234567
+line 2  foo bar blah
+line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
new file mode 100644
--- /dev/null
+++ b/src/testdir/test71.ok
@@ -0,0 +1,6 @@
+01234567890123456789012345678901234567
+line 2  foo bar blah
+line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+201234567890123456789012345678901234567
+2line 2  foo bar blah
+2line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx