KeyStore.java revision 5423e68d5dbe048ec6f042cce52a33f94184e9fb
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.nio.charset.Charsets; 27import java.util.ArrayList; 28 29/** 30 * @hide This should not be made public in its present form because it 31 * assumes that private and secret key bytes are available and would 32 * preclude the use of hardware crypto. 33 */ 34public class KeyStore { 35 36 // ResponseCodes 37 public static final int NO_ERROR = 1; 38 public static final int LOCKED = 2; 39 public static final int UNINITIALIZED = 3; 40 public static final int SYSTEM_ERROR = 4; 41 public static final int PROTOCOL_ERROR = 5; 42 public static final int PERMISSION_DENIED = 6; 43 public static final int KEY_NOT_FOUND = 7; 44 public static final int VALUE_CORRUPTED = 8; 45 public static final int UNDEFINED_ACTION = 9; 46 public static final int WRONG_PASSWORD = 10; 47 48 // States 49 public enum State { UNLOCKED, LOCKED, UNINITIALIZED }; 50 51 private static final LocalSocketAddress sAddress = new LocalSocketAddress( 52 "keystore", LocalSocketAddress.Namespace.RESERVED); 53 54 private int mError = NO_ERROR; 55 56 private KeyStore() {} 57 58 public static KeyStore getInstance() { 59 return new KeyStore(); 60 } 61 62 public State state() { 63 execute('t'); 64 switch (mError) { 65 case NO_ERROR: return State.UNLOCKED; 66 case LOCKED: return State.LOCKED; 67 case UNINITIALIZED: return State.UNINITIALIZED; 68 default: throw new AssertionError(mError); 69 } 70 } 71 72 private byte[] get(byte[] key) { 73 ArrayList<byte[]> values = execute('g', key); 74 return (values == null || values.isEmpty()) ? null : values.get(0); 75 } 76 77 public byte[] get(String key) { 78 return get(getBytes(key)); 79 } 80 81 private boolean put(byte[] key, byte[] value) { 82 execute('i', key, value); 83 return mError == NO_ERROR; 84 } 85 86 public boolean put(String key, byte[] value) { 87 return put(getBytes(key), value); 88 } 89 90 private boolean delete(byte[] key) { 91 execute('d', key); 92 return mError == NO_ERROR; 93 } 94 95 public boolean delete(String key) { 96 return delete(getBytes(key)); 97 } 98 99 private boolean contains(byte[] key) { 100 execute('e', key); 101 return mError == NO_ERROR; 102 } 103 104 public boolean contains(String key) { 105 return contains(getBytes(key)); 106 } 107 108 public byte[][] saw(byte[] prefix) { 109 ArrayList<byte[]> values = execute('s', prefix); 110 return (values == null) ? null : values.toArray(new byte[values.size()][]); 111 } 112 113 public String[] saw(String prefix) { 114 byte[][] values = saw(getBytes(prefix)); 115 if (values == null) { 116 return null; 117 } 118 String[] strings = new String[values.length]; 119 for (int i = 0; i < values.length; ++i) { 120 strings[i] = toString(values[i]); 121 } 122 return strings; 123 } 124 125 public boolean reset() { 126 execute('r'); 127 return mError == NO_ERROR; 128 } 129 130 private boolean password(byte[] password) { 131 execute('p', password); 132 return mError == NO_ERROR; 133 } 134 135 public boolean password(String password) { 136 return password(getBytes(password)); 137 } 138 139 public boolean lock() { 140 execute('l'); 141 return mError == NO_ERROR; 142 } 143 144 private boolean unlock(byte[] password) { 145 execute('u', password); 146 return mError == NO_ERROR; 147 } 148 149 public boolean unlock(String password) { 150 return unlock(getBytes(password)); 151 } 152 153 public boolean isEmpty() { 154 execute('z'); 155 return mError == KEY_NOT_FOUND; 156 } 157 158 private boolean generate(byte[] key) { 159 execute('a', key); 160 return mError == NO_ERROR; 161 } 162 163 public boolean generate(String key) { 164 return generate(getBytes(key)); 165 } 166 167 private boolean importKey(byte[] keyName, byte[] key) { 168 execute('m', keyName, key); 169 return mError == NO_ERROR; 170 } 171 172 public boolean importKey(String keyName, byte[] key) { 173 return importKey(getBytes(keyName), key); 174 } 175 176 private byte[] getPubkey(byte[] key) { 177 ArrayList<byte[]> values = execute('b', key); 178 return (values == null || values.isEmpty()) ? null : values.get(0); 179 } 180 181 public byte[] getPubkey(String key) { 182 return getPubkey(getBytes(key)); 183 } 184 185 private boolean delKey(byte[] key) { 186 execute('k', key); 187 return mError == NO_ERROR; 188 } 189 190 public boolean delKey(String key) { 191 return delKey(getBytes(key)); 192 } 193 194 private byte[] sign(byte[] keyName, byte[] data) { 195 final ArrayList<byte[]> values = execute('n', keyName, data); 196 return (values == null || values.isEmpty()) ? null : values.get(0); 197 } 198 199 public byte[] sign(String key, byte[] data) { 200 return sign(getBytes(key), data); 201 } 202 203 private boolean verify(byte[] keyName, byte[] data, byte[] signature) { 204 execute('v', keyName, data, signature); 205 return mError == NO_ERROR; 206 } 207 208 public boolean verify(String key, byte[] data, byte[] signature) { 209 return verify(getBytes(key), data, signature); 210 } 211 212 private boolean grant(byte[] key, byte[] uid) { 213 execute('x', key, uid); 214 return mError == NO_ERROR; 215 } 216 217 public boolean grant(String key, int uid) { 218 return grant(getBytes(key), Integer.toString(uid).getBytes()); 219 } 220 221 private boolean ungrant(byte[] key, byte[] uid) { 222 execute('y', key, uid); 223 return mError == NO_ERROR; 224 } 225 226 public boolean ungrant(String key, int uid) { 227 return ungrant(getBytes(key), Integer.toString(uid).getBytes()); 228 } 229 230 public int getLastError() { 231 return mError; 232 } 233 234 private ArrayList<byte[]> execute(int code, byte[]... parameters) { 235 mError = PROTOCOL_ERROR; 236 237 for (byte[] parameter : parameters) { 238 if (parameter == null || parameter.length > 65535) { 239 return null; 240 } 241 } 242 243 LocalSocket socket = new LocalSocket(); 244 try { 245 socket.connect(sAddress); 246 247 OutputStream out = socket.getOutputStream(); 248 out.write(code); 249 for (byte[] parameter : parameters) { 250 out.write(parameter.length >> 8); 251 out.write(parameter.length); 252 out.write(parameter); 253 } 254 out.flush(); 255 socket.shutdownOutput(); 256 257 InputStream in = socket.getInputStream(); 258 if ((code = in.read()) != NO_ERROR) { 259 if (code != -1) { 260 mError = code; 261 } 262 return null; 263 } 264 265 ArrayList<byte[]> values = new ArrayList<byte[]>(); 266 while (true) { 267 int i, j; 268 if ((i = in.read()) == -1) { 269 break; 270 } 271 if ((j = in.read()) == -1) { 272 return null; 273 } 274 byte[] value = new byte[i << 8 | j]; 275 for (i = 0; i < value.length; i += j) { 276 if ((j = in.read(value, i, value.length - i)) == -1) { 277 return null; 278 } 279 } 280 values.add(value); 281 } 282 mError = NO_ERROR; 283 return values; 284 } catch (IOException e) { 285 // ignore 286 } finally { 287 try { 288 socket.close(); 289 } catch (IOException e) {} 290 } 291 return null; 292 } 293 294 private static byte[] getBytes(String string) { 295 return string.getBytes(Charsets.UTF_8); 296 } 297 298 private static String toString(byte[] bytes) { 299 return new String(bytes, Charsets.UTF_8); 300 } 301} 302