18da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor/* 28da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * Copyright (C) 2010 The Android Open Source Project 38da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * 48da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * Licensed under the Apache License, Version 2.0 (the "License"); 58da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * you may not use this file except in compliance with the License. 68da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * You may obtain a copy of the License at 78da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * 88da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * http://www.apache.org/licenses/LICENSE-2.0 98da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * 108da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * Unless required by applicable law or agreed to in writing, software 118da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * distributed under the License is distributed on an "AS IS" BASIS, 128da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * See the License for the specific language governing permissions and 148da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor * limitations under the License. 158da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor */ 168da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 178da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorpackage android.security; 188da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 198da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport android.os.Environment; 201ff8fee7c8e4fcd4ef12c6c5d1055b7eccf5809bOscar Montemayorimport android.os.FileUtils; 218da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport android.os.Process; 228da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 238da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport java.io.File; 248da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport java.io.FileInputStream; 258da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport java.io.FileOutputStream; 268da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport java.io.IOException; 278da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport java.security.NoSuchAlgorithmException; 288da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport java.security.SecureRandom; 298da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 308da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport javax.crypto.KeyGenerator; 318da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorimport javax.crypto.SecretKey; 328da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 33460c26e9875833dc494575b5c43f08c8baa15f34Elliott Hughesimport libcore.io.IoUtils; 34460c26e9875833dc494575b5c43f08c8baa15f34Elliott Hughes 358da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor/** 368da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor *@hide 378da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor */ 388da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayorpublic class SystemKeyStore { 398da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 408da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor private static final String SYSTEM_KEYSTORE_DIRECTORY = "misc/systemkeys"; 41b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor private static final String KEY_FILE_EXTENSION = ".sks"; 428da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor private static SystemKeyStore mInstance = new SystemKeyStore(); 438da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 448da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor private SystemKeyStore() { } 458da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 468da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor public static SystemKeyStore getInstance() { 478da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor return mInstance; 488da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 498da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 50b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor public static String toHexString(byte[] keyData) { 51b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor if (keyData == null) { 52b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor return null; 53b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor } 54b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor int keyLen = keyData.length; 55b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor int expectedStringLen = keyData.length * 2; 56b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor StringBuilder sb = new StringBuilder(expectedStringLen); 57b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor for (int i = 0; i < keyData.length; i++) { 58b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor String hexStr = Integer.toString(keyData[i] & 0x00FF, 16); 59b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor if (hexStr.length() == 1) { 60b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor hexStr = "0" + hexStr; 61b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor } 62b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor sb.append(hexStr); 63b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor } 64b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor return sb.toString(); 65b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor } 66b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor 67b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor public String generateNewKeyHexString(int numBits, String algName, String keyName) 68b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor throws NoSuchAlgorithmException { 69b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor return toHexString(generateNewKey(numBits, algName, keyName)); 70b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor } 71b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor 728da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor public byte[] generateNewKey(int numBits, String algName, String keyName) 738da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor throws NoSuchAlgorithmException { 748da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 758da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor // Check if key with similar name exists. If so, return null. 768da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor File keyFile = getKeyFile(keyName); 778da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor if (keyFile.exists()) { 788da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor throw new IllegalArgumentException(); 798da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 808da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 818da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor KeyGenerator skg = KeyGenerator.getInstance(algName); 828da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor SecureRandom srng = SecureRandom.getInstance("SHA1PRNG"); 838da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor skg.init(numBits, srng); 848da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 858da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor SecretKey sk = skg.generateKey(); 868da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor byte[] retKey = sk.getEncoded(); 878da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 888da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor try { 898da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor // Store the key 908da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor if (!keyFile.createNewFile()) { 918da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor throw new IllegalArgumentException(); 928da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 938da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 948da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor FileOutputStream fos = new FileOutputStream(keyFile); 958da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor fos.write(retKey); 968da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor fos.flush(); 978bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn FileUtils.sync(fos); 988da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor fos.close(); 991ff8fee7c8e4fcd4ef12c6c5d1055b7eccf5809bOscar Montemayor FileUtils.setPermissions(keyFile.getName(), (FileUtils.S_IRUSR | FileUtils.S_IWUSR), 1001ff8fee7c8e4fcd4ef12c6c5d1055b7eccf5809bOscar Montemayor -1, -1); 1018da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } catch (IOException ioe) { 1028da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor return null; 1038da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 1048da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor return retKey; 1058da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 1068da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 1078da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor private File getKeyFile(String keyName) { 1088da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor File sysKeystoreDir = new File(Environment.getDataDirectory(), 1098da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor SYSTEM_KEYSTORE_DIRECTORY); 110b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor File keyFile = new File(sysKeystoreDir, keyName + KEY_FILE_EXTENSION); 1118da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor return keyFile; 1128da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 1138da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 1148d578836dc4f9fb41532b8b3dd7a6b168d6f4f9dRich Cannings public String retrieveKeyHexString(String keyName) throws IOException { 115b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor return toHexString(retrieveKey(keyName)); 116b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor } 117b62e8132df0d19a39a700324475b3df2de78e0b0Oscar Montemayor 1188d578836dc4f9fb41532b8b3dd7a6b168d6f4f9dRich Cannings public byte[] retrieveKey(String keyName) throws IOException { 1198da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor File keyFile = getKeyFile(keyName); 1208da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor if (!keyFile.exists()) { 1218da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor return null; 1228da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 123460c26e9875833dc494575b5c43f08c8baa15f34Elliott Hughes return IoUtils.readFileAsByteArray(keyFile.toString()); 1248da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 1258da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 1268da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor public void deleteKey(String keyName) { 1278da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 1288da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor // Get the file first. 1298da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor File keyFile = getKeyFile(keyName); 1308da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor if (!keyFile.exists()) { 1318da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor throw new IllegalArgumentException(); 1328da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 1338da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor 1348da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor keyFile.delete(); 1358da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor } 1368da98e30d8b2ae6e203f769dab0d6ec34cab3011Oscar Montemayor} 137