본문 바로가기
넓고 얕은 CS 지식

자바에서 암호화 구현에 필요한 최소한의 지식을 정리해보자.(Binary Data, bit, byte, Base64, Hex 등)

by 황원용 2023. 9. 29.
728x90
💡 이 글에서는 자바에서 암호화 관련 로직을 문제없이 구현하기 위해 필요한 최소한의 지식을 정리한다.
각 개념의 의미와 상호 관계를 알아보면서 컴퓨터의 기본적인 데이터 표현 방식에 대해 자세히 알아보도록 하자.

 

📌 2진수 (Binary)

  • 2진수란 숫자 체계 중 하나로, 0과 1 두 가지 값만을 사용하여 수를 표현한다.
  • 컴퓨터에서 가장 기본적으로 사용되며 모든 데이터는 이진 형태로 저장되고 처리된다.

예시

  • 숫자 "0"를 2진수로 표현하면 "0"이다.
  • 숫자 "1"를 2진수로 표현하면 "1"이다.
  • 숫자 "2"를 2진수로 표현하면 "10"이다.
  • 숫자 "3"를 2진수로 표현하면 "11"이다.
  • 숫자 "4"를 2진수로 표현하면 "100"이다.
  • 숫자 "42"를 2진수로 표현하면 "101010"이다.
    • 맨 왼쪽부터 32 + 8 + 2 = 42이기 때문이다.

 

📌 비트 (Bit)

  • 비트는 "binary digit"의 줄임말로서 컴퓨터에서 정보를 표현하는 최소 단위이다.
  • 컴퓨터 메모리와 프로세서 등 다양한 하드웨어 구성 요소에서 처리된다.
  • 0과 1로 이루어져 있다.

예시

  • "01010110"과 같은 비트열은 여덟 개의 비트로 구성된 것으로 컴퓨터에서 숫자나 문자 등을 나타낼 수 있다.

 

📌 바이트 (Byte)

  • 바이트는 일반적으로 여덟 개의 비트로 구성된 데이터 단위이다.
  • 컴퓨터 메모리에 저장되거나 전송되는 데이터의 기본 단위 중 하나이다.

예시

  • "01010110"과 같은 여덟 개의 비트열은 하나의 바이트를 나타낸다.

 

📌 바이너리 데이터 (Binary Data)

  • 0과 1로 구성된 여러 개의 비트들의 시퀀스(집합)를 말한다.
  • 숫자, 문자, 이미지, 오디오 등 다양한 종류의 정보를 나타낼 수 있다.

예시

  • "01010110 01100001"과 같은 비트열들을 조합하여 표현된 데이터가 바이너리 데이터이다.

 

📜 정리

 컴퓨터에서 모든 데이터는 이진 형태인 2진수로 저장되고 처리된다. 이러한 정보를 나타내기 위해서 사용하는 최소 단위가 0이나 1로 표현가능한 비트이며, 여덟 개의 비트가 모여 하나의 바이트를 형성한다. 컴퓨터에서 다양한 종류(숫자, 문자 등)의 정보를 나타내기 위해서는 이러한 조합된 형태인 '바이너리 데이터'를 사용해야 한다.

 

 

📌 자바에서 바이너리 데이터를 다루는 방법

자바에서는 바이너리 데이터를 다룰 때 byte[] 타입을 사용한다.

 

