Updates to cryptfs framework.
Update the enable inplace API to allow the UI to show a progress bar. Add new command changepw (whichis currently not working) Internal restructuring of code to support these two features. Some minor cleanup of the code as well. Change-Id: I11461fc9ce66965bea6cd0b6bb2ff48bcf607b97
This commit is contained in:
parent
6864b7ec94
commit
8ddbe40a8a
3 changed files with 238 additions and 97 deletions
|
@ -514,8 +514,6 @@ CommandListener::CryptfsCmd::CryptfsCmd() :
|
||||||
|
|
||||||
int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
|
int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
|
||||||
int argc, char **argv) {
|
int argc, char **argv) {
|
||||||
dumpArgs(argc, argv, -1);
|
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
|
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -528,20 +526,31 @@ int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
|
||||||
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
|
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
dumpArgs(argc, argv, 2);
|
||||||
rc = cryptfs_check_passwd(argv[2]);
|
rc = cryptfs_check_passwd(argv[2]);
|
||||||
} else if (!strcmp(argv[1], "restart")) {
|
} else if (!strcmp(argv[1], "restart")) {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
|
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
dumpArgs(argc, argv, -1);
|
||||||
rc = cryptfs_restart();
|
rc = cryptfs_restart();
|
||||||
} else if (!strcmp(argv[1], "enablecrypto")) {
|
} else if (!strcmp(argv[1], "enablecrypto")) {
|
||||||
if ( (argc != 4) || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
|
if ( (argc != 4) || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
|
||||||
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs enablecrypto <wipe|inplace> <passwd>", false);
|
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs enablecrypto <wipe|inplace> <passwd>", false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
dumpArgs(argc, argv, 3);
|
||||||
rc = cryptfs_enable(argv[2], argv[3]);
|
rc = cryptfs_enable(argv[2], argv[3]);
|
||||||
|
} else if (!strcmp(argv[1], "changepw")) {
|
||||||
|
if (argc != 4) {
|
||||||
|
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs changepw <oldpasswd> <newpasswd>", false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SLOGD("cryptfs changepw <oldpw> <newpw>");
|
||||||
|
rc = cryptfs_changepw(argv[2], argv[3]);
|
||||||
} else {
|
} else {
|
||||||
|
dumpArgs(argc, argv, -1);
|
||||||
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
|
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
263
cryptfs.c
263
cryptfs.c
|
@ -33,6 +33,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
#include "cryptfs.h"
|
#include "cryptfs.h"
|
||||||
|
@ -41,9 +42,13 @@
|
||||||
#include "cutils/properties.h"
|
#include "cutils/properties.h"
|
||||||
|
|
||||||
#define DM_CRYPT_BUF_SIZE 4096
|
#define DM_CRYPT_BUF_SIZE 4096
|
||||||
|
#define DATA_MNT_POINT "/data"
|
||||||
|
|
||||||
char *me = "cryptfs";
|
char *me = "cryptfs";
|
||||||
|
|
||||||
|
static unsigned char saved_key_sha1[20] = { '\0' };
|
||||||
|
static int key_sha1_saved = 0;
|
||||||
|
|
||||||
static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
|
static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
|
||||||
{
|
{
|
||||||
memset(io, 0, dataSize);
|
memset(io, 0, dataSize);
|
||||||
|
@ -150,13 +155,7 @@ static int get_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *cryp
|
||||||
* encryption info footer and key, and plenty of bytes to spare for future
|
* encryption info footer and key, and plenty of bytes to spare for future
|
||||||
* growth.
|
* growth.
|
||||||
*/
|
*/
|
||||||
#if 1 /* The real location, use when the enable code works */
|
|
||||||
off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET;
|
off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET;
|
||||||
#else
|
|
||||||
/* For testing, I'm slapping a handbuild header after my 200 megabyte
|
|
||||||
* /data partition. So my offset if 200 megabytes */
|
|
||||||
off = 200*1024*1024;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (lseek64(fd, off, SEEK_SET) == -1) {
|
if (lseek64(fd, off, SEEK_SET) == -1) {
|
||||||
SLOGE("Cannot seek to real block device footer\n");
|
SLOGE("Cannot seek to real block device footer\n");
|
||||||
|
@ -343,36 +342,31 @@ errout:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we need to debug this, look at Devmapper.cpp:dumpState(),
|
|
||||||
* It does DM_LIST_DEVICES, then iterates on each device and
|
|
||||||
* calls DM_DEV_STATUS.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define HASH_COUNT 2000
|
#define HASH_COUNT 2000
|
||||||
#define KEY_LEN_BYTES 16
|
#define KEY_LEN_BYTES 16
|
||||||
#define IV_LEN_BYTES 16
|
#define IV_LEN_BYTES 16
|
||||||
|
|
||||||
static int create_encrypted_random_key(char *passwd, unsigned char *master_key)
|
static void pbkdf2(char *passwd, unsigned char *ikey)
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
unsigned char buf[KEY_LEN_BYTES];
|
|
||||||
unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */
|
|
||||||
unsigned char salt[32] = { 0 };
|
unsigned char salt[32] = { 0 };
|
||||||
EVP_CIPHER_CTX e_ctx;
|
|
||||||
int encrypted_len, final_len;
|
|
||||||
|
|
||||||
/* Get some random bits for a key */
|
|
||||||
fd = open("/dev/urandom", O_RDONLY);
|
|
||||||
read(fd, buf, sizeof(buf));
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
/* Now encrypt it with the password */
|
|
||||||
/* To Do: Make a salt based on some immutable data about this device.
|
/* To Do: Make a salt based on some immutable data about this device.
|
||||||
* IMEI, or MEID, or CPU serial number, or whatever we can find
|
* IMEI, or MEID, or CPU serial number, or whatever we can find
|
||||||
*/
|
*/
|
||||||
/* Turn the password into a key and IV that can decrypt the master key */
|
/* Turn the password into a key and IV that can decrypt the master key */
|
||||||
PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, sizeof(salt),
|
PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, sizeof(salt),
|
||||||
HASH_COUNT, KEY_LEN_BYTES+IV_LEN_BYTES, ikey);
|
HASH_COUNT, KEY_LEN_BYTES+IV_LEN_BYTES, ikey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encrypt_master_key(char *passwd, unsigned char *decrypted_master_key,
|
||||||
|
unsigned char *encrypted_master_key)
|
||||||
|
{
|
||||||
|
unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */
|
||||||
|
EVP_CIPHER_CTX e_ctx;
|
||||||
|
int encrypted_len, final_len;
|
||||||
|
|
||||||
|
/* Turn the password into a key and IV that can decrypt the master key */
|
||||||
|
pbkdf2(passwd, ikey);
|
||||||
|
|
||||||
/* Initialize the decryption engine */
|
/* Initialize the decryption engine */
|
||||||
if (! EVP_EncryptInit(&e_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) {
|
if (! EVP_EncryptInit(&e_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) {
|
||||||
|
@ -380,13 +374,14 @@ static int create_encrypted_random_key(char *passwd, unsigned char *master_key)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
EVP_CIPHER_CTX_set_padding(&e_ctx, 0); /* Turn off padding as our data is block aligned */
|
EVP_CIPHER_CTX_set_padding(&e_ctx, 0); /* Turn off padding as our data is block aligned */
|
||||||
|
|
||||||
/* Encrypt the master key */
|
/* Encrypt the master key */
|
||||||
if (! EVP_EncryptUpdate(&e_ctx, master_key, &encrypted_len,
|
if (! EVP_EncryptUpdate(&e_ctx, encrypted_master_key, &encrypted_len,
|
||||||
buf, KEY_LEN_BYTES)) {
|
decrypted_master_key, KEY_LEN_BYTES)) {
|
||||||
SLOGE("EVP_EncryptUpdate failed\n");
|
SLOGE("EVP_EncryptUpdate failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (! EVP_EncryptFinal(&e_ctx, master_key + encrypted_len, &final_len)) {
|
if (! EVP_EncryptFinal(&e_ctx, encrypted_master_key + encrypted_len, &final_len)) {
|
||||||
SLOGE("EVP_EncryptFinal failed\n");
|
SLOGE("EVP_EncryptFinal failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -403,16 +398,11 @@ static int decrypt_master_key(char *passwd, unsigned char *encrypted_master_key,
|
||||||
unsigned char *decrypted_master_key)
|
unsigned char *decrypted_master_key)
|
||||||
{
|
{
|
||||||
unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */
|
unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */
|
||||||
unsigned char salt[32] = { 0 };
|
|
||||||
EVP_CIPHER_CTX d_ctx;
|
EVP_CIPHER_CTX d_ctx;
|
||||||
int decrypted_len, final_len;
|
int decrypted_len, final_len;
|
||||||
|
|
||||||
/* To Do: Make a salt based on some immutable data about this device.
|
|
||||||
* IMEI, or MEID, or CPU serial number, or whatever we can find
|
|
||||||
*/
|
|
||||||
/* Turn the password into a key and IV that can decrypt the master key */
|
/* Turn the password into a key and IV that can decrypt the master key */
|
||||||
PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), salt, sizeof(salt),
|
pbkdf2(passwd, ikey);
|
||||||
HASH_COUNT, KEY_LEN_BYTES+IV_LEN_BYTES, ikey);
|
|
||||||
|
|
||||||
/* Initialize the decryption engine */
|
/* Initialize the decryption engine */
|
||||||
if (! EVP_DecryptInit(&d_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) {
|
if (! EVP_DecryptInit(&d_ctx, EVP_aes_128_cbc(), ikey, ikey+KEY_LEN_BYTES)) {
|
||||||
|
@ -435,6 +425,24 @@ static int decrypt_master_key(char *passwd, unsigned char *encrypted_master_key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int create_encrypted_random_key(char *passwd, unsigned char *master_key)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned char buf[KEY_LEN_BYTES];
|
||||||
|
unsigned char ikey[32+32] = { 0 }; /* Big enough to hold a 256 bit key and 256 bit IV */
|
||||||
|
unsigned char salt[32] = { 0 };
|
||||||
|
EVP_CIPHER_CTX e_ctx;
|
||||||
|
int encrypted_len, final_len;
|
||||||
|
|
||||||
|
/* Get some random bits for a key */
|
||||||
|
fd = open("/dev/urandom", O_RDONLY);
|
||||||
|
read(fd, buf, sizeof(buf));
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
/* Now encrypt it with the password */
|
||||||
|
return encrypt_master_key(passwd, buf, master_key);
|
||||||
|
}
|
||||||
|
|
||||||
static int get_orig_mount_parms(char *mount_point, char *fs_type, char *real_blkdev,
|
static int get_orig_mount_parms(char *mount_point, char *fs_type, char *real_blkdev,
|
||||||
unsigned long *mnt_flags, char *fs_options)
|
unsigned long *mnt_flags, char *fs_options)
|
||||||
{
|
{
|
||||||
|
@ -482,6 +490,36 @@ static int wait_and_unmount(char *mountpoint)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DATA_PREP_TIMEOUT 100
|
||||||
|
static int prep_data_fs(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Do the prep of the /data filesystem */
|
||||||
|
property_set("vold.post_fs_data_done", "0");
|
||||||
|
property_set("vold.decrypt", "trigger_post_fs_data");
|
||||||
|
SLOGD("Just triggered post_fs_data\n");
|
||||||
|
|
||||||
|
/* Wait a max of 25 seconds, hopefully it takes much less */
|
||||||
|
for (i=0; i<DATA_PREP_TIMEOUT; i++) {
|
||||||
|
char p[16];;
|
||||||
|
|
||||||
|
property_get("vold.post_fs_data_done", p, "0");
|
||||||
|
if (*p == '1') {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
usleep(250000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == DATA_PREP_TIMEOUT) {
|
||||||
|
/* Ugh, we failed to prep /data in time. Bail. */
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
SLOGD("post_fs_data done\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int cryptfs_restart(void)
|
int cryptfs_restart(void)
|
||||||
{
|
{
|
||||||
char fs_type[32];
|
char fs_type[32];
|
||||||
|
@ -491,7 +529,6 @@ int cryptfs_restart(void)
|
||||||
unsigned long mnt_flags;
|
unsigned long mnt_flags;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
int rc = -1, i;
|
int rc = -1, i;
|
||||||
#define DATA_PREP_TIMEOUT 100
|
|
||||||
|
|
||||||
/* Here is where we shut down the framework. The init scripts
|
/* Here is where we shut down the framework. The init scripts
|
||||||
* start all services in one of three classes: core, main or late_start.
|
* start all services in one of three classes: core, main or late_start.
|
||||||
|
@ -523,31 +560,15 @@ int cryptfs_restart(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! get_orig_mount_parms("/data", fs_type, real_blkdev, &mnt_flags, fs_options)) {
|
if (! get_orig_mount_parms(DATA_MNT_POINT, fs_type, real_blkdev, &mnt_flags, fs_options)) {
|
||||||
SLOGD("Just got orig mount parms\n");
|
SLOGD("Just got orig mount parms\n");
|
||||||
|
|
||||||
if (! (rc = wait_and_unmount("/data")) ) {
|
if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
|
||||||
/* If that succeeded, then mount the decrypted filesystem */
|
/* If that succeeded, then mount the decrypted filesystem */
|
||||||
mount(crypto_blkdev, "/data", fs_type, mnt_flags, fs_options);
|
mount(crypto_blkdev, DATA_MNT_POINT, fs_type, mnt_flags, fs_options);
|
||||||
|
|
||||||
/* Do the prep of the /data filesystem */
|
/* Create necessary paths on /data */
|
||||||
property_set("vold.post_fs_data_done", "0");
|
if (prep_data_fs()) {
|
||||||
property_set("vold.decrypt", "trigger_post_fs_data");
|
|
||||||
SLOGD("Just triggered post_fs_data\n");
|
|
||||||
|
|
||||||
/* Wait a max of 25 seconds, hopefully it takes much less */
|
|
||||||
for (i=0; i<DATA_PREP_TIMEOUT; i++) {
|
|
||||||
char p[16];;
|
|
||||||
|
|
||||||
property_get("vold.post_fs_data_done", p, "0");
|
|
||||||
if (*p == '1') {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
usleep(250000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == DATA_PREP_TIMEOUT) {
|
|
||||||
/* Ugh, we failed to prep /data in time. Bail. */
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,6 +654,12 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point)
|
||||||
* so we can mount it when restarting the framework.
|
* so we can mount it when restarting the framework.
|
||||||
*/
|
*/
|
||||||
property_set("ro.crypto.fs_crypto_blkdev", crypto_blkdev);
|
property_set("ro.crypto.fs_crypto_blkdev", crypto_blkdev);
|
||||||
|
/* Also save a SHA1 of the master key so we can know if we
|
||||||
|
* successfully decrypted the key when we want to change the
|
||||||
|
* password on it.
|
||||||
|
*/
|
||||||
|
SHA1(decrypted_master_key, KEY_LEN_BYTES, saved_key_sha1);
|
||||||
|
key_sha1_saved = 1;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,7 +670,7 @@ int cryptfs_check_passwd(char *passwd)
|
||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
rc = test_mount_encrypted_fs(passwd, "/data");
|
rc = test_mount_encrypted_fs(passwd, DATA_MNT_POINT);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -707,6 +734,7 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, off64_
|
||||||
char *buf[CRYPT_INPLACE_BUFSIZE];
|
char *buf[CRYPT_INPLACE_BUFSIZE];
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
off64_t numblocks, i, remainder;
|
off64_t numblocks, i, remainder;
|
||||||
|
off64_t one_pct, cur_pct, new_pct;
|
||||||
|
|
||||||
if ( (realfd = open(real_blkdev, O_RDONLY)) < 0) {
|
if ( (realfd = open(real_blkdev, O_RDONLY)) < 0) {
|
||||||
SLOGE("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev);
|
SLOGE("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev);
|
||||||
|
@ -729,11 +757,18 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, off64_
|
||||||
|
|
||||||
SLOGE("Encrypting filesystem in place...");
|
SLOGE("Encrypting filesystem in place...");
|
||||||
|
|
||||||
|
one_pct = numblocks / 100;
|
||||||
|
cur_pct = 0;
|
||||||
/* process the majority of the filesystem in blocks */
|
/* process the majority of the filesystem in blocks */
|
||||||
for (i=0; i<numblocks; i++) {
|
for (i=0; i<numblocks; i++) {
|
||||||
if ( ! (i % 65536)) { //KEN
|
new_pct = i / one_pct;
|
||||||
SLOGE("|"); //KEN
|
if (new_pct > cur_pct) {
|
||||||
} //KEN
|
char buf[8];
|
||||||
|
|
||||||
|
cur_pct = new_pct;
|
||||||
|
snprintf(buf, sizeof(buf), "%lld", cur_pct);
|
||||||
|
property_set("vold.encrypt_progress", buf);
|
||||||
|
}
|
||||||
if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
|
if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
|
||||||
SLOGE("Error reading real_blkdev %s for inplace encrypt\n", crypto_blkdev);
|
SLOGE("Error reading real_blkdev %s for inplace encrypt\n", crypto_blkdev);
|
||||||
goto errout;
|
goto errout;
|
||||||
|
@ -756,6 +791,8 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, off64_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property_set("vold.encrypt_progress", "100");
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
errout:
|
errout:
|
||||||
|
@ -767,6 +804,9 @@ errout:
|
||||||
|
|
||||||
#define CRYPTO_ENABLE_WIPE 1
|
#define CRYPTO_ENABLE_WIPE 1
|
||||||
#define CRYPTO_ENABLE_INPLACE 2
|
#define CRYPTO_ENABLE_INPLACE 2
|
||||||
|
|
||||||
|
#define FRAMEWORK_BOOT_WAIT 60
|
||||||
|
|
||||||
int cryptfs_enable(char *howarg, char *passwd)
|
int cryptfs_enable(char *howarg, char *passwd)
|
||||||
{
|
{
|
||||||
int how = 0;
|
int how = 0;
|
||||||
|
@ -774,8 +814,9 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
char fs_type[32], fs_options[256], mount_point[32];
|
char fs_type[32], fs_options[256], mount_point[32];
|
||||||
unsigned long mnt_flags, nr_sec;
|
unsigned long mnt_flags, nr_sec;
|
||||||
unsigned char master_key[16], decrypted_master_key[16];
|
unsigned char master_key[16], decrypted_master_key[16];
|
||||||
int rc, fd;
|
int rc=-1, fd, i;
|
||||||
struct crypt_mnt_ftr crypt_ftr;
|
struct crypt_mnt_ftr crypt_ftr;
|
||||||
|
char tmpfs_options[80];
|
||||||
|
|
||||||
if (!strcmp(howarg, "wipe")) {
|
if (!strcmp(howarg, "wipe")) {
|
||||||
how = CRYPTO_ENABLE_WIPE;
|
how = CRYPTO_ENABLE_WIPE;
|
||||||
|
@ -789,7 +830,7 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options);
|
get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options);
|
||||||
|
|
||||||
/* The init files are setup to stop the class main and late start when
|
/* The init files are setup to stop the class main and late start when
|
||||||
* set to 4. They also unmount the fuse filesystem /mnt/sdcard on stingray.
|
* vold sets trigger_shutdown_framework.
|
||||||
*/
|
*/
|
||||||
property_set("vold.decrypt", "trigger_shutdown_framework");
|
property_set("vold.decrypt", "trigger_shutdown_framework");
|
||||||
SLOGD("Just asked init to shut down class main\n");
|
SLOGD("Just asked init to shut down class main\n");
|
||||||
|
@ -799,12 +840,56 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now unmount the /data partition. */
|
/* Now unmount the /data partition. */
|
||||||
if (! (rc = wait_and_unmount("/data")) ) {
|
if (wait_and_unmount(DATA_MNT_POINT)) {
|
||||||
/* OK, we've unmounted /data, time to setup an encrypted
|
return -1;
|
||||||
* mapping, and either write a new filesystem or encrypt
|
}
|
||||||
* in place.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/* Do extra work for a better UX when doing the long inplace encryption */
|
||||||
|
if (how == CRYPTO_ENABLE_INPLACE) {
|
||||||
|
/* Now that /data is unmounted, we need to mount a tmpfs
|
||||||
|
* /data, set a property saying we're doing inplace encryption,
|
||||||
|
* and restart the framework.
|
||||||
|
*/
|
||||||
|
property_get("ro.crypto.tmpfs_options", tmpfs_options, "");
|
||||||
|
if (mount("tmpfs", DATA_MNT_POINT, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
|
||||||
|
tmpfs_options) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Tells the framework that inplace encryption is starting */
|
||||||
|
property_set("vold.encrypt_progress", "startup");
|
||||||
|
|
||||||
|
/* restart the framework. */
|
||||||
|
/* Create necessary paths on /data */
|
||||||
|
if (prep_data_fs()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* startup service classes main and late_start */
|
||||||
|
property_set("vold.decrypt", "trigger_restart_min_framework");
|
||||||
|
SLOGD("Just triggered restart_min_framework\n");
|
||||||
|
|
||||||
|
/* Wait till the framework is ready */
|
||||||
|
for (i=0; i<FRAMEWORK_BOOT_WAIT; i++) {
|
||||||
|
char progress_state[32];
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
property_get("vold.encrypt_progress", progress_state, "");
|
||||||
|
if (! strcmp(progress_state, "ready")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == FRAMEWORK_BOOT_WAIT) {
|
||||||
|
/* The framework never rebooted, so abort */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* OK, the framework is restarted and displaying a progress bar,
|
||||||
|
* time to setup an encrypted mapping, and either write a new
|
||||||
|
* filesystem or encrypt in place, updating the progress bar
|
||||||
|
* as we work.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start the actual work of making an encrypted filesystem */
|
||||||
fd = open(real_blkdev, O_RDONLY);
|
fd = open(real_blkdev, O_RDONLY);
|
||||||
if ( (nr_sec = get_blkdev_size(fd)) == 0) {
|
if ( (nr_sec = get_blkdev_size(fd)) == 0) {
|
||||||
SLOGE("Cannot get size of block device %s\n", real_blkdev);
|
SLOGE("Cannot get size of block device %s\n", real_blkdev);
|
||||||
|
@ -839,12 +924,58 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! rc) {
|
/* Undo the dm-crypt mapping whether we succeed or not */
|
||||||
delete_crypto_blk_dev(crypto_blkdev);
|
delete_crypto_blk_dev(crypto_blkdev);
|
||||||
|
|
||||||
|
if (! rc) {
|
||||||
|
/* Success */
|
||||||
|
sleep(2); /* Give the UI a change to show 100% progress */
|
||||||
sync();
|
sync();
|
||||||
reboot(LINUX_REBOOT_CMD_RESTART);
|
reboot(LINUX_REBOOT_CMD_RESTART);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Only returns on error */
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cryptfs_changepw(char *oldpw, char *newpw)
|
||||||
|
{
|
||||||
|
struct crypt_mnt_ftr crypt_ftr;
|
||||||
|
unsigned char encrypted_master_key[32], decrypted_master_key[32];
|
||||||
|
unsigned char new_key_sha1[20];
|
||||||
|
char real_blkdev[MAXPATHLEN];
|
||||||
|
|
||||||
|
/* This is only allowed after we've successfully decrypted the master key */
|
||||||
|
if (! key_sha1_saved) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
property_get("ro.crypto.fs_real_blkdev", real_blkdev, "");
|
||||||
|
if (strlen(real_blkdev) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get key */
|
||||||
|
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key)) {
|
||||||
|
SLOGE("Error getting crypt footer and key\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decrypt key with old passwd */
|
||||||
|
decrypt_master_key(oldpw, encrypted_master_key, decrypted_master_key);
|
||||||
|
|
||||||
|
/* compute sha1 of decrypted key */
|
||||||
|
SHA1(decrypted_master_key, KEY_LEN_BYTES, new_key_sha1);
|
||||||
|
|
||||||
|
/* If computed sha1 and saved sha1 match, encrypt key with new passwd */
|
||||||
|
if (! memcmp(saved_key_sha1, new_key_sha1, sizeof(saved_key_sha1))) {
|
||||||
|
/* they match, it's safe to re-encrypt the key */
|
||||||
|
encrypt_master_key(newpw, decrypted_master_key, encrypted_master_key);
|
||||||
|
|
||||||
|
/* save the key */
|
||||||
|
put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key);
|
||||||
} else {
|
} else {
|
||||||
|
SLOGE("SHA1 mismatch");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ extern "C" {
|
||||||
int cryptfs_check_passwd(char *pw);
|
int cryptfs_check_passwd(char *pw);
|
||||||
int cryptfs_restart(void);
|
int cryptfs_restart(void);
|
||||||
int cryptfs_enable(char *flag, char *passwd);
|
int cryptfs_enable(char *flag, char *passwd);
|
||||||
|
int cryptfs_changepw(char *oldpw, char *newpw);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue