blob: 8e9cfe3e3ebcbeb03c43fe901be8239fda57b585 [file] [log] [blame]
/*
* 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;
}
}
}