ASP.NET Core의 컨텍스트 헤더

배경 및 이론

데이터 보호 시스템에서 "키"는 인증된 암호화 서비스를 제공할 수 있는 개체를 의미합니다. 각 키는 고유 ID(GUID)로 식별되며 알고리즘 정보와 entropic 자료를 통해 전달됩니다. 각 키가 고유한 엔트로피를 전달하지만 시스템에서 이를 적용할 수 없으며, 키 링에 있는 기존 키의 알고리즘 정보를 수정하여 키 링을 수동으로 변경할 수 있는 개발자도 고려해야 합니다. 이러한 경우 보안 요구 사항을 충족하기 위해 데이터 보호 시스템에는 여러 암호화 알고리즘에서 단일 entropic 값을 안전하게 사용할 수 있는 암호화 민첩성이라는 개념이 있습니다.

암호화 민첩성을 지원하는 대부분의 시스템은 페이로드 내에 알고리즘에 대한 일부 식별 정보를 포함하여 이 작업을 수행합니다. 일반적으로 알고리즘의 OID는 이에 적합한 후보입니다. 그러나 직면한 한 가지 문제는 동일한 알고리즘을 지정하는 여러 가지 방법이 있습니다. 즉, "AES"(CNG) 및 관리되는 Aes, AesManaged, AesCryptoServiceProvider, AesCng 및 RijndaelManaged(지정된 특정 매개 변수) 클래스는 모두 실제로 동일한 작업을 수행하며, 이러한 모든 항목의 매핑을 올바른 OID로 유지해야 합니다. 개발자가 사용자 지정 알고리즘(또는 다른 AES 구현)을 제공하려는 경우 해당 OID를 알려주세요. 이 추가 등록 단계를 수행하면 시스템 구성이 특히 어려워집니다.

이전 단계에서 문제에 대해 잘못된 방향으로 접근하고 있다고 결정했습니다. OID를 통해 알고리즘이 무엇인지 알 수 있지만 실제로는 신경쓰지 않습니다. 서로 다른 두 알고리즘에서 단일 entropic 값을 안전하게 사용해야 하는 경우 알고리즘이 실제로 무엇인지 알 필요가 없습니다. 실제로 중요한 것은 어떻게 동작하냐는 것입니다. 적절한 대칭 블록 암호화 알고리즘은 강력한 PRP(pseudorandom permutation)이기도 합니다. 입력(키, 체인 모드, IV, 일반 텍스트)을 수정하면 암호 텍스트 출력은 동일한 입력이 지정된 다른 대칭 블록 암호화 알고리즘과 크게 다르지 않습니다. 마찬가지로, 적절한 키 지정 해시 함수는 강력한 PRF(pseudorandom 함수)이기도 하며, 고정된 입력 세트가 지정되며 해당 출력은 다른 키 지정 해시 함수와 크게 구별됩니다.

이 강력한 PRP 및 PRF 개념을 사용하여 컨텍스트 헤더를 빌드합니다. 이 컨텍스트 헤더는 기본적으로 지정된 작업에 사용되는 알고리즘에 대한 안정적인 지문 역할을 하며, 데이터 보호 시스템에 필요한 암호화 민첩성을 제공합니다. 이 헤더는 재현할 수 있으며 나중에 하위 키 파생 프로세스의 일부로 사용됩니다. 기본 알고리즘의 작업 모드에 따라 컨텍스트 헤더를 빌드하는 두 가지 다른 방법이 있습니다.

CBC 모드 암호화 + HMAC 인증

컨텍스트 헤더는 다음 구성 요소로 구성됩니다.

  • [16비트] 값 00 00은 "CBC 암호화 + HMAC 인증"을 의미하는 마커입니다.

  • [32비트] 대칭 블록 암호화 알고리즘의 키 길이(바이트, 빅 endian)입니다.

  • [32비트] 대칭 블록 암호화 알고리즘의 블록 크기(바이트, 빅 endian)입니다.

  • [32비트] HMAC 알고리즘의 키 길이(바이트, 빅 endian)입니다. (현재 키 크기는 항상 다이제스트 크기와 일치합니다.)

  • [32비트] HMAC 알고리즘의 다이제스트 크기(바이트, 빅 endian)입니다.

  • EncCBC(K_E, IV, "")는 빈 문자열 입력이 지정된 대칭 블록 암호화 알고리즘의 출력입니다. 여기서 IV는 모두 0 벡터입니다. K_E의 구성은 아래에 설명되어 있습니다.

  • MAC(K_H, "")는 빈 문자열 입력이 지정된 HMAC 알고리즘의 출력입니다. K_H의 구성은 아래에 설명되어 있습니다.

