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