NAME

crypt, crypt_r - 패스워드 및 데이터 암호화

SYNOPSIS

#include <unistd.h>

char *crypt(const char *key, const char *salt);

#include <crypt.h>

char *crypt_r(const char *key, const char *salt,
              struct crypt_data *restrict data);

-lcrypt로 링크.

glibc 기능 확인 매크로 요건 (feature_test_macros(7) 참고):

crypt():
glibc 2.28부터:
_DEFAULT_SOURCE
glibc 2.27 및 이전:
_XOPEN_SOURCE
crypt_r():
_GNU_SOURCE

DESCRIPTION

crypt()는 패스워드 암호화 함수다. 데이터 암호화 표준(Data Encryption Standard) 알고리즘을 바탕으로 하드웨어 구현 키 탐색을 어렵게 하기 위한 등의 변경을 해서 쓴다.

key는 사용자가 입력한 패스워드다.

salt[a-zA-Z0-9./] 집합에서 고른 두 문자로 된 문자열이다. 이 문자열을 사용해 4096가지 방식 중 하나로 알고리즘에 변화를 준다.

key의 처음 여덟 글자 각각에서 하위 7비트를 뽑아서 56비트 키를 얻는다. 이 56비트 키를 사용해 상수 열(일반적으로 모두 0으로 된 열)을 반복적으로 암호화한다. 그 암호화된 패스워드를 반환 값이 가리키는데, 출력 가능한 ASCII 문자 13개로 된 열이다. (그 중 처음 두 문자는 그대로 솔트를 나타낸다.) 반환 값이 정적 데이터를 가리키므로 매 호출마다 그 내용을 덮어 쓴다.

경고: 키 공간을 이루는 값들이 2**56 개, 즉 7.2e16 개다. 대규모 병렬 컴퓨터를 쓰면 이 키 공간 전체를 전수 검색하는 게 가능하다. 또 crack(1) 같은 소프트웨어는 이 키 공간에서 사람들이 패스워드에 많이 쓰는 부분을 검색한다. 따라서 패스워드를 선정할 때 적어도 흔한 단어나 이름은 피해야 한다. 그리고 선정 과정에서 깰 수 있는 패스워드인지 검사해 주는 passwd(1) 프로그램을 사용하기를 권한다.

DES 알고리즘 자체에 있는 몇 가지 특이성 때문에 crypt() 인터페이스를 패스워드 인증 외의 용도에 쓰는 건 좋지 않은 선택이다. 혹시 암호 관련 프로젝트에 crypt()를 사용할 계획이라면 생각을 바꿔야 한다. 암호화에 대한 괜찮은 책을 하나 읽어 보고 널리 쓰이는 DES 라이브러리들 중 하나를 찾아 보라.

crypt_r()crypt()의 재진입 가능 버전이다. data가 가리키는 구조체를 사용해 결과 데이터와 내부용 정보를 저장한다. 호출자가 이 구조체를 할당하는 것 외에 추가해 해 줄 일은 처음 crypt_r()를 호출하기 전에 data->initialized를 0으로 설정하는 것이다.

RETURN VALUE

성공 시 암호화된 패스워드를 반환한다. 오류 시 NULL을 반환한다.

ERRORS

EINVAL
salt가 잘못된 형식이다.
ENOSYS
crypt() 함수가 구현돼 있지 않다. 미국 수출 규제 때문일 수 있다.
EPERM
/proc/sys/crypto/fips_enabled에 0 아닌 값이 있는데 DES 같은 약한 방식 암호화를 사용하려는 시도가 이뤄졌다.

ATTRIBUTES

이 절에서 사용하는 용어들에 대한 설명은 attributes(7)를 보라.

인터페이스 속성
crypt() 스레드 안전성 MT-Unsafe race:crypt
crypt_r() 스레드 안전성 MT-Safe

CONFORMING TO

crypt(): POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.

crypt_r()은 GNU 확장이다.

NOTES

glibc에서 사용 가능 여부

crypt(), encrypt(3), setkey(3) 함수는 POSIX.1-2008 XSI Options Group for Encryption의 일부이며 선택적이다. 이 인터페이스들이 사용 가능하지 않은 경우에는 심볼 상수 _XOPEN_CRYPT가 정의돼 있지 않거나 -1로 정의돼 있으며, 런타임에는 sysconf(3)로 사용 가능 여부를 확인할 수 있다. 배포판에서 glibc의 crypt를 libxcrypt로 전환한 경우가 여기 해당할 수 있다. 그런 배포판에서 응용을 다시 컴파일할 때 프로그래머는 _XOPEN_CRYPT가 사용 가능한지 확인해서 아니면 함수 원형을 위해 <crypt.h>를 포함시켜야 한다. 사용 가능하지 않은 경우 libxcrypt가 ABI 호환 대체물이 되어 준다.

glibc에서의 기능들

이 함수의 glibc 버전에서는 다른 암호화 알고리즘들을 추가로 지원한다.

salt$id$로 시작해서 그 뒤에 선택적으로 "$"로 끝나는 문자열이 오는 경우에는 결과가 다음 형태가 된다.

$id$salt$encrypted

id는 DES 대신 쓰는 암호화 방식을 나타내며 이 값이 패스워드 문자열 나머지를 어떻게 해석해야 하는지 결정한다. 다음 id 값을 지원한다.

ID 방법
1 MD5
2a 블로피시 (glibc 메인라인에 없음. 일부 리눅스 배포판에서 추가)
5 SHA-256 (glibc 2.7부터)
6 SHA-512 (glibc 2.7부터)

그래서 $5$salt$encrypted$6$salt$encrypted는 각각 SHA-256과 SHA-512 기반 함수로 암호화한 패스워드를 담는다.

"salt"는 솔트에서 "$id$" 다음에 오는 최대 16개 문자를 나타낸다. 그리고 패스워드 문자열의 "encrypted" 부분은 실제 계산된 패스워드다. 이 문자열의 크기는 고정돼 있다.

MD5 22 문자
SHA-256 43 문자
SHA-512 86 문자

"salt"와 "encrypted"의 문자들은 [a-zA-Z0-9./] 집합에서 고른다. MD5 및 SHA 구현에서는 (DES에서처럼 처음 8바이트가 아니라) key 전체를 계산에 쓴다.

glibc 2.7부터 SHA-256 및 SHA-512 구현에서 해싱 라운드 수를 사용자가 지정할 수 있으며 기본은 5000번이다. 솔트의 "$id$" 다음에 "rounds=xxx$"가 오면 (xxx는 정수) 결과가 다음 형태가 된다.

$id$rounds=yyy$salt$encrypted

여기서 yyy는 실제 적용된 해싱 라운드 수다. 실제 적용된 라운드 수는 xxx가 1000보다 작은 경우에는 1000이고, xxx가 999999999보다 큰 경우에는 999999999이고, 그 외에는 xxx와 같다.

SEE ALSO

login(1), passwd(1), encrypt(3), getpass(3), passwd(5)


2021-03-22