1f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root/* 2f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * Copyright 2014 The Android Open Source Project 3f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * 4f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 5f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * you may not use this file except in compliance with the License. 6f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * You may obtain a copy of the License at 7f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * 8f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * http://www.apache.org/licenses/LICENSE-2.0 9f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * 10f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * Unless required by applicable law or agreed to in writing, software 11f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * distributed under the License is distributed on an "AS IS" BASIS, 12f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * See the License for the specific language governing permissions and 14f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * limitations under the License. 15f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root */ 16f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 17f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootpackage org.conscrypt; 18f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 19f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.NoSuchAlgorithmException; 20f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.PrivateKey; 21f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.Provider; 22f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.Security; 23f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.Signature; 24f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.interfaces.DSAPrivateKey; 25f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.interfaces.ECPrivateKey; 26f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.interfaces.RSAPrivateKey; 27f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport javax.crypto.Cipher; 28f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport javax.crypto.NoSuchPaddingException; 29f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 30f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root/** 31f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * Provides a place where NativeCrypto can call back up to do Java language 32f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * calls to work on delegated key types from native code. 33f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root */ 34f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootpublic final class CryptoUpcalls { 35f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root private static final String RSA_CRYPTO_ALGORITHM = "RSA/ECB/PKCS1Padding"; 36f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 37f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root private CryptoUpcalls() { 38f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 39f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 40f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root /** 41f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * Finds the first provider which provides {@code algorithm} but is not from 42f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * the same ClassLoader as ours. 43f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root */ 44f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root public static Provider getExternalProvider(String algorithm) { 45f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root Provider selectedProvider = null; 46f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root for (Provider p : Security.getProviders(algorithm)) { 47f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (!p.getClass().getClassLoader().equals(CryptoUpcalls.class.getClassLoader())) { 48f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root selectedProvider = p; 49f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root break; 50f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 51f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 52f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (selectedProvider == null) { 53f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root System.err.println("Could not find external provider for algorithm: " + algorithm); 54f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 55f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return selectedProvider; 56f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 57f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 58f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root public static byte[] rawSignDigestWithPrivateKey(PrivateKey javaKey, byte[] message) { 59f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // Get the raw signature algorithm for this key type. 60f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root String algorithm = null; 61f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // Hint: Algorithm names come from: 62f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html 63f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (javaKey instanceof RSAPrivateKey) { 64f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // IMPORTANT: Due to a platform bug, this will throw 65f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // NoSuchAlgorithmException 66f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // on Android 4.0.x and 4.1.x. Fixed in 4.2 and higher. 67f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // See https://android-review.googlesource.com/#/c/40352/ 68f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root algorithm = "NONEwithRSA"; 69f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } else if (javaKey instanceof DSAPrivateKey) { 70f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root algorithm = "NONEwithDSA"; 71f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } else if (javaKey instanceof ECPrivateKey) { 72f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root algorithm = "NONEwithECDSA"; 73f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } else { 74f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root throw new RuntimeException("Unexpected key type: " + javaKey.toString()); 75f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 76f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 77f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root Provider p = getExternalProvider("Signature." + algorithm); 78f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (p == null) { 79f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return null; 80f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 81f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 82f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // Get the Signature for this key. 83f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root Signature signature = null; 84f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root try { 85f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root signature = Signature.getInstance(algorithm, p); 86f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } catch (NoSuchAlgorithmException e) { 87f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root ; 88f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 89f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 90f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (signature == null) { 91f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root System.err.println("Unsupported private key algorithm: " + javaKey.getAlgorithm()); 92f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return null; 93f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 94f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 95f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root // Sign the message. 96f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root try { 97f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root signature.initSign(javaKey); 98f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root signature.update(message); 99f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return signature.sign(); 100f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } catch (Exception e) { 101f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root System.err.println("Exception while signing message with " + javaKey.getAlgorithm() 102f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root + " private key:"); 103f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root e.printStackTrace(); 104f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return null; 105f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 106f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 107f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 108f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root public static byte[] rawCipherWithPrivateKey(PrivateKey javaKey, boolean encrypt, 109f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root byte[] input) { 110f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (!(javaKey instanceof RSAPrivateKey)) { 111f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root System.err.println("Unexpected key type: " + javaKey.toString()); 112f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return null; 113f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 114f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 115f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root Provider p = getExternalProvider("Cipher." + RSA_CRYPTO_ALGORITHM); 116f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (p == null) { 117f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return null; 118f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 119f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 120f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root Cipher c = null; 121f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root try { 122f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root c = Cipher.getInstance(RSA_CRYPTO_ALGORITHM, p); 123f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } catch (NoSuchAlgorithmException e) { 124f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root ; 125f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } catch (NoSuchPaddingException e) { 126f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root ; 127f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 128f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 129f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (c == null) { 130f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root System.err.println("Unsupported private key algorithm: " + javaKey.getAlgorithm()); 131f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 132f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 133f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root try { 134f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root c.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, javaKey); 135f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return c.doFinal(input); 136f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } catch (Exception e) { 137f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root System.err.println("Exception while ciphering message with " + javaKey.getAlgorithm() 138f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root + " private key:"); 139f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root e.printStackTrace(); 140f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return null; 141f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 142f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 143f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root} 144