KeyStore.java revision 34c47c855815d731e6deb55748ff690b0ec7b53f
144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh/*
244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * Copyright (C) 2009 The Android Open Source Project
344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh *
444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * you may not use this file except in compliance with the License.
644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * You may obtain a copy of the License at
744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh *
844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh *
1044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
1144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
1244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * See the License for the specific language governing permissions and
1444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * limitations under the License.
1544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh */
1644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1744039172627d1c15737ea73836ad375559d76211Chia-chi Yehpackage android.security;
1844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1944039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport android.net.LocalSocketAddress;
2044039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport android.net.LocalSocket;
2144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
2244039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.io.InputStream;
2344039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.io.IOException;
2444039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.io.OutputStream;
2534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevichimport java.io.UnsupportedEncodingException;
2644039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.util.ArrayList;
2744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
2844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh/**
2944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh * {@hide}
3044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh */
3144039172627d1c15737ea73836ad375559d76211Chia-chi Yehpublic class KeyStore {
32d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int NO_ERROR = 1;
33d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int LOCKED = 2;
34d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int UNINITIALIZED = 3;
35d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int SYSTEM_ERROR = 4;
36d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int PROTOCOL_ERROR = 5;
37d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int PERMISSION_DENIED = 6;
38d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int KEY_NOT_FOUND = 7;
39d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int VALUE_CORRUPTED = 8;
40d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int UNDEFINED_ACTION = 9;
41d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    public static final int WRONG_PASSWORD = 10;
4244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
4344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private static final LocalSocketAddress sAddress = new LocalSocketAddress(
4444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            "keystore", LocalSocketAddress.Namespace.RESERVED);
4544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
4644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private int mError = NO_ERROR;
4744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
4844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private KeyStore() {}
4944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public static KeyStore getInstance() {
5144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return new KeyStore();
5244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
5344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public int test() {
5544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('t');
5644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError;
5744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
5844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public byte[] get(byte[] key) {
60d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        ArrayList<byte[]> values = execute('g', key);
6134c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return (values == null || values.isEmpty()) ? null : values.get(0);
6244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
6344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
6444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public String get(String key) {
6534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        byte[] value = get(getBytes(key));
6634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return (value == null) ? null : toString(value);
6744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
6844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
6944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean put(byte[] key, byte[] value) {
7044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('i', key, value);
7144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
7244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
7344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
7444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean put(String key, String value) {
7534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return put(getBytes(key), getBytes(value));
7644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
7744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
7844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean delete(byte[] key) {
7944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('d', key);
8044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
8144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
8244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
8344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean delete(String key) {
8434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return delete(getBytes(key));
8544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
8644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
8744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean contains(byte[] key) {
8844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('e', key);
8944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
9044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
9144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
9244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean contains(String key) {
9334c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return contains(getBytes(key));
9444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
9544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
96613fcc850686dfe71cec9809c3694be9cf02cdc7Chia-chi Yeh    public byte[][] saw(byte[] prefix) {
97d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        ArrayList<byte[]> values = execute('s', prefix);
98d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        return (values == null) ? null : values.toArray(new byte[values.size()][]);
9944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
10044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
101613fcc850686dfe71cec9809c3694be9cf02cdc7Chia-chi Yeh    public String[] saw(String prefix) {
10234c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        byte[][] values = saw(getBytes(prefix));
10344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        if (values == null) {
10444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            return null;
10544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
10644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        String[] strings = new String[values.length];
10744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        for (int i = 0; i < values.length; ++i) {
10834c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            strings[i] = toString(values[i]);
10944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
11044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return strings;
11144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
11244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
11344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean reset() {
11444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('r');
11544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
11644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
11744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
11844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean password(byte[] oldPassword, byte[] newPassword) {
11944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('p', oldPassword, newPassword);
12044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
12144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
12244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
12344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean password(String oldPassword, String newPassword) {
12434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return password(getBytes(oldPassword), getBytes(newPassword));
12544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
12644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
12744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean password(byte[] password) {
12844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return password(password, password);
12944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
13044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
13144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean password(String password) {
13234c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return password(getBytes(password));
13344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
13444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
13544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean lock() {
13644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('l');
13744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
13844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
13944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
14044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean unlock(byte[] password) {
14144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('u', password);
14244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
14344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
14444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
14544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean unlock(String password) {
14634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return unlock(getBytes(password));
14744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
14844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
14944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public int getLastError() {
15044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError;
15144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
15244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
153d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    private ArrayList<byte[]> execute(int code, byte[]... parameters) {
15444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        mError = PROTOCOL_ERROR;
15544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
15644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        for (byte[] parameter : parameters) {
15744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            if (parameter == null || parameter.length > 65535) {
15844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                return null;
15944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
16044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
16144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
16244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        LocalSocket socket = new LocalSocket();
16344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        try {
16444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            socket.connect(sAddress);
16544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
16644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            OutputStream out = socket.getOutputStream();
16744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            out.write(code);
16844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            for (byte[] parameter : parameters) {
16944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter.length >> 8);
17044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter.length);
17144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter);
17244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
17344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            out.flush();
17444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            socket.shutdownOutput();
17544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
17644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            InputStream in = socket.getInputStream();
177f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh            if ((code = in.read()) != NO_ERROR) {
178f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                if (code != -1) {
179f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                    mError = code;
180f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                }
18144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                return null;
18244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
18344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
184d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh            ArrayList<byte[]> values = new ArrayList<byte[]>();
18544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            while (true) {
18644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                int i, j;
18744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                if ((i = in.read()) == -1) {
18844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    break;
18944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
19044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                if ((j = in.read()) == -1) {
19144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    return null;
19244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
193d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                byte[] value = new byte[i << 8 | j];
194d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                for (i = 0; i < value.length; i += j) {
195d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                    if ((j = in.read(value, i, value.length - i)) == -1) {
19644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                        return null;
19744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    }
19844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
199d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                values.add(value);
20044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
201f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh            mError = NO_ERROR;
202d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh            return values;
20344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        } catch (IOException e) {
20444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            // ignore
20544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        } finally {
20644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            try {
20744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                socket.close();
20844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            } catch (IOException e) {}
20944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
21044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return null;
21144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
21234c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich
21334c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    private static byte[] getBytes(String string) {
21434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        try {
21534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            return string.getBytes("UTF-8");
21634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        } catch (UnsupportedEncodingException e) {
21734c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            // will never happen
21834c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            throw new RuntimeException(e);
21934c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        }
22034c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    }
22134c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich
22234c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    private static String toString(byte[] bytes) {
22334c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        try {
22434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            return new String(bytes, "UTF-8");
22534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        } catch (UnsupportedEncodingException e) {
22634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            // will never happen
22734c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            throw new RuntimeException(e);
22834c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        }
22934c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    }
23044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh}
231