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; 255b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstromimport java.io.UTFDataFormatException; 2646703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstromimport java.nio.charset.Charsets; 275b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstromimport java.nio.charset.ModifiedUtf8; 2844039172627d1c15737ea73836ad375559d76211Chia-chi Yehimport java.util.ArrayList; 29473c712b19bad992ab4eafcd43175fdce77b913dKenny Rootimport java.util.Date; 3044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 3144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh/** 3246703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * @hide This should not be made public in its present form because it 3346703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * assumes that private and secret key bytes are available and would 3446703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom * preclude the use of hardware crypto. 3544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh */ 3644039172627d1c15737ea73836ad375559d76211Chia-chi Yehpublic class KeyStore { 375cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom 385cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom // ResponseCodes 397e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int NO_ERROR = 1; 407e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int LOCKED = 2; 417e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int UNINITIALIZED = 3; 427e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int SYSTEM_ERROR = 4; 437e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int PROTOCOL_ERROR = 5; 447e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int PERMISSION_DENIED = 6; 457e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int KEY_NOT_FOUND = 7; 467e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int VALUE_CORRUPTED = 8; 477e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int UNDEFINED_ACTION = 9; 487e4b1a488dd02c4bf6156379e36834e9e01c5b1bBrian Carlstrom public static final int WRONG_PASSWORD = 10; 495cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom 505cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom // States 515cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom public enum State { UNLOCKED, LOCKED, UNINITIALIZED }; 5244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 5344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh private static final LocalSocketAddress sAddress = new LocalSocketAddress( 5444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh "keystore", LocalSocketAddress.Namespace.RESERVED); 5544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 5644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh private int mError = NO_ERROR; 5744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 5844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh private KeyStore() {} 5944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 6044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh public static KeyStore getInstance() { 6144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return new KeyStore(); 6244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 6344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 645cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom public State state() { 6544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh execute('t'); 665cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom switch (mError) { 675cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom case NO_ERROR: return State.UNLOCKED; 685cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom case LOCKED: return State.LOCKED; 695cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom case UNINITIALIZED: return State.UNINITIALIZED; 705cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom default: throw new AssertionError(mError); 715cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom } 7244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 7344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 745cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom private byte[] get(byte[] key) { 75d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh ArrayList<byte[]> values = execute('g', key); 7634c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich return (values == null || values.isEmpty()) ? null : values.get(0); 7744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 7844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 795cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom public byte[] get(String key) { 805b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return get(getKeyBytes(key)); 8144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 8244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 835cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom private boolean put(byte[] key, byte[] value) { 8444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh execute('i', key, value); 8544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return mError == NO_ERROR; 8644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 8744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 885cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom public boolean put(String key, byte[] value) { 895b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return put(getKeyBytes(key), value); 9044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 9144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 925cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom private boolean delete(byte[] key) { 9344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh execute('d', key); 9444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return mError == NO_ERROR; 9544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 9644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 9744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh public boolean delete(String key) { 985b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return delete(getKeyBytes(key)); 9944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 10044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 1015cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom private boolean contains(byte[] key) { 10244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh execute('e', key); 10344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return mError == NO_ERROR; 10444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 10544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 10644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh public boolean contains(String key) { 1075b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return contains(getKeyBytes(key)); 10844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 10944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 110613fcc850686dfe71cec9809c3694be9cf02cdc7Chia-chi Yeh public byte[][] saw(byte[] prefix) { 111d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh ArrayList<byte[]> values = execute('s', prefix); 112d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh return (values == null) ? null : values.toArray(new byte[values.size()][]); 11344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 11444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 115613fcc850686dfe71cec9809c3694be9cf02cdc7Chia-chi Yeh public String[] saw(String prefix) { 1165b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom byte[][] values = saw(getKeyBytes(prefix)); 11744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh if (values == null) { 11844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return null; 11944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 12044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh String[] strings = new String[values.length]; 12144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh for (int i = 0; i < values.length; ++i) { 1225b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom strings[i] = toKeyString(values[i]); 12344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 12444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return strings; 12544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 12644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 12744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh public boolean reset() { 12844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh execute('r'); 12944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return mError == NO_ERROR; 13044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 13144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 1325cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom private boolean password(byte[] password) { 1335cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom execute('p', password); 13444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return mError == NO_ERROR; 13544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 13644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 13744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh public boolean password(String password) { 1385b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return password(getPasswordBytes(password)); 13944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 14044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 14144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh public boolean lock() { 14244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh execute('l'); 14344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return mError == NO_ERROR; 14444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 14544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 1465cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom private boolean unlock(byte[] password) { 14744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh execute('u', password); 14844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return mError == NO_ERROR; 14944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 15044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 15144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh public boolean unlock(String password) { 1525b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return unlock(getPasswordBytes(password)); 15344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 15444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 1555cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom public boolean isEmpty() { 1565cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom execute('z'); 1575cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom return mError == KEY_NOT_FOUND; 1585cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom } 1595cfee3fabb3482c6a6df1c8b6f21e843cf214527Brian Carlstrom 1605423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root private boolean generate(byte[] key) { 1615423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root execute('a', key); 1625423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return mError == NO_ERROR; 1635423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 1645423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 1655423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root public boolean generate(String key) { 1665b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return generate(getKeyBytes(key)); 1675423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 1685423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 1695423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root private boolean importKey(byte[] keyName, byte[] key) { 1705423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root execute('m', keyName, key); 1715423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return mError == NO_ERROR; 1725423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 1735423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 1745423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root public boolean importKey(String keyName, byte[] key) { 1755b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return importKey(getKeyBytes(keyName), key); 1765423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 1775423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 1785423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root private byte[] getPubkey(byte[] key) { 1795423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root ArrayList<byte[]> values = execute('b', key); 1805423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return (values == null || values.isEmpty()) ? null : values.get(0); 1815423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 1825423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 1835423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root public byte[] getPubkey(String key) { 1845b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return getPubkey(getKeyBytes(key)); 1855423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 1865423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 1875423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root private boolean delKey(byte[] key) { 1885423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root execute('k', key); 1895423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return mError == NO_ERROR; 1905423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 1915423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 1925423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root public boolean delKey(String key) { 1935b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return delKey(getKeyBytes(key)); 1945423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 1955423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 1965423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root private byte[] sign(byte[] keyName, byte[] data) { 1975423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root final ArrayList<byte[]> values = execute('n', keyName, data); 1985423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return (values == null || values.isEmpty()) ? null : values.get(0); 1995423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 2005423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 2015423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root public byte[] sign(String key, byte[] data) { 2025b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return sign(getKeyBytes(key), data); 2035423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 2045423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 2055423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root private boolean verify(byte[] keyName, byte[] data, byte[] signature) { 2065423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root execute('v', keyName, data, signature); 2075423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return mError == NO_ERROR; 2085423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 2095423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 2105423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root public boolean verify(String key, byte[] data, byte[] signature) { 2115b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return verify(getKeyBytes(key), data, signature); 2125423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 2135423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 2145423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root private boolean grant(byte[] key, byte[] uid) { 2155423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root execute('x', key, uid); 2165423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return mError == NO_ERROR; 2175423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 2185423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 2195423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root public boolean grant(String key, int uid) { 2205b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return grant(getKeyBytes(key), getUidBytes(uid)); 2215423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 2225423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 2235423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root private boolean ungrant(byte[] key, byte[] uid) { 2245423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root execute('y', key, uid); 2255423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root return mError == NO_ERROR; 2265423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 2275423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 2285423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root public boolean ungrant(String key, int uid) { 2295b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return ungrant(getKeyBytes(key), getUidBytes(uid)); 2305423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root } 2315423e68d5dbe048ec6f042cce52a33f94184e9fbKenny Root 232473c712b19bad992ab4eafcd43175fdce77b913dKenny Root private long getmtime(byte[] key) { 233473c712b19bad992ab4eafcd43175fdce77b913dKenny Root final ArrayList<byte[]> values = execute('c', key); 234473c712b19bad992ab4eafcd43175fdce77b913dKenny Root if (values == null || values.isEmpty()) { 235473c712b19bad992ab4eafcd43175fdce77b913dKenny Root return -1L; 236473c712b19bad992ab4eafcd43175fdce77b913dKenny Root } 237473c712b19bad992ab4eafcd43175fdce77b913dKenny Root 238473c712b19bad992ab4eafcd43175fdce77b913dKenny Root return Long.parseLong(new String(values.get(0))) * 1000L; 239473c712b19bad992ab4eafcd43175fdce77b913dKenny Root } 240473c712b19bad992ab4eafcd43175fdce77b913dKenny Root 241473c712b19bad992ab4eafcd43175fdce77b913dKenny Root /** 242473c712b19bad992ab4eafcd43175fdce77b913dKenny Root * Returns the last modification time of the key in milliseconds since the 243473c712b19bad992ab4eafcd43175fdce77b913dKenny Root * epoch. Will return -1L if the key could not be found or other error. 244473c712b19bad992ab4eafcd43175fdce77b913dKenny Root */ 245473c712b19bad992ab4eafcd43175fdce77b913dKenny Root public long getmtime(String key) { 246473c712b19bad992ab4eafcd43175fdce77b913dKenny Root return getmtime(getKeyBytes(key)); 247473c712b19bad992ab4eafcd43175fdce77b913dKenny Root } 248473c712b19bad992ab4eafcd43175fdce77b913dKenny Root 24944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh public int getLastError() { 25044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return mError; 25144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 25244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 253d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh private ArrayList<byte[]> execute(int code, byte[]... parameters) { 25444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh mError = PROTOCOL_ERROR; 25544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 25644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh for (byte[] parameter : parameters) { 25744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh if (parameter == null || parameter.length > 65535) { 25844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return null; 25944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 26044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 26144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 26244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh LocalSocket socket = new LocalSocket(); 26344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh try { 26444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh socket.connect(sAddress); 26544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 26644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh OutputStream out = socket.getOutputStream(); 26744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh out.write(code); 26844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh for (byte[] parameter : parameters) { 26944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh out.write(parameter.length >> 8); 27044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh out.write(parameter.length); 27144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh out.write(parameter); 27244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 27344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh out.flush(); 27444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh socket.shutdownOutput(); 27544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 27644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh InputStream in = socket.getInputStream(); 277f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh if ((code = in.read()) != NO_ERROR) { 278f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh if (code != -1) { 279f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh mError = code; 280f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh } 28144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return null; 28244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 28344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh 284d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh ArrayList<byte[]> values = new ArrayList<byte[]>(); 28544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh while (true) { 28644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh int i, j; 28744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh if ((i = in.read()) == -1) { 28844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh break; 28944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 29044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh if ((j = in.read()) == -1) { 29144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return null; 29244039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 293d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh byte[] value = new byte[i << 8 | j]; 294d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh for (i = 0; i < value.length; i += j) { 295d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh if ((j = in.read(value, i, value.length - i)) == -1) { 29644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return null; 29744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 29844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 299d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh values.add(value); 30044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 301f1ece5d0c16fa3e79390e41ad9bec020c77d7720Chia-chi Yeh mError = NO_ERROR; 302d12feb97667498378a472c5a7895a9fcd8056ec5Chia-chi Yeh return values; 30344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } catch (IOException e) { 30444039172627d1c15737ea73836ad375559d76211Chia-chi Yeh // ignore 30544039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } finally { 30644039172627d1c15737ea73836ad375559d76211Chia-chi Yeh try { 30744039172627d1c15737ea73836ad375559d76211Chia-chi Yeh socket.close(); 30844039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } catch (IOException e) {} 30944039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 31044039172627d1c15737ea73836ad375559d76211Chia-chi Yeh return null; 31144039172627d1c15737ea73836ad375559d76211Chia-chi Yeh } 31234c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich 3135b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom /** 3145b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom * ModifiedUtf8 is used for key encoding to match the 3155b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom * implementation of NativeCrypto.ENGINE_load_private_key. 3165b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom */ 3175b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom private static byte[] getKeyBytes(String string) { 3185b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom try { 3195b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom int utfCount = (int) ModifiedUtf8.countBytes(string, false); 3205b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom byte[] result = new byte[utfCount]; 3215b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom ModifiedUtf8.encode(result, 0, string); 3225b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return result; 3235b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom } catch (UTFDataFormatException e) { 3245b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom throw new RuntimeException(e); 3255b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom } 3265b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom } 3275b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom 3285b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom private static String toKeyString(byte[] bytes) { 3295b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom try { 3305b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return ModifiedUtf8.decode(bytes, new char[bytes.length], 0, bytes.length); 3315b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom } catch (UTFDataFormatException e) { 3325b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom throw new RuntimeException(e); 3335b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom } 3345b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom } 3355b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom 3365b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom private static byte[] getPasswordBytes(String password) { 3375b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return password.getBytes(Charsets.UTF_8); 33834c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich } 33934c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich 3405b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom private static byte[] getUidBytes(int uid) { 3415b1f037829bff93877a6257db69f4e7723a27e20Brian Carlstrom return Integer.toString(uid).getBytes(Charsets.UTF_8); 34234c47c855815d731e6deb55748ff690b0ec7b53fNick Kralevich } 34344039172627d1c15737ea73836ad375559d76211Chia-chi Yeh} 344