Merge "Switch keystore to binder"
diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk
index 89d3fba..acad442 100644
--- a/keystore-engine/Android.mk
+++ b/keystore-engine/Android.mk
@@ -27,13 +27,14 @@
 LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror
 
 LOCAL_C_INCLUDES += \
-	system/security/keystore \
 	external/openssl/include
 
 LOCAL_SHARED_LIBRARIES += \
 	libcrypto \
 	liblog \
 	libcutils \
-	libkeystore_client
+	libutils \
+	libbinder \
+	libkeystore_binder
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore-engine/eng_keystore.cpp b/keystore-engine/eng_keystore.cpp
index 8a6df77..4790a66 100644
--- a/keystore-engine/eng_keystore.cpp
+++ b/keystore-engine/eng_keystore.cpp
@@ -23,8 +23,6 @@
  *
  */
 
-#include <keystore.h>
-
 #include <utils/UniquePtr.h>
 
 #include <sys/socket.h>
@@ -40,8 +38,11 @@
 #define LOG_TAG "OpenSSL-keystore"
 #include <cutils/log.h>
 
-#include <keystore_client.h>
+#include <binder/IServiceManager.h>
+#include <keystore/keystore.h>
+#include <keystore/IKeystoreService.h>
 
+using namespace android;
 
 #define DYNAMIC_ENGINE
 #define KEYSTORE_ENGINE_ID   "keystore"
@@ -160,21 +161,33 @@
         return 0;
     }
 
-    Keystore_Reply reply;
-    if (keystore_cmd(CommandCodes[SIGN], &reply, 2, strlen(reinterpret_cast<const char*>(key_id)),
-            key_id, static_cast<size_t>(num), reinterpret_cast<const uint8_t*>(padded.get()))
-            != NO_ERROR) {
-        ALOGE("There was an error during rsa_mod_exp");
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+    sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+
+    if (service == NULL) {
+        ALOGE("could not contact keystore");
         return 0;
     }
 
-    const size_t replyLen = reply.length();
-    if (replyLen <= 0) {
+    uint8_t* reply = NULL;
+    size_t replyLen;
+    int32_t ret = service->sign(String16(reinterpret_cast<const char*>(key_id)), padded.get(),
+            num, &reply, &replyLen);
+    if (ret < 0) {
+        ALOGW("There was an error during rsa_mod_exp: could not connect");
+        free(reply);
+        return 0;
+    } else if (ret != 0) {
+        ALOGW("Error during rsa_mod_exp from keystore: %d", ret);
+        free(reply);
+        return 0;
+    } else if (replyLen <= 0) {
         ALOGW("No valid signature returned");
         return 0;
     }
 
-    memcpy(to, reply.get(), replyLen);
+    memcpy(to, reply, replyLen);
 
     ALOGV("rsa=%p keystore_rsa_sign => returning %p len %llu", rsa, to,
             (unsigned long long) replyLen);
@@ -219,14 +232,31 @@
     ALOGV("keystore_loadkey(%p, \"%s\", %p, %p)", e, key_id, ui_method, callback_data);
 #endif
 
-    Keystore_Reply reply;
-    if (keystore_cmd(CommandCodes[GET_PUBKEY], &reply, 1, strlen(key_id), key_id) != NO_ERROR) {
-        ALOGV("Cannot get public key for %s", key_id);
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+    sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+
+    if (service == NULL) {
+        ALOGE("could not contact keystore");
+        return 0;
+    }
+
+    uint8_t *pubkey = NULL;
+    size_t pubkeyLen;
+    int32_t ret = service->get_pubkey(String16(key_id), &pubkey, &pubkeyLen);
+    if (ret < 0) {
+        ALOGW("could not contact keystore");
+        free(pubkey);
+        return NULL;
+    } else if (ret != 0) {
+        ALOGW("keystore reports error: %d", ret);
+        free(pubkey);
         return NULL;
     }
 
-    const unsigned char* tmp = reinterpret_cast<const unsigned char*>(reply.get());
-    Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, reply.length()));
+    const unsigned char* tmp = reinterpret_cast<const unsigned char*>(pubkey);
+    Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, pubkeyLen));
+    free(pubkey);
     if (pkey.get() == NULL) {
         ALOGW("Cannot convert pubkey");
         return NULL;
diff --git a/keystore/Android.mk b/keystore/Android.mk
index d4fbe06..8824dfe 100644
--- a/keystore/Android.mk
+++ b/keystore/Android.mk
@@ -20,7 +20,7 @@
 LOCAL_CFLAGS := -Wall -Wextra -Werror
 LOCAL_SRC_FILES := keystore.cpp keyblob_utils.cpp
 LOCAL_C_INCLUDES := external/openssl/include
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto libhardware
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto libhardware libkeystore_binder libutils libbinder
 LOCAL_MODULE := keystore
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_EXECUTABLE)
@@ -29,7 +29,7 @@
 LOCAL_CFLAGS := -Wall -Wextra -Werror
 LOCAL_SRC_FILES := keystore_cli.cpp
 LOCAL_C_INCLUDES := external/openssl/include
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto libkeystore_binder libutils libbinder
 LOCAL_MODULE := keystore_cli
 LOCAL_MODULE_TAGS := debug
 include $(BUILD_EXECUTABLE)
@@ -37,8 +37,10 @@
 # Library for keystore clients
 include $(CLEAR_VARS)
 LOCAL_CFLAGS := -Wall -Wextra -Werror
-LOCAL_SRC_FILES := keystore_client.cpp keyblob_utils.cpp
-LOCAL_SHARED_LIBRARIES := libcutils
-LOCAL_MODULE := libkeystore_client
+LOCAL_SRC_FILES := IKeystoreService.cpp keystore_get.cpp keyblob_utils.cpp
+LOCAL_SHARED_LIBRARIES := libbinder libutils
+LOCAL_MODULE := libkeystore_binder
 LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
