13c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills/*
23c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Copyright (C) 2016 The Android Open Source Project
33c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills *
43c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Licensed under the Apache License, Version 2.0 (the "License");
53c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * you may not use this file except in compliance with the License.
63c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * You may obtain a copy of the License at
73c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills *
83c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills *      http://www.apache.org/licenses/LICENSE-2.0
93c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills *
103c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Unless required by applicable law or agreed to in writing, software
113c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * distributed under the License is distributed on an "AS IS" BASIS,
123c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * See the License for the specific language governing permissions and
143c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * limitations under the License.
153c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */
163c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
173c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willspackage com.android.server.wifi.util;
183c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
193c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willsimport android.net.wifi.WifiConfiguration;
203c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willsimport android.net.wifi.WifiEnterpriseConfig;
213c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willsimport android.telephony.TelephonyManager;
22259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Willsimport android.util.Base64;
23259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Willsimport android.util.Log;
243c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
25b8b3fb8228a1f90106bad8c59ce006b81ef7921cRoshan Piusimport com.android.server.wifi.WifiNative;
26b8b3fb8228a1f90106bad8c59ce006b81ef7921cRoshan Pius
273c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills/**
283c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Utilities for the Wifi Service to interact with telephony.
293c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */
303c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willspublic class TelephonyUtil {
31259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static final String TAG = "TelephonyUtil";
323c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
333c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    /**
348757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * Get the identity for the current SIM or null if the SIM is not available
358757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     *
368757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @param tm TelephonyManager instance
378757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @param config WifiConfiguration that indicates what sort of authentication is necessary
388757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @return String with the identity or none if the SIM is not available or config is invalid
393c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     */
408757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart    public static String getSimIdentity(TelephonyManager tm, WifiConfiguration config) {
41259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (tm == null) {
42259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "No valid TelephonyManager");
433c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            return null;
443c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
45259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        String imsi = tm.getSubscriberId();
46259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        String mccMnc = "";
47259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
48259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
49259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            mccMnc = tm.getSimOperator();
50259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
51259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
528757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart        return buildIdentity(getSimMethodForConfig(config), imsi, mccMnc);
533c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    }
543c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
553c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    /**
563c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * create Permanent Identity base on IMSI,
573c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     *
583c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * rfc4186 & rfc4187:
593c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * identity = usernam@realm
603c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * with username = prefix | IMSI
613c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
623c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     */
633c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    private static String buildIdentity(int eapMethod, String imsi, String mccMnc) {
643c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        if (imsi == null || imsi.isEmpty()) {
658757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart            Log.e(TAG, "No IMSI or IMSI is null");
663c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            return null;
673c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
683c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
693c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        String prefix;
703c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        if (eapMethod == WifiEnterpriseConfig.Eap.SIM) {
713c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            prefix = "1";
723c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        } else if (eapMethod == WifiEnterpriseConfig.Eap.AKA) {
733c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            prefix = "0";
743c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        } else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME) {
753c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            prefix = "6";
768757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart        } else {
778757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart            Log.e(TAG, "Invalid EAP method");
783c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            return null;
793c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
803c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
813c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        /* extract mcc & mnc from mccMnc */
823c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        String mcc;
833c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        String mnc;
843c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        if (mccMnc != null && !mccMnc.isEmpty()) {
853c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            mcc = mccMnc.substring(0, 3);
863c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            mnc = mccMnc.substring(3);
873c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            if (mnc.length() == 2) {
883c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills                mnc = "0" + mnc;
893c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            }
903c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        } else {
913c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            // extract mcc & mnc from IMSI, assume mnc size is 3
923c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            mcc = imsi.substring(0, 3);
933c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            mnc = imsi.substring(3, 6);
943c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
953c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
963c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
973c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    }
983c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
993c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    /**
1008757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * Return the associated SIM method for the configuration.
1013c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     *
1028757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @param config WifiConfiguration corresponding to the network.
1038757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @return the outer EAP method associated with this SIM configuration.
1043c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     */
1058757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart    private static int getSimMethodForConfig(WifiConfiguration config) {
1063c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        if (config == null || config.enterpriseConfig == null) {
1078757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart            return WifiEnterpriseConfig.Eap.NONE;
1088757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart        }
1098757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart        int eapMethod = config.enterpriseConfig.getEapMethod();
1108757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart        if (eapMethod == WifiEnterpriseConfig.Eap.PEAP) {
1118757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart            // Translate known inner eap methods into an equivalent outer eap method.
1128757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart            switch (config.enterpriseConfig.getPhase2Method()) {
1138757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                case WifiEnterpriseConfig.Phase2.SIM:
1148757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                    eapMethod = WifiEnterpriseConfig.Eap.SIM;
1158757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                    break;
1168757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                case WifiEnterpriseConfig.Phase2.AKA:
1178757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                    eapMethod = WifiEnterpriseConfig.Eap.AKA;
1188757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                    break;
1198757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                case WifiEnterpriseConfig.Phase2.AKA_PRIME:
1208757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                    eapMethod = WifiEnterpriseConfig.Eap.AKA_PRIME;
1218757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart                    break;
1228757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart            }
1233c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
1243c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
1258757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart        return isSimEapMethod(eapMethod) ? eapMethod : WifiEnterpriseConfig.Eap.NONE;
1268757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart    }
1278757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart
1288757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart    /**
1298757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * Checks if the network is a SIM config.
1308757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     *
1318757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @param config Config corresponding to the network.
1328757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @return true if it is a SIM config, false otherwise.
1338757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     */
1348757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart    public static boolean isSimConfig(WifiConfiguration config) {
1358757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart        return getSimMethodForConfig(config) != WifiEnterpriseConfig.Eap.NONE;
1363c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    }
1373c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
1383c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    /**
1398757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * Checks if the EAP outer method is SIM related.
1403c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     *
1418757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @param eapMethod WifiEnterpriseConfig Eap method.
1428757adcc5e1f17354d09b4bacd3abda911974448Paul Stewart     * @return true if this EAP outer method is SIM-related, false otherwise.
1433c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     */
1443c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    public static boolean isSimEapMethod(int eapMethod) {
1453c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        return eapMethod == WifiEnterpriseConfig.Eap.SIM
1463c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills                || eapMethod == WifiEnterpriseConfig.Eap.AKA
1473c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills                || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME;
1483c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    }
149259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
150259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    // TODO replace some of this code with Byte.parseByte
151259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static int parseHex(char ch) {
152259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if ('0' <= ch && ch <= '9') {
153259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return ch - '0';
154259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else if ('a' <= ch && ch <= 'f') {
155259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return ch - 'a' + 10;
156259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else if ('A' <= ch && ch <= 'F') {
157259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return ch - 'A' + 10;
158259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else {
159259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            throw new NumberFormatException("" + ch + " is not a valid hex digit");
160259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
161259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
162259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
163259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static byte[] parseHex(String hex) {
164259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        /* This only works for good input; don't throw bad data at it */
165259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (hex == null) {
166259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return new byte[0];
167259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
168259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
169259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (hex.length() % 2 != 0) {
170259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            throw new NumberFormatException(hex + " is not a valid hex string");
171259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
172259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
173259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        byte[] result = new byte[(hex.length()) / 2 + 1];
174259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        result[0] = (byte) ((hex.length()) / 2);
175259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
176259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i + 1));
177259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte b = (byte) (val & 0xFF);
178259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            result[j] = b;
179259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
180259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
181259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return result;
182259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
183259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
184259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static String makeHex(byte[] bytes) {
185259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        StringBuilder sb = new StringBuilder();
186259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        for (byte b : bytes) {
187259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            sb.append(String.format("%02x", b));
188259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
189259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return sb.toString();
190259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
191259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
192259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static String makeHex(byte[] bytes, int from, int len) {
193259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        StringBuilder sb = new StringBuilder();
194259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        for (int i = 0; i < len; i++) {
195259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            sb.append(String.format("%02x", bytes[from + i]));
196259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
197259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return sb.toString();
198259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
199259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
200259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static byte[] concatHex(byte[] array1, byte[] array2) {
201259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
202259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        int len = array1.length + array2.length;
203259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
204259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        byte[] result = new byte[len];
205259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
206259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        int index = 0;
207259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (array1.length != 0) {
208259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            for (byte b : array1) {
209259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                result[index] = b;
210259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                index++;
211259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
212259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
213259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
214259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (array2.length != 0) {
215259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            for (byte b : array2) {
216259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                result[index] = b;
217259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                index++;
218259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
219259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
220259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
221259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return result;
222259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
223259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
224259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) {
225259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (tm == null) {
226259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "No valid TelephonyManager");
227259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return null;
228259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
229259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        StringBuilder sb = new StringBuilder();
230259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        for (String challenge : requestData) {
231259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (challenge == null || challenge.isEmpty()) {
232259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                continue;
233259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
234259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.d(TAG, "RAND = " + challenge);
235259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
236259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte[] rand = null;
237259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            try {
238259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                rand = parseHex(challenge);
239259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } catch (NumberFormatException e) {
240259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malformed challenge");
241259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                continue;
242259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
243259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
244259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String base64Challenge = Base64.encodeToString(rand, Base64.NO_WRAP);
245259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
246259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            // Try USIM first for authentication.
247259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
248259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                    TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
249259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (tmResponse == null) {
250259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                // Then, in case of failure, issue may be due to sim type, retry as a simple sim
251259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_SIM,
252259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                        TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
253259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
254259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.v(TAG, "Raw Response - " + tmResponse);
255259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
256259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (tmResponse == null || tmResponse.length() <= 4) {
257259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "bad response - " + tmResponse);
258259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                return null;
259259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
260259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
261259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte[] result = Base64.decode(tmResponse, Base64.DEFAULT);
262259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.v(TAG, "Hex Response -" + makeHex(result));
263259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            int sresLen = result[0];
264259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (sresLen >= result.length) {
265259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malfomed response - " + tmResponse);
266259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                return null;
267259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
268259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String sres = makeHex(result, 1, sresLen);
269259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            int kcOffset = 1 + sresLen;
270259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (kcOffset >= result.length) {
271259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malfomed response - " + tmResponse);
272259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                return null;
273259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
274259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            int kcLen = result[kcOffset];
275259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (kcOffset + kcLen > result.length) {
276259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malfomed response - " + tmResponse);
277259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                return null;
278259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
279259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String kc = makeHex(result, 1 + kcOffset, kcLen);
280259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            sb.append(":" + kc + ":" + sres);
281259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.v(TAG, "kc:" + kc + " sres:" + sres);
282259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
283259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
284259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return sb.toString();
285259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
286259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
287259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    /**
288259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills     * Data supplied when making a SIM Auth Request
289259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills     */
290259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static class SimAuthRequestData {
291259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public SimAuthRequestData() {}
292259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public SimAuthRequestData(int networkId, int protocol, String ssid, String[] data) {
293259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.networkId = networkId;
294259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.protocol = protocol;
295259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.ssid = ssid;
296259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.data = data;
297259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
298259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
299259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public int networkId;
300259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public int protocol;
301259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public String ssid;
302259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges
303259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge
304259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public String[] data;
305259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
306259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
307259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    /**
308259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills     * The response to a SIM Auth request if successful
309259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills     */
310259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static class SimAuthResponseData {
311259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public SimAuthResponseData(String type, String response) {
312259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.type = type;
313259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.response = response;
314259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
315259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
316259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public String type;
317259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public String response;
318259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
319259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
320259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static SimAuthResponseData get3GAuthResponse(SimAuthRequestData requestData,
321259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            TelephonyManager tm) {
322259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        StringBuilder sb = new StringBuilder();
323259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        byte[] rand = null;
324259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        byte[] authn = null;
325b8b3fb8228a1f90106bad8c59ce006b81ef7921cRoshan Pius        String resType = WifiNative.SIM_AUTH_RESP_TYPE_UMTS_AUTH;
326259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
327259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (requestData.data.length == 2) {
328259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            try {
329259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                rand = parseHex(requestData.data[0]);
330259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                authn = parseHex(requestData.data[1]);
331259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } catch (NumberFormatException e) {
332259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malformed challenge");
333259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
334259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else {
335259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "malformed challenge");
336259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
337259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
338259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        String tmResponse = "";
339259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (rand != null && authn != null) {
340259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String base64Challenge = Base64.encodeToString(concatHex(rand, authn), Base64.NO_WRAP);
341259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (tm != null) {
342259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
343259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                        TelephonyManager.AUTHTYPE_EAP_AKA, base64Challenge);
344259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.v(TAG, "Raw Response - " + tmResponse);
345259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } else {
346259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "No valid TelephonyManager");
347259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
348259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
349259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
350259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        boolean goodReponse = false;
351259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (tmResponse != null && tmResponse.length() > 4) {
352259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte[] result = Base64.decode(tmResponse, Base64.DEFAULT);
353259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "Hex Response - " + makeHex(result));
354259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte tag = result[0];
355259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (tag == (byte) 0xdb) {
356259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.v(TAG, "successful 3G authentication ");
357259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                int resLen = result[1];
358259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                String res = makeHex(result, 2, resLen);
359259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                int ckLen = result[resLen + 2];
360259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                String ck = makeHex(result, resLen + 3, ckLen);
361259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                int ikLen = result[resLen + ckLen + 3];
362259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                String ik = makeHex(result, resLen + ckLen + 4, ikLen);
363259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                sb.append(":" + ik + ":" + ck + ":" + res);
364259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.v(TAG, "ik:" + ik + "ck:" + ck + " res:" + res);
365259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                goodReponse = true;
366259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } else if (tag == (byte) 0xdc) {
367259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "synchronisation failure");
368259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                int autsLen = result[1];
369259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                String auts = makeHex(result, 2, autsLen);
370b8b3fb8228a1f90106bad8c59ce006b81ef7921cRoshan Pius                resType = WifiNative.SIM_AUTH_RESP_TYPE_UMTS_AUTS;
371259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                sb.append(":" + auts);
372259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.v(TAG, "auts:" + auts);
373259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                goodReponse = true;
374259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } else {
375259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "bad response - unknown tag = " + tag);
376259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
377259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else {
378259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "bad response - " + tmResponse);
379259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
380259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
381259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (goodReponse) {
382259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String response = sb.toString();
383259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.v(TAG, "Supplicant Response -" + response);
384259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return new SimAuthResponseData(resType, response);
385259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else {
386259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return null;
387259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
388259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
3893c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills}
390