ENCRYPT_RAW

ENCRYPT_RAW

ENCRYPT_RAW는 BINARY 키를 사용해 BINARY 값을 암호화하는 암호화 함수예요. 키와 초기화 벡터(IV), 선택적으로 추가 인증 데이터(AAD)를 직접 지정해 암호화할 때 사용해요.

출처: Snowflake SQL Reference

본문

카테고리: 암호화 함수

구문 (Syntax)

ENCRYPT_RAW( <value_to_encrypt> , <key> , <iv> ,
         [ [ <additional_authenticated_data> , ] <encryption_method> ]
       )

인자 (Arguments)

필수:

<value_to_encrypt> — 암호화할 이진 값이에요.

<key> — 데이터를 암호화/복호화하는 데 사용하는 키예요. 키는 BINARY 값이어야 해요. 키는 길이만 맞으면 어떤 값이든 될 수 있어요. 예를 들어 AES128의 경우 키는 128비트(16바이트), AES256의 경우 키는 256비트(32바이트)여야 해요.

값을 암호화하는 데 사용한 키는 값을 복호화하는 데 사용해야 해요.

<iv> — 이 파라미터는 이 데이터를 암호화·복호화하는 데 사용할 초기화 벡터(IV)를 담아요. IV는 특정 길이의 BINARY 값이어야 해요:

  • GCM의 경우 96비트(12바이트)여야 해요. GCM 암호화 방식은 이 필드를 다른 크기로도 허용하지만, Snowflake는 현재 96비트만 지원해요.
  • CCM의 경우 56비트(7바이트)여야 해요.
  • ECB의 경우 이 파라미터가 필요 없어요.
  • 그 외 지원되는 암호화 모드에서는 128비트(16바이트)여야 해요.

이 값은 첫 번째 암호화 라운드를 초기화하는 데 사용돼요. 특히 GCM 같은 암호화 모드에서는 같은 IV와 키 조합을 두 번 이상 사용하면 안 돼요.

이 파라미터가 NULL로 설정되면 구현은 매 호출마다 새 의사 난수 IV를 선택해요.

선택:

<additional_authenticated_data> — 추가 인증 데이터(AAD)는 복호화 과정에서 기밀성과 진위가 보장되는 추가 데이터예요. 하지만 이 AAD는 암호화되지 않으며, ENCRYPT 또는 ENCRYPT_RAW 함수의 반환 값의 필드로 포함되지도 않아요.

AAD가 암호화 함수(ENCRYPT 또는 ENCRYPT_RAW)에 전달되면, 같은 AAD가 복호화 함수(DECRYPT 또는 DECRYPT_RAW)에도 전달되어야 해요. 복호화 함수에 전달된 AAD가 암호화 함수에 전달된 AAD와 일치하지 않으면 복호화는 실패해요.

AAD와 passphrase의 차이점은, passphrase는 비밀로 유지하려는 반면(그렇지 않으면 암호화가 사실상 무의미해져요) AAD는 공개로 남겨둘 수 있다는 거예요. AAD는 공개 정보 조각과 암호화 값이 서로 연결되어 있음을 인증하는 데 도움을 줘요. ENCRYPT 함수의 예시 섹션에는 AAD가 일치할 때와 일치하지 않을 때의 동작을 보여주는 예시가 있어요.

ENCRYPT_RAW와 DECRYPT_RAW의 경우 AAD의 데이터 타입은 BINARY여야 해요. ENCRYPT와 DECRYPT의 경우 AAD의 데이터 타입은 VARCHAR 또는 BINARY일 수 있으며, 암호화된 값의 데이터 타입과 일치할 필요는 없어요.

AAD는 GCM(기본값) 같은 AEAD 지원 암호화 모드에서만 지원돼요.

<encryption_method> — 데이터를 암호화/복호화하는 데 사용할 방법을 지정하는 문자열이에요. 이 문자열은 하위 필드를 담아요:

<algorithm>-<mode> [ /pad: <padding> ]

algorithm은 현재 다음으로 제한돼요:

  • 'AES': passphrase가 전달되면(예: ENCRYPT에) 함수는 AES-256 암호화(256비트)를 사용해요. 키가 전달되면(예: ENCRYPT_RAW에) 함수는 키 길이에 따라 128, 192, 또는 256비트 암호화를 사용해요.

algorithm은 대소문자를 구분하지 않아요.

mode는 메시지를 암호화하는 데 사용할 블록 암호 모드를 지정해요. 다음 표는 지원되는 모드와 그 중 패딩을 지원하는 모드를 보여줘요:

