KeyStore.java revision 7e4b1a488dd02c4bf6156379e36834e9e01c5b1b
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;
2646703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstromimport java.nio.charset.Charsets;
2744039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.util.ArrayList;
2844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
2944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh/**
3046703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * @hide This should not be made public in its present form because it
3146703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * assumes that private and secret key bytes are available and would
3246703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * preclude the use of hardware crypto.
3344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh */
3444039172627d1c15737ea73836ad375559d76211Chia-chi Yehpublic class KeyStore {
355cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom
365cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    // ResponseCodes
377e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int NO_ERROR = 1;
387e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int LOCKED = 2;
397e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int UNINITIALIZED = 3;
407e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int SYSTEM_ERROR = 4;
417e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int PROTOCOL_ERROR = 5;
427e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int PERMISSION_DENIED = 6;
437e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int KEY_NOT_FOUND = 7;
447e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int VALUE_CORRUPTED = 8;
457e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int UNDEFINED_ACTION = 9;
467e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom    public static final int WRONG_PASSWORD = 10;
475cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom
485cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    // States
495cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
5044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private static final LocalSocketAddress sAddress = new LocalSocketAddress(
5244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            "keystore", LocalSocketAddress.Namespace.RESERVED);
5344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private int mError = NO_ERROR;
5544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    private KeyStore() {}
5744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
5844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public static KeyStore getInstance() {
5944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return new KeyStore();
6044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
6144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
625cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public State state() {
6344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('t');
645cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        switch (mError) {
655cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom            case NO_ERROR: return State.UNLOCKED;
665cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom            case LOCKED: return State.LOCKED;
675cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom            case UNINITIALIZED: return State.UNINITIALIZED;
685cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom            default: throw new AssertionError(mError);
695cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        }
7044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
7144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
725cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private byte[] get(byte[] key) {
73d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        ArrayList<byte[]> values = execute('g', key);
7434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return (values == null || values.isEmpty()) ? null : values.get(0);
7544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
7644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
775cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public byte[] get(String key) {
785cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        return get(getBytes(key));
7944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
8044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
815cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean put(byte[] key, byte[] value) {
8244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('i', key, value);
8344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
8444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
8544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
865cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public boolean put(String key, byte[] value) {
875cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        return put(getBytes(key), value);
8844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
8944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
905cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean delete(byte[] key) {
9144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('d', key);
9244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
9344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
9444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
9544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean delete(String key) {
9634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return delete(getBytes(key));
9744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
9844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
995cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean contains(byte[] key) {
10044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('e', key);
10144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
10244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
10344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
10444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean contains(String key) {
10534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return contains(getBytes(key));
10644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
10744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
108613fcc850686dfe71cec9809c3694be9cf02cdc7Chia-chi Yeh    public byte[][] saw(byte[] prefix) {
109d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        ArrayList<byte[]> values = execute('s', prefix);
110d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh        return (values == null) ? null : values.toArray(new byte[values.size()][]);
11144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
11244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
113613fcc850686dfe71cec9809c3694be9cf02cdc7Chia-chi Yeh    public String[] saw(String prefix) {
11434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        byte[][] values = saw(getBytes(prefix));
11544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        if (values == null) {
11644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            return null;
11744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
11844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        String[] strings = new String[values.length];
11944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        for (int i = 0; i < values.length; ++i) {
12034c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich            strings[i] = toString(values[i]);
12144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
12244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return strings;
12344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
12444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
12544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean reset() {
12644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('r');
12744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
12844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
12944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1305cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean password(byte[] password) {
1315cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        execute('p', password);
13244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
13344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
13444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
13544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean password(String password) {
13634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return password(getBytes(password));
13744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
13844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
13944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean lock() {
14044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('l');
14144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
14244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
14344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1445cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    private boolean unlock(byte[] password) {
14544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        execute('u', password);
14644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError == NO_ERROR;
14744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
14844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
14944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public boolean unlock(String password) {
15034c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich        return unlock(getBytes(password));
15144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
15244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
1535cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    public boolean isEmpty() {
1545cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        execute('z');
1555cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom        return mError == KEY_NOT_FOUND;
1565cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom    }
1575cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom
15844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    public int getLastError() {
15944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return mError;
16044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
16144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
162d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh    private ArrayList<byte[]> execute(int code, byte[]... parameters) {
16344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        mError = PROTOCOL_ERROR;
16444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
16544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        for (byte[] parameter : parameters) {
16644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            if (parameter == null || parameter.length > 65535) {
16744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                return null;
16844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
16944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
17044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
17144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        LocalSocket socket = new LocalSocket();
17244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        try {
17344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            socket.connect(sAddress);
17444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
17544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            OutputStream out = socket.getOutputStream();
17644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            out.write(code);
17744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            for (byte[] parameter : parameters) {
17844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter.length >> 8);
17944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter.length);
18044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                out.write(parameter);
18144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
18244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            out.flush();
18344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            socket.shutdownOutput();
18444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
18544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            InputStream in = socket.getInputStream();
186f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh            if ((code = in.read()) != NO_ERROR) {
187f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                if (code != -1) {
188f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                    mError = code;
189f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh                }
19044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                return null;
19144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
19244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh
193d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh            ArrayList<byte[]> values = new ArrayList<byte[]>();
19444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            while (true) {
19544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                int i, j;
19644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                if ((i = in.read()) == -1) {
19744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    break;
19844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
19944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                if ((j = in.read()) == -1) {
20044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    return null;
20144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
202d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                byte[] value = new byte[i << 8 | j];
203d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                for (i = 0; i < value.length; i += j) {
204d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                    if ((j = in.read(value, i, value.length - i)) == -1) {
20544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                        return null;
20644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                    }
20744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                }
208d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh                values.add(value);
20944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            }
210f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh            mError = NO_ERROR;
211d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh            return values;
21244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        } catch (IOException e) {
21344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            // ignore
21444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        } finally {
21544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            try {
21644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh                socket.close();
21744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh            } catch (IOException e) {}
21844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        }
21944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh        return null;
22044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh    }
22134c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich
22234c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    private static byte[] getBytes(String string) {
22346703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        return string.getBytes(Charsets.UTF_8);
22434c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    }
22534c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich
22634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    private static String toString(byte[] bytes) {
22746703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        return new String(bytes, Charsets.UTF_8);
22834c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich    }
22944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh}
230