Update decrypt for 4.4

Change-Id: I8d5d7b6a49890e4707d70de8b429563de0d2ad99
diff --git a/Android.mk b/Android.mk
index aa17613..98ea68d9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -354,6 +354,8 @@
 ifeq ($(TW_INCLUDE_JB_CRYPTO), true)
     include $(commands_recovery_local_path)/crypto/jb/Android.mk
     include $(commands_recovery_local_path)/crypto/fs_mgr/Android.mk
+    include $(commands_recovery_local_path)/crypto/logwrapper/Android.mk
+    include $(commands_recovery_local_path)/crypto/scrypt/Android.mk
 endif
 ifeq ($(HAVE_SELINUX), true)
     include $(commands_recovery_local_path)/minzip/Android.mk
diff --git a/crypto/fs_mgr/Android.mk b/crypto/fs_mgr/Android.mk
index b2a341f..f638e98 100644
--- a/crypto/fs_mgr/Android.mk
+++ b/crypto/fs_mgr/Android.mk
@@ -1,34 +1,36 @@
 # Copyright 2011 The Android Open Source Project
-ifeq ($(TW_INCLUDE_JB_CRYPTO), true)
+
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= fs_mgr.c
+LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
 LOCAL_MODULE:= libfs_mgrtwrp
+LOCAL_SHARED_LIBRARIES := libext4_utils
+LOCAL_STATIC_LIBRARIES := liblogwraptwrp libmincrypttwrp
+LOCAL_C_INCLUDES += system/extras/ext4_utils bootable/recovery/libmincrypt/includes
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 
 include $(BUILD_STATIC_LIBRARY)
 
 
 
-#include $(CLEAR_VARS)
+include $(CLEAR_VARS)
 
-#LOCAL_SRC_FILES:= fs_mgr_main.c
+LOCAL_SRC_FILES:= fs_mgr_main.c
 
-#LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
-#LOCAL_MODULE:= fs_mgr
+LOCAL_MODULE:= fs_mgrtwrp
 
-#LOCAL_MODULE_TAGS := optional
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
-#LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
-#LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
+LOCAL_MODULE_TAGS := optional
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
+LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
 
-#LOCAL_STATIC_LIBRARIES := libfs_mgr libcutils libc
+LOCAL_STATIC_LIBRARIES := libfs_mgrtwrp liblogwraptwrp libcutils liblog libc libmincrypttwrp libext4_utils_static
 
-#include $(BUILD_EXECUTABLE)
+include $(BUILD_EXECUTABLE)
 
-endif
diff --git a/crypto/fs_mgr/fs_mgr.c b/crypto/fs_mgr/fs_mgr.c
index 02f3ac5..3aa9e60 100644
--- a/crypto/fs_mgr/fs_mgr.c
+++ b/crypto/fs_mgr/fs_mgr.c
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-/* TO DO:
- *   1. Re-direct fsck output to the kernel log?
- *
- */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -32,17 +27,37 @@
 #include <sys/wait.h>
 #include <libgen.h>
 #include <time.h>
+//#include <sys/swap.h>
+/* XXX These need to be obtained from kernel headers. See b/9336527 */
+#define SWAP_FLAG_PREFER        0x8000
+#define SWAP_FLAG_PRIO_MASK     0x7fff
+#define SWAP_FLAG_PRIO_SHIFT    0
+#define SWAP_FLAG_DISCARD       0x10000
 
+#include <linux/loop.h>
 #include <private/android_filesystem_config.h>
 #include <cutils/partition_utils.h>
 #include <cutils/properties.h>
+#include <logwrap/logwrap.h>
+
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
 
 #include "fs_mgr_priv.h"
+#include "fs_mgr_priv_verity.h"
 
 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
 #define KEY_IN_FOOTER  "footer"
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
+#define MKSWAP_BIN      "/system/bin/mkswap"
+
+#define FSCK_LOG_FILE   "/dev/fscklogs/log"
+
+#define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
 struct flag_list {
     const char *name;
@@ -58,6 +73,12 @@
     { "ro",         MS_RDONLY },
     { "rw",         0 },
     { "remount",    MS_REMOUNT },
+    { "bind",       MS_BIND },
+    { "rec",        MS_REC },
+    { "unbindable", MS_UNBINDABLE },
+    { "private",    MS_PRIVATE },
+    { "slave",      MS_SLAVE },
+    { "shared",     MS_SHARED },
     { "defaults",   0 },
     { 0,            0 },
 };
@@ -66,10 +87,27 @@
     { "wait",        MF_WAIT },
     { "check",       MF_CHECK },
     { "encryptable=",MF_CRYPT },
+    { "nonremovable",MF_NONREMOVABLE },
+    { "voldmanaged=",MF_VOLDMANAGED},
+    { "length=",     MF_LENGTH },
+    { "recoveryonly",MF_RECOVERYONLY },
+    { "swapprio=",   MF_SWAPPRIO },
+    { "zramsize=",   MF_ZRAMSIZE },
+    { "verify",      MF_VERIFY },
+    { "noemulatedsd", MF_NOEMULATEDSD },
     { "defaults",    0 },
     { 0,             0 },
 };
 
+struct fs_mgr_flag_values {
+    char *key_loc;
+    long long part_length;
+    char *label;
+    int partnum;
+    int swap_prio;
+    unsigned int zram_size;
+};
+
 /*
  * gettime() - returns the time in seconds of the system's monotonic clock or
  * zero on error.
@@ -100,7 +138,8 @@
     return ret;
 }
 
-static int parse_flags(char *flags, struct flag_list *fl, char **key_loc,
+static int parse_flags(char *flags, struct flag_list *fl,
+                       struct fs_mgr_flag_values *flag_vals,
                        char *fs_options, int fs_options_len)
 {
     int f = 0;
@@ -108,11 +147,14 @@
     char *p;
     char *savep;
 
-    /* initialize key_loc to null, if we find an MF_CRYPT flag,
-     * then we'll set key_loc to the proper value */
-    if (key_loc) {
-        *key_loc = NULL;
+    /* initialize flag values.  If we find a relevant flag, we'll
+     * update the value */
+    if (flag_vals) {
+        memset(flag_vals, 0, sizeof(*flag_vals));
+        flag_vals->partnum = -1;
+        flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
     }
+
     /* initialize fs_options to the null string */
     if (fs_options && (fs_options_len > 0)) {
         fs_options[0] = '\0';
@@ -126,11 +168,45 @@
         for (i = 0; fl[i].name; i++) {
             if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
                 f |= fl[i].flag;
-                if ((fl[i].flag == MF_CRYPT) && key_loc) {
+                if ((fl[i].flag == MF_CRYPT) && flag_vals) {
                     /* The encryptable flag is followed by an = and the
                      * location of the keys.  Get it and return it.
                      */
-                    *key_loc = strdup(strchr(p, '=') + 1);
+                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
+                    /* The length flag is followed by an = and the
+                     * size of the partition.  Get it and return it.
+                     */
+                    flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
+                    /* The voldmanaged flag is followed by an = and the
+                     * label, a colon and the partition number or the
+                     * word "auto", e.g.
+                     *   voldmanaged=sdcard:3
+                     * Get and return them.
+                     */
+                    char *label_start;
+                    char *label_end;
+                    char *part_start;
+
+                    label_start = strchr(p, '=') + 1;
+                    label_end = strchr(p, ':');
+                    if (label_end) {
+                        flag_vals->label = strndup(label_start,
+                                                   (int) (label_end - label_start));
+                        part_start = strchr(p, ':') + 1;
+                        if (!strcmp(part_start, "auto")) {
+                            flag_vals->partnum = -1;
+                        } else {
+                            flag_vals->partnum = strtol(part_start, NULL, 0);
+                        }
+                    } else {
+                        ERROR("Warning: voldmanaged= flag malformed\n");
+                    }
+                } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
+                    flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
+                    flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
                 }
                 break;
             }
@@ -167,7 +243,7 @@
  * then return an empty buffer.  This effectively ignores lines that are too long.
  * On EOF, return null.
  */
-static char *fs_mgr_getline(char *buf, int size, FILE *file)
+static char *fs_getline(char *buf, int size, FILE *file)
 {
     int cnt = 0;
     int eof = 0;
@@ -221,7 +297,7 @@
     }
 }
 
-static struct fstab_rec *read_fstab(char *fstab_path)
+struct fstab *fs_mgr_read_fstab(const char *fstab_path)
 {
     FILE *fstab_file;
     int cnt, entries;
@@ -229,8 +305,9 @@
     char line[256];
     const char *delim = " \t";
     char *save_ptr, *p;
-    struct fstab_rec *fstab;
-    char *key_loc;
+    struct fstab *fstab;
+    struct fstab_rec *recs;
+    struct fs_mgr_flag_values flag_vals;
 #define FS_OPTIONS_LEN 1024
     char tmp_fs_options[FS_OPTIONS_LEN];
 
@@ -241,7 +318,7 @@
     }
 
     entries = 0;
-    while (fs_mgr_getline(line, sizeof(line), fstab_file)) {
+    while (fs_getline(line, sizeof(line), fstab_file)) {
         /* if the last character is a newline, shorten the string by 1 byte */
         len = strlen(line);
         if (line[len - 1] == '\n') {
@@ -263,12 +340,16 @@
         return 0;
     }
 
-    fstab = calloc(entries + 1, sizeof(struct fstab_rec));
+    /* Allocate and init the fstab structure */
+    fstab = calloc(1, sizeof(struct fstab));
+    fstab->num_entries = entries;
+    fstab->fstab_filename = strdup(fstab_path);
+    fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
 
     fseek(fstab_file, 0, SEEK_SET);
 
     cnt = 0;
-    while (fs_mgr_getline(line, sizeof(line), fstab_file)) {
+    while (fs_getline(line, sizeof(line), fstab_file)) {
         /* if the last character is a newline, shorten the string by 1 byte */
         len = strlen(line);
         if (line[len - 1] == '\n') {
@@ -297,41 +378,47 @@
             ERROR("Error parsing mount source\n");
             return 0;
         }
-        fstab[cnt].blk_dev = strdup(p);
+        fstab->recs[cnt].blk_device = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
-            ERROR("Error parsing mnt_point\n");
+            ERROR("Error parsing mount_point\n");
             return 0;
         }
-        fstab[cnt].mnt_point = strdup(p);
+        fstab->recs[cnt].mount_point = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_type\n");
             return 0;
         }
-        fstab[cnt].type = strdup(p);
+        fstab->recs[cnt].fs_type = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing mount_flags\n");
             return 0;
         }
         tmp_fs_options[0] = '\0';
-        fstab[cnt].flags = parse_flags(p, mount_flags, 0, tmp_fs_options, FS_OPTIONS_LEN);
+        fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
+                                       tmp_fs_options, FS_OPTIONS_LEN);
 
         /* fs_options are optional */
         if (tmp_fs_options[0]) {
-            fstab[cnt].fs_options = strdup(tmp_fs_options);
+            fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
         } else {
-            fstab[cnt].fs_options = NULL;
+            fstab->recs[cnt].fs_options = NULL;
         }
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_mgr_options\n");
             return 0;
         }
-        fstab[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &key_loc, 0, 0);
-        fstab[cnt].key_loc = key_loc;
-
+        fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
+                                                    &flag_vals, NULL, 0);
+        fstab->recs[cnt].key_loc = flag_vals.key_loc;
+        fstab->recs[cnt].length = flag_vals.part_length;
+        fstab->recs[cnt].label = flag_vals.label;
+        fstab->recs[cnt].partnum = flag_vals.partnum;
+        fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
+        fstab->recs[cnt].zram_size = flag_vals.zram_size;
         cnt++;
     }
     fclose(fstab_file);
@@ -339,46 +426,76 @@
     return fstab;
 }
 
-static void free_fstab(struct fstab_rec *fstab)
+void fs_mgr_free_fstab(struct fstab *fstab)
 {
-    int i = 0;
+    int i;
 
-    while (fstab[i].blk_dev) {
+    if (!fstab) {
+        return;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
         /* Free the pointers return by strdup(3) */
-        free(fstab[i].blk_dev);
-        free(fstab[i].mnt_point);
-        free(fstab[i].type);
-        free(fstab[i].fs_options);
-        free(fstab[i].key_loc);
-
+        free(fstab->recs[i].blk_device);
+        free(fstab->recs[i].mount_point);
+        free(fstab->recs[i].fs_type);
+        free(fstab->recs[i].fs_options);
+        free(fstab->recs[i].key_loc);
+        free(fstab->recs[i].label);
         i++;
     }
 
-    /* Free the actual fstab array created by calloc(3) */
+    /* Free the fstab_recs array created by calloc(3) */
+    free(fstab->recs);
+
+    /* Free the fstab filename */
+    free(fstab->fstab_filename);
+
+    /* Free fstab */
     free(fstab);
 }
 
-static void check_fs(char *blk_dev, char *type)
+static void check_fs(char *blk_device, char *fs_type, char *target)
 {
-    pid_t pid;
     int status;
+    int ret;
+    long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
+    char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
+    char *e2fsck_argv[] = {
+        E2FSCK_BIN,
+        "-y",
+        blk_device
+    };
 
     /* Check for the types of filesystems we know how to check */
-    if (!strcmp(type, "ext2") || !strcmp(type, "ext3") || !strcmp(type, "ext4")) {
-        INFO("Running %s on %s\n", E2FSCK_BIN, blk_dev);
-        pid = fork();
-        if (pid > 0) {
-            /* Parent, wait for the child to return */
-            waitpid(pid, &status, 0);
-        } else if (pid == 0) {
-            /* child, run checker */
-            execlp(E2FSCK_BIN, E2FSCK_BIN, "-y", blk_dev, (char *)NULL);
+    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
+        /*
+         * First try to mount and unmount the filesystem.  We do this because
+         * the kernel is more efficient than e2fsck in running the journal and
+         * processing orphaned inodes, and on at least one device with a
+         * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
+         * to do what the kernel does in about a second.
+         *
+         * After mounting and unmounting the filesystem, run e2fsck, and if an
+         * error is recorded in the filesystem superblock, e2fsck will do a full
+         * check.  Otherwise, it does nothing.  If the kernel cannot mount the
+         * filesytsem due to an error, e2fsck is still run to do a full check
+         * fix the filesystem.
+         */
+        ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
+        if (!ret) {
+            umount(target);
+        }
 
-            /* Only gets here on error */
-            ERROR("Cannot run fs_mgr binary %s\n", E2FSCK_BIN);
-        } else {
+        INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
+
+        ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
+                                      &status, true, LOG_KLOG | LOG_FILE,
+                                      true, FSCK_LOG_FILE);
+
+        if (ret < 0) {
             /* No need to check for error in fork, we can't really handle it now */
-            ERROR("Fork failed trying to run %s\n", E2FSCK_BIN);
+            ERROR("Failed trying to run %s\n", E2FSCK_BIN);
         }
     }
 
@@ -396,6 +513,43 @@
     }
 }
 
+/*
+ * Mark the given block device as read-only, using the BLKROSET ioctl.
+ * Return 0 on success, and -1 on error.
+ */
+static void fs_set_blk_ro(const char *blockdev)
+{
+    int fd;
+    int ON = 1;
+
+    fd = open(blockdev, O_RDONLY);
+    if (fd < 0) {
+        // should never happen
+        return;
+    }
+
+    ioctl(fd, BLKROSET, &ON);
+    close(fd);
+}
+
+/*
+ * __mount(): wrapper around the mount() system call which also
+ * sets the underlying block device to read-only if the mount is read-only.
+ * See "man 2 mount" for return values.
+ */
+static int __mount(const char *source, const char *target,
+                   const char *filesystemtype, unsigned long mountflags,
+                   const void *data)
+{
+    int ret = mount(source, target, filesystemtype, mountflags, data);
+
+    if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
+        fs_set_blk_ro(source);
+    }
+
+    return ret;
+}
+
 static int fs_match(char *in1, char *in2)
 {
     char *n1;
@@ -416,49 +570,71 @@
     return ret;
 }
 
-int fs_mgr_mount_all(char *fstab_file)
+int fs_mgr_mount_all(struct fstab *fstab)
 {
     int i = 0;
     int encrypted = 0;
     int ret = -1;
     int mret;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return ret;
     }
 
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (fstab[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Don't mount entries that are managed by vold */
+        if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
+            continue;
         }
 
-        if (fstab[i].fs_mgr_flags & MF_CHECK) {
-            check_fs(fstab[i].blk_dev, fstab[i].type);
+        /* Skip swap and raw partition entries such as boot, recovery, etc */
+        if (!strcmp(fstab->recs[i].fs_type, "swap") ||
+            !strcmp(fstab->recs[i].fs_type, "emmc") ||
+            !strcmp(fstab->recs[i].fs_type, "mtd")) {
+            continue;
         }
 
-        mret = mount(fstab[i].blk_dev, fstab[i].mnt_point, fstab[i].type,
-                     fstab[i].flags, fstab[i].fs_options);
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
+            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+            check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                     fstab->recs[i].mount_point);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+            if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
+                ERROR("Could not set up verified partition, skipping!");
+                continue;
+            }
+        }
+
+        mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
+                     fstab->recs[i].fs_type, fstab->recs[i].flags,
+                     fstab->recs[i].fs_options);
+
         if (!mret) {
             /* Success!  Go get the next one */
             continue;
         }
 
         /* mount(2) returned an error, check if it's encrypted and deal with it */
-        if ((fstab[i].fs_mgr_flags & MF_CRYPT) && !partition_wiped(fstab[i].blk_dev)) {
+        if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
+            !partition_wiped(fstab->recs[i].blk_device)) {
             /* Need to mount a tmpfs at this mountpoint for now, and set
              * properties that vold will query later for decrypting
              */
-            if (mount("tmpfs", fstab[i].mnt_point, "tmpfs",
+            if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
                   MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
                 ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s\n",
-                        fstab[i].mnt_point);
+                        fstab->recs[i].mount_point);
                 goto out;
             }
             encrypted = 1;
         } else {
             ERROR("Cannot mount filesystem on %s at %s\n",
-                    fstab[i].blk_dev, fstab[i].mnt_point);
+                    fstab->recs[i].blk_device, fstab->recs[i].mount_point);
             goto out;
         }
     }
@@ -470,49 +646,65 @@
     }
 
 out:
-    free_fstab(fstab);
     return ret;
 }
 
-/* If tmp_mnt_point is non-null, mount the filesystem there.  This is for the
+/* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
  * tmp mount we do to check the user password
  */
-int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point)
+int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+                    char *tmp_mount_point)
 {
     int i = 0;
     int ret = -1;
-    struct fstab_rec *fstab = 0;
     char *m;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return ret;
     }
 
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (!fs_match(fstab[i].mnt_point, n_name)) {
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (!fs_match(fstab->recs[i].mount_point, n_name)) {
             continue;
         }
 
         /* We found our match */
-        /* First check the filesystem if requested */
-        if (fstab[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
+        /* If this swap or a raw partition, report an error */
+        if (!strcmp(fstab->recs[i].fs_type, "swap") ||
+            !strcmp(fstab->recs[i].fs_type, "emmc") ||
+            !strcmp(fstab->recs[i].fs_type, "mtd")) {
+            ERROR("Cannot mount filesystem of type %s on %s\n",
+                  fstab->recs[i].fs_type, n_blk_device);
+            goto out;
         }
 
-        if ((fstab[i].fs_mgr_flags & MF_CHECK) && strcmp("ext4", fstab[i].type) != 0) {
-            check_fs(fstab[i].blk_dev, fstab[i].type);
+        /* First check the filesystem if requested */
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
+            wait_for_file(n_blk_device, WAIT_TIMEOUT);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+            check_fs(n_blk_device, fstab->recs[i].fs_type,
+                     fstab->recs[i].mount_point);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+            if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
+                ERROR("Could not set up verified partition, skipping!");
+                continue;
+            }
         }
 
         /* Now mount it where requested */
-        if (tmp_mnt_point) {
-            m = tmp_mnt_point;
+        if (tmp_mount_point) {
+            m = tmp_mount_point;
         } else {
-            m = fstab[i].mnt_point;
+            m = fstab->recs[i].mount_point;
         }
-        if (mount(n_blk_dev, m, fstab[i].type,
-                  fstab[i].flags, fstab[i].fs_options)) {
+        if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
+                    fstab->recs[i].flags, fstab->recs[i].fs_options)) {
             ERROR("Cannot mount filesystem on %s at %s\n",
-                    n_blk_dev, m);
+                    n_blk_device, m);
             goto out;
         } else {
             ret = 0;
@@ -521,10 +713,9 @@
     }
 
     /* We didn't find a match, say so and return an error */
-    ERROR("Cannot find mount point %s in fstab\n", fstab[i].mnt_point);
+    ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
 
 out:
-    free_fstab(fstab);
     return ret;
 }
 
@@ -547,65 +738,211 @@
     return 0;
 }
 
-int fs_mgr_unmount_all(char *fstab_file)
+int fs_mgr_unmount_all(struct fstab *fstab)
 {
     int i = 0;
     int ret = 0;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return -1;
     }
 
-    while (fstab[i].blk_dev) {
-        if (umount(fstab[i].mnt_point)) {
-            ERROR("Cannot unmount filesystem at %s\n", fstab[i].mnt_point);
+    while (fstab->recs[i].blk_device) {
+        if (umount(fstab->recs[i].mount_point)) {
+            ERROR("Cannot unmount filesystem at %s\n", fstab->recs[i].mount_point);
             ret = -1;
         }
         i++;
     }
 
-    free_fstab(fstab);
     return ret;
 }
+
+/* This must be called after mount_all, because the mkswap command needs to be
+ * available.
+ */
+int fs_mgr_swapon_all(struct fstab *fstab)
+{
+    int i = 0;
+    int flags = 0;
+    int err = 0;
+    int ret = 0;
+    int status;
+    char *mkswap_argv[2] = {
+        MKSWAP_BIN,
+        NULL
+    };
+
+    if (!fstab) {
+        return -1;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Skip non-swap entries */
+        if (strcmp(fstab->recs[i].fs_type, "swap")) {
+            continue;
+        }
+
+        if (fstab->recs[i].zram_size > 0) {
+            /* A zram_size was specified, so we need to configure the
+             * device.  There is no point in having multiple zram devices
+             * on a system (all the memory comes from the same pool) so
+             * we can assume the device number is 0.
+             */
+            FILE *zram_fp;
+
+            zram_fp = fopen(ZRAM_CONF_DEV, "r+");
+            if (zram_fp == NULL) {
+                ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
+                ret = -1;
+                continue;
+            }
+            fprintf(zram_fp, "%d\n", fstab->recs[i].zram_size);
+            fclose(zram_fp);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
+            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+        }
+
+        /* Initialize the swap area */
+        mkswap_argv[1] = fstab->recs[i].blk_device;
+        err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
+                                      &status, true, LOG_KLOG, false, NULL);
+        if (err) {
+            ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
+            ret = -1;
+            continue;
+        }
+
+        /* If -1, then no priority was specified in fstab, so don't set
+         * SWAP_FLAG_PREFER or encode the priority */
+        if (fstab->recs[i].swap_prio >= 0) {
+            flags = (fstab->recs[i].swap_prio << SWAP_FLAG_PRIO_SHIFT) &
+                    SWAP_FLAG_PRIO_MASK;
+            flags |= SWAP_FLAG_PREFER;
+        } else {
+            flags = 0;
+        }
+        // requires sys/swap.h which is not available in older trees
+        // this entire function does not appear to be used for decrypt
+        err = -1; //swapon(fstab->recs[i].blk_device, flags);
+        if (err) {
+            ERROR("swapon failed for %s\n", fstab->recs[i].blk_device);
+            ret = -1;
+        }
+    }
+
+    return ret;
+}
+
 /*
  * key_loc must be at least PROPERTY_VALUE_MAX bytes long
  *
- * real_blk_dev must be at least PROPERTY_VALUE_MAX bytes long
+ * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
  */
-int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size)
+int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
 {
     int i = 0;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return -1;
     }
     /* Initialize return values to null strings */
     if (key_loc) {
         *key_loc = '\0';
     }
-    if (real_blk_dev) {
-        *real_blk_dev = '\0';
+    if (real_blk_device) {
+        *real_blk_device = '\0';
     }
 
     /* Look for the encryptable partition to find the data */
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (!(fstab[i].fs_mgr_flags & MF_CRYPT)) {
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Don't deal with vold managed enryptable partitions here */
+        if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
+            continue;
+        }
+        if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
             continue;
         }
 
         /* We found a match */
         if (key_loc) {
-            strlcpy(key_loc, fstab[i].key_loc, size);
+            strlcpy(key_loc, fstab->recs[i].key_loc, size);
         }
-        if (real_blk_dev) {
-            strlcpy(real_blk_dev, fstab[i].blk_dev, size);
+        if (real_blk_device) {
+            strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
         }
         break;
     }
 
-    free_fstab(fstab);
     return 0;
 }
 
+/* Add an entry to the fstab, and return 0 on success or -1 on error */
+int fs_mgr_add_entry(struct fstab *fstab,
+                     const char *mount_point, const char *fs_type,
+                     const char *blk_device, long long length)
+{
+    struct fstab_rec *new_fstab_recs;
+    int n = fstab->num_entries;
+
+    new_fstab_recs = (struct fstab_rec *)
+                     realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
+
+    if (!new_fstab_recs) {
+        return -1;
+    }
+
+    /* A new entry was added, so initialize it */
+     memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
+     new_fstab_recs[n].mount_point = strdup(mount_point);
+     new_fstab_recs[n].fs_type = strdup(fs_type);
+     new_fstab_recs[n].blk_device = strdup(blk_device);
+     new_fstab_recs[n].length = 0;
+
+     /* Update the fstab struct */
+     fstab->recs = new_fstab_recs;
+     fstab->num_entries++;
+
+     return 0;
+}
+
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+{
+    int i;
+
+    if (!fstab) {
+        return NULL;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        int len = strlen(fstab->recs[i].mount_point);
+        if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
+            (path[len] == '\0' || path[len] == '/')) {
+            return &fstab->recs[i];
+        }
+    }
+
+    return NULL;
+}
+
+int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_VOLDMANAGED;
+}
+
+int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NONREMOVABLE;
+}
+
+int fs_mgr_is_encryptable(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_CRYPT;
+}
+
+int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
+}
diff --git a/crypto/fs_mgr/fs_mgr_main.c b/crypto/fs_mgr/fs_mgr_main.c
index 81febf1..4bde4a1 100644
--- a/crypto/fs_mgr/fs_mgr_main.c
+++ b/crypto/fs_mgr/fs_mgr_main.c
@@ -82,7 +82,8 @@
     int n_flag=0;
     char *n_name;
     char *n_blk_dev;
-    char *fstab;
+    char *fstab_file;
+    struct fstab *fstab;
 
     klog_init();
     klog_set_level(6);
@@ -90,7 +91,9 @@
     parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev);
 
     /* The name of the fstab file is last, after the option */
-    fstab = argv[argc - 1];
+    fstab_file = argv[argc - 1];
+
+    fstab = fs_mgr_read_fstab(fstab_file);
 
     if (a_flag) {
         return fs_mgr_mount_all(fstab);
@@ -103,6 +106,8 @@
         exit(1);
     }
 
+    fs_mgr_free_fstab(fstab);
+
     /* Should not get here */
     exit(1);
 }
diff --git a/crypto/fs_mgr/fs_mgr_priv.h b/crypto/fs_mgr/fs_mgr_priv.h
index 175fdab..59ffd78 100644
--- a/crypto/fs_mgr/fs_mgr_priv.h
+++ b/crypto/fs_mgr/fs_mgr_priv.h
@@ -25,17 +25,7 @@
 
 #define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000"
 
-struct fstab_rec {
-    char *blk_dev;
-    char *mnt_point;
-    char *type;
-    unsigned long flags;
-    char *fs_options;
-    int fs_mgr_flags;
-    char *key_loc;
-};
-
-#define WAIT_TIMEOUT 5
+#define WAIT_TIMEOUT 20
 
 /* fstab has the following format:
  *
@@ -59,8 +49,8 @@
  *                     run an fscheck program on the <source> before mounting the filesystem.
  *                     If check is specifed on a read-only filesystem, it is ignored.
  *                     Also, "encryptable" means that filesystem can be encrypted.
- *                     The "encryptable" flag _MUST_ be followed by a : and a string which
- *                     is the location of the encryption keys.  I can either be a path
+ *                     The "encryptable" flag _MUST_ be followed by a = and a string which
+ *                     is the location of the encryption keys.  It can either be a path
  *                     to a file or partition which contains the keys, or the word "footer"
  *                     which means the keys are in the last 16 Kbytes of the partition
  *                     containing the filesystem.
@@ -72,9 +62,24 @@
  *
  */
 
-#define MF_WAIT      0x1
-#define MF_CHECK     0x2
-#define MF_CRYPT     0x4
+#define MF_WAIT         0x1
+#define MF_CHECK        0x2
+#define MF_CRYPT        0x4
+#define MF_NONREMOVABLE 0x8
+#define MF_VOLDMANAGED  0x10
+#define MF_LENGTH       0x20
+#define MF_RECOVERYONLY 0x40
+#define MF_SWAPPRIO     0x80
+#define MF_ZRAMSIZE     0x100
+#define MF_VERIFY       0x200
+/*
+ * There is no emulated sdcard daemon running on /data/media on this device,
+ * so treat the physical SD card as the only external storage device,
+ * a la the Nexus One.
+ */
+#define MF_NOEMULATEDSD 0x400
+
+#define DM_BUF_SIZE 4096
 
 #endif /* __CORE_FS_MGR_PRIV_H */
 
diff --git a/crypto/fs_mgr/fs_mgr_priv_verity.h b/crypto/fs_mgr/fs_mgr_priv_verity.h
new file mode 100644
index 0000000..6193784
--- /dev/null
+++ b/crypto/fs_mgr/fs_mgr_priv_verity.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+int fs_mgr_setup_verity(struct fstab_rec *fstab);
\ No newline at end of file
diff --git a/crypto/fs_mgr/fs_mgr_verity.c b/crypto/fs_mgr/fs_mgr_verity.c
new file mode 100644
index 0000000..969eab2
--- /dev/null
+++ b/crypto/fs_mgr/fs_mgr_verity.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <libgen.h>
+#include <time.h>
+
+#include <private/android_filesystem_config.h>
+#include <logwrap/logwrap.h>
+
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
+
+#include "ext4_utils.h"
+#include "ext4.h"
+
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_verity.h"
+
+#define VERITY_METADATA_SIZE 32768
+#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
+#define VERITY_TABLE_RSA_KEY "/verity_key"
+
+extern struct fs_info info;
+
+static RSAPublicKey *load_key(char *path)
+{
+    FILE *f;
+    RSAPublicKey *key;
+
+    key = malloc(sizeof(RSAPublicKey));
+    if (!key) {
+        ERROR("Can't malloc key\n");
+        return NULL;
+    }
+
+    f = fopen(path, "r");
+    if (!f) {
+        ERROR("Can't open '%s'\n", path);
+        free(key);
+        return NULL;
+    }
+
+    if (!fread(key, sizeof(*key), 1, f)) {
+        ERROR("Could not read key!");
+        fclose(f);
+        free(key);
+        return NULL;
+    }
+
+    if (key->len != RSANUMWORDS) {
+        ERROR("Invalid key length %d\n", key->len);
+        fclose(f);
+        free(key);
+        return NULL;
+    }
+
+    fclose(f);
+    return key;
+}
+
+static int verify_table(char *signature, char *table, int table_length)
+{
+    int fd;
+    RSAPublicKey *key;
+    uint8_t hash_buf[SHA_DIGEST_SIZE];
+    int retval = -1;
+
+    // Hash the table
+    SHA_hash((uint8_t*)table, table_length, hash_buf);
+
+    // Now get the public key from the keyfile
+    key = load_key(VERITY_TABLE_RSA_KEY);
+    if (!key) {
+        ERROR("Couldn't load verity keys");
+        goto out;
+    }
+
+    // verify the result
+    if (!RSA_verify(key,
+                    (uint8_t*) signature,
+                    RSANUMBYTES,
+                    (uint8_t*) hash_buf,
+                    SHA_DIGEST_SIZE)) {
+        ERROR("Couldn't verify table.");
+        goto out;
+    }
+
+    retval = 0;
+
+out:
+    free(key);
+    return retval;
+}
+
+static int get_target_device_size(char *blk_device, uint64_t *device_size)
+{
+    int data_device;
+    struct ext4_super_block sb;
+
+    data_device = open(blk_device, O_RDONLY);
+    if (data_device < 0) {
+        ERROR("Error opening block device (%s)", strerror(errno));
+        return -1;
+    }
+
+    if (lseek64(data_device, 1024, SEEK_SET) < 0) {
+        ERROR("Error seeking to superblock");
+        close(data_device);
+        return -1;
+    }
+
+    if (read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
+        ERROR("Error reading superblock");
+        close(data_device);
+        return -1;
+    }
+
+    ext4_parse_sb(&sb);
+    *device_size = info.len;
+
+    close(data_device);
+    return 0;
+}
+
+static int read_verity_metadata(char *block_device, char **signature, char **table)
+{
+    unsigned magic_number;
+    unsigned table_length;
+    uint64_t device_length;
+    int protocol_version;
+    FILE *device;
+    int retval = -1;
+
+    device = fopen(block_device, "r");
+    if (!device) {
+        ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno));
+        goto out;
+    }
+
+    // find the start of the verity metadata
+    if (get_target_device_size(block_device, &device_length) < 0) {
+        ERROR("Could not get target device size.\n");
+        goto out;
+    }
+    if (fseek(device, device_length, SEEK_SET) < 0) {
+        ERROR("Could not seek to start of verity metadata block.\n");
+        goto out;
+    }
+
+    // check the magic number
+    if (!fread(&magic_number, sizeof(int), 1, device)) {
+        ERROR("Couldn't read magic number!\n");
+        goto out;
+    }
+    if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
+        ERROR("Couldn't find verity metadata at offset %llu!\n", device_length);
+        goto out;
+    }
+
+    // check the protocol version
+    if (!fread(&protocol_version, sizeof(int), 1, device)) {
+        ERROR("Couldn't read verity metadata protocol version!\n");
+        goto out;
+    }
+    if (protocol_version != 0) {
+        ERROR("Got unknown verity metadata protocol version %d!\n", protocol_version);
+        goto out;
+    }
+
+    // get the signature
+    *signature = (char*) malloc(RSANUMBYTES * sizeof(char));
+    if (!*signature) {
+        ERROR("Couldn't allocate memory for signature!\n");
+        goto out;
+    }
+    if (!fread(*signature, RSANUMBYTES, 1, device)) {
+        ERROR("Couldn't read signature from verity metadata!\n");
+        free(*signature);
+        goto out;
+    }
+
+    // get the size of the table
+    if (!fread(&table_length, sizeof(int), 1, device)) {
+        ERROR("Couldn't get the size of the verity table from metadata!\n");
+        free(*signature);
+        goto out;
+    }
+
+    // get the table + null terminator
+    table_length += 1;
+    *table = malloc(table_length);
+    if(!*table) {
+        ERROR("Couldn't allocate memory for verity table!\n");
+        goto out;
+    }
+    if (!fgets(*table, table_length, device)) {
+        ERROR("Couldn't read the verity table from metadata!\n");
+        free(*table);
+        free(*signature);
+        goto out;
+    }
+
+    retval = 0;
+
+out:
+    if (device)
+        fclose(device);
+    return retval;
+}
+
+static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
+{
+    memset(io, 0, DM_BUF_SIZE);
+    io->data_size = DM_BUF_SIZE;
+    io->data_start = sizeof(struct dm_ioctl);
+    io->version[0] = 4;
+    io->version[1] = 0;
+    io->version[2] = 0;
+    io->flags = flags | DM_READONLY_FLAG;
+    if (name) {
+        strlcpy(io->name, name, sizeof(io->name));
+    }
+}
+
+static int create_verity_device(struct dm_ioctl *io, char *name, int fd)
+{
+    verity_ioctl_init(io, name, 1);
+    if (ioctl(fd, DM_DEV_CREATE, io)) {
+        ERROR("Error creating device mapping (%s)", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name)
+{
+    verity_ioctl_init(io, name, 0);
+    if (ioctl(fd, DM_DEV_STATUS, io)) {
+        ERROR("Error fetching verity device number (%s)", strerror(errno));
+        return -1;
+    }
+    int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
+    if (asprintf(dev_name, "/dev/block/dm-%u", dev_num) < 0) {
+        ERROR("Error getting verity block device name (%s)", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table)
+{
+    char *verity_params;
+    char *buffer = (char*) io;
+    uint64_t device_size = 0;
+
+    if (get_target_device_size(blockdev, &device_size) < 0) {
+        return -1;
+    }
+
+    verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
+
+    struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
+
+    // set tgt arguments here
+    io->target_count = 1;
+    tgt->status=0;
+    tgt->sector_start=0;
+    tgt->length=device_size/512;
+    strcpy(tgt->target_type, "verity");
+
+    // build the verity params here
+    verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+    if (sprintf(verity_params, "%s", table) < 0) {
+        return -1;
+    }
+
+    // set next target boundary
+    verity_params += strlen(verity_params) + 1;
+    verity_params = (char*) (((unsigned long)verity_params + 7) & ~8);
+    tgt->next = verity_params - buffer;
+
+    // send the ioctl to load the verity table
+    if (ioctl(fd, DM_TABLE_LOAD, io)) {
+        ERROR("Error loading verity table (%s)", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int resume_verity_table(struct dm_ioctl *io, char *name, int fd)
+{
+    verity_ioctl_init(io, name, 0);
+    if (ioctl(fd, DM_DEV_SUSPEND, io)) {
+        ERROR("Error activating verity device (%s)", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+static int test_access(char *device) {
+    int tries = 25;
+    while (tries--) {
+        if (!access(device, F_OK) || errno != ENOENT) {
+            return 0;
+        }
+        usleep(40 * 1000);
+    }
+    return -1;
+}
+
+int fs_mgr_setup_verity(struct fstab_rec *fstab) {
+
+    int retval = -1;
+
+    char *verity_blk_name;
+    char *verity_table;
+    char *verity_table_signature;
+
+    char buffer[DM_BUF_SIZE];
+    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+    char *mount_point = basename(fstab->mount_point);
+
+    // set the dm_ioctl flags
+    io->flags |= 1;
+    io->target_count = 1;
+
+    // get the device mapper fd
+    int fd;
+    if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
+        ERROR("Error opening device mapper (%s)", strerror(errno));
+        return retval;
+    }
+
+    // create the device
+    if (create_verity_device(io, mount_point, fd) < 0) {
+        ERROR("Couldn't create verity device!");
+        goto out;
+    }
+
+    // get the name of the device file
+    if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) {
+        ERROR("Couldn't get verity device number!");
+        goto out;
+    }
+
+    // read the verity block at the end of the block device
+    if (read_verity_metadata(fstab->blk_device,
+                                    &verity_table_signature,
+                                    &verity_table) < 0) {
+        goto out;
+    }
+
+    // verify the signature on the table
+    if (verify_table(verity_table_signature,
+                            verity_table,
+                            strlen(verity_table)) < 0) {
+        goto out;
+    }
+
+    // load the verity mapping table
+    if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) {
+        goto out;
+    }
+
+    // activate the device
+    if (resume_verity_table(io, mount_point, fd) < 0) {
+        goto out;
+    }
+
+    // assign the new verity block device as the block device
+    free(fstab->blk_device);
+    fstab->blk_device = verity_blk_name;
+
+    // make sure we've set everything up properly
+    if (test_access(fstab->blk_device) < 0) {
+        goto out;
+    }
+
+    retval = 0;
+
+out:
+    close(fd);
+    return retval;
+}
diff --git a/crypto/fs_mgr/include/fs_mgr.h b/crypto/fs_mgr/include/fs_mgr.h
index 76abb83..0f90c32 100644
--- a/crypto/fs_mgr/include/fs_mgr.h
+++ b/crypto/fs_mgr/include/fs_mgr.h
@@ -17,11 +17,56 @@
 #ifndef __CORE_FS_MGR_H
 #define __CORE_FS_MGR_H
 
-int fs_mgr_mount_all(char *fstab_file);
-int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point);
+#include <stdint.h>
+#include <linux/dm-ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct fstab {
+    int num_entries;
+    struct fstab_rec *recs;
+    char *fstab_filename;
+};
+
+struct fstab_rec {
+    char *blk_device;
+    char *mount_point;
+    char *fs_type;
+    unsigned long flags;
+    char *fs_options;
+    int fs_mgr_flags;
+    char *key_loc;
+    char *verity_loc;
+    long long length;
+    char *label;
+    int partnum;
+    int swap_prio;
+    unsigned int zram_size;
+};
+
+struct fstab *fs_mgr_read_fstab(const char *fstab_path);
+void fs_mgr_free_fstab(struct fstab *fstab);
+int fs_mgr_mount_all(struct fstab *fstab);
+int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+                    char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
-int fs_mgr_unmount_all(char *fstab_file);
-int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size);
+int fs_mgr_unmount_all(struct fstab *fstab);
+int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
+                          char *real_blk_device, int size);
+int fs_mgr_add_entry(struct fstab *fstab,
+                     const char *mount_point, const char *fs_type,
+                     const char *blk_device, long long length);
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path);
+int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
+int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
+int fs_mgr_is_encryptable(struct fstab_rec *fstab);
+int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab);
+int fs_mgr_swapon_all(struct fstab *fstab);
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* __CORE_FS_MGR_H */
 
diff --git a/crypto/jb/Android.mk b/crypto/jb/Android.mk
index eebfcf0..dc458fd 100644
--- a/crypto/jb/Android.mk
+++ b/crypto/jb/Android.mk
@@ -7,9 +7,9 @@
 LOCAL_MODULES_TAGS = optional
 LOCAL_CFLAGS = 
 LOCAL_SRC_FILES = cryptfs.c
-LOCAL_C_INCLUDES += system/extras/ext4_utils external/openssl/include
-LOCAL_SHARED_LIBRARIES += libc liblog libcutils libcrypto
-LOCAL_STATIC_LIBRARIES += libfs_mgrtwrp
+LOCAL_C_INCLUDES += system/extras/ext4_utils external/openssl/include bootable/recovery/crypto/scrypt/lib/crypto
+LOCAL_SHARED_LIBRARIES += libc liblog libcutils libcrypto libext4_utils
+LOCAL_STATIC_LIBRARIES += libfs_mgrtwrp libscrypttwrp_static liblogwraptwrp libmincrypttwrp
 
 include $(BUILD_SHARED_LIBRARY)
 endif
\ No newline at end of file
diff --git a/crypto/jb/cryptfs.c b/crypto/jb/cryptfs.c
index be6c476..4e5706b 100644
--- a/crypto/jb/cryptfs.c
+++ b/crypto/jb/cryptfs.c
@@ -21,6 +21,7 @@
  */
 
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -35,17 +36,19 @@
 #include <openssl/evp.h>
 #include <openssl/sha.h>
 #include <errno.h>
-#include <cutils/android_reboot.h>
 #include <ext4.h>
 #include <linux/kdev_t.h>
-#include "../fs_mgr/include/fs_mgr.h"
+#include <fs_mgr.h>
 #include "cryptfs.h"
 #define LOG_TAG "Cryptfs"
-#include "cutils/android_reboot.h"
 #include "cutils/log.h"
 #include "cutils/properties.h"
+#include "cutils/android_reboot.h"
 #include "hardware_legacy/power.h"
-//#include "VolumeManager.h"
+/*#include <logwrap/logwrap.h>
+#include "VolumeManager.h"
+#include "VoldUtil.h"*/
+#include "crypto_scrypt.h"
 
 #define DM_CRYPT_BUF_SIZE 4096
 #define DATA_MNT_POINT "/data"
@@ -59,14 +62,29 @@
 #define EXT4_FS 1
 #define FAT_FS 2
 
+#define TABLE_LOAD_RETRIES 10
+
 char *me = "cryptfs";
 
 static unsigned char saved_master_key[KEY_LEN_BYTES];
-static char *saved_data_blkdev;
 static char *saved_mount_point;
 static int  master_key_saved = 0;
-#define FSTAB_PREFIX "/fstab."
-static char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+static struct crypt_persist_data *persist_data = NULL;
+
+struct fstab *fstab;
+
+static void cryptfs_reboot(int recovery)
+{
+    /*if (recovery) {
+        property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
+    } else {
+        property_set(ANDROID_RB_PROPERTY, "reboot");
+    }
+    sleep(20);*/
+
+    /* Shouldn't get here, reboot should happen before sleep times out */
+    return;
+}
 
 static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
 {
@@ -82,6 +100,56 @@
     }
 }
 
+/**
+ * Gets the default device scrypt parameters for key derivation time tuning.
+ * The parameters should lead to about one second derivation time for the
+ * given device.
+ */
+static void get_device_scrypt_params(struct crypt_mnt_ftr *ftr) {
+    const int default_params[] = SCRYPT_DEFAULTS;
+    int params[] = SCRYPT_DEFAULTS;
+    char paramstr[PROPERTY_VALUE_MAX];
+    char *token;
+    char *saveptr;
+    int i;
+
+    property_get(SCRYPT_PROP, paramstr, "");
+    if (paramstr[0] != '\0') {
+        /*
+         * The token we're looking for should be three integers separated by
+         * colons (e.g., "12:8:1"). Scan the property to make sure it matches.
+         */
+        for (i = 0, token = strtok_r(paramstr, ":", &saveptr);
+                token != NULL && i < 3;
+                i++, token = strtok_r(NULL, ":", &saveptr)) {
+            char *endptr;
+            params[i] = strtol(token, &endptr, 10);
+
+            /*
+             * Check that there was a valid number and it's 8-bit. If not,
+             * break out and the end check will take the default values.
+             */
+            if ((*token == '\0') || (*endptr != '\0') || params[i] < 0 || params[i] > 255) {
+                break;
+            }
+        }
+
+        /*
+         * If there were not enough tokens or a token was malformed (not an
+         * integer), it will end up here and the default parameters can be
+         * taken.
+         */
+        if ((i != 3) || (token != NULL)) {
+            printf("bad scrypt parameters '%s' should be like '12:8:1'; using defaults", paramstr);
+            memcpy(params, default_params, sizeof(params));
+        }
+    }
+
+    ftr->N_factor = params[0];
+    ftr->r_factor = params[1];
+    ftr->p_factor = params[2];
+}
+
 static unsigned int get_fs_size(char *dev)
 {
     int fd, block_size;
@@ -89,17 +157,17 @@
     off64_t len;
 
     if ((fd = open(dev, O_RDONLY)) < 0) {
-        SLOGE("Cannot open device to get filesystem size ");
+        printf("Cannot open device to get filesystem size ");
         return 0;
     }
 
     if (lseek64(fd, 1024, SEEK_SET) < 0) {
-        SLOGE("Cannot seek to superblock");
+        printf("Cannot seek to superblock");
         return 0;
     }
 
     if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
-        SLOGE("Cannot read superblock");
+        printf("Cannot read superblock");
         return 0;
     }
 
@@ -124,108 +192,102 @@
   return nr_sec;
 }
 
-/* Get and cache the name of the fstab file so we don't
- * keep talking over the socket to the property service.
- */
-static char *get_fstab_filename(void)
+static int get_crypt_ftr_info(char **metadata_fname, off64_t *off)
 {
-    if (fstab_filename[0] == 0) {
-        strcpy(fstab_filename, FSTAB_PREFIX);
-        property_get("ro.hardware", fstab_filename + sizeof(FSTAB_PREFIX) - 1, "");
-    }
+  static int cached_data = 0;
+  static off64_t cached_off = 0;
+  static char cached_metadata_fname[PROPERTY_VALUE_MAX] = "";
+  int fd;
+  char key_loc[PROPERTY_VALUE_MAX];
+  char real_blkdev[PROPERTY_VALUE_MAX];
+  unsigned int nr_sec;
+  int rc = -1;
 
-    return fstab_filename;
+  if (!cached_data) {
+    fs_mgr_get_crypt_info(fstab, key_loc, real_blkdev, sizeof(key_loc));
+
+    if (!strcmp(key_loc, KEY_IN_FOOTER)) {
+      if ( (fd = open(real_blkdev, O_RDWR)) < 0) {
+        printf("Cannot open real block device %s\n", real_blkdev);
+        return -1;
+      }
+
+      if ((nr_sec = get_blkdev_size(fd))) {
+        /* If it's an encrypted Android partition, the last 16 Kbytes contain the
+         * encryption info footer and key, and plenty of bytes to spare for future
+         * growth.
+         */
+        strlcpy(cached_metadata_fname, real_blkdev, sizeof(cached_metadata_fname));
+        cached_off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET;
+        cached_data = 1;
+      } else {
+        printf("Cannot get size of block device %s\n", real_blkdev);
+      }
+      close(fd);
+    } else {
+      strlcpy(cached_metadata_fname, key_loc, sizeof(cached_metadata_fname));
+      cached_off = 0;
+      cached_data = 1;
+    }
+  }
+
+  if (cached_data) {
+    if (metadata_fname) {
+        *metadata_fname = cached_metadata_fname;
+    }
+    if (off) {
+        *off = cached_off;
+    }
+    rc = 0;
+  }
+
+  return rc;
 }
 
 /* key or salt can be NULL, in which case just skip writing that value.  Useful to
  * update the failed mount count but not change the key.
  */
