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