summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDees Troy <dees_troy@teamw.in>2013-11-19 17:09:37 +0100
committerGerrit Code Review <gerrit2@gerrit>2013-11-19 17:09:38 +0100
commitbc183725cd9c06bf8611bd82e7b30806c6faca5f (patch)
tree76478c9e1a1a51631415a5ce0c36057babd82027
parentAdd check for making sure theme exists for device (diff)
parentUpdate decrypt for 4.4 (diff)
downloadandroid_bootable_recovery-bc183725cd9c06bf8611bd82e7b30806c6faca5f.tar
android_bootable_recovery-bc183725cd9c06bf8611bd82e7b30806c6faca5f.tar.gz
android_bootable_recovery-bc183725cd9c06bf8611bd82e7b30806c6faca5f.tar.bz2
android_bootable_recovery-bc183725cd9c06bf8611bd82e7b30806c6faca5f.tar.lz
android_bootable_recovery-bc183725cd9c06bf8611bd82e7b30806c6faca5f.tar.xz
android_bootable_recovery-bc183725cd9c06bf8611bd82e7b30806c6faca5f.tar.zst
android_bootable_recovery-bc183725cd9c06bf8611bd82e7b30806c6faca5f.zip
-rw-r--r--Android.mk2
-rw-r--r--crypto/fs_mgr/Android.mk28
-rw-r--r--crypto/fs_mgr/fs_mgr.c553
-rw-r--r--crypto/fs_mgr/fs_mgr_main.c9
-rw-r--r--crypto/fs_mgr/fs_mgr_priv.h37
-rw-r--r--crypto/fs_mgr/fs_mgr_priv_verity.h17
-rw-r--r--crypto/fs_mgr/fs_mgr_verity.c410
-rw-r--r--crypto/fs_mgr/include/fs_mgr.h53
-rw-r--r--crypto/jb/Android.mk6
-rw-r--r--crypto/jb/cryptfs.c1204
-rw-r--r--crypto/jb/cryptfs.h89
-rw-r--r--crypto/logwrapper/Android.mk34
-rw-r--r--crypto/logwrapper/NOTICE190
-rw-r--r--crypto/logwrapper/include/logwrap/logwrap.h87
-rw-r--r--crypto/logwrapper/logwrap.c569
-rw-r--r--crypto/logwrapper/logwrapper.c96
-rw-r--r--crypto/scrypt/Android.mk13
-rw-r--r--crypto/scrypt/MODULE_LICENSE_BSD_LIKE0
-rw-r--r--crypto/scrypt/NOTICE36
-rw-r--r--crypto/scrypt/Scrypt-config.mk105
-rw-r--r--crypto/scrypt/Scrypt.mk46
-rw-r--r--crypto/scrypt/android-config.mk16
-rw-r--r--crypto/scrypt/build-config.mk6
-rw-r--r--crypto/scrypt/config.h99
-rwxr-xr-xcrypto/scrypt/import_scrypt.sh493
-rw-r--r--crypto/scrypt/lib/README6
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt-neon-salsa208.h120
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt-neon.c305
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt-ref.c296
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt-sse.c378
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt.h46
-rw-r--r--crypto/scrypt/lib/util/sysendian.h140
-rw-r--r--crypto/scrypt/patches/README11
-rw-r--r--crypto/scrypt/patches/arm-neon.patch437
-rw-r--r--crypto/scrypt/patches/use_openssl_pbkdf2.patch80
-rw-r--r--crypto/scrypt/scrypt.config94
-rw-r--r--crypto/scrypt/scrypt.version1
-rw-r--r--crypto/scrypt/scrypt_platform.h12
-rw-r--r--crypto/scrypt/tests/Android.mk25
-rw-r--r--crypto/scrypt/tests/scrypt_test.cpp78
40 files changed, 5750 insertions, 477 deletions
diff --git a/Android.mk b/Android.mk
index aa176136d..98ea68d9b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -354,6 +354,8 @@ endif
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 b2a341f36..f638e98c2 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 02f3ac57b..3aa9e6039 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 @@ static struct flag_list mount_flags[] = {
{ "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 @@ static struct flag_list fs_mgr_flags[] = {
{ "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 @@ static int wait_for_file(const char *filename, int timeout)
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 @@ static int parse_flags(char *flags, struct flag_list *fl, char **key_loc,
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 @@ static int parse_flags(char *flags, struct flag_list *fl, char **key_loc,
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 @@ out:
* 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 char *fs_mgr_getline(char *buf, int size, FILE *file)
}
}
-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 @@ static struct fstab_rec *read_fstab(char *fstab_path)
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 @@ static struct fstab_rec *read_fstab(char *fstab_path)
}
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 @@ static struct fstab_rec *read_fstab(char *fstab_path)
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 @@ static struct fstab_rec *read_fstab(char *fstab_path)
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 @@ static struct fstab_rec *read_fstab(char *fstab_path)
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) {
- /* 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);
+ if (!fstab) {
+ return;
+ }
+ for (i = 0; i < fstab->num_entries; i++) {
+ /* Free the pointers return by strdup(3) */
+ 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);
-
- /* Only gets here on error */
- ERROR("Cannot run fs_mgr binary %s\n", E2FSCK_BIN);
- } else {
+ 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);
+ }
+
+ 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 @@ static void remove_trailing_slashes(char *n)
}
}
+/*
+ * 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 @@ static int fs_match(char *in1, char *in2)
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 @@ int fs_mgr_mount_all(char *fstab_file)
}
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 */
+ /* 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;
+ }
+
/* First check the filesystem if requested */
- if (fstab[i].fs_mgr_flags & MF_WAIT) {
- wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
+ 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[i].fs_mgr_flags & MF_CHECK) && strcmp("ext4", fstab[i].type) != 0) {
- check_fs(fstab[i].blk_dev, fstab[i].type);
+ 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 @@ int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_m
}
/* 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 @@ int fs_mgr_do_tmpfs_mount(char *n_name)
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 81febf124..4bde4a1da 100644
--- a/crypto/fs_mgr/fs_mgr_main.c
+++ b/crypto/fs_mgr/fs_mgr_main.c
@@ -82,7 +82,8 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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 175fdabd2..59ffd785c 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 @@ struct fstab_rec {
* 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 @@ struct fstab_rec {
*
*/
-#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 000000000..61937849a
--- /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 000000000..969eab2a0
--- /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 76abb8332..0f90c32f1 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 eebfcf0bd..dc458fd14 100644
--- a/crypto/jb/Android.mk
+++ b/crypto/jb/Android.mk
@@ -7,9 +7,9 @@ LOCAL_MODULE_TAGS := eng
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 be6c476b8..4e5706b64 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 @@ static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, u
}
}
+/**
+ * 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 @@ static unsigned int get_fs_size(char *dev)
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 @@ static unsigned int get_blkdev_size(int fd)
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;
+
+ 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 fstab_filename;
+ 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 ((cnt = write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) {
- SLOGE("Cannot write real block device footer\n");
- goto errout;
+ if (fname[0] != '/') {
+ printf("Unexpected value for crypto key location\n");
+ return -1;
}
-
- 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 ( (fd = open(fname, O_RDWR | O_CREAT, 0600)) < 0) {
+ printf("Cannot open footer file %s for put\n", fname);
+ return -1;
}
- 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;
- }
+ /* 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 = 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,111 +301,145 @@ errout:
}
-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)
{
- int fd;
- unsigned int nr_sec, cnt;
- off64_t off;
- int rc = -1;
- char key_loc[PROPERTY_VALUE_MAX];
- char *fname;
- struct stat statbuf;
-
- fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+ return TEMP_FAILURE_RETRY(read(fd, buff, len));
+}
- 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;
- }
+static inline int unix_write(int fd, const void* buff, int len)
+{
+ return TEMP_FAILURE_RETRY(write(fd, buff, len));
+}
- if ( (nr_sec = get_blkdev_size(fd)) == 0) {
- SLOGE("Cannot get size of block device %s\n", fname);
- goto errout;
- }
+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;
+}
- /* 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;
+/* 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);
- if (lseek64(fd, off, SEEK_SET) == -1) {
- SLOGE("Cannot seek to real block device footer\n");
- goto errout;
+ /* 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;
}
- } 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;
+
+ 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;
}
- /* 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;
+ 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));
}
- } else {
- SLOGE("Unexpected value for crypto key location\n");
- return -1;;
- }
+}
- if ( (cnt = read(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) {
- SLOGE("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);
- goto errout;
- }
+static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
+{
+ int fd;
+ unsigned int nr_sec, cnt;
+ off64_t starting_off;
+ int rc = -1;
+ char *fname = NULL;
+ struct stat statbuf;
- if (crypt_ftr->major_version != 1) {
- SLOGE("Cannot understand major version %d real block device footer\n",
- crypt_ftr->major_version);
- goto errout;
+ if (get_crypt_ftr_info(&fname, &starting_off)) {
+ printf("Unable to get crypt_ftr_info\n");
+ return -1;
}
-
- if (crypt_ftr->minor_version != 0) {
- SLOGW("Warning: crypto footer minor version %d, expected 0, continuing...\n",
- crypt_ftr->minor_version);
+ 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 (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;
- }
+ /* 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 (crypt_ftr->keysize != KEY_LEN_BYTES) {
- SLOGE("Keysize of %d bits not supported for real block device %s\n",
- crypt_ftr->keysize * 8, fname);
+ /* 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, key, crypt_ftr->keysize)) != crypt_ftr->keysize) {
- SLOGE("Cannot read key for real block device %s\n", fname);
+ if ( (cnt = read(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) {
+ printf("Cannot read real block device footer\n");
goto errout;
}
- if (lseek64(fd, KEY_TO_SALT_PADDING, SEEK_CUR) == -1) {
- SLOGE("Cannot seek to real block device salt\n");
+ if (crypt_ftr->magic != CRYPT_MNT_MAGIC) {
+ printf("Bad magic for real block device %s\n", fname);
goto errout;
}
- if ( (cnt = read(fd, salt, SALT_LEN)) != SALT_LEN) {
- SLOGE("Cannot read salt for real block device %s\n", fname);
+ 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 > CURRENT_MINOR_VERSION) {
+ printf("Warning: crypto footer minor version %d, expected <= %d, continuing...\n",
+ crypt_ftr->minor_version, CURRENT_MINOR_VERSION);
+ }
+
+ /* 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 @@ errout:
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 @@ void convert_key_to_hex_ascii(unsigned char *master_key, unsigned int keysize,
}
+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 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char
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 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char
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)];
-
- 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;
+ 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");
+ }
+ }
- 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 @@ static int delete_crypto_blk_dev(char *name)
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 @@ static int delete_crypto_blk_dev(char *name)
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 @@ errout:
}
-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 @@ static int encrypt_master_key(char *passwd, unsigned char *salt,
/* 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 encrypt_master_key(char *passwd, unsigned char *salt,
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 decrypt_master_key(char *passwd, unsigned char *salt,
}
}
-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 @@ static int create_encrypted_random_key(char *passwd, unsigned char *master_key,
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 @@ static int wait_and_unmount(char *mountpoint)
}
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 @@ static int prep_data_fs(void)
/* 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 @@ static int prep_data_fs(void)
}
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 @@ int cryptfs_restart(void)
/* 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 @@ int cryptfs_restart(void)
* 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 @@ int cryptfs_restart(void)
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 @@ int cryptfs_restart(void)
/* 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 @@ int cryptfs_restart(void)
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 @@ static int do_crypto_complete(char *mount_point)
* 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 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
{
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 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
*/
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 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
}
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 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
* 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 @@ int cryptfs_setup_volume(const char *label, int major, int minor,
{
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 @@ int cryptfs_crypto_complete(void)
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 @@ int cryptfs_verify_passwd(char *passwd)
{
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 @@ int cryptfs_verify_passwd(char *passwd)
/* 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 @@ int cryptfs_verify_passwd(char *passwd)
*/
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';
-}
-static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type)
-{
- char cmdline[256];
- int rc = -1;
+ ftr->kdf_type = KDF_SCRYPT;
+ get_device_scrypt_params(ftr);
- 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;
+ 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;
}
-
- 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)
+static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type)
{
- 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 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, off64_
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 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, off64_
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 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, off64_
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 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, off64_
/* 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 @@ static inline int should_encrypt(struct volume_info *volume)
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 1c1bc1aea..162159eb0 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 @@ struct crypt_mnt_ftr {
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 @@ struct volume_info {
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 @@ extern "C" {
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 000000000..01b61930d
--- /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 000000000..c5b1efa7a
--- /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 000000000..4307a3055
--- /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 000000000..4ca1db4c8
--- /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 000000000..d0d8d1471
--- /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 000000000..7fa96d06e
--- /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 000000000..e69de29bb
--- /dev/null
+++ b/crypto/scrypt/MODULE_LICENSE_BSD_LIKE
diff --git a/crypto/scrypt/NOTICE b/crypto/scrypt/NOTICE
new file mode 100644
index 000000000..b0b9311e6
--- /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 000000000..bdaeccf30
--- /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 000000000..45af97fc2
--- /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 000000000..326e1134e
--- /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 000000000..3d2ab9195
--- /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 000000000..3514f398e
--- /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 000000000..324eae64b
--- /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 000000000..3bb211e84
--- /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 000000000..a3b1019a7
--- /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 000000000..a3bf052b4
--- /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 000000000..abe23eaa5
--- /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 000000000..dd18f291c
--- /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 000000000..f72e1f4b0
--- /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 000000000..62ef31a42
--- /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 000000000..353ddbbc7
--- /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 000000000..7197f9968
--- /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 000000000..0a1328cc0
--- /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 000000000..3ccb4d0eb
--- /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 000000000..155e26061
--- /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 000000000..5cec23631
--- /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 000000000..b25e1c420
--- /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 000000000..28334d6f5
--- /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";
+ }
+}
+
+}