vold: Add support for unencrypted persistent info
In order to display the correct language, timezone, airplane mode and other settings on the decrypt screen, a copy of those settings needs to be stored unencrypted so the framework can query them. This adds support to vold to store up to 32 property like key/value pairs that are not encrypted. Change-Id: Id5c936d2c57d46ed5cff9325d92ba1e8d2ec8972
This commit is contained in:
parent
d3ae5221e2
commit
160b4d68ec
4 changed files with 653 additions and 209 deletions
|
@ -598,6 +598,25 @@ int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
|
|||
}
|
||||
SLOGD("cryptfs verifypw {}");
|
||||
rc = cryptfs_verify_passwd(argv[2]);
|
||||
} else if (!strcmp(argv[1], "getfield")) {
|
||||
char valbuf[PROPERTY_VALUE_MAX];
|
||||
|
||||
if (argc != 3) {
|
||||
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
|
||||
return 0;
|
||||
}
|
||||
dumpArgs(argc, argv, -1);
|
||||
rc = cryptfs_getfield(argv[2], valbuf, sizeof(valbuf));
|
||||
if (rc == 0) {
|
||||
cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
|
||||
}
|
||||
} else if (!strcmp(argv[1], "setfield")) {
|
||||
if (argc != 4) {
|
||||
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
|
||||
return 0;
|
||||
}
|
||||
dumpArgs(argc, argv, -1);
|
||||
rc = cryptfs_setfield(argv[2], argv[3]);
|
||||
} else {
|
||||
dumpArgs(argc, argv, -1);
|
||||
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
static const int VolumeListResult = 110;
|
||||
static const int AsecListResult = 111;
|
||||
static const int StorageUsersListResult = 112;
|
||||
static const int CryptfsGetfieldResult = 113;
|
||||
|
||||
// 200 series - Requested action has been successfully completed
|
||||
static const int CommandOkay = 200;
|
||||
|
|
783
cryptfs.c
783
cryptfs.c
|
@ -64,9 +64,9 @@
|
|||
char *me = "cryptfs";
|
||||
|
||||
static unsigned char saved_master_key[KEY_LEN_BYTES];
|
||||
static char *saved_data_blkdev;
|
||||
static char *saved_mount_point;
|
||||
static int master_key_saved = 0;
|
||||
static struct crypt_persist_data *persist_data = NULL;
|
||||
|
||||
extern struct fstab *fstab;
|
||||
|
||||
|
@ -126,53 +126,91 @@ static unsigned int get_blkdev_size(int fd)
|
|||
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;
|
||||
char key_loc[PROPERTY_VALUE_MAX];
|
||||
char real_blkdev[PROPERTY_VALUE_MAX];
|
||||
unsigned int nr_sec;
|
||||
int rc = -1;
|
||||
|
||||
if (!cached_data) {
|
||||
fs_mgr_get_crypt_info(fstab, key_loc, real_blkdev, sizeof(key_loc));
|
||||
|
||||
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
|
||||
if ( (fd = open(real_blkdev, O_RDWR)) < 0) {
|
||||
SLOGE("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 {
|
||||
SLOGE("Cannot get size of block device %s\n", real_blkdev);
|
||||
}
|
||||
close(fd);
|
||||
} else {
|
||||
strlcpy(cached_metadata_fname, key_loc, sizeof(cached_metadata_fname));
|
||||
cached_off = 0;
|
||||
cached_data = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cached_data) {
|
||||
if (metadata_fname) {
|
||||
*metadata_fname = cached_metadata_fname;
|
||||
}
|
||||
if (off) {
|
||||
*off = cached_off;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* key or salt can be NULL, in which case just skip writing that value. Useful to
|
||||
* update the failed mount count but not change the key.
|
||||
*/
|
||||
static int put_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *crypt_ftr,
|
||||
unsigned char *key, unsigned char *salt)
|
||||
static int put_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
|
||||
{
|
||||
int fd;
|
||||
unsigned int nr_sec, cnt;
|
||||
off64_t off;
|
||||
/* starting_off is set to the SEEK_SET offset
|
||||
* where the crypto structure starts
|
||||
*/
|
||||
off64_t starting_off;
|
||||
int rc = -1;
|
||||
char *fname;
|
||||
char *fname = NULL;
|
||||
char key_loc[PROPERTY_VALUE_MAX];
|
||||
struct stat statbuf;
|
||||
|
||||
fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
|
||||
|
||||
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
|
||||
fname = real_blk_name;
|
||||
if ( (fd = open(fname, O_RDWR)) < 0) {
|
||||
SLOGE("Cannot open real block device %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( (nr_sec = get_blkdev_size(fd)) == 0) {
|
||||
SLOGE("Cannot get size of block device %s\n", fname);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* If it's an encrypted Android partition, the last 16 Kbytes contain the
|
||||
* encryption info footer and key, and plenty of bytes to spare for future
|
||||
* growth.
|
||||
*/
|
||||
off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET;
|
||||
|
||||
if (lseek64(fd, off, SEEK_SET) == -1) {
|
||||
SLOGE("Cannot seek to real block device footer\n");
|
||||
goto errout;
|
||||
}
|
||||
} else if (key_loc[0] == '/') {
|
||||
fname = key_loc;
|
||||
if ( (fd = open(fname, O_RDWR | O_CREAT, 0600)) < 0) {
|
||||
SLOGE("Cannot open footer file %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (get_crypt_ftr_info(&fname, &starting_off)) {
|
||||
SLOGE("Unable to get crypt_ftr_info\n");
|
||||
return -1;
|
||||
}
|
||||
if (fname[0] != '/') {
|
||||
SLOGE("Unexpected value for crypto key location\n");
|
||||
return -1;;
|
||||
return -1;
|
||||
}
|
||||
if ( (fd = open(fname, O_RDWR)) < 0) {
|
||||
SLOGE("Cannot open footer file %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Seek to the start of the crypt footer */
|
||||
if (lseek64(fd, starting_off, SEEK_SET) == -1) {
|
||||
SLOGE("Cannot seek to real block device footer\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if ((cnt = write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) {
|
||||
|
@ -180,36 +218,6 @@ static int put_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *cryp
|
|||
goto errout;
|
||||
}
|
||||
|
||||
if (key) {
|
||||
if (crypt_ftr->keysize != KEY_LEN_BYTES) {
|
||||
SLOGE("Keysize of %d bits not supported for real block device %s\n",
|
||||
crypt_ftr->keysize*8, fname);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if ( (cnt = write(fd, key, crypt_ftr->keysize)) != crypt_ftr->keysize) {
|
||||
SLOGE("Cannot write key for real block device %s\n", fname);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (salt) {
|
||||
/* Compute the offset from the last write to the salt */
|
||||
off = KEY_TO_SALT_PADDING;
|
||||
if (! key)
|
||||
off += crypt_ftr->keysize;
|
||||
|
||||
if (lseek64(fd, off, SEEK_CUR) == -1) {
|
||||
SLOGE("Cannot seek to real block device salt \n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if ( (cnt = write(fd, salt, SALT_LEN)) != SALT_LEN) {
|
||||
SLOGE("Cannot write salt for real block device %s\n", fname);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
fstat(fd, &statbuf);
|
||||
/* If the keys are kept on a raw block device, do not try to truncate it. */
|
||||
if (S_ISREG(statbuf.st_mode) && (key_loc[0] == '/')) {
|
||||
|
@ -228,57 +236,107 @@ errout:
|
|||
|
||||
}
|
||||
|
||||
static int get_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *crypt_ftr,
|
||||
unsigned char *key, unsigned char *salt)
|
||||
static inline int unix_read(int fd, void* buff, int len)
|
||||
{
|
||||
return TEMP_FAILURE_RETRY(read(fd, buff, len));
|
||||
}
|
||||
|
||||
static inline int unix_write(int fd, const void* buff, int len)
|
||||
{
|
||||
return TEMP_FAILURE_RETRY(write(fd, buff, len));
|
||||
}
|
||||
|
||||
static void init_empty_persist_data(struct crypt_persist_data *pdata, int len)
|
||||
{
|
||||
memset(pdata, 0, len);
|
||||
pdata->persist_magic = PERSIST_DATA_MAGIC;
|
||||
pdata->persist_valid_entries = 0;
|
||||
}
|
||||
|
||||
/* A routine to update the passed in crypt_ftr to the lastest version.
|
||||
* fd is open read/write on the device that holds the crypto footer and persistent
|
||||
* data, crypt_ftr is a pointer to the struct to be updated, and offset is the
|
||||
* absolute offset to the start of the crypt_mnt_ftr on the passed in fd.
|
||||
*/
|
||||
static void upgrade_crypt_ftr(int fd, struct crypt_mnt_ftr *crypt_ftr, off64_t offset)
|
||||
{
|
||||
struct crypt_persist_data *pdata;
|
||||
off64_t pdata_offset = offset + CRYPT_FOOTER_TO_PERSIST_OFFSET;
|
||||
|
||||
/* This routine can currently only handle upgrading from 1.0 to 1.1.
|
||||
* Do nothing if the passed structure is not version 1.0
|
||||
*/
|
||||
|
||||
if ((crypt_ftr->major_version != 1) && (crypt_ftr->minor_version != 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pdata = malloc(CRYPT_PERSIST_DATA_SIZE);
|
||||
if (pdata == NULL) {
|
||||
SLOGE("Cannot allocate persisent data\n");
|
||||
return;
|
||||
}
|
||||
memset(pdata, 0, CRYPT_PERSIST_DATA_SIZE);
|
||||
|
||||
/* Need to initialize the persistent data area */
|
||||
if (lseek64(fd, pdata_offset, SEEK_SET) == -1) {
|
||||
SLOGE("Cannot seek to persisent data offset\n");
|
||||
return;
|
||||
}
|
||||
/* Write all zeros to the first copy, making it invalid */
|
||||
unix_write(fd, pdata, CRYPT_PERSIST_DATA_SIZE);
|
||||
|
||||
/* Write a valid but empty structure to the second copy */
|
||||
init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE);
|
||||
unix_write(fd, pdata, CRYPT_PERSIST_DATA_SIZE);
|
||||
|
||||
/* Update the footer */
|
||||
crypt_ftr->persist_data_size = CRYPT_PERSIST_DATA_SIZE;
|
||||
crypt_ftr->persist_data_offset[0] = pdata_offset;
|
||||
crypt_ftr->persist_data_offset[1] = pdata_offset + CRYPT_PERSIST_DATA_SIZE;
|
||||
crypt_ftr->minor_version = 1;
|
||||
if (lseek64(fd, offset, SEEK_SET) == -1) {
|
||||
SLOGE("Cannot seek to crypt footer\n");
|
||||
return;
|
||||
}
|
||||
unix_write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr));
|
||||
}
|
||||
|
||||
|
||||
static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr)
|
||||
{
|
||||
int fd;
|
||||
unsigned int nr_sec, cnt;
|
||||
off64_t off;
|
||||
off64_t starting_off;
|
||||
int rc = -1;
|
||||
char key_loc[PROPERTY_VALUE_MAX];
|
||||
char *fname;
|
||||
char *fname = NULL;
|
||||
struct stat statbuf;
|
||||
|
||||
fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
|
||||
|
||||
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
|
||||
fname = real_blk_name;
|
||||
if ( (fd = open(fname, O_RDONLY)) < 0) {
|
||||
SLOGE("Cannot open real block device %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( (nr_sec = get_blkdev_size(fd)) == 0) {
|
||||
SLOGE("Cannot get size of block device %s\n", fname);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* If it's an encrypted Android partition, the last 16 Kbytes contain the
|
||||
* encryption info footer and key, and plenty of bytes to spare for future
|
||||
* growth.
|
||||
*/
|
||||
off = ((off64_t)nr_sec * 512) - CRYPT_FOOTER_OFFSET;
|
||||
|
||||
if (lseek64(fd, off, SEEK_SET) == -1) {
|
||||
SLOGE("Cannot seek to real block device footer\n");
|
||||
goto errout;
|
||||
}
|
||||
} else if (key_loc[0] == '/') {
|
||||
fname = key_loc;
|
||||
if ( (fd = open(fname, O_RDONLY)) < 0) {
|
||||
SLOGE("Cannot open footer file %s\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)) {
|
||||
SLOGE("footer file %s is not the expected size!\n", fname);
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
if (get_crypt_ftr_info(&fname, &starting_off)) {
|
||||
SLOGE("Unable to get crypt_ftr_info\n");
|
||||
return -1;
|
||||
}
|
||||
if (fname[0] != '/') {
|
||||
SLOGE("Unexpected value for crypto key location\n");
|
||||
return -1;;
|
||||
return -1;
|
||||
}
|
||||
if ( (fd = open(fname, O_RDWR)) < 0) {
|
||||
SLOGE("Cannot open footer file %s\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)) {
|
||||
SLOGE("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) {
|
||||
SLOGE("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)) {
|
||||
|
@ -297,40 +355,16 @@ static int get_crypt_ftr_and_key(char *real_blk_name, struct crypt_mnt_ftr *cryp
|
|||
goto errout;
|
||||
}
|
||||
|
||||
if (crypt_ftr->minor_version != 0) {
|
||||
SLOGW("Warning: crypto footer minor version %d, expected 0, continuing...\n",
|
||||
if ((crypt_ftr->minor_version != 0) && (crypt_ftr->minor_version != 1)) {
|
||||
SLOGW("Warning: crypto footer minor version %d, expected 0 or 1, continuing...\n",
|
||||
crypt_ftr->minor_version);
|
||||
}
|
||||
|
||||
if (crypt_ftr->ftr_size > sizeof(struct crypt_mnt_ftr)) {
|
||||
/* the footer size is bigger than we expected.
|
||||
* Skip to it's stated end so we can read the key.
|
||||
*/
|
||||
if (lseek(fd, crypt_ftr->ftr_size - sizeof(struct crypt_mnt_ftr), SEEK_CUR) == -1) {
|
||||
SLOGE("Cannot seek to start of key\n");
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (crypt_ftr->keysize != KEY_LEN_BYTES) {
|
||||
SLOGE("Keysize of %d bits not supported for real block device %s\n",
|
||||
crypt_ftr->keysize * 8, fname);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if ( (cnt = read(fd, key, crypt_ftr->keysize)) != crypt_ftr->keysize) {
|
||||
SLOGE("Cannot read key for real block device %s\n", fname);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (lseek64(fd, KEY_TO_SALT_PADDING, SEEK_CUR) == -1) {
|
||||
SLOGE("Cannot seek to real block device salt\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if ( (cnt = read(fd, salt, SALT_LEN)) != SALT_LEN) {
|
||||
SLOGE("Cannot read salt for real block device %s\n", fname);
|
||||
goto errout;
|
||||
/* 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 == 0) {
|
||||
upgrade_crypt_ftr(fd, crypt_ftr, starting_off);
|
||||
}
|
||||
|
||||
/* Success! */
|
||||
|
@ -341,6 +375,227 @@ errout:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int validate_persistent_data_storage(struct crypt_mnt_ftr *crypt_ftr)
|
||||
{
|
||||
if (crypt_ftr->persist_data_offset[0] + crypt_ftr->persist_data_size >
|
||||
crypt_ftr->persist_data_offset[1]) {
|
||||
SLOGE("Crypt_ftr persist data regions overlap");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (crypt_ftr->persist_data_offset[0] >= crypt_ftr->persist_data_offset[1]) {
|
||||
SLOGE("Crypt_ftr persist data region 0 starts after region 1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (((crypt_ftr->persist_data_offset[1] + crypt_ftr->persist_data_size) -
|
||||
(crypt_ftr->persist_data_offset[0] - CRYPT_FOOTER_TO_PERSIST_OFFSET)) >
|
||||
CRYPT_FOOTER_OFFSET) {
|
||||
SLOGE("Persistent data extends past crypto footer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_persistent_data(void)
|
||||
{
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
struct crypt_persist_data *pdata = NULL;
|
||||
char encrypted_state[PROPERTY_VALUE_MAX];
|
||||
char *fname;
|
||||
int found = 0;
|
||||
int fd;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (persist_data) {
|
||||
/* Nothing to do, we've already loaded or initialized it */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* If not encrypted, just allocate an empty table and initialize it */
|
||||
property_get("ro.crypto.state", encrypted_state, "");
|
||||
if (strcmp(encrypted_state, "encrypted") ) {
|
||||
pdata = malloc(CRYPT_PERSIST_DATA_SIZE);
|
||||
if (pdata) {
|
||||
init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE);
|
||||
persist_data = pdata;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(get_crypt_ftr_and_key(&crypt_ftr)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((crypt_ftr.major_version != 1) || (crypt_ftr.minor_version != 1)) {
|
||||
SLOGE("Crypt_ftr version doesn't support persistent data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_crypt_ftr_info(&fname, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = validate_persistent_data_storage(&crypt_ftr);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(fname, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
SLOGE("Cannot open %s metadata file", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (persist_data == NULL) {
|
||||
pdata = malloc(crypt_ftr.persist_data_size);
|
||||
if (pdata == NULL) {
|
||||
SLOGE("Cannot allocate memory for persistent data");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (lseek64(fd, crypt_ftr.persist_data_offset[i], SEEK_SET) < 0) {
|
||||
SLOGE("Cannot seek to read persistent data on %s", fname);
|
||||
goto err2;
|
||||
}
|
||||
if (unix_read(fd, pdata, crypt_ftr.persist_data_size) < 0){
|
||||
SLOGE("Error reading persistent data on iteration %d", i);
|
||||
goto err2;
|
||||
}
|
||||
if (pdata->persist_magic == PERSIST_DATA_MAGIC) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
SLOGI("Could not find valid persistent data, creating");
|
||||
init_empty_persist_data(pdata, crypt_ftr.persist_data_size);
|
||||
}
|
||||
|
||||
/* Success */
|
||||
persist_data = pdata;
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
free(pdata);
|
||||
|
||||
err:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int save_persistent_data(void)
|
||||
{
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
struct crypt_persist_data *pdata;
|
||||
char *fname;
|
||||
off64_t write_offset;
|
||||
off64_t erase_offset;
|
||||
int found = 0;
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
if (persist_data == NULL) {
|
||||
SLOGE("No persistent data to save");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(get_crypt_ftr_and_key(&crypt_ftr)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((crypt_ftr.major_version != 1) || (crypt_ftr.minor_version != 1)) {
|
||||
SLOGE("Crypt_ftr version doesn't support persistent data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = validate_persistent_data_storage(&crypt_ftr);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_crypt_ftr_info(&fname, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(fname, O_RDWR);
|
||||
if (fd < 0) {
|
||||
SLOGE("Cannot open %s metadata file", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pdata = malloc(crypt_ftr.persist_data_size);
|
||||
if (pdata == NULL) {
|
||||
SLOGE("Cannot allocate persistant data");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (lseek64(fd, crypt_ftr.persist_data_offset[0], SEEK_SET) < 0) {
|
||||
SLOGE("Cannot seek to read persistent data on %s", fname);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (unix_read(fd, pdata, crypt_ftr.persist_data_size) < 0) {
|
||||
SLOGE("Error reading persistent data before save");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (pdata->persist_magic == PERSIST_DATA_MAGIC) {
|
||||
/* The first copy is the curent valid copy, so write to
|
||||
* the second copy and erase this one */
|
||||
write_offset = crypt_ftr.persist_data_offset[1];
|
||||
erase_offset = crypt_ftr.persist_data_offset[0];
|
||||
} else {
|
||||
/* The second copy must be the valid copy, so write to
|
||||
* the first copy, and erase the second */
|
||||
write_offset = crypt_ftr.persist_data_offset[0];
|
||||
erase_offset = crypt_ftr.persist_data_offset[1];
|
||||
}
|
||||
|
||||
/* Write the new copy first, if successful, then erase the old copy */
|
||||
if (lseek(fd, write_offset, SEEK_SET) < 0) {
|
||||
SLOGE("Cannot seek to write persistent data");
|
||||
goto err2;
|
||||
}
|
||||
if (unix_write(fd, persist_data, crypt_ftr.persist_data_size) ==
|
||||
(int) crypt_ftr.persist_data_size) {
|
||||
if (lseek(fd, erase_offset, SEEK_SET) < 0) {
|
||||
SLOGE("Cannot seek to erase previous persistent data");
|
||||
goto err2;
|
||||
}
|
||||
fsync(fd);
|
||||
memset(pdata, 0, crypt_ftr.persist_data_size);
|
||||
if (unix_write(fd, pdata, crypt_ftr.persist_data_size) !=
|
||||
(int) crypt_ftr.persist_data_size) {
|
||||
SLOGE("Cannot write to erase previous persistent data");
|
||||
goto err2;
|
||||
}
|
||||
fsync(fd);
|
||||
} else {
|
||||
SLOGE("Cannot write to save persistent data");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
free(pdata);
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
free(pdata);
|
||||
err:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a binary key of specified length into an ascii hex string equivalent,
|
||||
* without the leading 0x and with null termination
|
||||
*/
|
||||
|
@ -790,9 +1045,6 @@ int cryptfs_restart(void)
|
|||
static int do_crypto_complete(char *mount_point)
|
||||
{
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
unsigned char encrypted_master_key[32];
|
||||
unsigned char salt[SALT_LEN];
|
||||
char real_blkdev[MAXPATHLEN];
|
||||
char encrypted_state[PROPERTY_VALUE_MAX];
|
||||
char key_loc[PROPERTY_VALUE_MAX];
|
||||
|
||||
|
@ -802,9 +1054,7 @@ static int do_crypto_complete(char *mount_point)
|
|||
return 1;
|
||||
}
|
||||
|
||||
fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
|
||||
|
||||
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
|
||||
if (get_crypt_ftr_and_key(&crypt_ftr)) {
|
||||
fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
|
||||
|
||||
/*
|
||||
|
@ -837,8 +1087,7 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
|
|||
{
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
/* Allocate enough space for a 256 bit key, but we may use less */
|
||||
unsigned char encrypted_master_key[32], decrypted_master_key[32];
|
||||
unsigned char salt[SALT_LEN];
|
||||
unsigned char decrypted_master_key[32];
|
||||
char crypto_blkdev[MAXPATHLEN];
|
||||
char real_blkdev[MAXPATHLEN];
|
||||
char tmp_mount_point[64];
|
||||
|
@ -854,7 +1103,7 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
|
|||
|
||||
fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
|
||||
|
||||
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
|
||||
if (get_crypt_ftr_and_key(&crypt_ftr)) {
|
||||
SLOGE("Error getting crypt footer and key\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -863,7 +1112,7 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
|
|||
orig_failed_decrypt_count = crypt_ftr.failed_decrypt_count;
|
||||
|
||||
if (! (crypt_ftr.flags & CRYPT_MNT_KEY_UNENCRYPTED) ) {
|
||||
decrypt_master_key(passwd, salt, encrypted_master_key, decrypted_master_key);
|
||||
decrypt_master_key(passwd, crypt_ftr.salt, crypt_ftr.master_key, decrypted_master_key);
|
||||
}
|
||||
|
||||
if (create_crypto_blk_dev(&crypt_ftr, decrypted_master_key,
|
||||
|
@ -894,7 +1143,7 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
|
|||
}
|
||||
|
||||
if (orig_failed_decrypt_count != crypt_ftr.failed_decrypt_count) {
|
||||
put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, 0, 0);
|
||||
put_crypt_ftr_and_key(&crypt_ftr);
|
||||
}
|
||||
|
||||
if (crypt_ftr.failed_decrypt_count) {
|
||||
|
@ -911,7 +1160,6 @@ static int test_mount_encrypted_fs(char *passwd, char *mount_point, char *label)
|
|||
* the key when we want to change the password on it.
|
||||
*/
|
||||
memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES);
|
||||
saved_data_blkdev = strdup(real_blkdev);
|
||||
saved_mount_point = strdup(mount_point);
|
||||
master_key_saved = 1;
|
||||
rc = 0;
|
||||
|
@ -940,14 +1188,12 @@ int cryptfs_setup_volume(const char *label, int major, int minor,
|
|||
{
|
||||
char real_blkdev[MAXPATHLEN], crypto_blkdev[MAXPATHLEN];
|
||||
struct crypt_mnt_ftr sd_crypt_ftr;
|
||||
unsigned char key[32], salt[32];
|
||||
struct stat statbuf;
|
||||
int nr_sec, fd;
|
||||
|
||||
sprintf(real_blkdev, "/dev/block/vold/%d:%d", major, minor);
|
||||
|
||||
/* Just want the footer, but gotta get it all */
|
||||
get_crypt_ftr_and_key(saved_data_blkdev, &sd_crypt_ftr, key, salt);
|
||||
get_crypt_ftr_and_key(&sd_crypt_ftr);
|
||||
|
||||
/* Update the fs_size field to be the size of the volume */
|
||||
fd = open(real_blkdev, O_RDONLY);
|
||||
|
@ -990,9 +1236,7 @@ int cryptfs_verify_passwd(char *passwd)
|
|||
{
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
/* Allocate enough space for a 256 bit key, but we may use less */
|
||||
unsigned char encrypted_master_key[32], decrypted_master_key[32];
|
||||
unsigned char salt[SALT_LEN];
|
||||
char real_blkdev[MAXPATHLEN];
|
||||
unsigned char decrypted_master_key[32];
|
||||
char encrypted_state[PROPERTY_VALUE_MAX];
|
||||
int rc;
|
||||
|
||||
|
@ -1012,9 +1256,7 @@ int cryptfs_verify_passwd(char *passwd)
|
|||
return -1;
|
||||
}
|
||||
|
||||
fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
|
||||
|
||||
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
|
||||
if (get_crypt_ftr_and_key(&crypt_ftr)) {
|
||||
SLOGE("Error getting crypt footer and key\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -1023,7 +1265,8 @@ int cryptfs_verify_passwd(char *passwd)
|
|||
/* If the device has no password, then just say the password is valid */
|
||||
rc = 0;
|
||||
} else {
|
||||
decrypt_master_key(passwd, salt, encrypted_master_key, decrypted_master_key);
|
||||
decrypt_master_key(passwd, crypt_ftr.salt, crypt_ftr.master_key,
|
||||
decrypted_master_key);
|
||||
if (!memcmp(decrypted_master_key, saved_master_key, crypt_ftr.keysize)) {
|
||||
/* They match, the password is correct */
|
||||
rc = 0;
|
||||
|
@ -1044,16 +1287,21 @@ int cryptfs_verify_passwd(char *passwd)
|
|||
*/
|
||||
static void cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr)
|
||||
{
|
||||
off64_t off;
|
||||
|
||||
memset(ftr, 0, sizeof(struct crypt_mnt_ftr));
|
||||
ftr->magic = CRYPT_MNT_MAGIC;
|
||||
ftr->major_version = 1;
|
||||
ftr->minor_version = 0;
|
||||
ftr->minor_version = 1;
|
||||
ftr->ftr_size = sizeof(struct crypt_mnt_ftr);
|
||||
ftr->flags = 0;
|
||||
ftr->keysize = KEY_LEN_BYTES;
|
||||
ftr->spare1 = 0;
|
||||
ftr->fs_size = 0;
|
||||
ftr->failed_decrypt_count = 0;
|
||||
ftr->crypto_type_name[0] = '\0';
|
||||
|
||||
ftr->persist_data_size = CRYPT_PERSIST_DATA_SIZE;
|
||||
if (get_crypt_ftr_info(NULL, &off) == 0) {
|
||||
ftr->persist_data_offset[0] = off + CRYPT_FOOTER_TO_PERSIST_OFFSET;
|
||||
ftr->persist_data_offset[1] = off + CRYPT_FOOTER_TO_PERSIST_OFFSET +
|
||||
ftr->persist_data_size;
|
||||
}
|
||||
}
|
||||
|
||||
static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type)
|
||||
|
@ -1084,20 +1332,6 @@ static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static inline int unix_read(int fd, void* buff, int len)
|
||||
{
|
||||
int ret;
|
||||
do { ret = read(fd, buff, len); } while (ret < 0 && errno == EINTR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int unix_write(int fd, const void* buff, int len)
|
||||
{
|
||||
int ret;
|
||||
do { ret = write(fd, buff, len); } while (ret < 0 && errno == EINTR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CRYPT_INPLACE_BUFSIZE 4096
|
||||
#define CRYPT_SECTORS_PER_BUFSIZE (CRYPT_INPLACE_BUFSIZE / 512)
|
||||
static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, off64_t size,
|
||||
|
@ -1193,10 +1427,10 @@ int cryptfs_enable(char *howarg, char *passwd)
|
|||
int how = 0;
|
||||
char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN], sd_crypto_blkdev[MAXPATHLEN];
|
||||
unsigned long nr_sec;
|
||||
unsigned char master_key[KEY_LEN_BYTES], decrypted_master_key[KEY_LEN_BYTES];
|
||||
unsigned char salt[SALT_LEN];
|
||||
unsigned char decrypted_master_key[KEY_LEN_BYTES];
|
||||
int rc=-1, fd, i, ret;
|
||||
struct crypt_mnt_ftr crypt_ftr, sd_crypt_ftr;;
|
||||
struct crypt_persist_data *pdata;
|
||||
char tmpfs_options[PROPERTY_VALUE_MAX];
|
||||
char encrypted_state[PROPERTY_VALUE_MAX];
|
||||
char lockid[32] = { 0 };
|
||||
|
@ -1357,6 +1591,7 @@ int cryptfs_enable(char *howarg, char *passwd)
|
|||
/* Start the actual work of making an encrypted filesystem */
|
||||
/* Initialize a crypt_mnt_ftr for the partition */
|
||||
cryptfs_init_crypt_mnt_ftr(&crypt_ftr);
|
||||
|
||||
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
|
||||
crypt_ftr.fs_size = nr_sec - (CRYPT_FOOTER_OFFSET / 512);
|
||||
} else {
|
||||
|
@ -1366,15 +1601,29 @@ int cryptfs_enable(char *howarg, char *passwd)
|
|||
strcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
|
||||
|
||||
/* Make an encrypted master key */
|
||||
if (create_encrypted_random_key(passwd, master_key, salt)) {
|
||||
if (create_encrypted_random_key(passwd, crypt_ftr.master_key, crypt_ftr.salt)) {
|
||||
SLOGE("Cannot create encrypted master key\n");
|
||||
goto error_unencrypted;
|
||||
}
|
||||
|
||||
/* Write the key to the end of the partition */
|
||||
put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, master_key, salt);
|
||||
put_crypt_ftr_and_key(&crypt_ftr);
|
||||
|
||||
decrypt_master_key(passwd, salt, master_key, decrypted_master_key);
|
||||
/* If any persistent data has been remembered, save it.
|
||||
* If none, create a valid empty table and save that.
|
||||
*/
|
||||
if (!persist_data) {
|
||||
pdata = malloc(CRYPT_PERSIST_DATA_SIZE);
|
||||
if (pdata) {
|
||||
init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE);
|
||||
persist_data = pdata;
|
||||
}
|
||||
}
|
||||
if (persist_data) {
|
||||
save_persistent_data();
|
||||
}
|
||||
|
||||
decrypt_master_key(passwd, crypt_ftr.salt, crypt_ftr.master_key, decrypted_master_key);
|
||||
create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev,
|
||||
"userdata");
|
||||
|
||||
|
@ -1444,7 +1693,7 @@ int cryptfs_enable(char *howarg, char *passwd)
|
|||
|
||||
/* Clear the encryption in progres flag in the footer */
|
||||
crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
|
||||
put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, 0, 0);
|
||||
put_crypt_ftr_and_key(&crypt_ftr);
|
||||
|
||||
sleep(2); /* Give the UI a chance to show 100% progress */
|
||||
android_reboot(ANDROID_RB_RESTART, 0, 0);
|
||||
|
@ -1508,9 +1757,7 @@ error_shutting_down:
|
|||
int cryptfs_changepw(char *newpw)
|
||||
{
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
unsigned char encrypted_master_key[KEY_LEN_BYTES], decrypted_master_key[KEY_LEN_BYTES];
|
||||
unsigned char salt[SALT_LEN];
|
||||
char real_blkdev[MAXPATHLEN];
|
||||
unsigned char decrypted_master_key[KEY_LEN_BYTES];
|
||||
|
||||
/* This is only allowed after we've successfully decrypted the master key */
|
||||
if (! master_key_saved) {
|
||||
|
@ -1518,22 +1765,156 @@ int cryptfs_changepw(char *newpw)
|
|||
return -1;
|
||||
}
|
||||
|
||||
fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
|
||||
if (strlen(real_blkdev) == 0) {
|
||||
SLOGE("Can't find real blkdev");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get key */
|
||||
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
|
||||
if (get_crypt_ftr_and_key(&crypt_ftr)) {
|
||||
SLOGE("Error getting crypt footer and key");
|
||||
return -1;
|
||||
}
|
||||
|
||||
encrypt_master_key(newpw, salt, saved_master_key, encrypted_master_key);
|
||||
encrypt_master_key(newpw, crypt_ftr.salt, saved_master_key, crypt_ftr.master_key);
|
||||
|
||||
/* save the key */
|
||||
put_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt);
|
||||
put_crypt_ftr_and_key(&crypt_ftr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int persist_get_key(char *fieldname, char *value)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (persist_data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < persist_data->persist_valid_entries; i++) {
|
||||
if (!strncmp(persist_data->persist_entry[i].key, fieldname, PROPERTY_KEY_MAX)) {
|
||||
/* We found it! */
|
||||
strlcpy(value, persist_data->persist_entry[i].val, PROPERTY_VALUE_MAX);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int persist_set_key(char *fieldname, char *value, int encrypted)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int num;
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
unsigned int max_persistent_entries;
|
||||
unsigned int dsize;
|
||||
|
||||
if (persist_data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If encrypted, use the values from the crypt_ftr, otherwise
|
||||
* use the values for the current spec.
|
||||
*/
|
||||
if (encrypted) {
|
||||
if(get_crypt_ftr_and_key(&crypt_ftr)) {
|
||||
return -1;
|
||||
}
|
||||
dsize = crypt_ftr.persist_data_size;
|
||||
} else {
|
||||
dsize = CRYPT_PERSIST_DATA_SIZE;
|
||||
}
|
||||
max_persistent_entries = (dsize - sizeof(struct crypt_persist_data)) /
|
||||
sizeof(struct crypt_persist_entry);
|
||||
|
||||
num = persist_data->persist_valid_entries;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (!strncmp(persist_data->persist_entry[i].key, fieldname, PROPERTY_KEY_MAX)) {
|
||||
/* We found an existing entry, update it! */
|
||||
memset(persist_data->persist_entry[i].val, 0, PROPERTY_VALUE_MAX);
|
||||
strlcpy(persist_data->persist_entry[i].val, value, PROPERTY_VALUE_MAX);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We didn't find it, add it to the end, if there is room */
|
||||
if (persist_data->persist_valid_entries < max_persistent_entries) {
|
||||
memset(&persist_data->persist_entry[num], 0, sizeof(struct crypt_persist_entry));
|
||||
strlcpy(persist_data->persist_entry[num].key, fieldname, PROPERTY_KEY_MAX);
|
||||
strlcpy(persist_data->persist_entry[num].val, value, PROPERTY_VALUE_MAX);
|
||||
persist_data->persist_valid_entries++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return the value of the specified field. */
|
||||
int cryptfs_getfield(char *fieldname, char *value, int len)
|
||||
{
|
||||
char temp_value[PROPERTY_VALUE_MAX];
|
||||
char real_blkdev[MAXPATHLEN];
|
||||
/* 0 is success, 1 is not encrypted,
|
||||
* -1 is value not set, -2 is any other error
|
||||
*/
|
||||
int rc = -2;
|
||||
|
||||
if (persist_data == NULL) {
|
||||
load_persistent_data();
|
||||
if (persist_data == NULL) {
|
||||
SLOGE("Getfield error, cannot load persistent data");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!persist_get_key(fieldname, temp_value)) {
|
||||
/* We found it, copy it to the caller's buffer and return */
|
||||
strlcpy(value, temp_value, len);
|
||||
rc = 0;
|
||||
} else {
|
||||
/* Sadness, it's not there. Return the error */
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Set the value of the specified field. */
|
||||
int cryptfs_setfield(char *fieldname, char *value)
|
||||
{
|
||||
struct crypt_persist_data stored_pdata;
|
||||
struct crypt_persist_data *pdata_p;
|
||||
struct crypt_mnt_ftr crypt_ftr;
|
||||
char encrypted_state[PROPERTY_VALUE_MAX];
|
||||
/* 0 is success, -1 is an error */
|
||||
int rc = -1;
|
||||
int encrypted = 0;
|
||||
|
||||
if (persist_data == NULL) {
|
||||
load_persistent_data();
|
||||
if (persist_data == NULL) {
|
||||
SLOGE("Setfield error, cannot load persistent data");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
property_get("ro.crypto.state", encrypted_state, "");
|
||||
if (!strcmp(encrypted_state, "encrypted") ) {
|
||||
encrypted = 1;
|
||||
}
|
||||
|
||||
if (persist_set_key(fieldname, value, encrypted)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we are running encrypted, save the persistent data now */
|
||||
if (encrypted) {
|
||||
if (save_persistent_data()) {
|
||||
SLOGE("Setfield error, cannot save persistent data");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
|
59
cryptfs.h
59
cryptfs.h
|
@ -15,22 +15,27 @@
|
|||
*/
|
||||
|
||||
/* This structure starts 16,384 bytes before the end of a hardware
|
||||
* partition that is encrypted.
|
||||
* Immediately following this structure is the encrypted key.
|
||||
* The keysize field tells how long the key is, in bytes.
|
||||
* Then there is 32 bytes of padding,
|
||||
* Finally there is the salt used with the user password.
|
||||
* The salt is fixed at 16 bytes long.
|
||||
* partition that is encrypted, or in a separate partition. It's location
|
||||
* is specified by a property set in init.<device>.rc.
|
||||
* The structure allocates 48 bytes for a key, but the real key size is
|
||||
* specified in the struct. Currently, the code is hardcoded to use 128
|
||||
* bit keys.
|
||||
* The fields after salt are only valid in rev 1.1 and later stuctures.
|
||||
* Obviously, the filesystem does not include the last 16 kbytes
|
||||
* of the partition.
|
||||
* of the partition if the crypt_mnt_ftr lives at the end of the
|
||||
* partition.
|
||||
*/
|
||||
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#define CRYPT_FOOTER_OFFSET 0x4000
|
||||
#define CRYPT_FOOTER_TO_PERSIST_OFFSET 0x1000
|
||||
#define CRYPT_PERSIST_DATA_SIZE 0x1000
|
||||
|
||||
#define MAX_CRYPTO_TYPE_NAME_LEN 64
|
||||
|
||||
#define MAX_KEY_LEN 48
|
||||
#define SALT_LEN 16
|
||||
#define KEY_TO_SALT_PADDING 32
|
||||
|
||||
/* definitions of flags in the structure below */
|
||||
#define CRYPT_MNT_KEY_UNENCRYPTED 0x1 /* The key for the partition is not encrypted. */
|
||||
|
@ -38,6 +43,7 @@
|
|||
* clear when done before rebooting */
|
||||
|
||||
#define CRYPT_MNT_MAGIC 0xD0B5B1C4
|
||||
#define PERSIST_DATA_MAGIC 0xE950CD44
|
||||
|
||||
#define __le32 unsigned int
|
||||
#define __le16 unsigned short int
|
||||
|
@ -56,6 +62,41 @@ struct crypt_mnt_ftr {
|
|||
unsigned char crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN]; /* The type of encryption
|
||||
needed to decrypt this
|
||||
partition, null terminated */
|
||||
__le32 spare2; /* ignored */
|
||||
unsigned char master_key[MAX_KEY_LEN]; /* The encrypted key for decrypting the filesystem */
|
||||
unsigned char salt[SALT_LEN]; /* The salt used for this encryption */
|
||||
__le64 persist_data_offset[2]; /* Absolute offset to both copies of crypt_persist_data
|
||||
* on device with that info, either the footer of the
|
||||
* real_blkdevice or the metadata partition. */
|
||||
|
||||
__le32 persist_data_size; /* The number of bytes allocated to each copy of the
|
||||
* persistent data table*/
|
||||
};
|
||||
|
||||
/* 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 {
|
||||
|
@ -83,6 +124,8 @@ extern "C" {
|
|||
char *crypto_dev_path, unsigned int max_pathlen,
|
||||
int *new_major, int *new_minor);
|
||||
int cryptfs_revert_volume(const char *label);
|
||||
int cryptfs_getfield(char *fieldname, char *value, int len);
|
||||
int cryptfs_setfield(char *fieldname, char *value);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue