TelephonyUtil.java revision 259fb5a5265e0a2aa8a851d5e694d28afe9a87f2
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
253c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills/**
263c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills * Utilities for the Wifi Service to interact with telephony.
273c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills */
283c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Willspublic class TelephonyUtil {
29259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static final String TAG = "TelephonyUtil";
303c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
313c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    /**
323c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * Get the identity for the current SIM or null if the sim is not available
333c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     */
34259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static String getSimIdentity(TelephonyManager tm, int eapMethod) {
35259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (tm == null) {
36259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "No valid TelephonyManager");
373c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            return null;
383c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
39259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        String imsi = tm.getSubscriberId();
40259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        String mccMnc = "";
41259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
42259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
43259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            mccMnc = tm.getSimOperator();
44259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
45259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
46259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return buildIdentity(eapMethod, imsi, mccMnc);
473c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    }
483c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
493c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    /**
503c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * create Permanent Identity base on IMSI,
513c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     *
523c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * rfc4186 & rfc4187:
533c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * identity = usernam@realm
543c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * with username = prefix | IMSI
553c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
563c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     */
573c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    private static String buildIdentity(int eapMethod, String imsi, String mccMnc) {
583c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        if (imsi == null || imsi.isEmpty()) {
593c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            return null;
603c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
613c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
623c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        String prefix;
633c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        if (eapMethod == WifiEnterpriseConfig.Eap.SIM) {
643c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            prefix = "1";
653c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        } else if (eapMethod == WifiEnterpriseConfig.Eap.AKA) {
663c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            prefix = "0";
673c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        } else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME) {
683c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            prefix = "6";
693c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        } else {  // not a valide EapMethod
703c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            return null;
713c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
723c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
733c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        /* extract mcc & mnc from mccMnc */
743c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        String mcc;
753c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        String mnc;
763c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        if (mccMnc != null && !mccMnc.isEmpty()) {
773c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            mcc = mccMnc.substring(0, 3);
783c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            mnc = mccMnc.substring(3);
793c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            if (mnc.length() == 2) {
803c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills                mnc = "0" + mnc;
813c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            }
823c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        } else {
833c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            // extract mcc & mnc from IMSI, assume mnc size is 3
843c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            mcc = imsi.substring(0, 3);
853c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            mnc = imsi.substring(3, 6);
863c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
873c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
883c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
893c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    }
903c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
913c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    /**
923c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * Checks if the network is a sim config.
933c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     *
943c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * @param config Config corresponding to the network.
953c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * @return true if it is a sim config, false otherwise.
963c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     */
973c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    public static boolean isSimConfig(WifiConfiguration config) {
983c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        if (config == null || config.enterpriseConfig == null) {
993c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills            return false;
1003c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        }
1013c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
1023c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        return isSimEapMethod(config.enterpriseConfig.getEapMethod());
1033c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    }
1043c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills
1053c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    /**
1063c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * Checks if the network is a sim config.
1073c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     *
1083c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * @param method
1093c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     * @return true if it is a sim config, false otherwise.
1103c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills     */
1113c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    public static boolean isSimEapMethod(int eapMethod) {
1123c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills        return eapMethod == WifiEnterpriseConfig.Eap.SIM
1133c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills                || eapMethod == WifiEnterpriseConfig.Eap.AKA
1143c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills                || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME;
1153c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills    }
116259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
117259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    // TODO replace some of this code with Byte.parseByte
118259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static int parseHex(char ch) {
119259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if ('0' <= ch && ch <= '9') {
120259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return ch - '0';
121259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else if ('a' <= ch && ch <= 'f') {
122259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return ch - 'a' + 10;
123259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else if ('A' <= ch && ch <= 'F') {
124259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return ch - 'A' + 10;
125259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else {
126259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            throw new NumberFormatException("" + ch + " is not a valid hex digit");
127259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
128259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
129259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
130259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static byte[] parseHex(String hex) {
131259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        /* This only works for good input; don't throw bad data at it */
132259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (hex == null) {
133259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return new byte[0];
134259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
135259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
136259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (hex.length() % 2 != 0) {
137259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            throw new NumberFormatException(hex + " is not a valid hex string");
138259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
139259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
140259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        byte[] result = new byte[(hex.length()) / 2 + 1];
141259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        result[0] = (byte) ((hex.length()) / 2);
142259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
143259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i + 1));
144259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte b = (byte) (val & 0xFF);
145259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            result[j] = b;
146259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
147259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
148259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return result;
149259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
150259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
151259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static String makeHex(byte[] bytes) {
152259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        StringBuilder sb = new StringBuilder();
153259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        for (byte b : bytes) {
154259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            sb.append(String.format("%02x", b));
155259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
156259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return sb.toString();
157259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
158259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
159259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static String makeHex(byte[] bytes, int from, int len) {
160259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        StringBuilder sb = new StringBuilder();
161259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        for (int i = 0; i < len; i++) {
162259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            sb.append(String.format("%02x", bytes[from + i]));
163259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
164259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return sb.toString();
165259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
166259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
167259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    private static byte[] concatHex(byte[] array1, byte[] array2) {
168259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
169259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        int len = array1.length + array2.length;
170259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
171259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        byte[] result = new byte[len];
172259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
173259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        int index = 0;
174259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (array1.length != 0) {
175259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            for (byte b : array1) {
176259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                result[index] = b;
177259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                index++;
178259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
179259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
180259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
181259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (array2.length != 0) {
182259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            for (byte b : array2) {
183259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                result[index] = b;
184259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                index++;
185259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
186259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
187259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
188259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return result;
189259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
190259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
191259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) {
192259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (tm == null) {
193259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "No valid TelephonyManager");
194259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return null;
195259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
196259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        StringBuilder sb = new StringBuilder();
197259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        for (String challenge : requestData) {
198259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (challenge == null || challenge.isEmpty()) {
199259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                continue;
200259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
201259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.d(TAG, "RAND = " + challenge);
202259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
203259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte[] rand = null;
204259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            try {
205259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                rand = parseHex(challenge);
206259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } catch (NumberFormatException e) {
207259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malformed challenge");
208259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                continue;
209259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
210259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
211259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String base64Challenge = Base64.encodeToString(rand, Base64.NO_WRAP);
212259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
213259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            // Try USIM first for authentication.
214259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
215259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                    TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
216259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (tmResponse == null) {
217259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                // Then, in case of failure, issue may be due to sim type, retry as a simple sim
218259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_SIM,
219259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                        TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
220259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
221259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.v(TAG, "Raw Response - " + tmResponse);
222259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
223259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (tmResponse == null || tmResponse.length() <= 4) {
224259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "bad response - " + tmResponse);
225259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                return null;
226259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
227259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
228259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte[] result = Base64.decode(tmResponse, Base64.DEFAULT);
229259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.v(TAG, "Hex Response -" + makeHex(result));
230259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            int sresLen = result[0];
231259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (sresLen >= result.length) {
232259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malfomed response - " + tmResponse);
233259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                return null;
234259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
235259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String sres = makeHex(result, 1, sresLen);
236259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            int kcOffset = 1 + sresLen;
237259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (kcOffset >= result.length) {
238259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malfomed response - " + tmResponse);
239259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                return null;
240259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
241259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            int kcLen = result[kcOffset];
242259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (kcOffset + kcLen > result.length) {
243259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malfomed response - " + tmResponse);
244259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                return null;
245259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
246259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String kc = makeHex(result, 1 + kcOffset, kcLen);
247259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            sb.append(":" + kc + ":" + sres);
248259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.v(TAG, "kc:" + kc + " sres:" + sres);
249259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
250259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
251259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        return sb.toString();
252259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
253259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
254259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    /**
255259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills     * Data supplied when making a SIM Auth Request
256259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills     */
257259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static class SimAuthRequestData {
258259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public SimAuthRequestData() {}
259259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public SimAuthRequestData(int networkId, int protocol, String ssid, String[] data) {
260259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.networkId = networkId;
261259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.protocol = protocol;
262259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.ssid = ssid;
263259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.data = data;
264259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
265259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
266259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public int networkId;
267259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public int protocol;
268259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public String ssid;
269259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges
270259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge
271259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public String[] data;
272259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
273259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
274259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    /**
275259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills     * The response to a SIM Auth request if successful
276259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills     */
277259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static class SimAuthResponseData {
278259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public SimAuthResponseData(String type, String response) {
279259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.type = type;
280259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            this.response = response;
281259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
282259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
283259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public String type;
284259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        public String response;
285259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
286259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
287259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    public static SimAuthResponseData get3GAuthResponse(SimAuthRequestData requestData,
288259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            TelephonyManager tm) {
289259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        StringBuilder sb = new StringBuilder();
290259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        byte[] rand = null;
291259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        byte[] authn = null;
292259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        String resType = "UMTS-AUTH";
293259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
294259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (requestData.data.length == 2) {
295259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            try {
296259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                rand = parseHex(requestData.data[0]);
297259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                authn = parseHex(requestData.data[1]);
298259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } catch (NumberFormatException e) {
299259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "malformed challenge");
300259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
301259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else {
302259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "malformed challenge");
303259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
304259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
305259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        String tmResponse = "";
306259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (rand != null && authn != null) {
307259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String base64Challenge = Base64.encodeToString(concatHex(rand, authn), Base64.NO_WRAP);
308259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (tm != null) {
309259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
310259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                        TelephonyManager.AUTHTYPE_EAP_AKA, base64Challenge);
311259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.v(TAG, "Raw Response - " + tmResponse);
312259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } else {
313259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "No valid TelephonyManager");
314259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
315259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
316259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
317259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        boolean goodReponse = false;
318259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (tmResponse != null && tmResponse.length() > 4) {
319259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte[] result = Base64.decode(tmResponse, Base64.DEFAULT);
320259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "Hex Response - " + makeHex(result));
321259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            byte tag = result[0];
322259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            if (tag == (byte) 0xdb) {
323259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.v(TAG, "successful 3G authentication ");
324259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                int resLen = result[1];
325259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                String res = makeHex(result, 2, resLen);
326259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                int ckLen = result[resLen + 2];
327259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                String ck = makeHex(result, resLen + 3, ckLen);
328259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                int ikLen = result[resLen + ckLen + 3];
329259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                String ik = makeHex(result, resLen + ckLen + 4, ikLen);
330259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                sb.append(":" + ik + ":" + ck + ":" + res);
331259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.v(TAG, "ik:" + ik + "ck:" + ck + " res:" + res);
332259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                goodReponse = true;
333259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } else if (tag == (byte) 0xdc) {
334259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "synchronisation failure");
335259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                int autsLen = result[1];
336259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                String auts = makeHex(result, 2, autsLen);
337259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                resType = "UMTS-AUTS";
338259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                sb.append(":" + auts);
339259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.v(TAG, "auts:" + auts);
340259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                goodReponse = true;
341259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            } else {
342259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills                Log.e(TAG, "bad response - unknown tag = " + tag);
343259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            }
344259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else {
345259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.e(TAG, "bad response - " + tmResponse);
346259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
347259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills
348259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        if (goodReponse) {
349259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            String response = sb.toString();
350259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            Log.v(TAG, "Supplicant Response -" + response);
351259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return new SimAuthResponseData(resType, response);
352259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        } else {
353259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills            return null;
354259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills        }
355259fb5a5265e0a2aa8a851d5e694d28afe9a87f2Mitchell Wills    }
3563c8094ab45f3320dbe45e6460c5d62dcc24ce7aeMitchell Wills}
357