이상적으로, K_EK_H에 대해 모두 0인 벡터를 전달할 수 있습니다. 그러나 기본 알고리즘에서 작업(특히 DES 및 3DES)을 수행하기 전에 약한 키의 존재 여부를 확인하는 상황을 방지하는 것이 좋습니다. 이 경우에는 0이 아닌 벡터와 같은 단순하거나 반복 가능한 패턴을 사용하지 않습니다.

대신 길이가 0인 키, 레이블, 컨텍스트와 기본 PRF로 HMACSHA512를 통해 카운터 모드(NIST SP800-108, Sec. 5.1 참조)에 NIST SP800-108 KDF를 사용합니다. 출력의 | K_E | + | K_H |바이트를 파생시킨 다음, 결과를 K_EK_H 자체로 분해합니다. 수학적으로 다음과 같이 표시됩니다.

( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")

예: AES-192-CBC + HMACSHA256

예를 들어 대칭 블록 암호화 알고리즘이 AES-192-CBC이고 유효성 검사 알고리즘이 HMACSHA256인 경우를 고려해 보세요. 시스템은 다음 단계를 사용하여 컨텍스트 헤더를 생성합니다.

먼저 ( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")를 지정합니다. 여기서 | K_E | = 192 bits| K_H | = 256 bits는 지정된 알고리즘에 따라 다릅니다. 아래 예제에서 K_E = 5BB6..21DDK_H = A04A..00A9로 이어집니다.

5B B6 C9 83 13 78 22 1D 8E 10 73 CA CF 65 8E B0
61 62 42 71 CB 83 21 DD A0 4A 05 00 5B AB C0 A2
49 6F A5 61 E3 E2 49 87 AA 63 55 CD 74 0A DA C4
B7 92 3D BF 59 90 00 A9

다음으로, 위와 같이 IV = 0*K_E가 지정된 AES-192-CBC에 대한 Enc_CBC (K_E, IV, "")를 계산합니다.

result := F474B1872B3B53E4721DE19C0841DB6F

그런 다음, 위와 같이 K_H가 지정된 HMACSHA256에 대한 MAC(K_H, "")를 계산합니다.

result := D4791184B996092EE1202F36E8608FA8FBD98ABDFF5402F264B1D7211536220C

이렇게 하면 아래의 전체 컨텍스트 헤더가 생성됩니다.

00 00 00 00 00 18 00 00 00 10 00 00 00 20 00 00
00 20 F4 74 B1 87 2B 3B 53 E4 72 1D E1 9C 08 41
DB 6F D4 79 11 84 B9 96 09 2E E1 20 2F 36 E8 60
8F A8 FB D9 8A BD FF 54 02 F2 64 B1 D7 21 15 36
22 0C

이 컨텍스트 헤더는 인증된 암호화 알고리즘 쌍(AES-192-CBC 암호화 + HMACSHA256 유효성 검사)의 지문입니다. 위의에 설명된 구성 요소는 다음과 같습니다.

  • 마커 (00 00)

  • 블록 암호화 키 길이 (00 00 00 18)

  • 블록 암호화 블록 크기 (00 00 00 10)

  • HMAC 키 길이 (00 00 00 20)

  • HMAC 다이제스트 크기 (00 00 00 20)

  • 블록 암호화 PRP 출력 (F4 74 - DB 6F)

  • HMAC PRF 출력 (D4 79 - end).

참고 항목

CBC 모드 암호화 + HMAC 인증 컨텍스트 헤더는 알고리즘 구현이 Windows CNG 또는 관리되는 SymmetricAlgorithm 및 KeyedHashAlgorithm 유형에 따라 제공되는지 여부에 관계없이 동일한 방식으로 빌드됩니다. 이를 통해 다른 운영 체제에서 실행되는 애플리케이션은 OS 간에 알고리즘의 구현이 서로 다른 경우에도 동일한 컨텍스트 헤더를 안정적으로 생성할 수 있습니다. (실제로는 KeyedHashAlgorithm이 반드시 적합한 HMAC일 필요는 없으며, 키 지정 해시 알고리즘 형식도 가능합니다.)

예: 3DES-192-CBC + HMACSHA1

먼저 ( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")를 지정합니다. 여기서 | K_E | = 192 bits| K_H | = 160 bits는 지정된 알고리즘에 따라 다릅니다. 아래 예제에서 K_E = A219..E2BBK_H = DC4A..B464로 이어집니다.

A2 19 60 2F 83 A9 13 EA B0 61 3A 39 B8 A6 7E 22
61 D9 F8 6C 10 51 E2 BB DC 4A 00 D7 03 A2 48 3E
D1 F7 5A 34 EB 28 3E D7 D4 67 B4 64

다음으로, 위와 같이 IV = 0*K_E가 지정된 3DES-192-CBC에 대한 Enc_CBC (K_E, IV, "")를 계산합니다.

result := ABB100F81E53E10E

그런 다음, 위와 같이 K_H가 지정된 HMACSHA1에 대한 MAC(K_H, "")를 계산합니다.

result := 76EB189B35CF03461DDF877CD9F4B1B4D63A7555

이렇게 하면 아래와 같이 인증된 암호화 알고리즘 쌍(3DES-192-CBC 암호화 + HMACSHA1 유효성 검사)의 지문이 되는 전체 컨텍스트 헤더가 생성됩니다.

00 00 00 00 00 18 00 00 00 08 00 00 00 14 00 00
00 14 AB B1 00 F8 1E 53 E1 0E 76 EB 18 9B 35 CF
03 46 1D DF 87 7C D9 F4 B1 B4 D6 3A 75 55

구성 요소는 다음과 같이 구분됩니다.

  • 마커 (00 00)

  • 블록 암호화 키 길이 (00 00 00 18)

  • 블록 암호화 블록 크기 (00 00 00 08)

  • HMAC 키 길이 (00 00 00 14)

  • HMAC 다이제스트 크기 (00 00 00 14)

  • 블록 암호화 PRP 출력 (AB B1 - E1 0E)

  • HMAC PRF 출력 (76 EB - end).

Galois/Counter 모드 암호화 + 인증

컨텍스트 헤더는 다음 구성 요소로 구성됩니다.

  • [16비트] 값 00 01은 "GCM 암호화 + 인증"을 의미하는 마커입니다.

  • [32비트] 대칭 블록 암호화 알고리즘의 키 길이(바이트, 빅 endian)입니다.

  • [32비트] 인증된 암호화 작업 중에 사용되는 nonce 크기(바이트, 빅 endian)입니다. (시스템의 경우 nonce 크기 = 96비트로 고정됩니다.)

  • [32비트] 대칭 블록 암호화 알고리즘의 블록 크기(바이트, 빅 endian)입니다. (GCM의 경우 블록 크기 = 128비트로 고정됩니다.)

  • [32비트] 인증된 암호화 함수에 의해 생성된 인증 태그 크기(바이트, 빅 endian)입니다. (시스템의 경우 태그 크기 = 128비트로 고정됩니다.)

  • [128비트] Enc_GCM (K_E, nonce, "")의 태그는 빈 문자열 입력이 지정된 대칭 블록 암호화 알고리즘의 출력입니다. 여기서 nonce는 96비트의 모두 0 벡터입니다.

K_E는 CBC 암호화 + HMAC 인증 시나리오와 동일한 메커니즘을 사용하여 파생됩니다. 그러나 여기에는 K_H가 없으므로 기본적으로 | K_H | = 0가 있고 알고리즘은 아래 형태로 축소됩니다.

K_E = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")

예: AES-256-GCM

먼저 | K_E | = 256 bits에서 K_E = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")를 사용해 봅니다.

K_E := 22BC6F1B171C08C4AE2F27444AF8FC8B3087A90006CAEA91FDCFB47C1B8733B8

그런 다음, 위와 같이 nonce = 096K_E가 제공된 AES-256-GCM에 대한 Enc_GCM (K_E, nonce, "")의 인증 태그를 계산합니다.

result := E7DCCE66DF855A323A6BB7BD7A59BE45

이렇게 하면 아래의 전체 컨텍스트 헤더가 생성됩니다.

00 01 00 00 00 20 00 00 00 0C 00 00 00 10 00 00
00 10 E7 DC CE 66 DF 85 5A 32 3A 6B B7 BD 7A 59
BE 45

구성 요소는 다음과 같이 구분됩니다.

  • 마커 (00 01)

  • 블록 암호화 키 길이 (00 00 00 20)

  • nonce 크기 (00 00 00 0C)

  • 블록 암호화 블록 크기 (00 00 00 10)

  • 인증 태그 크기 (00 00 00 10)

  • 블록 암호화 (E7 DC - end)를 실행하는 인증 태그.