В этой статье показано несколько способов преобразования массивов байтов или байт[]
в шестнадцатеричный (базовый 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/”