blob: 9058cae3b0daa31f338e5f116275de2d53f47d29 [file] [log] [blame]
Chia-chi Yeh44039172009-09-21 11:53:59 +08001/*
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;
Nick Kralevich34c47c82010-03-09 13:28:14 -080025import java.io.UnsupportedEncodingException;
Brian Carlstrom46703b02011-04-06 15:41:29 -070026import java.nio.charset.Charsets;
Chia-chi Yeh44039172009-09-21 11:53:59 +080027import java.util.ArrayList;
28
29/**
Brian Carlstrom46703b02011-04-06 15:41:29 -070030 * @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.
Chia-chi Yeh44039172009-09-21 11:53:59 +080033 */
34public class KeyStore {
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070035
36 // ResponseCodes
Brian Carlstrom7e4b1a42011-06-01 15:29:29 -070037 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;
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070047
48 // States
49 public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
Chia-chi Yeh44039172009-09-21 11:53:59 +080050
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
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070062 public State state() {
Chia-chi Yeh44039172009-09-21 11:53:59 +080063 execute('t');
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070064 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 }
Chia-chi Yeh44039172009-09-21 11:53:59 +080070 }
71
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070072 private byte[] get(byte[] key) {
Chia-chi Yehd12feb92010-02-06 10:43:22 +080073 ArrayList<byte[]> values = execute('g', key);
Nick Kralevich34c47c82010-03-09 13:28:14 -080074 return (values == null || values.isEmpty()) ? null : values.get(0);
Chia-chi Yeh44039172009-09-21 11:53:59 +080075 }
76
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070077 public byte[] get(String key) {
78 return get(getBytes(key));
Chia-chi Yeh44039172009-09-21 11:53:59 +080079 }
80
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070081 private boolean put(byte[] key, byte[] value) {
Chia-chi Yeh44039172009-09-21 11:53:59 +080082 execute('i', key, value);
83 return mError == NO_ERROR;
84 }
85
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070086 public boolean put(String key, byte[] value) {
87 return put(getBytes(key), value);
Chia-chi Yeh44039172009-09-21 11:53:59 +080088 }
89
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070090 private boolean delete(byte[] key) {
Chia-chi Yeh44039172009-09-21 11:53:59 +080091 execute('d', key);
92 return mError == NO_ERROR;
93 }
94
95 public boolean delete(String key) {
Nick Kralevich34c47c82010-03-09 13:28:14 -080096 return delete(getBytes(key));
Chia-chi Yeh44039172009-09-21 11:53:59 +080097 }
98
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -070099 private boolean contains(byte[] key) {
Chia-chi Yeh44039172009-09-21 11:53:59 +0800100 execute('e', key);
101 return mError == NO_ERROR;
102 }
103
104 public boolean contains(String key) {
Nick Kralevich34c47c82010-03-09 13:28:14 -0800105 return contains(getBytes(key));
Chia-chi Yeh44039172009-09-21 11:53:59 +0800106 }
107
Chia-chi Yeh613fcc82009-09-22 03:04:46 +0800108 public byte[][] saw(byte[] prefix) {
Chia-chi Yehd12feb92010-02-06 10:43:22 +0800109 ArrayList<byte[]> values = execute('s', prefix);
110 return (values == null) ? null : values.toArray(new byte[values.size()][]);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800111 }
112
Chia-chi Yeh613fcc82009-09-22 03:04:46 +0800113 public String[] saw(String prefix) {
Nick Kralevich34c47c82010-03-09 13:28:14 -0800114 byte[][] values = saw(getBytes(prefix));
Chia-chi Yeh44039172009-09-21 11:53:59 +0800115 if (values == null) {
116 return null;
117 }
118 String[] strings = new String[values.length];
119 for (int i = 0; i < values.length; ++i) {
Nick Kralevich34c47c82010-03-09 13:28:14 -0800120 strings[i] = toString(values[i]);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800121 }
122 return strings;
123 }
124
125 public boolean reset() {
126 execute('r');
127 return mError == NO_ERROR;
128 }
129
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700130 private boolean password(byte[] password) {
131 execute('p', password);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800132 return mError == NO_ERROR;
133 }
134
Chia-chi Yeh44039172009-09-21 11:53:59 +0800135 public boolean password(String password) {
Nick Kralevich34c47c82010-03-09 13:28:14 -0800136 return password(getBytes(password));
Chia-chi Yeh44039172009-09-21 11:53:59 +0800137 }
138
139 public boolean lock() {
140 execute('l');
141 return mError == NO_ERROR;
142 }
143
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700144 private boolean unlock(byte[] password) {
Chia-chi Yeh44039172009-09-21 11:53:59 +0800145 execute('u', password);
146 return mError == NO_ERROR;
147 }
148
149 public boolean unlock(String password) {
Nick Kralevich34c47c82010-03-09 13:28:14 -0800150 return unlock(getBytes(password));
Chia-chi Yeh44039172009-09-21 11:53:59 +0800151 }
152
Brian Carlstrom5cfee3f2011-05-31 01:00:15 -0700153 public boolean isEmpty() {
154 execute('z');
155 return mError == KEY_NOT_FOUND;
156 }
157
Chia-chi Yeh44039172009-09-21 11:53:59 +0800158 public int getLastError() {
159 return mError;
160 }
161
Chia-chi Yehd12feb92010-02-06 10:43:22 +0800162 private ArrayList<byte[]> execute(int code, byte[]... parameters) {
Chia-chi Yeh44039172009-09-21 11:53:59 +0800163 mError = PROTOCOL_ERROR;
164
165 for (byte[] parameter : parameters) {
166 if (parameter == null || parameter.length > 65535) {
167 return null;
168 }
169 }
170
171 LocalSocket socket = new LocalSocket();
172 try {
173 socket.connect(sAddress);
174
175 OutputStream out = socket.getOutputStream();
176 out.write(code);
177 for (byte[] parameter : parameters) {
178 out.write(parameter.length >> 8);
179 out.write(parameter.length);
180 out.write(parameter);
181 }
182 out.flush();
183 socket.shutdownOutput();
184
185 InputStream in = socket.getInputStream();
Chia-chi Yehf1ece5d2009-09-24 13:29:58 +0800186 if ((code = in.read()) != NO_ERROR) {
187 if (code != -1) {
188 mError = code;
189 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800190 return null;
191 }
192
Chia-chi Yehd12feb92010-02-06 10:43:22 +0800193 ArrayList<byte[]> values = new ArrayList<byte[]>();
Chia-chi Yeh44039172009-09-21 11:53:59 +0800194 while (true) {
195 int i, j;
196 if ((i = in.read()) == -1) {
197 break;
198 }
199 if ((j = in.read()) == -1) {
200 return null;
201 }
Chia-chi Yehd12feb92010-02-06 10:43:22 +0800202 byte[] value = new byte[i << 8 | j];
203 for (i = 0; i < value.length; i += j) {
204 if ((j = in.read(value, i, value.length - i)) == -1) {
Chia-chi Yeh44039172009-09-21 11:53:59 +0800205 return null;
206 }
207 }
Chia-chi Yehd12feb92010-02-06 10:43:22 +0800208 values.add(value);
Chia-chi Yeh44039172009-09-21 11:53:59 +0800209 }
Chia-chi Yehf1ece5d2009-09-24 13:29:58 +0800210 mError = NO_ERROR;
Chia-chi Yehd12feb92010-02-06 10:43:22 +0800211 return values;
Chia-chi Yeh44039172009-09-21 11:53:59 +0800212 } catch (IOException e) {
213 // ignore
214 } finally {
215 try {
216 socket.close();
217 } catch (IOException e) {}
218 }
219 return null;
220 }
Nick Kralevich34c47c82010-03-09 13:28:14 -0800221
222 private static byte[] getBytes(String string) {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700223 return string.getBytes(Charsets.UTF_8);
Nick Kralevich34c47c82010-03-09 13:28:14 -0800224 }
225
226 private static String toString(byte[] bytes) {
Brian Carlstrom46703b02011-04-06 15:41:29 -0700227 return new String(bytes, Charsets.UTF_8);
Nick Kralevich34c47c82010-03-09 13:28:14 -0800228 }
Chia-chi Yeh44039172009-09-21 11:53:59 +0800229}