-static int put_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *crypt_ftr,
-                                  unsigned char *key, unsigned char *salt)
+static int put_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
 {
   int fd;
   unsigned int nr_sec, cnt;
-  off64_t off;
+  /* starting_off is set to the SEEK_SET offset
+   * where the crypto structure starts
+   */
+  off64_t starting_off;
   int rc = -1;
-  char *fname;
-  char key_loc[PROPERTY_VALUE_MAX];
+  char *fname = NULL;
   struct stat statbuf;
 
-  fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
-
-  if (!strcmp(key_loc, KEY_IN_FOOTER)) {
-    fname = real_blk_name;
-    if ( (fd = open(fname, O_RDWR)) < 0) {
-      SLOGE("Cannot open real block device %s\n", fname);
-      return -1;
-    }
-
-    if ( (nr_sec = get_blkdev_size(fd)) == 0) {
-      SLOGE("Cannot get size of block device %s\n", fname);
-      goto errout;
-    }
-
-    /* If it's an encrypted Android partition, the last 16 Kbytes contain the
-     * encryption info footer and key, and plenty of bytes to spare for future
-     * growth.
-     */
-    off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET;
-
-    if (lseek64(fd, off, SEEK_SET) == -1) {
-      SLOGE("Cannot seek to real block device footer\n");
-      goto errout;
-    }
-  } else if (key_loc[0] == '/') {
-    fname = key_loc;
-    if ( (fd = open(fname, O_RDWR | O_CREAT, 0600)) < 0) {
-      SLOGE("Cannot open footer file %s\n", fname);
-      return -1;
-    }
-  } else {
-    SLOGE("Unexpected value for crypto key location\n");
-    return -1;;
+  if (get_crypt_ftr_info(&fname, &starting_off)) {
+    printf("Unable to get crypt_ftr_info\n");
+    return -1;
+  }
+  if (fname[0] != '/') {
+    printf("Unexpected value for crypto key location\n");
+    return -1;
+  }
+  if ( (fd = open(fname, O_RDWR | O_CREAT, 0600)) < 0) {
+    printf("Cannot open footer file %s for put\n", fname);
+    return -1;
   }
 
-  if ((cnt = write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) {
-    SLOGE("Cannot write real block device footer\n");
+  /* Seek to the start of the crypt footer */
+  if (lseek64(fd, starting_off, SEEK_SET) == -1) {
+    printf("Cannot seek to real block device footer\n");
     goto errout;
   }
 
-  if (key) {
-    if (crypt_ftr->keysize != KEY_LEN_BYTES) {
-      SLOGE("Keysize of %d bits not supported for real block device %s\n",
-            crypt_ftr->keysize*8, fname);
-      goto errout; 
-    }
-
-    if ( (cnt = write(fd, key, crypt_ftr->keysize)) != crypt_ftr->keysize) {
-      SLOGE("Cannot write key for real block device %s\n", fname);
-      goto errout;
-    }
-  }
-
-  if (salt) {
-    /* Compute the offset from the last write to the salt */
-    off = KEY_TO_SALT_PADDING;
-    if (! key)
-      off += crypt_ftr->keysize;
-
-    if (lseek64(fd, off, SEEK_CUR) == -1) {
-      SLOGE("Cannot seek to real block device salt \n");
-      goto errout;
-    }
-
-    if ( (cnt = write(fd, salt, SALT_LEN)) != SALT_LEN) {
-      SLOGE("Cannot write salt for real block device %s\n", fname);
-      goto errout;
-    }
+  if ((cnt = write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) {
+    printf("Cannot write real block device footer\n");
+    goto errout;
   }
 
   fstat(fd, &statbuf);
   /* If the keys are kept on a raw block device, do not try to truncate it. */
-  if (S_ISREG(statbuf.st_mode) && (key_loc[0] == '/')) {
+  if (S_ISREG(statbuf.st_mode)) {
     if (ftruncate(fd, 0x4000)) {
-      SLOGE("Cannot set footer file size\n", fname);
+      printf("Cannot set footer file size\n", fname);
       goto errout;
     }
   }
@@ -239,110 +301,144 @@
 
 }
 
-static int get_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *crypt_ftr,
-                                  unsigned char *key, unsigned char *salt)
+static inline int unix_read(int  fd, void*  buff, int  len)
+{
+    return TEMP_FAILURE_RETRY(read(fd, buff, len));
+}
+
+static inline int unix_write(int  fd, const void*  buff, int  len)
+{
+    return TEMP_FAILURE_RETRY(write(fd, buff, len));
+}
+
+static void init_empty_persist_data(struct crypt_persist_data *pdata, int len)
+{
+    memset(pdata, 0, len);
+    pdata->persist_magic = PERSIST_DATA_MAGIC;
+    pdata->persist_valid_entries = 0;
+}
+
+/* A routine to update the passed in crypt_ftr to the lastest version.
+ * fd is open read/write on the device that holds the crypto footer and persistent
+ * data, crypt_ftr is a pointer to the struct to be updated, and offset is the
+ * absolute offset to the start of the crypt_mnt_ftr on the passed in fd.
+ */
+static void upgrade_crypt_ftr(int fd, struct crypt_mnt_ftr *crypt_ftr, off64_t offset)
+{
+    int orig_major = crypt_ftr->major_version;
+    int orig_minor = crypt_ftr->minor_version;
+    return; // in recovery we don't want to upgrade
+    if ((crypt_ftr->major_version == 1) && (crypt_ftr->minor_version == 0)) {
+        struct crypt_persist_data *pdata;
+        off64_t pdata_offset = offset + CRYPT_FOOTER_TO_PERSIST_OFFSET;
+
+        printf("upgrading crypto footer to 1.1");
+
+        pdata = malloc(CRYPT_PERSIST_DATA_SIZE);
+        if (pdata == NULL) {
+            printf("Cannot allocate persisent data\n");
+            return;
+        }
+        memset(pdata, 0, CRYPT_PERSIST_DATA_SIZE);
+
+        /* Need to initialize the persistent data area */
+        if (lseek64(fd, pdata_offset, SEEK_SET) == -1) {
+            printf("Cannot seek to persisent data offset\n");
+            return;
+        }
+        /* Write all zeros to the first copy, making it invalid */
+        unix_write(fd, pdata, CRYPT_PERSIST_DATA_SIZE);
+
+        /* Write a valid but empty structure to the second copy */
+        init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE);
+        unix_write(fd, pdata, CRYPT_PERSIST_DATA_SIZE);
+
+        /* Update the footer */
+        crypt_ftr->persist_data_size = CRYPT_PERSIST_DATA_SIZE;
+        crypt_ftr->persist_data_offset[0] = pdata_offset;
+        crypt_ftr->persist_data_offset[1] = pdata_offset + CRYPT_PERSIST_DATA_SIZE;
+        crypt_ftr->minor_version = 1;
+    }
+
+    if ((crypt_ftr->major_version == 1) && (crypt_ftr->minor_version)) {
+        printf("upgrading crypto footer to 1.2");
+        crypt_ftr->kdf_type = KDF_PBKDF2;
+        get_device_scrypt_params(crypt_ftr);
+        crypt_ftr->minor_version = 2;
+    }
+
+    if ((orig_major != crypt_ftr->major_version) || (orig_minor != crypt_ftr->minor_version)) {
+        if (lseek64(fd, offset, SEEK_SET) == -1) {
+            printf("Cannot seek to crypt footer\n");
+            return;
+        }
+        unix_write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr));
+    }
+}
+
+
+static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
 {
   int fd;
   unsigned int nr_sec, cnt;
-  off64_t off;
+  off64_t starting_off;
   int rc = -1;
-  char key_loc[PROPERTY_VALUE_MAX];
-  char *fname;
+  char *fname = NULL;
   struct stat statbuf;
 
-  fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+  if (get_crypt_ftr_info(&fname, &starting_off)) {
+    printf("Unable to get crypt_ftr_info\n");
+    return -1;
+  }
+  if (fname[0] != '/') {
+    printf("Unexpected value for crypto key location\n");
+    return -1;
+  }
+  if ( (fd = open(fname, O_RDWR)) < 0) {
+    printf("Cannot open footer file %s for get\n", fname);
+    return -1;
+  }
 
-  if (!strcmp(key_loc, KEY_IN_FOOTER)) {
-    fname = real_blk_name;
-    if ( (fd = open(fname, O_RDONLY)) < 0) {
-      SLOGE("Cannot open real block device %s\n", fname);
-      return -1;
-    }
+  /* Make sure it's 16 Kbytes in length */
+  fstat(fd, &statbuf);
+  if (S_ISREG(statbuf.st_mode) && (statbuf.st_size != 0x4000)) {
+    printf("footer file %s is not the expected size!\n", fname);
+    goto errout;
+  }
 
-    if ( (nr_sec = get_blkdev_size(fd)) == 0) {
-      SLOGE("Cannot get size of block device %s\n", fname);
-      goto errout;
-    }
-
-    /* If it's an encrypted Android partition, the last 16 Kbytes contain the
-     * encryption info footer and key, and plenty of bytes to spare for future
-     * growth.
-     */
-    off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET;
-
-    if (lseek64(fd, off, SEEK_SET) == -1) {
-      SLOGE("Cannot seek to real block device footer\n");
-      goto errout;
-    }
-  } else if (key_loc[0] == '/') {
-    fname = key_loc;
-    if ( (fd = open(fname, O_RDONLY)) < 0) {
-      SLOGE("Cannot open footer file %s\n", fname);
-      return -1;
-    }
-
-    /* Make sure it's 16 Kbytes in length */
-    fstat(fd, &statbuf);
-    if (S_ISREG(statbuf.st_mode) && (statbuf.st_size != 0x4000)) {
-      SLOGE("footer file %s is not the expected size!\n", fname);
-      goto errout;
-    }
-  } else {
-    SLOGE("Unexpected value for crypto key location\n");
-    return -1;;
+  /* Seek to the start of the crypt footer */
+  if (lseek64(fd, starting_off, SEEK_SET) == -1) {
+    printf("Cannot seek to real block device footer\n");
+    goto errout;
   }
 
   if ( (cnt = read(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) {
-    SLOGE("Cannot read real block device footer\n");
+    printf("Cannot read real block device footer\n");
     goto errout;
   }
 
   if (crypt_ftr->magic != CRYPT_MNT_MAGIC) {
-    SLOGE("Bad magic for real block device %s\n", fname);
+    printf("Bad magic for real block device %s\n", fname);
     goto errout;
   }
 
-  if (crypt_ftr->major_version != 1) {
-    SLOGE("Cannot understand major version %d real block device footer\n",
-          crypt_ftr->major_version);
+  if (crypt_ftr->major_version != CURRENT_MAJOR_VERSION) {
+    printf("Cannot understand major version %d real block device footer; expected %d\n",
+          crypt_ftr->major_version, CURRENT_MAJOR_VERSION);
     goto errout;
   }
 
-  if (crypt_ftr->minor_version != 0) {
-    SLOGW("Warning: crypto footer minor version %d, expected 0, continuing...\n",
-          crypt_ftr->minor_version);
+  if (crypt_ftr->minor_version > CURRENT_MINOR_VERSION) {
+    printf("Warning: crypto footer minor version %d, expected <= %d, continuing...\n",
+          crypt_ftr->minor_version, CURRENT_MINOR_VERSION);
   }
 
-  if (crypt_ftr->ftr_size > sizeof(struct crypt_mnt_ftr)) {
-    /* the footer size is bigger than we expected.
-     * Skip to it's stated end so we can read the key.
-     */
-    if (lseek64(fd, crypt_ftr->ftr_size - sizeof(struct crypt_mnt_ftr),  SEEK_CUR) == -1) {
-      SLOGE("Cannot seek to start of key\n");
-      goto errout;
-    }
-  }
-
-  if (crypt_ftr->keysize != KEY_LEN_BYTES) {
-    SLOGE("Keysize of %d bits not supported for real block device %s\n",
-          crypt_ftr->keysize * 8, fname);
-    goto errout;
-  }
-
-  if ( (cnt = read(fd, key, crypt_ftr->keysize)) != crypt_ftr->keysize) {
-    SLOGE("Cannot read key for real block device %s\n", fname);
-    goto errout;
-  }
-
-  if (lseek64(fd, KEY_TO_SALT_PADDING, SEEK_CUR) == -1) {
-    SLOGE("Cannot seek to real block device salt\n");
-    goto errout;
-  }
-
-  if ( (cnt = read(fd, salt, SALT_LEN)) != SALT_LEN) {
-    SLOGE("Cannot read salt for real block device %s\n", fname);
-    goto errout;
-  }
+  /* If this is a verion 1.0 crypt_ftr, make it a 1.1 crypt footer, and update the
+   * copy on disk before returning.
+   */
+  /*if (crypt_ftr->minor_version < CURRENT_MINOR_VERSION) {
+    upgrade_crypt_ftr(fd, crypt_ftr, starting_off);
+  }*/
 
   /* Success! */
   rc = 0;
@@ -352,6 +448,227 @@
   return rc;
 }
 
+static int validate_persistent_data_storage(struct crypt_mnt_ftr *crypt_ftr)
+{
+    if (crypt_ftr->persist_data_offset[0] + crypt_ftr->persist_data_size >
+        crypt_ftr->persist_data_offset[1]) {
+        printf("Crypt_ftr persist data regions overlap");
+        return -1;
+    }
+
+    if (crypt_ftr->persist_data_offset[0] >= crypt_ftr->persist_data_offset[1]) {
+        printf("Crypt_ftr persist data region 0 starts after region 1");
+        return -1;
+    }
+
+    if (((crypt_ftr->persist_data_offset[1] + crypt_ftr->persist_data_size) -
+        (crypt_ftr->persist_data_offset[0] - CRYPT_FOOTER_TO_PERSIST_OFFSET)) >
+        CRYPT_FOOTER_OFFSET) {
+        printf("Persistent data extends past crypto footer");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int load_persistent_data(void)
+{
+    struct crypt_mnt_ftr crypt_ftr;
+    struct crypt_persist_data *pdata = NULL;
+    char encrypted_state[PROPERTY_VALUE_MAX];
+    char *fname;
+    int found = 0;
+    int fd;
+    int ret;
+    int i;
+
+    if (persist_data) {
+        /* Nothing to do, we've already loaded or initialized it */
+        return 0;
+    }
+
+
+    /* If not encrypted, just allocate an empty table and initialize it */
+    property_get("ro.crypto.state", encrypted_state, "");
+    if (strcmp(encrypted_state, "encrypted") ) {
+        pdata = malloc(CRYPT_PERSIST_DATA_SIZE);
+        if (pdata) {
+            init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE);
+            persist_data = pdata;
+            return 0;
+        }
+        return -1;
+    }
+
+    if(get_crypt_ftr_and_key(&crypt_ftr)) {
+        return -1;
+    }
+
+    if ((crypt_ftr.major_version != 1) || (crypt_ftr.minor_version != 1)) {
+        printf("Crypt_ftr version doesn't support persistent data");
+        return -1;
+    }
+
+    if (get_crypt_ftr_info(&fname, NULL)) {
+        return -1;
+    }
+
+    ret = validate_persistent_data_storage(&crypt_ftr);
+    if (ret) {
+        return -1;
+    }
+
+    fd = open(fname, O_RDONLY);
+    if (fd < 0) {
+        printf("Cannot open %s metadata file", fname);
+        return -1;
+    }
+
+    if (persist_data == NULL) {
+        pdata = malloc(crypt_ftr.persist_data_size);
+        if (pdata == NULL) {
+            printf("Cannot allocate memory for persistent data");
+            goto err;
+        }
+    }
+
+    for (i = 0; i < 2; i++) {
+        if (lseek64(fd, crypt_ftr.persist_data_offset[i], SEEK_SET) < 0) {
+            printf("Cannot seek to read persistent data on %s", fname);
+            goto err2;
+        }
+        if (unix_read(fd, pdata, crypt_ftr.persist_data_size) < 0){
+            printf("Error reading persistent data on iteration %d", i);
+            goto err2;
+        }
+        if (pdata->persist_magic == PERSIST_DATA_MAGIC) {
+            found = 1;
+            break;
+        }
+    }
+
+    if (!found) {
+        printf("Could not find valid persistent data, creating");
+        init_empty_persist_data(pdata, crypt_ftr.persist_data_size);
+    }
+
+    /* Success */
+    persist_data = pdata;
+    close(fd);
+    return 0;
+
+err2:
+    free(pdata);
+
+err:
+    close(fd);
+    return -1;
+}
+
+static int save_persistent_data(void)
+{
+    struct crypt_mnt_ftr crypt_ftr;
+    struct crypt_persist_data *pdata;
+    char *fname;
+    off64_t write_offset;
+    off64_t erase_offset;
+    int found = 0;
+    int fd;
+    int ret;
+
+    if (persist_data == NULL) {
+        printf("No persistent data to save");
+        return -1;
+    }
+
+    if(get_crypt_ftr_and_key(&crypt_ftr)) {
+        return -1;
+    }
+
+    if ((crypt_ftr.major_version != 1) || (crypt_ftr.minor_version != 1)) {
+        printf("Crypt_ftr version doesn't support persistent data");
+        return -1;
+    }
+
+    ret = validate_persistent_data_storage(&crypt_ftr);
+    if (ret) {
+        return -1;
+    }
+
+    if (get_crypt_ftr_info(&fname, NULL)) {
+        return -1;
+    }
+
+    fd = open(fname, O_RDWR);
+    if (fd < 0) {
+        printf("Cannot open %s metadata file", fname);
+        return -1;
+    }
+
+    pdata = malloc(crypt_ftr.persist_data_size);
+    if (pdata == NULL) {
+        printf("Cannot allocate persistant data");
+        goto err;
+    }
+
+    if (lseek64(fd, crypt_ftr.persist_data_offset[0], SEEK_SET) < 0) {
+        printf("Cannot seek to read persistent data on %s", fname);
+        goto err2;
+    }
+
+    if (unix_read(fd, pdata, crypt_ftr.persist_data_size) < 0) {
+            printf("Error reading persistent data before save");
+            goto err2;
+    }
+
+    if (pdata->persist_magic == PERSIST_DATA_MAGIC) {
+        /* The first copy is the curent valid copy, so write to
+         * the second copy and erase this one */
+       write_offset = crypt_ftr.persist_data_offset[1];
+       erase_offset = crypt_ftr.persist_data_offset[0];
+    } else {
+        /* The second copy must be the valid copy, so write to
+         * the first copy, and erase the second */
+       write_offset = crypt_ftr.persist_data_offset[0];
+       erase_offset = crypt_ftr.persist_data_offset[1];
+    }
+
+    /* Write the new copy first, if successful, then erase the old copy */
+    if (lseek(fd, write_offset, SEEK_SET) < 0) {
+        printf("Cannot seek to write persistent data");
+        goto err2;
+    }
+    if (unix_write(fd, persist_data, crypt_ftr.persist_data_size) ==
+        (int) crypt_ftr.persist_data_size) {
+        if (lseek(fd, erase_offset, SEEK_SET) < 0) {
+            printf("Cannot seek to erase previous persistent data");
+            goto err2;
+        }
+        fsync(fd);
+        memset(pdata, 0, crypt_ftr.persist_data_size);
+        if (unix_write(fd, pdata, crypt_ftr.persist_data_size) !=
+            (int) crypt_ftr.persist_data_size) {
+            printf("Cannot write to erase previous persistent data");
+            goto err2;
+        }
+        fsync(fd);
+    } else {
+        printf("Cannot write to save persistent data");
+        goto err2;
+    }
+
+    /* Success */
+    free(pdata);
+    close(fd);
+    return 0;
+
+err2:
+    free(pdata);
+err:
+    close(fd);
+    return -1;
+}
+
 /* Convert a binary key of specified length into an ascii hex string equivalent,
  * without the leading 0x and with null termination
  */
@@ -375,6 +692,86 @@
 
 }
 
+static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
+                                     char *real_blk_name, const char *name, int fd,
+                                     char *extra_params)
+{
+  char buffer[DM_CRYPT_BUF_SIZE];
+  struct dm_ioctl *io;
+  struct dm_target_spec *tgt;
+  char *crypt_params;
+  char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */
+  int i;
+
+  io = (struct dm_ioctl *) buffer;
+
+  /* Load the mapping table for this device */
+  tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
+
+  ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
+  io->target_count = 1;
+  tgt->status = 0;
+  tgt->sector_start = 0;
+  tgt->length = crypt_ftr->fs_size;
+  strcpy(tgt->target_type, "crypt");
+
+  crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+  convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
+  sprintf(crypt_params, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name,
+          master_key_ascii, real_blk_name, extra_params);
+  crypt_params += strlen(crypt_params) + 1;
+  crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
+  tgt->next = crypt_params - buffer;
+
+  for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
+    if (! ioctl(fd, DM_TABLE_LOAD, io)) {
+      break;
+    }
+    usleep(500000);
+  }
+
+  if (i == TABLE_LOAD_RETRIES) {
+    /* We failed to load the table, return an error */
+    return -1;
+  } else {
+    return i + 1;
+  }
+}
+
+
+static int get_dm_crypt_version(int fd, const char *name,  int *version)
+{
+    char buffer[DM_CRYPT_BUF_SIZE];
+    struct dm_ioctl *io;
+    struct dm_target_versions *v;
+    int i;
+
+    io = (struct dm_ioctl *) buffer;
+
+    ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
+
+    if (ioctl(fd, DM_LIST_VERSIONS, io)) {
+        return -1;
+    }
+
+    /* Iterate over the returned versions, looking for name of "crypt".
+     * When found, get and return the version.
+     */
+    v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
+    while (v->next) {
+        if (! strcmp(v->name, "crypt")) {
+            /* We found the crypt driver, return the version, and get out */
+            version[0] = v->version[0];
+            version[1] = v->version[1];
+            version[2] = v->version[2];
+            return 0;
+        }
+        v = (struct dm_target_versions *)(((char *)v) + v->next);
+    }
+
+    return -1;
+}
+
 static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
                                     char *real_blk_name, char *crypto_blk_name, const char *name)
 {
@@ -385,10 +782,14 @@
   struct dm_target_spec *tgt;
   unsigned int minor;
   int fd;
+  int i;
   int retval = -1;
+  int version[3];
+  char *extra_params;
+  int load_count;
 
   if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) {
-    SLOGE("Cannot open device-mapper\n");
+    printf("Cannot open device-mapper\n");
     goto errout;
   }
 
@@ -396,47 +797,43 @@
 
   ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
   if (ioctl(fd, DM_DEV_CREATE, io)) {
-    SLOGE("Cannot create dm-crypt device\n");
+    printf("Cannot create dm-crypt device\n");
     goto errout;
   }
 
   /* Get the device status, in particular, the name of it's device file */
   ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
   if (ioctl(fd, DM_DEV_STATUS, io)) {
-    SLOGE("Cannot retrieve dm-crypt device status\n");
+    printf("Cannot retrieve dm-crypt device status\n");
     goto errout;
   }
   minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
   snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor);
 
-  /* Load the mapping table for this device */
-  tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
+  extra_params = "";
+  if (! get_dm_crypt_version(fd, name, version)) {
+      /* Support for allow_discards was added in version 1.11.0 */
+      if ((version[0] >= 2) ||
+          ((version[0] == 1) && (version[1] >= 11))) {
+          extra_params = "1 allow_discards";
+          printf("Enabling support for allow_discards in dmcrypt.\n");
+      }
+  }
 
-  ioctl_init(io, 4096, name, 0);
-  io->target_count = 1;
-  tgt->status = 0;
-  tgt->sector_start = 0;
-  tgt->length = crypt_ftr->fs_size;
-  strcpy(tgt->target_type, "crypt");
-
-  crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
-  convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
-  sprintf(crypt_params, "%s %s 0 %s 0", crypt_ftr->crypto_type_name,
-          master_key_ascii, real_blk_name);
-  crypt_params += strlen(crypt_params) + 1;
-  crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
-  tgt->next = crypt_params - buffer;
-
-  if (ioctl(fd, DM_TABLE_LOAD, io)) {
-      SLOGE("Cannot load dm-crypt mapping table.\n");
+  load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name,
+                                         fd, extra_params);
+  if (load_count < 0) {
+      printf("Cannot load dm-crypt mapping table.\n");
       goto errout;
+  } else if (load_count > 1) {
+      printf("Took %d tries to load dmcrypt table.\n", load_count);
   }
 
   /* Resume this device to activate it */
-  ioctl_init(io, 4096, name, 0);
+  ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
 
   if (ioctl(fd, DM_DEV_SUSPEND, io)) {
-    SLOGE("Cannot resume the dm-crypt device\n");
+    printf("Cannot resume the dm-crypt device\n");
     goto errout;
   }
 
@@ -457,7 +854,7 @@
   int retval = -1;
 
   if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) {
-    SLOGE("Cannot open device-mapper\n");
+    printf("Cannot open device-mapper\n");
     goto errout;
   }
 
@@ -465,7 +862,7 @@
 
   ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
   if (ioctl(fd, DM_DEV_REMOVE, io)) {
-    SLOGE("Cannot remove dm-crypt device\n");
+    printf("Cannot remove dm-crypt device\n");
     goto errout;
   }
 
@@ -479,27 +876,40 @@
 
 }
 
-static void pbkdf2(char *passwd, unsigned char *salt, unsigned char *ikey)
-{
+static void pbkdf2(char *passwd, unsigned char *salt, unsigned char *ikey, void *params) {
     /* Turn the password into a key and IV that can decrypt the master key */
     PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, SALT_LEN,
                            HASH_COUNT, KEY_LEN_BYTES+IV_LEN_BYTES, ikey);
 }
 
+static void scrypt(char *passwd, unsigned char *salt, unsigned char *ikey, void *params) {
+    struct crypt_mnt_ftr *ftr = (struct crypt_mnt_ftr *) params;
+
+    int N = 1 << ftr->N_factor;
+    int r = 1 << ftr->r_factor;
+    int p = 1 << ftr->p_factor;
+
+    /* Turn the password into a key and IV that can decrypt the master key */
+    crypto_scrypt((unsigned char *) passwd, strlen(passwd), salt, SALT_LEN, N, r, p, ikey,
+            KEY_LEN_BYTES + IV_LEN_BYTES);
+}
+
 static int encrypt_master_key(char *passwd, unsigned char *salt,
                               unsigned char *decrypted_master_key,
-                              unsigned char *encrypted_master_key)
+                              unsigned char *encrypted_master_key,
+                              struct crypt_mnt_ftr *crypt_ftr)
 {
     unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */
     EVP_CIPHER_CTX e_ctx;
     int encrypted_len, final_len;
 
     /* Turn the password into a key and IV that can decrypt the master key */
-    pbkdf2(passwd, salt, ikey);
-  
+    get_device_scrypt_params(crypt_ftr);
+    scrypt(passwd, salt, ikey, crypt_ftr);
+
     /* Initialize the decryption engine */
     if (! EVP_EncryptInit(&e_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) {
-        SLOGE("EVP_EncryptInit failed\n");
+        printf("EVP_EncryptInit failed\n");
         return -1;
     }
     EVP_CIPHER_CTX_set_padding(&e_ctx, 0); /* Turn off padding as our data is block aligned */
@@ -507,16 +917,16 @@
     /* Encrypt the master key */
     if (! EVP_EncryptUpdate(&e_ctx, encrypted_master_key, &encrypted_len,
                               decrypted_master_key, KEY_LEN_BYTES)) {
-        SLOGE("EVP_EncryptUpdate failed\n");
+        printf("EVP_EncryptUpdate failed\n");
         return -1;
     }
     if (! EVP_EncryptFinal(&e_ctx, encrypted_master_key + encrypted_len, &final_len)) {
-        SLOGE("EVP_EncryptFinal failed\n");
+        printf("EVP_EncryptFinal failed\n");
         return -1;
     }
 
     if (encrypted_len + final_len != KEY_LEN_BYTES) {
-        SLOGE("EVP_Encryption length check failed with %d, %d bytes\n", encrypted_len, final_len);
+        printf("EVP_Encryption length check failed with %d, %d bytes\n", encrypted_len, final_len);
         return -1;
     } else {
         return 0;
@@ -525,14 +935,15 @@
 
 static int decrypt_master_key(char *passwd, unsigned char *salt,
                               unsigned char *encrypted_master_key,
-                              unsigned char *decrypted_master_key)
+                              unsigned char *decrypted_master_key,
+                              kdf_func kdf, void *kdf_params)
 {
   unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */
   EVP_CIPHER_CTX d_ctx;
   int decrypted_len, final_len;
 
   /* Turn the password into a key and IV that can decrypt the master key */
-  pbkdf2(passwd, salt, ikey);
+  kdf(passwd, salt, ikey, kdf_params);
 
   /* Initialize the decryption engine */
   if (! EVP_DecryptInit(&d_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) {
@@ -555,8 +966,47 @@
   }
 }
 
-static int create_encrypted_random_key(char *passwd, unsigned char *master_key, unsigned char *salt)
+static void get_kdf_func(struct crypt_mnt_ftr *ftr, kdf_func *kdf, void** kdf_params)
 {
+    if (ftr->kdf_type == KDF_SCRYPT) {
+        *kdf = scrypt;
+        *kdf_params = ftr;
+    } else {
+        *kdf = pbkdf2;
+        *kdf_params = NULL;
+    }
+}
+
+static int decrypt_master_key_and_upgrade(char *passwd, unsigned char *decrypted_master_key,
+        struct crypt_mnt_ftr *crypt_ftr)
+{
+    kdf_func kdf;
+    void *kdf_params;
+    int ret;
+
+    get_kdf_func(crypt_ftr, &kdf, &kdf_params);
+    ret = decrypt_master_key(passwd, crypt_ftr->salt, crypt_ftr->master_key, decrypted_master_key, kdf,
+            kdf_params);
+    if (ret != 0) {
+        printf("failure decrypting master key");
+        return ret;
+    }
+
+    /*
+     * Upgrade if we're not using the latest KDF.
+     */
+    /*if (crypt_ftr->kdf_type != KDF_SCRYPT) {
+        crypt_ftr->kdf_type = KDF_SCRYPT;
+        encrypt_master_key(passwd, crypt_ftr->salt, decrypted_master_key, crypt_ftr->master_key,
+                crypt_ftr);
+        put_crypt_ftr_and_key(crypt_ftr);
+    }*/
+
+    return ret;
+}
+
+static int create_encrypted_random_key(char *passwd, unsigned char *master_key, unsigned char *salt,
+        struct crypt_mnt_ftr *crypt_ftr) {
     int fd;
     unsigned char key_buf[KEY_LEN_BYTES];
     EVP_CIPHER_CTX e_ctx;
@@ -569,7 +1019,7 @@
     close(fd);
 
     /* Now encrypt it with the password */
-    return encrypt_master_key(passwd, salt, key_buf, master_key);
+    return encrypt_master_key(passwd, salt, key_buf, master_key, crypt_ftr);
 }
 
 static int wait_and_unmount(char *mountpoint)
@@ -594,17 +1044,17 @@
     }
 
     if (i < WAIT_UNMOUNT_COUNT) {
-      SLOGD("unmounting %s succeeded\n", mountpoint);
+      printf("unmounting %s succeeded\n", mountpoint);
       rc = 0;
     } else {
-      SLOGE("unmounting %s failed\n", mountpoint);
+      printf("unmounting %s failed\n", mountpoint);
       rc = -1;
     }
 
     return rc;
 }
 
-#define DATA_PREP_TIMEOUT 100
+#define DATA_PREP_TIMEOUT 200
 static int prep_data_fs(void)
 {
     int i;
@@ -612,9 +1062,9 @@
     /* Do the prep of the /data filesystem */
     property_set("vold.post_fs_data_done", "0");
     property_set("vold.decrypt", "trigger_post_fs_data");
-    SLOGD("Just triggered post_fs_data\n");
+    printf("Just triggered post_fs_data\n");
 
-    /* Wait a max of 25 seconds, hopefully it takes much less */
+    /* Wait a max of 50 seconds, hopefully it takes much less */
     for (i=0; i<DATA_PREP_TIMEOUT; i++) {
         char p[PROPERTY_VALUE_MAX];
 
@@ -627,9 +1077,10 @@
     }
     if (i == DATA_PREP_TIMEOUT) {
         /* Ugh, we failed to prep /data in time.  Bail. */
+        printf("post_fs_data timed out!\n");
         return -1;
     } else {
-        SLOGD("post_fs_data done\n");
+        printf("post_fs_data done\n");
         return 0;
     }
 }
@@ -647,12 +1098,12 @@
 
     /* Validate that it's OK to call this routine */
     if (! master_key_saved) {
-        SLOGE("Encrypted filesystem not validated, aborting");
+        printf("Encrypted filesystem not validated, aborting");
         return -1;
     }
 
     if (restart_successful) {
-        SLOGE("System already restarted with encrypted disk, aborting");
+        printf("System already restarted with encrypted disk, aborting");
         return -1;
     }
 
@@ -674,7 +1125,14 @@
      * set to trigger_reset_main.
      */
     property_set("vold.decrypt", "trigger_reset_main");
-    SLOGD("Just asked init to shut down class main\n");
+    printf("Just asked init to shut down class main\n");
+
+    /* Ugh, shutting down the framework is not synchronous, so until it
+     * can be fixed, this horrible hack will wait a moment for it all to
+     * shut down before proceeding.  Without it, some devices cannot
+     * restart the graphics services.
+     */
+    sleep(2);
 
     /* Now that the framework is shutdown, we should be able to umount()
      * the tmpfs filesystem, and mount the real one.
@@ -682,13 +1140,13 @@
 
     property_get("ro.crypto.fs_crypto_blkdev", crypto_blkdev, "");
     if (strlen(crypto_blkdev) == 0) {
-        SLOGE("fs_crypto_blkdev not set\n");
+        printf("fs_crypto_blkdev not set\n");
         return -1;
     }
 
     if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
         /* If that succeeded, then mount the decrypted filesystem */
-        fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, 0);
+        fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, 0);
 
         property_set("vold.decrypt", "trigger_load_persist_props");
         /* Create necessary paths on /data */
