KeyStore.java revision 46703b099516c383a6882815bcf9cd4df0ec538d
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    public static final int NO_ERROR = 1;
36    public static final int LOCKED = 2;
37    public static final int UNINITIALIZED = 3;
38    public static final int SYSTEM_ERROR = 4;
39    public static final int PROTOCOL_ERROR = 5;
40    public static final int PERMISSION_DENIED = 6;
41    public static final int KEY_NOT_FOUND = 7;
42    public static final int VALUE_CORRUPTED = 8;
43    public static final int UNDEFINED_ACTION = 9;
44    public static final int WRONG_PASSWORD = 10;
45
46    private static final LocalSocketAddress sAddress = new LocalSocketAddress(
47            "keystore", LocalSocketAddress.Namespace.RESERVED);
48
49    private int mError = NO_ERROR;
50
51    private KeyStore() {}
52
53    public static KeyStore getInstance() {
54        return new KeyStore();
55    }
56
57    public int test() {
58        execute('t');
59        return mError;
60    }
61
62    public byte[] get(byte[] key) {
63        ArrayList<byte[]> values = execute('g', key);
64        return (values == null || values.isEmpty()) ? null : values.get(0);
65    }
66
67    public String get(String key) {
68        byte[] value = get(getBytes(key));
69        return (value == null) ? null : toString(value);
70    }
71
72    public boolean put(byte[] key, byte[] value) {
73        execute('i', key, value);
74        return mError == NO_ERROR;
75    }
76
77    public boolean put(String key, String value) {
78        return put(getBytes(key), getBytes(value));
79    }
80
81    public boolean delete(byte[] key) {
82        execute('d', key);
83        return mError == NO_ERROR;
84    }
85
86    public boolean delete(String key) {
87        return delete(getBytes(key));
88    }
89
90    public boolean contains(byte[] key) {
91        execute('e', key);
92        return mError == NO_ERROR;
93    }
94
95    public boolean contains(String key) {
96        return contains(getBytes(key));
97    }
98
99    public byte[][] saw(byte[] prefix) {
100        ArrayList<byte[]> values = execute('s', prefix);
101        return (values == null) ? null : values.toArray(new byte[values.size()][]);
102    }
103
104    public String[] saw(String prefix) {
105        byte[][] values = saw(getBytes(prefix));
106        if (values == null) {
107            return null;
108        }
109        String[] strings = new String[values.length];
110        for (int i = 0; i < values.length; ++i) {
111            strings[i] = toString(values[i]);
112        }
113        return strings;
114    }
115
116    public boolean reset() {
117        execute('r');
118        return mError == NO_ERROR;
119    }
120
121    public boolean password(byte[] oldPassword, byte[] newPassword) {
122        execute('p', oldPassword, newPassword);
123        return mError == NO_ERROR;
124    }
125
126    public boolean password(String oldPassword, String newPassword) {
127        return password(getBytes(oldPassword), getBytes(newPassword));
128    }
129
130    public boolean password(byte[] password) {
131        return password(password, password);
132    }
133
134    public boolean password(String password) {
135        return password(getBytes(password));
136    }
137
138    public boolean lock() {
139        execute('l');
140        return mError == NO_ERROR;
141    }
142
143    public boolean unlock(byte[] password) {
144        execute('u', password);
145        return mError == NO_ERROR;
146    }
147
148    public boolean unlock(String password) {
149        return unlock(getBytes(password));
150    }
151
152    public int getLastError() {
153        return mError;
154    }
155
156    private ArrayList<byte[]> execute(int code, byte[]... parameters) {
157        mError = PROTOCOL_ERROR;
158
159        for (byte[] parameter : parameters) {
160            if (parameter == null || parameter.length > 65535) {
161                return null;
162            }
163        }
164
165        LocalSocket socket = new LocalSocket();
166        try {
167            socket.connect(sAddress);
168
169            OutputStream out = socket.getOutputStream();
170            out.write(code);
171            for (byte[] parameter : parameters) {
172                out.write(parameter.length >> 8);
173                out.write(parameter.length);
174                out.write(parameter);
175            }
176            out.flush();
177            socket.shutdownOutput();
178
179            InputStream in = socket.getInputStream();
180            if ((code = in.read()) != NO_ERROR) {
181                if (code != -1) {
182                    mError = code;
183                }
184                return null;
185            }
186
187            ArrayList<byte[]> values = new ArrayList<byte[]>();
188            while (true) {
189                int i, j;
190                if ((i = in.read()) == -1) {
191                    break;
192                }
193                if ((j = in.read()) == -1) {
194                    return null;
195                }
196                byte[] value = new byte[i << 8 | j];
197                for (i = 0; i < value.length; i += j) {
198                    if ((j = in.read(value, i, value.length - i)) == -1) {
199                        return null;
200                    }
201                }
202                values.add(value);
203            }
204            mError = NO_ERROR;
205            return values;
206        } catch (IOException e) {
207            // ignore
208        } finally {
209            try {
210                socket.close();
211            } catch (IOException e) {}
212        }
213        return null;
214    }
215
216    private static byte[] getBytes(String string) {
217        return string.getBytes(Charsets.UTF_8);
218    }
219
220    private static String toString(byte[] bytes) {
221        return new String(bytes, Charsets.UTF_8);
222    }
223}
224