모드 패딩 설명
'ECB' 예 키로 각 블록을 개별적으로 암호화. 이 모드는 일반적으로 권장되지 않으며 외부 구현과의 호환성을 위해서만 포함됨.
'CBC' 예 암호화된 블록이 이전 블록과 XOR됨.
'GCM' 아니요 Galois/Counter Mode는 AEAD 지원이 되는 고성능 암호화 모드. AEAD는 AEAD 태그를 생성해 암호화된 데이터의 진위와 기밀성을 추가로 보장. 또한 AEAD는 AAD(추가 인증 데이터)를 지원.
'CTR' 아니요 카운터 모드.
'OFB' 아니요 출력 피드백. 암호문이 블록의 평문과 XOR됨.
'CFB' 아니요 암호 피드백은 OFB와 CBC의 결합.

mode는 대소문자를 구분하지 않아요.

padding은 블록 크기의 배수가 아닌 길이의 메시지를 어떻게 패딩할지 지정해요. 패딩은 ECB와 CBC 모드에만 적용되며, 다른 모드에서는 무시돼요. 패딩의 가능한 값:

  • 'PKCS': 블록 패딩에 PKCS5를 사용해요.
  • 'NONE': 패딩 없음. ECB 또는 CBC 모드를 사용할 때는 사용자가 패딩을 직접 처리해야 해요.

padding은 대소문자를 구분하지 않아요.

기본 설정: 'AES-GCM'. mode를 지정하지 않으면 GCM이 사용돼요. padding을 지정하지 않으면 PKCS가 사용돼요.

반환값 (Returns)

암호화된 값을 반환해요. 반환되는 값의 데이터 타입은 VARIANT예요.

단일 값 하나만 반환되지만, 그 값은 두세 개의 필드를 담아요:

  • 첫 번째 필드는 초기화 벡터(IV)예요. 암호화와 복호화 모두 IV를 사용해요.
  • 두 번째 필드는 value_to_encrypt의 암호문(암호화된 값)이에요.
  • 암호화 모드가 AEAD 지원이면, 반환 값에는 세 번째 필드인 AEAD 태그도 포함돼요.

IV와 태그 크기는 암호화 모드에 따라 달라져요. VARIANT 안의 세 필드는 모두 BINARY 타입이에요.

사용 시 유의사항 (Usage notes)

  • ENCRYPT()로 암호화한 데이터를 복호화하려면 DECRYPT()를 사용해요. DECRYPT_RAW()를 사용하지 마세요.
  • ENCRYPT_RAW()로 암호화한 데이터를 복호화하려면 DECRYPT_RAW()를 사용해요. DECRYPT()를 사용하지 마세요.
  • 함수의 파라미터는 보안을 위해 마스킹돼요. 다음 같은 민감 정보는 쿼리 로그에 보이지 않고 Snowflake에도 보이지 않아요:
    • 암호화 또는 복호화할 문자열 또는 이진 값.
    • passphrase 또는 키.
  • 이 함수들은 FIPS 호환 암호화 라이브러리를 사용해 암호화와 복호화를 효과적으로 수행해요.
  • 데이터를 복호화하는 데 사용하는 passphrase 또는 키는 그 데이터를 암호화하는 데 사용한 것과 같아야 해요.

예시 (Examples)

이 예시는 암호화와 복호화를 보여줘요.

가독성을 위해 BINARY_OUTPUT_FORMAT을 HEX로 설정해요:

ALTER SESSION SET BINARY_OUTPUT_FORMAT='HEX';

테이블을 만들고 로드해요.

주의: 이 예시를 단순화하기 위해 암호화/복호화 키를 암호화된 값과 함께 테이블에 저장해요. 이것은 안전하지 않아요. 키는 암호화된 데이터를 저장하는 테이블에 암호화되지 않은 값으로 절대 저장하면 안 돼요.

CREATE OR REPLACE TABLE binary_table (
    encryption_key BINARY,   -- DO NOT STORE REAL ENCRYPTION KEYS THIS WAY!
    initialization_vector BINARY(12), -- DO NOT STORE REAL IV'S THIS WAY!!
    binary_column BINARY,
    encrypted_binary_column VARIANT,
    aad_column BINARY);

INSERT INTO binary_table (encryption_key,
                          initialization_vector,
                          binary_column,
                          aad_column)
    SELECT SHA2_BINARY('NotSecretEnough', 256),
            SUBSTR(TO_BINARY(HEX_ENCODE('AlsoNotSecretEnough'), 'HEX'), 0, 12),
            TO_BINARY(HEX_ENCODE('Bonjour'), 'HEX'),
            TO_BINARY(HEX_ENCODE('additional data'), 'HEX')
    ;

