Update decrypt for 4.4

Change-Id: I8d5d7b6a49890e4707d70de8b429563de0d2ad99
This commit is contained in:
Dees Troy
2013-11-10 04:11:43 +00:00
parent 0226cd55ab
commit 4dff2e6234
40 changed files with 5757 additions and 484 deletions
+2
View File
@@ -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
+15 -13
View File
@@ -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
+444 -107
View File
@@ -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) {
if (!fstab) {
return;
}
for (i = 0; i < fstab->num_entries; i++) {
/* Free the pointers return by strdup(3) */
free(fstab[i].blk_dev);
free(fstab[i].mnt_point);
free(fstab[i].type);
free(fstab[i].fs_options);
free(fstab[i].key_loc);
free(fstab->recs[i].blk_device);
free(fstab->recs[i].mount_point);
free(fstab->recs[i].fs_type);
free(fstab->recs[i].fs_options);
free(fstab->recs[i].key_loc);
free(fstab->recs[i].label);
i++;
}
/* Free the actual fstab array created by calloc(3) */
/* Free the fstab_recs array created by calloc(3) */
free(fstab->recs);
/* Free the fstab filename */
free(fstab->fstab_filename);
/* Free fstab */
free(fstab);
}
static void check_fs(char *blk_dev, char *type)
static void check_fs(char *blk_device, char *fs_type, char *target)
{
pid_t pid;
int status;
int ret;
long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
char *e2fsck_argv[] = {
E2FSCK_BIN,
"-y",
blk_device
};
/* Check for the types of filesystems we know how to check */
if (!strcmp(type, "ext2") || !strcmp(type, "ext3") || !strcmp(type, "ext4")) {
INFO("Running %s on %s\n", E2FSCK_BIN, blk_dev);
pid = fork();
if (pid > 0) {
/* Parent, wait for the child to return */
waitpid(pid, &status, 0);
} else if (pid == 0) {
/* child, run checker */
execlp(E2FSCK_BIN, E2FSCK_BIN, "-y", blk_dev, (char *)NULL);
if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
/*
* First try to mount and unmount the filesystem. We do this because
* the kernel is more efficient than e2fsck in running the journal and
* processing orphaned inodes, and on at least one device with a
* performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
* to do what the kernel does in about a second.
*
* After mounting and unmounting the filesystem, run e2fsck, and if an
* error is recorded in the filesystem superblock, e2fsck will do a full
* check. Otherwise, it does nothing. If the kernel cannot mount the
* filesytsem due to an error, e2fsck is still run to do a full check
* fix the filesystem.
*/
ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
if (!ret) {
umount(target);
}
/* Only gets here on error */
ERROR("Cannot run fs_mgr binary %s\n", E2FSCK_BIN);
} else {
INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
&status, true, LOG_KLOG | LOG_FILE,
true, FSCK_LOG_FILE);
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
ERROR("Fork failed trying to run %s\n", E2FSCK_BIN);
ERROR("Failed trying to run %s\n", E2FSCK_BIN);
}
}
@@ -396,6 +513,43 @@ 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 */
/* First check the filesystem if requested */
if (fstab[i].fs_mgr_flags & MF_WAIT) {
wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
/* If this swap or a raw partition, report an error */
if (!strcmp(fstab->recs[i].fs_type, "swap") ||
!strcmp(fstab->recs[i].fs_type, "emmc") ||
!strcmp(fstab->recs[i].fs_type, "mtd")) {
ERROR("Cannot mount filesystem of type %s on %s\n",
fstab->recs[i].fs_type, n_blk_device);
goto out;
}
if ((fstab[i].fs_mgr_flags & MF_CHECK) && strcmp("ext4", fstab[i].type) != 0) {
check_fs(fstab[i].blk_dev, fstab[i].type);
/* First check the filesystem if requested */
if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
wait_for_file(n_blk_device, WAIT_TIMEOUT);
}
if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
check_fs(n_blk_device, fstab->recs[i].fs_type,
fstab->recs[i].mount_point);
}
if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
ERROR("Could not set up verified partition, skipping!");
continue;
}
}
/* Now mount it where requested */
if (tmp_mnt_point) {
m = tmp_mnt_point;
if (tmp_mount_point) {
m = tmp_mount_point;
} else {
m = fstab[i].mnt_point;
m = fstab->recs[i].mount_point;
}
if (mount(n_blk_dev, m, fstab[i].type,
fstab[i].flags, fstab[i].fs_options)) {
if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
fstab->recs[i].flags, fstab->recs[i].fs_options)) {
ERROR("Cannot mount filesystem on %s at %s\n",
n_blk_dev, m);
n_blk_device, m);
goto out;
} else {
ret = 0;
@@ -521,10 +713,9 @@ 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;
}
+7 -2
View File
@@ -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);
}
+21 -16
View File
@@ -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 */
+17
View File
@@ -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);
+410
View File
@@ -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;
}
+49 -4
View File
@@ -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 */
+3 -3
View File
@@ -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
+892 -328
View File
File diff suppressed because it is too large Load Diff
+78 -11
View File
@@ -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
+34
View File
@@ -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)
+190
View File
@@ -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
@@ -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 */
+569
View File
@@ -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;
}
+96
View File
@@ -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;
}
+13
View File
@@ -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)
+36
View File
@@ -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
*/
+105
View File
@@ -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
+46
View File
@@ -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)
+16
View File
@@ -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
+6
View File
@@ -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 := \
+99
View File
@@ -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 */
+493
View File
@@ -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 $@
+6
View File
@@ -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.
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
+46
View File
@@ -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_ */
+140
View File
@@ -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_ */
+11
View File
@@ -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.
+437
View File
@@ -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);
+}
@@ -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
+94
View File
@@ -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 \
"
+1
View File
@@ -0,0 +1 @@
SCRYPT_VERSION=1.1.6
+12
View File
@@ -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_ */
+25
View File
@@ -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)
+78
View File
@@ -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";
}
}
}