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