В этой статье показано несколько способов преобразования массивов байтов или байт[] в шестнадцатеричный (базовый 16 или шестнадцатеричный) строковый представитель.
В этой статье показано несколько способов преобразования массивов байтов илибайт[]- в
шестнадцатеричный - (базовый 16 или шестнадцатеричный) строковый представитель.
В этой статье показано несколько способов преобразования массивов байтов или - байт[]
Примечание Как кодек Apache Commons, так и криптомодули Spring Security используют аналогичные 5. Побитовое смещение и маскирование методы преобразования байтовых массивов в шестнадцатеричную строку, пожалуйста, изучите исходный код ниже, это полезно в образовательных целях.
1. Строка.формат %02x
Это Это это самый простой и очевидный способ преобразования байтовых массивов в шестнадцатеричный, %02x для шестнадцатеричного в нижнем регистре,
package com.mkyong.crypto.bytes;
import java.nio.charset.StandardCharsets;
public class ByteToHexExample1 {
public static String hex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte aByte : bytes) {
result.append(String.format("%02x", aByte));
// upper case
// result.append(String.format("%02X", aByte));
}
return result.toString();
}
public static void main(String[] args) {
String input = "a";
System.out.println(hex(input.getBytes(StandardCharsets.UTF_8)));
}
}
Выход
61
2. Выход
Этот Integer.toHexString(int i) принимает int в качестве аргумента и возвращает шестнадцатеричную строку. Ключ преобразует байт в int и маскирует 0xff , чтобы предотвратить расширение знака .
package com.mkyong.crypto.bytes;
import java.nio.charset.StandardCharsets;
public class ByteToHexExample2 {
public static String hex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte aByte : bytes) {
int decimal = (int) aByte & 0xff; // bytes widen to int, need mask, prevent sign extension
// get last 8 bits
String hex = Integer.toHexString(decimal);
if (hex.length() % 2 == 1) { // if half hex, pad with zero, e.g \t
hex = "0" + hex;
}
result.append(hex);
}
return result.toString();
}
public static void main(String[] args) {
String input = "a";
System.out.println(hex(input.getBytes(StandardCharsets.UTF_8)));
}
}
Выход
61
3. Кодек Apache Commons
Мы можем использовать Hex.encodehex для преобразования байта[] в шестнадцатеричную строку или Hex.decodehex для преобразования шестнадцатеричной строки в байт[] .
package com.mkyong.crypto.bytes;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import java.nio.charset.StandardCharsets;
public class ByteToHexExample3 {
public static String hex(byte[] bytes) {
char[] result = Hex.encodeHex(bytes);
return new String(result);
}
public static String unhex(String hex) throws DecoderException {
return new String(Hex.decodeHex(hex));
}
public static void main(String[] args) throws DecoderException {
String input = "a";
String hex = hex(input.getBytes(StandardCharsets.UTF_8));
System.out.println(hex); // 61
String unhex = unhex(hex);
System.out.println(unhex); // a
}
}
Знаток.
commons-codec commons-codec 1.14
4. Криптографическая система безопасности Spring
В Spring Security мы можем использовать Hex.encode для преобразования байта[] в шестнадцатеричную строку.
package com.mkyong.crypto.bytes;
import org.springframework.security.crypto.codec.Hex;
import java.nio.charset.StandardCharsets;
public class ByteToHexExample4 {
public static void main(String[] args) {
String input = "a";
char[] encode = Hex.encode(input.getBytes(StandardCharsets.UTF_8));
String hex = new String(encode);
System.out.println(hex); // 61
byte[] decode = Hex.decode(hex);
System.out.println(new String(decode)); // a
}
}
Знаток.
org.springframework.security spring-security-crypto 5.3.2.RELEASE
5. Побитовое смещение и маскировка.
Приведенный ниже исходный код взят из модуля Spring Security Crypto , а коды Apache Commons используют аналогичные методы для преобразования массивов байтов в шестнадцатеричные строки, с некоторыми незначительными изменениями, такими как различающееся имя переменной или вычисление длины, основные идеи одинаковы.
5.1 Шестнадцатеричное кодирование.
package org.springframework.security.crypto.codec;
//...
private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
public static char[] encode(byte[] bytes) {
final int nBytes = bytes.length;
char[] result = new char[2 * nBytes]; // 1 hex contains two chars
// hex = [0-f][0-f], e.g 0f or ff
int j = 0;
for (byte aByte : bytes) { // loop byte by byte
// 0xF0 = FFFF 0000
result[j++] = HEX[(0xF0 & aByte) >>> 4]; // get the top 4 bits, first half hex char
// 0x0F = 0000 FFFF
result[j++] = HEX[(0x0F & aByte)]; // get the bottom 4 bits, second half hex char
// combine first and second half, we get a complete hex
}
return result;
}
Самое сложное – понять следующие два утверждения.
HEX[(0xF0 & aByte) >>> 4]; HEX[(0x0F & aByte)];
5.1.1 ШЕСТНАДЦАТЕРИЧНЫЙ[(0xF0 и байт)>>> 4] (первая половина шестнадцатеричного)
Например, символ a , двоичный является 0110 0001 , после побитового И a 0xF0 , это становится 0110 0000 .
0110 0001 # 1 hex = 2 chars [0-f][0-f]
# In this case, hex = [0110][0001]
0110 0001 # 0110 = first half hex, 0001 = second half hex
&
FFFF 0000 # 0xF0 = FFFF 0000 , bitwise AND operator.
0110 0000 # result 0110 0000
Логический сдвиг вправо 4 бита 0110 0000 >>> 4 , это становится 0000 0110 . Прочитайте это Java>> и >>> оператор побитового сдвига .
0110 0000 | ???? 0110 | 0000 # >>> 4 0000 0110 | 0000 # >>> 4 (logical right shift, zero extension) 0000 0110 # result, the first half hex
Преобразуйте этот двоичный файл 0000 0110 для десятичной дроби это 6 , посмотрите на переменную статический конечный символ[] шестнадцатеричный , значение индекса 6 равно 6, а первая половина шестнадцатеричного числа равна 6.
5.1.2 ШЕСТНАДЦАТЕРИЧНЫЙ[(0x0F и байт)] (вторая половина шестнадцатеричного) Тот же символ a , двоичный является 0110 0001 , побитовое И a 0x0F .
0110 0001 # 0110 = first half hex, 0001 = second half hex & # bitwise AND operator. 0000 FFFF # 0x0F = 0000 FFFF 0000 0001 # result 0000 0001
Преобразуйте этот двоичный файл 0000 00001 для десятичной дроби это 1 , посмотрите на переменную статический конечный символ[] шестнадцатеричный снова, значение индекса 1 равно 1, а вторая половина шестнадцатеричного значения равна 1.
Мы объединяем первую половину и вторую половину шестигранника, который равен 6 +1, он становится 61 . Для символа a шестнадцатеричное значение равно 61 .
5.2 Шестнадцатеричное декодирование.
package org.springframework.security.crypto.codec;
//...
private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
public static byte[] decode(CharSequence s) {
int nChars = s.length();
if (nChars % 2 != 0) {
throw new IllegalArgumentException(
"Hex-encoded string must have an even number of characters");
}
byte[] result = new byte[nChars / 2]; // 1 hex = 2 char
for (int i = 0; i < nChars; i += 2) { // step 2, 1 hex = 2 char
int msb = Character.digit(s.charAt(i), 16); // char -> hex, base16
int lsb = Character.digit(s.charAt(i + 1), 16);
if (msb < 0 || lsb < 0) {
throw new IllegalArgumentException(
"Detected a Non-hex character at " + (i + 1) + " or " + (i + 2) + " position");
}
result[i / 2] = (byte) ((msb << 4) | lsb);
}
return result;
}
}
Например, тот же самый шестнадцатеричный 61 , символ a .
Символ.цифра – это API-интерфейсы JDK, преобразующие символ в базовое 16 или шестнадцатеричное значение и возвращающие int .
int msb = Character.digit(s.charAt(i), 16); // msb = 6 int lsb = Character.digit(s.charAt(i + 1), 16); // lsb = 1
-
msbобозначает самый значительный бит (или бит высокого порядка или крайний левый бит). -
lsbобозначает наименее значимый бит (или самый правый бит).
Примечание В msb и lsb имена переменных немного странные, и я думаю, что автор ссылается на первые 4 бита и последние 4 бита.
В Java, int 6 , двоичный файл является 0000 0110 ; для int 1 двоичный файл равен 0000 0001
(byte) ((msb << 4) | lsb); // in this example, msb = 6, lsb = 1
# (byte) ((msb << 4) | lsb);
| 0000 0000 | 0000 0000 | 0000 0000 | 0000 0110 | # msb, 6 is an int, 32-bit
# (byte) ((msb << 4) | lsb);
# (byte) ((6 << 4) | 1);
# <<-- 4
0000 | 0000 0000 | 0000 0000 | 0000 0000 | 0110 ???? | # 6 << 4
0000 | 0000 0000 | 0000 0000 | 0000 0000 | 0110 0000 | # left shift, ignore sign, zero extension.
| 0000 0000 | 0000 0000 | 0000 0000 | 0110 0000 | # final msb
# bitwise | operator, bitwise inclusive OR
| 0000 0000 | 0000 0000 | 0000 0000 | 0000 0001 | # lsb = 1
| 0000 0000 | 0000 0000 | 0000 0000 | 0110 0001 | # msb | lsb = 0110 0001
| 0110 0001 | # (byte) (msb|lsb) , down cast from int to byte 8-bit
Окончательный двоичный файл – это 0110 0001 .
Этот фрагмент кода преобразует двоичную строку в строку, для двоичного 0110 0001 , строка a .
int charCode = Integer.parseInt("01100001", 2);
System.out.println(charCode); // 97, look ascii table
String str = Character.toString((char) charCode);
System.out.println(str); // output = a
Спасибо за чтение.
Рекомендации
- Википедия – Шестнадцатеричный
- Википедия – Побитовая операция
- Расширение знака Java
- Java>> и >>> оператор побитового сдвига
- Oracle – Операторы побитового и битового сдвига
- Криптографическая система безопасности Spring
Оригинал: “https://mkyong.com/java/java-how-to-convert-bytes-to-hex/”