diff options
Diffstat (limited to 'crypto')
27 files changed, 4527 insertions, 0 deletions
diff --git a/crypto/lollipop/Android.mk b/crypto/lollipop/Android.mk new file mode 100644 index 000000000..148e328da --- /dev/null +++ b/crypto/lollipop/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH := $(call my-dir) +ifeq ($(TW_INCLUDE_CRYPTO), true) +include $(CLEAR_VARS) + +LOCAL_MODULE := libcryptfslollipop +LOCAL_MODULE_TAGS := eng optional +LOCAL_CFLAGS := +LOCAL_SRC_FILES = cryptfs.c +LOCAL_SHARED_LIBRARIES := libcrypto libhardware libcutils +LOCAL_C_INCLUDES := external/openssl/include $(commands_recovery_local_path)/crypto/scrypt/lib/crypto +LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static + +include $(BUILD_SHARED_LIBRARY) + +endif diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c new file mode 100644 index 000000000..496b960ad --- /dev/null +++ b/crypto/lollipop/cryptfs.c @@ -0,0 +1,1449 @@ +/* + * Copyright (C) 2010 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. + */ + +/* TO DO: + * 1. Perhaps keep several copies of the encrypted key, in case something + * goes horribly wrong? + * + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <ctype.h> +#include <fcntl.h> +#include <inttypes.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <linux/dm-ioctl.h> +#include <libgen.h> +#include <stdlib.h> +#include <sys/param.h> +#include <string.h> +#include <sys/mount.h> +#include <openssl/evp.h> +#include <errno.h> +#include <linux/kdev_t.h> +#include <time.h> +#include "cryptfs.h" +#include "cutils/properties.h" +#include "crypto_scrypt.h" +#include <hardware/keymaster.h> + +#ifndef min /* already defined by windows.h */ +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define UNUSED __attribute__((unused)) + +#define UNUSED __attribute__((unused)) + +#define DM_CRYPT_BUF_SIZE 4096 + +#define HASH_COUNT 2000 +#define KEY_LEN_BYTES 16 +#define IV_LEN_BYTES 16 + +#define KEY_IN_FOOTER "footer" + +// "default_password" encoded into hex (d=0x64 etc) +#define DEFAULT_PASSWORD "64656661756c745f70617373776f7264" + +#define EXT4_FS 1 +#define F2FS_FS 2 + +#define TABLE_LOAD_RETRIES 10 + +#define RSA_KEY_SIZE 2048 +#define RSA_KEY_SIZE_BYTES (RSA_KEY_SIZE / 8) +#define RSA_EXPONENT 0x10001 + +#define RETRY_MOUNT_ATTEMPTS 10 +#define RETRY_MOUNT_DELAY_SECONDS 1 + +char *me = "cryptfs"; + +static unsigned char saved_master_key[KEY_LEN_BYTES]; +static char *saved_mount_point; +static int master_key_saved = 0; +static struct crypt_persist_data *persist_data = NULL; +static char key_fname[PROPERTY_VALUE_MAX] = ""; +static char real_blkdev[PROPERTY_VALUE_MAX] = ""; +static char file_system[PROPERTY_VALUE_MAX] = ""; + +void set_partition_data(const char* block_device, const char* key_location, const char* fs) +{ + strcpy(key_fname, key_location); + strcpy(real_blkdev, block_device); + strcpy(file_system, fs); +} + +static int keymaster_init(keymaster_device_t **keymaster_dev) +{ + int rc; + + const hw_module_t* mod; + rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod); + if (rc) { + printf("could not find any keystore module\n"); + goto out; + } + + rc = keymaster_open(mod, keymaster_dev); + if (rc) { + printf("could not open keymaster device in %s (%s)\n", + KEYSTORE_HARDWARE_MODULE_ID, strerror(-rc)); + goto out; + } + + return 0; + +out: + *keymaster_dev = NULL; + return rc; +} + +/* Should we use keymaster? */ +static int keymaster_check_compatibility() +{ + keymaster_device_t *keymaster_dev = 0; + int rc = 0; + + if (keymaster_init(&keymaster_dev)) { + printf("Failed to init keymaster\n"); + rc = -1; + goto out; + } + + printf("keymaster version is %d\n", keymaster_dev->common.module->module_api_version); + +#if (KEYMASTER_HEADER_VERSION >= 3) + if (keymaster_dev->common.module->module_api_version + < KEYMASTER_MODULE_API_VERSION_0_3) { + rc = 0; + goto out; + } + + if (keymaster_dev->flags & KEYMASTER_BLOBS_ARE_STANDALONE) { + rc = 1; + } + +#endif +out: + keymaster_close(keymaster_dev); + return rc; +} + +/* Create a new keymaster key and store it in this footer */ +static int keymaster_create_key(struct crypt_mnt_ftr *ftr) +{ + uint8_t* key = 0; + keymaster_device_t *keymaster_dev = 0; + + if (keymaster_init(&keymaster_dev)) { + printf("Failed to init keymaster\n"); + return -1; + } + + int rc = 0; + + keymaster_rsa_keygen_params_t params; + memset(¶ms, '\0', sizeof(params)); + params.public_exponent = RSA_EXPONENT; + params.modulus_size = RSA_KEY_SIZE; + + size_t key_size; + if (keymaster_dev->generate_keypair(keymaster_dev, TYPE_RSA, ¶ms, + &key, &key_size)) { + printf("Failed to generate keypair\n"); + rc = -1; + goto out; + } + + if (key_size > KEYMASTER_BLOB_SIZE) { + printf("Keymaster key too large for crypto footer\n"); + rc = -1; + goto out; + } + + memcpy(ftr->keymaster_blob, key, key_size); + ftr->keymaster_blob_size = key_size; + +out: + keymaster_close(keymaster_dev); + free(key); + return rc; +} + +/* This signs the given object using the keymaster key. */ +static int keymaster_sign_object(struct crypt_mnt_ftr *ftr, + const unsigned char *object, + const size_t object_size, + unsigned char **signature, + size_t *signature_size) +{ + int rc = 0; + keymaster_device_t *keymaster_dev = 0; + if (keymaster_init(&keymaster_dev)) { + printf("Failed to init keymaster\n"); + return -1; + } + + /* We currently set the digest type to DIGEST_NONE because it's the + * only supported value for keymaster. A similar issue exists with + * PADDING_NONE. Long term both of these should likely change. + */ + keymaster_rsa_sign_params_t params; + params.digest_type = DIGEST_NONE; + params.padding_type = PADDING_NONE; + + unsigned char to_sign[RSA_KEY_SIZE_BYTES]; + size_t to_sign_size = sizeof(to_sign); + memset(to_sign, 0, RSA_KEY_SIZE_BYTES); + + // To sign a message with RSA, the message must satisfy two + // constraints: + // + // 1. The message, when interpreted as a big-endian numeric value, must + // be strictly less than the public modulus of the RSA key. Note + // that because the most significant bit of the public modulus is + // guaranteed to be 1 (else it's an (n-1)-bit key, not an n-bit + // key), an n-bit message with most significant bit 0 always + // satisfies this requirement. + // + // 2. The message must have the same length in bits as the public + // modulus of the RSA key. This requirement isn't mathematically + // necessary, but is necessary to ensure consistency in + // implementations. + switch (ftr->kdf_type) { + case KDF_SCRYPT_KEYMASTER_UNPADDED: + // This is broken: It produces a message which is shorter than + // the public modulus, failing criterion 2. + memcpy(to_sign, object, object_size); + to_sign_size = object_size; + printf("Signing unpadded object\n"); + break; + case KDF_SCRYPT_KEYMASTER_BADLY_PADDED: + // This is broken: Since the value of object is uniformly + // distributed, it produces a message that is larger than the + // public modulus with probability 0.25. + memcpy(to_sign, object, min(RSA_KEY_SIZE_BYTES, object_size)); + printf("Signing end-padded object\n"); + break; + case KDF_SCRYPT_KEYMASTER: + // This ensures the most significant byte of the signed message + // is zero. We could have zero-padded to the left instead, but + // this approach is slightly more robust against changes in + // object size. However, it's still broken (but not unusably + // so) because we really should be using a proper RSA padding + // function, such as OAEP. + // + // TODO(paullawrence): When keymaster 0.4 is available, change + // this to use the padding options it provides. + memcpy(to_sign + 1, object, min(RSA_KEY_SIZE_BYTES - 1, object_size)); + printf("Signing safely-padded object\n"); + break; + default: + printf("Unknown KDF type %d\n", ftr->kdf_type); + return -1; + } + + rc = keymaster_dev->sign_data(keymaster_dev, + ¶ms, + ftr->keymaster_blob, + ftr->keymaster_blob_size, + to_sign, + to_sign_size, + signature, + signature_size); + + keymaster_close(keymaster_dev); + return rc; +} + +/* Store password when userdata is successfully decrypted and mounted. + * Cleared by cryptfs_clear_password + * + * To avoid a double prompt at boot, we need to store the CryptKeeper + * password and pass it to KeyGuard, which uses it to unlock KeyStore. + * Since the entire framework is torn down and rebuilt after encryption, + * we have to use a daemon or similar to store the password. Since vold + * is secured against IPC except from system processes, it seems a reasonable + * place to store this. + * + * password should be cleared once it has been used. + * + * password is aged out after password_max_age_seconds seconds. + */ +static char* password = 0; +static int password_expiry_time = 0; +static const int password_max_age_seconds = 60; + +static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags) +{ + memset(io, 0, dataSize); + io->data_size = dataSize; + io->data_start = sizeof(struct dm_ioctl); + io->version[0] = 4; + io->version[1] = 0; + io->version[2] = 0; + io->flags = flags; + if (name) { + strncpy(io->name, name, sizeof(io->name)); + } +} + +/** + * Gets the default device scrypt parameters for key derivation time tuning. + * The parameters should lead to about one second derivation time for the + * given device. + */ +static void get_device_scrypt_params(struct crypt_mnt_ftr *ftr) { + const int default_params[] = SCRYPT_DEFAULTS; + int params[] = SCRYPT_DEFAULTS; + char paramstr[PROPERTY_VALUE_MAX]; + char *token; + char *saveptr; + int i; + + property_get(SCRYPT_PROP, paramstr, ""); + if (paramstr[0] != '\0') { + /* + * The token we're looking for should be three integers separated by + * colons (e.g., "12:8:1"). Scan the property to make sure it matches. + */ + for (i = 0, token = strtok_r(paramstr, ":", &saveptr); + token != NULL && i < 3; + i++, token = strtok_r(NULL, ":", &saveptr)) { + char *endptr; + params[i] = strtol(token, &endptr, 10); + + /* + * Check that there was a valid number and it's 8-bit. If not, + * break out and the end check will take the default values. + */ + if ((*token == '\0') || (*endptr != '\0') || params[i] < 0 || params[i] > 255) { + break; + } + } + + /* + * If there were not enough tokens or a token was malformed (not an + * integer), it will end up here and the default parameters can be + * taken. + */ + if ((i != 3) || (token != NULL)) { + printf("bad scrypt parameters '%s' should be like '12:8:1'; using defaults", paramstr); + memcpy(params, default_params, sizeof(params)); + } + } + + ftr->N_factor = params[0]; + ftr->r_factor = params[1]; + ftr->p_factor = params[2]; +} + +static unsigned int get_blkdev_size(int fd) +{ + unsigned int nr_sec; + + if ( (ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) { + nr_sec = 0; + } + + return nr_sec; +} + +static int get_crypt_ftr_info(char **metadata_fname, off64_t *off) +{ + static int cached_data = 0; + static off64_t cached_off = 0; + static char cached_metadata_fname[PROPERTY_VALUE_MAX] = ""; + int fd; + unsigned int nr_sec; + int rc = -1; + + if (!cached_data) { + printf("get_crypt_ftr_info crypto key location: '%s'\n", key_fname); + if (!strcmp(key_fname, KEY_IN_FOOTER)) { + if ( (fd = open(real_blkdev, O_RDWR)) < 0) { + printf("Cannot open real block device %s\n", real_blkdev); + return -1; + } + + if ((nr_sec = get_blkdev_size(fd))) { + /* If it's an encrypted Android partition, the last 16 Kbytes contain the + * encryption info footer and key, and plenty of bytes to spare for future + * growth. + */ + strlcpy(cached_metadata_fname, real_blkdev, sizeof(cached_metadata_fname)); + cached_off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET; + cached_data = 1; + } else { + printf("Cannot get size of block device %s\n", real_blkdev); + } + close(fd); + } else { + strlcpy(cached_metadata_fname, key_fname, sizeof(cached_metadata_fname)); + cached_off = 0; + cached_data = 1; + } + } + + if (cached_data) { + if (metadata_fname) { + *metadata_fname = cached_metadata_fname; + } + if (off) { + *off = cached_off; + } + rc = 0; + } + + return rc; +} + +static inline int unix_read(int fd, void* buff, int len) +{ + return TEMP_FAILURE_RETRY(read(fd, buff, len)); +} + +static inline int unix_write(int fd, const void* buff, int len) +{ + return TEMP_FAILURE_RETRY(write(fd, buff, len)); +} + +static void init_empty_persist_data(struct crypt_persist_data *pdata, int len) +{ + memset(pdata, 0, len); + pdata->persist_magic = PERSIST_DATA_MAGIC; + pdata->persist_valid_entries = 0; +} + +static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr) +{ + int fd; + unsigned int nr_sec, cnt; + off64_t starting_off; + int rc = -1; + char *fname = NULL; + struct stat statbuf; + + if (get_crypt_ftr_info(&fname, &starting_off)) { + printf("Unable to get crypt_ftr_info\n"); + return -1; + } + if (fname[0] != '/') { + printf("Unexpected value for crypto key location\n"); + return -1; + } + if ( (fd = open(fname, O_RDWR)) < 0) { + printf("Cannot open footer file %s for get\n", fname); + return -1; + } + + /* Make sure it's 16 Kbytes in length */ + fstat(fd, &statbuf); + if (S_ISREG(statbuf.st_mode) && (statbuf.st_size != 0x4000)) { + printf("footer file %s is not the expected size!\n", fname); + goto errout; + } + + /* Seek to the start of the crypt footer */ + if (lseek64(fd, starting_off, SEEK_SET) == -1) { + printf("Cannot seek to real block device footer\n"); + goto errout; + } + + if ( (cnt = read(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) { + printf("Cannot read real block device footer\n"); + goto errout; + } + + if (crypt_ftr->magic != CRYPT_MNT_MAGIC) { + printf("Bad magic for real block device %s\n", fname); + goto errout; + } + + if (crypt_ftr->major_version != CURRENT_MAJOR_VERSION) { + printf("Cannot understand major version %d real block device footer; expected %d\n", + crypt_ftr->major_version, CURRENT_MAJOR_VERSION); + goto errout; + } + + if (crypt_ftr->minor_version > CURRENT_MINOR_VERSION) { + printf("Warning: crypto footer minor version %d, expected <= %d, continuing...\n", + crypt_ftr->minor_version, CURRENT_MINOR_VERSION); + } + + /* If this is a verion 1.0 crypt_ftr, make it a 1.1 crypt footer, and update the + * copy on disk before returning. + */ + /*if (crypt_ftr->minor_version < CURRENT_MINOR_VERSION) { + upgrade_crypt_ftr(fd, crypt_ftr, starting_off); + }*/ + + /* Success! */ + rc = 0; + +errout: + close(fd); + return rc; +} + +static int hexdigit (char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + c = tolower(c); + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + return -1; +} + +static unsigned char* convert_hex_ascii_to_key(const char* master_key_ascii, + unsigned int* out_keysize) +{ + unsigned int i; + *out_keysize = 0; + + size_t size = strlen (master_key_ascii); + if (size % 2) { + printf("Trying to convert ascii string of odd length"); + return NULL; + } + + unsigned char* master_key = (unsigned char*) malloc(size / 2); + if (master_key == 0) { + printf("Cannot allocate"); + return NULL; + } + + for (i = 0; i < size; i += 2) { + int high_nibble = hexdigit (master_key_ascii[i]); + int low_nibble = hexdigit (master_key_ascii[i + 1]); + + if(high_nibble < 0 || low_nibble < 0) { + printf("Invalid hex string"); + free (master_key); + return NULL; + } + + master_key[*out_keysize] = high_nibble * 16 + low_nibble; + (*out_keysize)++; + } + + return master_key; +} + +/* Convert a binary key of specified length into an ascii hex string equivalent, + * without the leading 0x and with null termination + */ +static void convert_key_to_hex_ascii(unsigned char *master_key, unsigned int keysize, + char *master_key_ascii) +{ + unsigned int i, a; + unsigned char nibble; + + for (i=0, a=0; i<keysize; i++, a+=2) { + /* For each byte, write out two ascii hex digits */ + nibble = (master_key[i] >> 4) & 0xf; + master_key_ascii[a] = nibble + (nibble > 9 ? 0x37 : 0x30); + + nibble = master_key[i] & 0xf; + master_key_ascii[a+1] = nibble + (nibble > 9 ? 0x37 : 0x30); + } + + /* Add the null termination */ + master_key_ascii[a] = '\0'; + +} + +static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key, + char *real_blk_name, const char *name, int fd, + char *extra_params) +{ + char buffer[DM_CRYPT_BUF_SIZE]; + struct dm_ioctl *io; + struct dm_target_spec *tgt; + char *crypt_params; + char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */ + int i; + + io = (struct dm_ioctl *) buffer; + + /* Load the mapping table for this device */ + tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)]; + + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + io->target_count = 1; + tgt->status = 0; + tgt->sector_start = 0; + tgt->length = crypt_ftr->fs_size; + strcpy(tgt->target_type, "crypt"); + + crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); + convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii); + sprintf(crypt_params, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name, + master_key_ascii, real_blk_name, extra_params); + crypt_params += strlen(crypt_params) + 1; + crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */ + tgt->next = crypt_params - buffer; + + for (i = 0; i < TABLE_LOAD_RETRIES; i++) { + if (! ioctl(fd, DM_TABLE_LOAD, io)) { + break; + } + usleep(500000); + } + + if (i == TABLE_LOAD_RETRIES) { + /* We failed to load the table, return an error */ + return -1; + } else { + return i + 1; + } +} + + +static int get_dm_crypt_version(int fd, const char *name, int *version) +{ + char buffer[DM_CRYPT_BUF_SIZE]; + struct dm_ioctl *io; + struct dm_target_versions *v; + int i; + + io = (struct dm_ioctl *) buffer; + + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + + if (ioctl(fd, DM_LIST_VERSIONS, io)) { + return -1; + } + + /* Iterate over the returned versions, looking for name of "crypt". + * When found, get and return the version. + */ + v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)]; + while (v->next) { + if (! strcmp(v->name, "crypt")) { + /* We found the crypt driver, return the version, and get out */ + version[0] = v->version[0]; + version[1] = v->version[1]; + version[2] = v->version[2]; + return 0; + } + v = (struct dm_target_versions *)(((char *)v) + v->next); + } + + return -1; +} + +static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key, + char *real_blk_name, char *crypto_blk_name, const char *name) +{ + char buffer[DM_CRYPT_BUF_SIZE]; + char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */ + char *crypt_params; + struct dm_ioctl *io; + struct dm_target_spec *tgt; + unsigned int minor; + int fd; + int i; + int retval = -1; + int version[3]; + char *extra_params; + int load_count; + + if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) { + printf("Cannot open device-mapper\n"); + goto errout; + } + + io = (struct dm_ioctl *) buffer; + + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + if (ioctl(fd, DM_DEV_CREATE, io)) { + printf("Cannot create dm-crypt device\n"); + goto errout; + } + + /* Get the device status, in particular, the name of it's device file */ + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + if (ioctl(fd, DM_DEV_STATUS, io)) { + printf("Cannot retrieve dm-crypt device status\n"); + goto errout; + } + minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00); + snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor); + + extra_params = ""; + if (! get_dm_crypt_version(fd, name, version)) { + /* Support for allow_discards was added in version 1.11.0 */ + if ((version[0] >= 2) || + ((version[0] == 1) && (version[1] >= 11))) { + extra_params = "1 allow_discards"; + printf("Enabling support for allow_discards in dmcrypt.\n"); + } + } + + load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name, + fd, extra_params); + if (load_count < 0) { + printf("Cannot load dm-crypt mapping table.\n"); + goto errout; + } else if (load_count > 1) { + printf("Took %d tries to load dmcrypt table.\n", load_count); + } + + /* Resume this device to activate it */ + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + + if (ioctl(fd, DM_DEV_SUSPEND, io)) { + printf("Cannot resume the dm-crypt device\n"); + goto errout; + } + + /* We made it here with no errors. Woot! */ + retval = 0; + +errout: + close(fd); /* If fd is <0 from a failed open call, it's safe to just ignore the close error */ + + return retval; +} + +int delete_crypto_blk_dev(char *name) +{ + int fd; + char buffer[DM_CRYPT_BUF_SIZE]; + struct dm_ioctl *io; + int retval = -1; + + if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) { + printf("Cannot open device-mapper\n"); + goto errout; + } + + io = (struct dm_ioctl *) buffer; + + ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); + if (ioctl(fd, DM_DEV_REMOVE, io)) { + printf("Cannot remove dm-crypt device\n"); + goto errout; + } + + /* We made it here with no errors. Woot! */ + retval = 0; + +errout: + close(fd); /* If fd is <0 from a failed open call, it's safe to just ignore the close error */ + + return retval; + +} + +static int pbkdf2(const char *passwd, const unsigned char *salt, + unsigned char *ikey, void *params UNUSED) +{ + printf("Using pbkdf2 for cryptfs KDF"); + + /* Turn the password into a key and IV that can decrypt the master key */ + unsigned int keysize; + char* master_key = (char*)convert_hex_ascii_to_key(passwd, &keysize); + if (!master_key) return -1; + PKCS5_PBKDF2_HMAC_SHA1(master_key, keysize, salt, SALT_LEN, + HASH_COUNT, KEY_LEN_BYTES+IV_LEN_BYTES, ikey); + + memset(master_key, 0, keysize); + free (master_key); + return 0; +} + +static int scrypt(const char *passwd, const unsigned char *salt, + unsigned char *ikey, void *params) +{ + printf("Using scrypt for cryptfs KDF\n"); + + struct crypt_mnt_ftr *ftr = (struct crypt_mnt_ftr *) params; + + int N = 1 << ftr->N_factor; + int r = 1 << ftr->r_factor; + int p = 1 << ftr->p_factor; + + /* Turn the password into a key and IV that can decrypt the master key */ + unsigned int keysize; + unsigned char* master_key = convert_hex_ascii_to_key(passwd, &keysize); + if (!master_key) return -1; + crypto_scrypt(master_key, keysize, salt, SALT_LEN, N, r, p, ikey, + KEY_LEN_BYTES + IV_LEN_BYTES); + + memset(master_key, 0, keysize); + free (master_key); + return 0; +} + +static int scrypt_keymaster(const char *passwd, const unsigned char *salt, + unsigned char *ikey, void *params) +{ + printf("Using scrypt with keymaster for cryptfs KDF\n"); + + int rc; + unsigned int key_size; + size_t signature_size; + unsigned char* signature; + struct crypt_mnt_ftr *ftr = (struct crypt_mnt_ftr *) params; + + int N = 1 << ftr->N_factor; + int r = 1 << ftr->r_factor; + int p = 1 << ftr->p_factor; + + unsigned char* master_key = convert_hex_ascii_to_key(passwd, &key_size); + if (!master_key) { + printf("Failed to convert passwd from hex\n"); + return -1; + } + + rc = crypto_scrypt(master_key, key_size, salt, SALT_LEN, + N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES); + memset(master_key, 0, key_size); + free(master_key); + + if (rc) { + printf("scrypt failed\n"); + return -1; + } + + if (keymaster_sign_object(ftr, ikey, KEY_LEN_BYTES + IV_LEN_BYTES, + &signature, &signature_size)) { + printf("Signing failed\n"); + return -1; + } + + rc = crypto_scrypt(signature, signature_size, salt, SALT_LEN, + N, r, p, ikey, KEY_LEN_BYTES + IV_LEN_BYTES); + free(signature); + + if (rc) { + printf("scrypt failed\n"); + return -1; + } + + return 0; +} + +static int encrypt_master_key(const char *passwd, const unsigned char *salt, + const unsigned char *decrypted_master_key, + unsigned char *encrypted_master_key, + struct crypt_mnt_ftr *crypt_ftr) +{ + unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */ + EVP_CIPHER_CTX e_ctx; + int encrypted_len, final_len; + int rc = 0; + + /* Turn the password into an intermediate key and IV that can decrypt the master key */ + get_device_scrypt_params(crypt_ftr); + + switch (crypt_ftr->kdf_type) { + case KDF_SCRYPT_KEYMASTER_UNPADDED: + case KDF_SCRYPT_KEYMASTER_BADLY_PADDED: + case KDF_SCRYPT_KEYMASTER: + if (keymaster_create_key(crypt_ftr)) { + printf("keymaster_create_key failed"); + return -1; + } + + if (scrypt_keymaster(passwd, salt, ikey, crypt_ftr)) { + printf("scrypt failed"); + return -1; + } + break; + + case KDF_SCRYPT: + if (scrypt(passwd, salt, ikey, crypt_ftr)) { + printf("scrypt failed"); + return -1; + } + break; + + default: + printf("Invalid kdf_type"); + return -1; + } + + /* Initialize the decryption engine */ + if (! EVP_EncryptInit(&e_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) { + printf("EVP_EncryptInit failed\n"); + return -1; + } + EVP_CIPHER_CTX_set_padding(&e_ctx, 0); /* Turn off padding as our data is block aligned */ + + /* Encrypt the master key */ + if (! EVP_EncryptUpdate(&e_ctx, encrypted_master_key, &encrypted_len, + decrypted_master_key, KEY_LEN_BYTES)) { + printf("EVP_EncryptUpdate failed\n"); + return -1; + } + if (! EVP_EncryptFinal(&e_ctx, encrypted_master_key + encrypted_len, &final_len)) { + printf("EVP_EncryptFinal failed\n"); + return -1; + } + + if (encrypted_len + final_len != KEY_LEN_BYTES) { + printf("EVP_Encryption length check failed with %d, %d bytes\n", encrypted_len, final_len); + return -1; + } + + /* Store the scrypt of the intermediate key, so we can validate if it's a + password error or mount error when things go wrong. + Note there's no need to check for errors, since if this is incorrect, we + simply won't wipe userdata, which is the correct default behavior + */ + int N = 1 << crypt_ftr->N_factor; + int r = 1 << crypt_ftr->r_factor; + int p = 1 << crypt_ftr->p_factor; + + rc = crypto_scrypt(ikey, KEY_LEN_BYTES, + crypt_ftr->salt, sizeof(crypt_ftr->salt), N, r, p, + crypt_ftr->scrypted_intermediate_key, + sizeof(crypt_ftr->scrypted_intermediate_key)); + + if (rc) { + printf("encrypt_master_key: crypto_scrypt failed"); + } + + return 0; +} + +static int decrypt_master_key_aux(char *passwd, unsigned char *salt, + unsigned char *encrypted_master_key, + unsigned char *decrypted_master_key, + kdf_func kdf, void *kdf_params, + unsigned char** intermediate_key, + size_t* intermediate_key_size) +{ + unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */ + EVP_CIPHER_CTX d_ctx; + int decrypted_len, final_len; + + /* Turn the password into an intermediate key and IV that can decrypt the + master key */ + if (kdf(passwd, salt, ikey, kdf_params)) { + printf("kdf failed"); + return -1; + } + + /* Initialize the decryption engine */ + if (! EVP_DecryptInit(&d_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) { + return -1; + } + EVP_CIPHER_CTX_set_padding(&d_ctx, 0); /* Turn off padding as our data is block aligned */ + /* Decrypt the master key */ + if (! EVP_DecryptUpdate(&d_ctx, decrypted_master_key, &decrypted_len, + encrypted_master_key, KEY_LEN_BYTES)) { + return -1; + } + if (! EVP_DecryptFinal(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) { + return -1; + } + + if (decrypted_len + final_len != KEY_LEN_BYTES) { + return -1; + } + + /* Copy intermediate key if needed by params */ + if (intermediate_key && intermediate_key_size) { + *intermediate_key = (unsigned char*) malloc(KEY_LEN_BYTES); + if (intermediate_key) { + memcpy(*intermediate_key, ikey, KEY_LEN_BYTES); + *intermediate_key_size = KEY_LEN_BYTES; + } + } + + return 0; +} + +static void get_kdf_func(struct crypt_mnt_ftr *ftr, kdf_func *kdf, void** kdf_params) +{ + if (ftr->kdf_type == KDF_SCRYPT_KEYMASTER_UNPADDED || + ftr->kdf_type == KDF_SCRYPT_KEYMASTER_BADLY_PADDED || + ftr->kdf_type == KDF_SCRYPT_KEYMASTER) { + *kdf = scrypt_keymaster; + *kdf_params = ftr; + } else if (ftr->kdf_type == KDF_SCRYPT) { + *kdf = scrypt; + *kdf_params = ftr; + } else { + *kdf = pbkdf2; + *kdf_params = NULL; + } +} + +static int decrypt_master_key(char *passwd, unsigned char *decrypted_master_key, + struct crypt_mnt_ftr *crypt_ftr, + unsigned char** intermediate_key, + size_t* intermediate_key_size) +{ + kdf_func kdf; + void *kdf_params; + int ret; + + get_kdf_func(crypt_ftr, &kdf, &kdf_params); + ret = decrypt_master_key_aux(passwd, crypt_ftr->salt, crypt_ftr->master_key, + decrypted_master_key, kdf, kdf_params, + intermediate_key, intermediate_key_size); + if (ret != 0) { + printf("failure decrypting master key"); + } + + return ret; +} + +static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, + char *passwd, char *mount_point, char *label) +{ + /* Allocate enough space for a 256 bit key, but we may use less */ + unsigned char decrypted_master_key[32]; + char crypto_blkdev[MAXPATHLEN]; + char tmp_mount_point[64]; + unsigned int orig_failed_decrypt_count; + int rc; + kdf_func kdf; + void *kdf_params; + int use_keymaster = 0; + int upgrade = 0; + unsigned char* intermediate_key = 0; + size_t intermediate_key_size = 0; + + printf("crypt_ftr->fs_size = %lld\n", crypt_ftr->fs_size); + orig_failed_decrypt_count = crypt_ftr->failed_decrypt_count; + + if (! (crypt_ftr->flags & CRYPT_MNT_KEY_UNENCRYPTED) ) { + if (decrypt_master_key(passwd, decrypted_master_key, crypt_ftr, + &intermediate_key, &intermediate_key_size)) { + printf("Failed to decrypt master key\n"); + rc = -1; + goto errout; + } + } + + // Create crypto block device - all (non fatal) code paths + // need it + if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, + real_blkdev, crypto_blkdev, label)) { + printf("Error creating decrypted block device\n"); + rc = -1; + goto errout; + } + + /* Work out if the problem is the password or the data */ + unsigned char scrypted_intermediate_key[sizeof(crypt_ftr-> + scrypted_intermediate_key)]; + int N = 1 << crypt_ftr->N_factor; + int r = 1 << crypt_ftr->r_factor; + int p = 1 << crypt_ftr->p_factor; + + rc = crypto_scrypt(intermediate_key, intermediate_key_size, + crypt_ftr->salt, sizeof(crypt_ftr->salt), + N, r, p, scrypted_intermediate_key, + sizeof(scrypted_intermediate_key)); + + // Does the key match the crypto footer? + if (rc == 0 && memcmp(scrypted_intermediate_key, + crypt_ftr->scrypted_intermediate_key, + sizeof(scrypted_intermediate_key)) == 0) { + printf("Password matches\n"); + rc = 0; + } else { + /* Try mounting the file system anyway, just in case the problem's with + * the footer, not the key. */ + sprintf(tmp_mount_point, "%s/tmp_mnt", mount_point); + mkdir(tmp_mount_point, 0755); + if (mount(crypto_blkdev, tmp_mount_point, file_system, NULL, NULL) != 0) { + printf("Error temp mounting decrypted block device '%s'\n", crypto_blkdev); + delete_crypto_blk_dev(label); + + rc = ++crypt_ftr->failed_decrypt_count; + //put_crypt_ftr_and_key(crypt_ftr); // Do not penalize for attempting to decrypt in recovery + } else { + /* Success! */ + printf("Password did not match but decrypted drive mounted - continue\n"); + umount(tmp_mount_point); + rc = 0; + } + } + + if (rc == 0) { + /*crypt_ftr->failed_decrypt_count = 0; + if (orig_failed_decrypt_count != 0) { + put_crypt_ftr_and_key(crypt_ftr); + }*/ + + /* Save the name of the crypto block device + * so we can mount it when restarting the framework. */ + property_set("ro.crypto.fs_crypto_blkdev", crypto_blkdev); + + /* Also save a the master key so we can reencrypted the key + * the key when we want to change the password on it. */ + /*memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES); + saved_mount_point = strdup(mount_point); + master_key_saved = 1; + printf("%s(): Master key saved\n", __FUNCTION__);*/ + rc = 0; + + // Upgrade if we're not using the latest KDF. + /*use_keymaster = keymaster_check_compatibility(); + if (crypt_ftr->kdf_type == KDF_SCRYPT_KEYMASTER) { + // Don't allow downgrade + } else if (use_keymaster == 1 && crypt_ftr->kdf_type != KDF_SCRYPT_KEYMASTER) { + crypt_ftr->kdf_type = KDF_SCRYPT_KEYMASTER; + upgrade = 1; + } else if (use_keymaster == 0 && crypt_ftr->kdf_type != KDF_SCRYPT) { + crypt_ftr->kdf_type = KDF_SCRYPT; + upgrade = 1; + } + + if (upgrade) { + rc = encrypt_master_key(passwd, crypt_ftr->salt, saved_master_key, + crypt_ftr->master_key, crypt_ftr); + if (!rc) { + rc = put_crypt_ftr_and_key(crypt_ftr); + } + printf("Key Derivation Function upgrade: rc=%d\n", rc); + + // Do not fail even if upgrade failed - machine is bootable + // Note that if this code is ever hit, there is a *serious* problem + // since KDFs should never fail. You *must* fix the kdf before + // proceeding! + if (rc) { + printf("Upgrade failed with error %d," + " but continuing with previous state\n", + rc); + rc = 0; + } + }*/ + } + + errout: + if (intermediate_key) { + memset(intermediate_key, 0, intermediate_key_size); + free(intermediate_key); + } + return rc; +} + +/* Called by vold when it wants to undo the crypto mapping of a volume it + * manages. This is usually in response to a factory reset, when we want + * to undo the crypto mapping so the volume is formatted in the clear. + */ +int cryptfs_revert_volume(const char *label) +{ + return delete_crypto_blk_dev((char *)label); +} + +int check_unmounted_and_get_ftr(struct crypt_mnt_ftr* crypt_ftr) +{ + char encrypted_state[PROPERTY_VALUE_MAX]; + property_get("ro.crypto.state", encrypted_state, ""); + if ( master_key_saved || strcmp(encrypted_state, "encrypted") ) { + printf("encrypted fs already validated or not running with encryption," + " aborting\n"); + //return -1; + } + + if (get_crypt_ftr_and_key(crypt_ftr)) { + printf("Error getting crypt footer and key\n"); + return -1; + } + + return 0; +} + +/* + * TODO - transition patterns to new format in calling code + * and remove this vile hack, and the use of hex in + * the password passing code. + * + * Patterns are passed in zero based (i.e. the top left dot + * is represented by zero, the top middle one etc), but we want + * to store them '1' based. + * This is to allow us to migrate the calling code to use this + * convention. It also solves a nasty problem whereby scrypt ignores + * trailing zeros, so patterns ending at the top left could be + * truncated, and similarly, you could add the top left to any + * pattern and still match. + * adjust_passwd is a hack function that returns the alternate representation + * if the password appears to be a pattern (hex numbers all less than 09) + * If it succeeds we need to try both, and in particular try the alternate + * first. If the original matches, then we need to update the footer + * with the alternate. + * All code that accepts passwords must adjust them first. Since + * cryptfs_check_passwd is always the first function called after a migration + * (and indeed on any boot) we only need to do the double try in this + * function. + */ +char* adjust_passwd(const char* passwd) +{ + size_t index, length; + + if (!passwd) { + return 0; + } + + // Check even length. Hex encoded passwords are always + // an even length, since each character encodes to two characters. + length = strlen(passwd); + if (length % 2) { + printf("Password not correctly hex encoded."); + return 0; + } + + // Check password is old-style pattern - a collection of hex + // encoded bytes less than 9 (00 through 08) + for (index = 0; index < length; index +=2) { + if (passwd[index] != '0' + || passwd[index + 1] < '0' || passwd[index + 1] > '8') { + return 0; + } + } + + // Allocate room for adjusted passwd and null terminate + char* adjusted = malloc(length + 1); + adjusted[length] = 0; + + // Add 0x31 ('1') to each character + for (index = 0; index < length; index += 2) { + // output is 31 through 39 so set first byte to three, second to src + 1 + adjusted[index] = '3'; + adjusted[index + 1] = passwd[index + 1] + 1; + } + + return adjusted; +} + +/* + * Passwords in L get passed from Android to cryptfs in hex, so a '1' + * gets converted to '31' where 31 is 0x31 which is the ascii character + * code in hex of the character '1'. This function will convert the + * regular character codes to their hexadecimal representation to make + * decrypt work properly with Android 5.0 lollipop decryption. + */ +char* hexadj_passwd(const char* passwd) +{ + size_t index, length; + char* ptr = passwd; + + if (!passwd) { + return 0; + } + + length = strlen(passwd); + + // Allocate room for hex passwd and null terminate + char* hex = malloc((length * 2) + 1); + hex[length * 2] = 0; + + // Convert to hex + for (index = 0; index < length; index++) { + sprintf(hex + (index * 2), "%02X", *ptr); + ptr++; + } + + return hex; +} + +int cryptfs_check_footer() +{ + int rc = -1; + struct crypt_mnt_ftr crypt_ftr; + + rc = get_crypt_ftr_and_key(&crypt_ftr); + + return rc; +} + +int cryptfs_check_passwd(char *passwd) +{ + struct crypt_mnt_ftr crypt_ftr; + int rc; + + rc = check_unmounted_and_get_ftr(&crypt_ftr); + if (rc) + return rc; + + char* adjusted_passwd = adjust_passwd(passwd); + char* hex_passwd = hexadj_passwd(passwd); + + if (adjusted_passwd) { + int failed_decrypt_count = crypt_ftr.failed_decrypt_count; + rc = test_mount_encrypted_fs(&crypt_ftr, adjusted_passwd, + DATA_MNT_POINT, "userdata"); + + // Maybe the original one still works? + if (rc) { + // Don't double count this failure + crypt_ftr.failed_decrypt_count = failed_decrypt_count; + rc = test_mount_encrypted_fs(&crypt_ftr, passwd, + DATA_MNT_POINT, "userdata"); + if (!rc) { + // cryptfs_changepw also adjusts so pass original + // Note that adjust_passwd only recognises patterns + // so we can safely use CRYPT_TYPE_PATTERN + printf("TWRP NOT Updating pattern to new format"); + //cryptfs_changepw(CRYPT_TYPE_PATTERN, passwd); + } else if (hex_passwd) { + rc = test_mount_encrypted_fs(&crypt_ftr, hex_passwd, + DATA_MNT_POINT, "userdata"); + } + } + free(adjusted_passwd); + } else { + rc = test_mount_encrypted_fs(&crypt_ftr, passwd, + DATA_MNT_POINT, "userdata"); + if (rc && hex_passwd) { + rc = test_mount_encrypted_fs(&crypt_ftr, hex_passwd, + DATA_MNT_POINT, "userdata"); + } + } + + if (hex_passwd) + free(hex_passwd); + + /*if (rc == 0 && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) { + printf("cryptfs_check_passwd update expiry time?\n"); + cryptfs_clear_password(); + password = strdup(passwd); + struct timespec now; + clock_gettime(CLOCK_BOOTTIME, &now); + password_expiry_time = now.tv_sec + password_max_age_seconds; + }*/ + + return rc; +} + +int cryptfs_verify_passwd(char *passwd) +{ + struct crypt_mnt_ftr crypt_ftr; + /* Allocate enough space for a 256 bit key, but we may use less */ + unsigned char decrypted_master_key[32]; + char encrypted_state[PROPERTY_VALUE_MAX]; + int rc; + + property_get("ro.crypto.state", encrypted_state, ""); + if (strcmp(encrypted_state, "encrypted") ) { + printf("device not encrypted, aborting"); + return -2; + } + + if (!master_key_saved) { + printf("encrypted fs not yet mounted, aborting"); + return -1; + } + + if (!saved_mount_point) { + printf("encrypted fs failed to save mount point, aborting"); + return -1; + } + + if (get_crypt_ftr_and_key(&crypt_ftr)) { + printf("Error getting crypt footer and key\n"); + return -1; + } + + if (crypt_ftr.flags & CRYPT_MNT_KEY_UNENCRYPTED) { + /* If the device has no password, then just say the password is valid */ + rc = 0; + } else { + char* adjusted_passwd = adjust_passwd(passwd); + if (adjusted_passwd) { + passwd = adjusted_passwd; + } + + decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0); + if (!memcmp(decrypted_master_key, saved_master_key, crypt_ftr.keysize)) { + /* They match, the password is correct */ + rc = 0; + } else { + /* If incorrect, sleep for a bit to prevent dictionary attacks */ + sleep(1); + rc = 1; + } + + free(adjusted_passwd); + } + + return rc; +} + +/* Initialize a crypt_mnt_ftr structure. The keysize is + * defaulted to 16 bytes, and the filesystem size to 0. + * Presumably, at a minimum, the caller will update the + * filesystem size and crypto_type_name after calling this function. + */ +static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr) +{ + off64_t off; + + memset(ftr, 0, sizeof(struct crypt_mnt_ftr)); + ftr->magic = CRYPT_MNT_MAGIC; + ftr->major_version = CURRENT_MAJOR_VERSION; + ftr->minor_version = CURRENT_MINOR_VERSION; + ftr->ftr_size = sizeof(struct crypt_mnt_ftr); + ftr->keysize = KEY_LEN_BYTES; + + switch (keymaster_check_compatibility()) { + case 1: + ftr->kdf_type = KDF_SCRYPT_KEYMASTER; + break; + + case 0: + ftr->kdf_type = KDF_SCRYPT; + break; + + default: + printf("keymaster_check_compatibility failed"); + return -1; + } + + get_device_scrypt_params(ftr); + + ftr->persist_data_size = CRYPT_PERSIST_DATA_SIZE; + if (get_crypt_ftr_info(NULL, &off) == 0) { + ftr->persist_data_offset[0] = off + CRYPT_FOOTER_TO_PERSIST_OFFSET; + ftr->persist_data_offset[1] = off + CRYPT_FOOTER_TO_PERSIST_OFFSET + + ftr->persist_data_size; + } + + return 0; +} + +/* Returns type of the password, default, pattern, pin or password. + */ +int cryptfs_get_password_type(void) +{ + struct crypt_mnt_ftr crypt_ftr; + + if (get_crypt_ftr_and_key(&crypt_ftr)) { + printf("Error getting crypt footer and key\n"); + return -1; + } + + if (crypt_ftr.flags & CRYPT_INCONSISTENT_STATE) { + return -1; + } + + return crypt_ftr.crypt_type; +} diff --git a/crypto/lollipop/cryptfs.h b/crypto/lollipop/cryptfs.h new file mode 100644 index 000000000..bc8b463ee --- /dev/null +++ b/crypto/lollipop/cryptfs.h @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2010 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 structure starts 16,384 bytes before the end of a hardware + * 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 if the crypt_mnt_ftr lives at the end of the + * partition. + */ + +#include <cutils/properties.h> +#include "openssl/sha.h" + +/* The current cryptfs version */ +#define CURRENT_MAJOR_VERSION 1 +#define CURRENT_MINOR_VERSION 3 + +#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 SCRYPT_LEN 32 + +/* definitions of flags in the structure below */ +#define CRYPT_MNT_KEY_UNENCRYPTED 0x1 /* The key for the partition is not encrypted. */ +#define CRYPT_ENCRYPTION_IN_PROGRESS 0x2 /* Encryption partially completed, + encrypted_upto valid*/ +#define CRYPT_INCONSISTENT_STATE 0x4 /* Set when starting encryption, clear when + exit cleanly, either through success or + correctly marked partial encryption */ +#define CRYPT_DATA_CORRUPT 0x8 /* Set when encryption is fine, but the + underlying volume is corrupt */ + +/* Allowed values for type in the structure below */ +#define CRYPT_TYPE_PASSWORD 0 /* master_key is encrypted with a password + * Must be zero to be compatible with pre-L + * devices where type is always password.*/ +#define CRYPT_TYPE_DEFAULT 1 /* master_key is encrypted with default + * password */ +#define CRYPT_TYPE_PATTERN 2 /* master_key is encrypted with a pattern */ +#define CRYPT_TYPE_PIN 3 /* master_key is encrypted with a pin */ +#define CRYPT_TYPE_MAX_TYPE 3 /* type cannot be larger than this value */ + +#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 +/* TODO(paullawrence): Remove KDF_SCRYPT_KEYMASTER_UNPADDED and KDF_SCRYPT_KEYMASTER_BADLY_PADDED + * when it is safe to do so. */ +#define KDF_SCRYPT_KEYMASTER_UNPADDED 3 +#define KDF_SCRYPT_KEYMASTER_BADLY_PADDED 4 +#define KDF_SCRYPT_KEYMASTER 5 + +/* Maximum allowed keymaster blob size. */ +#define KEYMASTER_BLOB_SIZE 2048 + +/* __le32 and __le16 defined in system/extras/ext4_utils/ext4_utils.h */ +#define __le8 unsigned char + +struct crypt_mnt_ftr { + __le32 magic; /* See above */ + __le16 major_version; + __le16 minor_version; + __le32 ftr_size; /* in bytes, not including key following */ + __le32 flags; /* See above */ + __le32 keysize; /* in bytes */ + __le32 crypt_type; /* how master_key is encrypted. Must be a + * CRYPT_TYPE_XXX value */ + __le64 fs_size; /* Size of the encrypted fs, in 512 byte sectors */ + __le32 failed_decrypt_count; /* count of # of failed attempts to decrypt and + mount, set to 0 on successful mount */ + 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) */ + __le64 encrypted_upto; /* If we are in state CRYPT_ENCRYPTION_IN_PROGRESS and + we have to stop (e.g. power low) this is the last + encrypted 512 byte sector.*/ + __le8 hash_first_block[SHA256_DIGEST_LENGTH]; /* When CRYPT_ENCRYPTION_IN_PROGRESS + set, hash of first block, used + to validate before continuing*/ + + /* key_master key, used to sign the derived key which is then used to generate + * the intermediate key + * This key should be used for no other purposes! We use this key to sign unpadded + * data, which is acceptable but only if the key is not reused elsewhere. */ + __le8 keymaster_blob[KEYMASTER_BLOB_SIZE]; + __le32 keymaster_blob_size; + + /* Store scrypt of salted intermediate key. When decryption fails, we can + check if this matches, and if it does, we know that the problem is with the + drive, and there is no point in asking the user for more passwords. + + Note that if any part of this structure is corrupt, this will not match and + we will continue to believe the user entered the wrong password. In that + case the only solution is for the user to enter a password enough times to + force a wipe. + + Note also that there is no need to worry about migration. If this data is + wrong, we simply won't recognise a right password, and will continue to + prompt. On the first password change, this value will be populated and + then we will be OK. + */ + unsigned char scrypted_intermediate_key[SCRYPT_LEN]; +}; + +/* 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 { + unsigned int size; + unsigned int flags; + struct crypt_mnt_ftr crypt_ftr; + char mnt_point[256]; + char blk_dev[256]; + char crypto_blkdev[256]; + char label[256]; +}; +#define VOL_NONREMOVABLE 0x1 +#define VOL_ENCRYPTABLE 0x2 +#define VOL_PRIMARY 0x4 +#define VOL_PROVIDES_ASEC 0x8 + +#define DATA_MNT_POINT "/data" + +/* Return values for cryptfs_crypto_complete */ +#define CRYPTO_COMPLETE_NOT_ENCRYPTED 1 +#define CRYPTO_COMPLETE_ENCRYPTED 0 +#define CRYPTO_COMPLETE_BAD_METADATA -1 +#define CRYPTO_COMPLETE_PARTIAL -2 +#define CRYPTO_COMPLETE_INCONSISTENT -3 +#define CRYPTO_COMPLETE_CORRUPT -4 + +/* Return values for cryptfs_enable_inplace*() */ +#define ENABLE_INPLACE_OK 0 +#define ENABLE_INPLACE_ERR_OTHER -1 +#define ENABLE_INPLACE_ERR_DEV -2 /* crypto_blkdev issue */ + +#ifdef __cplusplus +extern "C" { +#endif + + typedef int (*kdf_func)(const char *passwd, const unsigned char *salt, + unsigned char *ikey, void *params); + + void set_partition_data(const char* block_device, const char* key_location, const char* fs); + int cryptfs_check_footer(); + int cryptfs_check_passwd(char *pw); + int cryptfs_verify_passwd(char *newpw); + int cryptfs_get_password_type(void); + int delete_crypto_blk_dev(char *name); +#ifdef __cplusplus +} +#endif diff --git a/crypto/scrypt/Android.mk b/crypto/scrypt/Android.mk new file mode 100644 index 000000000..4514f9467 --- /dev/null +++ b/crypto/scrypt/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH := $(call my-dir) + +# Enable to be able to use ALOG* with #include "cutils/log.h" +#log_c_includes += system/core/include +#log_shared_libraries := liblog + +# These makefiles are here instead of being Android.mk files in the +# respective crypto, ssl, and apps directories so +# that import_openssl.sh import won't remove them. +include $(LOCAL_PATH)/build-config.mk +include $(LOCAL_PATH)/Scrypt.mk + +include $(LOCAL_PATH)/tests/Android.mk diff --git a/crypto/scrypt/MODULE_LICENSE_BSD_LIKE b/crypto/scrypt/MODULE_LICENSE_BSD_LIKE new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/crypto/scrypt/MODULE_LICENSE_BSD_LIKE diff --git a/crypto/scrypt/NOTICE b/crypto/scrypt/NOTICE new file mode 100644 index 000000000..b0b9311e6 --- /dev/null +++ b/crypto/scrypt/NOTICE @@ -0,0 +1,36 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +/* + * version 20110505 + * D. J. Bernstein + * Public domain. + * + * Based on crypto_core/salsa208/armneon/core.c from SUPERCOP 20130419 + */ diff --git a/crypto/scrypt/Scrypt-config.mk b/crypto/scrypt/Scrypt-config.mk new file mode 100644 index 000000000..bbe10631e --- /dev/null +++ b/crypto/scrypt/Scrypt-config.mk @@ -0,0 +1,105 @@ +# Auto-generated - DO NOT EDIT! +# To regenerate, edit scrypt.config, then run: +# ./import_scrypt.sh import /path/to/scrypt-1.1.6.tar.gz +# +# Before including this file, the local Android.mk must define the following +# variables: +# +# local_c_flags +# local_c_includes +# local_additional_dependencies +# +# This script will define the following variables: +# +# target_c_flags +# target_c_includes +# target_src_files +# +# host_c_flags +# host_c_includes +# host_src_files +# + +# Ensure these are empty. +unknown_arch_c_flags := +unknown_arch_src_files := +unknown_arch_exclude_files := + + +common_c_flags := + +common_src_files := \ + lib/crypto/crypto_scrypt-ref.c \ + +common_c_includes := \ + lib/crypto \ + lib/util \ + +arm_c_flags := + +arm_src_files := + +arm_exclude_files := + +arm_neon_c_flags := + +arm_neon_src_files := \ + lib/crypto/crypto_scrypt-neon.c \ + +arm_neon_exclude_files := \ + lib/crypto/crypto_scrypt-ref.c \ + +x86_c_flags := + +x86_src_files := \ + lib/crypto/crypto_scrypt-sse.c \ + +x86_exclude_files := \ + lib/crypto/crypto_scrypt-ref.c \ + +x86_64_c_flags := + +x86_64_src_files := \ + lib/crypto/crypto_scrypt-sse.c \ + +x86_64_exclude_files := \ + lib/crypto/crypto_scrypt-ref.c \ + +mips_c_flags := + +mips_src_files := + +mips_exclude_files := + +target_arch := $(TARGET_ARCH) +ifeq ($(target_arch)-$(TARGET_HAS_BIGENDIAN),mips-true) +target_arch := unknown_arch +endif + +target_c_flags := $(common_c_flags) $($(target_arch)_c_flags) $(local_c_flags) +target_c_includes := $(addprefix 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)/Scrypt-config.mk + diff --git a/crypto/scrypt/Scrypt.mk b/crypto/scrypt/Scrypt.mk new file mode 100644 index 000000000..d2a2fa413 --- /dev/null +++ b/crypto/scrypt/Scrypt.mk @@ -0,0 +1,46 @@ +local_c_flags := -DUSE_OPENSSL_PBKDF2 + +local_c_includes := $(log_c_includes) external/openssl/include + +local_additional_dependencies := $(LOCAL_PATH)/android-config.mk $(LOCAL_PATH)/Scrypt.mk + +include $(LOCAL_PATH)/Scrypt-config.mk + +####################################### +# target static library +include $(CLEAR_VARS) +include $(LOCAL_PATH)/android-config.mk + +LOCAL_SHARED_LIBRARIES := $(log_shared_libraries) + +# If we're building an unbundled build, don't try to use clang since it's not +# in the NDK yet. This can be removed when a clang version that is fast enough +# in the NDK. +ifeq (,$(TARGET_BUILD_APPS)) +LOCAL_CLANG := true +else +LOCAL_SDK_VERSION := 9 +endif + +LOCAL_SRC_FILES += $(target_src_files) +LOCAL_CFLAGS += $(target_c_flags) +LOCAL_C_INCLUDES += $(target_c_includes) $(commands_recovery_local_path)/crypto/scrypt/lib/util +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) $(commands_recovery_local_path)/crypto/scrypt/lib/util +LOCAL_LDLIBS += -ldl +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE:= libscrypttwrp_static +LOCAL_ADDITIONAL_DEPENDENCIES := $(local_additional_dependencies) +include $(BUILD_HOST_STATIC_LIBRARY) diff --git a/crypto/scrypt/android-config.mk b/crypto/scrypt/android-config.mk new file mode 100644 index 000000000..326e1134e --- /dev/null +++ b/crypto/scrypt/android-config.mk @@ -0,0 +1,16 @@ +# +# These flags represent the build-time configuration of scrypt for Android +# +# The value of $(scrypt_cflags) was pruned from the Makefile generated +# by running ./configure from import_scrypt.sh. +# +# This script performs minor but required patching for the Android build. +# + +LOCAL_CFLAGS += $(scrypt_cflags) + +# Add in flags to let config.h be read properly +LOCAL_CFLAGS += "-DHAVE_CONFIG_H" + +# Add clang here when it works on host +# LOCAL_CLANG := true diff --git a/crypto/scrypt/build-config.mk b/crypto/scrypt/build-config.mk new file mode 100644 index 000000000..3d2ab9195 --- /dev/null +++ b/crypto/scrypt/build-config.mk @@ -0,0 +1,6 @@ +# Auto-generated - DO NOT EDIT! +# To regenerate, edit scrypt.config, then run: +# ./import_scrypt.sh import /path/to/scrypt-1.1.6.tar.gz +# +scrypt_cflags := \ + diff --git a/crypto/scrypt/config.h b/crypto/scrypt/config.h new file mode 100644 index 000000000..3514f398e --- /dev/null +++ b/crypto/scrypt/config.h @@ -0,0 +1,99 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `clock_gettime' function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the declaration of `be64enc', and to 0 if you + don't. */ +#define HAVE_DECL_BE64ENC 0 + +/* Define to 1 if you have the <err.h> header file. */ +#define HAVE_ERR_H 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `rt' library (-lrt). */ +#define HAVE_LIBRT 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `posix_memalign' function. */ +#define HAVE_POSIX_MEMALIGN 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if the system has the type `struct sysinfo'. */ +#define HAVE_STRUCT_SYSINFO 1 + +/* Define to 1 if `mem_unit' is member of `struct sysinfo'. */ +#define HAVE_STRUCT_SYSINFO_MEM_UNIT 1 + +/* Define to 1 if `totalram' is member of `struct sysinfo'. */ +#define HAVE_STRUCT_SYSINFO_TOTALRAM 1 + +/* Define to 1 if the OS has a hw.usermem sysctl */ +/* #undef HAVE_SYSCTL_HW_USERMEM */ + +/* Define to 1 if you have the `sysinfo' function. */ +#define HAVE_SYSINFO 1 + +/* Define to 1 if you have the <sys/endian.h> header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the <sys/param.h> header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/sysinfo.h> header file. */ +#define HAVE_SYS_SYSINFO_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "scrypt" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "scrypt" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "scrypt 1.1.6" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "scrypt" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.1.6" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.1.6" + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ diff --git a/crypto/scrypt/import_scrypt.sh b/crypto/scrypt/import_scrypt.sh new file mode 100755 index 000000000..324eae64b --- /dev/null +++ b/crypto/scrypt/import_scrypt.sh @@ -0,0 +1,493 @@ +#!/bin/bash +# +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +# This script imports new versions of scrypt (http://www.tarsnap.com/scrypt/) into the +# Android source tree. To run, (1) fetch the appropriate tarball from the scrypt repository, +# (2) check the gpg/pgp signature, and then (3) run: +# ./import_scrypt.sh import scrypt-*.tar.gz +# +# IMPORTANT: See README.android for additional details. + +# turn on exit on error as well as a warning when it happens +set -e +set -x +trap "echo WARNING: Exiting on non-zero subprocess exit code" ERR; + +# Ensure consistent sorting order / tool output. +export LANG=C +export LC_ALL=C + +export DIRNAME=$(dirname $0) + +function die() { + declare -r message=$1 + + echo $message + exit 1 +} + +function usage() { + declare -r message=$1 + + if [ ! "$message" = "" ]; then + echo $message + fi + echo "Usage:" + echo " ./import_scrypt.sh import </path/to/scrypt-*.tar.gz>" + echo " ./import_scrypt.sh regenerate <patch/*.patch>" + echo " ./import_scrypt.sh generate <patch/*.patch> </path/to/scrypt-*.tar.gz>" + exit 1 +} + +function main() { + if [ ! -d patches ]; then + die "scrypt patch directory patches/ not found" + fi + + if [ ! -f scrypt.version ]; then + die "scrypt.version not found" + fi + + source $DIRNAME/scrypt.version + if [ "$SCRYPT_VERSION" == "" ]; then + die "Invalid scrypt.version; see README.android for more information" + fi + + SCRYPT_DIR=scrypt-$SCRYPT_VERSION + SCRYPT_DIR_ORIG=$SCRYPT_DIR.orig + + if [ ! -f scrypt.config ]; then + die "scrypt.config not found" + fi + + source $DIRNAME/scrypt.config + if [ "$CONFIGURE_ARGS" == "" -o "$UNNEEDED_SOURCES" == "" -o "$NEEDED_SOURCES" == "" ]; then + die "Invalid scrypt.config; see README.android for more information" + fi + + declare -r command=$1 + shift || usage "No command specified. Try import, regenerate, or generate." + if [ "$command" = "import" ]; then + declare -r tar=$1 + shift || usage "No tar file specified." + import $tar + elif [ "$command" = "regenerate" ]; then + declare -r patch=$1 + shift || usage "No patch file specified." + [ -d $SCRYPT_DIR ] || usage "$SCRYPT_DIR not found, did you mean to use generate?" + [ -d $SCRYPT_DIR_ORIG_ORIG ] || usage "$SCRYPT_DIR_ORIG not found, did you mean to use generate?" + regenerate $patch + elif [ "$command" = "generate" ]; then + declare -r patch=$1 + shift || usage "No patch file specified." + declare -r tar=$1 + shift || usage "No tar file specified." + generate $patch $tar + else + usage "Unknown command specified $command. Try import, regenerate, or generate." + fi +} + +# Compute the name of an assembly source file generated by one of the +# gen_asm_xxxx() functions below. The logic is the following: +# - if "$2" is not empty, output it directly +# - otherwise, change the file extension of $1 from .pl to .S and output +# it. +# Usage: default_asm_file "$1" "$2" +# or default_asm_file "$@" +# +# $1: generator path (perl script) +# $2: optional output file name. +function default_asm_file () { + if [ "$2" ]; then + echo "$2" + else + echo "${1%%.pl}.S" + fi +} + +# Generate an ARM assembly file. +# $1: generator (perl script) +# $2: [optional] output file name +function gen_asm_arm () { + local OUT + OUT=$(default_asm_file "$@") + perl "$1" > "$OUT" +} + +function gen_asm_mips () { + local OUT + OUT=$(default_asm_file "$@") + # The perl scripts expect to run the target compiler as $CC to determine + # the endianess of the target. Setting CC to true is a hack that forces the scripts + # to generate little endian output + CC=true perl "$1" o32 > "$OUT" +} + +function gen_asm_x86 () { + local OUT + OUT=$(default_asm_file "$@") + perl "$1" elf -fPIC > "$OUT" +} + +function gen_asm_x86_64 () { + local OUT + OUT=$(default_asm_file "$@") + perl "$1" elf "$OUT" > "$OUT" +} + + +# Filter all items in a list that match a given pattern. +# $1: space-separated list +# $2: egrep pattern. +# Out: items in $1 that match $2 +function filter_by_egrep() { + declare -r pattern=$1 + shift + echo "$@" | tr ' ' '\n' | grep -e "$pattern" | tr '\n' ' ' +} + +# Sort and remove duplicates in a space-separated list +# $1: space-separated list +# Out: new space-separated list +function uniq_sort () { + echo "$@" | tr ' ' '\n' | sort -u | tr '\n' ' ' +} + +function print_autogenerated_header() { + echo "# Auto-generated - DO NOT EDIT!" + echo "# To regenerate, edit scrypt.config, then run:" + echo "# ./import_scrypt.sh import /path/to/scrypt-$SCRYPT_VERSION.tar.gz" + echo "#" +} + +function generate_build_config_mk() { + ./configure $CONFIGURE_ARGS + #rm -f apps/CA.pl.bak crypto/scryptconf.h.bak + + declare -r tmpfile=$(mktemp) + (grep -e -D Makefile | grep -v CONFIGURE_ARGS= | grep -v OPTIONS=) > $tmpfile + + declare -r cflags=$(filter_by_egrep "^-D" $(grep -e "^CFLAG=" $tmpfile)) + declare -r depflags=$(filter_by_egrep "^-D" $(grep -e "^DEPFLAG=" $tmpfile)) + rm -f $tmpfile + + echo "Generating $(basename $1)" + ( + print_autogenerated_header + + echo "scrypt_cflags := \\" + for cflag in $cflags $depflags; do + echo " $cflag \\" + done + echo "" + ) > $1 +} + +# Return the value of a computed variable name. +# E.g.: +# FOO=foo +# BAR=bar +# echo $(var_value FOO_$BAR) -> prints the value of ${FOO_bar} +# $1: Variable name +# Out: variable value +var_value() { + # Note: don't use 'echo' here, because it's sensitive to values + # that begin with an underscore (e.g. "-n") + eval printf \"%s\\n\" \$$1 +} + +# Same as var_value, but returns sorted output without duplicates. +# $1: Variable name +# Out: variable value (if space-separated list, sorted with no duplicates) +var_sorted_value() { + uniq_sort $(var_value $1) +} + +# Print the definition of a given variable in a GNU Make build file. +# $1: Variable name (e.g. common_src_files) +# $2+: Variable value (e.g. list of sources) +print_vardef_in_mk() { + declare -r varname=$1 + shift + if [ -z "$1" ]; then + echo "$varname :=" + else + echo "$varname := \\" + for src; do + echo " $src \\" + done + fi + echo "" +} + +# Same as print_vardef_in_mk, but print a CFLAGS definition from +# a list of compiler defines. +# $1: Variable name (e.g. common_c_flags) +# $2: List of defines (e.g. SCRYPT_NO_DONKEYS ...) +print_defines_in_mk() { + declare -r varname=$1 + shift + if [ -z "$1" ]; then + echo "$varname :=" + else + echo "$varname := \\" + for def; do + echo " -D$def \\" + done + fi + echo "" +} + +# Generate a configuration file like Scrypt-config.mk +# This uses variable definitions from scrypt.config to build a config +# file that can compute the list of target- and host-specific sources / +# compiler flags for a given component. +# +# $1: Target file name. (e.g. Scrypt-config.mk) +function generate_config_mk() { + declare -r output="$1" + declare -r all_archs="arm arm_neon x86 x86_64 mips" + + echo "Generating $(basename $output)" + ( + print_autogenerated_header + echo \ +"# Before including this file, the local Android.mk must define the following +# variables: +# +# local_c_flags +# local_c_includes +# local_additional_dependencies +# +# This script will define the following variables: +# +# target_c_flags +# target_c_includes +# target_src_files +# +# host_c_flags +# host_c_includes +# host_src_files +# + +# Ensure these are empty. +unknown_arch_c_flags := +unknown_arch_src_files := +unknown_arch_exclude_files := + +" + common_defines=$(var_sorted_value SCRYPT_DEFINES) + print_defines_in_mk common_c_flags $common_defines + + common_sources=$(var_sorted_value SCRYPT_SOURCES) + print_vardef_in_mk common_src_files $common_sources + + common_includes=$(var_sorted_value SCRYPT_INCLUDES) + print_vardef_in_mk common_c_includes $common_includes + + for arch in $all_archs; do + arch_defines=$(var_sorted_value SCRYPT_DEFINES_${arch}) + print_defines_in_mk ${arch}_c_flags $arch_defines + + arch_sources=$(var_sorted_value SCRYPT_SOURCES_${arch}) + print_vardef_in_mk ${arch}_src_files $arch_sources + + arch_exclude_sources=$(var_sorted_value SCRYPT_SOURCES_EXCLUDES_${arch}) + print_vardef_in_mk ${arch}_exclude_files $arch_exclude_sources + + done + + echo "\ +target_arch := \$(TARGET_ARCH) +ifeq (\$(target_arch)-\$(TARGET_HAS_BIGENDIAN),mips-true) +target_arch := unknown_arch +endif + +target_c_flags := \$(common_c_flags) \$(\$(target_arch)_c_flags) \$(local_c_flags) +target_c_includes := \$(addprefix external/scrypt/,\$(common_c_includes)) \$(local_c_includes) +target_src_files := \$(common_src_files) \$(\$(target_arch)_src_files) +target_src_files := \$(filter-out \$(\$(target_arch)_exclude_files), \$(target_src_files)) + +# Hacks for ARM NEON support +ifeq (\$(target_arch),arm) +ifeq (\$(ARCH_ARM_HAVE_NEON),true) +target_c_flags += \$(arm_neon_c_flags) +target_src_files += \$(arm_neon_src_files) +target_src_files := \$(filter-out \$(arm_neon_exclude_files), \$(target_src_files)) +endif +endif + +ifeq (\$(HOST_OS)-\$(HOST_ARCH),linux-x86) +host_arch := x86 +else +host_arch := unknown_arch +endif + +host_c_flags := \$(common_c_flags) \$(\$(host_arch)_c_flags) \$(local_c_flags) +host_c_includes := \$(addprefix external/scrypt/,\$(common_c_includes)) \$(local_c_includes) +host_src_files := \$(common_src_files) \$(\$(host_arch)_src_files) +host_src_files := \$(filter-out \$(\$(host_arch)_exclude_files), \$(host_src_files)) + +local_additional_dependencies += \$(LOCAL_PATH)/$(basename $output) +" + + ) > "$output" +} + +function import() { + declare -r SCRYPT_SOURCE=$1 + + untar $SCRYPT_SOURCE readonly + applypatches $SCRYPT_DIR + + cd $SCRYPT_DIR + + generate_build_config_mk ../build-config.mk + + touch ../MODULE_LICENSE_BSD_LIKE + + cd .. + + generate_config_mk Scrypt-config.mk + + # Prune unnecessary sources + prune + + NEEDED_SOURCES="$NEEDED_SOURCES" + for i in $NEEDED_SOURCES; do + echo "Updating $i" + rm -r $i + mv $SCRYPT_DIR/$i . + done + + cleantar +} + +function regenerate() { + declare -r patch=$1 + + generatepatch $patch +} + +function generate() { + declare -r patch=$1 + declare -r SCRYPT_SOURCE=$2 + + untar $SCRYPT_SOURCE + applypatches $SCRYPT_DIR_ORIG $patch + prune + + for i in $NEEDED_SOURCES; do + echo "Restoring $i" + rm -r $SCRYPT_DIR/$i + cp -rf $i $SCRYPT_DIR/$i + done + + generatepatch $patch + cleantar +} + +# Find all files in a sub-directory that are encoded in ISO-8859 +# $1: Directory. +# Out: list of files in $1 that are encoded as ISO-8859. +function find_iso8859_files() { + find $1 -type f -print0 | xargs -0 file | fgrep "ISO-8859" | cut -d: -f1 +} + +# Convert all ISO-8859 files in a given subdirectory to UTF-8 +# $1: Directory name +function convert_iso8859_to_utf8() { + declare -r iso_files=$(find_iso8859_files "$1") + for iso_file in $iso_files; do + iconv --from-code iso-8859-1 --to-code utf-8 $iso_file > $iso_file.tmp + rm -f $iso_file + mv $iso_file.tmp $iso_file + done +} + +function untar() { + declare -r SCRYPT_SOURCE=$1 + declare -r readonly=$2 + + # Remove old source + cleantar + + # Process new source + tar -zxf $SCRYPT_SOURCE + convert_iso8859_to_utf8 $SCRYPT_DIR + cp -rfP $SCRYPT_DIR $SCRYPT_DIR_ORIG + if [ ! -z $readonly ]; then + find $SCRYPT_DIR_ORIG -type f -print0 | xargs -0 chmod a-w + fi +} + +function prune() { + echo "Removing $UNNEEDED_SOURCES" + (cd $SCRYPT_DIR_ORIG && rm -rf $UNNEEDED_SOURCES) + (cd $SCRYPT_DIR && rm -r $UNNEEDED_SOURCES) +} + +function cleantar() { + rm -rf $SCRYPT_DIR_ORIG + rm -rf $SCRYPT_DIR +} + +function applypatches () { + declare -r dir=$1 + declare -r skip_patch=$2 + + cd $dir + + # Apply appropriate patches + for i in $SCRYPT_PATCHES; do + if [ ! "$skip_patch" = "patches/$i" ]; then + echo "Applying patch $i" + patch -p1 --merge < ../patches/$i || die "Could not apply patches/$i. Fix source and run: $0 regenerate patches/$i" + else + echo "Skiping patch $i" + fi + + done + + # Cleanup patch output + find . \( -type f -o -type l \) -name "*.orig" -print0 | xargs -0 rm -f + + cd .. +} + +function generatepatch() { + declare -r patch=$1 + + # Cleanup stray files before generating patch + find $SCRYPT_DIR -type f -name "*.orig" -print0 | xargs -0 rm -f + find $SCRYPT_DIR -type f -name "*~" -print0 | xargs -0 rm -f + + declare -r variable_name=SCRYPT_PATCHES_`basename $patch .patch | sed s/-/_/`_SOURCES + # http://tldp.org/LDP/abs/html/ivr.html + eval declare -r sources=\$$variable_name + rm -f $patch + touch $patch + for i in $sources; do + LC_ALL=C TZ=UTC0 diff -aup $SCRYPT_DIR_ORIG/$i $SCRYPT_DIR/$i >> $patch && die "ERROR: No diff for patch $path in file $i" + done + echo "Generated patch $patch" + echo "NOTE To make sure there are not unwanted changes from conflicting patches, be sure to review the generated patch." +} + +main $@ diff --git a/crypto/scrypt/lib/README b/crypto/scrypt/lib/README new file mode 100644 index 000000000..3bb211e84 --- /dev/null +++ b/crypto/scrypt/lib/README @@ -0,0 +1,6 @@ +The source code under this directory is taken from the client for the +Tarsnap online backup system (and released under the 2-clause BSD license +with permission of the author); keeping this code in sync with the Tarsnap +code is highly desirable and explains why there is some functionality +included here which is not actually used by the scrypt file encryption +utility. diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-neon-salsa208.h b/crypto/scrypt/lib/crypto/crypto_scrypt-neon-salsa208.h new file mode 100644 index 000000000..a3b1019a7 --- /dev/null +++ b/crypto/scrypt/lib/crypto/crypto_scrypt-neon-salsa208.h @@ -0,0 +1,120 @@ +/* + * version 20110505 + * D. J. Bernstein + * Public domain. + * + * Based on crypto_core/salsa208/armneon/core.c from SUPERCOP 20130419 + */ + +#define ROUNDS 8 +static void +salsa20_8_intrinsic(void * input) +{ + int i; + + const uint32x4_t abab = {-1,0,-1,0}; + + /* + * This is modified since we only have one argument. Usually you'd rearrange + * the constant, key, and input bytes, but we just have one linear array to + * rearrange which is a bit easier. + */ + + /* + * Change the input to be diagonals as if it's a 4x4 matrix of 32-bit values. + */ + uint32x4_t x0x5x10x15; + uint32x4_t x12x1x6x11; + uint32x4_t x8x13x2x7; + uint32x4_t x4x9x14x3; + + uint32x4_t x0x1x10x11; + uint32x4_t x12x13x6x7; + uint32x4_t x8x9x2x3; + uint32x4_t x4x5x14x15; + + uint32x4_t x0x1x2x3; + uint32x4_t x4x5x6x7; + uint32x4_t x8x9x10x11; + uint32x4_t x12x13x14x15; + + x0x1x2x3 = vld1q_u8((uint8_t *) input); + x4x5x6x7 = vld1q_u8(16 + (uint8_t *) input); + x8x9x10x11 = vld1q_u8(32 + (uint8_t *) input); + x12x13x14x15 = vld1q_u8(48 + (uint8_t *) input); + + x0x1x10x11 = vcombine_u32(vget_low_u32(x0x1x2x3), vget_high_u32(x8x9x10x11)); + x4x5x14x15 = vcombine_u32(vget_low_u32(x4x5x6x7), vget_high_u32(x12x13x14x15)); + x8x9x2x3 = vcombine_u32(vget_low_u32(x8x9x10x11), vget_high_u32(x0x1x2x3)); + x12x13x6x7 = vcombine_u32(vget_low_u32(x12x13x14x15), vget_high_u32(x4x5x6x7)); + + x0x5x10x15 = vbslq_u32(abab,x0x1x10x11,x4x5x14x15); + x8x13x2x7 = vbslq_u32(abab,x8x9x2x3,x12x13x6x7); + x4x9x14x3 = vbslq_u32(abab,x4x5x14x15,x8x9x2x3); + x12x1x6x11 = vbslq_u32(abab,x12x13x6x7,x0x1x10x11); + + uint32x4_t start0 = x0x5x10x15; + uint32x4_t start1 = x12x1x6x11; + uint32x4_t start3 = x4x9x14x3; + uint32x4_t start2 = x8x13x2x7; + + /* From here on this should be the same as the SUPERCOP version. */ + + uint32x4_t diag0 = start0; + uint32x4_t diag1 = start1; + uint32x4_t diag2 = start2; + uint32x4_t diag3 = start3; + + uint32x4_t a0; + uint32x4_t a1; + uint32x4_t a2; + uint32x4_t a3; + + for (i = ROUNDS;i > 0;i -= 2) { + a0 = diag1 + diag0; + diag3 ^= vsriq_n_u32(vshlq_n_u32(a0,7),a0,25); + a1 = diag0 + diag3; + diag2 ^= vsriq_n_u32(vshlq_n_u32(a1,9),a1,23); + a2 = diag3 + diag2; + diag1 ^= vsriq_n_u32(vshlq_n_u32(a2,13),a2,19); + a3 = diag2 + diag1; + diag0 ^= vsriq_n_u32(vshlq_n_u32(a3,18),a3,14); + + diag3 = vextq_u32(diag3,diag3,3); + diag2 = vextq_u32(diag2,diag2,2); + diag1 = vextq_u32(diag1,diag1,1); + + a0 = diag3 + diag0; + diag1 ^= vsriq_n_u32(vshlq_n_u32(a0,7),a0,25); + a1 = diag0 + diag1; + diag2 ^= vsriq_n_u32(vshlq_n_u32(a1,9),a1,23); + a2 = diag1 + diag2; + diag3 ^= vsriq_n_u32(vshlq_n_u32(a2,13),a2,19); + a3 = diag2 + diag3; + diag0 ^= vsriq_n_u32(vshlq_n_u32(a3,18),a3,14); + + diag1 = vextq_u32(diag1,diag1,3); + diag2 = vextq_u32(diag2,diag2,2); + diag3 = vextq_u32(diag3,diag3,1); + } + + x0x5x10x15 = diag0 + start0; + x12x1x6x11 = diag1 + start1; + x8x13x2x7 = diag2 + start2; + x4x9x14x3 = diag3 + start3; + + x0x1x10x11 = vbslq_u32(abab,x0x5x10x15,x12x1x6x11); + x12x13x6x7 = vbslq_u32(abab,x12x1x6x11,x8x13x2x7); + x8x9x2x3 = vbslq_u32(abab,x8x13x2x7,x4x9x14x3); + x4x5x14x15 = vbslq_u32(abab,x4x9x14x3,x0x5x10x15); + + x0x1x2x3 = vcombine_u32(vget_low_u32(x0x1x10x11),vget_high_u32(x8x9x2x3)); + x4x5x6x7 = vcombine_u32(vget_low_u32(x4x5x14x15),vget_high_u32(x12x13x6x7)); + x8x9x10x11 = vcombine_u32(vget_low_u32(x8x9x2x3),vget_high_u32(x0x1x10x11)); + x12x13x14x15 = vcombine_u32(vget_low_u32(x12x13x6x7),vget_high_u32(x4x5x14x15)); + + vst1q_u8((uint8_t *) input,(uint8x16_t) x0x1x2x3); + vst1q_u8(16 + (uint8_t *) input,(uint8x16_t) x4x5x6x7); + vst1q_u8(32 + (uint8_t *) input,(uint8x16_t) x8x9x10x11); + vst1q_u8(48 + (uint8_t *) input,(uint8x16_t) x12x13x14x15); +} diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c b/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c new file mode 100644 index 000000000..a3bf052b4 --- /dev/null +++ b/crypto/scrypt/lib/crypto/crypto_scrypt-neon.c @@ -0,0 +1,305 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include <machine/cpu-features.h> +#include <arm_neon.h> + +#include <errno.h> +#include <stdint.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +#ifdef USE_OPENSSL_PBKDF2 +#include <openssl/evp.h> +#else +#include "sha256.h" +#endif +#include "sysendian.h" + +#include "crypto_scrypt.h" + +#include "crypto_scrypt-neon-salsa208.h" + +static void blkcpy(void *, void *, size_t); +static void blkxor(void *, void *, size_t); +void crypto_core_salsa208_armneon2(void *); +static void blockmix_salsa8(uint8x16_t *, uint8x16_t *, uint8x16_t *, size_t); +static uint64_t integerify(void *, size_t); +static void smix(uint8_t *, size_t, uint64_t, void *, void *); + +static void +blkcpy(void * dest, void * src, size_t len) +{ + uint8x16_t * D = dest; + uint8x16_t * S = src; + size_t L = len / 16; + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, void * src, size_t len) +{ + uint8x16_t * D = dest; + uint8x16_t * S = src; + size_t L = len / 16; + size_t i; + + for (i = 0; i < L; i++) + D[i] = veorq_u8(D[i], S[i]); +} + +/** + * blockmix_salsa8(B, Y, r): + * Compute B = BlockMix_{salsa20/8, r}(B). The input B must be 128r bytes in + * length; the temporary space Y must also be the same size. + */ +static void +blockmix_salsa8(uint8x16_t * Bin, uint8x16_t * Bout, uint8x16_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[8 * r - 4], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < r; i++) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8], 64); + salsa20_8_intrinsic((void *) X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 4], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8 + 4], 64); + salsa20_8_intrinsic((void *) X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[(r + i) * 4], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(void * B, size_t r) +{ + uint8_t * X = (void*)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (le64dec(X)); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage + * XY must be 256r bytes in length. The value N must be a power of 2. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY) +{ + uint8x16_t * X = XY; + uint8x16_t * Y = (void *)((uintptr_t)(XY) + 128 * r); + uint8x16_t * Z = (void *)((uintptr_t)(XY) + 256 * r); + uint32_t * X32 = (void *)X; + uint64_t i, j; + size_t k; + + /* 1: X <-- B */ + blkcpy(X, B, 128 * r); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r), + Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + blkcpy(B, X, 128 * r); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N == 0)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#ifndef MAP_ANON + if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#ifndef MAP_ANON + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#ifdef MAP_ANON + if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ +#ifdef USE_OPENSSL_PBKDF2 + PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B); +#else + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); +#endif + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ +#ifdef USE_OPENSSL_PBKDF2 + PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf); +#else + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); +#endif + + /* Free memory. */ +#ifdef MAP_ANON + if (munmap(V0, 128 * r * N)) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-ref.c b/crypto/scrypt/lib/crypto/crypto_scrypt-ref.c new file mode 100644 index 000000000..abe23eaa5 --- /dev/null +++ b/crypto/scrypt/lib/crypto/crypto_scrypt-ref.c @@ -0,0 +1,296 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#ifdef USE_OPENSSL_PBKDF2 +#include <openssl/evp.h> +#else +#include "sha256.h" +#endif +#include "sysendian.h" + +#include "crypto_scrypt.h" + +static void blkcpy(uint8_t *, uint8_t *, size_t); +static void blkxor(uint8_t *, uint8_t *, size_t); +static void salsa20_8(uint8_t[64]); +static void blockmix_salsa8(uint8_t *, uint8_t *, size_t); +static uint64_t integerify(uint8_t *, size_t); +static void smix(uint8_t *, size_t, uint64_t, uint8_t *, uint8_t *); + +static void +blkcpy(uint8_t * dest, uint8_t * src, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + dest[i] = src[i]; +} + +static void +blkxor(uint8_t * dest, uint8_t * src, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + dest[i] ^= src[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint8_t B[64]) +{ + uint32_t B32[16]; + uint32_t x[16]; + size_t i; + + /* Convert little-endian values in. */ + for (i = 0; i < 16; i++) + B32[i] = le32dec(&B[i * 4]); + + /* Compute x = doubleround^4(B32). */ + for (i = 0; i < 16; i++) + x[i] = B32[i]; + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + + /* Compute B32 = B32 + x. */ + for (i = 0; i < 16; i++) + B32[i] += x[i]; + + /* Convert little-endian values out. */ + for (i = 0; i < 16; i++) + le32enc(&B[4 * i], B32[i]); +} + +/** + * blockmix_salsa8(B, Y, r): + * Compute B = BlockMix_{salsa20/8, r}(B). The input B must be 128r bytes in + * length; the temporary space Y must also be the same size. + */ +static void +blockmix_salsa8(uint8_t * B, uint8_t * Y, size_t r) +{ + uint8_t X[64]; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &B[(2 * r - 1) * 64], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i++) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &B[i * 64], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + blkcpy(&Y[i * 64], X, 64); + } + + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + for (i = 0; i < r; i++) + blkcpy(&B[i * 64], &Y[(i * 2) * 64], 64); + for (i = 0; i < r; i++) + blkcpy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64); +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(uint8_t * B, size_t r) +{ + uint8_t * X = &B[(2 * r - 1) * 64]; + + return (le64dec(X)); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage + * XY must be 256r bytes in length. The value N must be a power of 2. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint8_t * V, uint8_t * XY) +{ + uint8_t * X = XY; + uint8_t * Y = &XY[128 * r]; + uint64_t i; + uint64_t j; + + /* 1: X <-- B */ + blkcpy(X, B, 128 * r); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i++) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (128 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i++) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (128 * r)], 128 * r); + blockmix_salsa8(X, Y, r); + } + + /* 10: B' <-- X */ + blkcpy(B, X, 128 * r); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + uint8_t * B; + uint8_t * V; + uint8_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N == 0)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ + if ((B = malloc(128 * r * p)) == NULL) + goto err0; + if ((XY = malloc(256 * r)) == NULL) + goto err1; + if ((V = malloc(128 * r * N)) == NULL) + goto err2; + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ +#ifdef USE_OPENSSL_PBKDF2 + PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B); +#else + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); +#endif + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ +#ifdef USE_OPENSSL_PBKDF2 + PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf); +#else + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); +#endif + + /* Free memory. */ + free(V); + free(XY); + free(B); + + /* Success! */ + return (0); + +err2: + free(XY); +err1: + free(B); +err0: + /* Failure! */ + return (-1); +} diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt-sse.c b/crypto/scrypt/lib/crypto/crypto_scrypt-sse.c new file mode 100644 index 000000000..dd18f291c --- /dev/null +++ b/crypto/scrypt/lib/crypto/crypto_scrypt-sse.c @@ -0,0 +1,378 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include "scrypt_platform.h" + +#include <sys/types.h> +#include <sys/mman.h> + +#include <emmintrin.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#ifdef USE_OPENSSL_PBKDF2 +#include <openssl/evp.h> +#else +#include "sha256.h" +#endif +#include "sysendian.h" + +#include "crypto_scrypt.h" + +static void blkcpy(void *, void *, size_t); +static void blkxor(void *, void *, size_t); +static void salsa20_8(__m128i *); +static void blockmix_salsa8(__m128i *, __m128i *, __m128i *, size_t); +static uint64_t integerify(void *, size_t); +static void smix(uint8_t *, size_t, uint64_t, void *, void *); + +static void +blkcpy(void * dest, void * src, size_t len) +{ + __m128i * D = dest; + __m128i * S = src; + size_t L = len / 16; + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, void * src, size_t len) +{ + __m128i * D = dest; + __m128i * S = src; + size_t L = len / 16; + size_t i; + + for (i = 0; i < L; i++) + D[i] = _mm_xor_si128(D[i], S[i]); +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(__m128i B[4]) +{ + __m128i X0, X1, X2, X3; + __m128i T; + size_t i; + + X0 = B[0]; + X1 = B[1]; + X2 = B[2]; + X3 = B[3]; + + for (i = 0; i < 8; i += 2) { + /* Operate on "columns". */ + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + + /* Operate on "rows". */ + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + } + + B[0] = _mm_add_epi32(B[0], X0); + B[1] = _mm_add_epi32(B[1], X1); + B[2] = _mm_add_epi32(B[2], X2); + B[3] = _mm_add_epi32(B[3], X3); +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(__m128i * Bin, __m128i * Bout, __m128i * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[8 * r - 4], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < r; i++) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 4], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8 + 4], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[(r + i) * 4], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(void * B, size_t r) +{ + uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[13]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY) +{ + __m128i * X = XY; + __m128i * Y = (void *)((uintptr_t)(XY) + 128 * r); + __m128i * Z = (void *)((uintptr_t)(XY) + 256 * r); + uint32_t * X32 = (void *)X; + uint64_t i, j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X32[k * 16 + i] = + le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r), + Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], + X32[k * 16 + i]); + } + } +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N == 0)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > (SIZE_MAX - 64) / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#ifndef MAP_ANON + if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#ifndef MAP_ANON + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#ifdef MAP_ANON + if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ +#ifdef USE_OPENSSL_PBKDF2 + PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B); +#else + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); +#endif + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ +#ifdef USE_OPENSSL_PBKDF2 + PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf); +#else + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); +#endif + + /* Free memory. */ +#ifdef MAP_ANON + if (munmap(V0, 128 * r * N)) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} diff --git a/crypto/scrypt/lib/crypto/crypto_scrypt.h b/crypto/scrypt/lib/crypto/crypto_scrypt.h new file mode 100644 index 000000000..f72e1f4b0 --- /dev/null +++ b/crypto/scrypt/lib/crypto/crypto_scrypt.h @@ -0,0 +1,46 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _CRYPTO_SCRYPT_H_ +#define _CRYPTO_SCRYPT_H_ + +#include <stdint.h> + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int crypto_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, + uint32_t, uint32_t, uint8_t *, size_t); + +#endif /* !_CRYPTO_SCRYPT_H_ */ diff --git a/crypto/scrypt/lib/util/sysendian.h b/crypto/scrypt/lib/util/sysendian.h new file mode 100644 index 000000000..62ef31a42 --- /dev/null +++ b/crypto/scrypt/lib/util/sysendian.h @@ -0,0 +1,140 @@ +/*- + * Copyright 2007-2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +#include "scrypt_platform.h" + +/* If we don't have be64enc, the <sys/endian.h> we have isn't usable. */ +#if !HAVE_DECL_BE64ENC +#undef HAVE_SYS_ENDIAN_H +#endif + +#ifdef HAVE_SYS_ENDIAN_H + +#include <sys/endian.h> + +#else + +#include <stdint.h> + +static inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static inline uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static inline void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static inline uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static inline uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); +} + +static inline void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} +#endif /* !HAVE_SYS_ENDIAN_H */ + +#endif /* !_SYSENDIAN_H_ */ diff --git a/crypto/scrypt/patches/README b/crypto/scrypt/patches/README new file mode 100644 index 000000000..353ddbbc7 --- /dev/null +++ b/crypto/scrypt/patches/README @@ -0,0 +1,11 @@ +bionic.patch: + +Allows scrypt to compile against bionic. + +use_openssl_pbkdf2.patch: + +Uses the PBKDF2 function from OpenSSL (it uses accelerated SHA256) + +arm-neon.patch: + +Adds NEON acceleration for the Salsa20/8 mixing function. diff --git a/crypto/scrypt/patches/arm-neon.patch b/crypto/scrypt/patches/arm-neon.patch new file mode 100644 index 000000000..7197f9968 --- /dev/null +++ b/crypto/scrypt/patches/arm-neon.patch @@ -0,0 +1,437 @@ +diff --git a/lib/crypto/crypto_scrypt-neon-salsa208.h b/lib/crypto/crypto_scrypt-neon-salsa208.h +new file mode 100644 +index 0000000..a3b1019 +--- /dev/null ++++ b/lib/crypto/crypto_scrypt-neon-salsa208.h +@@ -0,0 +1,120 @@ ++/* ++ * version 20110505 ++ * D. J. Bernstein ++ * Public domain. ++ * ++ * Based on crypto_core/salsa208/armneon/core.c from SUPERCOP 20130419 ++ */ ++ ++#define ROUNDS 8 ++static void ++salsa20_8_intrinsic(void * input) ++{ ++ int i; ++ ++ const uint32x4_t abab = {-1,0,-1,0}; ++ ++ /* ++ * This is modified since we only have one argument. Usually you'd rearrange ++ * the constant, key, and input bytes, but we just have one linear array to ++ * rearrange which is a bit easier. ++ */ ++ ++ /* ++ * Change the input to be diagonals as if it's a 4x4 matrix of 32-bit values. ++ */ ++ uint32x4_t x0x5x10x15; ++ uint32x4_t x12x1x6x11; ++ uint32x4_t x8x13x2x7; ++ uint32x4_t x4x9x14x3; ++ ++ uint32x4_t x0x1x10x11; ++ uint32x4_t x12x13x6x7; ++ uint32x4_t x8x9x2x3; ++ uint32x4_t x4x5x14x15; ++ ++ uint32x4_t x0x1x2x3; ++ uint32x4_t x4x5x6x7; ++ uint32x4_t x8x9x10x11; ++ uint32x4_t x12x13x14x15; ++ ++ x0x1x2x3 = vld1q_u8((uint8_t *) input); ++ x4x5x6x7 = vld1q_u8(16 + (uint8_t *) input); ++ x8x9x10x11 = vld1q_u8(32 + (uint8_t *) input); ++ x12x13x14x15 = vld1q_u8(48 + (uint8_t *) input); ++ ++ x0x1x10x11 = vcombine_u32(vget_low_u32(x0x1x2x3), vget_high_u32(x8x9x10x11)); ++ x4x5x14x15 = vcombine_u32(vget_low_u32(x4x5x6x7), vget_high_u32(x12x13x14x15)); ++ x8x9x2x3 = vcombine_u32(vget_low_u32(x8x9x10x11), vget_high_u32(x0x1x2x3)); ++ x12x13x6x7 = vcombine_u32(vget_low_u32(x12x13x14x15), vget_high_u32(x4x5x6x7)); ++ ++ x0x5x10x15 = vbslq_u32(abab,x0x1x10x11,x4x5x14x15); ++ x8x13x2x7 = vbslq_u32(abab,x8x9x2x3,x12x13x6x7); ++ x4x9x14x3 = vbslq_u32(abab,x4x5x14x15,x8x9x2x3); ++ x12x1x6x11 = vbslq_u32(abab,x12x13x6x7,x0x1x10x11); ++ ++ uint32x4_t start0 = x0x5x10x15; ++ uint32x4_t start1 = x12x1x6x11; ++ uint32x4_t start3 = x4x9x14x3; ++ uint32x4_t start2 = x8x13x2x7; ++ ++ /* From here on this should be the same as the SUPERCOP version. */ ++ ++ uint32x4_t diag0 = start0; ++ uint32x4_t diag1 = start1; ++ uint32x4_t diag2 = start2; ++ uint32x4_t diag3 = start3; ++ ++ uint32x4_t a0; ++ uint32x4_t a1; ++ uint32x4_t a2; ++ uint32x4_t a3; ++ ++ for (i = ROUNDS;i > 0;i -= 2) { ++ a0 = diag1 + diag0; ++ diag3 ^= vsriq_n_u32(vshlq_n_u32(a0,7),a0,25); ++ a1 = diag0 + diag3; ++ diag2 ^= vsriq_n_u32(vshlq_n_u32(a1,9),a1,23); ++ a2 = diag3 + diag2; ++ diag1 ^= vsriq_n_u32(vshlq_n_u32(a2,13),a2,19); ++ a3 = diag2 + diag1; ++ diag0 ^= vsriq_n_u32(vshlq_n_u32(a3,18),a3,14); ++ ++ diag3 = vextq_u32(diag3,diag3,3); ++ diag2 = vextq_u32(diag2,diag2,2); ++ diag1 = vextq_u32(diag1,diag1,1); ++ ++ a0 = diag3 + diag0; ++ diag1 ^= vsriq_n_u32(vshlq_n_u32(a0,7),a0,25); ++ a1 = diag0 + diag1; ++ diag2 ^= vsriq_n_u32(vshlq_n_u32(a1,9),a1,23); ++ a2 = diag1 + diag2; ++ diag3 ^= vsriq_n_u32(vshlq_n_u32(a2,13),a2,19); ++ a3 = diag2 + diag3; ++ diag0 ^= vsriq_n_u32(vshlq_n_u32(a3,18),a3,14); ++ ++ diag1 = vextq_u32(diag1,diag1,3); ++ diag2 = vextq_u32(diag2,diag2,2); ++ diag3 = vextq_u32(diag3,diag3,1); ++ } ++ ++ x0x5x10x15 = diag0 + start0; ++ x12x1x6x11 = diag1 + start1; ++ x8x13x2x7 = diag2 + start2; ++ x4x9x14x3 = diag3 + start3; ++ ++ x0x1x10x11 = vbslq_u32(abab,x0x5x10x15,x12x1x6x11); ++ x12x13x6x7 = vbslq_u32(abab,x12x1x6x11,x8x13x2x7); ++ x8x9x2x3 = vbslq_u32(abab,x8x13x2x7,x4x9x14x3); ++ x4x5x14x15 = vbslq_u32(abab,x4x9x14x3,x0x5x10x15); ++ ++ x0x1x2x3 = vcombine_u32(vget_low_u32(x0x1x10x11),vget_high_u32(x8x9x2x3)); ++ x4x5x6x7 = vcombine_u32(vget_low_u32(x4x5x14x15),vget_high_u32(x12x13x6x7)); ++ x8x9x10x11 = vcombine_u32(vget_low_u32(x8x9x2x3),vget_high_u32(x0x1x10x11)); ++ x12x13x14x15 = vcombine_u32(vget_low_u32(x12x13x6x7),vget_high_u32(x4x5x14x15)); ++ ++ vst1q_u8((uint8_t *) input,(uint8x16_t) x0x1x2x3); ++ vst1q_u8(16 + (uint8_t *) input,(uint8x16_t) x4x5x6x7); ++ vst1q_u8(32 + (uint8_t *) input,(uint8x16_t) x8x9x10x11); ++ vst1q_u8(48 + (uint8_t *) input,(uint8x16_t) x12x13x14x15); ++} +diff --git a/lib/crypto/crypto_scrypt-neon.c b/lib/crypto/crypto_scrypt-neon.c +new file mode 100644 +index 0000000..a3bf052 +--- /dev/null ++++ b/lib/crypto/crypto_scrypt-neon.c +@@ -0,0 +1,305 @@ ++/*- ++ * Copyright 2009 Colin Percival ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file was originally written by Colin Percival as part of the Tarsnap ++ * online backup system. ++ */ ++#include "scrypt_platform.h" ++ ++#include <machine/cpu-features.h> ++#include <arm_neon.h> ++ ++#include <errno.h> ++#include <stdint.h> ++#include <limits.h> ++#include <stdlib.h> ++#include <string.h> ++ ++#ifdef USE_OPENSSL_PBKDF2 ++#include <openssl/evp.h> ++#else ++#include "sha256.h" ++#endif ++#include "sysendian.h" ++ ++#include "crypto_scrypt.h" ++ ++#include "crypto_scrypt-neon-salsa208.h" ++ ++static void blkcpy(void *, void *, size_t); ++static void blkxor(void *, void *, size_t); ++void crypto_core_salsa208_armneon2(void *); ++static void blockmix_salsa8(uint8x16_t *, uint8x16_t *, uint8x16_t *, size_t); ++static uint64_t integerify(void *, size_t); ++static void smix(uint8_t *, size_t, uint64_t, void *, void *); ++ ++static void ++blkcpy(void * dest, void * src, size_t len) ++{ ++ uint8x16_t * D = dest; ++ uint8x16_t * S = src; ++ size_t L = len / 16; ++ size_t i; ++ ++ for (i = 0; i < L; i++) ++ D[i] = S[i]; ++} ++ ++static void ++blkxor(void * dest, void * src, size_t len) ++{ ++ uint8x16_t * D = dest; ++ uint8x16_t * S = src; ++ size_t L = len / 16; ++ size_t i; ++ ++ for (i = 0; i < L; i++) ++ D[i] = veorq_u8(D[i], S[i]); ++} ++ ++/** ++ * blockmix_salsa8(B, Y, r): ++ * Compute B = BlockMix_{salsa20/8, r}(B). The input B must be 128r bytes in ++ * length; the temporary space Y must also be the same size. ++ */ ++static void ++blockmix_salsa8(uint8x16_t * Bin, uint8x16_t * Bout, uint8x16_t * X, size_t r) ++{ ++ size_t i; ++ ++ /* 1: X <-- B_{2r - 1} */ ++ blkcpy(X, &Bin[8 * r - 4], 64); ++ ++ /* 2: for i = 0 to 2r - 1 do */ ++ for (i = 0; i < r; i++) { ++ /* 3: X <-- H(X \xor B_i) */ ++ blkxor(X, &Bin[i * 8], 64); ++ salsa20_8_intrinsic((void *) X); ++ ++ /* 4: Y_i <-- X */ ++ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ ++ blkcpy(&Bout[i * 4], X, 64); ++ ++ /* 3: X <-- H(X \xor B_i) */ ++ blkxor(X, &Bin[i * 8 + 4], 64); ++ salsa20_8_intrinsic((void *) X); ++ ++ /* 4: Y_i <-- X */ ++ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ ++ blkcpy(&Bout[(r + i) * 4], X, 64); ++ } ++} ++ ++/** ++ * integerify(B, r): ++ * Return the result of parsing B_{2r-1} as a little-endian integer. ++ */ ++static uint64_t ++integerify(void * B, size_t r) ++{ ++ uint8_t * X = (void*)((uintptr_t)(B) + (2 * r - 1) * 64); ++ ++ return (le64dec(X)); ++} ++ ++/** ++ * smix(B, r, N, V, XY): ++ * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; the ++ * temporary storage V must be 128rN bytes in length; the temporary storage ++ * XY must be 256r bytes in length. The value N must be a power of 2. ++ */ ++static void ++smix(uint8_t * B, size_t r, uint64_t N, void * V, void * XY) ++{ ++ uint8x16_t * X = XY; ++ uint8x16_t * Y = (void *)((uintptr_t)(XY) + 128 * r); ++ uint8x16_t * Z = (void *)((uintptr_t)(XY) + 256 * r); ++ uint32_t * X32 = (void *)X; ++ uint64_t i, j; ++ size_t k; ++ ++ /* 1: X <-- B */ ++ blkcpy(X, B, 128 * r); ++ ++ /* 2: for i = 0 to N - 1 do */ ++ for (i = 0; i < N; i += 2) { ++ /* 3: V_i <-- X */ ++ blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r); ++ ++ /* 4: X <-- H(X) */ ++ blockmix_salsa8(X, Y, Z, r); ++ ++ /* 3: V_i <-- X */ ++ blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r), ++ Y, 128 * r); ++ ++ /* 4: X <-- H(X) */ ++ blockmix_salsa8(Y, X, Z, r); ++ } ++ ++ /* 6: for i = 0 to N - 1 do */ ++ for (i = 0; i < N; i += 2) { ++ /* 7: j <-- Integerify(X) mod N */ ++ j = integerify(X, r) & (N - 1); ++ ++ /* 8: X <-- H(X \xor V_j) */ ++ blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); ++ blockmix_salsa8(X, Y, Z, r); ++ ++ /* 7: j <-- Integerify(X) mod N */ ++ j = integerify(Y, r) & (N - 1); ++ ++ /* 8: X <-- H(X \xor V_j) */ ++ blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); ++ blockmix_salsa8(Y, X, Z, r); ++ } ++ ++ /* 10: B' <-- X */ ++ blkcpy(B, X, 128 * r); ++} ++ ++/** ++ * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): ++ * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, ++ * p, buflen) and write the result into buf. The parameters r, p, and buflen ++ * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N ++ * must be a power of 2. ++ * ++ * Return 0 on success; or -1 on error. ++ */ ++int ++crypto_scrypt(const uint8_t * passwd, size_t passwdlen, ++ const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, ++ uint8_t * buf, size_t buflen) ++{ ++ void * B0, * V0, * XY0; ++ uint8_t * B; ++ uint32_t * V; ++ uint32_t * XY; ++ uint32_t i; ++ ++ /* Sanity-check parameters. */ ++#if SIZE_MAX > UINT32_MAX ++ if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { ++ errno = EFBIG; ++ goto err0; ++ } ++#endif ++ if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { ++ errno = EFBIG; ++ goto err0; ++ } ++ if (((N & (N - 1)) != 0) || (N == 0)) { ++ errno = EINVAL; ++ goto err0; ++ } ++ if ((r > SIZE_MAX / 128 / p) || ++#if SIZE_MAX / 256 <= UINT32_MAX ++ (r > SIZE_MAX / 256) || ++#endif ++ (N > SIZE_MAX / 128 / r)) { ++ errno = ENOMEM; ++ goto err0; ++ } ++ ++ /* Allocate memory. */ ++#ifdef HAVE_POSIX_MEMALIGN ++ if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) ++ goto err0; ++ B = (uint8_t *)(B0); ++ if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) ++ goto err1; ++ XY = (uint32_t *)(XY0); ++#ifndef MAP_ANON ++ if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) ++ goto err2; ++ V = (uint32_t *)(V0); ++#endif ++#else ++ if ((B0 = malloc(128 * r * p + 63)) == NULL) ++ goto err0; ++ B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); ++ if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) ++ goto err1; ++ XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); ++#ifndef MAP_ANON ++ if ((V0 = malloc(128 * r * N + 63)) == NULL) ++ goto err2; ++ V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); ++#endif ++#endif ++#ifdef MAP_ANON ++ if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, ++#ifdef MAP_NOCORE ++ MAP_ANON | MAP_PRIVATE | MAP_NOCORE, ++#else ++ MAP_ANON | MAP_PRIVATE, ++#endif ++ -1, 0)) == MAP_FAILED) ++ goto err2; ++ V = (uint32_t *)(V0); ++#endif ++ ++ /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ ++#ifdef USE_OPENSSL_PBKDF2 ++ PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B); ++#else ++ PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); ++#endif ++ ++ /* 2: for i = 0 to p - 1 do */ ++ for (i = 0; i < p; i++) { ++ /* 3: B_i <-- MF(B_i, N) */ ++ smix(&B[i * 128 * r], r, N, V, XY); ++ } ++ ++ /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ ++#ifdef USE_OPENSSL_PBKDF2 ++ PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf); ++#else ++ PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); ++#endif ++ ++ /* Free memory. */ ++#ifdef MAP_ANON ++ if (munmap(V0, 128 * r * N)) ++ goto err2; ++#else ++ free(V0); ++#endif ++ free(XY0); ++ free(B0); ++ ++ /* Success! */ ++ return (0); ++ ++err2: ++ free(XY0); ++err1: ++ free(B0); ++err0: ++ /* Failure! */ ++ return (-1); ++} diff --git a/crypto/scrypt/patches/use_openssl_pbkdf2.patch b/crypto/scrypt/patches/use_openssl_pbkdf2.patch new file mode 100644 index 000000000..0a1328cc0 --- /dev/null +++ b/crypto/scrypt/patches/use_openssl_pbkdf2.patch @@ -0,0 +1,80 @@ +diff --git a/lib/crypto/crypto_scrypt-ref.c b/lib/crypto/crypto_scrypt-ref.c +index 79a6f8f..60ef2aa 100644 +--- a/lib/crypto/crypto_scrypt-ref.c ++++ b/lib/crypto/crypto_scrypt-ref.c +@@ -34,7 +34,11 @@ + #include <stdlib.h> + #include <string.h> + ++#ifdef USE_OPENSSL_PBKDF2 ++#include <openssl/evp.h> ++#else + #include "sha256.h" ++#endif + #include "sysendian.h" + + #include "crypto_scrypt.h" +@@ -256,7 +260,11 @@ crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + goto err2; + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ ++#ifdef USE_OPENSSL_PBKDF2 ++ PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B); ++#else + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); ++#endif + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { +@@ -265,7 +273,11 @@ crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ ++#ifdef USE_OPENSSL_PBKDF2 ++ PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf); ++#else + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); ++#endif + + /* Free memory. */ + free(V); +diff --git a/lib/crypto/crypto_scrypt-sse.c b/lib/crypto/crypto_scrypt-sse.c +index 875175e..dd18f29 100644 +--- a/lib/crypto/crypto_scrypt-sse.c ++++ b/lib/crypto/crypto_scrypt-sse.c +@@ -37,7 +37,11 @@ + #include <stdlib.h> + #include <string.h> + ++#ifdef USE_OPENSSL_PBKDF2 ++#include <openssl/evp.h> ++#else + #include "sha256.h" ++#endif + #include "sysendian.h" + + #include "crypto_scrypt.h" +@@ -332,7 +336,11 @@ crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + #endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ ++#ifdef USE_OPENSSL_PBKDF2 ++ PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, salt, saltlen, 1, EVP_sha256(), p * 128 * r, B); ++#else + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); ++#endif + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { +@@ -341,7 +349,11 @@ crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ ++#ifdef USE_OPENSSL_PBKDF2 ++ PKCS5_PBKDF2_HMAC((const char *)passwd, passwdlen, B, p * 128 * r, 1, EVP_sha256(), buflen, buf); ++#else + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); ++#endif + + /* Free memory. */ + #ifdef MAP_ANON diff --git a/crypto/scrypt/scrypt.config b/crypto/scrypt/scrypt.config new file mode 100644 index 000000000..3ccb4d0eb --- /dev/null +++ b/crypto/scrypt/scrypt.config @@ -0,0 +1,94 @@ +CONFIGURE_ARGS="\ + \ +" + +# unneeded directories +UNNEEDED_SOURCES="\ +lib/scryptenc \ +" + +# unneeded files +UNNEEDED_SOURCES+="\ +config.h.in \ +configure \ +FORMAT \ +main.c \ +Makefile.in \ +scrypt.1 \ +lib/crypto/crypto_aesctr.c \ +lib/crypto/crypto_aesctr.h \ +lib/crypto/crypto_scrypt-nosse.c \ +lib/crypto/sha256.c \ +lib/crypto/sha256.h \ +lib/util/memlimit.c \ +lib/util/memlimit.h \ +lib/util/readpass.c \ +lib/util/readpass.h \ +lib/util/warn.c \ +lib/util/warn.h \ +" + +NEEDED_SOURCES="\ +config.h \ +lib \ +scrypt_platform.h \ +" + +SCRYPT_INCLUDES="\ +lib/crypto \ +lib/util \ +" + +SCRYPT_SOURCES="\ +lib/crypto/crypto_scrypt-ref.c \ +" + +SCRYPT_SOURCES_arm="\ +" + +SCRYPT_SOURCES_EXCLUDES_arm="\ +" + +SCRYPT_SOURCES_arm_neon="\ +lib/crypto/crypto_scrypt-neon.c \ +" + +SCRYPT_SOURCES_EXCLUDES_arm_neon="\ +lib/crypto/crypto_scrypt-ref.c \ +" + +SCRYPT_SOURCES_mips="\ +" + +SCRYPT_SOURCES_EXCLUDES_mips="\ +" + +SCRYPT_SOURCES_x86="\ +lib/crypto/crypto_scrypt-sse.c \ +" + +SCRYPT_SOURCES_EXCLUDES_x86="\ +lib/crypto/crypto_scrypt-ref.c \ +" + +SCRYPT_SOURCES_x86_64="\ +lib/crypto/crypto_scrypt-sse.c \ +" + +SCRYPT_SOURCES_EXCLUDES_x86_64="\ +lib/crypto/crypto_scrypt-ref.c \ +" + +SCRYPT_PATCHES="\ +use_openssl_pbkdf2.patch \ +arm-neon.patch \ +" + +SCRYPT_PATCHES_use_openssl_pbkdf2_SOURCES="\ +lib/crypto/crypto_scrypt-ref.c \ +" + +SCRYPT_PATCHES_bionic_SOURCES="\ +lib/crypto/crypto_scrypt-neon.c \ +lib/crypto/crypto_scrypt-neon-salsa208.h \ +" diff --git a/crypto/scrypt/scrypt.version b/crypto/scrypt/scrypt.version new file mode 100644 index 000000000..155e26061 --- /dev/null +++ b/crypto/scrypt/scrypt.version @@ -0,0 +1 @@ +SCRYPT_VERSION=1.1.6 diff --git a/crypto/scrypt/scrypt_platform.h b/crypto/scrypt/scrypt_platform.h new file mode 100644 index 000000000..5cec23631 --- /dev/null +++ b/crypto/scrypt/scrypt_platform.h @@ -0,0 +1,12 @@ +#ifndef _SCRYPT_PLATFORM_H_ +#define _SCRYPT_PLATFORM_H_ + +#if defined(CONFIG_H_FILE) +#include CONFIG_H_FILE +#elif defined(HAVE_CONFIG_H) +#include "config.h" +#else +#error Need either CONFIG_H_FILE or HAVE_CONFIG_H defined. +#endif + +#endif /* !_SCRYPT_PLATFORM_H_ */ diff --git a/crypto/scrypt/tests/Android.mk b/crypto/scrypt/tests/Android.mk new file mode 100644 index 000000000..c20b41da9 --- /dev/null +++ b/crypto/scrypt/tests/Android.mk @@ -0,0 +1,26 @@ +# 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_TAGS := optional +LOCAL_MODULE := scrypttwrp_test + +include $(BUILD_NATIVE_TEST) diff --git a/crypto/scrypt/tests/scrypt_test.cpp b/crypto/scrypt/tests/scrypt_test.cpp new file mode 100644 index 000000000..ffb568df9 --- /dev/null +++ b/crypto/scrypt/tests/scrypt_test.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "scrypt_test" +#include <UniquePtr.h> +#include <utils/Log.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"; + } +} + +} |