keystore: Add multi-user support

Split the directories out per-user. Each Android user ID gets its own
directory and master key. This gives each user its own locked/unlocked
state.

Add migration code that converts existing keystores to this scheme. This
even migrates keys that used the non-public API, but only for the
primary user. The secondary users may have a different lock screen
pattern that would no longer work to unlock the master key.

Bug: 7249554
Change-Id: Ie135235ab1eb88ddb2d89a6cb4ffd8fb6736c573
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 760ec4d..482e21b 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -24,6 +24,7 @@
 #include <signal.h>
 #include <errno.h>
 #include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
 #include <assert.h>
@@ -41,9 +42,9 @@
 
 #include <hardware/keymaster.h>
 
+#include <utils/String8.h>
 #include <utils/UniquePtr.h>
-
-#include <cutils/list.h>
+#include <utils/Vector.h>
 
 #include <keystore/IKeystoreService.h>
 #include <binder/IPCThreadState.h>
@@ -162,7 +163,29 @@
 static const perm_t DEFAULT_PERMS = static_cast<perm_t>(P_TEST | P_GET | P_INSERT | P_DELETE | P_EXIST | P_SAW | P_SIGN
         | P_VERIFY);
 
+/**
+ * Returns the app ID (in the Android multi-user sense) for the current
+ * UNIX UID.
+ */
+static uid_t get_app_id(uid_t uid) {
+    return uid % AID_USER;
+}
+
+/**
+ * Returns the user ID (in the Android multi-user sense) for the current
+ * UNIX UID.
+ */
+static uid_t get_user_id(uid_t uid) {
+    return uid / AID_USER;
+}
+
+
 static bool has_permission(uid_t uid, perm_t perm) {
+    // All system users are equivalent for multi-user support.
+    if (get_app_id(uid) == AID_SYSTEM) {
+        uid = AID_SYSTEM;
+    }
+
     for (size_t i = 0; i < sizeof(user_perms)/sizeof(user_perms[0]); i++) {
         struct user_perm user = user_perms[i];
         if (user.uid == uid) {
@@ -211,16 +234,27 @@
  * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
  * that Base64 cannot be used here due to the need of prefix match on keys. */
 
+static size_t encode_key_length(const android::String8& keyName) {
+    const uint8_t* in = reinterpret_cast<const uint8_t*>(keyName.string());
+    size_t length = keyName.length();
+    for (int i = length; i > 0; --i, ++in) {
+        if (*in < '0' || *in > '~') {
+            ++length;
+        }
+    }
+    return length;
+}
+
 static int encode_key(char* out, const android::String8& keyName) {
     const uint8_t* in = reinterpret_cast<const uint8_t*>(keyName.string());
     size_t length = keyName.length();
     for (int i = length; i > 0; --i, ++in, ++out) {
-        if (*in >= '0' && *in <= '~') {
-            *out = *in;
-        } else {
+        if (*in < '0' || *in > '~') {
             *out = '+' + (*in >> 6);
             *++out = '0' + (*in & 0x3F);
             ++length;
+        } else {
+            *out = *in;
         }
     }
     *out = '\0';
@@ -521,27 +555,50 @@
     struct blob mBlob;
 };
 
-typedef struct {
-    uint32_t uid;
-    const uint8_t* filename;
-
-    struct listnode plist;
-} grant_t;
-
-class KeyStore {
+class UserState {
 public:
-    KeyStore(Entropy* entropy, keymaster_device_t* device)
-        : mEntropy(entropy)
-        , mDevice(device)
-        , mRetry(MAX_RETRY)
-    {
-        if (access(MASTER_KEY_FILE, R_OK) == 0) {
+    UserState(uid_t userId) : mUserId(userId), mRetry(MAX_RETRY) {
+        asprintf(&mUserDir, "user_%u", mUserId);
+        asprintf(&mMasterKeyFile, "%s/.masterkey", mUserDir);
+    }
+
+    ~UserState() {
+        free(mUserDir);
+        free(mMasterKeyFile);
+    }
+
+    bool initialize() {
+        if ((mkdir(mUserDir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) && (errno != EEXIST)) {
+            ALOGE("Could not create directory '%s'", mUserDir);
+            return false;
+        }
+
+        if (access(mMasterKeyFile, R_OK) == 0) {
             setState(STATE_LOCKED);
         } else {
             setState(STATE_UNINITIALIZED);
         }
 
-        list_init(&mGrants);
+        return true;
+    }
+
+    uid_t getUserId() const {
+        return mUserId;
+    }
+
+    const char* getUserDirName() const {
+        return mUserDir;
+    }
+
+    const char* getMasterKeyFileName() const {
+        return mMasterKeyFile;
+    }
+
+    void setState(State state) {
+        mState = state;
+        if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
+            mRetry = MAX_RETRY;
+        }
     }
 
     State getState() const {
@@ -552,15 +609,18 @@
         return mRetry;
     }
 
-    keymaster_device_t* getDevice() const {
-        return mDevice;
+    void zeroizeMasterKeysInMemory() {
+        memset(mMasterKey, 0, sizeof(mMasterKey));
+        memset(mSalt, 0, sizeof(mSalt));
+        memset(&mMasterKeyEncryption, 0, sizeof(mMasterKeyEncryption));
+        memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption));
     }
 
-    ResponseCode initialize(const android::String8& pw) {
-        if (!generateMasterKey()) {
+    ResponseCode initialize(const android::String8& pw, Entropy* entropy) {
+        if (!generateMasterKey(entropy)) {
             return SYSTEM_ERROR;
         }
-        ResponseCode response = writeMasterKey(pw);
+        ResponseCode response = writeMasterKey(pw, entropy);
         if (response != NO_ERROR) {
             return response;
         }
@@ -568,17 +628,17 @@
         return ::NO_ERROR;
     }
 
-    ResponseCode writeMasterKey(const android::String8& pw) {
+    ResponseCode writeMasterKey(const android::String8& pw, Entropy* entropy) {
         uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
         generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
         AES_KEY passwordAesKey;
         AES_set_encrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
         Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
-        return masterKeyBlob.encryptBlob(MASTER_KEY_FILE, &passwordAesKey, mEntropy);
+        return masterKeyBlob.encryptBlob(mMasterKeyFile, &passwordAesKey, entropy);
     }
 
-    ResponseCode readMasterKey(const android::String8& pw) {
-        int in = TEMP_FAILURE_RETRY(open(MASTER_KEY_FILE, O_RDONLY));
+    ResponseCode readMasterKey(const android::String8& pw, Entropy* entropy) {
+        int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY));
         if (in < 0) {
             return SYSTEM_ERROR;
         }
@@ -602,17 +662,17 @@
         AES_KEY passwordAesKey;
         AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
         Blob masterKeyBlob(rawBlob);
-        ResponseCode response = masterKeyBlob.decryptBlob(MASTER_KEY_FILE, &passwordAesKey);
+        ResponseCode response = masterKeyBlob.decryptBlob(mMasterKeyFile, &passwordAesKey);
         if (response == SYSTEM_ERROR) {
             return SYSTEM_ERROR;
         }
         if (response == NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
             // if salt was missing, generate one and write a new master key file with the salt.
             if (salt == NULL) {
-                if (!generateSalt()) {
+                if (!generateSalt(entropy)) {
                     return SYSTEM_ERROR;
                 }
-                response = writeMasterKey(pw);
+                response = writeMasterKey(pw, entropy);
             }
             if (response == NO_ERROR) {
                 memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
@@ -634,32 +694,225 @@
         }
     }
 
+    AES_KEY* getEncryptionKey() {
+        return &mMasterKeyEncryption;
+    }
+
+    AES_KEY* getDecryptionKey() {
+        return &mMasterKeyDecryption;
+    }
+
     bool reset() {
-        clearMasterKeys();
-        setState(STATE_UNINITIALIZED);
-
-        DIR* dir = opendir(".");
-        struct dirent* file;
-
+        DIR* dir = opendir(getUserDirName());
         if (!dir) {
+            ALOGW("couldn't open user directory: %s", strerror(errno));
             return false;
         }
+
+        struct dirent* file;
         while ((file = readdir(dir)) != NULL) {
-            unlink(file->d_name);
+            // We only care about files.
+            if (file->d_type != DT_REG) {
+                continue;
+            }
+
+            // Skip anything that starts with a "."
+            if (file->d_name[0] == '.') {
+                continue;
+            }
+
+            // Find the current file's UID.
+            char* end;
+            unsigned long thisUid = strtoul(file->d_name, &end, 10);
+            if (end[0] != '_' || end[1] == 0) {
+                continue;
+            }
+
+            // Skip if this is not our user.
+            if (get_user_id(thisUid) != mUserId) {
+                continue;
+            }
+
+            unlinkat(dirfd(dir), file->d_name, 0);
         }
         closedir(dir);
         return true;
     }
 
-    bool isEmpty() const {
-        DIR* dir = opendir(".");
+private:
+    static const int MASTER_KEY_SIZE_BYTES = 16;
+    static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
+
+    static const int MAX_RETRY = 4;
+    static const size_t SALT_SIZE = 16;
+
+    void generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw,
+            uint8_t* salt) {
+        size_t saltSize;
+        if (salt != NULL) {
+            saltSize = SALT_SIZE;
+        } else {
+            // pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
+            salt = (uint8_t*) "keystore";
+            // sizeof = 9, not strlen = 8
+            saltSize = sizeof("keystore");
+        }
+
+        PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt,
+                saltSize, 8192, keySize, key);
+    }
+
+    bool generateSalt(Entropy* entropy) {
+        return entropy->generate_random_data(mSalt, sizeof(mSalt));
+    }
+
+    bool generateMasterKey(Entropy* entropy) {
+        if (!entropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) {
+            return false;
+        }
+        if (!generateSalt(entropy)) {
+            return false;
+        }
+        return true;
+    }
+
+    void setupMasterKeys() {
+        AES_set_encrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyEncryption);
+        AES_set_decrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyDecryption);
+        setState(STATE_NO_ERROR);
+    }
+
+    uid_t mUserId;
+
+    char* mUserDir;
+    char* mMasterKeyFile;
+
+    State mState;
+    int8_t mRetry;
+
+    uint8_t mMasterKey[MASTER_KEY_SIZE_BYTES];
+    uint8_t mSalt[SALT_SIZE];
+
+    AES_KEY mMasterKeyEncryption;
+    AES_KEY mMasterKeyDecryption;
+};
+
+typedef struct {
+    uint32_t uid;
+    const uint8_t* filename;
+} grant_t;
+
+class KeyStore {
+public:
+    KeyStore(Entropy* entropy, keymaster_device_t* device)
+        : mEntropy(entropy)
+        , mDevice(device)
+    {
+        memset(&mMetaData, '\0', sizeof(mMetaData));
+    }
+
+    ~KeyStore() {
+        for (android::Vector<grant_t*>::iterator it(mGrants.begin());
+                it != mGrants.end(); it++) {
+            delete *it;
+            mGrants.erase(it);
+        }
+
+        for (android::Vector<UserState*>::iterator it(mMasterKeys.begin());
+                it != mMasterKeys.end(); it++) {
+            delete *it;
+            mMasterKeys.erase(it);
+        }
+    }
+
+    keymaster_device_t* getDevice() const {
+        return mDevice;
+    }
+
+    ResponseCode initialize() {
+        readMetaData();
+        if (upgradeKeystore()) {
+            writeMetaData();
+        }
+
+        return ::NO_ERROR;
+    }
+
+    State getState(uid_t uid) {
+        return getUserState(uid)->getState();
+    }
+
+    ResponseCode initializeUser(const android::String8& pw, uid_t uid) {
+        UserState* userState = getUserState(uid);
+        return userState->initialize(pw, mEntropy);
+    }
+
+    ResponseCode writeMasterKey(const android::String8& pw, uid_t uid) {
+        uid_t user_id = get_user_id(uid);
+        UserState* userState = getUserState(user_id);
+        return userState->writeMasterKey(pw, mEntropy);
+    }
+
+    ResponseCode readMasterKey(const android::String8& pw, uid_t uid) {
+        uid_t user_id = get_user_id(uid);
+        UserState* userState = getUserState(user_id);
+        return userState->readMasterKey(pw, mEntropy);
+    }
+
+    android::String8 getKeyName(const android::String8& keyName) {
+        char encoded[encode_key_length(keyName)];
+        encode_key(encoded, keyName);
+        return android::String8(encoded);
+    }
+
+    android::String8 getKeyNameForUid(const android::String8& keyName, uid_t uid) {
+        char encoded[encode_key_length(keyName)];
+        encode_key(encoded, keyName);
+        return android::String8::format("%u_%s", uid, encoded);
+    }
+
+    android::String8 getKeyNameForUidWithDir(const android::String8& keyName, uid_t uid) {
+        char encoded[encode_key_length(keyName)];
+        encode_key(encoded, keyName);
+        return android::String8::format("%s/%u_%s", getUserState(uid)->getUserDirName(), uid,
+                encoded);
+    }
+
+    bool reset(uid_t uid) {
+        UserState* userState = getUserState(uid);
+        userState->zeroizeMasterKeysInMemory();
+        userState->setState(STATE_UNINITIALIZED);
+        return userState->reset();
+    }
+
+    bool isEmpty(uid_t uid) const {
+        const UserState* userState = getUserState(uid);
+        if (userState == NULL) {
+            return true;
+        }
+
+        DIR* dir = opendir(userState->getUserDirName());
         struct dirent* file;
         if (!dir) {
             return true;
         }
         bool result = true;
+
+        char filename[NAME_MAX];
+        int n = snprintf(filename, sizeof(filename), "%u_", uid);
+
         while ((file = readdir(dir)) != NULL) {
-            if (isKeyFile(file->d_name)) {
+            // We only care about files.
+            if (file->d_type != DT_REG) {
+                continue;
+            }
+
+            // Skip anything that starts with a "."
+            if (file->d_name[0] == '.') {
+                continue;
+            }
+
+            if (!strncmp(file->d_name, filename, n)) {
                 result = false;
                 break;
             }
@@ -668,13 +921,15 @@
         return result;
     }
 
-    void lock() {
-        clearMasterKeys();
-        setState(STATE_LOCKED);
+    void lock(uid_t uid) {
+        UserState* userState = getUserState(uid);
+        userState->zeroizeMasterKeysInMemory();
+        userState->setState(STATE_LOCKED);
     }
 
-    ResponseCode get(const char* filename, Blob* keyBlob, const BlobType type) {
-        ResponseCode rc = keyBlob->decryptBlob(filename, &mMasterKeyDecryption);
+    ResponseCode get(const char* filename, Blob* keyBlob, const BlobType type, uid_t uid) {
+        UserState* userState = getUserState(uid);
+        ResponseCode rc = keyBlob->decryptBlob(filename, userState->getDecryptionKey());
         if (rc != NO_ERROR) {
             return rc;
         }
@@ -685,9 +940,10 @@
              * it must be read it again since the blob is encrypted each time
              * it's written.
              */
-            if (upgrade(filename, keyBlob, version, type)) {
-                if ((rc = this->put(filename, keyBlob)) != NO_ERROR
-                        || (rc = keyBlob->decryptBlob(filename, &mMasterKeyDecryption)) != NO_ERROR) {
+            if (upgradeBlob(filename, keyBlob, version, type, uid)) {
+                if ((rc = this->put(filename, keyBlob, uid)) != NO_ERROR
+                        || (rc = keyBlob->decryptBlob(filename, userState->getDecryptionKey()))
+                                != NO_ERROR) {
                     return rc;
                 }
             }
@@ -701,28 +957,31 @@
         return rc;
     }
 
-    ResponseCode put(const char* filename, Blob* keyBlob) {
-        return keyBlob->encryptBlob(filename, &mMasterKeyEncryption, mEntropy);
+    ResponseCode put(const char* filename, Blob* keyBlob, uid_t uid) {
+        UserState* userState = getUserState(uid);
+        return keyBlob->encryptBlob(filename, userState->getEncryptionKey(), mEntropy);
     }
 
     void addGrant(const char* filename, uid_t granteeUid) {
-        grant_t *grant = getGrant(filename, granteeUid);
-        if (grant == NULL) {
-            grant = new grant_t;
+        const grant_t* existing = getGrant(filename, granteeUid);
+        if (existing == NULL) {
+            grant_t* grant = new grant_t;
             grant->uid = granteeUid;
             grant->filename = reinterpret_cast<const uint8_t*>(strdup(filename));
-            list_add_tail(&mGrants, &grant->plist);
+            mGrants.add(grant);
         }
     }
 
     bool removeGrant(const char* filename, uid_t granteeUid) {
-        grant_t *grant = getGrant(filename, granteeUid);
-        if (grant != NULL) {
-            list_remove(&grant->plist);
-            delete grant;
-            return true;
+        for (android::Vector<grant_t*>::iterator it(mGrants.begin());
+                it != mGrants.end(); it++) {
+            grant_t* grant = *it;
+            if (grant->uid == granteeUid
+                    && !strcmp(reinterpret_cast<const char*>(grant->filename), filename)) {
+                mGrants.erase(it);
+                return true;
+            }
         }
-
         return false;
     }
 
@@ -730,7 +989,7 @@
         return getGrant(filename, uid) != NULL;
     }
 
-    ResponseCode importKey(const uint8_t* key, size_t keyLen, const char* filename) {
+    ResponseCode importKey(const uint8_t* key, size_t keyLen, const char* filename, uid_t uid) {
         uint8_t* data;
         size_t dataLength;
         int rc;
@@ -749,105 +1008,128 @@
         Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
         free(data);
 
-        return put(filename, &keyBlob);
+        return put(filename, &keyBlob, uid);
     }
 
     bool isHardwareBacked() const {
         return (mDevice->flags & KEYMASTER_SOFTWARE_ONLY) == 0;
     }
 
+    ResponseCode getKeyForName(Blob* keyBlob, const android::String8& keyName, const uid_t uid,
+            const BlobType type) {
+        char filename[NAME_MAX];
+        encode_key_for_uid(filename, uid, keyName);
+
+        UserState* userState = getUserState(uid);
+        android::String8 filepath8;
+
+        filepath8 = android::String8::format("%s/%s", userState->getUserDirName(), filename);
+        if (filepath8.string() == NULL) {
+            ALOGW("can't create filepath for key %s", filename);
+            return SYSTEM_ERROR;
+        }
+
+        ResponseCode responseCode = get(filepath8.string(), keyBlob, type, uid);
+        if (responseCode == NO_ERROR) {
+            return responseCode;
+        }
+
+        // If this is one of the legacy UID->UID mappings, use it.
+        uid_t euid = get_keystore_euid(uid);
+        if (euid != uid) {
+            encode_key_for_uid(filename, euid, keyName);
+            filepath8 = android::String8::format("%s/%s", userState->getUserDirName(), filename);
+            responseCode = get(filepath8.string(), keyBlob, type, uid);
+            if (responseCode == NO_ERROR) {
+                return responseCode;
+            }
+        }
+
+        // They might be using a granted key.
+        encode_key(filename, keyName);
+        char* end;
+        strtoul(filename, &end, 10);
+        if (end[0] != '_' || end[1] == 0) {
+            return KEY_NOT_FOUND;
+        }
+        filepath8 = android::String8::format("%s/%s", userState->getUserDirName(), filename);
+        if (!hasGrant(filepath8.string(), uid)) {
+            return responseCode;
+        }
+
+        // It is a granted key. Try to load it.
+        return get(filepath8.string(), keyBlob, type, uid);
+    }
+
+    /**
+     * Returns any existing UserState or creates it if it doesn't exist.
+     */
+    UserState* getUserState(uid_t uid) {
+        uid_t userId = get_user_id(uid);
+
+        for (android::Vector<UserState*>::iterator it(mMasterKeys.begin());
+                it != mMasterKeys.end(); it++) {
+            UserState* state = *it;
+            if (state->getUserId() == userId) {
+                return state;
+            }
+        }
+
+        UserState* userState = new UserState(userId);
+        if (!userState->initialize()) {
+            /* There's not much we can do if initialization fails. Trying to
+             * unlock the keystore for that user will fail as well, so any
+             * subsequent request for this user will just return SYSTEM_ERROR.
+             */
+            ALOGE("User initialization failed for %u; subsuquent operations will fail", userId);
+        }
+        mMasterKeys.add(userState);
+        return userState;
+    }
+
+    /**
+     * Returns NULL if the UserState doesn't already exist.
+     */
+    const UserState* getUserState(uid_t uid) const {
+        uid_t userId = get_user_id(uid);
+
+        for (android::Vector<UserState*>::const_iterator it(mMasterKeys.begin());
+                it != mMasterKeys.end(); it++) {
+            UserState* state = *it;
+            if (state->getUserId() == userId) {
+                return state;
+            }
+        }
+
+        return NULL;
+    }
+
 private:
-    static const char* MASTER_KEY_FILE;
-    static const int MASTER_KEY_SIZE_BYTES = 16;
-    static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
-
-    static const int MAX_RETRY = 4;
-    static const size_t SALT_SIZE = 16;
-
+    static const char* sOldMasterKey;
+    static const char* sMetaDataFile;
     Entropy* mEntropy;
 
     keymaster_device_t* mDevice;
 
-    State mState;
-    int8_t mRetry;
+    android::Vector<UserState*> mMasterKeys;
 
-    uint8_t mMasterKey[MASTER_KEY_SIZE_BYTES];
-    uint8_t mSalt[SALT_SIZE];
+    android::Vector<grant_t*> mGrants;
 
-    AES_KEY mMasterKeyEncryption;
-    AES_KEY mMasterKeyDecryption;
+    typedef struct {
+        uint32_t version;
+    } keystore_metadata_t;
 
-    struct listnode mGrants;
+    keystore_metadata_t mMetaData;
 
-    void setState(State state) {
-        mState = state;
-        if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
-            mRetry = MAX_RETRY;
-        }
-    }
-
-    bool generateSalt() {
-        return mEntropy->generate_random_data(mSalt, sizeof(mSalt));
-    }
-
-    bool generateMasterKey() {
-        if (!mEntropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) {
-            return false;
-        }
-        if (!generateSalt()) {
-            return false;
-        }
-        return true;
-    }
-
-    void setupMasterKeys() {
-        AES_set_encrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyEncryption);
-        AES_set_decrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyDecryption);
-        setState(STATE_NO_ERROR);
-    }
-
-    void clearMasterKeys() {
-        memset(mMasterKey, 0, sizeof(mMasterKey));
-        memset(mSalt, 0, sizeof(mSalt));
-        memset(&mMasterKeyEncryption, 0, sizeof(mMasterKeyEncryption));
-        memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption));
-    }
-
-    static void generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw,
-            uint8_t* salt) {
-        size_t saltSize;
-        if (salt != NULL) {
-            saltSize = SALT_SIZE;
-        } else {
-            // pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
-            salt = (uint8_t*) "keystore";
-            // sizeof = 9, not strlen = 8
-            saltSize = sizeof("keystore");
-        }
-
-        PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt,
-                saltSize, 8192, keySize, key);
-    }
-
-    static bool isKeyFile(const char* filename) {
-        return ((strcmp(filename, MASTER_KEY_FILE) != 0)
-                && (strcmp(filename, ".") != 0)
-                && (strcmp(filename, "..") != 0));
-    }
-
-    grant_t* getGrant(const char* filename, uid_t uid) const {
-        struct listnode *node;
-        grant_t *grant;
-
-        list_for_each(node, &mGrants) {
-            grant = node_to_item(node, grant_t, plist);
+    const grant_t* getGrant(const char* filename, uid_t uid) const {
+        for (android::Vector<grant_t*>::const_iterator it(mGrants.begin());
+                it != mGrants.end(); it++) {
+            grant_t* grant = *it;
             if (grant->uid == uid
-                    && !strcmp(reinterpret_cast<const char*>(grant->filename),
-                               filename)) {
+                    && !strcmp(reinterpret_cast<const char*>(grant->filename), filename)) {
                 return grant;
             }
         }
-
         return NULL;
     }
 
@@ -855,7 +1137,8 @@
      * Upgrade code. This will upgrade the key from the current version
      * to whatever is newest.
      */
-    bool upgrade(const char* filename, Blob* blob, const uint8_t oldVersion, const BlobType type) {
+    bool upgradeBlob(const char* filename, Blob* blob, const uint8_t oldVersion,
+            const BlobType type, uid_t uid) {
         bool updated = false;
         uint8_t version = oldVersion;
 
@@ -865,7 +1148,7 @@
 
             blob->setType(type);
             if (type == TYPE_KEY_PAIR) {
-                importBlobAsKey(blob, filename);
+                importBlobAsKey(blob, filename, uid);
             }
             version = 1;
             updated = true;
@@ -889,7 +1172,7 @@
      * Then it overwrites the original blob with the new blob
      * format that is returned from the keymaster.
      */
-    ResponseCode importBlobAsKey(Blob* blob, const char* filename) {
+    ResponseCode importBlobAsKey(Blob* blob, const char* filename, uid_t uid) {
         // We won't even write to the blob directly with this BIO, so const_cast is okay.
         Unique_BIO b(BIO_new_mem_buf(const_cast<uint8_t*>(blob->getValue()), blob->getLength()));
         if (b.get() == NULL) {
@@ -917,46 +1200,118 @@
             return SYSTEM_ERROR;
         }
 
-        ResponseCode rc = importKey(pkcs8key.get(), len, filename);
+        ResponseCode rc = importKey(pkcs8key.get(), len, filename, uid);
         if (rc != NO_ERROR) {
             return rc;
         }
 
-        return get(filename, blob, TYPE_KEY_PAIR);
+        return get(filename, blob, TYPE_KEY_PAIR, uid);
+    }
+
+    void readMetaData() {
+        int in = TEMP_FAILURE_RETRY(open(sMetaDataFile, O_RDONLY));
+        if (in < 0) {
+            return;
+        }
+        size_t fileLength = readFully(in, (uint8_t*) &mMetaData, sizeof(mMetaData));
+        if (fileLength != sizeof(mMetaData)) {
+            ALOGI("Metadata file is %zd bytes (%zd experted); upgrade?", fileLength,
+                    sizeof(mMetaData));
+        }
+        close(in);
+    }
+
+    void writeMetaData() {
+        const char* tmpFileName = ".metadata.tmp";
+        int out = TEMP_FAILURE_RETRY(open(tmpFileName,
+                O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
+        if (out < 0) {
+            ALOGE("couldn't write metadata file: %s", strerror(errno));
+            return;
+        }
+        size_t fileLength = writeFully(out, (uint8_t*) &mMetaData, sizeof(mMetaData));
+        if (fileLength != sizeof(mMetaData)) {
+            ALOGI("Could only write %zd bytes to metadata file (%zd expected)", fileLength,
+                    sizeof(mMetaData));
+        }
+        close(out);
+        rename(tmpFileName, sMetaDataFile);
+    }
+
+    bool upgradeKeystore() {
+        bool upgraded = false;
+
+        if (mMetaData.version == 0) {
+            UserState* userState = getUserState(0);
+
+            // Initialize first so the directory is made.
+            userState->initialize();
+
+            // Migrate the old .masterkey file to user 0.
+            if (access(sOldMasterKey, R_OK) == 0) {
+                if (rename(sOldMasterKey, userState->getMasterKeyFileName()) < 0) {
+                    ALOGE("couldn't migrate old masterkey: %s", strerror(errno));
+                    return false;
+                }
+            }
+
+            // Initialize again in case we had a key.
+            userState->initialize();
+
+            // Try to migrate existing keys.
+            DIR* dir = opendir(".");
+            if (!dir) {
+                // Give up now; maybe we can upgrade later.
+                ALOGE("couldn't open keystore's directory; something is wrong");
+                return false;
+            }
+
+            struct dirent* file;
+            while ((file = readdir(dir)) != NULL) {
+                // We only care about files.
+                if (file->d_type != DT_REG) {
+                    continue;
+                }
+
+                // Skip anything that starts with a "."
+                if (file->d_name[0] == '.') {
+                    continue;
+                }
+
+                // Find the current file's user.
+                char* end;
+                unsigned long thisUid = strtoul(file->d_name, &end, 10);
+                if (end[0] != '_' || end[1] == 0) {
+                    continue;
+                }
+                UserState* otherUser = getUserState(thisUid);
+                if (otherUser->getUserId() != 0) {
+                    unlinkat(dirfd(dir), file->d_name, 0);
+                }
+
+                // Rename the file into user directory.
+                DIR* otherdir = opendir(otherUser->getUserDirName());
+                if (otherdir == NULL) {
+                    ALOGW("couldn't open user directory for rename");
+                    continue;
+                }
+                if (renameat(dirfd(dir), file->d_name, dirfd(otherdir), file->d_name) < 0) {
+                    ALOGW("couldn't rename blob: %s: %s", file->d_name, strerror(errno));
+                }
+                closedir(otherdir);
+            }
+            closedir(dir);
+
+            mMetaData.version = 1;
+            upgraded = true;
+        }
+
+        return upgraded;
     }
 };
 
-const char* KeyStore::MASTER_KEY_FILE = ".masterkey";
-
-static ResponseCode get_key_for_name(KeyStore* keyStore, Blob* keyBlob,
-        const android::String8& keyName, const uid_t uid, const BlobType type) {
-    char filename[NAME_MAX];
-
-    encode_key_for_uid(filename, uid, keyName);
-    ResponseCode responseCode = keyStore->get(filename, keyBlob, type);
-    if (responseCode == NO_ERROR) {
-        return responseCode;
-    }
-
-    // If this is one of the legacy UID->UID mappings, use it.
-    uid_t euid = get_keystore_euid(uid);
-    if (euid != uid) {
-        encode_key_for_uid(filename, euid, keyName);
-        responseCode = keyStore->get(filename, keyBlob, type);
-        if (responseCode == NO_ERROR) {
-            return responseCode;
-        }
-    }
-
-    // They might be using a granted key.
-    encode_key(filename, keyName);
-    if (!keyStore->hasGrant(filename, uid)) {
-        return responseCode;
-    }
-
-    // It is a granted key. Try to load it.
-    return keyStore->get(filename, keyBlob, type);
-}
+const char* KeyStore::sOldMasterKey = ".masterkey";
+const char* KeyStore::sMetaDataFile = ".metadata";
 
 namespace android {
 class KeyStoreProxy : public BnKeystoreService, public IBinder::DeathRecipient {
@@ -977,7 +1332,7 @@
             return ::PERMISSION_DENIED;
         }
 
-        return mKeyStore->getState();
+        return mKeyStore->getState(callingUid);
     }
 
     int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {
@@ -987,20 +1342,19 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling get in state: %d", state);
             return state;
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
         Blob keyBlob;
 
-        ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, callingUid,
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
                 TYPE_GENERIC);
         if (responseCode != ::NO_ERROR) {
-            ALOGW("Could not read %s", filename);
+            ALOGW("Could not read %s", name8.string());
             *item = NULL;
             *itemLength = 0;
             return responseCode;
@@ -1026,19 +1380,17 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling insert in state: %d", state);
             return state;
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
-
-        encode_key_for_uid(filename, targetUid, name8);
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
 
         Blob keyBlob(item, itemLength, NULL, 0, ::TYPE_GENERIC);
-        return mKeyStore->put(filename, &keyBlob);
+        return mKeyStore->put(filename.string(), &keyBlob, callingUid);
     }
 
     int32_t del(const String16& name, int targetUid) {
@@ -1055,12 +1407,11 @@
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
-
-        encode_key_for_uid(filename, targetUid, name8);
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
 
         Blob keyBlob;
-        ResponseCode responseCode = mKeyStore->get(filename, &keyBlob, TYPE_GENERIC);
+        ResponseCode responseCode = mKeyStore->get(filename.string(), &keyBlob, TYPE_GENERIC,
+                callingUid);
         if (responseCode != ::NO_ERROR) {
             return responseCode;
         }
@@ -1081,11 +1432,9 @@
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
 
-        encode_key_for_uid(filename, targetUid, name8);
-
-        if (access(filename, R_OK) == -1) {
+        if (access(filename.string(), R_OK) == -1) {
             return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
         }
         return ::NO_ERROR;
@@ -1104,19 +1453,30 @@
             return ::PERMISSION_DENIED;
         }
 
-        DIR* dir = opendir(".");
+        UserState* userState = mKeyStore->getUserState(targetUid);
+        DIR* dir = opendir(userState->getUserDirName());
         if (!dir) {
+            ALOGW("can't open directory for user: %s", strerror(errno));
             return ::SYSTEM_ERROR;
         }
 
         const String8 prefix8(prefix);
-        char filename[NAME_MAX];
-
-        int n = encode_key_for_uid(filename, targetUid, prefix8);
+        String8 filename(mKeyStore->getKeyNameForUid(prefix8, targetUid));
+        size_t n = filename.length();
 
         struct dirent* file;
         while ((file = readdir(dir)) != NULL) {
-            if (!strncmp(filename, file->d_name, n)) {
+            // We only care about files.
+            if (file->d_type != DT_REG) {
+                continue;
+            }
+
+            // Skip anything that starts with a "."
+            if (file->d_name[0] == '.') {
+                continue;
+            }
+
+            if (!strncmp(filename.string(), file->d_name, n)) {
                 const char* p = &file->d_name[n];
                 size_t plen = strlen(p);
 
@@ -1143,7 +1503,7 @@
             return ::PERMISSION_DENIED;
         }
 
-        ResponseCode rc = mKeyStore->reset() ? ::NO_ERROR : ::SYSTEM_ERROR;
+        ResponseCode rc = mKeyStore->reset(callingUid) ? ::NO_ERROR : ::SYSTEM_ERROR;
 
         const keymaster_device_t* device = mKeyStore->getDevice();
         if (device == NULL) {
@@ -1180,18 +1540,18 @@
 
         const String8 password8(password);
 
-        switch (mKeyStore->getState()) {
+        switch (mKeyStore->getState(callingUid)) {
             case ::STATE_UNINITIALIZED: {
                 // generate master key, encrypt with password, write to file, initialize mMasterKey*.
-                return mKeyStore->initialize(password8);
+                return mKeyStore->initializeUser(password8, callingUid);
             }
             case ::STATE_NO_ERROR: {
                 // rewrite master key with new password.
-                return mKeyStore->writeMasterKey(password8);
+                return mKeyStore->writeMasterKey(password8, callingUid);
             }
             case ::STATE_LOCKED: {
                 // read master key, decrypt with password, initialize mMasterKey*.
-                return mKeyStore->readMasterKey(password8);
+                return mKeyStore->readMasterKey(password8, callingUid);
             }
         }
         return ::SYSTEM_ERROR;
@@ -1204,13 +1564,13 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (state != ::STATE_NO_ERROR) {
             ALOGD("calling lock in state: %d", state);
             return state;
         }
 
-        mKeyStore->lock();
+        mKeyStore->lock(callingUid);
         return ::NO_ERROR;
     }
 
@@ -1221,7 +1581,7 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (state != ::STATE_LOCKED) {
             ALOGD("calling unlock when not locked");
             return state;
@@ -1238,7 +1598,7 @@
             return -1;
         }
 
-        return mKeyStore->isEmpty() ? ::KEY_NOT_FOUND : ::NO_ERROR;
+        return mKeyStore->isEmpty(callingUid) ? ::KEY_NOT_FOUND : ::NO_ERROR;
     }
 
     int32_t generate(const String16& name, int targetUid) {
@@ -1254,15 +1614,12 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling generate in state: %d", state);
             return state;
         }
 
-        String8 name8(name);
-        char filename[NAME_MAX];
-
         uint8_t* data;
         size_t dataLength;
         int rc;
@@ -1285,12 +1642,13 @@
             return ::SYSTEM_ERROR;
         }
 
-        encode_key_for_uid(filename, targetUid, name8);
+        String8 name8(name);
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
 
         Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
         free(data);
 
-        return mKeyStore->put(filename, &keyBlob);
+        return mKeyStore->put(filename.string(), &keyBlob, callingUid);
     }
 
     int32_t import(const String16& name, const uint8_t* data, size_t length, int targetUid) {
@@ -1306,18 +1664,16 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling import in state: %d", state);
             return state;
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
 
-        encode_key_for_uid(filename, targetUid, name8);
-
-        return mKeyStore->importKey(data, length, filename);
+        return mKeyStore->importKey(data, length, filename.string(), callingUid);
     }
 
     int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
@@ -1328,7 +1684,7 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling sign in state: %d", state);
             return state;
@@ -1340,7 +1696,7 @@
         ALOGV("sign %s from uid %d", name8.string(), callingUid);
         int rc;
 
-        ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, callingUid,
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
                 ::TYPE_KEY_PAIR);
         if (responseCode != ::NO_ERROR) {
             return responseCode;
@@ -1379,7 +1735,7 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling verify in state: %d", state);
             return state;
@@ -1389,7 +1745,7 @@
         String8 name8(name);
         int rc;
 
-        ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, callingUid,
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
                 TYPE_KEY_PAIR);
         if (responseCode != ::NO_ERROR) {
             return responseCode;
@@ -1435,7 +1791,7 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling get_pubkey in state: %d", state);
             return state;
@@ -1446,7 +1802,7 @@
 
         ALOGV("get_pubkey '%s' from uid %d", name8.string(), callingUid);
 
-        ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, callingUid,
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
                 TYPE_KEY_PAIR);
         if (responseCode != ::NO_ERROR) {
             return responseCode;
@@ -1485,12 +1841,11 @@
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
-
-        encode_key_for_uid(filename, targetUid, name8);
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
 
         Blob keyBlob;
-        ResponseCode responseCode = mKeyStore->get(filename, &keyBlob, ::TYPE_KEY_PAIR);
+        ResponseCode responseCode = mKeyStore->get(filename.string(), &keyBlob, ::TYPE_KEY_PAIR,
+                callingUid);
         if (responseCode != ::NO_ERROR) {
             return responseCode;
         }
@@ -1523,22 +1878,20 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling grant in state: %d", state);
             return state;
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
 
-        encode_key_for_uid(filename, callingUid, name8);
-
-        if (access(filename, R_OK) == -1) {
+        if (access(filename.string(), R_OK) == -1) {
             return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
         }
 
-        mKeyStore->addGrant(filename, granteeUid);
+        mKeyStore->addGrant(filename.string(), granteeUid);
         return ::NO_ERROR;
     }
 
@@ -1549,22 +1902,20 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling ungrant in state: %d", state);
             return state;
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
 
-        encode_key_for_uid(filename, callingUid, name8);
-
-        if (access(filename, R_OK) == -1) {
+        if (access(filename.string(), R_OK) == -1) {
             return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
         }
 
-        return mKeyStore->removeGrant(filename, granteeUid) ? ::NO_ERROR : ::KEY_NOT_FOUND;
+        return mKeyStore->removeGrant(filename.string(), granteeUid) ? ::NO_ERROR : ::KEY_NOT_FOUND;
     }
 
     int64_t getmtime(const String16& name) {
@@ -1575,18 +1926,16 @@
         }
 
         String8 name8(name);
-        char filename[NAME_MAX];
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
 
-        encode_key_for_uid(filename, callingUid, name8);
-
-        if (access(filename, R_OK) == -1) {
-            ALOGW("could not access %s for getmtime", filename);
+        if (access(filename.string(), R_OK) == -1) {
+            ALOGW("could not access %s for getmtime", filename.string());
             return -1L;
         }
 
-        int fd = TEMP_FAILURE_RETRY(open(filename, O_NOFOLLOW, O_RDONLY));
+        int fd = TEMP_FAILURE_RETRY(open(filename.string(), O_NOFOLLOW, O_RDONLY));
         if (fd < 0) {
-            ALOGW("could not open %s for getmtime", filename);
+            ALOGW("could not open %s for getmtime", filename.string());
             return -1L;
         }
 
@@ -1594,7 +1943,7 @@
         int ret = fstat(fd, &s);
         close(fd);
         if (ret == -1) {
-            ALOGW("could not stat %s for getmtime", filename);
+            ALOGW("could not stat %s for getmtime", filename.string());
             return -1L;
         }
 
@@ -1609,7 +1958,7 @@
             return -1L;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling duplicate in state: %d", state);
             return state;
@@ -1640,27 +1989,24 @@
         }
 
         String8 source8(srcKey);
-        char source[NAME_MAX];
-
-        encode_key_for_uid(source, srcUid, source8);
+        String8 sourceFile(mKeyStore->getKeyNameForUidWithDir(source8, srcUid));
 
         String8 target8(destKey);
-        char target[NAME_MAX];
+        String8 targetFile(mKeyStore->getKeyNameForUidWithDir(target8, srcUid));
 
-        encode_key_for_uid(target, destUid, target8);
-
-        if (access(target, W_OK) != -1 || errno != ENOENT) {
-            ALOGD("destination already exists: %s", target);
+        if (access(targetFile.string(), W_OK) != -1 || errno != ENOENT) {
+            ALOGD("destination already exists: %s", targetFile.string());
             return ::SYSTEM_ERROR;
         }
 
         Blob keyBlob;
-        ResponseCode responseCode = mKeyStore->get(source, &keyBlob, TYPE_ANY);
+        ResponseCode responseCode = mKeyStore->get(sourceFile.string(), &keyBlob, TYPE_ANY,
+                callingUid);
         if (responseCode != ::NO_ERROR) {
             return responseCode;
         }
 
-        return mKeyStore->put(target, &keyBlob);
+        return mKeyStore->put(targetFile.string(), &keyBlob, callingUid);
     }
 
     int32_t is_hardware_backed() {
@@ -1674,7 +2020,7 @@
             return ::PERMISSION_DENIED;
         }
 
-        State state = mKeyStore->getState();
+        State state = mKeyStore->getState(callingUid);
         if (!isKeystoreUnlocked(state)) {
             ALOGD("calling clear_uid in state: %d", state);
             return state;
@@ -1682,32 +2028,43 @@
 
         const keymaster_device_t* device = mKeyStore->getDevice();
         if (device == NULL) {
+            ALOGW("can't get keymaster device");
             return ::SYSTEM_ERROR;
         }
 
-        DIR* dir = opendir(".");
+        UserState* userState = mKeyStore->getUserState(callingUid);
+        DIR* dir = opendir(userState->getUserDirName());
         if (!dir) {
+            ALOGW("can't open user directory: %s", strerror(errno));
             return ::SYSTEM_ERROR;
         }
 
-        char filename[NAME_MAX];
-        int n = snprintf(filename, NAME_MAX, "%u_", static_cast<uid_t>(targetUid));
-        char *end = &filename[n];
+        char prefix[NAME_MAX];
+        int n = snprintf(prefix, NAME_MAX, "%u_", static_cast<uid_t>(targetUid));
 
         ResponseCode rc = ::NO_ERROR;
 
         struct dirent* file;
         while ((file = readdir(dir)) != NULL) {
-            if (strncmp(filename, file->d_name, n)) {
+            // We only care about files.
+            if (file->d_type != DT_REG) {
                 continue;
             }
 
-            String8 file8(&file->d_name[n]);
-            encode_key(end, file8);
+            // Skip anything that starts with a "."
+            if (file->d_name[0] == '.') {
+                continue;
+            }
 
+            if (strncmp(prefix, file->d_name, n)) {
+                continue;
+            }
+
+            String8 filename(String8::format("%s/%s", userState->getUserDirName(), file->d_name));
             Blob keyBlob;
-            if (mKeyStore->get(filename, &keyBlob, ::TYPE_ANY) != ::NO_ERROR) {
-                ALOGW("couldn't open %s", filename);
+            if (mKeyStore->get(filename.string(), &keyBlob, ::TYPE_ANY, callingUid)
+                    != ::NO_ERROR) {
+                ALOGW("couldn't open %s", filename.string());
                 continue;
             }
 
@@ -1716,14 +2073,14 @@
                 if (device->delete_keypair != NULL) {
                     if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
                         rc = ::SYSTEM_ERROR;
-                        ALOGW("device couldn't remove %s", filename);
+                        ALOGW("device couldn't remove %s", filename.string());
                     }
                 }
             }
 
-            if (unlink(filename) && errno != ENOENT) {
+            if (unlinkat(dirfd(dir), filename.string(), 0) && errno != ENOENT) {
                 rc = ::SYSTEM_ERROR;
-                ALOGW("couldn't unlink %s", filename);
+                ALOGW("couldn't unlink %s", filename.string());
             }
         }
         closedir(dir);
@@ -1770,6 +2127,7 @@
     }
 
     KeyStore keyStore(&entropy, dev);
+    keyStore.initialize();
     android::sp<android::IServiceManager> sm = android::defaultServiceManager();
     android::sp<android::KeyStoreProxy> proxy = new android::KeyStoreProxy(&keyStore);
     android::status_t ret = sm->addService(android::String16("android.security.keystore"), proxy);