프로그래밍/Java,JSP

16진 문자열을 바이트 배열로 변환하기 (convert hexa-string to byte array)

채윤아빠 2020. 9. 7. 16:19
728x90
반응형

 

16진 문자열을 바이트 배열로 변환하기 위하여, for 문으로 직접 각 문자열을 파싱하는 함수를 직접 만들어 줄 수도 있지만, 일반적으로 BigInteger나, DatatypeConverter 클래스를 이용하는 것이 코드가 깔끔하고 편리합니다.
하지만, BigInteger 클래스는 실제로 BigInteger 데이터를 다루는 용도가 아닌, 바이트 배열로 변환에 이용하는 것은 문제가 있을 수 있습니다.

 

다음과 같이 원문 16진 문자열을 갖을 경우에 대한 예제 코드를 실행하여 보시기 바랍니다.

String hexaString = "0000e04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309d";

System.out.printf("\n== use BigInteger class ==\n");
byte[] bigIntegerData = new java.math.BigInteger(hexaString, 16).toByteArray();
System.out.printf("original HexaString    = %s\n", hexaString);
System.out.printf("BigInteger HexaString  = %s\n", new java.math.BigInteger(1, bigIntegerData).toString(16));
System.out.printf("BigInteger Data(0 ~ 3) = %02x %02x %02x %02x\n", bigIntegerData[0], bigIntegerData[1], bigIntegerData[2], bigIntegerData[3]);

위와 같은 코드를 실행하면, 그 결과는 다음과 같이 나옵니다.

== use BigInteger class ==
original HexaString    = 0000e04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309d
BigInteger HexaString  = e04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309d
BigInteger Data(0 ~ 3) = 00 e0 4f d0

BigInteger 클래스 자체가 숫자를 다루는 것이기 때문에, 앞에 붙은 "0"은 의미가 없기 때문에(숫자는 Big endian 이므로) 무시됩니다.
그래서 위 예에서 "0000" 부분이 1바이트로 축소 되었고, 문자열로 변환했을 경우에는 아예 출력이 되지 않아, 바이트 배열에서 실제 데이터의 누락이 생기게 됩니다.

이에 대한 해결책으로 숫자 데이터를 다루는 것이 아니라면, DatatypeConverter 클래스를 이용하는 것입니다.
아래 동일한 16진 문자열을 바이트 배열로 변환하는 예제입니다.

String hexaString = "0000e04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309d";

System.out.printf("\n== use DatatypeConverter class ==\n");
byte[] convertedData = javax.xml.bind.DatatypeConverter.parseHexBinary(hexaString);
System.out.printf("original HexaString   = %s\n", hexaString);
System.out.printf("converted HexaString  = %s\n", javax.xml.bind.DatatypeConverter.printHexBinary(convertedData));
System.out.printf("converted Data(0 ~ 3) = %02x %02x %02x %02x\n", convertedData[0], convertedData[1], convertedData[2], convertedData[3]);

위 코드를 실행하면 다음과 같습니다.

== use DatatypeConverter class ==
original HexaString   = 0000e04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309de04fd020ea3a6910a2d808002b30309d
converted HexaString  = 0000E04FD020EA3A6910A2D808002B30309DE04FD020EA3A6910A2D808002B30309DE04FD020EA3A6910A2D808002B30309D
converted Data(0 ~ 3) = 00 00 e0 4f

DatatypeConverter 클래스를 이용하여 16진 문자열을 바이트 배열로 변환하면, 앞에 중복으로 나타나는 "00" 도 누락없이 정상적으로 처리됨을 확인할 수 있습니다.

DatatypeConverter를 이용하여 16진 문자열을 매개변수로 넘겨줄 때는 반드시 짝수 길이여야 하고, '0' ~ '9', 'a' ~ 'f' 사이의 문자만 입력되어야 합니다.
이를 만족하지 않을 경우에는 아래와 같이 "IllegalArgumentException" Exception이 발생하게 됩니다.

//        byte[] notEvenLengthData = javax.xml.bind.DatatypeConverter.parseHexBinary("123");
/* Exception in thread "main" java.lang.IllegalArgumentException: hexBinary needs to be even-length: 123
    at javax.xml.bind.DatatypeConverterImpl.parseHexBinary(DatatypeConverterImpl.java:442)
    at javax.xml.bind.DatatypeConverter.parseHexBinary(DatatypeConverter.java:357)
*/

//        byte[] illegalCharacterData = javax.xml.bind.DatatypeConverter.parseHexBinary("12 34 56");
/* Exception in thread "main" java.lang.IllegalArgumentException: contains illegal character for hexBinary: 12 34 56
    at javax.xml.bind.DatatypeConverterImpl.parseHexBinary(DatatypeConverterImpl.java:451)
    at javax.xml.bind.DatatypeConverter.parseHexBinary(DatatypeConverter.java:357)
*/

예제 소스 : https://github.com/hanwhhanwh/java-test/blob/master/JavaTest/src/HexaStringToByteArray.java

 

참고자료