11864f965419c5b14ac9317c576c8a0f7169c067enmittler/*
21864f965419c5b14ac9317c576c8a0f7169c067enmittler * Copyright 2016 The Android Open Source Project
31864f965419c5b14ac9317c576c8a0f7169c067enmittler *
41864f965419c5b14ac9317c576c8a0f7169c067enmittler * Licensed under the Apache License, Version 2.0 (the "License");
51864f965419c5b14ac9317c576c8a0f7169c067enmittler * you may not use this file except in compliance with the License.
61864f965419c5b14ac9317c576c8a0f7169c067enmittler * You may obtain a copy of the License at
71864f965419c5b14ac9317c576c8a0f7169c067enmittler *
81864f965419c5b14ac9317c576c8a0f7169c067enmittler *      http://www.apache.org/licenses/LICENSE-2.0
91864f965419c5b14ac9317c576c8a0f7169c067enmittler *
101864f965419c5b14ac9317c576c8a0f7169c067enmittler * Unless required by applicable law or agreed to in writing, software
111864f965419c5b14ac9317c576c8a0f7169c067enmittler * distributed under the License is distributed on an "AS IS" BASIS,
121864f965419c5b14ac9317c576c8a0f7169c067enmittler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131864f965419c5b14ac9317c576c8a0f7169c067enmittler * See the License for the specific language governing permissions and
141864f965419c5b14ac9317c576c8a0f7169c067enmittler * limitations under the License.
151864f965419c5b14ac9317c576c8a0f7169c067enmittler */
161864f965419c5b14ac9317c576c8a0f7169c067enmittler
171864f965419c5b14ac9317c576c8a0f7169c067enmittlerpackage libcore.java.security;
181864f965419c5b14ac9317c576c8a0f7169c067enmittler
19d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittlerimport static java.nio.charset.StandardCharsets.UTF_8;
20d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler
211864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.io.BufferedReader;
221864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.io.FileReader;
231864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.io.IOException;
24d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittlerimport java.io.InputStreamReader;
251864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.lang.reflect.InvocationTargetException;
261864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.lang.reflect.Method;
271864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.util.Arrays;
281864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.util.List;
291864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.util.regex.Matcher;
301864f965419c5b14ac9317c576c8a0f7169c067enmittlerimport java.util.regex.Pattern;
311864f965419c5b14ac9317c576c8a0f7169c067enmittler
321864f965419c5b14ac9317c576c8a0f7169c067enmittlerpublic class CpuFeatures {
331864f965419c5b14ac9317c576c8a0f7169c067enmittler    private CpuFeatures() {}
341864f965419c5b14ac9317c576c8a0f7169c067enmittler
351864f965419c5b14ac9317c576c8a0f7169c067enmittler    public static boolean isAESHardwareAccelerated() {
361864f965419c5b14ac9317c576c8a0f7169c067enmittler        List<String> features = getListFromCpuinfo("Features");
371864f965419c5b14ac9317c576c8a0f7169c067enmittler        if (features != null && features.contains("aes")) {
381864f965419c5b14ac9317c576c8a0f7169c067enmittler            return true;
391864f965419c5b14ac9317c576c8a0f7169c067enmittler        }
401864f965419c5b14ac9317c576c8a0f7169c067enmittler
411864f965419c5b14ac9317c576c8a0f7169c067enmittler        List<String> flags = getListFromCpuinfo("flags");
421864f965419c5b14ac9317c576c8a0f7169c067enmittler        if (flags != null && flags.contains("aes")) {
431864f965419c5b14ac9317c576c8a0f7169c067enmittler            return true;
441864f965419c5b14ac9317c576c8a0f7169c067enmittler        }
451864f965419c5b14ac9317c576c8a0f7169c067enmittler
46d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        features = getCpuFeaturesMac();
47d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        if (features != null && features.contains("aes")) {
48d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            return true;
49d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        }
50d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler
511864f965419c5b14ac9317c576c8a0f7169c067enmittler        // If we're in an emulated ABI, Conscrypt's NativeCrypto might bridge to
521864f965419c5b14ac9317c576c8a0f7169c067enmittler        // a library that has accelerated AES instructions. See if Conscrypt
531864f965419c5b14ac9317c576c8a0f7169c067enmittler        // detects that condition.
546321f7ae67de5eb2542c48e16ee86763463de5f2Nathan Mittler        Class<?> nativeCrypto = findNativeCrypto();
55d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        if (nativeCrypto != null) {
56d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            try {
57d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                Method EVP_has_aes_hardware =
58d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                        nativeCrypto.getDeclaredMethod("EVP_has_aes_hardware");
59d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                EVP_has_aes_hardware.setAccessible(true);
60d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                return ((Integer) EVP_has_aes_hardware.invoke(null)) == 1;
61401f1c4645f5ec715516ee9674c662448d115e66Nathan Mittler            } catch (NoSuchMethodException ignored) {
62401f1c4645f5ec715516ee9674c662448d115e66Nathan Mittler            } catch (SecurityException ignored) {
63401f1c4645f5ec715516ee9674c662448d115e66Nathan Mittler            } catch (IllegalAccessException ignored) {
64401f1c4645f5ec715516ee9674c662448d115e66Nathan Mittler            } catch (IllegalArgumentException ignored) {
65d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            } catch (InvocationTargetException e) {
66d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                throw new IllegalArgumentException(e);
67d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            }
681864f965419c5b14ac9317c576c8a0f7169c067enmittler        }
691864f965419c5b14ac9317c576c8a0f7169c067enmittler
701864f965419c5b14ac9317c576c8a0f7169c067enmittler        return false;
711864f965419c5b14ac9317c576c8a0f7169c067enmittler    }
721864f965419c5b14ac9317c576c8a0f7169c067enmittler
736321f7ae67de5eb2542c48e16ee86763463de5f2Nathan Mittler    private static Class<?> findNativeCrypto() {
746321f7ae67de5eb2542c48e16ee86763463de5f2Nathan Mittler        for (String packageName : new String[]{"com.android.org.conscrypt", "org.conscrypt"}) {
756321f7ae67de5eb2542c48e16ee86763463de5f2Nathan Mittler            String name = packageName + ".NativeCrypto";
76d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            try {
77d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                return Class.forName(name);
78d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            } catch (ClassNotFoundException e) {
796321f7ae67de5eb2542c48e16ee86763463de5f2Nathan Mittler                // Try the next one.
80d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            }
81d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        }
82d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        return null;
83d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler    }
84d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler
851864f965419c5b14ac9317c576c8a0f7169c067enmittler    private static String getFieldFromCpuinfo(String field) {
861864f965419c5b14ac9317c576c8a0f7169c067enmittler        try {
8729916ef38dc9cb4e4c6e3fdb87d4e921546d3ef4Nathan Mittler            @SuppressWarnings("DefaultCharset")
881864f965419c5b14ac9317c576c8a0f7169c067enmittler            BufferedReader br = new BufferedReader(new FileReader("/proc/cpuinfo"));
891864f965419c5b14ac9317c576c8a0f7169c067enmittler            Pattern p = Pattern.compile(field + "\\s*:\\s*(.*)");
901864f965419c5b14ac9317c576c8a0f7169c067enmittler
911864f965419c5b14ac9317c576c8a0f7169c067enmittler            try {
921864f965419c5b14ac9317c576c8a0f7169c067enmittler                String line;
931864f965419c5b14ac9317c576c8a0f7169c067enmittler                while ((line = br.readLine()) != null) {
941864f965419c5b14ac9317c576c8a0f7169c067enmittler                    Matcher m = p.matcher(line);
951864f965419c5b14ac9317c576c8a0f7169c067enmittler                    if (m.matches()) {
961864f965419c5b14ac9317c576c8a0f7169c067enmittler                        return m.group(1);
971864f965419c5b14ac9317c576c8a0f7169c067enmittler                    }
981864f965419c5b14ac9317c576c8a0f7169c067enmittler                }
991864f965419c5b14ac9317c576c8a0f7169c067enmittler            } finally {
1001864f965419c5b14ac9317c576c8a0f7169c067enmittler                br.close();
1011864f965419c5b14ac9317c576c8a0f7169c067enmittler            }
1021864f965419c5b14ac9317c576c8a0f7169c067enmittler        } catch (IOException ignored) {
103d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            // Ignored.
1041864f965419c5b14ac9317c576c8a0f7169c067enmittler        }
1051864f965419c5b14ac9317c576c8a0f7169c067enmittler
1061864f965419c5b14ac9317c576c8a0f7169c067enmittler        return null;
1071864f965419c5b14ac9317c576c8a0f7169c067enmittler    }
1081864f965419c5b14ac9317c576c8a0f7169c067enmittler
1091864f965419c5b14ac9317c576c8a0f7169c067enmittler    private static List<String> getListFromCpuinfo(String fieldName) {
1101864f965419c5b14ac9317c576c8a0f7169c067enmittler        String features = getFieldFromCpuinfo(fieldName);
1111864f965419c5b14ac9317c576c8a0f7169c067enmittler        if (features == null)
1121864f965419c5b14ac9317c576c8a0f7169c067enmittler            return null;
1131864f965419c5b14ac9317c576c8a0f7169c067enmittler
1141864f965419c5b14ac9317c576c8a0f7169c067enmittler        return Arrays.asList(features.split("\\s"));
1151864f965419c5b14ac9317c576c8a0f7169c067enmittler    }
116d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler
117d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler    private static List<String> getCpuFeaturesMac() {
118d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        try {
119d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            StringBuilder output = new StringBuilder();
120d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            Process proc = Runtime.getRuntime().exec("sysctl -a");
121d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            if (proc.waitFor() == 0) {
122d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                BufferedReader reader =
123d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                        new BufferedReader(new InputStreamReader(proc.getInputStream(), UTF_8));
124d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler
125d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                final String linePrefix = "machdep.cpu.features:";
126d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler
127d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                String line;
128d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                while ((line = reader.readLine()) != null) {
129d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                    line = line.toLowerCase();
130d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                    if (line.startsWith(linePrefix)) {
131d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                        // Strip the line prefix from the results.
132d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                        output.append(line.substring(linePrefix.length())).append(' ');
133d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                    }
134d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                }
135d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                if (output.length() > 0) {
136d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                    String outputString = output.toString();
137d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                    String[] parts = outputString.split("\\s+");
138d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                    return Arrays.asList(parts);
139d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler                }
140d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            }
141d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        } catch (Exception ignored) {
142d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler            // Ignored.
143d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        }
144d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler
145d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler        return null;
146d4d974d98b4f232abf0a03b631a69ebc4df0b50dNathan Mittler    }
1471864f965419c5b14ac9317c576c8a0f7169c067enmittler}
148