new file mode 100644
index 0000000..9b4590e
--- /dev/null
+++ b/keystore/IKeystoreService.cpp
@@ -0,0 +1,726 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define LOG_TAG "KeystoreService"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <keystore/IKeystoreService.h>
+
+namespace android {
+
+class BpKeystoreService: public BpInterface<IKeystoreService>
+{
+public:
+    BpKeystoreService(const sp<IBinder>& impl)
+        : BpInterface<IKeystoreService>(impl)
+    {
+    }
+
+    // test ping
+    virtual int32_t test()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        status_t status = remote()->transact(BnKeystoreService::TEST, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("test() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("test() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        status_t status = remote()->transact(BnKeystoreService::GET, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("get() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        ssize_t len = reply.readInt32();
+        if (len >= 0 && (size_t) len <= reply.dataAvail()) {
+            size_t ulen = (size_t) len;
+            const void* buf = reply.readInplace(ulen);
+            *item = (uint8_t*) malloc(ulen);
+            if (*item != NULL) {
+                memcpy(*item, buf, ulen);
+                *itemLength = ulen;
+            } else {
+                ALOGE("out of memory allocating output array in get");
+                *itemLength = 0;
+            }
+        } else {
+            *itemLength = 0;
+        }
+        if (err < 0) {
+            ALOGD("get() caught exception %d\n", err);
+            return -1;
+        }
+        return 0;
+    }
+
+    virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(itemLength);
+        void* buf = data.writeInplace(itemLength);
+        memcpy(buf, item, itemLength);
+        status_t status = remote()->transact(BnKeystoreService::INSERT, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("import() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("import() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t del(const String16& name)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        status_t status = remote()->transact(BnKeystoreService::DEL, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("del() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("del() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t exist(const String16& name)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        status_t status = remote()->transact(BnKeystoreService::EXIST, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("exist() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("exist() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t saw(const String16& name, Vector<String16>* matches)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        status_t status = remote()->transact(BnKeystoreService::SAW, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("saw() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t numMatches = reply.readInt32();
+        for (int32_t i = 0; i < numMatches; i++) {
+            matches->push(reply.readString16());
+        }
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("saw() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t reset()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        status_t status = remote()->transact(BnKeystoreService::RESET, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("reset() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("reset() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t password(const String16& password)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(password);
+        status_t status = remote()->transact(BnKeystoreService::PASSWORD, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("password() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("password() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t lock()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        status_t status = remote()->transact(BnKeystoreService::LOCK, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("lock() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("lock() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t unlock(const String16& password)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(password);
+        status_t status = remote()->transact(BnKeystoreService::UNLOCK, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("unlock() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("unlock() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t zero()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        status_t status = remote()->transact(BnKeystoreService::ZERO, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("zero() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("zero() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t generate(const String16& name)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        status_t status = remote()->transact(BnKeystoreService::GENERATE, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("generate() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("generate() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t import(const String16& name, const uint8_t* key, size_t keyLength)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(keyLength);
+        void* buf = data.writeInplace(keyLength);
+        memcpy(buf, key, keyLength);
+        status_t status = remote()->transact(BnKeystoreService::IMPORT, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("import() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("import() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t sign(const String16& name, const uint8_t* in, size_t inLength, uint8_t** out,
+            size_t* outLength)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(inLength);
+        void* buf = data.writeInplace(inLength);
+        memcpy(buf, in, inLength);
+        status_t status = remote()->transact(BnKeystoreService::SIGN, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("import() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        ssize_t len = reply.readInt32();
+        if (len >= 0 && (size_t) len <= reply.dataAvail()) {
+            size_t ulen = (size_t) len;
+            const void* outBuf = reply.readInplace(ulen);
+            *out = (uint8_t*) malloc(ulen);
+            if (*out != NULL) {
+                memcpy((void*) *out, outBuf, ulen);
+                *outLength = ulen;
+            } else {
+                ALOGE("out of memory allocating output array in sign");
+                *outLength = 0;
+            }
+        } else {
+            *outLength = 0;
+        }
+        if (err < 0) {
+            ALOGD("import() caught exception %d\n", err);
+            return -1;
+        }
+        return 0;
+    }
+
+    virtual int32_t verify(const String16& name, const uint8_t* in, size_t inLength,
+            const uint8_t* signature, size_t signatureLength)
+    {
+        Parcel data, reply;
+        void* buf;
+
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(inLength);
+        buf = data.writeInplace(inLength);
+        memcpy(buf, in, inLength);
+        data.writeInt32(signatureLength);
+        buf = data.writeInplace(signatureLength);
+        memcpy(buf, signature, signatureLength);
+        status_t status = remote()->transact(BnKeystoreService::VERIFY, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("verify() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("verify() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        status_t status = remote()->transact(BnKeystoreService::GET_PUBKEY, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("get_pubkey() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        ssize_t len = reply.readInt32();
+        if (len >= 0 && (size_t) len <= reply.dataAvail()) {
+            size_t ulen = (size_t) len;
+            const void* buf = reply.readInplace(ulen);
+            *pubkey = (uint8_t*) malloc(ulen);
+            if (*pubkey != NULL) {
+                memcpy(*pubkey, buf, ulen);
+                *pubkeyLength = ulen;
+            } else {
+                ALOGE("out of memory allocating output array in get_pubkey");
+                *pubkeyLength = 0;
+            }
+        } else {
+            *pubkeyLength = 0;
+        }
+        if (err < 0) {
+            ALOGD("get_pubkey() caught exception %d\n", err);
+            return -1;
+        }
+        return 0;
+     }
+
+    virtual int32_t del_key(const String16& name)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        status_t status = remote()->transact(BnKeystoreService::DEL_KEY, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("del_key() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("del_key() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t grant(const String16& name, int32_t granteeUid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(granteeUid);
+        status_t status = remote()->transact(BnKeystoreService::GRANT, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("grant() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("grant() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t ungrant(const String16& name, int32_t granteeUid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(granteeUid);
+        status_t status = remote()->transact(BnKeystoreService::UNGRANT, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("ungrant() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("ungrant() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    int64_t getmtime(const String16& name)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        status_t status = remote()->transact(BnKeystoreService::GETMTIME, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("getmtime() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int64_t ret = reply.readInt64();
+        if (err < 0) {
+            ALOGD("getmtime() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore");
+
+// ----------------------------------------------------------------------
+
+status_t BnKeystoreService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case TEST: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t ret = test();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case GET: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            void* out = NULL;
+            size_t outSize = 0;
+            int32_t ret = get(name, (uint8_t**) &out, &outSize);
+            reply->writeNoException();
+            if (ret == 1) {
+                reply->writeInt32(outSize);
+                void* buf = reply->writeInplace(outSize);
+                memcpy(buf, out, outSize);
+                free(out);
+            } else {
+                reply->writeInt32(-1);
+            }
+            return NO_ERROR;
+        } break;
+        case INSERT: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            ssize_t inSize = data.readInt32();
+            const void* in;
+            if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
+                in = data.readInplace(inSize);
+            } else {
+                in = NULL;
+                inSize = 0;
+            }
+            int32_t ret = insert(name, (const uint8_t*) in, (size_t) inSize);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case DEL: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            int32_t ret = del(name);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case EXIST: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            int32_t ret = exist(name);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case SAW: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            Vector<String16> matches;
+            int32_t ret = saw(name, &matches);
+            reply->writeNoException();
+            reply->writeInt32(matches.size());
+            Vector<String16>::const_iterator it = matches.begin();
+            for (; it != matches.end(); ++it) {
+                reply->writeString16(*it);
+            }
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case RESET: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t ret = reset();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case PASSWORD: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 pass = data.readString16();
+            int32_t ret = password(pass);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case LOCK: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t ret = lock();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case UNLOCK: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 pass = data.readString16();
+            int32_t ret = unlock(pass);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case ZERO: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t ret = zero();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case GENERATE: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            int32_t ret = generate(name);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case IMPORT: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            ssize_t inSize = data.readInt32();
+            const void* in;
+            if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
+                in = data.readInplace(inSize);
+            } else {
+                in = NULL;
+                inSize = 0;
+            }
+            int32_t ret = import(name, (const uint8_t*) in, (size_t) inSize);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case SIGN: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            ssize_t inSize = data.readInt32();
+            const void* in;
+            if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
+                in = data.readInplace(inSize);
+            } else {
+                in = NULL;
+                inSize = 0;
+            }
+            void* out = NULL;
+            size_t outSize = 0;
+            int32_t ret = sign(name, (const uint8_t*) in, (size_t) inSize, (uint8_t**) &out, &outSize);
+            reply->writeNoException();
+            reply->writeInt32(outSize);
+            void* buf = reply->writeInplace(outSize);
+            memcpy(buf, out, outSize);
+            free(out);
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case VERIFY: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            ssize_t inSize = data.readInt32();
+            const void* in;
+            if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
+                in = data.readInplace(inSize);
+            } else {
+                in = NULL;
+                inSize = 0;
+            }
+            ssize_t sigSize = data.readInt32();
+            const void* sig;
+            if (sigSize >= 0 && (size_t) sigSize <= data.dataAvail()) {
+                sig = data.readInplace(sigSize);
+            } else {
+                sig = NULL;
+                sigSize = 0;
+            }
+            bool ret = verify(name, (const uint8_t*) in, (size_t) inSize, (const uint8_t*) sig,
+                    (size_t) sigSize);
+            reply->writeNoException();
+            reply->writeInt32(ret ? 1 : 0);
+            return NO_ERROR;
+        } break;
+        case GET_PUBKEY: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            void* out = NULL;
+            size_t outSize = 0;
+            int32_t ret = get_pubkey(name, (unsigned char**) &out, &outSize);
+            reply->writeNoException();
+            reply->writeInt32(outSize);
+            void* buf = reply->writeInplace(outSize);
+            memcpy(buf, out, outSize);
+            free(out);
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case DEL_KEY: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            int32_t ret = del_key(name);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case GRANT: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            int32_t granteeUid = data.readInt32();
+            int32_t ret = grant(name, granteeUid);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case UNGRANT: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            int32_t granteeUid = data.readInt32();
+            int32_t ret = ungrant(name, granteeUid);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case GETMTIME: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 name = data.readString16();
+            int64_t ret = getmtime(name);
+            reply->writeNoException();
+            reply->writeInt64(ret);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
new file mode 100644
index 0000000..15712ce
--- /dev/null
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef KEYSTORE_IKEYSTORESERVICE_H
+#define KEYSTORE_IKEYSTORESERVICE_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+/*
+ * This must be kept manually in sync with frameworks/base's IKeystoreService.java
+ */
+class IKeystoreService: public IInterface {
+public:
+    enum {
+        TEST = IBinder::FIRST_CALL_TRANSACTION + 0,
+        GET = IBinder::FIRST_CALL_TRANSACTION + 1,
+        INSERT = IBinder::FIRST_CALL_TRANSACTION + 2,
+        DEL = IBinder::FIRST_CALL_TRANSACTION + 3,
+        EXIST = IBinder::FIRST_CALL_TRANSACTION + 4,
+        SAW = IBinder::FIRST_CALL_TRANSACTION + 5,
+        RESET = IBinder::FIRST_CALL_TRANSACTION + 6,
+        PASSWORD = IBinder::FIRST_CALL_TRANSACTION + 7,
+        LOCK = IBinder::FIRST_CALL_TRANSACTION + 8,
+        UNLOCK = IBinder::FIRST_CALL_TRANSACTION + 9,
+        ZERO = IBinder::FIRST_CALL_TRANSACTION + 10,
+        GENERATE = IBinder::FIRST_CALL_TRANSACTION + 11,
+        IMPORT = IBinder::FIRST_CALL_TRANSACTION + 12,
+        SIGN = IBinder::FIRST_CALL_TRANSACTION + 13,
+        VERIFY = IBinder::FIRST_CALL_TRANSACTION + 14,
+        GET_PUBKEY = IBinder::FIRST_CALL_TRANSACTION + 15,
+        DEL_KEY = IBinder::FIRST_CALL_TRANSACTION + 16,
+        GRANT = IBinder::FIRST_CALL_TRANSACTION + 17,
+        UNGRANT = IBinder::FIRST_CALL_TRANSACTION + 18,
+        GETMTIME = IBinder::FIRST_CALL_TRANSACTION + 19,
+    };
+
+    DECLARE_META_INTERFACE(KeystoreService);
+
+    virtual int32_t test() = 0;
+
+    virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength) = 0;
+
+    virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength) = 0;
+
+    virtual int32_t del(const String16& name) = 0;
+
+    virtual int32_t exist(const String16& name) = 0;
+
+    virtual int32_t saw(const String16& name, Vector<String16>* matches) = 0;
+
+    virtual int32_t reset() = 0;
+
+    virtual int32_t password(const String16& password) = 0;
+
+    virtual int32_t lock() = 0;
+
+    virtual int32_t unlock(const String16& password) = 0;
+
+    virtual int32_t zero() = 0;
+
+    virtual int32_t generate(const String16& name) = 0;
+
+    virtual int32_t import(const String16& name, const uint8_t* data, size_t length) = 0;
+
+    virtual int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
+            size_t* outLength) = 0;
+
+    virtual int32_t verify(const String16& name, const uint8_t* data, size_t dataLength,
+            const uint8_t* signature, size_t signatureLength) = 0;
+
+    virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) = 0;
+
+    virtual int32_t del_key(const String16& name) = 0;
+
+    virtual int32_t grant(const String16& name, int32_t granteeUid) = 0;
+
+    virtual int32_t ungrant(const String16& name, int32_t granteeUid) = 0;
+
+    virtual int64_t getmtime(const String16& name) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnKeystoreService: public BnInterface<IKeystoreService> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+            uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif
diff --git a/keystore/keystore.h b/keystore/include/keystore/keystore.h
similarity index 67%
rename from keystore/keystore.h
rename to keystore/include/keystore/keystore.h
index f5e4439..c8f2755 100644
--- a/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -43,56 +43,6 @@
     SIGNATURE_INVALID = 14,
 };
 
-enum CommandNames {
-    TEST = 0,
-    GET = 1,
-    INSERT = 2,
-    DELETE = 3,
-    EXIST = 4,
-    SAW = 5,
-    RESET = 6,
-    PASSWORD = 7,
-    LOCK = 8,
-    UNLOCK = 9,
-    ZERO = 10,
-    GENERATE = 11,
-    IMPORT = 12,
-    SIGN = 13,
-    VERIFY = 14,
-    GET_PUBKEY = 15,
-    DEL_KEY = 16,
-    GRANT = 17,
-    UNGRANT = 18,
-    GETMTIME = 19,
-};
-
-typedef uint8_t command_code_t;
-
-// Taken: a b c d e f g h i j k l m n o p q r s t u v w x y z
-//        * * * * *   *   *   * * * *   *   * * * * *   *   *
-command_code_t CommandCodes[] = {
-    't', // TEST
-    'g', // GET
-    'i', // INSERT
-    'd', // DELETE
-    'e', // EXIST
-    's', // SAW
-    'r', // RESET
-    'p', // PASSWORD
-    'l', // LOCK
-    'u', // UNLOCK
-    'z', // ZERO
-    'a', // GENERATE
-    'm', // IMPORT
-    'n', // SIGN
-    'v', // VERIFY
-    'b', // GET_PUBKEY
-    'k', // DEL_KEY
-    'x', // GRANT
-    'y', // UNGRANT
-    'c', // GETMTIME
-};
-
 /**
  * Returns the size of the softkey magic header value for measuring
  * and allocating purposes.
diff --git a/keystore/include/keystore/keystore_get.h b/keystore/include/keystore/keystore_get.h
new file mode 100644
index 0000000..4bddd70
--- /dev/null
+++ b/keystore/include/keystore/keystore_get.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __KEYSTORE_GET_H__
+#define __KEYSTORE_GET_H__
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This function is provided for native components to get values from keystore.
+ * Users are required to link against libkeystore_binder.
+ *
+ * Keys and values are 8-bit safe. The first two arguments are the key and its
+ * length. The third argument is a pointer to an array that will be malloc()
+ * and the caller is responsible for calling free() on the buffer.
+ */
+ssize_t keystore_get(const char *key, size_t length, uint8_t** value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index ea58ad6..23711e7 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "keystore"
+
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
@@ -42,13 +45,15 @@
 
 #include <cutils/list.h>
 
-//#define LOG_NDEBUG 0
-#define LOG_TAG "keystore"
+#include <keystore/IKeystoreService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
 #include <cutils/log.h>
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 
-#include "keystore.h"
+#include <keystore/keystore.h>
 
 /* KeyStore is a secured storage for key-value pairs. In this implementation,
  * each file stores one key-value pair. Keys are encoded in file names, and
@@ -154,6 +159,72 @@
     keymaster_close(dev);
 }
 
+/***************
+ * PERMISSIONS *
+ ***************/
+
+/* Here are the permissions, actions, users, and the main function. */
+typedef enum {
+    P_TEST     = 1 << 0,
+    P_GET      = 1 << 1,
+    P_INSERT   = 1 << 2,
+    P_DELETE   = 1 << 3,
+    P_EXIST    = 1 << 4,
+    P_SAW      = 1 << 5,
+    P_RESET    = 1 << 6,
+    P_PASSWORD = 1 << 7,
+    P_LOCK     = 1 << 8,
+    P_UNLOCK   = 1 << 9,
+    P_ZERO     = 1 << 10,
+    P_SIGN     = 1 << 11,
+    P_VERIFY   = 1 << 12,
+    P_GRANT    = 1 << 13,
+} perm_t;
+
+static struct user_euid {
+    uid_t uid;
+    uid_t euid;
+} user_euids[] = {
+    {AID_VPN, AID_SYSTEM},
+    {AID_WIFI, AID_SYSTEM},
+    {AID_ROOT, AID_SYSTEM},
+};
+
+static struct user_perm {
+    uid_t uid;
+    perm_t perms;
+} user_perms[] = {
+    {AID_SYSTEM, static_cast<perm_t>((uint32_t)(~0)) },
+    {AID_VPN,    static_cast<perm_t>(P_GET | P_SIGN | P_VERIFY) },
+    {AID_WIFI,   static_cast<perm_t>(P_GET | P_SIGN | P_VERIFY) },
+    {AID_ROOT,   static_cast<perm_t>(P_GET) },
+};
+
+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);
+
+static bool has_permission(uid_t uid, perm_t perm) {
+    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) {
+            return user.perms & perm;
+        }
+    }
+
+    return DEFAULT_PERMS & perm;
+}
+
+static uid_t get_keystore_euid(uid_t uid) {
+    for (size_t i = 0; i < sizeof(user_euids)/sizeof(user_euids[0]); i++) {
+        struct user_euid user = user_euids[i];
+        if (user.uid == uid) {
+            return user.euid;
+        }
+    }
+
+    return uid;
+}
+
 /* Here is the encoding of keys. This is necessary in order to allow arbitrary
  * characters in keys. Characters in [0-~] are not encoded. Others are encoded
  * into two bytes. The first byte is one of [+-.] which represents the first
@@ -161,9 +232,9 @@
  * [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 int encode_key(char* out, const Value* key) {
-    const uint8_t* in = key->value;
-    int length = key->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;
@@ -177,25 +248,48 @@
     return length;
 }
 
-static int encode_key_for_uid(char* out, uid_t uid, const Value* key) {
+static int encode_key_for_uid(char* out, uid_t uid, const android::String8& keyName) {
     int n = snprintf(out, NAME_MAX, "%u_", uid);
     out += n;
 
-    return n + encode_key(out, key);
+    return n + encode_key(out, keyName);
 }
 
-static int decode_key(uint8_t* out, const char* in, int length) {
-    for (int i = 0; i < length; ++i, ++in, ++out) {
-        if (*in >= '0' && *in <= '~') {
-            *out = *in;
+/*
+ * Converts from the "escaped" format on disk to actual name.
+ * This will be smaller than the input string.
+ *
+ * Characters that should combine with the next at the end will be truncated.
+ */
+static size_t decode_key_length(const char* in, size_t length) {
+    size_t outLength = 0;
+
+    for (const char* end = in + length; in < end; in++) {
+        /* This combines with the next character. */
+        if (*in < '0' || *in > '~') {
+            continue;
+        }
+
+        outLength++;
+    }
+    return outLength;
+}
+
+static void decode_key(char* out, const char* in, size_t length) {
+    for (const char* end = in + length; in < end; in++) {
+        if (*in < '0' || *in > '~') {
+            /* Truncate combining characters at the end. */
+            if (in + 1 >= end) {
+                break;
+            }
+
+            *out = (*in++ - '+') << 6;
+            *out++ |= (*in - '0') & 0x3F;
         } else {
-            *out = (*in - '+') << 6;
-            *out |= (*++in - '0') & 0x3F;
-            --length;
+            *out++ = *in;
         }
     }
     *out = '\0';
-    return length;
 }
 
 static size_t readFully(int fd, uint8_t* data, size_t size) {
@@ -293,18 +387,19 @@
     TYPE_KEY_PAIR = 3,
 } BlobType;
 
-static const uint8_t CurrentBlobVersion = 1;
+static const uint8_t CURRENT_BLOB_VERSION = 1;
 
 class Blob {
 public:
-    Blob(uint8_t* value, int32_t valueLength, uint8_t* info, uint8_t infoLength, BlobType type) {
+    Blob(const uint8_t* value, int32_t valueLength, const uint8_t* info, uint8_t infoLength,
+            BlobType type) {
         mBlob.length = valueLength;
         memcpy(mBlob.value, value, valueLength);
 
         mBlob.info = infoLength;
         memcpy(mBlob.value + valueLength, info, infoLength);
 
-        mBlob.version = CurrentBlobVersion;
+        mBlob.version = CURRENT_BLOB_VERSION;
         mBlob.type = uint8_t(type);
     }
 
@@ -388,7 +483,7 @@
             unlink(tmpFileName);
             return SYSTEM_ERROR;
         }
-        return (rename(tmpFileName, filename) == 0) ? NO_ERROR : SYSTEM_ERROR;
+        return (rename(tmpFileName, filename) == 0) ? ::NO_ERROR : ::SYSTEM_ERROR;
     }
 
     ResponseCode decryptBlob(const char* filename, AES_KEY *aes_key) {
@@ -430,7 +525,7 @@
             // move info from after padding to after data
             memmove(&mBlob.value[mBlob.length], &mBlob.value[maxValueLength], mBlob.info);
         }
-        return NO_ERROR;
+        return ::NO_ERROR;
     }
 
 private:
@@ -472,7 +567,7 @@
         return mDevice;
     }
 
-    ResponseCode initialize(Value* pw) {
+    ResponseCode initialize(const android::String8& pw) {
         if (!generateMasterKey()) {
             return SYSTEM_ERROR;
         }
@@ -481,10 +576,10 @@
             return response;
         }
         setupMasterKeys();
-        return NO_ERROR;
+        return ::NO_ERROR;
     }
 
-    ResponseCode writeMasterKey(Value* pw) {
+    ResponseCode writeMasterKey(const android::String8& pw) {
         uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
         generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
         AES_KEY passwordAesKey;
@@ -493,7 +588,7 @@
         return masterKeyBlob.encryptBlob(MASTER_KEY_FILE, &passwordAesKey, mEntropy);
     }
 
-    ResponseCode readMasterKey(Value* pw) {
+    ResponseCode readMasterKey(const android::String8& pw) {
         int in = open(MASTER_KEY_FILE, O_RDONLY);
         if (in == -1) {
             return SYSTEM_ERROR;
@@ -596,7 +691,7 @@
         }
 
         const uint8_t version = keyBlob->getVersion();
-        if (version < CurrentBlobVersion) {
+        if (version < CURRENT_BLOB_VERSION) {
             upgrade(filename, keyBlob, version, type);
         }
 
@@ -612,28 +707,18 @@
         return keyBlob->encryptBlob(filename, &mMasterKeyEncryption, mEntropy);
     }
 
-    void addGrant(const char* filename, const Value* uidValue) {
-        uid_t uid;
-        if (!convertToUid(uidValue, &uid)) {
-            return;
-        }
-
-        grant_t *grant = getGrant(filename, uid);
+    void addGrant(const char* filename, uid_t granteeUid) {
+        grant_t *grant = getGrant(filename, granteeUid);
         if (grant == NULL) {
             grant = new grant_t;
-            grant->uid = uid;
+            grant->uid = granteeUid;
             grant->filename = reinterpret_cast<const uint8_t*>(strdup(filename));
             list_add_tail(&mGrants, &grant->plist);
         }
     }
 
-    bool removeGrant(const char* filename, const Value* uidValue) {
-        uid_t uid;
-        if (!convertToUid(uidValue, &uid)) {
-            return false;
-        }
-
-        grant_t *grant = getGrant(filename, uid);
+    bool removeGrant(const char* filename, uid_t granteeUid) {
+        grant_t *grant = getGrant(filename, granteeUid);
         if (grant != NULL) {
             list_remove(&grant->plist);
             delete grant;
@@ -647,7 +732,7 @@
         return getGrant(filename, uid) != NULL;
     }
 
-    ResponseCode importKey(const Value* key, const char* filename) {
+    ResponseCode importKey(const uint8_t* key, size_t keyLen, const char* filename) {
         uint8_t* data;
         size_t dataLength;
         int rc;
@@ -657,7 +742,7 @@
             return SYSTEM_ERROR;
         }
 
-        rc = mDevice->import_keypair(mDevice, key->value, key->length, &data, &dataLength);
+        rc = mDevice->import_keypair(mDevice, key, keyLen, &data, &dataLength);
         if (rc) {
             ALOGE("Error while importing keypair: %d", rc);
             return SYSTEM_ERROR;
@@ -726,7 +811,8 @@
         memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption));
     }
 
-    static void generateKeyFromPassword(uint8_t* key, ssize_t keySize, Value* pw, uint8_t* salt) {
+    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;
@@ -736,7 +822,9 @@
             // sizeof = 9, not strlen = 8
             saltSize = sizeof("keystore");
         }
-        PKCS5_PBKDF2_HMAC_SHA1((char*) pw->value, pw->length, salt, saltSize, 8192, keySize, key);
+
+        PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt,
+                saltSize, 8192, keySize, key);
     }
 
     static bool isKeyFile(const char* filename) {
@@ -834,7 +922,7 @@
             return SYSTEM_ERROR;
         }
 
-        ResponseCode rc = importKey(&pkcs8key, filename);
+        ResponseCode rc = importKey(pkcs8key.value, pkcs8key.length, filename);
         if (rc != NO_ERROR) {
             return rc;
         }
@@ -845,55 +933,8 @@
 
 const char* KeyStore::MASTER_KEY_FILE = ".masterkey";
 
-/* Here is the protocol used in both requests and responses:
- *     code [length_1 message_1 ... length_n message_n] end-of-file
- * where code is one byte long and lengths are unsigned 16-bit integers in
- * network order. Thus the maximum length of a message is 65535 bytes. */
-
-static int recv_code(int sock, int8_t* code) {
-    return recv(sock, code, 1, 0) == 1;
-}
-
-static int recv_message(int sock, uint8_t* message, int length) {
-    uint8_t bytes[2];
-    if (recv(sock, &bytes[0], 1, 0) != 1 ||
-        recv(sock, &bytes[1], 1, 0) != 1) {
-        return -1;
-    } else {
-        int offset = bytes[0] << 8 | bytes[1];
-        if (length < offset) {
-            return -1;
-        }
-        length = offset;
-        offset = 0;
-        while (offset < length) {
-            int n = recv(sock, &message[offset], length - offset, 0);
-            if (n <= 0) {
-                return -1;
-            }
-            offset += n;
-        }
-    }
-    return length;
-}
-
-static int recv_end_of_file(int sock) {
-    uint8_t byte;
-    return recv(sock, &byte, 1, 0) == 0;
-}
-
-static void send_code(int sock, int8_t code) {
-    send(sock, &code, 1, 0);
-}
-
-static void send_message(int sock, const uint8_t* message, int length) {
-    uint16_t bytes = htons(length);
-    send(sock, &bytes, 2, 0);
-    send(sock, message, length, 0);
-}
-
-static ResponseCode get_key_for_name(KeyStore* keyStore, Blob* keyBlob, const Value* keyName,
-        const uid_t uid, const BlobType type) {
+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);
@@ -922,494 +963,627 @@
     return keyStore->get(filename, keyBlob, type);
 }
 
-/* Here are the actions. Each of them is a function without arguments. All
- * information is defined in global variables, which are set properly before
- * performing an action. The number of parameters required by each action is
- * fixed and defined in a table. If the return value of an action is positive,
- * it will be treated as a response code and transmitted to the client. Note
- * that the lengths of parameters are checked when they are received, so
- * boundary checks on parameters are omitted. */
-
-static const ResponseCode NO_ERROR_RESPONSE_CODE_SENT = (ResponseCode) 0;
-
-static ResponseCode test(KeyStore* keyStore, int, uid_t, Value*, Value*, Value*) {
-    return (ResponseCode) keyStore->getState();
-}
-
-static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*, Value*) {
-    char filename[NAME_MAX];
-    encode_key_for_uid(filename, uid, keyName);
-    Blob keyBlob;
-    ResponseCode responseCode = keyStore->get(filename, &keyBlob, TYPE_GENERIC);
-    if (responseCode != NO_ERROR) {
-        return responseCode;
+namespace android {
+class KeyStoreProxy : public BnKeystoreService, public IBinder::DeathRecipient {
+public:
+    KeyStoreProxy(KeyStore* keyStore)
+        : mKeyStore(keyStore)
+    {
     }
-    send_code(sock, NO_ERROR);
-    send_message(sock, keyBlob.getValue(), keyBlob.getLength());
-    return NO_ERROR_RESPONSE_CODE_SENT;
-}
 
-static ResponseCode insert(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value* val,
-        Value*) {
-    char filename[NAME_MAX];
-    encode_key_for_uid(filename, uid, keyName);
-    Blob keyBlob(val->value, val->length, NULL, 0, TYPE_GENERIC);
-    return keyStore->put(filename, &keyBlob);
-}
-
-static ResponseCode del(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value*, Value*) {
-    char filename[NAME_MAX];
-    encode_key_for_uid(filename, uid, keyName);
-    Blob keyBlob;
-    ResponseCode responseCode = keyStore->get(filename, &keyBlob, TYPE_GENERIC);
-    if (responseCode != NO_ERROR) {
-        return responseCode;
+    void binderDied(const wp<IBinder>&) {
+        ALOGE("binder death detected");
     }
-    return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
-}
 
-static ResponseCode exist(KeyStore*, int, uid_t uid, Value* keyName, Value*, Value*) {
-    char filename[NAME_MAX];
-    encode_key_for_uid(filename, uid, keyName);
-    if (access(filename, R_OK) == -1) {
-        return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
-    }
-    return NO_ERROR;
-}
-
-static ResponseCode saw(KeyStore*, int sock, uid_t uid, Value* keyPrefix, Value*, Value*) {
-    DIR* dir = opendir(".");
-    if (!dir) {
-        return SYSTEM_ERROR;
-    }
-    char filename[NAME_MAX];
-    int n = encode_key_for_uid(filename, uid, keyPrefix);
-    send_code(sock, NO_ERROR);
-
-    struct dirent* file;
-    while ((file = readdir(dir)) != NULL) {
-        if (!strncmp(filename, file->d_name, n)) {
-            const char* p = &file->d_name[n];
-            keyPrefix->length = decode_key(keyPrefix->value, p, strlen(p));
-            send_message(sock, keyPrefix->value, keyPrefix->length);
+    int32_t test() {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_TEST)) {
+            ALOGW("permission denied for %d: test", uid);
+            return ::PERMISSION_DENIED;
         }
-    }
-    closedir(dir);
-    return NO_ERROR_RESPONSE_CODE_SENT;
-}
 
-static ResponseCode reset(KeyStore* keyStore, int, uid_t, Value*, Value*, Value*) {
-    ResponseCode rc = keyStore->reset() ? NO_ERROR : SYSTEM_ERROR;
-
-    const keymaster_device_t* device = keyStore->getDevice();
-    if (device == NULL) {
-        ALOGE("No keymaster device!");
-        return SYSTEM_ERROR;
+        return mKeyStore->getState();
     }
 
-    if (device->delete_all == NULL) {
-        ALOGV("keymaster device doesn't implement delete_all");
-        return rc;
-    }
-
-    if (device->delete_all(device)) {
-        ALOGE("Problem calling keymaster's delete_all");
-        return SYSTEM_ERROR;
-    }
-
-    return rc;
-}
-
-/* Here is the history. To improve the security, the parameters to generate the
- * master key has been changed. To make a seamless transition, we update the
- * file using the same password when the user unlock it for the first time. If
- * any thing goes wrong during the transition, the new file will not overwrite
- * the old one. This avoids permanent damages of the existing data. */
-
-static ResponseCode password(KeyStore* keyStore, int, uid_t, Value* pw, Value*, Value*) {
-    switch (keyStore->getState()) {
-        case STATE_UNINITIALIZED: {
-            // generate master key, encrypt with password, write to file, initialize mMasterKey*.
-            return keyStore->initialize(pw);
+    int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_GET)) {
+            ALOGW("permission denied for %d: get", uid);
+            return ::PERMISSION_DENIED;
         }
-        case STATE_NO_ERROR: {
-            // rewrite master key with new password.
-            return keyStore->writeMasterKey(pw);
+        uid = get_keystore_euid(uid);
+
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling get in state: %d", state);
+            return state;
         }
-        case STATE_LOCKED: {
-            // read master key, decrypt with password, initialize mMasterKey*.
-            return keyStore->readMasterKey(pw);
+
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        encode_key_for_uid(filename, uid, name8);
+
+        Blob keyBlob;
+        ResponseCode responseCode = mKeyStore->get(filename, &keyBlob, TYPE_GENERIC);
+        if (responseCode != ::NO_ERROR) {
+            *item = NULL;
+            *itemLength = 0;
+            return responseCode;
         }
-    }
-    return SYSTEM_ERROR;
-}
 
-static ResponseCode lock(KeyStore* keyStore, int, uid_t, Value*, Value*, Value*) {
-    keyStore->lock();
-    return NO_ERROR;
-}
+        *item = (uint8_t*) malloc(keyBlob.getLength());
+        memcpy(*item, keyBlob.getValue(), keyBlob.getLength());
+        *itemLength = keyBlob.getLength();
 
-static ResponseCode unlock(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value* unused,
-        Value* unused2) {
-    return password(keyStore, sock, uid, pw, unused, unused2);
-}
-
-static ResponseCode zero(KeyStore* keyStore, int, uid_t, Value*, Value*, Value*) {
-    return keyStore->isEmpty() ? KEY_NOT_FOUND : NO_ERROR;
-}
-
-static ResponseCode generate(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value*,
-        Value*) {
-    char filename[NAME_MAX];
-    uint8_t* data;
-    size_t dataLength;
-    int rc;
-
-    const keymaster_device_t* device = keyStore->getDevice();
-    if (device == NULL) {
-        return SYSTEM_ERROR;
+        return ::NO_ERROR;
     }
 
-    if (device->generate_keypair == NULL) {
-        return SYSTEM_ERROR;
+    int32_t insert(const String16& name, const uint8_t* item, size_t itemLength) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_INSERT)) {
+            ALOGW("permission denied for %d: insert", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
+
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling insert in state: %d", state);
+            return state;
+        }
+
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        encode_key_for_uid(filename, uid, name8);
+
+        Blob keyBlob(item, itemLength, NULL, 0, ::TYPE_GENERIC);
+        return mKeyStore->put(filename, &keyBlob);
     }
 
-    keymaster_rsa_keygen_params_t rsa_params;
-    rsa_params.modulus_size = 2048;
-    rsa_params.public_exponent = 0x10001;
+    int32_t del(const String16& name) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_DELETE)) {
+            ALOGW("permission denied for %d: del", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
 
-    rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength);
-    if (rc) {
-        return SYSTEM_ERROR;
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        encode_key_for_uid(filename, uid, name8);
+
+        Blob keyBlob;
+        ResponseCode responseCode = mKeyStore->get(filename, &keyBlob, TYPE_GENERIC);
+        if (responseCode != ::NO_ERROR) {
+            return responseCode;
+        }
+        return (unlink(filename) && errno != ENOENT) ? ::SYSTEM_ERROR : ::NO_ERROR;
     }
 
-    encode_key_for_uid(filename, uid, keyName);
+    int32_t exist(const String16& name) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_EXIST)) {
+            ALOGW("permission denied for %d: exist", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
 
-    Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
-    free(data);
+        String8 name8(name);
+        char filename[NAME_MAX];
 
-    return keyStore->put(filename, &keyBlob);
-}
+        encode_key_for_uid(filename, uid, name8);
 
-static ResponseCode import(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value* key,
-        Value*) {
-    char filename[NAME_MAX];
-
-    encode_key_for_uid(filename, uid, keyName);
-
-    return keyStore->importKey(key, filename);
-}
-
-/*
- * TODO: The abstraction between things stored in hardware and regular blobs
- * of data stored on the filesystem should be moved down to keystore itself.
- * Unfortunately the Java code that calls this has naming conventions that it
- * knows about. Ideally keystore shouldn't be used to store random blobs of
- * data.
- *
- * Until that happens, it's necessary to have a separate "get_pubkey" and
- * "del_key" since the Java code doesn't really communicate what it's
- * intentions are.
- */
-static ResponseCode get_pubkey(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*, Value*) {
-    Blob keyBlob;
-    ALOGV("get_pubkey '%s' from uid %d", ValueString(keyName).c_str(), uid);
-
-    ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid, TYPE_KEY_PAIR);
-    if (responseCode != NO_ERROR) {
-        return responseCode;
+        if (access(filename, R_OK) == -1) {
+            return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+        }
+        return ::NO_ERROR;
     }
 
-    const keymaster_device_t* device = keyStore->getDevice();
-    if (device == NULL) {
-        return SYSTEM_ERROR;
-    }
+    int32_t saw(const String16& prefix, Vector<String16>* matches) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_SAW)) {
+            ALOGW("permission denied for %d: saw", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
 
-    if (device->get_keypair_public == NULL) {
-        ALOGE("device has no get_keypair_public implementation!");
-        return SYSTEM_ERROR;
-    }
+        DIR* dir = opendir(".");
+        if (!dir) {
+            return ::SYSTEM_ERROR;
+        }
 
-    uint8_t* data = NULL;
-    size_t dataLength;
+        const String8 prefix8(prefix);
+        char filename[NAME_MAX];
 
-    int rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), &data,
-            &dataLength);
-    if (rc) {
-        return SYSTEM_ERROR;
-    }
+        int n = encode_key_for_uid(filename, uid, prefix8);
 
-    send_code(sock, NO_ERROR);
-    send_message(sock, data, dataLength);
-    free(data);
+        struct dirent* file;
+        while ((file = readdir(dir)) != NULL) {
+            if (!strncmp(filename, file->d_name, n)) {
+                const char* p = &file->d_name[n];
+                size_t plen = strlen(p);
 
-    return NO_ERROR_RESPONSE_CODE_SENT;
-}
-
-static ResponseCode del_key(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value*,
-        Value*) {
-    char filename[NAME_MAX];
-    encode_key_for_uid(filename, uid, keyName);
-    Blob keyBlob;
-    ResponseCode responseCode = keyStore->get(filename, &keyBlob, TYPE_KEY_PAIR);
-    if (responseCode != NO_ERROR) {
-        return responseCode;
-    }
-
-    ResponseCode rc = NO_ERROR;
-
-    const keymaster_device_t* device = keyStore->getDevice();
-    if (device == NULL) {
-        rc = SYSTEM_ERROR;
-    } else {
-        // A device doesn't have to implement delete_keypair.
-        if (device->delete_keypair != NULL) {
-            if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
-                rc = SYSTEM_ERROR;
+                size_t extra = decode_key_length(p, plen);
+                char *match = (char*) malloc(extra + 1);
+                if (match != NULL) {
+                    decode_key(match, p, plen);
+                    matches->push(String16(match, extra));
+                    free(match);
+                } else {
+                    ALOGW("could not allocate match of size %zd", extra);
+                }
             }
         }
+        closedir(dir);
+
+        return ::NO_ERROR;
     }
 
-    if (rc != NO_ERROR) {
+    int32_t reset() {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_RESET)) {
+            ALOGW("permission denied for %d: reset", uid);
+            return ::PERMISSION_DENIED;
+        }
+
+        ResponseCode rc = mKeyStore->reset() ? ::NO_ERROR : ::SYSTEM_ERROR;
+
+        const keymaster_device_t* device = mKeyStore->getDevice();
+        if (device == NULL) {
+            ALOGE("No keymaster device!");
+            return ::SYSTEM_ERROR;
+        }
+
+        if (device->delete_all == NULL) {
+            ALOGV("keymaster device doesn't implement delete_all");
+            return rc;
+        }
+
+        if (device->delete_all(device)) {
+            ALOGE("Problem calling keymaster's delete_all");
+            return ::SYSTEM_ERROR;
+        }
+
         return rc;
     }
 
-    return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
-}
+    /*
+     * Here is the history. To improve the security, the parameters to generate the
+     * master key has been changed. To make a seamless transition, we update the
+     * file using the same password when the user unlock it for the first time. If
+     * any thing goes wrong during the transition, the new file will not overwrite
+     * the old one. This avoids permanent damages of the existing data.
+     */
+    int32_t password(const String16& password) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_PASSWORD)) {
+            ALOGW("permission denied for %d: password", uid);
+            return ::PERMISSION_DENIED;
+        }
 
-static ResponseCode sign(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* data,
-        Value*) {
-    ALOGV("sign %s from uid %d", ValueString(keyName).c_str(), uid);
-    Blob keyBlob;
-    int rc;
+        const String8 password8(password);
 
-    ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid, TYPE_KEY_PAIR);
-    if (responseCode != NO_ERROR) {
-        return responseCode;
+        switch (mKeyStore->getState()) {
+            case ::STATE_UNINITIALIZED: {
+                // generate master key, encrypt with password, write to file, initialize mMasterKey*.
+                return mKeyStore->initialize(password8);
+            }
+            case ::STATE_NO_ERROR: {
+                // rewrite master key with new password.
+                return mKeyStore->writeMasterKey(password8);
+            }
+            case ::STATE_LOCKED: {
+                // read master key, decrypt with password, initialize mMasterKey*.
+                return mKeyStore->readMasterKey(password8);
+            }
+        }
+        return ::SYSTEM_ERROR;
     }
 
-    uint8_t* signedData;
-    size_t signedDataLength;
+    int32_t lock() {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_LOCK)) {
+            ALOGW("permission denied for %d: lock", uid);
+            return ::PERMISSION_DENIED;
+        }
 
-    const keymaster_device_t* device = keyStore->getDevice();
-    if (device == NULL) {
-        ALOGE("no keymaster device; cannot sign");
-        return SYSTEM_ERROR;
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling lock in state: %d", state);
+            return state;
+        }
+
+        mKeyStore->lock();
+        return ::NO_ERROR;
     }
 
-    if (device->sign_data == NULL) {
-        ALOGE("device doesn't implement signing");
-        return SYSTEM_ERROR;
+    int32_t unlock(const String16& pw) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_UNLOCK)) {
+            ALOGW("permission denied for %d: unlock", uid);
+            return ::PERMISSION_DENIED;
+        }
+
+        State state = checkState();
+        if (state != STATE_LOCKED) {
+            ALOGD("calling unlock when not locked");
+            return state;
+        }
+
+        const String8 password8(pw);
+        return password(pw);
     }
 
-    keymaster_rsa_sign_params_t params;
-    params.digest_type = DIGEST_NONE;
-    params.padding_type = PADDING_NONE;
+    int32_t zero() {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_ZERO)) {
+            ALOGW("permission denied for %d: zero", uid);
+            return -1;
+        }
 
-    rc = device->sign_data(device, &params, keyBlob.getValue(), keyBlob.getLength(),
-            data->value, data->length, &signedData, &signedDataLength);
-    if (rc) {
-        ALOGW("device couldn't sign data");
-        return SYSTEM_ERROR;
+        return mKeyStore->isEmpty() ? ::KEY_NOT_FOUND : ::NO_ERROR;
     }
 
-    send_code(sock, NO_ERROR);
-    send_message(sock, signedData, signedDataLength);
-    return NO_ERROR_RESPONSE_CODE_SENT;
-}
+    int32_t generate(const String16& name) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_INSERT)) {
+            ALOGW("permission denied for %d: generate", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
 
-static ResponseCode verify(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value* data,
-        Value* signature) {
-    Blob keyBlob;
-    int rc;
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling generate in state: %d", state);
+            return state;
+        }
 
-    ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid, TYPE_KEY_PAIR);
-    if (responseCode != NO_ERROR) {
-        return responseCode;
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        uint8_t* data;
+        size_t dataLength;
+        int rc;
+
+        const keymaster_device_t* device = mKeyStore->getDevice();
+        if (device == NULL) {
+            return ::SYSTEM_ERROR;
+        }
+
+        if (device->generate_keypair == NULL) {
+            return ::SYSTEM_ERROR;
+        }
+
+        keymaster_rsa_keygen_params_t rsa_params;
+        rsa_params.modulus_size = 2048;
+        rsa_params.public_exponent = 0x10001;
+
+        rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength);
+        if (rc) {
+            return ::SYSTEM_ERROR;
+        }
+
+        encode_key_for_uid(filename, uid, name8);
+
+        Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
+        free(data);
+
+        return mKeyStore->put(filename, &keyBlob);
     }
 
-    const keymaster_device_t* device = keyStore->getDevice();
-    if (device == NULL) {
-        return SYSTEM_ERROR;
+    int32_t import(const String16& name, const uint8_t* data, size_t length) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_INSERT)) {
+            ALOGW("permission denied for %d: import", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
+
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling import in state: %d", state);
+            return state;
+        }
+
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        encode_key_for_uid(filename, uid, name8);
+
+        return mKeyStore->importKey(data, length, filename);
     }
 
-    if (device->verify_data == NULL) {
-        return SYSTEM_ERROR;
+    int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
+            size_t* outLength) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_SIGN)) {
+            ALOGW("permission denied for %d: saw", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
+
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling sign in state: %d", state);
+            return state;
+        }
+
+        Blob keyBlob;
+        String8 name8(name);
+
+        ALOGV("sign %s from uid %d", name8.string(), uid);
+        int rc;
+
+        ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, uid, ::TYPE_KEY_PAIR);
+        if (responseCode != ::NO_ERROR) {
+            return responseCode;
+        }
+
+        const keymaster_device_t* device = mKeyStore->getDevice();
+        if (device == NULL) {
+            ALOGE("no keymaster device; cannot sign");
+            return ::SYSTEM_ERROR;
+        }
+
+        if (device->sign_data == NULL) {
+            ALOGE("device doesn't implement signing");
+            return ::SYSTEM_ERROR;
+        }
+
+        keymaster_rsa_sign_params_t params;
+        params.digest_type = DIGEST_NONE;
+        params.padding_type = PADDING_NONE;
+
+        rc = device->sign_data(device, &params, keyBlob.getValue(), keyBlob.getLength(),
+                data, length, out, outLength);
+        if (rc) {
+            ALOGW("device couldn't sign data");
+            return ::SYSTEM_ERROR;
+        }
+
+        return ::NO_ERROR;
     }
 
-    keymaster_rsa_sign_params_t params;
-    params.digest_type = DIGEST_NONE;
-    params.padding_type = PADDING_NONE;
+    int32_t verify(const String16& name, const uint8_t* data, size_t dataLength,
+            const uint8_t* signature, size_t signatureLength) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_VERIFY)) {
+            ALOGW("permission denied for %d: verify", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
 
-    rc = device->verify_data(device, &params, keyBlob.getValue(), keyBlob.getLength(),
-            data->value, data->length, signature->value, signature->length);
-    if (rc) {
-        return SYSTEM_ERROR;
-    } else {
-        return NO_ERROR;
-    }
-}
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling verify in state: %d", state);
+            return state;
+        }
 
-static ResponseCode grant(KeyStore* keyStore, int, uid_t uid, Value* keyName,
-        Value* granteeData, Value*) {
-    char filename[NAME_MAX];
-    encode_key_for_uid(filename, uid, keyName);
-    if (access(filename, R_OK) == -1) {
-        return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
-    }
+        Blob keyBlob;
+        String8 name8(name);
+        int rc;
 
-    keyStore->addGrant(filename, granteeData);
-    return NO_ERROR;
-}
+        ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, uid, TYPE_KEY_PAIR);
+        if (responseCode != ::NO_ERROR) {
+            return responseCode;
+        }
 
-static ResponseCode ungrant(KeyStore* keyStore, int, uid_t uid, Value* keyName,
-        Value* granteeData, Value*) {
-    char filename[NAME_MAX];
-    encode_key_for_uid(filename, uid, keyName);
-    if (access(filename, R_OK) == -1) {
-        return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
-    }
+        const keymaster_device_t* device = mKeyStore->getDevice();
+        if (device == NULL) {
+            return ::SYSTEM_ERROR;
+        }
 
-    return keyStore->removeGrant(filename, granteeData) ? NO_ERROR : KEY_NOT_FOUND;
-}
+        if (device->verify_data == NULL) {
+            return ::SYSTEM_ERROR;
+        }
 
-static ResponseCode getmtime(KeyStore*, int sock, uid_t uid, Value* keyName,
-        Value*, Value*) {
-    char filename[NAME_MAX];
-    encode_key_for_uid(filename, uid, keyName);
-    if (access(filename, R_OK) == -1) {
-        return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
-    }
+        keymaster_rsa_sign_params_t params;
+        params.digest_type = DIGEST_NONE;
+        params.padding_type = PADDING_NONE;
 
-    int fd = open(filename, O_NOFOLLOW, O_RDONLY);
-    if (fd < 0) {
-        return SYSTEM_ERROR;
-    }
-
-    struct stat s;
-    int ret = fstat(fd, &s);
-    close(fd);
-    if (ret == -1) {
-        return SYSTEM_ERROR;
-    }
-
-    uint8_t *data;
-    int dataLength = asprintf(reinterpret_cast<char**>(&data), "%lu", s.st_mtime);
-    if (dataLength < 0) {
-        return SYSTEM_ERROR;
-    }
-
-    send_code(sock, NO_ERROR);
-    send_message(sock, data, dataLength);
-    free(data);
-
-    return NO_ERROR_RESPONSE_CODE_SENT;
-}
-
-/* Here are the permissions, actions, users, and the main function. */
-enum perm {
-    P_TEST     = 1 << TEST,
-    P_GET      = 1 << GET,
-    P_INSERT   = 1 << INSERT,
-    P_DELETE   = 1 << DELETE,
-    P_EXIST    = 1 << EXIST,
-    P_SAW      = 1 << SAW,
-    P_RESET    = 1 << RESET,
-    P_PASSWORD = 1 << PASSWORD,
-    P_LOCK     = 1 << LOCK,
-    P_UNLOCK   = 1 << UNLOCK,
-    P_ZERO     = 1 << ZERO,
-    P_SIGN     = 1 << SIGN,
-    P_VERIFY   = 1 << VERIFY,
-    P_GRANT    = 1 << GRANT,
-};
-
-static const int MAX_PARAM = 3;
-
-static const State STATE_ANY = (State) 0;
-
-static struct action {
-    ResponseCode (*run)(KeyStore* keyStore, int sock, uid_t uid, Value* param1, Value* param2,
-            Value* param3);
-    uint8_t code;
-    State state;
-    uint32_t perm;
-    int lengths[MAX_PARAM];
-} actions[] = {
-    {test,       CommandCodes[TEST],       STATE_ANY,      P_TEST,     {0, 0, 0}},
-    {get,        CommandCodes[GET],        STATE_NO_ERROR, P_GET,      {KEY_SIZE, 0, 0}},
-    {insert,     CommandCodes[INSERT],     STATE_NO_ERROR, P_INSERT,   {KEY_SIZE, VALUE_SIZE, 0}},
-    {del,        CommandCodes[DELETE],     STATE_ANY,      P_DELETE,   {KEY_SIZE, 0, 0}},
-    {exist,      CommandCodes[EXIST],      STATE_ANY,      P_EXIST,    {KEY_SIZE, 0, 0}},
-    {saw,        CommandCodes[SAW],        STATE_ANY,      P_SAW,      {KEY_SIZE, 0, 0}},
-    {reset,      CommandCodes[RESET],      STATE_ANY,      P_RESET,    {0, 0, 0}},
-    {password,   CommandCodes[PASSWORD],   STATE_ANY,      P_PASSWORD, {PASSWORD_SIZE, 0, 0}},
-    {lock,       CommandCodes[LOCK],       STATE_NO_ERROR, P_LOCK,     {0, 0, 0}},
-    {unlock,     CommandCodes[UNLOCK],     STATE_LOCKED,   P_UNLOCK,   {PASSWORD_SIZE, 0, 0}},
-    {zero,       CommandCodes[ZERO],       STATE_ANY,      P_ZERO,     {0, 0, 0}},
-    {generate,   CommandCodes[GENERATE],   STATE_NO_ERROR, P_INSERT,   {KEY_SIZE, 0, 0}},
-    {import,     CommandCodes[IMPORT],     STATE_NO_ERROR, P_INSERT,   {KEY_SIZE, VALUE_SIZE, 0}},
-    {sign,       CommandCodes[SIGN],       STATE_NO_ERROR, P_SIGN,     {KEY_SIZE, VALUE_SIZE, 0}},
-    {verify,     CommandCodes[VERIFY],     STATE_NO_ERROR, P_VERIFY,   {KEY_SIZE, VALUE_SIZE, VALUE_SIZE}},
-    {get_pubkey, CommandCodes[GET_PUBKEY], STATE_NO_ERROR, P_GET,      {KEY_SIZE, 0, 0}},
-    {del_key,    CommandCodes[DEL_KEY],    STATE_ANY,      P_DELETE,   {KEY_SIZE, 0, 0}},
-    {grant,      CommandCodes[GRANT],      STATE_NO_ERROR, P_GRANT,    {KEY_SIZE, KEY_SIZE, 0}},
-    {ungrant,    CommandCodes[UNGRANT],    STATE_NO_ERROR, P_GRANT,    {KEY_SIZE, KEY_SIZE, 0}},
-    {getmtime,   CommandCodes[GETMTIME],   STATE_ANY,      P_SAW,      {KEY_SIZE, 0, 0}},
-    {NULL,       0,                        STATE_ANY,      0,          {0, 0, 0}},
-};
-
-static struct user {
-    uid_t uid;
-    uid_t euid;
-    uint32_t perms;
-} users[] = {
-    {AID_SYSTEM,  (uid_t)(~0), (uint32_t)(~0)},
-    {AID_VPN,     AID_SYSTEM,  P_GET | P_SIGN | P_VERIFY },
-    {AID_WIFI,    AID_SYSTEM,  P_GET | P_SIGN | P_VERIFY },
-    {AID_ROOT,    AID_SYSTEM,  P_GET},
-    {(uid_t)(~0), (uid_t)(~0), P_TEST | P_GET | P_INSERT | P_DELETE | P_EXIST | P_SAW |
-                               P_SIGN | P_VERIFY},
-};
-
-static ResponseCode process(KeyStore* keyStore, int sock, uid_t uid, int8_t code) {
-    struct user* user = users;
-    struct action* action = actions;
-    int i;
-
-    while (~user->uid && user->uid != (uid % AID_USER)) {
-        ++user;
-    }
-    while (action->code && action->code != code) {
-        ++action;
-    }
-    if (!action->code) {
-        return UNDEFINED_ACTION;
-    }
-    if (!(action->perm & user->perms)) {
-        return PERMISSION_DENIED;
-    }
-    if (action->state != STATE_ANY && action->state != keyStore->getState()) {
-        return (ResponseCode) keyStore->getState();
-    }
-    if (~user->euid) {
-        uid = user->euid;
-    }
-    Value params[MAX_PARAM];
-    for (i = 0; i < MAX_PARAM && action->lengths[i] != 0; ++i) {
-        params[i].length = recv_message(sock, params[i].value, action->lengths[i]);
-        if (params[i].length < 0) {
-            return PROTOCOL_ERROR;
+        rc = device->verify_data(device, &params, keyBlob.getValue(), keyBlob.getLength(),
+                data, dataLength, signature, signatureLength);
+        if (rc) {
+            return ::SYSTEM_ERROR;
+        } else {
+            return ::NO_ERROR;
         }
     }
-    if (!recv_end_of_file(sock)) {
-        return PROTOCOL_ERROR;
+
+    /*
+     * TODO: The abstraction between things stored in hardware and regular blobs
+     * of data stored on the filesystem should be moved down to keystore itself.
+     * Unfortunately the Java code that calls this has naming conventions that it
+     * knows about. Ideally keystore shouldn't be used to store random blobs of
+     * data.
+     *
+     * Until that happens, it's necessary to have a separate "get_pubkey" and
+     * "del_key" since the Java code doesn't really communicate what it's
+     * intentions are.
+     */
+    int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_GET)) {
+            ALOGW("permission denied for %d: get_pubkey", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
+
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling get_pubkey in state: %d", state);
+            return state;
+        }
+
+        Blob keyBlob;
+        String8 name8(name);
+
+        ALOGV("get_pubkey '%s' from uid %d", name8.string(), uid);
+
+        ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, uid,
+                TYPE_KEY_PAIR);
+        if (responseCode != ::NO_ERROR) {
+            return responseCode;
+        }
+
+        const keymaster_device_t* device = mKeyStore->getDevice();
+        if (device == NULL) {
+            return ::SYSTEM_ERROR;
+        }
+
+        if (device->get_keypair_public == NULL) {
+            ALOGE("device has no get_keypair_public implementation!");
+            return ::SYSTEM_ERROR;
+        }
+
+        int rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), pubkey,
+                pubkeyLength);
+        if (rc) {
+            return ::SYSTEM_ERROR;
+        }
+
+        return ::NO_ERROR;
     }
-    return action->run(keyStore, sock, uid, &params[0], &params[1], &params[2]);
-}
+
+    int32_t del_key(const String16& name) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_DELETE)) {
+            ALOGW("permission denied for %d: del_key", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
+
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        encode_key_for_uid(filename, uid, name8);
+
+        Blob keyBlob;
+        ResponseCode responseCode = mKeyStore->get(filename, &keyBlob, ::TYPE_KEY_PAIR);
+        if (responseCode != ::NO_ERROR) {
+            return responseCode;
+        }
+
+        ResponseCode rc = ::NO_ERROR;
+
+        const keymaster_device_t* device = mKeyStore->getDevice();
+        if (device == NULL) {
+            rc = ::SYSTEM_ERROR;
+        } else {
+            // A device doesn't have to implement delete_keypair.
+            if (device->delete_keypair != NULL) {
+                if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
+                    rc = ::SYSTEM_ERROR;
+                }
+            }
+        }
+
+        if (rc != ::NO_ERROR) {
+            return rc;
+        }
+
+        return (unlink(filename) && errno != ENOENT) ? ::SYSTEM_ERROR : ::NO_ERROR;
+    }
+
+    int32_t grant(const String16& name, int32_t granteeUid) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_GRANT)) {
+            ALOGW("permission denied for %d: grant", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
+
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling grant in state: %d", state);
+            return state;
+        }
+
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        encode_key_for_uid(filename, uid, name8);
+
+        if (access(filename, R_OK) == -1) {
+            return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+        }
+
+        mKeyStore->addGrant(filename, granteeUid);
+        return ::NO_ERROR;
+    }
+
+    int32_t ungrant(const String16& name, int32_t granteeUid) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_GRANT)) {
+            ALOGW("permission denied for %d: ungrant", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
+
+        State state = checkState();
+        if (state != STATE_NO_ERROR) {
+            ALOGD("calling ungrant in state: %d", state);
+            return state;
+        }
+
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        encode_key_for_uid(filename, uid, name8);
+
+        if (access(filename, R_OK) == -1) {
+            return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+        }
+
+        return mKeyStore->removeGrant(filename, granteeUid) ? ::NO_ERROR : ::KEY_NOT_FOUND;
+    }
+
+    int64_t getmtime(const String16& name) {
+        uid_t uid = IPCThreadState::self()->getCallingUid();
+        if (!has_permission(uid, P_GET)) {
+            ALOGW("permission denied for %d: getmtime", uid);
+            return ::PERMISSION_DENIED;
+        }
+        uid = get_keystore_euid(uid);
+
+        String8 name8(name);
+        char filename[NAME_MAX];
+
+        encode_key_for_uid(filename, uid, name8);
+
+        if (access(filename, R_OK) == -1) {
+            return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+        }
+
+        int fd = open(filename, O_NOFOLLOW, O_RDONLY);
+        if (fd < 0) {
+            return ::SYSTEM_ERROR;
+        }
+
+        struct stat s;
+        int ret = fstat(fd, &s);
+        close(fd);
+        if (ret == -1) {
+            return ::SYSTEM_ERROR;
+        }
+
+        return s.st_mtime;
+    }
+
+private:
+    inline State checkState() {
+        return mKeyStore->getState();
+    }
+
+    ::KeyStore* mKeyStore;
+};
+
+}; // namespace android
 
 int main(int argc, char* argv[]) {
-    int controlSocket = android_get_control_socket("keystore");
     if (argc < 2) {
         ALOGE("A directory must be specified!");
         return 1;
@@ -1430,48 +1604,21 @@
         return 1;
     }
 
-    if (listen(controlSocket, 3) == -1) {
-        ALOGE("listen: %s", strerror(errno));
-        return 1;
-    }
-
-    signal(SIGPIPE, SIG_IGN);
-
     KeyStore keyStore(&entropy, dev);
-    int sock;
-    while ((sock = accept(controlSocket, NULL, 0)) != -1) {
-        struct timeval tv;
-        tv.tv_sec = 3;
-        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
-        setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
-
-        struct ucred cred;
-        socklen_t size = sizeof(cred);
-        int credResult = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &size);
-        if (credResult != 0) {
-            ALOGW("getsockopt: %s", strerror(errno));
-        } else {
-            int8_t request;
-            if (recv_code(sock, &request)) {
-                State old_state = keyStore.getState();
-                ResponseCode response = process(&keyStore, sock, cred.uid, request);
-                if (response == NO_ERROR_RESPONSE_CODE_SENT) {
-                    response = NO_ERROR;
-                } else {
-                    send_code(sock, response);
-                }
-                ALOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d",
-                     cred.uid,
-                     request, response,
-                     old_state, keyStore.getState(),
-                     keyStore.getRetry());
-            }
-        }
-        close(sock);
+    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);
+    if (ret != android::OK) {
+        ALOGE("Couldn't register binder service!");
+        return -1;
     }
-    ALOGE("accept: %s", strerror(errno));
+
+    /*
+     * We're the only thread in existence, so we're just going to process
+     * Binder transaction as a single-threaded program.
+     */
+    android::IPCThreadState::self()->joinThreadPool();
 
     keymaster_device_release(dev);
-
     return 1;
 }
diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp
index dcd3bcb..01da2c0 100644
--- a/keystore/keystore_cli.cpp
+++ b/keystore/keystore_cli.cpp
@@ -18,11 +18,14 @@
 #include <stdint.h>
 #include <string.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 
-#include <cutils/sockets.h>
+#include <keystore/IKeystoreService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
 
-#include "keystore.h"
+#include <keystore/keystore.h>
+
+using namespace android;
 
 static const char* responses[] = {
     NULL,
@@ -41,55 +44,158 @@
     /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)",
 };
 
+#define NO_ARG_INT_RETURN(cmd) \
+    do { \
+        if (strcmp(argv[1], #cmd) == 0) { \
+            int32_t ret = service->cmd(); \
+            if (ret < 0) { \
+                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
+                return 1; \
+            } else { \
+                printf(#cmd ": %s (%d)\n", responses[ret], ret); \
+                return 0; \
+            } \
+        } \
+    } while (0)
+
+#define SINGLE_ARG_INT_RETURN(cmd) \
+    do { \
+        if (strcmp(argv[1], #cmd) == 0) { \
+            if (argc < 3) { \
+                fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
+                return 1; \
+            } \
+            int32_t ret = service->cmd(String16(argv[2])); \
+            if (ret < 0) { \
+                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
+                return 1; \
+            } else { \
+                printf(#cmd ": %s (%d)\n", responses[ret], ret); \
+                return 0; \
+            } \
+        } \
+    } while (0)
+
+#define STING_ARG_DATA_STDIN_INT_RETURN(cmd) \
+    do { \
+        if (strcmp(argv[1], #cmd) == 0) { \
+            if (argc < 3) { \
+                fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
+                return 1; \
+            } \
+            uint8_t* data; \
+            size_t dataSize; \
+            read_input(&data, &dataSize); \
+            int32_t ret = service->cmd(String16(argv[2]), data, dataSize); \
+            if (ret < 0) { \
+                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
+                return 1; \
+            } else { \
+                printf(#cmd ": %s (%d)\n", responses[ret], ret); \
+                return 0; \
+            } \
+        } \
+    } while (0)
+
+#define SINGLE_ARG_DATA_RETURN(cmd) \
+    do { \
+        if (strcmp(argv[1], #cmd) == 0) { \
+            if (argc < 3) { \
+                fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
+                return 1; \
+            } \
+            uint8_t* data; \
+            size_t dataSize; \
+            int32_t ret = service->cmd(String16(argv[2]), &data, &dataSize); \
+            if (ret < 0) { \
+                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
+                return 1; \
+            } else if (ret != ::NO_ERROR) { \
+                fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \
+                return 1; \
+            } else { \
+                fwrite(data, dataSize, 1, stdout); \
+                fflush(stdout); \
+                free(data); \
+                return 0; \
+            } \
+        } \
+    } while (0)
+
+static int saw(sp<IKeystoreService> service, const String16& name) {
+    Vector<String16> matches;
+    int32_t ret = service->saw(name, &matches);
+    if (ret < 0) {
+        fprintf(stderr, "saw: could not connect: %d\n", ret);
+        return 1;
+    } else if (ret != ::NO_ERROR) {
+        fprintf(stderr, "saw: %s (%d)\n", responses[ret], ret);
+        return 1;
+    } else {
+        Vector<String16>::const_iterator it = matches.begin();
+        for (; it != matches.end(); ++it) {
+            printf("%s\n", String8(*it).string());
+        }
+        return 0;
+    }
+}
+
 int main(int argc, char* argv[])
 {
     if (argc < 2) {
-        printf("Usage: %s action [parameter ...]\n", argv[0]);
-        return 0;
-    }
-
-    int sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                   SOCK_STREAM);
-    if (sock == -1) {
-        puts("Failed to connect");
+        fprintf(stderr, "Usage: %s action [parameter ...]\n", argv[0]);
         return 1;
     }
 
-    send(sock, argv[1], 1, 0);
-    uint8_t bytes[65536];
-    for (int i = 2; i < argc; ++i) {
-        uint16_t length = strlen(argv[i]);
-        bytes[0] = length >> 8;
-        bytes[1] = length;
-        send(sock, &bytes, 2, 0);
-        send(sock, argv[i], length, 0);
-    }
-    shutdown(sock, SHUT_WR);
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+    sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
 
-    uint8_t code;
-    if (recv(sock, &code, 1, 0) != 1) {
-        puts("Failed to receive");
+    if (service == NULL) {
+        fprintf(stderr, "%s: error: could not connect to keystore service\n", argv[0]);
         return 1;
     }
-    printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown");
-    int i;
-    while ((i = recv(sock, &bytes[0], 1, 0)) == 1) {
-        int length;
-        int offset;
-        if ((i = recv(sock, &bytes[1], 1, 0)) != 1) {
-            puts("Failed to receive");
-            return 1;
-        }
-        length = bytes[0] << 8 | bytes[1];
-        for (offset = 0; offset < length; offset += i) {
-            i = recv(sock, &bytes[offset], length - offset, 0);
-            if (i <= 0) {
-                puts("Failed to receive");
-                return 1;
-            }
-        }
-        fwrite(bytes, 1, length, stdout);
-        puts("");
+
+    /*
+     * All the commands should return a value
+     */
+
+    NO_ARG_INT_RETURN(test);
+
+    SINGLE_ARG_DATA_RETURN(get);
+
+    // TODO: insert
+
+    SINGLE_ARG_INT_RETURN(del);
+
+    SINGLE_ARG_INT_RETURN(exist);
+
+    if (strcmp(argv[1], "saw") == 0) {
+        return saw(service, argc < 3 ? String16("") : String16(argv[2]));
     }
-    return 0;
+
+    NO_ARG_INT_RETURN(reset);
+
+    SINGLE_ARG_INT_RETURN(password);
+
+    NO_ARG_INT_RETURN(lock);
+
+    SINGLE_ARG_INT_RETURN(unlock);
+
+    NO_ARG_INT_RETURN(zero);
+
+    SINGLE_ARG_INT_RETURN(generate);
+
+    SINGLE_ARG_DATA_RETURN(get_pubkey);
+
+    SINGLE_ARG_INT_RETURN(del_key);
+
+    // TODO: grant
+
+    // TODO: ungrant
+
+    // TODO: getmtime
+
+    fprintf(stderr, "%s: unknown command: %s\n", argv[0], argv[1]);
+    return 1;
 }
diff --git a/keystore/keystore_client.cpp b/keystore/keystore_client.cpp
deleted file mode 100644
index a3a51ec..0000000
--- a/keystore/keystore_client.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <keystore.h>
-#include <keystore_client.h>
-
-#include <cutils/sockets.h>
-
-#define LOG_TAG "keystore_client"
-#include <cutils/log.h>
-
-ResponseCode keystore_cmd(command_code_t cmd, Keystore_Reply* reply, int numArgs, ...) {
-    int sock;
-
-    sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
-    if (sock == -1) {
-        return SYSTEM_ERROR;
-    }
-
-    if (TEMP_FAILURE_RETRY(send(sock, &cmd, 1, MSG_NOSIGNAL)) != 1) {
-        close(sock);
-        return SYSTEM_ERROR;
-    }
-
-    va_list vl;
-    va_start(vl, numArgs);
-    for (int i = 0; i < numArgs; i++) {
-        size_t argLen = va_arg(vl, size_t);
-        uint8_t* arg = va_arg(vl, uint8_t*);
-
-        if (argLen > KEYSTORE_MESSAGE_SIZE) {
-            ALOGE("code called us with an argLen out of bounds: %llu", (unsigned long long) argLen);
-            close(sock);
-            return SYSTEM_ERROR;
-        }
-
-        uint8_t bytes[2] = { (uint8_t)(argLen >> 8), (uint8_t)argLen };
-        if (TEMP_FAILURE_RETRY(send(sock, bytes, 2, MSG_NOSIGNAL)) != 2
-                || TEMP_FAILURE_RETRY(send(sock, arg, argLen, MSG_NOSIGNAL))
-                        != static_cast<ssize_t>(argLen)) {
-            ALOGW("truncated write to keystore");
-            close(sock);
-            return SYSTEM_ERROR;
-        }
-    }
-    va_end(vl);
-
-    uint8_t code = 0;
-    if (shutdown(sock, SHUT_WR) != 0
-            || TEMP_FAILURE_RETRY(recv(sock, &code, 1, 0)) != 1
-            || code != NO_ERROR) {
-        ALOGW("Error from keystore: %d", code);
-        close(sock);
-        return SYSTEM_ERROR;
-    }
-
-    if (reply != NULL) {
-        reply->setCode(static_cast<ResponseCode>(code));
-
-        uint8_t bytes[2];
-        uint8_t* data = reply->get();
-        if (TEMP_FAILURE_RETRY(recv(sock, &bytes[0], 1, 0)) == 1
-                && TEMP_FAILURE_RETRY(recv(sock, &bytes[1], 1, 0)) == 1) {
-            int offset = 0;
-            int length = bytes[0] << 8 | bytes[1];
-            while (offset < length) {
-                int n = TEMP_FAILURE_RETRY(recv(sock, &data[offset], length - offset, 0));
-                if (n <= 0) {
-                    ALOGW("truncated read from keystore for data");
-                    code = SYSTEM_ERROR;
-                    break;
-                }
-                offset += n;
-            }
-            reply->setLength(length);
-        } else {
-            ALOGW("truncated read from keystore for length");
-            code = SYSTEM_ERROR;
-        }
-    }
-
-    close(sock);
-    return static_cast<ResponseCode>(code);
-}
-
-Keystore_Reply::Keystore_Reply()
-        : mCode(SYSTEM_ERROR)
-        , mLength(-1) {
-    mData = new uint8_t[KEYSTORE_MESSAGE_SIZE];
-}
-
-Keystore_Reply::~Keystore_Reply() {
-    delete[] mData;
-}
-
-uint8_t* Keystore_Reply::get() {
-    return mData;
-}
-
-void Keystore_Reply::setLength(size_t length) {
-    mLength = length;
-}
-
-size_t Keystore_Reply::length() const {
-    return mLength;
-}
-
-void Keystore_Reply::setCode(ResponseCode code) {
-    mCode = code;
-}
-
-ResponseCode Keystore_Reply::code() const {
-    return mCode;
-}
-
-uint8_t* Keystore_Reply::release() {
-    uint8_t* data = mData;
-    mData = NULL;
-    return data;
-}
diff --git a/keystore/keystore_client.h b/keystore/keystore_client.h
deleted file mode 100644
index 7ea6bb8..0000000
--- a/keystore/keystore_client.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __KEYSTORE_CLIENT_H__
-#define __KEYSTORE_CLIENT_H__
-
-#include <keystore.h>
-
-#define KEYSTORE_MESSAGE_SIZE 65535
-
-
-class Keystore_Reply {
-public:
-    Keystore_Reply();
-    ~Keystore_Reply();
-
-    uint8_t* get();
-    void setLength(size_t length);
-    size_t length() const;
-    void setCode(ResponseCode code);
-    ResponseCode code() const;
-    uint8_t* release();
-
-private:
-    ResponseCode mCode;
-    uint8_t* mData;
-    size_t mLength;
-};
-
-
-/**
- * This sends a command to the keystore. The arguments must be of the format:
- *
- * size_t length, const uint8_t* data, [size_t length, const uint8_t* data, [...]]
- */
-ResponseCode keystore_cmd(command_code_t cmd, Keystore_Reply* reply, int numArgs, ...);
-
-#endif /* __KEYSTORE_CLIENT_H__ */
diff --git a/keystore/keystore_get.cpp b/keystore/keystore_get.cpp
new file mode 100644
index 0000000..45ad415
--- /dev/null
+++ b/keystore/keystore_get.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keystore/IKeystoreService.h>
+#include <binder/IServiceManager.h>
+
+#include <keystore/keystore_get.h>
+
+using namespace android;
+
+ssize_t keystore_get(const char *key, size_t keyLength, uint8_t** value) {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+    sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+
+    if (service == NULL) {
+        return -1;
+    }
+
+    size_t valueLength;
+    int32_t ret = service->get(String16(key, keyLength), value, &valueLength);
+    if (ret < 0) {
+        return -1;
+    } else if (ret != ::NO_ERROR) {
+        return -1;
+    } else {
+        return valueLength;
+    }
+}
diff --git a/keystore/keystore_get.h b/keystore/keystore_get.h
deleted file mode 100644
index 4b4923e..0000000
--- a/keystore/keystore_get.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __KEYSTORE_GET_H__
-#define __KEYSTORE_GET_H__
-
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <cutils/sockets.h>
-
-#define KEYSTORE_MESSAGE_SIZE 65535
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This function is provided for native components to get values from keystore.
- * Users are required to link against libcutils. Keys and values are 8-bit safe.
- * The first two arguments are the key and its length. The third argument
- * specifies the buffer to store the retrieved value, which must be an array of
- * KEYSTORE_MESSAGE_SIZE bytes. This function returns the length of the value or
- * -1 if an error happens. */
-static int keystore_get(const char *key, int length, char *value)
-{
-    uint8_t bytes[2] = {length >> 8, length};
-    uint8_t code = 'g';
-    int sock;
-
-    if (length < 0 || length > KEYSTORE_MESSAGE_SIZE) {
-        return -1;
-    }
-    sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
-                               SOCK_STREAM);
-    if (sock == -1) {
-        return -1;
-    }
-    if (send(sock, &code, 1, 0) == 1 && send(sock, bytes, 2, 0) == 2 &&
-        send(sock, key, length, 0) == length && shutdown(sock, SHUT_WR) == 0 &&
-        recv(sock, &code, 1, 0) == 1 && code == /* NO_ERROR */ 1 &&
-        recv(sock, &bytes[0], 1, 0) == 1 && recv(sock, &bytes[1], 1, 0) == 1) {
-        int offset = 0;
-        length = bytes[0] << 8 | bytes[1];
-        while (offset < length) {
-            int n = recv(sock, &value[offset], length - offset, 0);
-            if (n <= 0) {
-                length = -1;
-                break;
-            }
-            offset += n;
-        }
-    } else {
-        length = -1;
-    }
-
-    close(sock);
-    return length;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/softkeymaster/Android.mk b/softkeymaster/Android.mk
index 8623c2e..63c2ba1 100644
--- a/softkeymaster/Android.mk
+++ b/softkeymaster/Android.mk
@@ -28,7 +28,7 @@
 
 LOCAL_C_FLAGS = -fvisibility=hidden -Wall -Werror
 
-LOCAL_SHARED_LIBRARIES := libcrypto liblog libkeystore_client
+LOCAL_SHARED_LIBRARIES := libcrypto liblog libkeystore_binder
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/softkeymaster/keymaster_openssl.cpp b/softkeymaster/keymaster_openssl.cpp
index 5a7327b..3620450 100644
--- a/softkeymaster/keymaster_openssl.cpp
+++ b/softkeymaster/keymaster_openssl.cpp
@@ -17,7 +17,7 @@
 #include <string.h>
 #include <stdint.h>
 
-#include <keystore.h>
+#include <keystore/keystore.h>
 
 #include <hardware/hardware.h>
 #include <hardware/keymaster.h>