@@ -698,7 +1156,7 @@
 
         /* startup service classes main and late_start */
         property_set("vold.decrypt", "trigger_restart_framework");
-        SLOGD("Just triggered restart_framework\n");
+        printf("Just triggered restart_framework\n");
 
         /* Give it a few moments to get started */
         sleep(1);
@@ -714,22 +1172,17 @@
 static int do_crypto_complete(char *mount_point)
 {
   struct crypt_mnt_ftr crypt_ftr;
-  unsigned char encrypted_master_key[32];
-  unsigned char salt[SALT_LEN];
-  char real_blkdev[MAXPATHLEN];
   char encrypted_state[PROPERTY_VALUE_MAX];
   char key_loc[PROPERTY_VALUE_MAX];
 
   property_get("ro.crypto.state", encrypted_state, "");
   if (strcmp(encrypted_state, "encrypted") ) {
-    SLOGE("not running with encryption, aborting");
+    printf("not running with encryption, aborting");
     return 1;
   }
 
-  fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
-
-  if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
-    fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+  if (get_crypt_ftr_and_key(&crypt_ftr)) {
+    fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
 
     /*
      * Only report this error if key_loc is a file and it exists.
@@ -739,16 +1192,16 @@
      * device" screen.
      */
     if ((key_loc[0] == '/') && (access("key_loc", F_OK) == -1)) {
-      SLOGE("master key file does not exist, aborting");
+      printf("master key file does not exist, aborting");
       return 1;
     } else {
-      SLOGE("Error getting crypt footer and key\n");
+      printf("Error getting crypt footer and key\n");
       return -1;
     }
   }
 
   if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) {
-    SLOGE("Encryption process didn't finish successfully\n");
+    printf("Encryption process didn't finish successfully\n");
     return -2;  /* -2 is the clue to the UI that there is no usable data on the disk,
                  * and give the user an option to wipe the disk */
   }