그 이유?

  • 메모리 상에서 각각의 요소가 연속적으로 저장되기 때문에 메모리에 효율적이다.
  • 예를 들어, int나 long과 같은 크기가 더 큰 원시 타입을 사용하면 불필요한 메모리 공간을 차지할 수 있다.
    • 자바에서는 기본적으로 변수의 메모리 할당을 정렬(Alignment)에 따라 진행한다. 정렬은 데이터를 메모리에 저장할 때 주소가 데이터의 크기로 나누어 떨어지도록 조정하는 것을 의미한다. 예를 들어, int 타입은 4바이트이므로 해당 변수는 4의 배수 주소에서 시작해야 한다. 마찬가지로 long 타입은 8바이트이므로 8의 배수 주소에서 시작해야 한다.
    • byte[] 배열의 경우 각 요소들이 연속적으로 저장되기 때문에 메모리 상에서 효율적으로 사용될 수 있다. 반면에 int나 long과 같은 원시 타입을 사용하면 정렬을 위해 추가적인 바이트들이 낭비될 수 있는 것이다.
    • 예를 들어, int 배열 int[] arr = new int[10]; 을 생성한다고 가정해보자. 이 경우 각 요소는 4바이트씩 차지하게 되며, 배열의 첫 번째 요소는 시작 주소 그대로 할당되고 나머지 요소들은 정렬을 위해 추가 바이트를 차지한다. 따라서 실제로는 각각의 요소 사이에 여분의 바이트가 존재하여 메모리 공간을 낭비하게 된다.
    • 하지만 byte[] 배열을 사용하는 경우에는 각각의 바이트들이 연속적으로 저장되기 때문에 메모리 상에서 효율적으로 활용되는 것이다.
  • 대부분의 네트워크 프로토콜 및 파일 형식은 바이너리 데이터를 byte 배열 형태로 전송하거나 저장한다.
    • 따라서 자바에서도 해당 형식에 맞추어 데이터를 다룰 때 byte[] 타입을 사용하는 것이 유용하다.
    • 자바에서 제공하는 다양한 API 중 많은 부분에서 바이너리 데이터 처리 시 byte[] 타입을 기본으로 지원한다.
    • 예를 들어 java.security.MessageDigest 클래스는 입력으로 byte[] 배열을 받아들여 해시 값을 계산하고 반환한다.

 

 그런데, 자바에서 해시함수를 이용하여 해싱하거나 대칭키, 공개키를 이용한 암호화, 개인키를 이용한 전자 서명 등을 할 때 리턴 값을 byte[] 타입으로 두지 않는다. 해싱하거나 암호화한 byte[] 타입의 결과를 인코딩하여 String 타입으로 리턴하는 것이 일반적이다.

 

 

인코딩(Encoding) & 디코딩(Decoding)

  • 인코딩과 디코딩은 데이터를 다른 형식으로 변환하는 과정을 의미한다.

 

인코딩(Encoding)

  • 인코딩은 원본 데이터를 다른 형식으로 변환하는 과정을 말한다.

디코딩(Decoding)

  • 디코딩은 인코딩된 데이터를 원래의 형태로 복원하는 과정을 말한다.

 

바이너리 데이터를 인코딩하는 이유

전송 및 저장

  • 바이너리 데이터를 네트워크 상에서 전송하거나 파일로 저장해야 할 때 일부 프로토콜이나 파일 형식은 텍스트 형태의 데이터만 지원하기 때문이다.
  • 이 경우 바이너리 데이터를 텍스트로 변환하여 전송하거나 저장하기 위해 인코딩을 사용한다.

텍스트 기반 처리

  • 일부 시스템이나 라이브러리는 텍스트 형태의 입력만을 처리할 수 있다.
  • 바이너리 데이터를 해당 시스템에 적용하기 위해서는 텍스트 형태로 변환하여 사용해야 한다.

가독성 및 디버깅

  • 바이너리 데이터는 사람이 직접적으로 읽기 어렵다.
  • 디버깅 과정에서 원시 바이트 값을 확인하기 어려운 경우 인코딩을 사용하여 가독성을 높일 수 있다.

보안

일부 애플리케이션에서는 보안상의 이유로 바이너리 데이터를 인코딩하여 암호화하거나 숨기는 작업을 수행한다.

예를 들어 Base64 인코딩 된 문자열은 일반적인 문자열처럼 다룰 수 있으며 암호화된 정보가 외부에 노출되지 않도록 도와준다.

 

 

자바에서 바이너리 데이터를 인코딩하는 대표적인 방법

Base64 인코딩

  • Base64는 8비트 이진 데이터를 ASCII 문자로 변환하는 인코딩 방식이다.
  • 바이너리 데이터를 문자열로 변환하여 전송하거나 저장할 때 사용된다.
  • Java에서는 java.util.Base64 클래스를 제공하여 Base64 인코딩 및 디코딩을 지원한다.
  • 원본 데이터보다 약간 큰 크기를 가진다.

 

Hexadecimal(16진수) 인코딩

  • 16진수는 0부터 9까지의 숫자와 A부터 F까지의 알파벳으로 이루어진 표기법이다.
  • 바이너리 데이터의 각 바이트 값을 16진수로 표현하여 문자열로 변환한다.
  • Java에서는 직접 구현하여 사용할 수 있다.
  • 원본 데이터보다 크기가 두 배 커진다.

 

 

 

참고

뤼튼

 

728x90