Change KeyStore to use Modified UTF-8 to match NativeCrypto

Bug: http://code.google.com/p/android/issues/detail?id=35141
Bug: 6869713

Change-Id: I61cb309786960072148ef97ea5afedb33dc45f4e
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index a32e469..f49c429 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -22,8 +22,9 @@
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
+import java.io.UTFDataFormatException;
 import java.nio.charset.Charsets;
+import java.nio.charset.ModifiedUtf8;
 import java.util.ArrayList;
 
 /**
@@ -75,7 +76,7 @@
     }
 
     public byte[] get(String key) {
-        return get(getBytes(key));
+        return get(getKeyBytes(key));
     }
 
     private boolean put(byte[] key, byte[] value) {
@@ -84,7 +85,7 @@
     }
 
     public boolean put(String key, byte[] value) {
-        return put(getBytes(key), value);
+        return put(getKeyBytes(key), value);
     }
 
     private boolean delete(byte[] key) {
@@ -93,7 +94,7 @@
     }
 
     public boolean delete(String key) {
-        return delete(getBytes(key));
+        return delete(getKeyBytes(key));
     }
 
     private boolean contains(byte[] key) {
@@ -102,7 +103,7 @@
     }
 
     public boolean contains(String key) {
-        return contains(getBytes(key));
+        return contains(getKeyBytes(key));
     }
 
     public byte[][] saw(byte[] prefix) {
@@ -111,13 +112,13 @@
     }
 
     public String[] saw(String prefix) {
-        byte[][] values = saw(getBytes(prefix));
+        byte[][] values = saw(getKeyBytes(prefix));
         if (values == null) {
             return null;
         }
         String[] strings = new String[values.length];
         for (int i = 0; i < values.length; ++i) {
-            strings[i] = toString(values[i]);
+            strings[i] = toKeyString(values[i]);
         }
         return strings;
     }
@@ -133,7 +134,7 @@
     }
 
     public boolean password(String password) {
-        return password(getBytes(password));
+        return password(getPasswordBytes(password));
     }
 
     public boolean lock() {
@@ -147,7 +148,7 @@
     }
 
     public boolean unlock(String password) {
-        return unlock(getBytes(password));
+        return unlock(getPasswordBytes(password));
     }
 
     public boolean isEmpty() {
@@ -161,7 +162,7 @@
     }
 
     public boolean generate(String key) {
-        return generate(getBytes(key));
+        return generate(getKeyBytes(key));
     }
 
     private boolean importKey(byte[] keyName, byte[] key) {
@@ -170,7 +171,7 @@
     }
 
     public boolean importKey(String keyName, byte[] key) {
-        return importKey(getBytes(keyName), key);
+        return importKey(getKeyBytes(keyName), key);
     }
 
     private byte[] getPubkey(byte[] key) {
@@ -179,7 +180,7 @@
     }
 
     public byte[] getPubkey(String key) {
-        return getPubkey(getBytes(key));
+        return getPubkey(getKeyBytes(key));
     }
 
     private boolean delKey(byte[] key) {
@@ -188,7 +189,7 @@
     }
 
     public boolean delKey(String key) {
-        return delKey(getBytes(key));
+        return delKey(getKeyBytes(key));
     }
 
     private byte[] sign(byte[] keyName, byte[] data) {
@@ -197,7 +198,7 @@
     }
 
     public byte[] sign(String key, byte[] data) {
-        return sign(getBytes(key), data);
+        return sign(getKeyBytes(key), data);
     }
 
     private boolean verify(byte[] keyName, byte[] data, byte[] signature) {
@@ -206,7 +207,7 @@
     }
 
     public boolean verify(String key, byte[] data, byte[] signature) {
-        return verify(getBytes(key), data, signature);
+        return verify(getKeyBytes(key), data, signature);
     }
 
     private boolean grant(byte[] key, byte[] uid) {
@@ -215,7 +216,7 @@
     }
 
     public boolean grant(String key, int uid) {
-        return grant(getBytes(key), Integer.toString(uid).getBytes());
+         return grant(getKeyBytes(key), getUidBytes(uid));
     }
 
     private boolean ungrant(byte[] key, byte[] uid) {
@@ -224,7 +225,7 @@
     }
 
     public boolean ungrant(String key, int uid) {
-        return ungrant(getBytes(key), Integer.toString(uid).getBytes());
+        return ungrant(getKeyBytes(key), getUidBytes(uid));
     }
 
     public int getLastError() {
@@ -291,11 +292,34 @@
         return null;
     }
 
-    private static byte[] getBytes(String string) {
-        return string.getBytes(Charsets.UTF_8);
+    /**
+     * ModifiedUtf8 is used for key encoding to match the
+     * implementation of NativeCrypto.ENGINE_load_private_key.
+     */
+    private static byte[] getKeyBytes(String string) {
+        try {
+            int utfCount = (int) ModifiedUtf8.countBytes(string, false);
+            byte[] result = new byte[utfCount];
+            ModifiedUtf8.encode(result, 0, string);
+            return result;
+        } catch (UTFDataFormatException e) {
+            throw new RuntimeException(e);
+        }
     }
 
-    private static String toString(byte[] bytes) {
-        return new String(bytes, Charsets.UTF_8);
+    private static String toKeyString(byte[] bytes) {
+        try {
+            return ModifiedUtf8.decode(bytes, new char[bytes.length], 0, bytes.length);
+        } catch (UTFDataFormatException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static byte[] getPasswordBytes(String password) {
+        return password.getBytes(Charsets.UTF_8);
+    }
+
+    private static byte[] getUidBytes(int uid) {
+        return Integer.toString(uid).getBytes(Charsets.UTF_8);
     }
 }
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 91c56d6..32cd6e2 100755
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -37,7 +37,7 @@
     private static final String TEST_PASSWD2 = "87654321";
     private static final String TEST_KEYNAME = "test-key";
     private static final String TEST_KEYNAME1 = "test-key.1";
-    private static final String TEST_KEYNAME2 = "test-key.2";
+    private static final String TEST_KEYNAME2 = "test-key\02";
     private static final byte[] TEST_KEYVALUE = "test value".getBytes(Charsets.UTF_8);
 
     // "Hello, World" in Chinese