/* * strcrypt.h - STRCrypt C FFI Header * * 이 헤더는 libstrcrypt.so의 C ABI 함수를 선언합니다. * RDBMS 통합용 C 래퍼(shim)에서 사용됩니다. * * 빌드: * cargo build --release * -> target/release/libstrcrypt.so * * 메모리 관리: * 반환된 모든 char* 포인터는 free_encrypted_string()으로 해제해야 합니다. * strcrypt_*_ex()와 strcrypt_*_batch() 함수의 오류 문자열은 strcrypt_free_error()로 해제합니다. * strcrypt_*_batch() 함수의 결과 블록은 strcrypt_free_batch()로 해제합니다. * 데이터 키 컨텍스트 함수(strcrypt_ctx_*, strcrypt_dek_*, strcrypt_master_kek_id)와 strcrypt_search_index_compute 의 오류 문자열은 * strcrypt_free_error()로, 결과 블록은 strcrypt_free_batch()로, 핸들은 strcrypt_ctx_free()로 해제합니다. * char*를 반환하는 함수에서 NULL 반환은 오류를 의미합니다. */ #ifndef STRCRYPT_H #define STRCRYPT_H #include #include #ifdef __cplusplus extern "C" { #endif /* ======================================================================== * 기본 암호화/복호화 * ======================================================================== */ /* * 문자열을 헤더 없는 레거시 형식(KcmvpApproved: ARIA-256-GCM, NonApproved: AES-256-GCM)으로 * 암호화하고 Base64로 반환합니다. * * input: NULL-terminated UTF-8 문자열 * 반환: Base64 인코딩된 암호문 (caller가 free_encrypted_string으로 해제) * 실패 시 NULL */ char *encrypt_string(const char *input); /* * Base64 인코딩된 암호문을 복호화합니다. * 암호문 헤더에서 알고리즘을 자동 감지합니다. * * base64_input: Base64 인코딩된 암호문 * 반환: 복호화된 UTF-8 문자열 (caller가 free_encrypted_string으로 해제) * 실패 시 NULL */ char *decrypt_string(const char *base64_input); /* ======================================================================== * 알고리즘 선택 암호화/복호화 * ======================================================================== */ /* * 지정된 알고리즘으로 문자열을 암호화합니다. * * input: NULL-terminated UTF-8 문자열 * algorithm: 알고리즘 이름 ("aegis128l", "aegis256", "aes256gcm", * "aes256gcmsiv", "aria256gcm", "ascon128", "seed128gcm", "lea128gcm") * NULL이면 헤더 없는 레거시 형식으로 암호화 * (KcmvpApproved: ARIA-256-GCM, NonApproved: AES-256-GCM) * 반환: Base64 인코딩된 암호문 (caller가 free_encrypted_string으로 해제) * 실패 시 NULL */ char *encrypt_string_with_algorithm(const char *input, const char *algorithm); /* * 지정된 알고리즘으로 복호화합니다. * * base64_input: Base64 인코딩된 암호문 * algorithm: 알고리즘 이름 (NULL이면 헤더에서 자동 감지) * 반환: 복호화된 UTF-8 문자열 (caller가 free_encrypted_string으로 해제) * 실패 시 NULL */ char *decrypt_string_with_algorithm(const char *base64_input, const char *algorithm); /* ======================================================================== * AAD(추가 인증 데이터) 지원 * ======================================================================== */ /* * AAD와 함께 헤더 없는 레거시 형식(KcmvpApproved: ARIA-256-GCM, NonApproved: AES-256-GCM)으로 * 암호화합니다. * * input: NULL-terminated UTF-8 문자열 * aad: 추가 인증 데이터 바이트 배열 (aad_len이 0일 때만 NULL 허용) * aad_len: AAD 길이 (바이트) */ char *encrypt_string_with_aad(const char *input, const unsigned char *aad, size_t aad_len); /* * AAD와 함께 복호화합니다. 헤더가 없으면 현재 동작 모드의 레거시 알고리즘을 사용합니다. * * base64_input: Base64 인코딩된 암호문 * aad: 암호화 시 사용한 것과 동일한 AAD * aad_len: AAD 길이 (바이트) */ char *decrypt_string_with_aad(const char *base64_input, const unsigned char *aad, size_t aad_len); /* * 지정된 알고리즘과 AAD로 암호화합니다. */ char *encrypt_string_with_algorithm_and_aad(const char *input, const char *algorithm, const unsigned char *aad, size_t aad_len); /* * 지정된 알고리즘과 AAD로 복호화합니다. * algorithm이 NULL이면 자동 감지. */ char *decrypt_string_with_algorithm_and_aad(const char *base64_input, const char *algorithm, const unsigned char *aad, size_t aad_len); /* ======================================================================== * 유틸리티 * ======================================================================== */ /* * 하드웨어 가속 정보를 JSON으로 반환합니다. * 예: {"aes_ni":true,"pclmulqdq":true,"platform":"x86_64"} */ char *hardware_info(void); /* * 지원 알고리즘 목록을 JSON 배열로 반환합니다. * 예: ["aes256gcm","aria256gcm","ascon128","aegis128l","aegis256","aes256gcmsiv","seed128gcm","lea128gcm"] */ char *supported_algorithms(void); /* * 위 함수들이 반환한 char* 메모리를 해제합니다. * NULL 전달 시 무시합니다. */ void free_encrypted_string(void *ptr); /* ======================================================================== * 확장 API (오류 출력 파라미터 버전) * ======================================================================== */ /* * 오류 메시지를 out_error로 반환하는 확장 암호화 함수. * * input: NULL-terminated UTF-8 문자열 * algorithm: 알고리즘 이름 (NULL이면 헤더 없는 레거시 형식: * KcmvpApproved ARIA-256-GCM, NonApproved AES-256-GCM) * out_error: 오류 시 오류 메시지 포인터가 설정됨 (strcrypt_free_error로 해제) * 성공 시 *out_error = NULL * 반환: 성공 시 Base64 암호문 (free_encrypted_string으로 해제) * 실패 시 NULL */ char *strcrypt_encrypt_ex(const char *input, const char *algorithm, char **out_error); /* * 오류 메시지를 out_error로 반환하는 확장 복호화 함수. * * input: Base64 인코딩된 암호문 * algorithm: 알고리즘 이름 (NULL이면 자동 감지) * out_error: 오류 시 오류 메시지 포인터가 설정됨 (strcrypt_free_error로 해제) * 성공 시 *out_error = NULL * 반환: 성공 시 복호화된 UTF-8 문자열 (free_encrypted_string으로 해제) * 실패 시 NULL */ char *strcrypt_decrypt_ex(const char *input, const char *algorithm, char **out_error); /* * out_error 로 받은 오류 문자열(strcrypt_*_ex, 배치, 데이터 키 컨텍스트 함수)을 해제합니다. * NULL 전달 시 무시합니다. */ void strcrypt_free_error(char *ptr); /* ======================================================================== * 대량 배치 API * * 입력 배열 한 번을 레코드마다 암복호화해 결과를 한 블록으로 돌려준다. 원소 결과는 스칼라 함수와 * 같은 형식이라 서로 복호화된다(암호화 원소는 헤더형 암호문의 Base64, 표준 알파벳·패딩 포함·줄바꿈 없음). * * 입력 규칙 * inputs[i], input_lens[i]: 포인터+길이 레코드. NUL 종료가 필요 없다. * inputs[i] == NULL 이고 길이 0 -> SQL NULL 로 보고 원소 길이 0 을 돌려준다(오류 아님). * 호출자가 자기 입력으로 NULL 과 빈 문자열을 구분한다. * inputs[i] == NULL 이고 길이 > 0 -> STRCRYPT_E_ARGUMENT * inputs[i] != NULL 이고 길이 0 -> 암호화는 빈 평문을 암호화, 복호화는 STRCRYPT_E_INVALID_INPUT * count == 0 이면 inputs·input_lens 는 NULL 이어도 된다. 사전조건(초기화·키·알고리즘 허용)은 수행한다. * aads == NULL 이면 모든 레코드에 AAD 가 없고 aad_lens 를 읽지 않는다. aads != NULL 이면 * aad_lens 도 NULL 이 아니어야 하고, aads[i] 는 aad_lens[i] 가 0 일 때만 NULL 을 허용한다. * inputs[i] == NULL 인 위치의 AAD 는 읽지 않는다. AAD 없음과 길이 0 AAD 는 같은 계산이다. * 길이 값은 PTRDIFF_MAX 이하여야 하고, 암호화 결과 합계도 그 이하여야 한다(넘으면 STRCRYPT_E_ARGUMENT). * * 스레드(threads) * threads 는 1 이상이어야 한다. 0 은 STRCRYPT_E_ARGUMENT 이다(0 을 CPU 코어 수로 해석하는 * Rust EncryptionContext::with_thread_pool 과 다르다). * threads == 1 이거나 count 가 50 미만이면 풀을 만들지 않고 호출 스레드에서 입력 순서로 처리한다. * 그 밖에는 min(threads, 사용 가능 CPU 수)개 스레드로 이 호출 안에서만 쓰는 풀을 만들고, * 반환하기 전에 모든 스레드가 끝날 때까지 기다린다. 풀 스레드는 모든 시그널이 막힌 채 시작하며 * DB API 를 부르지 않는다. 호출 스레드의 시그널 마스크는 호출 전 값으로 돌아온다. * RAYON_NUM_THREADS 는 이 함수에 영향이 없고, 상주 스레드나 전역 풀을 두지 않는다. * DB 서버 프로세스에서는 threads = 1 을 기본으로 둔다. * * 반환 코드와 출력 인자 * 함수는 진입 즉시 *out 을 읽지 않고 빈 결과(포인터 NULL·길이 0)로, *out_error_index 를 SIZE_MAX 로, * *out_error 를 NULL 로 덮어쓴다(out_error_index·out_error 는 NULL 을 허용한다). 이전 성공 결과를 * 담은 구조체를 다시 넘기기 전에 strcrypt_free_batch() 로 해제한다. * STRCRYPT_OK 이면 out->count == count, out->data_len == lens 합계이고 *out_error 는 NULL 이다. * 그 밖의 코드이면 *out 은 빈 결과이고(부분 결과 없음) *out_error 에 오류 문구(UTF-8, 평문·키·AAD 를 * 담지 않음. strcrypt_free_error 로 해제)가 설정된다. 라이브러리는 문구 길이를 자르지 않는다. * *out_error_index 는 레코드를 처리하다 난 오류이면 실패한 레코드 중 가장 작은 인덱스(0 부터)이고, * 인자 검사·사전조건·풀 생성·panic 오류이면 SIZE_MAX 이다. 최소 인덱스는 threads 와 무관하다. * 검사 순서: 출력 인자 초기화 -> out NULL -> 배열 NULL·threads 0·알고리즘 이름 -> 원소 순서로 * NULL 원소 길이·크기 한도 -> 사전조건(초기화·동작 모드의 알고리즘 허용·키 로드) -> 풀 생성 -> 레코드. * ======================================================================== */ typedef struct strcrypt_batch_result { uint8_t *data; /* 라이브러리 할당. 원소 결과를 입력 순서로 이어 붙인다(NUL 없음). data_len == 0 이면 NULL */ size_t data_len; /* data 바이트 수 */ size_t *lens; /* 원소 길이 count 개. count == 0 이면 NULL */ size_t count; /* 원소 수 */ } strcrypt_batch_result; /* * 반환 코드 * STRCRYPT_OK 성공 * STRCRYPT_E_INVALID_INPUT 레코드 데이터: Base64 형식, UTF-8 위반, NUL 포함, 빈 암호문 * STRCRYPT_E_AUTH 레코드 데이터: 인증 실패(키·AAD 불일치, 변조) * STRCRYPT_E_TOO_LONG 레코드 데이터: 평문 또는 AAD 가 알고리즘 길이 한도 초과 * STRCRYPT_E_ARGUMENT 호출 인자 오류(코드 수정) * STRCRYPT_E_KEY 설정: 키 로드 실패(설정 수정 후 프로세스 재시작) * STRCRYPT_E_NOT_APPROVED 설정: 현재 동작 모드가 허용하지 않는 알고리즘 * STRCRYPT_E_MODULE 프로세스: 모듈 상태 이상, 자가시험 실패, 스레드 풀 생성 실패 등(재시작) * STRCRYPT_E_PANIC 프로세스: 라이브러리 내부 panic 포착(재시작) * 레코드 데이터 오류만 같은 입력을 레코드 단위로 격리할 수 있다. 자동 재시도로 성공하는 코드는 없다. */ #define STRCRYPT_OK 0 #define STRCRYPT_E_INVALID_INPUT 1 #define STRCRYPT_E_AUTH 2 #define STRCRYPT_E_TOO_LONG 3 #define STRCRYPT_E_ARGUMENT 10 #define STRCRYPT_E_KEY 20 #define STRCRYPT_E_NOT_APPROVED 21 #define STRCRYPT_E_MODULE 30 #define STRCRYPT_E_PANIC 31 /* * UTF-8 평문 레코드 배열을 algorithm 으로 암호화한다. * * inputs[i]: NUL 이 없는 UTF-8 평문 input_lens[i] 바이트(위반은 STRCRYPT_E_INVALID_INPUT) * algorithm: 알고리즘 이름(NULL 불가. 헤더 없는 레거시 형식은 만들지 않는다) * 출력 원소: 헤더형 암호문의 Base64 텍스트 */ int32_t strcrypt_encrypt_batch( const char *const *inputs, const size_t *input_lens, size_t count, const unsigned char *const *aads, const size_t *aad_lens, const char *algorithm, uint32_t threads, strcrypt_batch_result *out, size_t *out_error_index, char **out_error); /* * Base64 암호문 레코드 배열을 복호화한다. 레코드마다 헤더에서 알고리즘을 감지하고, 헤더가 없으면 * 현재 동작 모드의 레거시 알고리즘을 쓰므로 헤더형·레거시 암호문이 섞인 배열을 한 번에 처리한다. * * inputs[i]: Base64 텍스트 input_lens[i] 바이트 * 출력 원소: NUL 이 없는 UTF-8 평문(결과가 UTF-8 이 아니거나 NUL 을 포함하면 STRCRYPT_E_INVALID_INPUT) */ int32_t strcrypt_decrypt_batch( const char *const *inputs, const size_t *input_lens, size_t count, const unsigned char *const *aads, const size_t *aad_lens, uint32_t threads, strcrypt_batch_result *out, size_t *out_error_index, char **out_error); /* * 배치 함수의 결과 블록을 해제한다. data 전체를 0 으로 지운 뒤 해제하고 모든 필드를 NULL·0 으로 * 되돌린다. NULL, 실패한 호출의 결과, 이미 해제한 결과를 넘겨도 안전하다. 필드를 바꾼 구조체는 넘기지 않는다. */ void strcrypt_free_batch(strcrypt_batch_result *out); /* ======================================================================== * 데이터 키(DEK) 컨텍스트 API * * 키 보유 주체(고객사·사용자·시스템)마다 따로 두는 데이터 키로 레코드를 암복호화한다. * 감싼 DEK 는 마스터 키(STRCRYPT_KEY_FILE·STRCRYPT_KEY)로 데이터 키를 감싼 83 또는 99바이트 값이며 * 비밀이 아니라 데이터 옆에 저장해도 된다. 평문 데이터 키는 돌려주지 않고 핸들만 만든다. * 형식·binding 인코딩 규칙·동작 모드·마스터 키 교체 절차는 docs/KEY_MANAGEMENT.md 와 Rust 문서 * (strcrypt::dek 모듈)에 있다. SQL 함수로는 노출하지 않는다. * * 인자 * 바이트 인자(포인터 + 길이)는 길이가 0 이면 포인터를 읽지 않고 빈 값으로 본다(NULL 허용). * 포인터가 NULL 인데 길이가 0 보다 크면 STRCRYPT_E_ARGUMENT 이다. 길이는 PTRDIFF_MAX 이하여야 한다. * binding 은 1바이트 이상 65,536바이트 이하인 호출자 문맥(용도·주체)이다. 감싼 값에 저장하지 않으므로 * 풀 때 만들 때와 같은 값을 준다. * algorithm 은 NULL 을 받지 않는 알고리즘 이름이다(대량 배치 API 와 같은 이름, 예: "aria256gcm"). * 출력 포인터 인자(out_ctx, out, out_algorithm 등)는 NULL 을 받지 않는다. out_error 와 out_error_index 는 * NULL 이어도 된다. * * 출력 인자 * 함수는 진입 즉시 출력 인자를 읽지 않고 빈 값(포인터 NULL·길이 0·식별자 0)으로, *out_error 를 NULL 로 * 덮어쓴다. 실패하면 출력 인자는 빈 값이고 *out_error 에 오류 문구가 설정된다(strcrypt_free_error 로 해제). * 오류 문구에는 키·binding·경로·평문·AAD 를 넣지 않는다. * * 핸들(strcrypt_ctx) * strcrypt_ctx_new_wrapped()·strcrypt_ctx_new_raw() 가 만들고 strcrypt_ctx_free() 로 해제한다. 핸들 안의 * 키는 해제할 때 소거된다. 같은 핸들을 여러 스레드에서 동시에 써도 된다. 다른 스레드가 쓰는 중에 해제하거나 * 두 번 해제하면 정의되지 않은 동작이다(C 의 free 와 같다). 핸들은 스레드 풀을 갖지 않는다. * 핸들로 만든 암호문은 헤더형([알고리즘 식별자 1B][nonce][암호문][tag])이고, 핸들 복호화는 헤더형만 받는다. * 첫 바이트가 핸들 알고리즘의 식별자가 아니면 STRCRYPT_E_AUTH 이다. 헤더 없는 레거시 암호문은 받지 않는다. * * 사용량 한계 * ARIA-256-GCM·SEED-128-GCM·LEA-128-GCM·AES-256-GCM 핸들은 키마다 암호화 호출을 센다. 같은 키로 핸들을 * 다시 만들어도 카운터는 이어진다. 한 프로세스에서 한 키가 2^32-1 회에 닿으면 그 키의 암호화는 * STRCRYPT_E_MODULE 이고 복호화는 계속된다. 이때는 새 데이터 키로 교체한다. 카운터는 이 프로세스 * 메모리에만 있어 재시작·여러 프로세스·fork 자식에 걸친 누적은 합쳐지지 않는다. 호출자가 데이터 키별 * 암호화 건수를 모든 프로세스에 걸쳐 누계하거나, 건수·처리량·기간 기준으로 데이터 키를 교체한다. * * 라이브러리 인스턴스 * 핸들·결과 블록·오류 문자열은 그것을 만든 라이브러리 인스턴스의 함수로만 해제한다. 한 프로세스에 * libstrcrypt 와 언어 바인딩 모듈(Python·Node.js·Java)을 함께 로드하면 마스터 키 캐시와 사용량 카운터가 * 인스턴스마다 따로 생긴다. * * 반환 코드(위 STRCRYPT_* 상수의 이 절 함수에서의 뜻) * STRCRYPT_E_ARGUMENT NULL·길이 규칙 위반, threads 0, binding 길이, 알 수 없는 알고리즘, 원시 키 길이 * 불일치, 새 마스터 키가 현재 마스터 키와 같음, 같은 키를 다른 알고리즘으로 이미 씀 * STRCRYPT_E_INVALID_INPUT 감싼 DEK 형식 오류(식별자·버전·알고리즘·길이), 레코드 데이터 오류 * STRCRYPT_E_AUTH 감싼 DEK 인증 실패(binding 불일치·변조), KEK 식별자 불일치(감싼 값을 감싼 마스터 * 키가 현재 마스터 키와 다름. 마스터 키 교체 중이면 값마다 생길 수 있고, 모든 값이 * 이 코드이면 STRCRYPT_KEY_FILE·STRCRYPT_KEY 설정이 틀렸을 수 있다), 레코드 인증 실패 * STRCRYPT_E_KEY 마스터 키가 없거나 읽지 못함, 생성할 때 현재 마스터 키가 키 강도 검사를 통과하지 * 못함, 재감싸기의 새 마스터 키 파일 오류(권한·읽기·내용·형식·길이·키 강도) * STRCRYPT_E_NOT_APPROVED 현재 동작 모드가 허용하지 않는 알고리즘(NonApproved 에서 만든 감싼 DEK 를 * KcmvpApproved 에서 풀거나 재감쌀 때 포함) * STRCRYPT_E_MODULE 사용량 한계, 모듈 상태 이상, 스레드 풀 생성 실패 등 * ======================================================================== */ /* 불투명 컨텍스트 핸들. */ typedef struct strcrypt_ctx strcrypt_ctx; /* * 감싼 DEK 를 현재 마스터 키로 풀어 핸들을 만든다. 알고리즘은 감싼 값이 정한다. 모듈을 초기화해 * STRCRYPT_MODE 를 반영한 뒤 마스터 키를 읽는다. 마스터 키 강도 검사는 하지 않는다. * 검사 순서: 인자 -> 형식 -> 모듈 상태·동작 모드 -> 마스터 키 -> KEK 식별자 -> 인증. */ int32_t strcrypt_ctx_new_wrapped(const uint8_t *wrapped, size_t wrapped_len, const uint8_t *binding, size_t binding_len, strcrypt_ctx **out_ctx, char **out_error); /* * 외부 키 관리 서비스가 준 평문 데이터 키로 핸들을 만든다. 마스터 키를 읽지 않는다. * key_len 은 algorithm 의 키 길이와 정확히 같아야 한다(32바이트: aria256gcm·aes256gcm·aes256gcmsiv· * aegis256, 16바이트: seed128gcm·lea128gcm·aegis128l·ascon128). 알고리즘 이름을 먼저 해석하므로 두 오류가 * 함께 있으면 알 수 없는 알고리즘 오류다. * 키 취급 의무 * - 라이브러리는 호출자의 key 버퍼를 소거하지 않는다. 반환 직후 호출자가 0 으로 덮어쓴다(컴파일러가 * 지우지 못하도록 explicit_bzero 같은 함수를 쓴다). 호출자 쪽에서 이미 만든 사본은 그래도 남는다. * - 신뢰하는 키 관리 서비스가 준 키만 넣는다. GCM 계열 암호문은 key-committing 이 아니라, 공격자가 알거나 * 고른 키가 들어오면 한 암호문이 여러 키로 복호화되게 만들 수 있다. * - 비밀번호에서 파생한 키는 넣지 않는다. * - 같은 키를 마스터 키(STRCRYPT_KEY·STRCRYPT_KEY_FILE)나 키 래핑 KEK 등 다른 경로에 함께 쓰지 않는다. * 사용량 한도가 따로 세어진다. * - 같은 키를 다른 알고리즘으로 넣으면 STRCRYPT_E_ARGUMENT 이다. 키 하나는 알고리즘 하나에만 쓴다. * - 서로 다른 키마다 약 100바이트가 프로세스 수명 동안 남는다. */ int32_t strcrypt_ctx_new_raw(const uint8_t *key, size_t key_len, const char *algorithm, strcrypt_ctx **out_ctx, char **out_error); /* 핸들을 해제하고 핸들 안의 키를 소거한다. NULL 은 무시한다. */ void strcrypt_ctx_free(strcrypt_ctx *ctx); /* * 바이트 레코드 배열을 핸들의 키·알고리즘으로 암호화한다(레코드별 AAD). * * inputs[i], input_lens[i]: 평문 원시 바이트(NUL 종료 불필요, UTF-8·NUL 검사 없음). NULL 이고 길이 0 이면 * 빈 평문이다(SQL NULL 이 아니다). * aads, aad_lens: count > 0 이면 NULL 을 받지 않는다(레코드마다 AAD 가 있고, 원소는 빈 값이어도 된다). * aads[i] 는 aad_lens[i] 가 0 일 때만 NULL 을 허용한다. * count == 0 이면 배열 인자는 모두 NULL 이어도 되고, 사전조건만 확인한 뒤 빈 결과를 돌려준다. * threads: 대량 배치 API 와 같은 규칙이다(1 이상, 1 이거나 count 가 50 미만이면 풀 없이 호출 스레드에서 * 처리, 그 밖에는 min(threads, 사용 가능 CPU 수)개 스레드로 이 호출 안에서만 쓰는 풀). * 출력 원소: 헤더형 이진 암호문(Base64 아님). 결과는 strcrypt_free_batch() 로 해제한다. * *out_error_index 는 레코드를 처리하다 난 오류이면 실패한 레코드 중 가장 작은 인덱스이고 그 밖에는 SIZE_MAX 다. * 검사 순서: 출력 인자 초기화 -> out NULL -> ctx NULL·배열 NULL·threads 0 -> 원소 순서로 NULL 원소 길이· * 크기 한도 -> 사전조건(모듈 상태·현재 동작 모드의 핸들 알고리즘 허용) -> 풀 생성 -> 레코드. */ int32_t strcrypt_ctx_encrypt_batch(const strcrypt_ctx *ctx, const uint8_t *const *inputs, const size_t *input_lens, size_t count, const uint8_t *const *aads, const size_t *aad_lens, uint32_t threads, strcrypt_batch_result *out, size_t *out_error_index, char **out_error); /* * 헤더형 이진 암호문 배열을 핸들로 복호화한다(레코드별 AAD). 출력 원소는 평문 원시 바이트다. * encrypted[i] 가 NULL 이고 길이 0 이면 빈 암호문이라 STRCRYPT_E_INVALID_INPUT 과 그 인덱스다. * 그 밖의 인자·스레드·출력·검사 순서 규칙은 strcrypt_ctx_encrypt_batch 와 같다. */ int32_t strcrypt_ctx_decrypt_batch(const strcrypt_ctx *ctx, const uint8_t *const *encrypted, const size_t *encrypted_lens, size_t count, const uint8_t *const *aads, const size_t *aad_lens, uint32_t threads, strcrypt_batch_result *out, size_t *out_error_index, char **out_error); /* * 새 데이터 키(algorithm 의 키 길이 난수)를 만들어 현재 마스터 키로 감싼 값을 *out 에 쓴다. 평문 데이터 키는 * 돌려주지 않는다. 감싸기 알고리즘은 현재 동작 모드가 정한다(KcmvpApproved ARIA-256-GCM, NonApproved * AES-256-GCM). 성공하면 out->count == 1 이고 out->lens[0] == out->data_len 은 83 또는 99 이다. 결과는 * strcrypt_free_batch() 로 해제한다. */ int32_t strcrypt_dek_generate(const uint8_t *binding, size_t binding_len, const char *algorithm, strcrypt_batch_result *out, char **out_error); /* * 감싼 DEK 를 새 마스터 키 파일의 키로 다시 감싼다(마스터 키 교체). 데이터 키 알고리즘·감싸기 알고리즘· * binding 은 유지한다. 감싼 값이 이미 새 키로 감싼 것이면 새 키로 검증만 하고 입력과 같은 값을 돌려준다. * new_master_key_file: NUL 로 끝나는 UTF-8 경로(NULL·빈 문자열·UTF-8 위반은 STRCRYPT_E_ARGUMENT, Windows ANSI * 코드 페이지 경로는 받지 않는다). 권한 0600 의 줄바꿈 없는 한 줄 키 파일이어야 하고 호출마다 읽는다. * 결과 규칙은 strcrypt_dek_generate 와 같다. 형식 오류와 키 파일 오류가 함께 있으면 형식 오류를 보고한다. */ int32_t strcrypt_dek_rewrap(const uint8_t *wrapped, size_t wrapped_len, const uint8_t *binding, size_t binding_len, const char *new_master_key_file, strcrypt_batch_result *out, char **out_error); /* * 감싼 DEK 를 파싱만 해서 데이터 키 알고리즘 이름, 감싸기 알고리즘 이름, KEK 식별자 16바이트를 쓴다. 키와 * 모듈 초기화가 필요 없고 동작 모드와 무관하다. 두 이름은 라이브러리 정적 문자열이라 해제하지 않는다. * 형식 버전 1 만 조회하고 그 밖의 형식은 STRCRYPT_E_INVALID_INPUT 이다. */ int32_t strcrypt_dek_info(const uint8_t *wrapped, size_t wrapped_len, const char **out_algorithm, const char **out_wrap_algorithm, uint8_t out_kek_id[16], char **out_error); /* * 현재 마스터 키의 KEK 식별자(16바이트, 비밀 아님)를 쓴다. strcrypt_dek_info 의 식별자와 비교해 현재 마스터 * 키로 풀 값을 고른다. 모듈을 초기화해 STRCRYPT_MODE 를 반영한 뒤 마스터 키를 읽는다. */ int32_t strcrypt_master_kek_id(uint8_t out_kek_id[16], char **out_error); /* * 현재 마스터 키로 값의 검색 인덱스 32바이트를 쓴다. 암호화한 열의 같은 값 검색에 쓰는 결정적 값이다. * 인덱스 = HMAC-SHA256(KBKDF-CTR-HMAC-SHA256(마스터 키, "STRCrypt search index v1", domain, 256비트), value). * 마스터 키는 32바이트보다 짧으면 뒤를 0 으로 채운 32바이트다. * 같은 마스터 키·domain·value 면 언어와 DB 에 무관하게 같고, 동작 모드와도 무관하다. domain 은 열을 구분하는 * 1~256바이트 문자열이고, value 는 value_len 이 0 이면 NULL 일 수 있다. 같은 값을 가진 행끼리 인덱스가 같으므로 * 값의 일치와 빈도가 드러나고, 이 함수를 부를 수 있으면 후보 값을 넣어 맞춰 볼 수 있다. 실패하면 out_index 를 0 으로 * 채운다. */ int32_t strcrypt_search_index_compute(const uint8_t *value, size_t value_len, const uint8_t *domain, size_t domain_len, uint8_t out_index[32], char **out_error); #ifdef __cplusplus } #endif #endif /* STRCRYPT_H */