Рубрики
Без рубрики

Ява – Как преобразовать массивы байтов в шестнадцатеричный

В этой статье показано несколько способов преобразования байтовых[] или байтовых массивов в шестнадцатеричную строку.

В этой статье показано несколько способов преобразования массивов байтов или байт[] в шестнадцатеричный (базовый 16 или шестнадцатеричный) строковый представитель.

  1. В этой статье показано несколько способов преобразования массивов байтов или
  2. байт[]
  3. в шестнадцатеричный
  4. (базовый 16 или шестнадцатеричный) строковый представитель. В этой статье показано несколько способов преобразования массивов байтов или
  5. байт[]

Примечание Как кодек 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 имена переменных немного странные, и я думаю, что автор ссылается на первые 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

Спасибо за чтение.

Рекомендации

Оригинал: “https://mkyong.com/java/java-how-to-convert-bytes-to-hex/”