1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.net; 6 7 import org.chromium.base.Log; 8 import org.chromium.base.annotations.CalledByNative; 9 import org.chromium.base.annotations.JNINamespace; 10 11 import java.security.InvalidKeyException; 12 import java.security.NoSuchAlgorithmException; 13 import java.security.PrivateKey; 14 import java.security.Signature; 15 16 import javax.crypto.Cipher; 17 import javax.crypto.NoSuchPaddingException; 18 19 /** 20 * Specifies all the dependencies from the native OpenSSL engine on an Android KeyStore. 21 */ 22 @JNINamespace("net::android") 23 public class AndroidKeyStore { 24 private static final String TAG = "AndroidKeyStore"; 25 26 @CalledByNative getPrivateKeyClassName(PrivateKey privateKey)27 private static String getPrivateKeyClassName(PrivateKey privateKey) { 28 return privateKey.getClass().getName(); 29 } 30 31 /** 32 * Check if a given PrivateKey object supports a signature algorithm. 33 * 34 * @param privateKey The PrivateKey handle. 35 * @param algorithm The signature algorithm to use. 36 * @return whether the algorithm is supported. 37 */ 38 @CalledByNative privateKeySupportsSignature(PrivateKey privateKey, String algorithm)39 private static boolean privateKeySupportsSignature(PrivateKey privateKey, String algorithm) { 40 try { 41 Signature signature = Signature.getInstance(algorithm); 42 signature.initSign(privateKey); 43 } catch (NoSuchAlgorithmException | InvalidKeyException e) { 44 return false; 45 } catch (Exception e) { 46 Log.e(TAG, "Exception while checking support for " + algorithm + ": " + e); 47 return false; 48 } 49 return true; 50 } 51 52 /** 53 * Check if a given PrivateKey object supports an encryption algorithm. 54 * 55 * @param privateKey The PrivateKey handle. 56 * @param algorithm The signature algorithm to use. 57 * @return whether the algorithm is supported. 58 */ 59 @CalledByNative privateKeySupportsCipher(PrivateKey privateKey, String algorithm)60 private static boolean privateKeySupportsCipher(PrivateKey privateKey, String algorithm) { 61 try { 62 Cipher cipher = Cipher.getInstance(algorithm); 63 cipher.init(Cipher.ENCRYPT_MODE, privateKey); 64 } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) { 65 return false; 66 } catch (Exception e) { 67 Log.e(TAG, "Exception while checking support for " + algorithm + ": " + e); 68 return false; 69 } 70 return true; 71 } 72 73 /** 74 * Sign a given message with a given PrivateKey object. 75 * 76 * @param privateKey The PrivateKey handle. 77 * @param algorithm The signature algorithm to use. 78 * @param message The message to sign. 79 * @return signature as a byte buffer. 80 * 81 * Note: NONEwithRSA is not implemented in Android < 4.2. See 82 * getOpenSSLHandleForPrivateKey() below for a work-around. 83 */ 84 @CalledByNative signWithPrivateKey( PrivateKey privateKey, String algorithm, byte[] message)85 private static byte[] signWithPrivateKey( 86 PrivateKey privateKey, String algorithm, byte[] message) { 87 // Hint: Algorithm names come from: 88 // http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html 89 Signature signature = null; 90 try { 91 signature = Signature.getInstance(algorithm); 92 } catch (NoSuchAlgorithmException e) { 93 Log.e(TAG, "Signature algorithm " + algorithm + " not supported: " + e); 94 return null; 95 } 96 97 try { 98 signature.initSign(privateKey); 99 signature.update(message); 100 return signature.sign(); 101 } catch (Exception e) { 102 Log.e(TAG, 103 "Exception while signing message with " + algorithm + " and " 104 + privateKey.getAlgorithm() + " private key (" 105 + privateKey.getClass().getName() + "): " + e); 106 return null; 107 } 108 } 109 110 /** 111 * Encrypts a given input with a given PrivateKey object. 112 * 113 * @param privateKey The PrivateKey handle. 114 * @param algorithm The cipher to use. 115 * @param input The input to encrypt. 116 * @return ciphertext as a byte buffer. 117 * 118 * Note: NONEwithRSA is not implemented in Android < 4.2. See 119 * getOpenSSLHandleForPrivateKey() below for a work-around. 120 */ 121 @CalledByNative encryptWithPrivateKey( PrivateKey privateKey, String algorithm, byte[] message)122 private static byte[] encryptWithPrivateKey( 123 PrivateKey privateKey, String algorithm, byte[] message) { 124 Cipher cipher = null; 125 try { 126 cipher = Cipher.getInstance(algorithm); 127 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 128 Log.e(TAG, "Cipher " + algorithm + " not supported: " + e); 129 return null; 130 } 131 132 try { 133 cipher.init(Cipher.ENCRYPT_MODE, privateKey); 134 return cipher.doFinal(message); 135 } catch (Exception e) { 136 Log.e(TAG, 137 "Exception while encrypting input with " + algorithm + " and " 138 + privateKey.getAlgorithm() + " private key (" 139 + privateKey.getClass().getName() + "): " + e); 140 return null; 141 } 142 } 143 } 144