암호화해요:

UPDATE binary_table SET encrypted_binary_column =
    ENCRYPT_RAW(binary_column,
        encryption_key,
        initialization_vector,
        aad_column,
        'AES-GCM');
+------------------------+-------------------------------------+
| number of rows updated | number of multi-joined rows updated |
|------------------------+-------------------------------------|
|                      1 |                                   0 |
+------------------------+-------------------------------------+

이것은 DECRYPT_RAW() 함수의 해당 호출을 보여줘요. 초기화 벡터(IV)는 암호화된 값에서 가져오므로, 초기화 벡터를 따로 저장할 필요가 없어요. 마찬가지로 AEAD 태그도 암호화된 값에서 읽어요.

주의: 이 예시를 단순화하기 위해 암호화/복호화 키를 암호화된 값과 함께 테이블에서 읽어요. 이것은 안전하지 않아요. 키는 암호화된 데이터를 저장하는 테이블에 암호화되지 않은 값으로 절대 저장하면 안 돼요.

SELECT 'Bonjour' as original_value,
       binary_column,
       hex_decode_string(to_varchar(binary_column)) as decoded,
       encrypted_binary_column,
       decrypt_raw(as_binary(get(encrypted_binary_column, 'ciphertext')),
                  encryption_key,
                  as_binary(get(encrypted_binary_column, 'iv')),
                  aad_column,
                  'AES-GCM',
                  as_binary(get(encrypted_binary_column, 'tag')))
           as decrypted,
       hex_decode_string(to_varchar(decrypt_raw(as_binary(get(encrypted_binary_column, 'ciphertext')),
                  encryption_key,
                  as_binary(get(encrypted_binary_column, 'iv')),
                  aad_column,
                  'AES-GCM',
                  as_binary(get(encrypted_binary_column, 'tag')))
                  ))
           as decrypted_and_decoded
    FROM binary_table;
+----------------+----------------+---------+---------------------------------------------+----------------+-----------------------+
| ORIGINAL_VALUE | BINARY_COLUMN  | DECODED | ENCRYPTED_BINARY_COLUMN                     | DECRYPTED      | DECRYPTED_AND_DECODED |
|----------------+----------------+---------+---------------------------------------------+----------------+-----------------------|
| Bonjour        | 426F6E6A6F7572 | Bonjour | {                                           | 426F6E6A6F7572 | Bonjour               |
|                |                |         |   "ciphertext": "CA2F4A383F6F55",           |                |                       |
|                |                |         |   "iv": "416C736F4E6F745365637265",         |                |                       |
|                |                |         |   "tag": "91F28FBC6A2FE9B213D1C44B8D75D147" |                |                       |
|                |                |         | }                                           |                |                       |
+----------------+----------------+---------+---------------------------------------------+----------------+-----------------------+

이전 예시는 긴 DECRYPT_RAW() 호출을 반복했어요. WITH 절을 사용해 반복을 줄일 수 있어요:

WITH
    decrypted_but_not_decoded as (
        decrypt_raw(as_binary(get(encrypted_binary_column, 'ciphertext')),
                      encryption_key,
                      as_binary(get(encrypted_binary_column, 'iv')),
                      aad_column,
                      'AES-GCM',
                      as_binary(get(encrypted_binary_column, 'tag')))
    )
SELECT 'Bonjour' as original_value,
       binary_column,
       hex_decode_string(to_varchar(binary_column)) as decoded,
       encrypted_binary_column,
       decrypted_but_not_decoded,
       hex_decode_string(to_varchar(decrypted_but_not_decoded))
           as decrypted_and_decoded
    FROM binary_table;
+----------------+----------------+---------+---------------------------------------------+---------------------------+-----------------------+
| ORIGINAL_VALUE | BINARY_COLUMN  | DECODED | ENCRYPTED_BINARY_COLUMN                     | DECRYPTED_BUT_NOT_DECODED | DECRYPTED_AND_DECODED |
|----------------+----------------+---------+---------------------------------------------+---------------------------+-----------------------|
| Bonjour        | 426F6E6A6F7572 | Bonjour | {                                           | 426F6E6A6F7572            | Bonjour               |
|                |                |         |   "ciphertext": "CA2F4A383F6F55",           |                           |                       |
|                |                |         |   "iv": "416C736F4E6F745365637265",         |                           |                       |
|                |                |         |   "tag": "91F28FBC6A2FE9B213D1C44B8D75D147" |                           |                       |
|                |                |         | }                                           |                           |                       |
+----------------+----------------+---------+---------------------------------------------+---------------------------+-----------------------+

더 알아보기