Argon2id

IT 위키

Argon2id은 암호 해싱 및 키 유도 함수(Password-Based Key Derivation Function, PBKDF)의 한 형태로, 암호 저장 및 검증에 강점을 지닌 알고리즘이다.

개요[편집 | 원본 편집]

Argon2 계열은 2015년 열린 비밀번호 해싱 경연 대회(Password Hashing Competition)의 우승 알고리즘이다. Argon2에는 세 가지 변형이 있다: Argon2d, Argon2i, Argon2id. 이 중 Argon2id는 Argon2i와 Argon2d의 장점을 혼합한 하이브리드 방식이다. [1]

Argon2id는 첫 번째 패스에서 데이터 독립적 접근(data-independent access, Argon2i 스타일)을 사용하고, 이후 패스에서는 데이터 의존적 접근(data-dependent access, Argon2d 스타일)을 사용하는 방식으로 동작한다. 이 방식은 사이드 채널 공격 저항성과 GPU 기반 브루트포스 공격에 대한 강건성을 어느 정도 모두 확보하려는 설계 철학이다.

작동 원리 및 매개변수[편집 | 원본 편집]

Argon2id는 입력된 비밀번호(password), 솔트(salt), 메모리 비용(memory cost), 반복 횟수(iterations, 또는 time cost), 병렬성(parallelism) 등의 매개변수를 기반으로 해시값(태그, tag)을 생성한다. 중요 매개변수는 다음과 같다:

  • 메모리 비용 (m): 알고리즘이 사용하는 작업 메모리 양 (예: 메가바이트 단위)
  • 반복 횟수 (t): 메모리 패스를 반복하는 횟수
  • 병렬성 (p): 동시에 병렬로 처리할 라인(lanes) 수
  • 솔트 길이, 해시 출력 길이(tag length) 등

이들 매개변수는 해시 생성의 계산 복잡성과 자원 사용량을 조절하게 해 준다. 매개변수를 높이면 공격자가 무차별 대입(brute force) 공격을 수행할 때 드는 비용이 커지지만, 정당한 사용자 인증 시 처리 시간도 증가한다.

구체적 동작 과정[편집 | 원본 편집]

아래는 Argon2id의 동작을 단계별로 정리한 설명이다. 구현 세부는 RFC 9106 및 PHC 사양을 참조해야 한다.

  1. 초기화 및 H_0 생성
    • 1. 모든 입력(비밀번호, 솔트, 키, 연관 데이터,매개변수 등)을 길이 표기를 포함한 바이트열로 직렬화한다.
    • 2. 직렬화한 값을 Blake2b 기반의 가변 길이 해시 함수로 해싱하여 64바이트(예시) 길이의 초기 해시 H_0를 만든다. H_0는 이후 메모리 블록 생성의 시드 역할을 한다.
  2. 메모리 구조 할당
    • 3. 요구된 전체 메모리(m KiB)를 1KiB(1024바이트) 블록 단위로 나눈다. Argon2 내부에서의 기본 블록 크기는 1024바이트이다(블록 당 1024B). 전체 블록 수를 p(병렬성)로 나누어 각 'lane'(행)의 열 수(columnCount, q)를 결정한다.
    • 4. 2차원 배열 B[i][j] (i=0..p-1: lane, j=0..q-1: column)을 할당한다. 각 B[i][j]는 1024바이트 블록이다.
  3. 초기 두 블록 생성(각 lane의 j=0,1)
    • 5. 각 lane i에 대해 다음을 계산한다:
      • 5.1. B[i][0] ← Hash'(H_0 ∥ 0 ∥ i, 1024)
      • 5.2. B[i][1] ← Hash'(H_0 ∥ 1 ∥ i, 1024)
    • Hash'는 Blake2b를 사용하여 1024바이트 출력을 생성하는 래퍼(필요시 내부 반복을 통해 확장)이다. 이 단계는 모든 lane의 첫 두 블록을 결정한다.
  4. 블록 생성의 주 루프(패스와 칼럼)
    • 6. 총 반복 횟수 t(패스 수)만큼 전역 패스를 수행한다. 각 패스는 모든 lane과 모든 column을 처리한다. 각 블록 B[i][j]는 이전 블록들과 특정 인덱스의 블록을 입력으로 하는 내부 압축함수 G를 통해 계산되며, 그 결과가 블록에 저장되거나 XOR(반복 패스에서)으로 결합된다.
    • 7. 인덱스 선택 규칙(GetBlockIndexes) — Argon2id의 핵심
      • 7.1. 데이터 독립적 접근(data-independent addressing): 첫 번째 패스(특히 초기 절반 섹션)에서는 주소들이 입력 데이터(비밀번호 등)에 의존하지 않도록 의사난수(예: Blake2b로 생성된 스트림)로 결정된다. 이는 캐시 타이밍과 같은 사이드채널 공격을 완화한다(Argon2i 방식).
      • 7.2. 데이터 의존적 접근(data-dependent addressing): 이후 패스에서는 인덱스가 이미 계산된 블록 데이터에 의존하여 결정된다(Argon2d 방식). 이 방식은 시간-메모리 절충 공격을 어렵게 만든다.
      • 7.3. Argon2id는 "첫 패스는 데이터 독립적 접근을 사용하고, 이후 패스에서는 데이터 의존적 접근을 사용"하는 하이브리드 정책을 따른다. 이로써 초기 패스에서 사이드채널 저항을 확보하고 전체적으로 TMTO 저항성을 제공한다.
    • 8. 압축 함수 G의 동작(요약)
      • 8.1. G는 두 개의 1024바이트 입력 블록(예: X, Y)을 받아 내부적으로 BLAKE2b의 내부 순열을 이용하는 라운드 조합을 통해 1024바이트 출력을 생성한다.
      • 8.2. 구체적으로는 블록을 여러 64비트 워드(예: 128개의 64비트 워드)로 보고, BLAKE2b의 64비트 연산 스타일을 차용한 혼합/압축 연산(예: ARX 스타일의 덧셈·XOR·회전)을 수행한다. 최종 출력은 하나의 1024바이트 블록이다.
    • 9. 블록 저장 규칙(패스별)
      • 9.1. 만약 j==0(각 lane의 첫 열)이고 패스 수가 1보다 클 경우, 새로운 값은 이전 패스의 같은 lane 마지막 블록과 선정된 블록을 G로 결합한 뒤 XOR으로 B[i][0]에 합쳐진다.
      • 9.2. 그 외의 경우 B[i][j] = G(B[i][j-1], B[i′][j′]) 또는 B[i][j] = B[i][j] xor G(...) 형태로 갱신된다(패스와 RFC 규칙에 따름).
  5. 최종화 및 태그 생성
    • 10. 모든 패스가 끝나면 각 lane의 마지막 열(열 q-1)에 있는 블록들을 XOR하여 단일 블록 C를 만든다: C ← B[0][q-1] xor B[1][q-1] xor ... xor B[p-1][q-1].
    • 11. 출력 태그(tag)는 Hash'(C, T) (예: Blake2b 기반 가변 길이 해시)로 계산되어 요구된 바이트 수 T를 반환한다.

