1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.security; 18 19import android.net.LocalSocketAddress; 20import android.net.LocalSocket; 21 22import java.io.InputStream; 23import java.io.IOException; 24import java.io.OutputStream; 25import java.io.UnsupportedEncodingException; 26import java.util.ArrayList; 27 28/** 29 * {@hide} 30 */ 31public class KeyStore { 32 public static final int NO_ERROR = 1; 33 public static final int LOCKED = 2; 34 public static final int UNINITIALIZED = 3; 35 public static final int SYSTEM_ERROR = 4; 36 public static final int PROTOCOL_ERROR = 5; 37 public static final int PERMISSION_DENIED = 6; 38 public static final int KEY_NOT_FOUND = 7; 39 public static final int VALUE_CORRUPTED = 8; 40 public static final int UNDEFINED_ACTION = 9; 41 public static final int WRONG_PASSWORD = 10; 42 43 private static final LocalSocketAddress sAddress = new LocalSocketAddress( 44 "keystore", LocalSocketAddress.Namespace.RESERVED); 45 46 private int mError = NO_ERROR; 47 48 private KeyStore() {} 49 50 public static KeyStore getInstance() { 51 return new KeyStore(); 52 } 53 54 public int test() { 55 execute('t'); 56 return mError; 57 } 58 59 public byte[] get(byte[] key) { 60 ArrayList<byte[]> values = execute('g', key); 61 return (values == null || values.isEmpty()) ? null : values.get(0); 62 } 63 64 public String get(String key) { 65 byte[] value = get(getBytes(key)); 66 return (value == null) ? null : toString(value); 67 } 68 69 public boolean put(byte[] key, byte[] value) { 70 execute('i', key, value); 71 return mError == NO_ERROR; 72 } 73 74 public boolean put(String key, String value) { 75 return put(getBytes(key), getBytes(value)); 76 } 77 78 public boolean delete(byte[] key) { 79 execute('d', key); 80 return mError == NO_ERROR; 81 } 82 83 public boolean delete(String key) { 84 return delete(getBytes(key)); 85 } 86 87 public boolean contains(byte[] key) { 88 execute('e', key); 89 return mError == NO_ERROR; 90 } 91 92 public boolean contains(String key) { 93 return contains(getBytes(key)); 94 } 95 96 public byte[][] saw(byte[] prefix) { 97 ArrayList<byte[]> values = execute('s', prefix); 98 return (values == null) ? null : values.toArray(new byte[values.size()][]); 99 } 100 101 public String[] saw(String prefix) { 102 byte[][] values = saw(getBytes(prefix)); 103 if (values == null) { 104 return null; 105 } 106 String[] strings = new String[values.length]; 107 for (int i = 0; i < values.length; ++i) { 108 strings[i] = toString(values[i]); 109 } 110 return strings; 111 } 112 113 public boolean reset() { 114 execute('r'); 115 return mError == NO_ERROR; 116 } 117 118 public boolean password(byte[] oldPassword, byte[] newPassword) { 119 execute('p', oldPassword, newPassword); 120 return mError == NO_ERROR; 121 } 122 123 public boolean password(String oldPassword, String newPassword) { 124 return password(getBytes(oldPassword), getBytes(newPassword)); 125 } 126 127 public boolean password(byte[] password) { 128 return password(password, password); 129 } 130 131 public boolean password(String password) { 132 return password(getBytes(password)); 133 } 134 135 public boolean lock() { 136 execute('l'); 137 return mError == NO_ERROR; 138 } 139 140 public boolean unlock(byte[] password) { 141 execute('u', password); 142 return mError == NO_ERROR; 143 } 144 145 public boolean unlock(String password) { 146 return unlock(getBytes(password)); 147 } 148 149 public int getLastError() { 150 return mError; 151 } 152 153 private ArrayList<byte[]> execute(int code, byte[]... parameters) { 154 mError = PROTOCOL_ERROR; 155 156 for (byte[] parameter : parameters) { 157 if (parameter == null || parameter.length > 65535) { 158 return null; 159 } 160 } 161 162 LocalSocket socket = new LocalSocket(); 163 try { 164 socket.connect(sAddress); 165 166 OutputStream out = socket.getOutputStream(); 167 out.write(code); 168 for (byte[] parameter : parameters) { 169 out.write(parameter.length >> 8); 170 out.write(parameter.length); 171 out.write(parameter); 172 } 173 out.flush(); 174 socket.shutdownOutput(); 175 176 InputStream in = socket.getInputStream(); 177 if ((code = in.read()) != NO_ERROR) { 178 if (code != -1) { 179 mError = code; 180 } 181 return null; 182 } 183 184 ArrayList<byte[]> values = new ArrayList<byte[]>(); 185 while (true) { 186 int i, j; 187 if ((i = in.read()) == -1) { 188 break; 189 } 190 if ((j = in.read()) == -1) { 191 return null; 192 } 193 byte[] value = new byte[i << 8 | j]; 194 for (i = 0; i < value.length; i += j) { 195 if ((j = in.read(value, i, value.length - i)) == -1) { 196 return null; 197 } 198 } 199 values.add(value); 200 } 201 mError = NO_ERROR; 202 return values; 203 } catch (IOException e) { 204 // ignore 205 } finally { 206 try { 207 socket.close(); 208 } catch (IOException e) {} 209 } 210 return null; 211 } 212 213 private static byte[] getBytes(String string) { 214 try { 215 return string.getBytes("UTF-8"); 216 } catch (UnsupportedEncodingException e) { 217 // will never happen 218 throw new RuntimeException(e); 219 } 220 } 221 222 private static String toString(byte[] bytes) { 223 try { 224 return new String(bytes, "UTF-8"); 225 } catch (UnsupportedEncodingException e) { 226 // will never happen 227 throw new RuntimeException(e); 228 } 229 } 230} 231