| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /* |
| * Copyright (c) 2017, The Linux Foundation. |
| */ |
| |
| /* |
| * Contributed by: Giesecke & Devrient GmbH. |
| */ |
| |
| package com.android.se.internal; |
| |
| import android.content.Context; |
| import android.content.pm.PackageManager; |
| |
| import java.security.AccessControlException; |
| |
| /** Util class for byte[] operations */ |
| public class Util { |
| |
| public static final byte END = -1; |
| |
| /** Returns a new array containing both the arrays appended */ |
| public static byte[] mergeBytes(byte[] array1, byte[] array2) { |
| byte[] data = new byte[array1.length + array2.length]; |
| System.arraycopy(array1, 0, data, 0, array1.length); |
| System.arraycopy(array2, 0, data, array1.length, array2.length); |
| return data; |
| } |
| |
| /** Extracts the required bytes from the array */ |
| public static byte[] getMid(byte[] array, int start, int length) { |
| byte[] data = new byte[length]; |
| System.arraycopy(array, start, data, 0, length); |
| return data; |
| } |
| |
| /** |
| * Returns a concatenated response. |
| * |
| * @param r1 the first part of the response. |
| * @param r2 the second part of the response. |
| * @param length the number of bytes of the second part to be appended. |
| * @return a concatenated response. |
| */ |
| public static byte[] appendResponse(byte[] r1, byte[] r2, int length) { |
| byte[] rsp = new byte[r1.length + length]; |
| System.arraycopy(r1, 0, rsp, 0, r1.length); |
| System.arraycopy(r2, 0, rsp, r1.length, length); |
| return rsp; |
| } |
| |
| /** |
| * Creates a formatted exception message. |
| * |
| * @param commandName the name of the command. <code>null</code> if not specified. |
| * @param sw the response status word. |
| * @return a formatted exception message. |
| */ |
| public static String createMessage(String commandName, int sw) { |
| StringBuilder message = new StringBuilder(); |
| if (commandName != null) { |
| message.append(commandName).append(" "); |
| } |
| message.append("SW1/2 error: "); |
| message.append(Integer.toHexString(sw | 0x10000).substring(1)); |
| return message.toString(); |
| } |
| |
| /** |
| * Creates a formatted exception message. |
| * |
| * @param commandName the name of the command. <code>null</code> if not specified. |
| * @param message the message to be formatted. |
| * @return a formatted exception message. |
| */ |
| public static String createMessage(String commandName, String message) { |
| if (commandName == null) { |
| return message; |
| } |
| return commandName + " " + message; |
| } |
| |
| /** |
| * Get package name from the user id. |
| * |
| * <p>This shall fix the problem the issue that process name != package name due to |
| * anndroid:process attribute in manifest file. |
| * |
| * <p>But this call is not really secure either since a uid can be shared between one and more |
| * apks |
| * |
| * @return The first package name associated with this uid. |
| */ |
| public static String getPackageNameFromCallingUid(Context context, int uid) { |
| PackageManager packageManager = context.getPackageManager(); |
| if (packageManager != null) { |
| String[] packageName = packageManager.getPackagesForUid(uid); |
| if (packageName != null && packageName.length > 0) { |
| return packageName[0]; |
| } |
| } |
| throw new AccessControlException("Caller PackageName can not be determined"); |
| } |
| |
| /** |
| * Returns a copy of the given CLA byte where the channel number bits are set as specified by |
| * the |
| * given channel number See GlobalPlatform Card Specification 2.2.0.7: 11.1.4 Class Byte |
| * Coding. |
| * |
| * @param cla the CLA byte. Won't be modified |
| * @param channelNumber within [0..3] (for first interindustry class byte coding) or [4..19] |
| * (for |
| * further interindustry class byte coding) |
| * @return the CLA byte with set channel number bits. The seventh bit indicating the used coding |
| * (first/further interindustry class byte coding) might be modified |
| */ |
| public static byte setChannelToClassByte(byte cla, int channelNumber) { |
| if (channelNumber < 4) { |
| // b7 = 0 indicates the first interindustry class byte coding |
| cla = (byte) ((cla & 0xBC) | channelNumber); |
| } else if (channelNumber < 20) { |
| // b7 = 1 indicates the further interindustry class byte coding |
| boolean isSM = (cla & 0x0C) != 0; |
| cla = (byte) ((cla & 0xB0) | 0x40 | (channelNumber - 4)); |
| if (isSM) { |
| cla |= 0x20; |
| } |
| } else { |
| throw new IllegalArgumentException("Channel number must be within [0..19]"); |
| } |
| return cla; |
| } |
| |
| /** |
| * Clear the channel number. |
| * |
| * @return the cla without channel number |
| */ |
| public static byte clearChannelNumber(byte cla) { |
| // bit 7 determines which standard is used |
| boolean isFirstInterindustryClassByteCoding = (cla & 0x40) == 0x00; |
| |
| if (isFirstInterindustryClassByteCoding) { |
| // First Interindustry Class Byte Coding |
| // see 11.1.4.1: channel number is encoded in the 2 rightmost bits |
| return (byte) (cla & 0xFC); |
| } else { |
| // Further Interindustry Class Byte Coding |
| // see 11.1.4.2: channel number is encoded in the 4 rightmost bits |
| return (byte) (cla & 0xF0); |
| } |
| } |
| |
| /** |
| * Extracts the channel number from a CLA byte. Specified in GlobalPlatform Card Specification |
| * 2.2.0.7: 11.1.4 Class Byte Coding. |
| * |
| * @param cla the command's CLA byte |
| * @return the channel number within [0x00..0x0F] |
| */ |
| public static int parseChannelNumber(byte cla) { |
| // bit 7 determines which standard is used |
| boolean isFirstInterindustryClassByteCoding = (cla & 0x40) == 0x00; |
| |
| if (isFirstInterindustryClassByteCoding) { |
| // First Interindustry Class Byte Coding |
| // see 11.1.4.1: channel number is encoded in the 2 rightmost bits |
| return cla & 0x03; |
| } else { |
| // Further Interindustry Class Byte Coding |
| // see 11.1.4.2: channel number is encoded in the 4 rightmost bits |
| return (cla & 0x0F) + 4; |
| } |
| } |
| } |