보안 관점[편집 | 원본 편집]

  • Argon2id는 Argon2i의 취약점인 시간-메모리 절충 공격(time-memory trade-off attack)에 대해 더 강한 저항성을 보인다.
  • 또한, Argon2d만을 사용할 경우 유리한 GPU 가속 공격 저항성이 있으나 사이드 채널 공격(예: 캐시 타이밍 공격)에 노출될 가능성이 있다. Argon2id는 이러한 균형을 고려한 선택지로 권장된다.
  • RFC 9106에서는 매개변수를 선택할 때 “Argon2id를 기본적으로 사용하라”는 지침을 제공한다.
  • OWASP도 비밀번호 저장 지침에서 Argon2id 를 권장한다. [2]

실사용 권장 설정[편집 | 원본 편집]

RFC 9106에서는 일반적인 안전 설정 예시를 제시한다:

  • 반복 횟수 t = 1, 병렬성 p = 4, 메모리 m = 2^21 (2 GiB)
  • 또는 메모리가 제한된 환경에서는 t = 3, p = 4, m = 2^16 (64 MiB) 등이 대체안으로 제안된다.

OWASP 기준에서는 최소 구성이 메모리 19 MiB, 반복 2회, 병렬성 1 등도 제시된다.

하지만 실제 응용에서는 하드웨어 성능, 사용자 응답성 요구 사항, 서비스 부하 등을 고려해 적절한 타협점을 찾아야 한다.

장단점 및 주의사항[편집 | 원본 편집]

장점[편집 | 원본 편집]

  • 메모리 집약적인 특성(memory-hardness)으로 GPU 또는 ASIC 가속을 통한 대규모 공격을 어렵게 만든다.
  • 사이드 채널 공격과 무차별 대입 공격 간의 균형을 어느 정도 제공하는 설계
  • 매개변수를 조절하여 보안 수준과 성능을 유연하게 조정할 수 있음

단점 / 주의 사항[편집 | 원본 편집]

  • 매개변수를 지나치게 높이면 인증 요청 처리 지연이나 시스템 자원 과다 사용 문제가 발생할 수 있다.
  • 매우 약한 비밀번호(password) 자체는 어떤 해싱 기법을 사용해도 취약하다.
  • 구현 시 버그나 안전하지 않은 라이브러리 사용, 매개변수 설정 실수, 솔트 재사용 등으로 취약점이 생길 수 있다.
  • 실제 배포된 소프트웨어 중에는 권장 설정보다 약하게 설정한 사례도 보고되고 있다. [3]

응용 및 적용 사례[편집 | 원본 편집]

많은 암호 관리 서비스(password manager), 인증 시스템, 보안 라이브러리 등이 Argon2id를 선택하거나 옵션으로 제공한다. 예를 들어 Bitwarden은 암호 키 도출을 위해 Argon2id를 사용한다. Go 언어 패키지 golang.org/x/crypto/argon2 에서도 Argon2id (IDKey 함수)를 지원하며, Go 생태계에서는 Argon2id를 기본 권장 방식으로 채택하는 경향이 있다.

같이 보기[편집 | 원본 편집]

참고 문헌[편집 | 원본 편집]

  • “Argon2: the memory-hard function for password hashing and other applications” (PHC 사양 문서)
  • RFC 9106, “Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications”
  • OWASP, “Password Storage Cheat Sheet”

각주[편집 | 원본 편집]

  1. RFC 9106
  2. OWASP Password Storage Cheat Sheet
  3. “Evaluating Argon2 Adoption and Effectiveness in Real-World Software” (2025)