summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto')
-rw-r--r--crypto/lollipop/Android.mk60
-rw-r--r--crypto/lollipop/cryptfs.c1580
-rw-r--r--crypto/lollipop/cryptfs.h229
-rw-r--r--crypto/lollipop/main.c32
-rw-r--r--crypto/scrypt/Android.mk13
-rw-r--r--crypto/scrypt/MODULE_LICENSE_BSD_LIKE0
-rw-r--r--crypto/scrypt/NOTICE36
-rw-r--r--crypto/scrypt/Scrypt-config.mk105
-rw-r--r--crypto/scrypt/Scrypt.mk46
-rw-r--r--crypto/scrypt/android-config.mk16
-rw-r--r--crypto/scrypt/build-config.mk6
-rw-r--r--crypto/scrypt/config.h99
-rwxr-xr-xcrypto/scrypt/import_scrypt.sh493
-rw-r--r--crypto/scrypt/lib/README6
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt-neon-salsa208.h120
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt-neon.c305
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt-ref.c296
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt-sse.c378
-rw-r--r--crypto/scrypt/lib/crypto/crypto_scrypt.h46
-rw-r--r--crypto/scrypt/lib/util/sysendian.h140
-rw-r--r--crypto/scrypt/patches/README11
-rw-r--r--crypto/scrypt/patches/arm-neon.patch437
-rw-r--r--crypto/scrypt/patches/use_openssl_pbkdf2.patch80
-rw-r--r--crypto/scrypt/scrypt.config94
-rw-r--r--crypto/scrypt/scrypt.version1
-rw-r--r--crypto/scrypt/scrypt_platform.h12
-rw-r--r--crypto/scrypt/tests/Android.mk26
-rw-r--r--crypto/scrypt/tests/scrypt_test.cpp78
28 files changed, 4745 insertions, 0 deletions
diff --git a/crypto/lollipop/Android.mk b/crypto/lollipop/Android.mk
new file mode 100644
index 000000000..6dc386a29
--- /dev/null
+++ b/crypto/lollipop/Android.mk
@@ -0,0 +1,60 @@
+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
+
+ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
+ ifeq ($(TARGET_CRYPTFS_HW_PATH),)
+ LOCAL_C_INCLUDES += device/qcom/common/cryptfs_hw
+ else
+ LOCAL_C_INCLUDES += $(TARGET_CRYPTFS_HW_PATH)
+ endif
+ LOCAL_SHARED_LIBRARIES += libcryptfs_hw
+ LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION
+endif
+
+ifneq ($(wildcard hardware/libhardware/include/hardware/keymaster0.h),)
+ LOCAL_CFLAGS += -DTW_CRYPTO_HAVE_KEYMASTERX
+ LOCAL_C_INCLUDES += external/boringssl/src/include
+endif
+
+LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := twrpdec
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := main.c cryptfs.c
+LOCAL_SHARED_LIBRARIES := libcrypto libhardware libcutils libc
+LOCAL_C_INCLUDES := external/openssl/include $(commands_recovery_local_path)/crypto/scrypt/lib/crypto
+
+ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
+ ifeq ($(TARGET_CRYPTFS_HW_PATH),)
+ LOCAL_C_INCLUDES += device/qcom/common/cryptfs_hw
+ else
+ LOCAL_C_INCLUDES += $(TARGET_CRYPTFS_HW_PATH)
+ endif
+ LOCAL_SHARED_LIBRARIES += libcryptfs_hw
+ LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION
+endif
+
+ifneq ($(wildcard hardware/libhardware/include/hardware/keymaster0.h),)
+ LOCAL_CFLAGS += -DTW_CRYPTO_HAVE_KEYMASTERX
+ LOCAL_C_INCLUDES += external/boringssl/src/include
+endif
+
+LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c
new file mode 100644
index 000000000..0c7848d8f
--- /dev/null
+++ b/crypto/lollipop/cryptfs.c
@@ -0,0 +1,1580 @@
+/*
+ * 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 <linux/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"
+
+#ifndef TW_CRYPTO_HAVE_KEYMASTERX
+#include <hardware/keymaster.h>
+#else
+#include <stdbool.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster1.h>
+#endif
+
+#ifndef min /* already defined by windows.h */
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define UNUSED __attribute__((unused))
+
+#define UNUSED __attribute__((unused))
+
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+#include "cryptfs_hw.h"
+#endif
+
+#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"
+
+#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 KEYMASTER_CRYPTFS_RATE_LIMIT 1 // Maximum one try per second
+
+#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] = "";
+
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+static int scrypt_keymaster(const char *passwd, const unsigned char *salt,
+ unsigned char *ikey, void *params);
+static void convert_key_to_hex_ascii(const unsigned char *master_key,
+ unsigned int keysize, char *master_key_ascii);
+static int get_keymaster_hw_fde_passwd(const char* passwd, unsigned char* newpw,
+ unsigned char* salt,
+ const struct crypt_mnt_ftr *ftr)
+{
+ /* if newpw updated, return 0
+ * if newpw not updated return -1
+ */
+ int rc = -1;
+
+ if (should_use_keymaster()) {
+ if (scrypt_keymaster(passwd, salt, newpw, (void*)ftr)) {
+ printf("scrypt failed");
+ } else {
+ rc = 0;
+ }
+ }
+
+ return rc;
+}
+
+static int verify_hw_fde_passwd(char *passwd, struct crypt_mnt_ftr* crypt_ftr)
+{
+ unsigned char newpw[32] = {0};
+ int key_index;
+ if (get_keymaster_hw_fde_passwd(passwd, newpw, crypt_ftr->salt, crypt_ftr))
+ key_index = set_hw_device_encryption_key(passwd,
+ (char*) crypt_ftr->crypto_type_name);
+ else
+ key_index = set_hw_device_encryption_key((const char*)newpw,
+ (char*) crypt_ftr->crypto_type_name);
+ return key_index;
+}
+#endif
+
+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);
+}
+
+#ifndef TW_CRYPTO_HAVE_KEYMASTERX
+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(&params, '\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, &params,
+ &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,
+ &params,
+ ftr->keymaster_blob,
+ ftr->keymaster_blob_size,
+ to_sign,
+ to_sign_size,
+ signature,
+ signature_size);
+
+ keymaster_close(keymaster_dev);
+ return rc;
+}
+#else //#ifndef TW_CRYPTO_HAVE_KEYMASTERX
+static int keymaster_init(keymaster0_device_t **keymaster0_dev,
+ keymaster1_device_t **keymaster1_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 err;
+ }
+
+ printf("keymaster module name is %s\n", mod->name);
+ printf("keymaster version is %d\n", mod->module_api_version);
+
+ *keymaster0_dev = NULL;
+ *keymaster1_dev = NULL;
+ if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
+ printf("Found keymaster1 module, using keymaster1 API.\n");
+ rc = keymaster1_open(mod, keymaster1_dev);
+ } else {
+ printf("Found keymaster0 module, using keymaster0 API.\n");
+ rc = keymaster0_open(mod, keymaster0_dev);
+ }
+
+ if (rc) {
+ printf("could not open keymaster device in %s (%s)\n",
+ KEYSTORE_HARDWARE_MODULE_ID, strerror(-rc));
+ goto err;
+ }
+
+ return 0;
+
+err:
+ *keymaster0_dev = NULL;
+ *keymaster1_dev = NULL;
+ return rc;
+}
+
+/* Should we use keymaster? */
+static int keymaster_check_compatibility()
+{
+ keymaster0_device_t *keymaster0_dev = 0;
+ keymaster1_device_t *keymaster1_dev = 0;
+ int rc = 0;
+
+ if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
+ printf("Failed to init keymaster\n");
+ rc = -1;
+ goto out;
+ }
+
+ if (keymaster1_dev) {
+ rc = 1;
+ goto out;
+ }
+
+ // TODO(swillden): Check to see if there's any reason to require v0.3. I think v0.1 and v0.2
+ // should work.
+ if (keymaster0_dev->common.module->module_api_version
+ < KEYMASTER_MODULE_API_VERSION_0_3) {
+ rc = 0;
+ goto out;
+ }
+
+ if (!(keymaster0_dev->flags & KEYMASTER_SOFTWARE_ONLY) &&
+ (keymaster0_dev->flags & KEYMASTER_BLOBS_ARE_STANDALONE)) {
+ rc = 1;
+ }
+
+out:
+ if (keymaster1_dev) {
+ keymaster1_close(keymaster1_dev);
+ }
+ if (keymaster0_dev) {
+ keymaster0_close(keymaster0_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;
+ keymaster0_device_t *keymaster0_dev = 0;
+ keymaster1_device_t *keymaster1_dev = 0;
+
+ if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
+ printf("Failed to init keymaster\n");
+ return -1;
+ }
+
+ int rc = 0;
+ size_t key_size = 0;
+ if (keymaster1_dev) {
+ keymaster_key_param_t params[] = {
+ /* Algorithm & size specifications. Stick with RSA for now. Switch to AES later. */
+ keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA),
+ keymaster_param_int(KM_TAG_KEY_SIZE, RSA_KEY_SIZE),
+ keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, RSA_EXPONENT),
+
+ /* The only allowed purpose for this key is signing. */
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
+
+ /* Padding & digest specifications. */
+ keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
+ keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+
+ /* Require that the key be usable in standalone mode. File system isn't available. */
+ keymaster_param_enum(KM_TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE),
+
+ /* No auth requirements, because cryptfs is not yet integrated with gatekeeper. */
+ keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
+
+ /* Rate-limit key usage attempts, to rate-limit brute force */
+ keymaster_param_int(KM_TAG_MIN_SECONDS_BETWEEN_OPS, KEYMASTER_CRYPTFS_RATE_LIMIT),
+ };
+ keymaster_key_param_set_t param_set = { params, sizeof(params)/sizeof(*params) };
+ keymaster_key_blob_t key_blob;
+ keymaster_error_t error = keymaster1_dev->generate_key(keymaster1_dev, &param_set,
+ &key_blob,
+ NULL /* characteristics */);
+ if (error != KM_ERROR_OK) {
+ printf("Failed to generate keymaster1 key, error %d\n", error);
+ rc = -1;
+ goto out;
+ }
+
+ key = (uint8_t*)key_blob.key_material;
+ key_size = key_blob.key_material_size;
+ }
+ else if (keymaster0_dev) {
+ keymaster_rsa_keygen_params_t params;
+ memset(&params, '\0', sizeof(params));
+ params.public_exponent = RSA_EXPONENT;
+ params.modulus_size = RSA_KEY_SIZE;
+
+ if (keymaster0_dev->generate_keypair(keymaster0_dev, TYPE_RSA, &params,
+ &key, &key_size)) {
+ printf("Failed to generate keypair\n");
+ rc = -1;
+ goto out;
+ }
+ } else {
+ printf("Cryptfs bug: keymaster_init succeeded but didn't initialize a device\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:
+ if (keymaster0_dev)
+ keymaster0_close(keymaster0_dev);
+ if (keymaster1_dev)
+ keymaster1_close(keymaster1_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;
+ keymaster0_device_t *keymaster0_dev = 0;
+ keymaster1_device_t *keymaster1_dev = 0;
+ if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
+ printf("Failed to init keymaster\n");
+ rc = -1;
+ goto out;
+ }
+
+ 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:
+ // 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 deterministic
+ // RSA padding function, such as PKCS1.
+ 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);
+ rc = -1;
+ goto out;
+ }
+
+ if (keymaster0_dev) {
+ keymaster_rsa_sign_params_t params;
+ params.digest_type = DIGEST_NONE;
+ params.padding_type = PADDING_NONE;
+
+ rc = keymaster0_dev->sign_data(keymaster0_dev,
+ &params,
+ ftr->keymaster_blob,
+ ftr->keymaster_blob_size,
+ to_sign,
+ to_sign_size,
+ signature,
+ signature_size);
+ goto out;
+ } else if (keymaster1_dev) {
+ keymaster_key_blob_t key = { ftr->keymaster_blob, ftr->keymaster_blob_size };
+ keymaster_key_param_t params[] = {
+ keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
+ keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+ };
+ keymaster_key_param_set_t param_set = { params, sizeof(params)/sizeof(*params) };
+ keymaster_operation_handle_t op_handle;
+ keymaster_error_t error = keymaster1_dev->begin(keymaster1_dev, KM_PURPOSE_SIGN, &key,
+ &param_set, NULL /* out_params */,
+ &op_handle);
+ if (error == KM_ERROR_KEY_RATE_LIMIT_EXCEEDED) {
+ // Key usage has been rate-limited. Wait a bit and try again.
+ sleep(KEYMASTER_CRYPTFS_RATE_LIMIT);
+ error = keymaster1_dev->begin(keymaster1_dev, KM_PURPOSE_SIGN, &key,
+ &param_set, NULL /* out_params */,
+ &op_handle);
+ }
+ if (error != KM_ERROR_OK) {
+ printf("Error starting keymaster signature transaction: %d\n", error);
+ rc = -1;
+ goto out;
+ }
+
+ keymaster_blob_t input = { to_sign, to_sign_size };
+ size_t input_consumed;
+ error = keymaster1_dev->update(keymaster1_dev, op_handle, NULL /* in_params */,
+ &input, &input_consumed, NULL /* out_params */,
+ NULL /* output */);
+ if (error != KM_ERROR_OK) {
+ printf("Error sending data to keymaster signature transaction: %d\n", error);
+ rc = -1;
+ goto out;
+ }
+ if (input_consumed != to_sign_size) {
+ // This should never happen. If it does, it's a bug in the keymaster implementation.
+ printf("Keymaster update() did not consume all data.\n");
+ keymaster1_dev->abort(keymaster1_dev, op_handle);
+ rc = -1;
+ goto out;
+ }
+
+ keymaster_blob_t tmp_sig;
+ error = keymaster1_dev->finish(keymaster1_dev, op_handle, NULL /* in_params */,
+ NULL /* verify signature */, NULL /* out_params */,
+ &tmp_sig);
+ if (error != KM_ERROR_OK) {
+ printf("Error finishing keymaster signature transaction: %d\n", error);
+ rc = -1;
+ goto out;
+ }
+
+ *signature = (uint8_t*)tmp_sig.data;
+ *signature_size = tmp_sig.data_length;
+ } else {
+ printf("Cryptfs bug: keymaster_init succeded but didn't initialize a device.\n");
+ rc = -1;
+ goto out;
+ }
+
+ out:
+ if (keymaster1_dev)
+ keymaster1_close(keymaster1_dev);
+ if (keymaster0_dev)
+ keymaster0_close(keymaster0_dev);
+
+ return rc;
+}
+#endif //#ifndef TW_CRYPTO_HAVE_KEYMASTERX
+
+/* 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\n", 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 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\n");
+ return NULL;
+ }
+
+ unsigned char* master_key = (unsigned char*) malloc(size / 2);
+ if (master_key == 0) {
+ printf("Cannot allocate\n");
+ 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\n");
+ 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(const 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, const unsigned char *master_key,
+ const 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;
+ crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ if(is_hw_disk_encryption((char*)crypt_ftr->crypto_type_name)) {
+ strlcpy(tgt->target_type, "req-crypt",DM_MAX_TYPE_NAME);
+ if (is_ice_enabled())
+ convert_key_to_hex_ascii(master_key, sizeof(int), master_key_ascii);
+ else
+ convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
+ }
+ else {
+ convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
+ strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME);
+ }
+#else
+ convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
+ strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME);
+#endif
+
+ sprintf(crypt_params, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name,
+ master_key_ascii, real_blk_name, extra_params);
+
+ printf("%s: target_type = %s\n", __func__, tgt->target_type);
+ printf("%s: real_blk_name = %s, extra_params = %s\n", __func__, 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;
+ }
+ printf("%i\n", errno);
+ 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 flag;
+ 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) {
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ if (is_hw_fde_enabled()) {
+ flag = (!strcmp(v->name, "crypt") || !strcmp(v->name, "req-crypt"));
+ } else {
+ flag = (!strcmp(v->name, "crypt"));
+ }
+ printf("get_dm_crypt_version flag: %i, name: '%s'\n", flag, v->name);
+ if (flag) {
+#else
+ if (! strcmp(v->name, "crypt")) {
+#endif
+ /* 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, const unsigned char *master_key,
+ const 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=0;
+ int i;
+ int retval = -1;
+ int version[3];
+ char *extra_params;
+ int load_count;
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ char encrypted_state[PROPERTY_VALUE_MAX] = {0};
+ char progress[PROPERTY_VALUE_MAX] = {0};
+#endif
+
+ 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 %i\n", errno);
+ 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);
+
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ if(is_hw_disk_encryption((char*)crypt_ftr->crypto_type_name)) {
+ /* Set fde_enabled if either FDE completed or in-progress */
+ property_get("ro.crypto.state", encrypted_state, ""); /* FDE completed */
+ property_get("vold.encrypt_progress", progress, ""); /* FDE in progress */
+ if (!strcmp(encrypted_state, "encrypted") || strcmp(progress, "")) {
+ if (is_ice_enabled())
+ extra_params = "fde_enabled ice";
+ else
+ extra_params = "fde_enabled";
+ } else
+ extra_params = "fde_disabled";
+ } else {
+ 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");
+ }
+ }
+ }
+#else
+ 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");
+ }
+ }
+#endif
+
+ 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\n");
+
+ /* 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, using passwd instead\n");
+ master_key = strdup(passwd);
+ }
+
+ 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 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\n");
+ 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;
+ }
+#ifndef TW_CRYPTO_HAVE_KEYMASTERX
+ if (! EVP_DecryptFinal(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) {
+#else
+ if (! EVP_DecryptFinal_ex(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) {
+#endif
+ 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\n");
+ }
+
+ 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];
+ int rc = 0;
+ 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);
+
+ 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;
+ }
+ }
+
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ int key_index = 0;
+ if(is_hw_disk_encryption((char*)crypt_ftr->crypto_type_name)) {
+ key_index = verify_hw_fde_passwd(passwd, crypt_ftr);
+
+ if (key_index < 0) {
+ rc = 1;
+ goto errout;
+ }
+ else {
+ if (is_ice_enabled()) {
+ if (create_crypto_blk_dev(crypt_ftr, (unsigned char*)&key_index,
+ real_blkdev, crypto_blkdev, label)) {
+ printf("Error creating decrypted block device");
+ rc = -1;
+ goto errout;
+ }
+ } else {
+ if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key,
+ real_blkdev, crypto_blkdev, label)) {
+ printf("Error creating decrypted block device");
+ rc = -1;
+ goto errout;
+ }
+ }
+ }
+ } else {
+ /* in case HW FDE is delivered through OTA and device is already encrypted
+ * using SW FDE, we should let user continue using SW FDE until userdata is
+ * wiped.
+ */
+ if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key,
+ real_blkdev, crypto_blkdev, label)) {
+ printf("Error creating decrypted block device");
+ rc = -1;
+ goto errout;
+ }
+ }
+#else
+ // 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;
+ }
+#endif
+
+ /* 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, 0, NULL) != 0) {
+ printf("Error temp mounting decrypted block device '%s'\n", crypto_blkdev);
+ delete_crypto_blk_dev(label);
+ rc = 1;
+ } else {
+ /* Success! */
+ printf("Password did not match but decrypted drive mounted - continue\n");
+ umount(tmp_mount_point);
+ rc = 0;
+ }
+ }
+
+ if (rc == 0) {
+ // Don't increment the failed attempt counter as it doesn't
+ // make sense to do so in TWRP
+
+ /* 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);
+
+ // TWRP shouldn't change the stored key
+ }
+
+ errout:
+ if (intermediate_key) {
+ memset(intermediate_key, 0, intermediate_key_size);
+ free(intermediate_key);
+ }
+ return rc;
+}
+
+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;
+}
+
+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;
+
+ if (!passwd) {
+ printf("cryptfs_check_passwd: passwd is NULL!\n");
+ return -1;
+ }
+
+ rc = check_unmounted_and_get_ftr(&crypt_ftr);
+ if (rc)
+ return rc;
+
+ rc = test_mount_encrypted_fs(&crypt_ftr, passwd,
+ DATA_MNT_POINT, "userdata");
+
+ // try falling back to Lollipop hex passwords
+ if (rc) {
+ int hex_pass_len = strlen(passwd) * 2 + 1;
+ char *hex_passwd = (char *)malloc(hex_pass_len);
+ if (hex_passwd) {
+ convert_key_to_hex_ascii((unsigned char *)passwd,
+ strlen(passwd), hex_passwd);
+ rc = test_mount_encrypted_fs(&crypt_ftr, hex_passwd,
+ DATA_MNT_POINT, "userdata");
+ memset(hex_passwd, 0, hex_pass_len);
+ free(hex_passwd);
+ }
+ }
+
+ return rc;
+}
+
+/* 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;
+}
+
+/*
+ * Called by vold when it's asked to mount an encrypted external
+ * storage volume. The incoming partition has no crypto header/footer,
+ * as any metadata is been stored in a separate, small partition.
+ *
+ * out_crypto_blkdev must be MAXPATHLEN.
+ */
+int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
+ const unsigned char* key, int keysize, char* out_crypto_blkdev) {
+ int fd = open(real_blkdev, O_RDONLY|O_CLOEXEC);
+ if (fd == -1) {
+ printf("Failed to open %s: %s", real_blkdev, strerror(errno));
+ return -1;
+ }
+
+ unsigned long nr_sec = 0;
+ nr_sec = get_blkdev_size(fd);
+ close(fd);
+
+ if (nr_sec == 0) {
+ printf("Failed to get size of %s: %s", real_blkdev, strerror(errno));
+ return -1;
+ }
+
+ struct crypt_mnt_ftr ext_crypt_ftr;
+ memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr));
+ ext_crypt_ftr.fs_size = nr_sec;
+ ext_crypt_ftr.keysize = keysize;
+ strcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
+
+ return create_crypto_blk_dev(&ext_crypt_ftr, key, real_blkdev,
+ out_crypto_blkdev, label);
+}
+
+/*
+ * Called by vold when it's asked to unmount an encrypted external
+ * storage volume.
+ */
+int cryptfs_revert_ext_volume(const char* label) {
+ return delete_crypto_blk_dev((char*) label);
+}
diff --git a/crypto/lollipop/cryptfs.h b/crypto/lollipop/cryptfs.h
new file mode 100644
index 000000000..cd07e5af7
--- /dev/null
+++ b/crypto/lollipop/cryptfs.h
@@ -0,0 +1,229 @@
+/*
+ * 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 */
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+/* This flag is used to transition from L->M upgrade. L release passed
+ * a byte for every nible of user password while M release is passing
+ * ascii value of user password.
+ * Random flag value is chosen so that it does not conflict with other use cases
+ */
+#define CRYPT_ASCII_PASSWORD_UPDATED 0x1000
+#endif
+/* 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);
+ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
+ const unsigned char* key, int keysize, char* out_crypto_blkdev);
+ int cryptfs_revert_ext_volume(const char* label);
+#ifdef __cplusplus
+}
+#endif
diff --git a/crypto/lollipop/main.c b/crypto/lollipop/main.c
new file mode 100644
index 000000000..232afb959
--- /dev/null
+++ b/crypto/lollipop/main.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <linux/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"
+
+int main() {
+ set_partition_data("/dev/block/platform/sdhci-tegra.3/by-name/UDA", "/dev/block/platform/sdhci-tegra.3/by-name/MD1", "f2fs");
+ //int ret = cryptfs_check_passwd("30303030");
+ int ret = cryptfs_check_passwd("0000");
+ return 0;
+}
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..baa41eca6
--- /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 external/boringssl/src/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";
+ }
+}
+
+}