Add the blowfish encryption patch from Mohsin Ahmed.  Needs more work.
diff --git a/src/Make_bc5.mak b/src/Make_bc5.mak
index a1d92bd..1373b4e 100644
--- a/src/Make_bc5.mak
+++ b/src/Make_bc5.mak
@@ -533,6 +533,7 @@
 !endif
 
 vimobj =  \
+	$(OBJDIR)\blowfish.obj \
 	$(OBJDIR)\buffer.obj \
 	$(OBJDIR)\charset.obj \
 	$(OBJDIR)\diff.obj \
@@ -567,6 +568,7 @@
 	$(OBJDIR)\regexp.obj \
 	$(OBJDIR)\screen.obj \
 	$(OBJDIR)\search.obj \
+	$(OBJDIR)\sha256.obj \
 	$(OBJDIR)\spell.obj \
 	$(OBJDIR)\syntax.obj \
 	$(OBJDIR)\tag.obj \
diff --git a/src/Make_ivc.mak b/src/Make_ivc.mak
index 2d118d5..1b06aff 100644
--- a/src/Make_ivc.mak
+++ b/src/Make_ivc.mak
@@ -210,6 +210,7 @@
 
 LINK32_OBJS= \
 	$(EXTRAS) \
+	"$(INTDIR)/blowfish.obj" \
 	"$(INTDIR)/buffer.obj" \
 	"$(INTDIR)/charset.obj" \
 	"$(INTDIR)/diff.obj" \
@@ -246,6 +247,7 @@
 	"$(INTDIR)/regexp.obj" \
 	"$(INTDIR)/screen.obj" \
 	"$(INTDIR)/search.obj" \
+	"$(INTDIR)/sha256.obj" \
 	"$(INTDIR)/spell.obj" \
 	"$(INTDIR)/syntax.obj" \
 	"$(INTDIR)/tag.obj" \
diff --git a/src/Make_manx.mak b/src/Make_manx.mak
index b8e7852..c4b3bcb 100644
--- a/src/Make_manx.mak
+++ b/src/Make_manx.mak
@@ -124,7 +124,8 @@
 	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 @@
 	proto/regexp.pro \
 	proto/screen.pro \
 	proto/search.pro \
+	proto/sha256.pro \
 	proto/spell.pro \
 	proto/syntax.pro \
 	proto/tag.pro \
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index 38ced6e..16afb40 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -453,6 +453,8 @@
 	$(NBDEBUG_INCL)
 
 OBJ = \
+	$(OUTDIR)\blowfish.obj \
+	$(OUTDIR)\sha256.obj \
 	$(OUTDIR)\buffer.obj \
 	$(OUTDIR)\charset.obj \
 	$(OUTDIR)\diff.obj \