@@ -761,42 +1214,43 @@
 {
   struct crypt_mnt_ftr crypt_ftr;
   /* Allocate enough space for a 256 bit key, but we may use less */
-  unsigned char encrypted_master_key[32], decrypted_master_key[32];
-  unsigned char salt[SALT_LEN];
+  unsigned char decrypted_master_key[32];
   char crypto_blkdev[MAXPATHLEN];
   char real_blkdev[MAXPATHLEN];
   char tmp_mount_point[64];
   unsigned int orig_failed_decrypt_count;
   char encrypted_state[PROPERTY_VALUE_MAX];
   int rc;
+  kdf_func kdf;
+  void *kdf_params;
 
   property_get("ro.crypto.state", encrypted_state, "");
   if ( master_key_saved || strcmp(encrypted_state, "encrypted") ) {
-    SLOGE("encrypted fs already validated or not running with encryption, aborting");
+    printf("encrypted fs already validated or not running with encryption, aborting");
     return -1;
   }
 
-  fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+  fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
 
-  if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
-    SLOGE("Error getting crypt footer and key\n");
+  if (get_crypt_ftr_and_key(&crypt_ftr)) {
+    printf("Error getting crypt footer and key\n");
     return -1;
   }
 
-  SLOGD("crypt_ftr->fs_size = %lld\n", crypt_ftr.fs_size);
+  printf("crypt_ftr->fs_size = %lld\n", crypt_ftr.fs_size);
   orig_failed_decrypt_count = crypt_ftr.failed_decrypt_count;
 
   if (! (crypt_ftr.flags & CRYPT_MNT_KEY_UNENCRYPTED) ) {
-    decrypt_master_key(passwd, salt, encrypted_master_key, decrypted_master_key);
+    decrypt_master_key_and_upgrade(passwd, decrypted_master_key, &crypt_ftr);
   }
 
   if (create_crypto_blk_dev(&crypt_ftr, decrypted_master_key,
                                real_blkdev, crypto_blkdev, label)) {
-    SLOGE("Error creating decrypted block device\n");
+    printf("Error creating decrypted block device\n");
     return -1;
   }
 
-  /* If init detects an encrypted filesystme, it writes a file for each such
+  /* If init detects an encrypted filesystem, it writes a file for each such
    * encrypted fs into the tmpfs /data filesystem, and then the framework finds those
    * files and passes that data to me */
   /* Create a tmp mount point to try mounting the decryptd fs
@@ -805,8 +1259,8 @@
    */
   sprintf(tmp_mount_point, "%s/tmp_mnt", mount_point);
   mkdir(tmp_mount_point, 0755);
-  if (fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
-    SLOGE("Error temp mounting decrypted block device\n");
+  if (fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
+    printf("Error temp mounting decrypted block device\n");
     delete_crypto_blk_dev(label);
     crypt_ftr.failed_decrypt_count++;
   } else {
@@ -818,7 +1272,7 @@
   }
 
   if (orig_failed_decrypt_count != crypt_ftr.failed_decrypt_count) {
-    put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, 0, 0);
+    put_crypt_ftr_and_key(&crypt_ftr);
   }
 
   if (crypt_ftr.failed_decrypt_count) {
@@ -835,7 +1289,6 @@
      * the key when we want to change the password on it.
      */
     memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES);
-    saved_data_blkdev = strdup(real_blkdev);
     saved_mount_point = strdup(mount_point);
     master_key_saved = 1;
     rc = 0;
@@ -864,21 +1317,19 @@
 {
     char real_blkdev[MAXPATHLEN], crypto_blkdev[MAXPATHLEN];
     struct crypt_mnt_ftr sd_crypt_ftr;
-    unsigned char key[32], salt[32];
     struct stat statbuf;
     int nr_sec, fd;
 
     sprintf(real_blkdev, "/dev/block/vold/%d:%d", major, minor);
 
-    /* Just want the footer, but gotta get it all */
-    get_crypt_ftr_and_key(saved_data_blkdev, &sd_crypt_ftr, key, salt);
+    get_crypt_ftr_and_key(&sd_crypt_ftr);
 
     /* Update the fs_size field to be the size of the volume */
     fd = open(real_blkdev, O_RDONLY);
     nr_sec = get_blkdev_size(fd);
     close(fd);
     if (nr_sec == 0) {
-        SLOGE("Cannot get size of volume %s\n", real_blkdev);
+        printf("Cannot get size of volume %s\n", real_blkdev);
         return -1;
     }
 
@@ -901,9 +1352,24 @@
   return do_crypto_complete("/data");
 }
 
+#define FSTAB_PREFIX "/fstab."
+
 int cryptfs_check_passwd(char *passwd)
 {
     int rc = -1;
+    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char propbuf[PROPERTY_VALUE_MAX];
+    int i;
+    int flags;
+
+    property_get("ro.hardware", propbuf, "");
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+    fstab = fs_mgr_read_fstab(fstab_filename);
+    if (!fstab) {
+        printf("failed to open %s\n", fstab_filename);
+        return -1;
+    }
 
     rc = test_mount_encrypted_fs(passwd, DATA_MNT_POINT, "userdata");
 
@@ -914,32 +1380,28 @@
 {
     struct crypt_mnt_ftr crypt_ftr;
     /* Allocate enough space for a 256 bit key, but we may use less */
-    unsigned char encrypted_master_key[32], decrypted_master_key[32];
-    unsigned char salt[SALT_LEN];
-    char real_blkdev[MAXPATHLEN];
+    unsigned char decrypted_master_key[32];
     char encrypted_state[PROPERTY_VALUE_MAX];
     int rc;
 
     property_get("ro.crypto.state", encrypted_state, "");
     if (strcmp(encrypted_state, "encrypted") ) {
-        SLOGE("device not encrypted, aborting");
+        printf("device not encrypted, aborting");
         return -2;
     }
 
     if (!master_key_saved) {
-        SLOGE("encrypted fs not yet mounted, aborting");
+        printf("encrypted fs not yet mounted, aborting");
         return -1;
     }
 
     if (!saved_mount_point) {
-        SLOGE("encrypted fs failed to save mount point, aborting");
+        printf("encrypted fs failed to save mount point, aborting");
         return -1;
     }
 
-    fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
-
-    if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
-        SLOGE("Error getting crypt footer and key\n");
+    if (get_crypt_ftr_and_key(&crypt_ftr)) {
+        printf("Error getting crypt footer and key\n");
         return -1;
     }
 
@@ -947,7 +1409,7 @@
         /* If the device has no password, then just say the password is valid */
         rc = 0;
     } else {
-        decrypt_master_key(passwd, salt, encrypted_master_key, decrypted_master_key);
+        decrypt_master_key_and_upgrade(passwd, decrypted_master_key, &crypt_ftr);
         if (!memcmp(decrypted_master_key, saved_master_key, crypt_ftr.keysize)) {
             /* They match, the password is correct */
             rc = 0;
@@ -968,58 +1430,29 @@
  */
 static void cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr)
 {
+    off64_t off;
+
+    memset(ftr, 0, sizeof(struct crypt_mnt_ftr));
     ftr->magic = CRYPT_MNT_MAGIC;
-    ftr->major_version = 1;
-    ftr->minor_version = 0;
+    ftr->major_version = CURRENT_MAJOR_VERSION;
+    ftr->minor_version = CURRENT_MINOR_VERSION;
     ftr->ftr_size = sizeof(struct crypt_mnt_ftr);
-    ftr->flags = 0;
     ftr->keysize = KEY_LEN_BYTES;
-    ftr->spare1 = 0;
-    ftr->fs_size = 0;
-    ftr->failed_decrypt_count = 0;
-    ftr->crypto_type_name[0] = '\0';
+
+    ftr->kdf_type = KDF_SCRYPT;
+    get_device_scrypt_params(ftr);
+
+    ftr->persist_data_size = CRYPT_PERSIST_DATA_SIZE;
+    if (get_crypt_ftr_info(NULL, &off) == 0) {
+        ftr->persist_data_offset[0] = off + CRYPT_FOOTER_TO_PERSIST_OFFSET;
+        ftr->persist_data_offset[1] = off + CRYPT_FOOTER_TO_PERSIST_OFFSET +
+                                    ftr->persist_data_size;
+    }
 }
 
 static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type)
 {
-    char cmdline[256];
-    int rc = -1;
-
-    if (type == EXT4_FS) {
-        snprintf(cmdline, sizeof(cmdline), "/system/bin/make_ext4fs -a /data -l %lld %s",
-                 size * 512, crypto_blkdev);
-        SLOGI("Making empty filesystem with command %s\n", cmdline);
-    } else if (type== FAT_FS) {
-        snprintf(cmdline, sizeof(cmdline), "/system/bin/newfs_msdos -F 32 -O android -c 8 -s %lld %s",
-                 size, crypto_blkdev);
-        SLOGI("Making empty filesystem with command %s\n", cmdline);
-    } else {
-        SLOGE("cryptfs_enable_wipe(): unknown filesystem type %d\n", type);
-        return -1;
-    }
-
-    if (system(cmdline)) {
-      SLOGE("Error creating empty filesystem on %s\n", crypto_blkdev);
-    } else {
-      SLOGD("Successfully created empty filesystem on %s\n", crypto_blkdev);
-      rc = 0;
-    }
-
-    return rc;
-}
-
-static inline int unix_read(int  fd, void*  buff, int  len)
-{
-    int  ret;
-    do { ret = read(fd, buff, len); } while (ret < 0 && errno == EINTR);
-    return ret;
-}
-
-static inline int unix_write(int  fd, const void*  buff, int  len)
-{
-    int  ret;
-    do { ret = write(fd, buff, len); } while (ret < 0 && errno == EINTR);
-    return ret;
+    return -1;
 }
 
 #define CRYPT_INPLACE_BUFSIZE 4096
@@ -1035,12 +1468,12 @@
     off64_t blocks_already_done, tot_numblocks;
 
     if ( (realfd = open(real_blkdev, O_RDONLY)) < 0) { 
-        SLOGE("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev);
+        printf("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev);
         return -1;
     }
 
     if ( (cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) { 
-        SLOGE("Error opening crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
+        printf("Error opening crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
         close(realfd);
         return -1;
     }
@@ -1055,7 +1488,7 @@
     tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE;
     blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE;
 
-    SLOGE("Encrypting filesystem in place...");
+    printf("Encrypting filesystem in place...");
 
     one_pct = tot_numblocks / 100;
     cur_pct = 0;
@@ -1070,11 +1503,11 @@
             property_set("vold.encrypt_progress", buf);
         }
         if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
-            SLOGE("Error reading real_blkdev %s for inplace encrypt\n", crypto_blkdev);
+            printf("Error reading real_blkdev %s for inplace encrypt\n", crypto_blkdev);
             goto errout;
         }
         if (unix_write(cryptofd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
-            SLOGE("Error writing crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
+            printf("Error writing crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
             goto errout;
         }
     }
@@ -1082,11 +1515,11 @@
     /* Do any remaining sectors */
     for (i=0; i<remainder; i++) {
         if (unix_read(realfd, buf, 512) <= 0) {
-            SLOGE("Error reading rival sectors from real_blkdev %s for inplace encrypt\n", crypto_blkdev);
+            printf("Error reading rival sectors from real_blkdev %s for inplace encrypt\n", crypto_blkdev);
             goto errout;
         }
         if (unix_write(cryptofd, buf, 512) <= 0) {
-            SLOGE("Error writing final sectors to crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
+            printf("Error writing final sectors to crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
             goto errout;
         }
     }
@@ -1114,39 +1547,170 @@
 
 int cryptfs_enable(char *howarg, char *passwd)
 {
-    // Code removed because it needs other parts of vold that aren't needed for decryption
     return -1;
 }
 
 int cryptfs_changepw(char *newpw)
 {
     struct crypt_mnt_ftr crypt_ftr;
-    unsigned char encrypted_master_key[KEY_LEN_BYTES], decrypted_master_key[KEY_LEN_BYTES];
-    unsigned char salt[SALT_LEN];
-    char real_blkdev[MAXPATHLEN];
+    unsigned char decrypted_master_key[KEY_LEN_BYTES];
 
     /* This is only allowed after we've successfully decrypted the master key */
     if (! master_key_saved) {
-        SLOGE("Key not saved, aborting");
-        return -1;
-    }
-
-    fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
-    if (strlen(real_blkdev) == 0) {
-        SLOGE("Can't find real blkdev");
+        printf("Key not saved, aborting");
         return -1;
     }
 
     /* get key */
-    if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
-      SLOGE("Error getting crypt footer and key");
+    if (get_crypt_ftr_and_key(&crypt_ftr)) {
+      printf("Error getting crypt footer and key");
       return -1;
     }
 
-    encrypt_master_key(newpw, salt, saved_master_key, encrypted_master_key);
+    encrypt_master_key(newpw, crypt_ftr.salt, saved_master_key, crypt_ftr.master_key, &crypt_ftr);
 
     /* save the key */
-    put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt);
+    put_crypt_ftr_and_key(&crypt_ftr);
 
     return 0;
 }
+
+static int persist_get_key(char *fieldname, char *value)
+{
+    unsigned int i;
+
+    if (persist_data == NULL) {
+        return -1;
+    }
+    for (i = 0; i < persist_data->persist_valid_entries; i++) {
+        if (!strncmp(persist_data->persist_entry[i].key, fieldname, PROPERTY_KEY_MAX)) {
+            /* We found it! */
+            strlcpy(value, persist_data->persist_entry[i].val, PROPERTY_VALUE_MAX);
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+static int persist_set_key(char *fieldname, char *value, int encrypted)
+{
+    unsigned int i;
+    unsigned int num;
+    struct crypt_mnt_ftr crypt_ftr;
+    unsigned int max_persistent_entries;
+    unsigned int dsize;
+
+    if (persist_data == NULL) {
+        return -1;
+    }
+
+    /* If encrypted, use the values from the crypt_ftr, otherwise
+     * use the values for the current spec.
+     */
+    if (encrypted) {
+        if(get_crypt_ftr_and_key(&crypt_ftr)) {
+            return -1;
+        }
+        dsize = crypt_ftr.persist_data_size;
+    } else {
+        dsize = CRYPT_PERSIST_DATA_SIZE;
+    }
+    max_persistent_entries = (dsize - sizeof(struct crypt_persist_data)) /
+                             sizeof(struct crypt_persist_entry);
+
+    num = persist_data->persist_valid_entries;
+
+    for (i = 0; i < num; i++) {
+        if (!strncmp(persist_data->persist_entry[i].key, fieldname, PROPERTY_KEY_MAX)) {
+            /* We found an existing entry, update it! */
+            memset(persist_data->persist_entry[i].val, 0, PROPERTY_VALUE_MAX);
+            strlcpy(persist_data->persist_entry[i].val, value, PROPERTY_VALUE_MAX);
+            return 0;
+        }
+    }
+
+    /* We didn't find it, add it to the end, if there is room */
+    if (persist_data->persist_valid_entries < max_persistent_entries) {
+        memset(&persist_data->persist_entry[num], 0, sizeof(struct crypt_persist_entry));
+        strlcpy(persist_data->persist_entry[num].key, fieldname, PROPERTY_KEY_MAX);
+        strlcpy(persist_data->persist_entry[num].val, value, PROPERTY_VALUE_MAX);
+        persist_data->persist_valid_entries++;
+        return 0;
+    }
+
+    return -1;
+}
+
+/* Return the value of the specified field. */
+int cryptfs_getfield(char *fieldname, char *value, int len)
+{
+    char temp_value[PROPERTY_VALUE_MAX];
+    char real_blkdev[MAXPATHLEN];
+    /* 0 is success, 1 is not encrypted,
+     * -1 is value not set, -2 is any other error
+     */
+    int rc = -2;
+
+    if (persist_data == NULL) {
+        load_persistent_data();
+        if (persist_data == NULL) {
+            printf("Getfield error, cannot load persistent data");
+            goto out;
+        }
+    }
+
+    if (!persist_get_key(fieldname, temp_value)) {
+        /* We found it, copy it to the caller's buffer and return */
+        strlcpy(value, temp_value, len);
+        rc = 0;
+    } else {
+        /* Sadness, it's not there.  Return the error */
+        rc = -1;
+    }
+
+out:
+    return rc;
+}
+
+/* Set the value of the specified field. */
+int cryptfs_setfield(char *fieldname, char *value)
+{
+    struct crypt_persist_data stored_pdata;
+    struct crypt_persist_data *pdata_p;
+    struct crypt_mnt_ftr crypt_ftr;
+    char encrypted_state[PROPERTY_VALUE_MAX];
+    /* 0 is success, -1 is an error */
+    int rc = -1;
+    int encrypted = 0;
+
+    if (persist_data == NULL) {
+        load_persistent_data();
+        if (persist_data == NULL) {
+            printf("Setfield error, cannot load persistent data");
+            goto out;
+        }
+    }
+
+    property_get("ro.crypto.state", encrypted_state, "");
+    if (!strcmp(encrypted_state, "encrypted") ) {
+        encrypted = 1;
+    }
+
+    if (persist_set_key(fieldname, value, encrypted)) {
+        goto out;
+    }
+
+    /* If we are running encrypted, save the persistent data now */
+    if (encrypted) {
+        if (save_persistent_data()) {
+            printf("Setfield error, cannot save persistent data");
+            goto out;
+        }
+    }
+
+    rc = 0;
+
+out:
+    return rc;
+}
diff --git a/crypto/jb/cryptfs.h b/crypto/jb/cryptfs.h
index 1c1bc1a..162159e 100644
--- a/crypto/jb/cryptfs.h
+++ b/crypto/jb/cryptfs.h
@@ -15,22 +15,31 @@
  */
 
 /* This structure starts 16,384 bytes before the end of a hardware
- * partition that is encrypted.
- * Immediately following this structure is the encrypted key.
- * The keysize field tells how long the key is, in bytes.
- * Then there is 32 bytes of padding,
- * Finally there is the salt used with the user password.
- * The salt is fixed at 16 bytes long.
+ * partition that is encrypted, or in a separate partition.  It's location
+ * is specified by a property set in init.<device>.rc.
+ * The structure allocates 48 bytes for a key, but the real key size is
+ * specified in the struct.  Currently, the code is hardcoded to use 128
+ * bit keys.
+ * The fields after salt are only valid in rev 1.1 and later stuctures.
  * Obviously, the filesystem does not include the last 16 kbytes
- * of the partition.
+ * of the partition if the crypt_mnt_ftr lives at the end of the
+ * partition.
  */
 
+#include <cutils/properties.h>
+
+/* The current cryptfs version */
+#define CURRENT_MAJOR_VERSION 1
+#define CURRENT_MINOR_VERSION 2
+
 #define CRYPT_FOOTER_OFFSET 0x4000
+#define CRYPT_FOOTER_TO_PERSIST_OFFSET 0x1000
+#define CRYPT_PERSIST_DATA_SIZE 0x1000
 
 #define MAX_CRYPTO_TYPE_NAME_LEN 64
 
+#define MAX_KEY_LEN 48
 #define SALT_LEN 16
-#define KEY_TO_SALT_PADDING 32
 
 /* definitions of flags in the structure below */
 #define CRYPT_MNT_KEY_UNENCRYPTED 0x1 /* The key for the partition is not encrypted. */
@@ -38,9 +47,18 @@
                                           * clear when done before rebooting */
 
 #define CRYPT_MNT_MAGIC 0xD0B5B1C4
+#define PERSIST_DATA_MAGIC 0xE950CD44
+
+#define SCRYPT_PROP "ro.crypto.scrypt_params"
+#define SCRYPT_DEFAULTS { 15, 3, 1 }
+
+/* Key Derivation Function algorithms */
+#define KDF_PBKDF2 1
+#define KDF_SCRYPT 2
 
 #define __le32 unsigned int
-#define __le16 unsigned short int 
+#define __le16 unsigned short int
+#define __le8  unsigned char
 
 struct crypt_mnt_ftr {
   __le32 magic;		/* See above */
@@ -56,6 +74,48 @@
   unsigned char crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN]; /* The type of encryption
 							       needed to decrypt this
 							       partition, null terminated */
+  __le32 spare2;        /* ignored */
+  unsigned char master_key[MAX_KEY_LEN]; /* The encrypted key for decrypting the filesystem */
+  unsigned char salt[SALT_LEN];   /* The salt used for this encryption */
+  __le64 persist_data_offset[2];  /* Absolute offset to both copies of crypt_persist_data
+                                   * on device with that info, either the footer of the
+                                   * real_blkdevice or the metadata partition. */
+
+  __le32 persist_data_size;       /* The number of bytes allocated to each copy of the
+                                   * persistent data table*/
+
+  __le8  kdf_type; /* The key derivation function used. */
+
+  /* scrypt parameters. See www.tarsnap.com/scrypt/scrypt.pdf */
+  __le8  N_factor; /* (1 << N) */
+  __le8  r_factor; /* (1 << r) */
+  __le8  p_factor; /* (1 << p) */
+};
+
+/* Persistant data that should be available before decryption.
+ * Things like airplane mode, locale and timezone are kept
+ * here and can be retrieved by the CryptKeeper UI to properly
+ * configure the phone before asking for the password
+ * This is only valid if the major and minor version above
+ * is set to 1.1 or higher.
+ *
+ * This is a 4K structure.  There are 2 copies, and the code alternates
+ * writing one and then clearing the previous one.  The reading
+ * code reads the first valid copy it finds, based on the magic number.
+ * The absolute offset to the first of the two copies is kept in rev 1.1
+ * and higher crypt_mnt_ftr structures.
+ */
+struct crypt_persist_entry {
+  char key[PROPERTY_KEY_MAX];
+  char val[PROPERTY_VALUE_MAX];
+};
+
+/* Should be exactly 4K in size */
+struct crypt_persist_data {
+  __le32 persist_magic;
+  __le32 persist_valid_entries;
+  __le32 persist_spare[30];
+  struct crypt_persist_entry persist_entry[0];
 };
 
 struct volume_info {
@@ -67,12 +127,17 @@
    char crypto_blkdev[256];
    char label[256];
 };
-#define VOL_NONREMOVABLE 0x1
-#define VOL_ENCRYPTABLE  0x2
+#define VOL_NONREMOVABLE   0x1
+#define VOL_ENCRYPTABLE    0x2
+#define VOL_PRIMARY        0x4
+#define VOL_PROVIDES_ASEC  0x8
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+
+  typedef void (*kdf_func)(char *passwd, unsigned char *salt, unsigned char *ikey, void *params);
+
   int cryptfs_crypto_complete(void);
   int cryptfs_check_passwd(char *pw);
   int cryptfs_verify_passwd(char *newpw);
@@ -83,6 +148,8 @@
                            char *crypto_dev_path, unsigned int max_pathlen,
                            int *new_major, int *new_minor);
   int cryptfs_revert_volume(const char *label);
+  int cryptfs_getfield(char *fieldname, char *value, int len);
+  int cryptfs_setfield(char *fieldname, char *value);
 #ifdef __cplusplus
 }
 #endif
diff --git a/crypto/logwrapper/Android.mk b/crypto/logwrapper/Android.mk
new file mode 100644
index 0000000..01b6193
--- /dev/null
+++ b/crypto/logwrapper/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# ========================================================
+# Static library
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := liblogwraptwrp
+LOCAL_SRC_FILES := logwrap.c
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+include $(BUILD_STATIC_LIBRARY)
+
+# ========================================================
+# Shared library
+# ========================================================
+#include $(CLEAR_VARS)
+#LOCAL_MODULE := liblogwrap
+#LOCAL_SHARED_LIBRARIES := libcutils liblog
+#LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
+#LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+#LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+#include $(BUILD_SHARED_LIBRARY)
+
+# ========================================================
+# Executable
+# ========================================================
+#include $(CLEAR_VARS)
+#LOCAL_SRC_FILES:= logwrapper.c
+#LOCAL_MODULE := logwrapper
+#LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
+#include $(BUILD_EXECUTABLE)
diff --git a/crypto/logwrapper/NOTICE b/crypto/logwrapper/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/crypto/logwrapper/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/crypto/logwrapper/include/logwrap/logwrap.h b/crypto/logwrapper/include/logwrap/logwrap.h
new file mode 100644
index 0000000..4307a30
--- /dev/null
+++ b/crypto/logwrapper/include/logwrap/logwrap.h
@@ -0,0 +1,87 @@
+/* system/core/include/logwrap/logwrap.h
+ *
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LIBS_LOGWRAP_H
+#define __LIBS_LOGWRAP_H
+
+#include <stdbool.h>
+
+__BEGIN_DECLS
+
+/*
+ * Run a command while logging its stdout and stderr
+ *
+ * WARNING: while this function is running it will clear all SIGCHLD handlers
+ * if you rely on SIGCHLD in the caller there is a chance zombies will be
+ * created if you're not calling waitpid after calling this. This function will
+ * log a warning when it clears SIGCHLD for processes other than the child it
+ * created.
+ *
+ * Arguments:
+ *   argc:   the number of elements in argv
+ *   argv:   an array of strings containing the command to be executed and its
+ *           arguments as separate strings. argv does not need to be
+ *           NULL-terminated
+ *   status: the equivalent child status as populated by wait(status). This
+ *           value is only valid when logwrap successfully completes. If NULL
+ *           the return value of the child will be the function's return value.
+ *   ignore_int_quit: set to true if you want to completely ignore SIGINT and
+ *           SIGQUIT while logwrap is running. This may force the end-user to
+ *           send a signal twice to signal the caller (once for the child, and
+ *           once for the caller)
+ *   log_target: Specify where to log the output of the child, either LOG_NONE,
+ *           LOG_ALOG (for the Android system log), LOG_KLOG (for the kernel
+ *           log), or LOG_FILE (and you need to specify a pathname in the
+ *           file_path argument, otherwise pass NULL).  These are bit fields,
+ *           and can be OR'ed together to log to multiple places.
+ *   abbreviated: If true, capture up to the first 100 lines and last 4K of
+ *           output from the child.  The abbreviated output is not dumped to
+ *           the specified log until the child has exited.
+ *   file_path: if log_target has the LOG_FILE bit set, then this parameter
+ *           must be set to the pathname of the file to log to.
+ *
+ * Return value:
+ *   0 when logwrap successfully run the child process and captured its status
+ *   -1 when an internal error occurred
+ *   -ECHILD if status is NULL and the child didn't exit properly
+ *   the return value of the child if it exited properly and status is NULL
+ *
+ */
+
+/* Values for the log_target parameter android_fork_execvp_ext() */
+#define LOG_NONE        0
+#define LOG_ALOG        1
+#define LOG_KLOG        2
+#define LOG_FILE        4
+
+int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
+        int log_target, bool abbreviated, char *file_path);
+
+/* Similar to above, except abbreviated logging is not available, and if logwrap
+ * is true, logging is to the Android system log, and if false, there is no
+ * logging.
+ */
+static inline int android_fork_execvp(int argc, char* argv[], int *status,
+                                     bool ignore_int_quit, bool logwrap)
+{
+    return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
+                                   (logwrap ? LOG_ALOG : LOG_NONE), false, NULL);
+}
+
+__END_DECLS
+
+#endif /* __LIBS_LOGWRAP_H */
diff --git a/crypto/logwrapper/logwrap.c b/crypto/logwrapper/logwrap.c
new file mode 100644
index 0000000..4ca1db4
--- /dev/null
+++ b/crypto/logwrapper/logwrap.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <pthread.h>
+
+#include <logwrap/logwrap.h>
+#include "private/android_filesystem_config.h"
+#include "cutils/log.h"
+#include <cutils/klog.h>
+
+#define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*(x)))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define ERROR(fmt, args...)                                                   \
+do {                                                                          \
+    fprintf(stderr, fmt, ## args);                                            \
+    ALOG(LOG_ERROR, "logwrapper", fmt, ## args);                              \
+} while(0)
+
+#define FATAL_CHILD(fmt, args...)                                             \
+do {                                                                          \
+    ERROR(fmt, ## args);                                                      \
+    _exit(-1);                                                                \
+} while(0)
+
+#define MAX_KLOG_TAG 16
+
+/* This is a simple buffer that holds up to the first beginning_buf->buf_size
+ * bytes of output from a command.
+ */
+#define BEGINNING_BUF_SIZE 0x1000
+struct beginning_buf {
+    char *buf;
+    size_t alloc_len;
+    /* buf_size is the usable space, which is one less than the allocated size */
+    size_t buf_size;
+    size_t used_len;
+};
+
+/* This is a circular buf that holds up to the last ending_buf->buf_size bytes
+ * of output from a command after the first beginning_buf->buf_size bytes
+ * (which are held in beginning_buf above).
+ */
+#define ENDING_BUF_SIZE 0x1000
+struct ending_buf {
+    char *buf;
+    ssize_t alloc_len;
+    /* buf_size is the usable space, which is one less than the allocated size */
+    ssize_t buf_size;
+    ssize_t used_len;
+    /* read and write offsets into the circular buffer */
+    int read;
+    int write;
+};
+
+ /* A structure to hold all the abbreviated buf data */
+struct abbr_buf {
+    struct beginning_buf b_buf;
+    struct ending_buf e_buf;
+    int beginning_buf_full;
+};
+
+/* Collect all the various bits of info needed for logging in one place. */
+struct log_info {
+    int log_target;
+    char klog_fmt[MAX_KLOG_TAG * 2];
+    char *btag;
+    bool abbreviated;
+    FILE *fp;
+    struct abbr_buf a_buf;
+};
+
+/* Forware declaration */
+static void add_line_to_abbr_buf(struct abbr_buf *a_buf, char *linebuf, int linelen);
+
+/* Return 0 on success, and 1 when full */
+static int add_line_to_linear_buf(struct beginning_buf *b_buf,
+                                   char *line, ssize_t line_len)
+{
+    size_t new_len;
+    char *new_buf;
+    int full = 0;
+
+    if ((line_len + b_buf->used_len) > b_buf->buf_size) {
+        full = 1;
+    } else {
+        /* Add to the end of the buf */
+        memcpy(b_buf->buf + b_buf->used_len, line, line_len);
+        b_buf->used_len += line_len;
+    }
+
+    return full;
+}
+
+static void add_line_to_circular_buf(struct ending_buf *e_buf,
+                                     char *line, ssize_t line_len)
+{
+    ssize_t free_len;
+    ssize_t needed_space;
+    char *new_buf;
+    int cnt;
+
+    if (e_buf->buf == NULL) {
+        return;
+    }
+
+   if (line_len > e_buf->buf_size) {
+       return;
+   }
+
+    free_len = e_buf->buf_size - e_buf->used_len;
+
+    if (line_len > free_len) {
+        /* remove oldest entries at read, and move read to make
+         * room for the new string */
+        needed_space = line_len - free_len;
+        e_buf->read = (e_buf->read + needed_space) % e_buf->buf_size;
+        e_buf->used_len -= needed_space;
+    }
+
+    /* Copy the line into the circular buffer, dealing with possible
+     * wraparound.
+     */
+    cnt = MIN(line_len, e_buf->buf_size - e_buf->write);
+    memcpy(e_buf->buf + e_buf->write, line, cnt);
+    if (cnt < line_len) {
+        memcpy(e_buf->buf, line + cnt, line_len - cnt);
+    }
+    e_buf->used_len += line_len;
+    e_buf->write = (e_buf->write + line_len) % e_buf->buf_size;
+}
+
+/* Log directly to the specified log */
+static void do_log_line(struct log_info *log_info, char *line) {
+    if (log_info->log_target & LOG_KLOG) {
+        klog_write(6, log_info->klog_fmt, line);
+    }
+    if (log_info->log_target & LOG_ALOG) {
+        ALOG(LOG_INFO, log_info->btag, "%s", line);
+    }
+    if (log_info->log_target & LOG_FILE) {
+        fprintf(log_info->fp, "%s\n", line);
+    }
+}
+
+/* Log to either the abbreviated buf, or directly to the specified log
+ * via do_log_line() above.
+ */
+static void log_line(struct log_info *log_info, char *line, int len) {
+    if (log_info->abbreviated) {
+        add_line_to_abbr_buf(&log_info->a_buf, line, len);
+    } else {
+        do_log_line(log_info, line);
+    }
+}
+
+/*
+ * The kernel will take a maximum of 1024 bytes in any single write to
+ * the kernel logging device file, so find and print each line one at
+ * a time.  The allocated size for buf should be at least 1 byte larger
+ * than buf_size (the usable size of the buffer) to make sure there is
+ * room to temporarily stuff a null byte to terminate a line for logging.
+ */
+static void print_buf_lines(struct log_info *log_info, char *buf, int buf_size)
+{
+    char *line_start;
+    char c;
+    int line_len;
+    int i;
+
+    line_start = buf;
+    for (i = 0; i < buf_size; i++) {
+        if (*(buf + i) == '\n') {
+            /* Found a line ending, print the line and compute new line_start */
+            /* Save the next char and replace with \0 */
+            c = *(buf + i + 1);
+            *(buf + i + 1) = '\0';
+            do_log_line(log_info, line_start);
+            /* Restore the saved char */
+            *(buf + i + 1) = c;
+            line_start = buf + i + 1;
+        } else if (*(buf + i) == '\0') {
+            /* The end of the buffer, print the last bit */
+            do_log_line(log_info, line_start);
+            break;
+        }
+    }
+    /* If the buffer was completely full, and didn't end with a newline, just
+     * ignore the partial last line.
+     */
+}
+
+static void init_abbr_buf(struct abbr_buf *a_buf) {
+    char *new_buf;
+
+    memset(a_buf, 0, sizeof(struct abbr_buf));
+    new_buf = malloc(BEGINNING_BUF_SIZE);
+    if (new_buf) {
+        a_buf->b_buf.buf = new_buf;
+        a_buf->b_buf.alloc_len = BEGINNING_BUF_SIZE;
+        a_buf->b_buf.buf_size = BEGINNING_BUF_SIZE - 1;
+    }
+    new_buf = malloc(ENDING_BUF_SIZE);
+    if (new_buf) {
+        a_buf->e_buf.buf = new_buf;
+        a_buf->e_buf.alloc_len = ENDING_BUF_SIZE;
+        a_buf->e_buf.buf_size = ENDING_BUF_SIZE - 1;
+    }
+}
+
+static void free_abbr_buf(struct abbr_buf *a_buf) {
+    free(a_buf->b_buf.buf);
+    free(a_buf->e_buf.buf);
+}
+
+static void add_line_to_abbr_buf(struct abbr_buf *a_buf, char *linebuf, int linelen) {
+    if (!a_buf->beginning_buf_full) {
+        a_buf->beginning_buf_full =
+            add_line_to_linear_buf(&a_buf->b_buf, linebuf, linelen);
+    }
+    if (a_buf->beginning_buf_full) {
+        add_line_to_circular_buf(&a_buf->e_buf, linebuf, linelen);
+    }
+}
+
+static void print_abbr_buf(struct log_info *log_info) {
+    struct abbr_buf *a_buf = &log_info->a_buf;
+
+    /* Add the abbreviated output to the kernel log */
+    if (a_buf->b_buf.alloc_len) {
+        print_buf_lines(log_info, a_buf->b_buf.buf, a_buf->b_buf.used_len);
+    }
+
+    /* Print an ellipsis to indicate that the buffer has wrapped or
+     * is full, and some data was not logged.
+     */
+    if (a_buf->e_buf.used_len == a_buf->e_buf.buf_size) {
+        do_log_line(log_info, "...\n");
+    }
+
+    if (a_buf->e_buf.used_len == 0) {
+        return;
+    }
+
+    /* Simplest way to print the circular buffer is allocate a second buf
+     * of the same size, and memcpy it so it's a simple linear buffer,
+     * and then cal print_buf_lines on it */
+    if (a_buf->e_buf.read < a_buf->e_buf.write) {
+        /* no wrap around, just print it */
+        print_buf_lines(log_info, a_buf->e_buf.buf + a_buf->e_buf.read,
+                        a_buf->e_buf.used_len);
+    } else {
+        /* The circular buffer will always have at least 1 byte unused,
+         * so by allocating alloc_len here we will have at least
+         * 1 byte of space available as required by print_buf_lines().
+         */
+        char * nbuf = malloc(a_buf->e_buf.alloc_len);
+        if (!nbuf) {
+            return;
+        }
+        int first_chunk_len = a_buf->e_buf.buf_size - a_buf->e_buf.read;
+        memcpy(nbuf, a_buf->e_buf.buf + a_buf->e_buf.read, first_chunk_len);
+        /* copy second chunk */
+        memcpy(nbuf + first_chunk_len, a_buf->e_buf.buf, a_buf->e_buf.write);
+        print_buf_lines(log_info, nbuf, first_chunk_len + a_buf->e_buf.write);
+        free(nbuf);
+    }
+}
+
+static int parent(const char *tag, int parent_read, pid_t pid,
+        int *chld_sts, int log_target, bool abbreviated, char *file_path) {
+    int status = 0;
+    char buffer[4096];
+    struct pollfd poll_fds[] = {
+        [0] = {
+            .fd = parent_read,
+            .events = POLLIN,
+        },
+    };
+    int rc = 0;
+    int fd;
+
+    struct log_info log_info;
+
+    int a = 0;  // start index of unprocessed data
+    int b = 0;  // end index of unprocessed data
+    int sz;
+    bool found_child = false;
+    char tmpbuf[256];
+
+    log_info.btag = basename(tag);
+    if (!log_info.btag) {
+        log_info.btag = (char*) tag;
+    }
+
+    if (abbreviated && (log_target == LOG_NONE)) {
+        abbreviated = 0;
+    }
+    if (abbreviated) {
+        init_abbr_buf(&log_info.a_buf);
+    }
+
+    if (log_target & LOG_KLOG) {
+        snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt),
+                 "<6>%.*s: %%s", MAX_KLOG_TAG, log_info.btag);
+    }
+
+    if ((log_target & LOG_FILE) && !file_path) {
+        /* No file_path specified, clear the LOG_FILE bit */
+        log_target &= ~LOG_FILE;
+    }
+
+    if (log_target & LOG_FILE) {
+        fd = open(file_path, O_WRONLY | O_CREAT, 0664);
+        if (fd < 0) {
+            ERROR("Cannot log to file %s\n", file_path);
+            log_target &= ~LOG_FILE;
+        } else {
+            lseek(fd, 0, SEEK_END);
+            log_info.fp = fdopen(fd, "a");
+        }
+    }
+
+    log_info.log_target = log_target;
+    log_info.abbreviated = abbreviated;
+
+    while (!found_child) {
+        if (TEMP_FAILURE_RETRY(poll(poll_fds, ARRAY_SIZE(poll_fds), -1)) < 0) {
+            ERROR("poll failed\n");
+            rc = -1;
+            goto err_poll;
+        }
+
+        if (poll_fds[0].revents & POLLIN) {
+            sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);
+
+            sz += b;
+            // Log one line at a time
+            for (b = 0; b < sz; b++) {
+                if (buffer[b] == '\r') {
+                    if (abbreviated) {
+                        /* The abbreviated logging code uses newline as
+                         * the line separator.  Lucikly, the pty layer
+                         * helpfully cooks the output of the command
+                         * being run and inserts a CR before NL.  So
+                         * I just change it to NL here when doing
+                         * abbreviated logging.
+                         */
+                        buffer[b] = '\n';
+                    } else {
+                        buffer[b] = '\0';
+                    }
+                } else if (buffer[b] == '\n') {
+                    buffer[b] = '\0';
+                    log_line(&log_info, &buffer[a], b - a);
+                    a = b + 1;
+                }
+            }
+
+            if (a == 0 && b == sizeof(buffer) - 1) {
+                // buffer is full, flush
+                buffer[b] = '\0';
+                log_line(&log_info, &buffer[a], b - a);
+                b = 0;
+            } else if (a != b) {
+                // Keep left-overs
+                b -= a;
+                memmove(buffer, &buffer[a], b);
+                a = 0;
+            } else {
+                a = 0;
+                b = 0;
+            }
+        }
+
+        if (poll_fds[0].revents & POLLHUP) {
+            int ret;
+
+            ret = waitpid(pid, &status, WNOHANG);
+            if (ret < 0) {
+                rc = errno;
+                ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno));
+                goto err_waitpid;
+            }
+            if (ret > 0) {
+                found_child = true;
+            }
+        }
+    }
+
+    if (chld_sts != NULL) {
+        *chld_sts = status;
+    } else {
+      if (WIFEXITED(status))
+        rc = WEXITSTATUS(status);
+      else
+        rc = -ECHILD;
+    }
+
+    // Flush remaining data
+    if (a != b) {
+      buffer[b] = '\0';
+      log_line(&log_info, &buffer[a], b - a);
+    }
+
+    /* All the output has been processed, time to dump the abbreviated output */
+    if (abbreviated) {
+        print_abbr_buf(&log_info);
+    }
+
+    if (WIFEXITED(status)) {
+      if (WEXITSTATUS(status)) {
+        snprintf(tmpbuf, sizeof(tmpbuf),
+                 "%s terminated by exit(%d)\n", log_info.btag, WEXITSTATUS(status));
+        do_log_line(&log_info, tmpbuf);
+      }
+    } else {
+      if (WIFSIGNALED(status)) {
+        snprintf(tmpbuf, sizeof(tmpbuf),
+                       "%s terminated by signal %d\n", log_info.btag, WTERMSIG(status));
+        do_log_line(&log_info, tmpbuf);
+      } else if (WIFSTOPPED(status)) {
+        snprintf(tmpbuf, sizeof(tmpbuf),
+                       "%s stopped by signal %d\n", log_info.btag, WSTOPSIG(status));
+        do_log_line(&log_info, tmpbuf);
+      }
+    }
+
+err_waitpid:
+err_poll:
+    if (log_target & LOG_FILE) {
+        fclose(log_info.fp); /* Also closes underlying fd */
+    }
+    if (abbreviated) {
+        free_abbr_buf(&log_info.a_buf);
+    }
+    return rc;
+}
+
+static void child(int argc, char* argv[]) {
+    // create null terminated argv_child array
+    char* argv_child[argc + 1];
+    memcpy(argv_child, argv, argc * sizeof(char *));
+    argv_child[argc] = NULL;
+
+    if (execvp(argv_child[0], argv_child)) {
+        FATAL_CHILD("executing %s failed: %s\n", argv_child[0],
+                strerror(errno));
+    }
+}
+
+int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
+        int log_target, bool abbreviated, char *file_path) {
+    pid_t pid;
+    int parent_ptty;
+    int child_ptty;
+    char *child_devname = NULL;
+    struct sigaction intact;
+    struct sigaction quitact;
+    sigset_t blockset;
+    sigset_t oldset;
+    int rc = 0;
+
+    rc = pthread_mutex_lock(&fd_mutex);
+    if (rc) {
+        ERROR("failed to lock signal_fd mutex\n");
+        goto err_lock;
+    }
+
+    /* Use ptty instead of socketpair so that STDOUT is not buffered */
+    parent_ptty = open("/dev/ptmx", O_RDWR);
+    if (parent_ptty < 0) {
+        ERROR("Cannot create parent ptty\n");
+        rc = -1;
+        goto err_open;
+    }
+
+    if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
+            ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
+        ERROR("Problem with /dev/ptmx\n");
+        rc = -1;
+        goto err_ptty;
+    }
+
+    child_ptty = open(child_devname, O_RDWR);
+    if (child_ptty < 0) {
+        ERROR("Cannot open child_ptty\n");
+        rc = -1;
+        goto err_child_ptty;
+    }
+
+    sigemptyset(&blockset);
+    sigaddset(&blockset, SIGINT);
+    sigaddset(&blockset, SIGQUIT);
+    pthread_sigmask(SIG_BLOCK, &blockset, &oldset);
+
+    pid = fork();
+    if (pid < 0) {
+        close(child_ptty);
+        ERROR("Failed to fork\n");
+        rc = -1;
+        goto err_fork;
+    } else if (pid == 0) {
+        pthread_mutex_unlock(&fd_mutex);
+        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+        close(parent_ptty);
+
+        // redirect stdout and stderr
+        dup2(child_ptty, 1);
+        dup2(child_ptty, 2);
+        close(child_ptty);
+
+        child(argc, argv);
+    } else {
+        close(child_ptty);
+        if (ignore_int_quit) {
+            struct sigaction ignact;
+
+            memset(&ignact, 0, sizeof(ignact));
+            ignact.sa_handler = SIG_IGN;
+            sigaction(SIGINT, &ignact, &intact);
+            sigaction(SIGQUIT, &ignact, &quitact);
+        }
+
+        rc = parent(argv[0], parent_ptty, pid, status, log_target,
+                    abbreviated, file_path);
+    }
+
+    if (ignore_int_quit) {
+        sigaction(SIGINT, &intact, NULL);
+        sigaction(SIGQUIT, &quitact, NULL);
+    }
+err_fork:
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+err_child_ptty:
+err_ptty:
+    close(parent_ptty);
+err_open:
+    pthread_mutex_unlock(&fd_mutex);
+err_lock:
+    return rc;
+}
diff --git a/crypto/logwrapper/logwrapper.c b/crypto/logwrapper/logwrapper.c
new file mode 100644
index 0000000..d0d8d14
--- /dev/null
+++ b/crypto/logwrapper/logwrapper.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <logwrap/logwrap.h>
+#include <cutils/klog.h>
+
+#include "cutils/log.h"
+
+void fatal(const char *msg) {
+    fprintf(stderr, "%s", msg);
+    ALOG(LOG_ERROR, "logwrapper", "%s", msg);
+    exit(-1);
+}
+
+void usage() {
+    fatal(
+        "Usage: logwrapper [-a] [-d] [-k] BINARY [ARGS ...]\n"
+        "\n"
+        "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
+        "the Android logging system. Tag is set to BINARY, priority is\n"
+        "always LOG_INFO.\n"
+        "\n"
+        "-a: Causes logwrapper to do abbreviated logging.\n"
+        "    This logs up to the first 4K and last 4K of the command\n"
+        "    being run, and logs the output when the command exits\n"
+        "-d: Causes logwrapper to SIGSEGV when BINARY terminates\n"
+        "    fault address is set to the status of wait()\n"
+        "-k: Causes logwrapper to log to the kernel log instead of\n"
+        "    the Android system log\n");
+}
+
+int main(int argc, char* argv[]) {
+    int seg_fault_on_exit = 0;
+    int log_target = LOG_ALOG;
+    bool abbreviated = false;
+    int ch;
+    int status = 0xAAAA;
+    int rc;
+
+    while ((ch = getopt(argc, argv, "adk")) != -1) {
+        switch (ch) {
+            case 'a':
+                abbreviated = true;
+                break;
+            case 'd':
+                seg_fault_on_exit = 1;
+                break;
+            case 'k':
+                log_target = LOG_KLOG;
+                klog_set_level(6);
+                break;
+            case '?':
+            default:
+              usage();
+        }
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 1) {
+        usage();
+    }
+
+    rc = android_fork_execvp_ext(argc, &argv[0], &status, true,
+                                 log_target, abbreviated, NULL);
+    if (!rc) {
+        if (WIFEXITED(status))
+            rc = WEXITSTATUS(status);
+        else
+            rc = -ECHILD;
+    }
+
+    if (seg_fault_on_exit) {
+        *(int *)status = 0;  // causes SIGSEGV with fault_address = status
+    }
+
+    return rc;
+}
diff --git a/crypto/scrypt/Android.mk b/crypto/scrypt/Android.mk
new file mode 100644
index 0000000..7fa96d0
--- /dev/null
+++ b/crypto/scrypt/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+
+# Enable to be able to use ALOG* with #include "cutils/log.h"
+#log_c_includes += system/core/include
+#log_shared_libraries := liblog
+
+# These makefiles are here instead of being Android.mk files in the
+# respective crypto, ssl, and apps directories so
+# that import_openssl.sh import won't remove them.
+include $(LOCAL_PATH)/build-config.mk
+include $(LOCAL_PATH)/Scrypt.mk
+
+include $(call all-named-subdir-makefiles,tests)
diff --git a/crypto/scrypt/MODULE_LICENSE_BSD_LIKE b/crypto/scrypt/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/crypto/scrypt/MODULE_LICENSE_BSD_LIKE
diff --git a/crypto/scrypt/NOTICE b/crypto/scrypt/NOTICE
new file mode 100644
index 0000000..b0b9311
--- /dev/null
+++ b/crypto/scrypt/NOTICE
@@ -0,0 +1,36 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+
+/*
+ * version 20110505
+ * D. J. Bernstein
+ * Public domain.
+ *
+ * Based on crypto_core/salsa208/armneon/core.c from SUPERCOP 20130419
+ */
diff --git a/crypto/scrypt/Scrypt-config.mk b/crypto/scrypt/Scrypt-config.mk
new file mode 100644
index 0000000..bdaeccf
--- /dev/null
+++ b/crypto/scrypt/Scrypt-config.mk
@@ -0,0 +1,105 @@
+# Auto-generated - DO NOT EDIT!
+# To regenerate, edit scrypt.config, then run:
+#     ./import_scrypt.sh import /path/to/scrypt-1.1.6.tar.gz
+#
+# Before including this file, the local Android.mk must define the following
+# variables:
+#
+#    local_c_flags
+#    local_c_includes
+#    local_additional_dependencies
+#
+# This script will define the following variables:
+#
+#    target_c_flags
+#    target_c_includes
+#    target_src_files
+#
+#    host_c_flags
+#    host_c_includes
+#    host_src_files
+#
+
+# Ensure these are empty.
+unknown_arch_c_flags :=
+unknown_arch_src_files :=
+unknown_arch_exclude_files :=
+
+
+common_c_flags :=
+
+common_src_files := \
+  lib/crypto/crypto_scrypt-ref.c \
+
+common_c_includes := \
+  lib/crypto \
+  lib/util \
+
+arm_c_flags :=
+
+arm_src_files :=
+
+arm_exclude_files :=
+
+arm_neon_c_flags :=
+
+arm_neon_src_files := \
+  lib/crypto/crypto_scrypt-neon.c \
+
+arm_neon_exclude_files := \
+  lib/crypto/crypto_scrypt-ref.c \
+
+x86_c_flags :=
+
+x86_src_files := \
+  lib/crypto/crypto_scrypt-sse.c \
+
+x86_exclude_files := \
+  lib/crypto/crypto_scrypt-ref.c \
+
+x86_64_c_flags :=
+
+x86_64_src_files := \
+  lib/crypto/crypto_scrypt-sse.c \
+
+x86_64_exclude_files := \
+  lib/crypto/crypto_scrypt-ref.c \
+
+mips_c_flags :=
+
+mips_src_files :=
+
+mips_exclude_files :=
+
+target_arch := $(TARGET_ARCH)
+ifeq ($(target_arch)-$(TARGET_HAS_BIGENDIAN),mips-true)
+target_arch := unknown_arch
+endif
+
+target_c_flags    := $(common_c_flags) $($(target_arch)_c_flags) $(local_c_flags)
+target_c_includes := $(addprefix bootable/recovery/crypto/scrypt/,$(common_c_includes)) $(local_c_includes)
+target_src_files  := $(common_src_files) $($(target_arch)_src_files)
+target_src_files  := $(filter-out $($(target_arch)_exclude_files), $(target_src_files))
+
+# Hacks for ARM NEON support
+ifeq ($(target_arch),arm)
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
+target_c_flags   += $(arm_neon_c_flags)
+target_src_files += $(arm_neon_src_files)
+target_src_files := $(filter-out $(arm_neon_exclude_files), $(target_src_files))
+endif
+endif
+
+ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
+host_arch := x86
+else
+host_arch := unknown_arch
+endif
+
+host_c_flags    := $(common_c_flags) $($(host_arch)_c_flags) $(local_c_flags)
+host_c_includes := $(addprefix bootable/recovery/crypto/scrypt/,$(common_c_includes)) $(local_c_includes)
+host_src_files  := $(common_src_files) $($(host_arch)_src_files)
+host_src_files  := $(filter-out $($(host_arch)_exclude_files), $(host_src_files))
+
+local_additional_dependencies += $(LOCAL_PATH)/Scrypt-config.mk
+
diff --git a/crypto/scrypt/Scrypt.mk b/crypto/scrypt/Scrypt.mk
new file mode 100644
index 0000000..45af97f
--- /dev/null
+++ b/crypto/scrypt/Scrypt.mk
@@ -0,0 +1,46 @@
+local_c_flags := -DUSE_OPENSSL_PBKDF2
+
+local_c_includes := $(log_c_includes) external/openssl/include
+
+local_additional_dependencies := $(LOCAL_PATH)/android-config.mk $(LOCAL_PATH)/Scrypt.mk
+
+include $(LOCAL_PATH)/Scrypt-config.mk
+
+#######################################
+# target static library
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android-config.mk
+
+LOCAL_SHARED_LIBRARIES := $(log_shared_libraries)
+
+# If we're building an unbundled build, don't try to use clang since it's not
+# in the NDK yet. This can be removed when a clang version that is fast enough
+# in the NDK.
+ifeq (,$(TARGET_BUILD_APPS))
+LOCAL_CLANG := true
+else
+LOCAL_SDK_VERSION := 9
+endif
+
+LOCAL_SRC_FILES += $(target_src_files)
+LOCAL_CFLAGS += $(target_c_flags)
+LOCAL_C_INCLUDES += $(target_c_includes)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:= libscrypttwrp_static
+LOCAL_ADDITIONAL_DEPENDENCIES := $(local_additional_dependencies)
+include $(BUILD_STATIC_LIBRARY)
+
+########################################
+# host static library
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/android-config.mk
+LOCAL_SHARED_LIBRARIES := $(log_shared_libraries)
+LOCAL_SRC_FILES += $(host_src_files)
+LOCAL_CFLAGS += $(host_c_flags)
+LOCAL_C_INCLUDES += $(host_c_includes)
+LOCAL_LDLIBS += -ldl
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:= libscrypttwrp_static
+LOCAL_ADDITIONAL_DEPENDENCIES := $(local_additional_dependencies)
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/crypto/scrypt/android-config.mk b/crypto/scrypt/android-config.mk
new file mode 100644
index 0000000..326e113
--- /dev/null
+++ b/crypto/scrypt/android-config.mk
@@ -0,0 +1,16 @@
+#
+# These flags represent the build-time configuration of scrypt for Android
+#
+# The value of $(scrypt_cflags) was pruned from the Makefile generated
+# by running ./configure from import_scrypt.sh.
+#
+# This script performs minor but required patching for the Android build.
+#
+
+LOCAL_CFLAGS += $(scrypt_cflags)
+
+# Add in flags to let config.h be read properly
+LOCAL_CFLAGS += "-DHAVE_CONFIG_H"
+
+# Add clang here when it works on host
+# LOCAL_CLANG := true
diff --git a/crypto/scrypt/build-config.mk b/crypto/scrypt/build-config.mk
new file mode 100644
index 0000000..3d2ab91
--- /dev/null
+++ b/crypto/scrypt/build-config.mk
@@ -0,0 +1,6 @@
+# Auto-generated - DO NOT EDIT!
+# To regenerate, edit scrypt.config, then run:
+#     ./import_scrypt.sh import /path/to/scrypt-1.1.6.tar.gz
+#
+scrypt_cflags := \
+
diff --git a/crypto/scrypt/config.h b/crypto/scrypt/config.h
new file mode 100644
index 0000000..3514f39
--- /dev/null
+++ b/crypto/scrypt/config.h
@@ -0,0 +1,99 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the declaration of `be64enc', and to 0 if you
+   don't. */
+#define HAVE_DECL_BE64ENC 0
+
+/* Define to 1 if you have the <err.h> header file. */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `posix_memalign' function. */
+#define HAVE_POSIX_MEMALIGN 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if the system has the type `struct sysinfo'. */
+#define HAVE_STRUCT_SYSINFO 1
+
+/* Define to 1 if `mem_unit' is member of `struct sysinfo'. */
+#define HAVE_STRUCT_SYSINFO_MEM_UNIT 1
+
+/* Define to 1 if `totalram' is member of `struct sysinfo'. */
+#define HAVE_STRUCT_SYSINFO_TOTALRAM 1
+
+/* Define to 1 if the OS has a hw.usermem sysctl */
+/* #undef HAVE_SYSCTL_HW_USERMEM */
+
+/* Define to 1 if you have the `sysinfo' function. */
+#define HAVE_SYSINFO 1
+
+/* Define to 1 if you have the <sys/endian.h> header file. */
+/* #undef HAVE_SYS_ENDIAN_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/sysinfo.h> header file. */
+#define HAVE_SYS_SYSINFO_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Name of package */
+#define PACKAGE "scrypt"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "scrypt"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "scrypt 1.1.6"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "scrypt"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.1.6"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.1.6"
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
diff --git a/crypto/scrypt/import_scrypt.sh b/crypto/scrypt/import_scrypt.sh
new file mode 100755
index 0000000..324eae6
--- /dev/null
+++ b/crypto/scrypt/import_scrypt.sh
@@ -0,0 +1,493 @@
+#!/bin/bash
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# This script imports new versions of scrypt (http://www.tarsnap.com/scrypt/) into the
+# Android source tree.  To run, (1) fetch the appropriate tarball from the scrypt repository,
+# (2) check the gpg/pgp signature, and then (3) run:
+#   ./import_scrypt.sh import scrypt-*.tar.gz
+#
+# IMPORTANT: See README.android for additional details.
+
+# turn on exit on error as well as a warning when it happens
+set -e
+set -x
+trap  "echo WARNING: Exiting on non-zero subprocess exit code" ERR;
+
+# Ensure consistent sorting order / tool output.
+export LANG=C
+export LC_ALL=C
+
+export DIRNAME=$(dirname $0)
+
+function die() {
+  declare -r message=$1
+
+  echo $message
+  exit 1
+}
+
+function usage() {
+  declare -r message=$1
+
+  if [ ! "$message" = "" ]; then
+    echo $message
+  fi
+  echo "Usage:"
+  echo "  ./import_scrypt.sh import </path/to/scrypt-*.tar.gz>"
+  echo "  ./import_scrypt.sh regenerate <patch/*.patch>"
+  echo "  ./import_scrypt.sh generate <patch/*.patch> </path/to/scrypt-*.tar.gz>"
+  exit 1
+}
+
+function main() {
+  if [ ! -d patches ]; then
+    die "scrypt patch directory patches/ not found"
+  fi
+
+  if [ ! -f scrypt.version ]; then
+    die "scrypt.version not found"
+  fi
+
+  source $DIRNAME/scrypt.version
+  if [ "$SCRYPT_VERSION" == "" ]; then
+    die "Invalid scrypt.version; see README.android for more information"
+  fi
+
+  SCRYPT_DIR=scrypt-$SCRYPT_VERSION
+  SCRYPT_DIR_ORIG=$SCRYPT_DIR.orig
+
+  if [ ! -f scrypt.config ]; then
+    die "scrypt.config not found"
+  fi
+
+  source $DIRNAME/scrypt.config
+  if [ "$CONFIGURE_ARGS" == "" -o "$UNNEEDED_SOURCES" == "" -o "$NEEDED_SOURCES" == "" ]; then
+    die "Invalid scrypt.config; see README.android for more information"
+  fi
+
+  declare -r command=$1
+  shift || usage "No command specified. Try import, regenerate, or generate."
+  if [ "$command" = "import" ]; then
+    declare -r tar=$1
+    shift || usage "No tar file specified."
+    import $tar
+  elif [ "$command" = "regenerate" ]; then
+    declare -r patch=$1
+    shift || usage "No patch file specified."
+    [ -d $SCRYPT_DIR ] || usage "$SCRYPT_DIR not found, did you mean to use generate?"
+    [ -d $SCRYPT_DIR_ORIG_ORIG ] || usage "$SCRYPT_DIR_ORIG not found, did you mean to use generate?"
+    regenerate $patch
+  elif [ "$command" = "generate" ]; then
+    declare -r patch=$1
+    shift || usage "No patch file specified."
+    declare -r tar=$1
+    shift || usage "No tar file specified."
+    generate $patch $tar
+  else
+    usage "Unknown command specified $command. Try import, regenerate, or generate."
+  fi
+}
+
+# Compute the name of an assembly source file generated by one of the
+# gen_asm_xxxx() functions below. The logic is the following:
+# - if "$2" is not empty, output it directly
+# - otherwise, change the file extension of $1 from .pl to .S and output
+#   it.
+# Usage: default_asm_file "$1" "$2"
+#     or default_asm_file "$@"
+#
+# $1: generator path (perl script)
+# $2: optional output file name.
+function default_asm_file () {
+  if [ "$2" ]; then
+    echo "$2"
+  else
+    echo "${1%%.pl}.S"
+  fi
+}
+
+# Generate an ARM assembly file.
+# $1: generator (perl script)
+# $2: [optional] output file name
+function gen_asm_arm () {
+  local OUT
+  OUT=$(default_asm_file "$@")
+  perl "$1" > "$OUT"
+}
+
+function gen_asm_mips () {
+  local OUT
+  OUT=$(default_asm_file "$@")
+  # The perl scripts expect to run the target compiler as $CC to determine
+  # the endianess of the target. Setting CC to true is a hack that forces the scripts
+  # to generate little endian output
+  CC=true perl "$1" o32 > "$OUT"
+}
+
+function gen_asm_x86 () {
+  local OUT
+  OUT=$(default_asm_file "$@")
+  perl "$1" elf -fPIC > "$OUT"
+}
+
+function gen_asm_x86_64 () {
+  local OUT
+  OUT=$(default_asm_file "$@")
+  perl "$1" elf "$OUT" > "$OUT"
+}
+
+
+# Filter all items in a list that match a given pattern.
+# $1: space-separated list
+# $2: egrep pattern.
+# Out: items in $1 that match $2
+function filter_by_egrep() {
+  declare -r pattern=$1
+  shift
+  echo "$@" | tr ' ' '\n' | grep -e "$pattern" | tr '\n' ' '
+}
+
+# Sort and remove duplicates in a space-separated list
+# $1: space-separated list
+# Out: new space-separated list
+function uniq_sort () {
+  echo "$@" | tr ' ' '\n' | sort -u | tr '\n' ' '
+}
+
+function print_autogenerated_header() {
+  echo "# Auto-generated - DO NOT EDIT!"
+  echo "# To regenerate, edit scrypt.config, then run:"
+  echo "#     ./import_scrypt.sh import /path/to/scrypt-$SCRYPT_VERSION.tar.gz"
+  echo "#"
+}
+
+function generate_build_config_mk() {
+  ./configure $CONFIGURE_ARGS
+  #rm -f apps/CA.pl.bak crypto/scryptconf.h.bak
+
+  declare -r tmpfile=$(mktemp)
+  (grep -e -D Makefile | grep -v CONFIGURE_ARGS= | grep -v OPTIONS=) > $tmpfile
+
+  declare -r cflags=$(filter_by_egrep "^-D" $(grep -e "^CFLAG=" $tmpfile))
+  declare -r depflags=$(filter_by_egrep "^-D" $(grep -e "^DEPFLAG=" $tmpfile))
+  rm -f $tmpfile
+
+  echo "Generating $(basename $1)"
+  (
+    print_autogenerated_header
+
+    echo "scrypt_cflags := \\"
+    for cflag in $cflags $depflags; do
+      echo "  $cflag \\"
+    done
+    echo ""
+  ) > $1
+}
+
+# Return the value of a computed variable name.
+# E.g.:
+#   FOO=foo
+#   BAR=bar
+#   echo $(var_value FOO_$BAR)   -> prints the value of ${FOO_bar}
+# $1: Variable name
+# Out: variable value
+var_value() {
+  # Note: don't use 'echo' here, because it's sensitive to values
+  #       that begin with an underscore (e.g. "-n")
+  eval printf \"%s\\n\" \$$1
+}
+
+# Same as var_value, but returns sorted output without duplicates.
+# $1: Variable name
+# Out: variable value (if space-separated list, sorted with no duplicates)
+var_sorted_value() {
+  uniq_sort $(var_value $1)
+}
+
+# Print the definition of a given variable in a GNU Make build file.
+# $1: Variable name (e.g. common_src_files)
+# $2+: Variable value (e.g. list of sources)
+print_vardef_in_mk() {
+  declare -r varname=$1
+  shift
+  if [ -z "$1" ]; then
+    echo "$varname :="
+  else
+    echo "$varname := \\"
+    for src; do
+      echo "  $src \\"
+    done
+  fi
+  echo ""
+}
+
+# Same as print_vardef_in_mk, but print a CFLAGS definition from
+# a list of compiler defines.
+# $1: Variable name (e.g. common_c_flags)
+# $2: List of defines (e.g. SCRYPT_NO_DONKEYS ...)
+print_defines_in_mk() {
+  declare -r varname=$1
+  shift
+  if [ -z "$1" ]; then
+    echo "$varname :="
+  else
+    echo "$varname := \\"
+    for def; do
+    echo "  -D$def \\"
+    done
+  fi
+  echo ""
+}
+
+# Generate a configuration file like Scrypt-config.mk
+# This uses variable definitions from scrypt.config to build a config
+# file that can compute the list of target- and host-specific sources /
+# compiler flags for a given component.
+#
+# $1: Target file name.  (e.g. Scrypt-config.mk)
+function generate_config_mk() {
+  declare -r output="$1"
+  declare -r all_archs="arm arm_neon x86 x86_64 mips"
+
+  echo "Generating $(basename $output)"
+  (
+    print_autogenerated_header
+    echo \
+"# Before including this file, the local Android.mk must define the following
+# variables:
+#
+#    local_c_flags
+#    local_c_includes
+#    local_additional_dependencies
+#
+# This script will define the following variables:
+#
+#    target_c_flags
+#    target_c_includes
+#    target_src_files
+#
+#    host_c_flags
+#    host_c_includes
+#    host_src_files
+#
+
+# Ensure these are empty.
+unknown_arch_c_flags :=
+unknown_arch_src_files :=
+unknown_arch_exclude_files :=
+
+"
+    common_defines=$(var_sorted_value SCRYPT_DEFINES)
+    print_defines_in_mk common_c_flags $common_defines
+
+    common_sources=$(var_sorted_value SCRYPT_SOURCES)
+    print_vardef_in_mk common_src_files $common_sources
+
+    common_includes=$(var_sorted_value SCRYPT_INCLUDES)
+    print_vardef_in_mk common_c_includes $common_includes
+
+    for arch in $all_archs; do
+      arch_defines=$(var_sorted_value SCRYPT_DEFINES_${arch})
+      print_defines_in_mk ${arch}_c_flags $arch_defines
+
+      arch_sources=$(var_sorted_value SCRYPT_SOURCES_${arch})
+      print_vardef_in_mk ${arch}_src_files $arch_sources
+
+      arch_exclude_sources=$(var_sorted_value SCRYPT_SOURCES_EXCLUDES_${arch})
+      print_vardef_in_mk ${arch}_exclude_files $arch_exclude_sources
+
+    done
+
+    echo "\
+target_arch := \$(TARGET_ARCH)
+ifeq (\$(target_arch)-\$(TARGET_HAS_BIGENDIAN),mips-true)
+target_arch := unknown_arch
+endif
+
+target_c_flags    := \$(common_c_flags) \$(\$(target_arch)_c_flags) \$(local_c_flags)
+target_c_includes := \$(addprefix external/scrypt/,\$(common_c_includes)) \$(local_c_includes)
+target_src_files  := \$(common_src_files) \$(\$(target_arch)_src_files)
+target_src_files  := \$(filter-out \$(\$(target_arch)_exclude_files), \$(target_src_files))
+
+# Hacks for ARM NEON support
+ifeq (\$(target_arch),arm)
+ifeq (\$(ARCH_ARM_HAVE_NEON),true)
+target_c_flags   += \$(arm_neon_c_flags)
+target_src_files += \$(arm_neon_src_files)
+target_src_files := \$(filter-out \$(arm_neon_exclude_files), \$(target_src_files))
+endif
+endif
+
+ifeq (\$(HOST_OS)-\$(HOST_ARCH),linux-x86)
+host_arch := x86
+else
+host_arch := unknown_arch
+endif
+
+host_c_flags    := \$(common_c_flags) \$(\$(host_arch)_c_flags) \$(local_c_flags)
+host_c_includes := \$(addprefix external/scrypt/,\$(common_c_includes)) \$(local_c_includes)
+host_src_files  := \$(common_src_files) \$(\$(host_arch)_src_files)
+host_src_files  := \$(filter-out \$(\$(host_arch)_exclude_files), \$(host_src_files))
+
+local_additional_dependencies += \$(LOCAL_PATH)/$(basename $output)
+"
+
+  ) > "$output"
+}
+
+function import() {
+  declare -r SCRYPT_SOURCE=$1
+
+  untar $SCRYPT_SOURCE readonly
+  applypatches $SCRYPT_DIR
+
+  cd $SCRYPT_DIR
+
+  generate_build_config_mk ../build-config.mk
+
+  touch ../MODULE_LICENSE_BSD_LIKE
+
+  cd ..
+
+  generate_config_mk Scrypt-config.mk
+
+  # Prune unnecessary sources
+  prune
+
+  NEEDED_SOURCES="$NEEDED_SOURCES"
+  for i in $NEEDED_SOURCES; do
+    echo "Updating $i"
+    rm -r $i
+    mv $SCRYPT_DIR/$i .
+  done
+
+  cleantar
+}
+
+function regenerate() {
+  declare -r patch=$1
+
+  generatepatch $patch
+}
+
+function generate() {
+  declare -r patch=$1
+  declare -r SCRYPT_SOURCE=$2
+
+  untar $SCRYPT_SOURCE
+  applypatches $SCRYPT_DIR_ORIG $patch
+  prune
+
+  for i in $NEEDED_SOURCES; do
+    echo "Restoring $i"
+    rm -r $SCRYPT_DIR/$i
+    cp -rf $i $SCRYPT_DIR/$i
+  done
+
+  generatepatch $patch
+  cleantar
+}
+
+# Find all files in a sub-directory that are encoded in ISO-8859
+# $1: Directory.
+# Out: list of files in $1 that are encoded as ISO-8859.
+function find_iso8859_files() {
+  find $1 -type f -print0 | xargs -0 file | fgrep "ISO-8859" | cut -d: -f1
+}
+
+# Convert all ISO-8859 files in a given subdirectory to UTF-8
+# $1: Directory name
+function convert_iso8859_to_utf8() {
+  declare -r iso_files=$(find_iso8859_files "$1")
+  for iso_file in $iso_files; do
+    iconv --from-code iso-8859-1 --to-code utf-8 $iso_file > $iso_file.tmp
+    rm -f $iso_file
+    mv $iso_file.tmp $iso_file
+  done
+}
+
+function untar() {
+  declare -r SCRYPT_SOURCE=$1
+  declare -r readonly=$2
+
+  # Remove old source
+  cleantar
+
+  # Process new source
+  tar -zxf $SCRYPT_SOURCE
+  convert_iso8859_to_utf8 $SCRYPT_DIR
+  cp -rfP $SCRYPT_DIR $SCRYPT_DIR_ORIG
+  if [ ! -z $readonly ]; then
+    find $SCRYPT_DIR_ORIG -type f -print0 | xargs -0 chmod a-w
+  fi
+}
+
+function prune() {
+  echo "Removing $UNNEEDED_SOURCES"
+  (cd $SCRYPT_DIR_ORIG && rm -rf $UNNEEDED_SOURCES)
+  (cd $SCRYPT_DIR      && rm -r  $UNNEEDED_SOURCES)
+}
+
+function cleantar() {
+  rm -rf $SCRYPT_DIR_ORIG
+  rm -rf $SCRYPT_DIR
+}
+
+function applypatches () {
+  declare -r dir=$1
+  declare -r skip_patch=$2
+
+  cd $dir
+
+  # Apply appropriate patches
+  for i in $SCRYPT_PATCHES; do
+    if [ ! "$skip_patch" = "patches/$i" ]; then
+      echo "Applying patch $i"
+      patch -p1 --merge < ../patches/$i || die "Could not apply patches/$i. Fix source and run: $0 regenerate patches/$i"
+    else
+      echo "Skiping patch $i"
+    fi
+
+  done
+
+  # Cleanup patch output
+  find . \( -type f -o -type l \) -name "*.orig" -print0 | xargs -0 rm -f
+
+  cd ..
+}
+
+function generatepatch() {
+  declare -r patch=$1
+
+  # Cleanup stray files before generating patch
+  find $SCRYPT_DIR -type f -name "*.orig" -print0 | xargs -0 rm -f
+  find $SCRYPT_DIR -type f -name "*~" -print0 | xargs -0 rm -f
+
+  declare -r variable_name=SCRYPT_PATCHES_`basename $patch .patch | sed s/-/_/`_SOURCES
+  # http://tldp.org/LDP/abs/html/ivr.html
+  eval declare -r sources=\$$variable_name
+  rm -f $patch
+  touch $patch
+  for i in $sources; do
+    LC_ALL=C TZ=UTC0 diff -aup $SCRYPT_DIR_ORIG/$i $SCRYPT_DIR/$i >> $patch && die "ERROR: No diff for patch $path in file $i"
+  done
+  echo "Generated patch $patch"
+  echo "NOTE To make sure there are not unwanted changes from conflicting patches, be sure to review the generated patch."
+}
+
+main $@
diff --git a/crypto/scrypt/lib/README b/crypto/scrypt/lib/README
new file mode 100644
index 0000000..3bb211e
--- /dev/null
+++ b/crypto/scrypt/lib/README
@@ -0,0 +1,6 @@
+The source code under this directory is taken from the client for the
+Tarsnap online backup system (and released under the 2-clause BSD license
+with permission of the author); keeping this code in sync with the Tarsnap
+code is highly desirable and explains why there is some functionality
+included here which is not actually used by the scrypt file encryption
+utility.
diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-neon-salsa208.h b/crypto/scrypt/lib/crypto/crypto_scrypt-neon-salsa208.h
new file mode 100644
index 0000000..a3b1019
--- /dev/null
+++ b/crypto/scrypt/lib/crypto/crypto_scrypt-neon-salsa208.h
@@ -0,0 +1,120 @@
+/*
+ * version 20110505
+ * D. J. Bernstein
+ * Public domain.
+ *
+ * Based on crypto_core/salsa208/armneon/core.c from SUPERCOP 20130419
+ */
+
+#define ROUNDS 8
+static void
+salsa20_8_intrinsic(void * input)
+{
+  int i;
+
+  const uint32x4_t abab = {-1,0,-1,0};
+
+  /*
+   * This is modified since we only have one argument. Usually you'd rearrange
+   * the constant, key, and input bytes, but we just have one linear array to
+   * rearrange which is a bit easier.
+   */
+
+  /*
+   * Change the input to be diagonals as if it's a 4x4 matrix of 32-bit values.
+   */
+  uint32x4_t x0x5x10x15;
+  uint32x4_t x12x1x6x11;
+  uint32x4_t x8x13x2x7;
+  uint32x4_t x4x9x14x3;
+
+  uint32x4_t x0x1x10x11;
+  uint32x4_t x12x13x6x7;
+  uint32x4_t x8x9x2x3;
+  uint32x4_t x4x5x14x15;
+
+  uint32x4_t x0x1x2x3;
+  uint32x4_t x4x5x6x7;
+  uint32x4_t x8x9x10x11;
+  uint32x4_t x12x13x14x15;
+
+  x0x1x2x3 = vld1q_u8((uint8_t *) input);
+  x4x5x6x7 = vld1q_u8(16 + (uint8_t *) input);
+  x8x9x10x11 = vld1q_u8(32 + (uint8_t *) input);
+  x12x13x14x15 = vld1q_u8(48 + (uint8_t *) input);
+
+  x0x1x10x11 = vcombine_u32(vget_low_u32(x0x1x2x3), vget_high_u32(x8x9x10x11));
+  x4x5x14x15 = vcombine_u32(vget_low_u32(x4x5x6x7), vget_high_u32(x12x13x14x15));
+  x8x9x2x3 = vcombine_u32(vget_low_u32(x8x9x10x11), vget_high_u32(x0x1x2x3));
+  x12x13x6x7 = vcombine_u32(vget_low_u32(x12x13x14x15), vget_high_u32(x4x5x6x7));
+
+  x0x5x10x15 = vbslq_u32(abab,x0x1x10x11,x4x5x14x15);
+  x8x13x2x7 = vbslq_u32(abab,x8x9x2x3,x12x13x6x7);
+  x4x9x14x3 = vbslq_u32(abab,x4x5x14x15,x8x9x2x3);
+  x12x1x6x11 = vbslq_u32(abab,x12x13x6x7,x0x1x10x11);
+
+  uint32x4_t start0 = x0x5x10x15;
+  uint32x4_t start1 = x12x1x6x11;
+  uint32x4_t start3 = x4x9x14x3;
+  uint32x4_t start2 = x8x13x2x7;
+
+  /* From here on this should be the same as the SUPERCOP version. */
+
+  uint32x4_t diag0 = start0;
+  uint32x4_t diag1 = start1;
+  uint32x4_t diag2 = start2;
+  uint32x4_t diag3 = start3;
+
+  uint32x4_t a0;
+  uint32x4_t a1;
+  uint32x4_t a2;
+  uint32x4_t a3;
+
+  for (i = ROUNDS;i > 0;i -= 2) {
+    a0 = diag1 + diag0;
+    diag3 ^= vsriq_n_u32(vshlq_n_u32(a0,7),a0,25);
+    a1 = diag0 + diag3;
+    diag2 ^= vsriq_n_u32(vshlq_n_u32(a1,9),a1,23);
+    a2 = diag3 + diag2;
+    diag1 ^= vsriq_n_u32(vshlq_n_u32(a2,13),a2,19);
+    a3 = diag2 + diag1;
+    diag0 ^= vsriq_n_u32(vshlq_n_u32(a3,18),a3,14);
+
+    diag3 = vextq_u32(diag3,diag3,3);
+    diag2 = vextq_u32(diag2,diag2,2);
+    diag1 = vextq_u32(diag1,diag1,1);
+
+    a0 = diag3 + diag0;
+    diag1 ^= vsriq_n_u32(vshlq_n_u32(a0,7),a0,25);
+    a1 = diag0 + diag1;
+    diag2 ^= vsriq_n_u32(vshlq_n_u32(a1,9),a1,23);
+    a2 = diag1 + diag2;
+    diag3 ^= vsriq_n_u32(vshlq_n_u32(a2,13),a2,19);
+    a3 = diag2 + diag3;
+    diag0 ^= vsriq_n_u32(vshlq_n_u32(a3,18),a3,14);
+
+    diag1 = vextq_u32(diag1,diag1,3);
+    diag2 = vextq_u32(diag2,diag2,2);
+    diag3 = vextq_u32(diag3,diag3,1);
+  }
+
+  x0x5x10x15 = diag0 + start0;
+  x12x1x6x11 = diag1 + start1;
+  x8x13x2x7 = diag2 + start2;
+  x4x9x14x3 = diag3 + start3;
+
+  x0x1x10x11 = vbslq_u32(abab,x0x5x10x15,x12x1x6x11);
+  x12x13x6x7 = vbslq_u32(abab,x12x1x6x11,x8x13x2x7);
+  x8x9x2x3 = vbslq_u32(abab,x8x13x2x7,x4x9x14x3);
+  x4x5x14x15 = vbslq_u32(abab,x4x9x14x3,x0x5x10x15);
+
+  x0x1x2x3 = vcombine_u32(vget_low_u32(x0x1x10x11),vget_high_u32(x8x9x2x3));
+  x4x5x6x7 = vcombine_u32(vget_low_u32(x4x5x14x15),vget_high_u32(x12x13x6x7));
+  x8x9x10x11 = vcombine_u32(vget_low_u32(x8x9x2x3),vget_high_u32(x0x1x10x11));
+  x12x13x14x15 = vcombine_u32(vget_low_u32(x12x13x6x7),vget_high_u32(x4x5x14x15));
+
+  vst1q_u8((uint8_t *) input,(uint8x16_t) x0x1x2x3);
+  vst1q_u8(16 + (uint8_t *) input,(uint8x16_t) x4x5x6x7);
+  vst1q_u8(32 + (uint8_t *) input,(uint8x16_t) x8x9x10x11);
+  vst1q_u8(48 + (uint8_t *) input,(uint8x16_t) x12x13x14x15);
+}
diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c b/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c
new file mode 100644
index 0000000..a3bf052
--- /dev/null
+++ b/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c
@@ -0,0 +1,305 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <machine/cpu-features.h>
+#include <arm_neon.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USE_OPENSSL_PBKDF2
+#include <openssl/evp.h>
+#else
+#include "sha256.h"
+#endif
+#include "sysendian.h"
+
+#include "crypto_scrypt.h"
+
+#include "crypto_scrypt-neon-salsa208.h"
+
+static void blkcpy(void *, void *, size_t);
+static void blkxor(void *, void *, size_t);
+void crypto_core_salsa208_armneon2(void *);
+static void blockmix_salsa8(uint8x16_t *, uint8x16_t *, uint8x16_t *, size_t);
+static uint64_t integerify(void *, size_t);
+static void smix(uint8_t *, size_t, uint64_t, void *, void *);
+
+static void
+blkcpy(void * dest, void * src, size_t len)
+{
+	uint8x16_t * D = dest;
+	uint8x16_t * S = src;
+	size_t L = len / 16;
+	size_t i;
+
+	for (i = 0; i < L; i++)
+		D[i] = S[i];
+}
+
+static void
+blkxor(void * dest, void * src, size_t len)
+{
+	uint8x16_t * D = dest;
+	uint8x16_t * S = src;
+	size_t L = len / 16;
+	size_t i;
+
+	for (i = 0; i < L; i++)
+		D[i] = veorq_u8(D[i], S[i]);
+}
+
+/**
+ * blockmix_salsa8(B, Y, r):
+ * Compute B = BlockMix_{salsa20/8, r}(B).  The input B must be 128r bytes in
+ * length; the temporary space Y must also be the same size.
+ */
+static void
+blockmix_salsa8(uint8x16_t * Bin, uint8x16_t * Bout, uint8x16_t * X, size_t r)
+{
+	size_t i;
+
+	/* 1: X <-- B_{2r - 1} */
+	blkcpy(X, &Bin[8 * r - 4], 64);
+
+	/* 2: for i = 0 to 2r - 1 do */
+	for (i = 0; i < r; i++) {
+		/* 3: X <-- H(X \xor B_i) */
+		blkxor(X, &Bin[i * 8], 64);
+                salsa20_8_intrinsic((void *) X);
+
+		/* 4: Y_i <-- X */
+		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+		blkcpy(&Bout[i * 4], X, 64);
+
+		/* 3: X <-- H(X \xor B_i) */
+		blkxor(X, &Bin[i * 8 + 4], 64);
+                salsa20_8_intrinsic((void *) X);
+
+		/* 4: Y_i <-- X */
+		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+		blkcpy(&Bout[(r + i) * 4], X, 64);
+	}
+}
+
+/**
+ * integerify(B, r):
+ * Return the result of parsing B_{2r-1} as a little-endian integer.
+ */
+static uint64_t
+integerify(void * B, size_t r)
+{
+	uint8_t * X = (void*)((uintptr_t)(B) + (2 * r - 1) * 64);
+
+	return (le64dec(X));
+}
+
+/**
+ * smix(B, r, N, V, XY):
+ * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length; the
+ * temporary storage V must be 128rN bytes in length; the temporary storage
+ * XY must be 256r bytes in length.  The value N must be a power of 2.
+ */
+static void
+smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY)
+{
+	uint8x16_t * X = XY;
+	uint8x16_t * Y = (void *)((uintptr_t)(XY) + 128 * r);
+        uint8x16_t * Z = (void *)((uintptr_t)(XY) + 256 * r);
+        uint32_t * X32 = (void *)X;
+	uint64_t i, j;
+        size_t k;
+
+	/* 1: X <-- B */
+	blkcpy(X, B, 128 * r);
+
+	/* 2: for i = 0 to N - 1 do */
+	for (i = 0; i < N; i += 2) {
+		/* 3: V_i <-- X */
+		blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r);
+
+		/* 4: X <-- H(X) */
+		blockmix_salsa8(X, Y, Z, r);
+
+		/* 3: V_i <-- X */
+		blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r),
+		    Y, 128 * r);
+
+		/* 4: X <-- H(X) */
+		blockmix_salsa8(Y, X, Z, r);
+	}
+
+	/* 6: for i = 0 to N - 1 do */
+	for (i = 0; i < N; i += 2) {
+		/* 7: j <-- Integerify(X) mod N */
+		j = integerify(X, r) & (N - 1);
+
+		/* 8: X <-- H(X \xor V_j) */
+		blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
+		blockmix_salsa8(X, Y, Z, r);
+
+		/* 7: j <-- Integerify(X) mod N */
+		j = integerify(Y, r) & (N - 1);
+
+		/* 8: X <-- H(X \xor V_j) */
+		blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
+		blockmix_salsa8(Y, X, Z, r);
+	}
+
+	/* 10: B' <-- X */
+	blkcpy(B, X, 128 * r);
+}
+
+/**
+ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
+ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
+ * p, buflen) and write the result into buf.  The parameters r, p, and buflen
+ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
+ * must be a power of 2.
+ *
+ * Return 0 on success; or -1 on error.
+ */
+int
+crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
+    const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p,
+    uint8_t * buf, size_t buflen)
+{
+	void * B0, * V0, * XY0;
+	uint8_t * B;
+	uint32_t * V;
+	uint32_t * XY;
+	uint32_t i;
+
+	/* Sanity-check parameters. */
+#if SIZE_MAX > UINT32_MAX
+	if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
+		errno = EFBIG;
+		goto err0;
+	}
+#endif
+	if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
+		errno = EFBIG;
+		goto err0;
+	}
+	if (((N & (N - 1)) != 0) || (N == 0)) {
+		errno = EINVAL;
+		goto err0;
+	}
+	if ((r > SIZE_MAX / 128 / p) ||
+#if SIZE_MAX / 256 <= UINT32_MAX
+	    (r > SIZE_MAX / 256) ||
+#endif
+	    (N > SIZE_MAX / 128 / r)) {
+		errno = ENOMEM;
+		goto err0;
+	}
+
+	/* Allocate memory. */
+#ifdef HAVE_POSIX_MEMALIGN
+	if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)
+		goto err0;
+	B = (uint8_t *)(B0);
+	if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
+		goto err1;
+	XY = (uint32_t *)(XY0);
+#ifndef MAP_ANON
+	if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0)
+		goto err2;
+	V = (uint32_t *)(V0);
+#endif
+#else
+	if ((B0 = malloc(128 * r * p + 63)) == NULL)
+		goto err0;
+	B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));
+	if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)
+		goto err1;
+	XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));
+#ifndef MAP_ANON
+	if ((V0 = malloc(128 * r * N + 63)) == NULL)
+		goto err2;
+	V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));
+#endif
+#endif
+#ifdef MAP_ANON
+	if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE,
+#ifdef MAP_NOCORE
+	    MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
+#else
+	    MAP_ANON | MAP_PRIVATE,
+#endif
+	    -1, 0)) == MAP_FAILED)
+		goto err2;
+	V = (uint32_t *)(V0);
+#endif
+
+	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
+#ifdef USE_OPENSSL_PBKDF2
+	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B);
+#else
+	PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
+#endif
+
+	/* 2: for i = 0 to p - 1 do */
+	for (i = 0; i < p; i++) {
+		/* 3: B_i <-- MF(B_i, N) */
+		smix(&B[i * 128 * r], r, N, V, XY);
+	}
+
+	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
+#ifdef USE_OPENSSL_PBKDF2
+	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf);
+#else
+	PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
+#endif
+
+	/* Free memory. */
+#ifdef MAP_ANON
+	if (munmap(V0, 128 * r * N))
+		goto err2;
+#else
+	free(V0);
+#endif
+	free(XY0);
+	free(B0);
+
+	/* Success! */
+	return (0);
+
+err2:
+	free(XY0);
+err1:
+	free(B0);
+err0:
+	/* Failure! */
+	return (-1);
+}
diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-ref.c b/crypto/scrypt/lib/crypto/crypto_scrypt-ref.c
new file mode 100644
index 0000000..abe23ea
--- /dev/null
+++ b/crypto/scrypt/lib/crypto/crypto_scrypt-ref.c
@@ -0,0 +1,296 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USE_OPENSSL_PBKDF2
+#include <openssl/evp.h>
+#else
+#include "sha256.h"
+#endif
+#include "sysendian.h"
+
+#include "crypto_scrypt.h"
+
+static void blkcpy(uint8_t *, uint8_t *, size_t);
+static void blkxor(uint8_t *, uint8_t *, size_t);
+static void salsa20_8(uint8_t[64]);
+static void blockmix_salsa8(uint8_t *, uint8_t *, size_t);
+static uint64_t integerify(uint8_t *, size_t);
+static void smix(uint8_t *, size_t, uint64_t, uint8_t *, uint8_t *);
+
+static void
+blkcpy(uint8_t * dest, uint8_t * src, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++)
+		dest[i] = src[i];
+}
+
+static void
+blkxor(uint8_t * dest, uint8_t * src, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++)
+		dest[i] ^= src[i];
+}
+
+/**
+ * salsa20_8(B):
+ * Apply the salsa20/8 core to the provided block.
+ */
+static void
+salsa20_8(uint8_t B[64])
+{
+	uint32_t B32[16];
+	uint32_t x[16];
+	size_t i;
+
+	/* Convert little-endian values in. */
+	for (i = 0; i < 16; i++)
+		B32[i] = le32dec(&B[i * 4]);
+
+	/* Compute x = doubleround^4(B32). */
+	for (i = 0; i < 16; i++)
+		x[i] = B32[i];
+	for (i = 0; i < 8; i += 2) {
+#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
+		/* Operate on columns. */
+		x[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);
+		x[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);
+
+		x[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);
+		x[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);
+
+		x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);
+		x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);
+
+		x[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);
+		x[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);
+
+		/* Operate on rows. */
+		x[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);
+		x[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);
+
+		x[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);
+		x[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);
+
+		x[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);
+		x[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);
+
+		x[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);
+		x[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);
+#undef R
+	}
+
+	/* Compute B32 = B32 + x. */
+	for (i = 0; i < 16; i++)
+		B32[i] += x[i];
+
+	/* Convert little-endian values out. */
+	for (i = 0; i < 16; i++)
+		le32enc(&B[4 * i], B32[i]);
+}
+
+/**
+ * blockmix_salsa8(B, Y, r):
+ * Compute B = BlockMix_{salsa20/8, r}(B).  The input B must be 128r bytes in
+ * length; the temporary space Y must also be the same size.
+ */
+static void
+blockmix_salsa8(uint8_t * B, uint8_t * Y, size_t r)
+{
+	uint8_t X[64];
+	size_t i;
+
+	/* 1: X <-- B_{2r - 1} */
+	blkcpy(X, &B[(2 * r - 1) * 64], 64);
+
+	/* 2: for i = 0 to 2r - 1 do */
+	for (i = 0; i < 2 * r; i++) {
+		/* 3: X <-- H(X \xor B_i) */
+		blkxor(X, &B[i * 64], 64);
+		salsa20_8(X);
+
+		/* 4: Y_i <-- X */
+		blkcpy(&Y[i * 64], X, 64);
+	}
+
+	/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+	for (i = 0; i < r; i++)
+		blkcpy(&B[i * 64], &Y[(i * 2) * 64], 64);
+	for (i = 0; i < r; i++)
+		blkcpy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64);
+}
+
+/**
+ * integerify(B, r):
+ * Return the result of parsing B_{2r-1} as a little-endian integer.
+ */
+static uint64_t
+integerify(uint8_t * B, size_t r)
+{
+	uint8_t * X = &B[(2 * r - 1) * 64];
+
+	return (le64dec(X));
+}
+
+/**
+ * smix(B, r, N, V, XY):
+ * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length; the
+ * temporary storage V must be 128rN bytes in length; the temporary storage
+ * XY must be 256r bytes in length.  The value N must be a power of 2.
+ */
+static void
+smix(uint8_t * B, size_t r, uint64_t N, uint8_t * V, uint8_t * XY)
+{
+	uint8_t * X = XY;
+	uint8_t * Y = &XY[128 * r];
+	uint64_t i;
+	uint64_t j;
+
+	/* 1: X <-- B */
+	blkcpy(X, B, 128 * r);
+
+	/* 2: for i = 0 to N - 1 do */
+	for (i = 0; i < N; i++) {
+		/* 3: V_i <-- X */
+		blkcpy(&V[i * (128 * r)], X, 128 * r);
+
+		/* 4: X <-- H(X) */
+		blockmix_salsa8(X, Y, r);
+	}
+
+	/* 6: for i = 0 to N - 1 do */
+	for (i = 0; i < N; i++) {
+		/* 7: j <-- Integerify(X) mod N */
+		j = integerify(X, r) & (N - 1);
+
+		/* 8: X <-- H(X \xor V_j) */
+		blkxor(X, &V[j * (128 * r)], 128 * r);
+		blockmix_salsa8(X, Y, r);
+	}
+
+	/* 10: B' <-- X */
+	blkcpy(B, X, 128 * r);
+}
+
+/**
+ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
+ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
+ * p, buflen) and write the result into buf.  The parameters r, p, and buflen
+ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
+ * must be a power of 2.
+ *
+ * Return 0 on success; or -1 on error.
+ */
+int
+crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
+    const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p,
+    uint8_t * buf, size_t buflen)
+{
+	uint8_t * B;
+	uint8_t * V;
+	uint8_t * XY;
+	uint32_t i;
+
+	/* Sanity-check parameters. */
+#if SIZE_MAX > UINT32_MAX
+	if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
+		errno = EFBIG;
+		goto err0;
+	}
+#endif
+	if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
+		errno = EFBIG;
+		goto err0;
+	}
+	if (((N & (N - 1)) != 0) || (N == 0)) {
+		errno = EINVAL;
+		goto err0;
+	}
+	if ((r > SIZE_MAX / 128 / p) ||
+#if SIZE_MAX / 256 <= UINT32_MAX
+	    (r > SIZE_MAX / 256) ||
+#endif
+	    (N > SIZE_MAX / 128 / r)) {
+		errno = ENOMEM;
+		goto err0;
+	}
+
+	/* Allocate memory. */
+	if ((B = malloc(128 * r * p)) == NULL)
+		goto err0;
+	if ((XY = malloc(256 * r)) == NULL)
+		goto err1;
+	if ((V = malloc(128 * r * N)) == NULL)
+		goto err2;
+
+	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
+#ifdef USE_OPENSSL_PBKDF2
+	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B);
+#else
+	PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
+#endif
+
+	/* 2: for i = 0 to p - 1 do */
+	for (i = 0; i < p; i++) {
+		/* 3: B_i <-- MF(B_i, N) */
+		smix(&B[i * 128 * r], r, N, V, XY);
+	}
+
+	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
+#ifdef USE_OPENSSL_PBKDF2
+	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf);
+#else
+	PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
+#endif
+
+	/* Free memory. */
+	free(V);
+	free(XY);
+	free(B);
+
+	/* Success! */
+	return (0);
+
+err2:
+	free(XY);
+err1:
+	free(B);
+err0:
+	/* Failure! */
+	return (-1);
+}
diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-sse.c b/crypto/scrypt/lib/crypto/crypto_scrypt-sse.c
new file mode 100644
index 0000000..dd18f29
--- /dev/null
+++ b/crypto/scrypt/lib/crypto/crypto_scrypt-sse.c
@@ -0,0 +1,378 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#include "scrypt_platform.h"
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <emmintrin.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USE_OPENSSL_PBKDF2
+#include <openssl/evp.h>
+#else
+#include "sha256.h"
+#endif
+#include "sysendian.h"
+
+#include "crypto_scrypt.h"
+
+static void blkcpy(void *, void *, size_t);
+static void blkxor(void *, void *, size_t);
+static void salsa20_8(__m128i *);
+static void blockmix_salsa8(__m128i *, __m128i *, __m128i *, size_t);
+static uint64_t integerify(void *, size_t);
+static void smix(uint8_t *, size_t, uint64_t, void *, void *);
+
+static void
+blkcpy(void * dest, void * src, size_t len)
+{
+	__m128i * D = dest;
+	__m128i * S = src;
+	size_t L = len / 16;
+	size_t i;
+
+	for (i = 0; i < L; i++)
+		D[i] = S[i];
+}
+
+static void
+blkxor(void * dest, void * src, size_t len)
+{
+	__m128i * D = dest;
+	__m128i * S = src;
+	size_t L = len / 16;
+	size_t i;
+
+	for (i = 0; i < L; i++)
+		D[i] = _mm_xor_si128(D[i], S[i]);
+}
+
+/**
+ * salsa20_8(B):
+ * Apply the salsa20/8 core to the provided block.
+ */
+static void
+salsa20_8(__m128i B[4])
+{
+	__m128i X0, X1, X2, X3;
+	__m128i T;
+	size_t i;
+
+	X0 = B[0];
+	X1 = B[1];
+	X2 = B[2];
+	X3 = B[3];
+
+	for (i = 0; i < 8; i += 2) {
+		/* Operate on "columns". */
+		T = _mm_add_epi32(X0, X3);
+		X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7));
+		X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25));
+		T = _mm_add_epi32(X1, X0);
+		X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
+		X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
+		T = _mm_add_epi32(X2, X1);
+		X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13));
+		X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19));
+		T = _mm_add_epi32(X3, X2);
+		X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
+		X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));
+
+		/* Rearrange data. */
+		X1 = _mm_shuffle_epi32(X1, 0x93);
+		X2 = _mm_shuffle_epi32(X2, 0x4E);
+		X3 = _mm_shuffle_epi32(X3, 0x39);
+
+		/* Operate on "rows". */
+		T = _mm_add_epi32(X0, X1);
+		X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7));
+		X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25));
+		T = _mm_add_epi32(X3, X0);
+		X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
+		X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
+		T = _mm_add_epi32(X2, X3);
+		X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13));
+		X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19));
+		T = _mm_add_epi32(X1, X2);
+		X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
+		X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));
+
+		/* Rearrange data. */
+		X1 = _mm_shuffle_epi32(X1, 0x39);
+		X2 = _mm_shuffle_epi32(X2, 0x4E);
+		X3 = _mm_shuffle_epi32(X3, 0x93);
+	}
+
+	B[0] = _mm_add_epi32(B[0], X0);
+	B[1] = _mm_add_epi32(B[1], X1);
+	B[2] = _mm_add_epi32(B[2], X2);
+	B[3] = _mm_add_epi32(B[3], X3);
+}
+
+/**
+ * blockmix_salsa8(Bin, Bout, X, r):
+ * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r
+ * bytes in length; the output Bout must also be the same size.  The
+ * temporary space X must be 64 bytes.
+ */
+static void
+blockmix_salsa8(__m128i * Bin, __m128i * Bout, __m128i * X, size_t r)
+{
+	size_t i;
+
+	/* 1: X <-- B_{2r - 1} */
+	blkcpy(X, &Bin[8 * r - 4], 64);
+
+	/* 2: for i = 0 to 2r - 1 do */
+	for (i = 0; i < r; i++) {
+		/* 3: X <-- H(X \xor B_i) */
+		blkxor(X, &Bin[i * 8], 64);
+		salsa20_8(X);
+
+		/* 4: Y_i <-- X */
+		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+		blkcpy(&Bout[i * 4], X, 64);
+
+		/* 3: X <-- H(X \xor B_i) */
+		blkxor(X, &Bin[i * 8 + 4], 64);
+		salsa20_8(X);
+
+		/* 4: Y_i <-- X */
+		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
+		blkcpy(&Bout[(r + i) * 4], X, 64);
+	}
+}
+
+/**
+ * integerify(B, r):
+ * Return the result of parsing B_{2r-1} as a little-endian integer.
+ */
+static uint64_t
+integerify(void * B, size_t r)
+{
+	uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64);
+
+	return (((uint64_t)(X[13]) << 32) + X[0]);
+}
+
+/**
+ * smix(B, r, N, V, XY):
+ * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;
+ * the temporary storage V must be 128rN bytes in length; the temporary
+ * storage XY must be 256r + 64 bytes in length.  The value N must be a
+ * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a
+ * multiple of 64 bytes.
+ */
+static void
+smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY)
+{
+	__m128i * X = XY;
+	__m128i * Y = (void *)((uintptr_t)(XY) + 128 * r);
+	__m128i * Z = (void *)((uintptr_t)(XY) + 256 * r);
+	uint32_t * X32 = (void *)X;
+	uint64_t i, j;
+	size_t k;
+
+	/* 1: X <-- B */
+	for (k = 0; k < 2 * r; k++) {
+		for (i = 0; i < 16; i++) {
+			X32[k * 16 + i] =
+			    le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]);
+		}
+	}
+
+	/* 2: for i = 0 to N - 1 do */
+	for (i = 0; i < N; i += 2) {
+		/* 3: V_i <-- X */
+		blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r);
+
+		/* 4: X <-- H(X) */
+		blockmix_salsa8(X, Y, Z, r);
+
+		/* 3: V_i <-- X */
+		blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r),
+		    Y, 128 * r);
+
+		/* 4: X <-- H(X) */
+		blockmix_salsa8(Y, X, Z, r);
+	}
+
+	/* 6: for i = 0 to N - 1 do */
+	for (i = 0; i < N; i += 2) {
+		/* 7: j <-- Integerify(X) mod N */
+		j = integerify(X, r) & (N - 1);
+
+		/* 8: X <-- H(X \xor V_j) */
+		blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
+		blockmix_salsa8(X, Y, Z, r);
+
+		/* 7: j <-- Integerify(X) mod N */
+		j = integerify(Y, r) & (N - 1);
+
+		/* 8: X <-- H(X \xor V_j) */
+		blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
+		blockmix_salsa8(Y, X, Z, r);
+	}
+
+	/* 10: B' <-- X */
+	for (k = 0; k < 2 * r; k++) {
+		for (i = 0; i < 16; i++) {
+			le32enc(&B[(k * 16 + (i * 5 % 16)) * 4],
+			    X32[k * 16 + i]);
+		}
+	}
+}
+
+/**
+ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
+ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
+ * p, buflen) and write the result into buf.  The parameters r, p, and buflen
+ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
+ * must be a power of 2 greater than 1.
+ *
+ * Return 0 on success; or -1 on error.
+ */
+int
+crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
+    const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p,
+    uint8_t * buf, size_t buflen)
+{
+	void * B0, * V0, * XY0;
+	uint8_t * B;
+	uint32_t * V;
+	uint32_t * XY;
+	uint32_t i;
+
+	/* Sanity-check parameters. */
+#if SIZE_MAX > UINT32_MAX
+	if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
+		errno = EFBIG;
+		goto err0;
+	}
+#endif
+	if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
+		errno = EFBIG;
+		goto err0;
+	}
+	if (((N & (N - 1)) != 0) || (N == 0)) {
+		errno = EINVAL;
+		goto err0;
+	}
+	if ((r > SIZE_MAX / 128 / p) ||
+#if SIZE_MAX / 256 <= UINT32_MAX
+	    (r > (SIZE_MAX - 64) / 256) ||
+#endif
+	    (N > SIZE_MAX / 128 / r)) {
+		errno = ENOMEM;
+		goto err0;
+	}
+
+	/* Allocate memory. */
+#ifdef HAVE_POSIX_MEMALIGN
+	if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)
+		goto err0;
+	B = (uint8_t *)(B0);
+	if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
+		goto err1;
+	XY = (uint32_t *)(XY0);
+#ifndef MAP_ANON
+	if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0)
+		goto err2;
+	V = (uint32_t *)(V0);
+#endif
+#else
+	if ((B0 = malloc(128 * r * p + 63)) == NULL)
+		goto err0;
+	B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));
+	if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)
+		goto err1;
+	XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));
+#ifndef MAP_ANON
+	if ((V0 = malloc(128 * r * N + 63)) == NULL)
+		goto err2;
+	V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));
+#endif
+#endif
+#ifdef MAP_ANON
+	if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE,
+#ifdef MAP_NOCORE
+	    MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
+#else
+	    MAP_ANON | MAP_PRIVATE,
+#endif
+	    -1, 0)) == MAP_FAILED)
+		goto err2;
+	V = (uint32_t *)(V0);
+#endif
+
+	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
+#ifdef USE_OPENSSL_PBKDF2
+	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B);
+#else
+	PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
+#endif
+
+	/* 2: for i = 0 to p - 1 do */
+	for (i = 0; i < p; i++) {
+		/* 3: B_i <-- MF(B_i, N) */
+		smix(&B[i * 128 * r], r, N, V, XY);
+	}
+
+	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
+#ifdef USE_OPENSSL_PBKDF2
+	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf);
+#else
+	PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
+#endif
+
+	/* Free memory. */
+#ifdef MAP_ANON
+	if (munmap(V0, 128 * r * N))
+		goto err2;
+#else
+	free(V0);
+#endif
+	free(XY0);
+	free(B0);
+
+	/* Success! */
+	return (0);
+
+err2:
+	free(XY0);
+err1:
+	free(B0);
+err0:
+	/* Failure! */
+	return (-1);
+}
diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt.h b/crypto/scrypt/lib/crypto/crypto_scrypt.h
new file mode 100644
index 0000000..f72e1f4
--- /dev/null
+++ b/crypto/scrypt/lib/crypto/crypto_scrypt.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright 2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _CRYPTO_SCRYPT_H_
+#define _CRYPTO_SCRYPT_H_
+
+#include <stdint.h>
+
+/**
+ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
+ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
+ * p, buflen) and write the result into buf.  The parameters r, p, and buflen
+ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
+ * must be a power of 2 greater than 1.
+ *
+ * Return 0 on success; or -1 on error.
+ */
+int crypto_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t,
+    uint32_t, uint32_t, uint8_t *, size_t);
+
+#endif /* !_CRYPTO_SCRYPT_H_ */
diff --git a/crypto/scrypt/lib/util/sysendian.h b/crypto/scrypt/lib/util/sysendian.h
new file mode 100644
index 0000000..62ef31a
--- /dev/null
+++ b/crypto/scrypt/lib/util/sysendian.h
@@ -0,0 +1,140 @@
+/*-
+ * Copyright 2007-2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+#ifndef _SYSENDIAN_H_
+#define _SYSENDIAN_H_
+
+#include "scrypt_platform.h"
+
+/* If we don't have be64enc, the <sys/endian.h> we have isn't usable. */
+#if !HAVE_DECL_BE64ENC
+#undef HAVE_SYS_ENDIAN_H
+#endif
+
+#ifdef HAVE_SYS_ENDIAN_H
+
+#include <sys/endian.h>
+
+#else
+
+#include <stdint.h>
+
+static inline uint32_t
+be32dec(const void *pp)
+{
+	const uint8_t *p = (uint8_t const *)pp;
+
+	return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
+	    ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
+}
+
+static inline void
+be32enc(void *pp, uint32_t x)
+{
+	uint8_t * p = (uint8_t *)pp;
+
+	p[3] = x & 0xff;
+	p[2] = (x >> 8) & 0xff;
+	p[1] = (x >> 16) & 0xff;
+	p[0] = (x >> 24) & 0xff;
+}
+
+static inline uint64_t
+be64dec(const void *pp)
+{
+	const uint8_t *p = (uint8_t const *)pp;
+
+	return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) +
+	    ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) +
+	    ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) +
+	    ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56));
+}
+
+static inline void
+be64enc(void *pp, uint64_t x)
+{
+	uint8_t * p = (uint8_t *)pp;
+
+	p[7] = x & 0xff;
+	p[6] = (x >> 8) & 0xff;
+	p[5] = (x >> 16) & 0xff;
+	p[4] = (x >> 24) & 0xff;
+	p[3] = (x >> 32) & 0xff;
+	p[2] = (x >> 40) & 0xff;
+	p[1] = (x >> 48) & 0xff;
+	p[0] = (x >> 56) & 0xff;
+}
+
+static inline uint32_t
+le32dec(const void *pp)
+{
+	const uint8_t *p = (uint8_t const *)pp;
+
+	return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +
+	    ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));
+}
+
+static inline void
+le32enc(void *pp, uint32_t x)
+{
+	uint8_t * p = (uint8_t *)pp;
+
+	p[0] = x & 0xff;
+	p[1] = (x >> 8) & 0xff;
+	p[2] = (x >> 16) & 0xff;
+	p[3] = (x >> 24) & 0xff;
+}
+
+static inline uint64_t
+le64dec(const void *pp)
+{
+	const uint8_t *p = (uint8_t const *)pp;
+
+	return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) +
+	    ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) +
+	    ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) +
+	    ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56));
+}
+
+static inline void
+le64enc(void *pp, uint64_t x)
+{
+	uint8_t * p = (uint8_t *)pp;
+
+	p[0] = x & 0xff;
+	p[1] = (x >> 8) & 0xff;
+	p[2] = (x >> 16) & 0xff;
+	p[3] = (x >> 24) & 0xff;
+	p[4] = (x >> 32) & 0xff;
+	p[5] = (x >> 40) & 0xff;
+	p[6] = (x >> 48) & 0xff;
+	p[7] = (x >> 56) & 0xff;
+}
+#endif /* !HAVE_SYS_ENDIAN_H */
+
+#endif /* !_SYSENDIAN_H_ */
diff --git a/crypto/scrypt/patches/README b/crypto/scrypt/patches/README
new file mode 100644
index 0000000..353ddbb
--- /dev/null
+++ b/crypto/scrypt/patches/README
@@ -0,0 +1,11 @@
+bionic.patch:
+
+Allows scrypt to compile against bionic.
+
+use_openssl_pbkdf2.patch:
+
+Uses the PBKDF2 function from OpenSSL (it uses accelerated SHA256)
+
+arm-neon.patch:
+
+Adds NEON acceleration for the Salsa20/8 mixing function.
diff --git a/crypto/scrypt/patches/arm-neon.patch b/crypto/scrypt/patches/arm-neon.patch
new file mode 100644
index 0000000..7197f99
--- /dev/null
+++ b/crypto/scrypt/patches/arm-neon.patch
@@ -0,0 +1,437 @@
+diff --git a/lib/crypto/crypto_scrypt-neon-salsa208.h b/lib/crypto/crypto_scrypt-neon-salsa208.h
+new file mode 100644
+index 0000000..a3b1019
+--- /dev/null
++++ b/lib/crypto/crypto_scrypt-neon-salsa208.h
+@@ -0,0 +1,120 @@
++/*
++ * version 20110505
++ * D. J. Bernstein
++ * Public domain.
++ *
++ * Based on crypto_core/salsa208/armneon/core.c from SUPERCOP 20130419
++ */
++
++#define ROUNDS 8
++static void
++salsa20_8_intrinsic(void * input)
++{
++  int i;
++
++  const uint32x4_t abab = {-1,0,-1,0};
++
++  /*
++   * This is modified since we only have one argument. Usually you'd rearrange
++   * the constant, key, and input bytes, but we just have one linear array to
++   * rearrange which is a bit easier.
++   */
++
++  /*
++   * Change the input to be diagonals as if it's a 4x4 matrix of 32-bit values.
++   */
++  uint32x4_t x0x5x10x15;
++  uint32x4_t x12x1x6x11;
++  uint32x4_t x8x13x2x7;
++  uint32x4_t x4x9x14x3;
++
++  uint32x4_t x0x1x10x11;
++  uint32x4_t x12x13x6x7;
++  uint32x4_t x8x9x2x3;
++  uint32x4_t x4x5x14x15;
++
++  uint32x4_t x0x1x2x3;
++  uint32x4_t x4x5x6x7;
++  uint32x4_t x8x9x10x11;
++  uint32x4_t x12x13x14x15;
++
++  x0x1x2x3 = vld1q_u8((uint8_t *) input);
++  x4x5x6x7 = vld1q_u8(16 + (uint8_t *) input);
++  x8x9x10x11 = vld1q_u8(32 + (uint8_t *) input);
++  x12x13x14x15 = vld1q_u8(48 + (uint8_t *) input);
++
++  x0x1x10x11 = vcombine_u32(vget_low_u32(x0x1x2x3), vget_high_u32(x8x9x10x11));
++  x4x5x14x15 = vcombine_u32(vget_low_u32(x4x5x6x7), vget_high_u32(x12x13x14x15));
++  x8x9x2x3 = vcombine_u32(vget_low_u32(x8x9x10x11), vget_high_u32(x0x1x2x3));
++  x12x13x6x7 = vcombine_u32(vget_low_u32(x12x13x14x15), vget_high_u32(x4x5x6x7));
++
++  x0x5x10x15 = vbslq_u32(abab,x0x1x10x11,x4x5x14x15);
++  x8x13x2x7 = vbslq_u32(abab,x8x9x2x3,x12x13x6x7);
++  x4x9x14x3 = vbslq_u32(abab,x4x5x14x15,x8x9x2x3);
++  x12x1x6x11 = vbslq_u32(abab,x12x13x6x7,x0x1x10x11);
++
++  uint32x4_t start0 = x0x5x10x15;
++  uint32x4_t start1 = x12x1x6x11;
++  uint32x4_t start3 = x4x9x14x3;
++  uint32x4_t start2 = x8x13x2x7;
++
++  /* From here on this should be the same as the SUPERCOP version. */
++
++  uint32x4_t diag0 = start0;
++  uint32x4_t diag1 = start1;
++  uint32x4_t diag2 = start2;
++  uint32x4_t diag3 = start3;
++
++  uint32x4_t a0;
++  uint32x4_t a1;
++  uint32x4_t a2;
++  uint32x4_t a3;
++
++  for (i = ROUNDS;i > 0;i -= 2) {
++    a0 = diag1 + diag0;
++    diag3 ^= vsriq_n_u32(vshlq_n_u32(a0,7),a0,25);
++    a1 = diag0 + diag3;
++    diag2 ^= vsriq_n_u32(vshlq_n_u32(a1,9),a1,23);
++    a2 = diag3 + diag2;
++    diag1 ^= vsriq_n_u32(vshlq_n_u32(a2,13),a2,19);
++    a3 = diag2 + diag1;
++    diag0 ^= vsriq_n_u32(vshlq_n_u32(a3,18),a3,14);
++
++    diag3 = vextq_u32(diag3,diag3,3);
++    diag2 = vextq_u32(diag2,diag2,2);
++    diag1 = vextq_u32(diag1,diag1,1);
++
++    a0 = diag3 + diag0;
++    diag1 ^= vsriq_n_u32(vshlq_n_u32(a0,7),a0,25);
++    a1 = diag0 + diag1;
++    diag2 ^= vsriq_n_u32(vshlq_n_u32(a1,9),a1,23);
++    a2 = diag1 + diag2;
++    diag3 ^= vsriq_n_u32(vshlq_n_u32(a2,13),a2,19);
++    a3 = diag2 + diag3;
++    diag0 ^= vsriq_n_u32(vshlq_n_u32(a3,18),a3,14);
++
++    diag1 = vextq_u32(diag1,diag1,3);
++    diag2 = vextq_u32(diag2,diag2,2);
++    diag3 = vextq_u32(diag3,diag3,1);
++  }
++
++  x0x5x10x15 = diag0 + start0;
++  x12x1x6x11 = diag1 + start1;
++  x8x13x2x7 = diag2 + start2;
++  x4x9x14x3 = diag3 + start3;
++
++  x0x1x10x11 = vbslq_u32(abab,x0x5x10x15,x12x1x6x11);
++  x12x13x6x7 = vbslq_u32(abab,x12x1x6x11,x8x13x2x7);
++  x8x9x2x3 = vbslq_u32(abab,x8x13x2x7,x4x9x14x3);
++  x4x5x14x15 = vbslq_u32(abab,x4x9x14x3,x0x5x10x15);
++
++  x0x1x2x3 = vcombine_u32(vget_low_u32(x0x1x10x11),vget_high_u32(x8x9x2x3));
++  x4x5x6x7 = vcombine_u32(vget_low_u32(x4x5x14x15),vget_high_u32(x12x13x6x7));
++  x8x9x10x11 = vcombine_u32(vget_low_u32(x8x9x2x3),vget_high_u32(x0x1x10x11));
++  x12x13x14x15 = vcombine_u32(vget_low_u32(x12x13x6x7),vget_high_u32(x4x5x14x15));
++
++  vst1q_u8((uint8_t *) input,(uint8x16_t) x0x1x2x3);
++  vst1q_u8(16 + (uint8_t *) input,(uint8x16_t) x4x5x6x7);
++  vst1q_u8(32 + (uint8_t *) input,(uint8x16_t) x8x9x10x11);
++  vst1q_u8(48 + (uint8_t *) input,(uint8x16_t) x12x13x14x15);
++}
+diff --git a/lib/crypto/crypto_scrypt-neon.c b/lib/crypto/crypto_scrypt-neon.c
+new file mode 100644
+index 0000000..a3bf052
+--- /dev/null
++++ b/lib/crypto/crypto_scrypt-neon.c
+@@ -0,0 +1,305 @@
++/*-
++ * Copyright 2009 Colin Percival
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ * This file was originally written by Colin Percival as part of the Tarsnap
++ * online backup system.
++ */
++#include "scrypt_platform.h"
++
++#include <machine/cpu-features.h>
++#include <arm_neon.h>
++
++#include <errno.h>
++#include <stdint.h>
++#include <limits.h>
++#include <stdlib.h>
++#include <string.h>
++
++#ifdef USE_OPENSSL_PBKDF2
++#include <openssl/evp.h>
++#else
++#include "sha256.h"
++#endif
++#include "sysendian.h"
++
++#include "crypto_scrypt.h"
++
++#include "crypto_scrypt-neon-salsa208.h"
++
++static void blkcpy(void *, void *, size_t);
++static void blkxor(void *, void *, size_t);
++void crypto_core_salsa208_armneon2(void *);
++static void blockmix_salsa8(uint8x16_t *, uint8x16_t *, uint8x16_t *, size_t);
++static uint64_t integerify(void *, size_t);
++static void smix(uint8_t *, size_t, uint64_t, void *, void *);
++
++static void
++blkcpy(void * dest, void * src, size_t len)
++{
++	uint8x16_t * D = dest;
++	uint8x16_t * S = src;
++	size_t L = len / 16;
++	size_t i;
++
++	for (i = 0; i < L; i++)
++		D[i] = S[i];
++}
++
++static void
++blkxor(void * dest, void * src, size_t len)
++{
++	uint8x16_t * D = dest;
++	uint8x16_t * S = src;
++	size_t L = len / 16;
++	size_t i;
++
++	for (i = 0; i < L; i++)
++		D[i] = veorq_u8(D[i], S[i]);
++}
++
++/**
++ * blockmix_salsa8(B, Y, r):
++ * Compute B = BlockMix_{salsa20/8, r}(B).  The input B must be 128r bytes in
++ * length; the temporary space Y must also be the same size.
++ */
++static void
++blockmix_salsa8(uint8x16_t * Bin, uint8x16_t * Bout, uint8x16_t * X, size_t r)
++{
++	size_t i;
++
++	/* 1: X <-- B_{2r - 1} */
++	blkcpy(X, &Bin[8 * r - 4], 64);
++
++	/* 2: for i = 0 to 2r - 1 do */
++	for (i = 0; i < r; i++) {
++		/* 3: X <-- H(X \xor B_i) */
++		blkxor(X, &Bin[i * 8], 64);
++                salsa20_8_intrinsic((void *) X);
++
++		/* 4: Y_i <-- X */
++		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
++		blkcpy(&Bout[i * 4], X, 64);
++
++		/* 3: X <-- H(X \xor B_i) */
++		blkxor(X, &Bin[i * 8 + 4], 64);
++                salsa20_8_intrinsic((void *) X);
++
++		/* 4: Y_i <-- X */
++		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
++		blkcpy(&Bout[(r + i) * 4], X, 64);
++	}
++}
++
++/**
++ * integerify(B, r):
++ * Return the result of parsing B_{2r-1} as a little-endian integer.
++ */
++static uint64_t
++integerify(void * B, size_t r)
++{
++	uint8_t * X = (void*)((uintptr_t)(B) + (2 * r - 1) * 64);
++
++	return (le64dec(X));
++}
++
++/**
++ * smix(B, r, N, V, XY):
++ * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length; the
++ * temporary storage V must be 128rN bytes in length; the temporary storage
++ * XY must be 256r bytes in length.  The value N must be a power of 2.
++ */
++static void
++smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY)
++{
++	uint8x16_t * X = XY;
++	uint8x16_t * Y = (void *)((uintptr_t)(XY) + 128 * r);
++        uint8x16_t * Z = (void *)((uintptr_t)(XY) + 256 * r);
++        uint32_t * X32 = (void *)X;
++	uint64_t i, j;
++        size_t k;
++
++	/* 1: X <-- B */
++	blkcpy(X, B, 128 * r);
++
++	/* 2: for i = 0 to N - 1 do */
++	for (i = 0; i < N; i += 2) {
++		/* 3: V_i <-- X */
++		blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r);
++
++		/* 4: X <-- H(X) */
++		blockmix_salsa8(X, Y, Z, r);
++
++		/* 3: V_i <-- X */
++		blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r),
++		    Y, 128 * r);
++
++		/* 4: X <-- H(X) */
++		blockmix_salsa8(Y, X, Z, r);
++	}
++
++	/* 6: for i = 0 to N - 1 do */
++	for (i = 0; i < N; i += 2) {
++		/* 7: j <-- Integerify(X) mod N */
++		j = integerify(X, r) & (N - 1);
++
++		/* 8: X <-- H(X \xor V_j) */
++		blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
++		blockmix_salsa8(X, Y, Z, r);
++
++		/* 7: j <-- Integerify(X) mod N */
++		j = integerify(Y, r) & (N - 1);
++
++		/* 8: X <-- H(X \xor V_j) */
++		blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
++		blockmix_salsa8(Y, X, Z, r);
++	}
++
++	/* 10: B' <-- X */
++	blkcpy(B, X, 128 * r);
++}
++
++/**
++ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
++ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
++ * p, buflen) and write the result into buf.  The parameters r, p, and buflen
++ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
++ * must be a power of 2.
++ *
++ * Return 0 on success; or -1 on error.
++ */
++int
++crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
++    const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p,
++    uint8_t * buf, size_t buflen)
++{
++	void * B0, * V0, * XY0;
++	uint8_t * B;
++	uint32_t * V;
++	uint32_t * XY;
++	uint32_t i;
++
++	/* Sanity-check parameters. */
++#if SIZE_MAX > UINT32_MAX
++	if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
++		errno = EFBIG;
++		goto err0;
++	}
++#endif
++	if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
++		errno = EFBIG;
++		goto err0;
++	}
++	if (((N & (N - 1)) != 0) || (N == 0)) {
++		errno = EINVAL;
++		goto err0;
++	}
++	if ((r > SIZE_MAX / 128 / p) ||
++#if SIZE_MAX / 256 <= UINT32_MAX
++	    (r > SIZE_MAX / 256) ||
++#endif
++	    (N > SIZE_MAX / 128 / r)) {
++		errno = ENOMEM;
++		goto err0;
++	}
++
++	/* Allocate memory. */
++#ifdef HAVE_POSIX_MEMALIGN
++	if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)
++		goto err0;
++	B = (uint8_t *)(B0);
++	if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
++		goto err1;
++	XY = (uint32_t *)(XY0);
++#ifndef MAP_ANON
++	if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0)
++		goto err2;
++	V = (uint32_t *)(V0);
++#endif
++#else
++	if ((B0 = malloc(128 * r * p + 63)) == NULL)
++		goto err0;
++	B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));
++	if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)
++		goto err1;
++	XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));
++#ifndef MAP_ANON
++	if ((V0 = malloc(128 * r * N + 63)) == NULL)
++		goto err2;
++	V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));
++#endif
++#endif
++#ifdef MAP_ANON
++	if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE,
++#ifdef MAP_NOCORE
++	    MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
++#else
++	    MAP_ANON | MAP_PRIVATE,
++#endif
++	    -1, 0)) == MAP_FAILED)
++		goto err2;
++	V = (uint32_t *)(V0);
++#endif
++
++	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
++#ifdef USE_OPENSSL_PBKDF2
++	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B);
++#else
++	PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
++#endif
++
++	/* 2: for i = 0 to p - 1 do */
++	for (i = 0; i < p; i++) {
++		/* 3: B_i <-- MF(B_i, N) */
++		smix(&B[i * 128 * r], r, N, V, XY);
++	}
++
++	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
++#ifdef USE_OPENSSL_PBKDF2
++	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf);
++#else
++	PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
++#endif
++
++	/* Free memory. */
++#ifdef MAP_ANON
++	if (munmap(V0, 128 * r * N))
++		goto err2;
++#else
++	free(V0);
++#endif
++	free(XY0);
++	free(B0);
++
++	/* Success! */
++	return (0);
++
++err2:
++	free(XY0);
++err1:
++	free(B0);
++err0:
++	/* Failure! */
++	return (-1);
++}
diff --git a/crypto/scrypt/patches/use_openssl_pbkdf2.patch b/crypto/scrypt/patches/use_openssl_pbkdf2.patch
new file mode 100644
index 0000000..0a1328c
--- /dev/null
+++ b/crypto/scrypt/patches/use_openssl_pbkdf2.patch
@@ -0,0 +1,80 @@
+diff --git a/lib/crypto/crypto_scrypt-ref.c b/lib/crypto/crypto_scrypt-ref.c
+index 79a6f8f..60ef2aa 100644
+--- a/lib/crypto/crypto_scrypt-ref.c
++++ b/lib/crypto/crypto_scrypt-ref.c
+@@ -34,7 +34,11 @@
+ #include <stdlib.h>
+ #include <string.h>
+ 
++#ifdef USE_OPENSSL_PBKDF2
++#include <openssl/evp.h>
++#else
+ #include "sha256.h"
++#endif
+ #include "sysendian.h"
+ 
+ #include "crypto_scrypt.h"
+@@ -256,7 +260,11 @@ crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
+ 		goto err2;
+ 
+ 	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
++#ifdef USE_OPENSSL_PBKDF2
++	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B);
++#else
+ 	PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
++#endif
+ 
+ 	/* 2: for i = 0 to p - 1 do */
+ 	for (i = 0; i < p; i++) {
+@@ -265,7 +273,11 @@ crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
+ 	}
+ 
+ 	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
++#ifdef USE_OPENSSL_PBKDF2
++	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf);
++#else
+ 	PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
++#endif
+ 
+ 	/* Free memory. */
+ 	free(V);
+diff --git a/lib/crypto/crypto_scrypt-sse.c b/lib/crypto/crypto_scrypt-sse.c
+index 875175e..dd18f29 100644
+--- a/lib/crypto/crypto_scrypt-sse.c
++++ b/lib/crypto/crypto_scrypt-sse.c
+@@ -37,7 +37,11 @@
+ #include <stdlib.h>
+ #include <string.h>
+ 
++#ifdef USE_OPENSSL_PBKDF2
++#include <openssl/evp.h>
++#else
+ #include "sha256.h"
++#endif
+ #include "sysendian.h"
+ 
+ #include "crypto_scrypt.h"
+@@ -332,7 +336,11 @@ crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
+ #endif
+ 
+ 	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
++#ifdef USE_OPENSSL_PBKDF2
++	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B);
++#else
+ 	PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);
++#endif
+ 
+ 	/* 2: for i = 0 to p - 1 do */
+ 	for (i = 0; i < p; i++) {
+@@ -341,7 +349,11 @@ crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
+ 	}
+ 
+ 	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
++#ifdef USE_OPENSSL_PBKDF2
++	PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf);
++#else
+ 	PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);
++#endif
+ 
+ 	/* Free memory. */
+ #ifdef MAP_ANON
diff --git a/crypto/scrypt/scrypt.config b/crypto/scrypt/scrypt.config
new file mode 100644
index 0000000..3ccb4d0
--- /dev/null
+++ b/crypto/scrypt/scrypt.config
@@ -0,0 +1,94 @@
+CONFIGURE_ARGS="\
+ \
+"
+
+# unneeded directories
+UNNEEDED_SOURCES="\
+lib/scryptenc \
+"
+
+# unneeded files
+UNNEEDED_SOURCES+="\
+config.h.in \
+configure \
+FORMAT \
+main.c \
+Makefile.in \
+scrypt.1 \
+lib/crypto/crypto_aesctr.c \
+lib/crypto/crypto_aesctr.h \
+lib/crypto/crypto_scrypt-nosse.c \
+lib/crypto/sha256.c \
+lib/crypto/sha256.h \
+lib/util/memlimit.c \
+lib/util/memlimit.h \
+lib/util/readpass.c \
+lib/util/readpass.h \
+lib/util/warn.c \
+lib/util/warn.h \
+"
+
+NEEDED_SOURCES="\
+config.h \
+lib \
+scrypt_platform.h \
+"
+
+SCRYPT_INCLUDES="\
+lib/crypto \
+lib/util \
+"
+
+SCRYPT_SOURCES="\
+lib/crypto/crypto_scrypt-ref.c \
+"
+
+SCRYPT_SOURCES_arm="\
+"
+
+SCRYPT_SOURCES_EXCLUDES_arm="\
+"
+
+SCRYPT_SOURCES_arm_neon="\
+lib/crypto/crypto_scrypt-neon.c \
+"
+
+SCRYPT_SOURCES_EXCLUDES_arm_neon="\
+lib/crypto/crypto_scrypt-ref.c \
+"
+
+SCRYPT_SOURCES_mips="\
+"
+
+SCRYPT_SOURCES_EXCLUDES_mips="\
+"
+
+SCRYPT_SOURCES_x86="\
+lib/crypto/crypto_scrypt-sse.c \
+"
+
+SCRYPT_SOURCES_EXCLUDES_x86="\
+lib/crypto/crypto_scrypt-ref.c \
+"
+
+SCRYPT_SOURCES_x86_64="\
+lib/crypto/crypto_scrypt-sse.c \
+"
+
+SCRYPT_SOURCES_EXCLUDES_x86_64="\
+lib/crypto/crypto_scrypt-ref.c \
+"
+
+SCRYPT_PATCHES="\
+use_openssl_pbkdf2.patch \
+arm-neon.patch \
+"
+
+SCRYPT_PATCHES_use_openssl_pbkdf2_SOURCES="\
+lib/crypto/crypto_scrypt-ref.c \
+"
+
+SCRYPT_PATCHES_bionic_SOURCES="\
+lib/crypto/crypto_scrypt-neon.c \
+lib/crypto/crypto_scrypt-neon-salsa208.h \
+"
diff --git a/crypto/scrypt/scrypt.version b/crypto/scrypt/scrypt.version
new file mode 100644
index 0000000..155e260
--- /dev/null
+++ b/crypto/scrypt/scrypt.version
@@ -0,0 +1 @@
+SCRYPT_VERSION=1.1.6
diff --git a/crypto/scrypt/scrypt_platform.h b/crypto/scrypt/scrypt_platform.h
new file mode 100644
index 0000000..5cec236
--- /dev/null
+++ b/crypto/scrypt/scrypt_platform.h
@@ -0,0 +1,12 @@
+#ifndef _SCRYPT_PLATFORM_H_
+#define	_SCRYPT_PLATFORM_H_
+
+#if defined(CONFIG_H_FILE)
+#include CONFIG_H_FILE
+#elif defined(HAVE_CONFIG_H)
+#include "config.h"
+#else
+#error Need either CONFIG_H_FILE or HAVE_CONFIG_H defined.
+#endif
+
+#endif /* !_SCRYPT_PLATFORM_H_ */
diff --git a/crypto/scrypt/tests/Android.mk b/crypto/scrypt/tests/Android.mk
new file mode 100644
index 0000000..b25e1c4
--- /dev/null
+++ b/crypto/scrypt/tests/Android.mk
@@ -0,0 +1,25 @@
+# Build the scrypt unit tests
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_SRC_FILES:= \
+    scrypt_test.cpp
+
+LOCAL_C_INCLUDES := \
+    external/gtest/include \
+    external/scrypt/lib/crypto
+
+LOCAL_SHARED_LIBRARIES := \
+    libcrypto
+
+LOCAL_STATIC_LIBRARIES := \
+    libscrypt_static \
+    libgtest \
+    libgtest_main
+
+LOCAL_MODULE := scrypt_test
+
+include $(BUILD_NATIVE_TEST)
diff --git a/crypto/scrypt/tests/scrypt_test.cpp b/crypto/scrypt/tests/scrypt_test.cpp
new file mode 100644
index 0000000..28334d6
--- /dev/null
+++ b/crypto/scrypt/tests/scrypt_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "scrypt_test"
+#include <utils/Log.h>
+#include <utils/UniquePtr.h>
+
+#include <gtest/gtest.h>
+
+#include <fstream>
+#include <iostream>
+
+extern "C" {
+#include <crypto_scrypt.h>
+}
+
+namespace android {
+
+typedef struct scrypt_test_setting_t {
+        const char *pw, *salt;
+        uint32_t Nfactor, rfactor, pfactor;
+} scrypt_test_setting;
+
+static const scrypt_test_setting post_settings[] = {
+        {"", "", 16, 1, 1},
+        {"password", "NaCl", 1024, 8, 16},
+        {"pleaseletmein", "SodiumChloride", 16384, 8, 1},
+        {0, 0, 0, 0, 0}
+};
+
+static const uint8_t post_vectors[][64] = {
+        {0x77,0xd6,0x57,0x62,0x38,0x65,0x7b,0x20,0x3b,0x19,0xca,0x42,0xc1,0x8a,0x04,0x97,
+         0xf1,0x6b,0x48,0x44,0xe3,0x07,0x4a,0xe8,0xdf,0xdf,0xfa,0x3f,0xed,0xe2,0x14,0x42,
+         0xfc,0xd0,0x06,0x9d,0xed,0x09,0x48,0xf8,0x32,0x6a,0x75,0x3a,0x0f,0xc8,0x1f,0x17,
+         0xe8,0xd3,0xe0,0xfb,0x2e,0x0d,0x36,0x28,0xcf,0x35,0xe2,0x0c,0x38,0xd1,0x89,0x06},
+        {0xfd,0xba,0xbe,0x1c,0x9d,0x34,0x72,0x00,0x78,0x56,0xe7,0x19,0x0d,0x01,0xe9,0xfe,
+         0x7c,0x6a,0xd7,0xcb,0xc8,0x23,0x78,0x30,0xe7,0x73,0x76,0x63,0x4b,0x37,0x31,0x62,
+         0x2e,0xaf,0x30,0xd9,0x2e,0x22,0xa3,0x88,0x6f,0xf1,0x09,0x27,0x9d,0x98,0x30,0xda,
+         0xc7,0x27,0xaf,0xb9,0x4a,0x83,0xee,0x6d,0x83,0x60,0xcb,0xdf,0xa2,0xcc,0x06,0x40},
+        {0x70,0x23,0xbd,0xcb,0x3a,0xfd,0x73,0x48,0x46,0x1c,0x06,0xcd,0x81,0xfd,0x38,0xeb,
+         0xfd,0xa8,0xfb,0xba,0x90,0x4f,0x8e,0x3e,0xa9,0xb5,0x43,0xf6,0x54,0x5d,0xa1,0xf2,
+         0xd5,0x43,0x29,0x55,0x61,0x3f,0x0f,0xcf,0x62,0xd4,0x97,0x05,0x24,0x2a,0x9a,0xf9,
+         0xe6,0x1e,0x85,0xdc,0x0d,0x65,0x1e,0x40,0xdf,0xcf,0x01,0x7b,0x45,0x57,0x58,0x87},
+};
+
+class ScryptTest : public ::testing::Test {
+};
+
+TEST_F(ScryptTest, TestVectors) {
+    int i;
+
+    for (i = 0; post_settings[i].pw != NULL; i++) {
+        uint8_t output[64];
+
+        scrypt_test_setting_t s = post_settings[i];
+        ASSERT_EQ(0,
+                crypto_scrypt((const uint8_t*) s.pw, strlen(s.pw), (const uint8_t*) s.salt,
+                        strlen(s.salt), s.Nfactor, s.rfactor, s.pfactor, output, sizeof(output)))
+                << "scrypt call should succeed for " << i << "; error=" << strerror(errno);
+        ASSERT_EQ(0, memcmp(post_vectors[i], output, sizeof(output)))
+                << "Should match expected output";
+    }
+}
+
+}