1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.keystore.cts; 18 19 import java.nio.ByteBuffer; 20 21 /** 22 * Hexadecimal encoding where each byte is represented by two hexadecimal digits. 23 * 24 * @hide 25 */ 26 public class HexEncoding { 27 28 /** Hidden constructor to prevent instantiation. */ 29 private HexEncoding() {} 30 31 private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); 32 33 /** 34 * Encodes the provided data as a hexadecimal string. 35 */ 36 public static String encode(byte[] data) { 37 return encode(data, 0, data.length); 38 } 39 40 /** 41 * Encodes the provided data as a hexadecimal string. 42 */ 43 public static String encode(byte[] data, int offset, int len) { 44 StringBuilder result = new StringBuilder(len * 2); 45 for (int i = 0; i < len; i++) { 46 byte b = data[offset + i]; 47 result.append(HEX_DIGITS[(b >>> 4) & 0x0f]); 48 result.append(HEX_DIGITS[b & 0x0f]); 49 } 50 return result.toString(); 51 } 52 53 /** 54 * Encodes the provided data as a hexadecimal string. 55 */ 56 public static String encode(ByteBuffer buf) { 57 return encode(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining()); 58 } 59 60 /** 61 * Decodes the provided hexadecimal string into an array of bytes. 62 */ 63 public static byte[] decode(String encoded) { 64 // IMPLEMENTATION NOTE: Special care is taken to permit odd number of hexadecimal digits. 65 int resultLengthBytes = (encoded.length() + 1) / 2; 66 byte[] result = new byte[resultLengthBytes]; 67 int resultOffset = 0; 68 int encodedCharOffset = 0; 69 if ((encoded.length() % 2) != 0) { 70 // Odd number of digits -- the first digit is the lower 4 bits of the first result byte. 71 result[resultOffset++] = (byte) getHexadecimalDigitValue(encoded.charAt(encodedCharOffset)); 72 encodedCharOffset++; 73 } 74 for (int len = encoded.length(); encodedCharOffset < len; encodedCharOffset += 2) { 75 result[resultOffset++] = (byte) 76 ((getHexadecimalDigitValue(encoded.charAt(encodedCharOffset)) << 4) 77 | getHexadecimalDigitValue(encoded.charAt(encodedCharOffset + 1))); 78 } 79 return result; 80 } 81 82 private static int getHexadecimalDigitValue(char c) { 83 if ((c >= 'a') && (c <= 'f')) { 84 return (c - 'a') + 0x0a; 85 } else if ((c >= 'A') && (c <= 'F')) { 86 return (c - 'A') + 0x0a; 87 } else if ((c >= '0') && (c <= '9')) { 88 return c - '0'; 89 } else { 90 throw new IllegalArgumentException( 91 "Invalid hexadecimal digit at position : '" + c + "' (0x" + Integer.toHexString(c) + ")"); 92 } 93 } 94 } 95