@@ -912,6 +914,10 @@
 
 $(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 @@
 
 # End Custom Build
 proto.h: \
+	proto/blowfish.pro \
 	proto/buffer.pro \
 	proto/charset.pro \
 	proto/diff.pro \
@@ -1115,6 +1122,7 @@
 	proto/regexp.pro \
 	proto/screen.pro \
 	proto/search.pro \
+	proto/sha256.pro \
 	proto/spell.pro \
 	proto/syntax.pro \
 	proto/tag.pro \
diff --git a/src/Make_sas.mak b/src/Make_sas.mak
index 98ec528..7cbb888 100644
--- a/src/Make_sas.mak
+++ b/src/Make_sas.mak
@@ -179,6 +179,7 @@
 	$(TERMLIB)
 
 PRO = \
+	proto/blowfish.pro \
 	proto/buffer.pro \
 	proto/charset.pro \
 	proto/diff.pro \
@@ -214,6 +215,7 @@
 	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 @@
 	$(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 @@
 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
diff --git a/src/Makefile b/src/Makefile
index f6b6e6f..74d6e88 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -468,7 +468,7 @@
 #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 @@
 #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 @@
 TAGS_INCL = *.h
 
 BASIC_SRC = \
+	blowfish.c \
 	buffer.c \
 	charset.c \
 	diff.c \
@@ -1415,6 +1416,7 @@
 	regexp.c \
 	screen.c \
 	search.c \
+	sha256.c \
 	spell.c \
 	syntax.c \
 	tag.c \
@@ -1449,6 +1451,7 @@
 
 OBJ = \
 	objects/buffer.o \
+	objects/blowfish.o \
 	objects/charset.o \
 	objects/diff.o \
 	objects/digraph.o \
@@ -1487,6 +1490,7 @@
 	objects/regexp.o \
 	objects/screen.o \
 	objects/search.o \
+	objects/sha256.o \
 	objects/spell.o \
 	objects/syntax.o \
 	$(SNIFF_OBJ) \
@@ -1507,6 +1511,7 @@
 	$(WSDEBUG_OBJ)
 
 PRO_AUTO = \
+	blowfish.pro \
 	buffer.pro \
 	charset.pro \
 	diff.pro \
@@ -1547,6 +1552,7 @@
 	regexp.pro \
 	screen.pro \
 	search.pro \
+	sha256.pro \
 	spell.pro \
 	syntax.pro \
 	tag.pro \
@@ -2337,6 +2343,9 @@
 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/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
 
diff --git a/src/blowfish.c b/src/blowfish.c
new file mode 100644
index 0000000..f5b8e90
--- /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 */
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 13e26d5..fd7471d 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -11123,7 +11123,8 @@
 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
 
diff --git a/src/feature.h b/src/feature.h
index ea2e588..4568ffc 100644
--- 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
 
diff --git a/src/fileio.c b/src/fileio.c
index c367969..ad5fddd 100644
--- 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 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 @@
 	     */
 	    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 @@
 
 #ifdef FEAT_CRYPT
     if (cryptkey != curbuf->b_p_key)
-	vim_free(cryptkey);
+	free_crypt_key(cryptkey);
 #endif
 
 #ifdef FEAT_MBYTE
@@ -2456,7 +2465,8 @@
 		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 @@
 
 #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 @@
     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 @@
 
 	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);
+	    *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) */
+    /* 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 @@
 #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;
diff --git a/src/globals.h b/src/globals.h
index d2b898c..a65a2e3 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -105,6 +105,10 @@
 
 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
diff --git a/src/main.c b/src/main.c
index 0330f6a..7e741de 100644
--- a/src/main.c
+++ b/src/main.c
@@ -797,6 +797,7 @@
 #ifdef FEAT_CRYPT
     if (params.ask_for_key)
     {
+	(void)blowfish_self_test();
 	(void)get_crypt_key(TRUE, TRUE);
 	TIME_MSG("getting crypt key");
     }
diff --git a/src/misc2.c b/src/misc2.c
index 8cd5683..3abef15 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -3685,6 +3685,11 @@
  * 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 @@
 {
     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 @@
 /*
  * 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 @@
 }
 
 /*
+ * 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 @@
 	    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 @@
     need_wait_return = FALSE;
     msg_didout = FALSE;
 
-    vim_free(p2);
+    free_crypt_key(p2);
     return p1;
 }
 
diff --git a/src/option.c b/src/option.c
index c9cad32..e7ec0c8 100644
--- 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 @@
 #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 @@
 			    (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 @@
 
 #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 @@
 	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
diff --git a/src/option.h b/src/option.h
index b635db1..b49c0c4 100644
--- a/src/option.h
+++ b/src/option.h
@@ -908,6 +908,7 @@
 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
     , BV_CINW
 #endif
+    , BV_CM
 #ifdef FEAT_FOLDING
     , BV_CMS
 #endif
diff --git a/src/proto.h b/src/proto.h
index 85f4937..dd2e146 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -69,6 +69,9 @@
 #  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 @@
 # endif
 # include "regexp.pro"
 # include "screen.pro"
+# ifdef FEAT_CRYPT
+#  include "sha256.pro"
+# endif
 # include "search.pro"
 # include "spell.pro"
 # include "syntax.pro"
diff --git a/src/proto/blowfish.pro b/src/proto/blowfish.pro
new file mode 100644
index 0000000..6b66287
--- /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 : */
diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro
index 5c4cc42..9b27b7e 100644
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -81,8 +81,9 @@
 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));
diff --git a/src/proto/sha256.pro b/src/proto/sha256.pro
new file mode 100644
index 0000000..635721c
--- /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 : */
diff --git a/src/sha256.c b/src/sha256.c
new file mode 100644
index 0000000..24e57b9
--- /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 */
diff --git a/src/structs.h b/src/structs.h
index 72bd96c..5aceb59 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1358,6 +1358,7 @@
 #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' */
diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak
index 8f35c7b..4b1af5f 100644
--- a/src/testdir/Make_dos.mak
+++ b/src/testdir/Make_dos.mak
@@ -27,7 +27,7 @@
 		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
 
diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak
index 760bb21..960f5b2 100644
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -46,7 +46,7 @@
 		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
 
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
index 073a284..6a8e85f 100644
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -23,7 +23,7 @@
 		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 @@
 		  fi \
 		else echo $* NO OUTPUT >>test.log; \
 		fi"
-	-rm -rf X* test.ok viminfo
+	#-rm -rf X* test.ok viminfo
 
 test49.out: test49.vim
 
diff --git a/src/testdir/test71.in b/src/testdir/test71.in
new file mode 100644
index 0000000..a2eadd3
--- /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
diff --git a/src/testdir/test71.ok b/src/testdir/test71.ok
new file mode 100644
index 0000000..5820892
--- /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