이 문서에서는 AES-CTR HMAC 스트리밍 키 (type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey
로 프로토 형식으로 인코딩됨)로 표현되는 수학 함수를 공식적으로 정의합니다.
이 암호화는 [HRRV15]1을 대략적으로 기반으로 합니다. 보안 분석은 [HS20]2를 참고하세요. 또한 Tink 교차 언어 테스트에는 암호문을 가져오는 방법에 관한 전체 워크스루가 포함된 test_manually_created_test_vector
가 포함된 테스트 aes_ctr_hmac_streaming_key_test.py가 있습니다.
키 및 매개변수
키는 다음 부분으로 설명됩니다 (이 문서의 모든 크기는 바이트 단위임).
- \(\mathrm{InitialKeyMaterial}\), 바이트 문자열: 초기 키 재료입니다.
- \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
- \(\mathrm{DerivedKeySize} \in \{16, 32\}\).
- \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).
- \(\mathrm{HmacHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).
- \(\mathrm{HmacTagSize} \in \mathbb{N}\).
유효한 키는 다음 속성도 충족합니다.
- \(\mathrm{len}(\mathrm{InitialKeyMaterial}) \geq \mathrm{DerivedKeySize}\).
- \(\mathrm{HmacHashType} = \mathrm{SHA1}\) 이면 \(\mathrm{HmacTagSize} \in \{10, \ldots, 20\}\).
- \(\mathrm{HmacHashType} = \mathrm{SHA256}\) 이면 \(\mathrm{HmacTagSize} \in \{10, \ldots, 32\}\).
- \(\mathrm{HmacHashType} = \mathrm{SHA512}\) 이면 \(\mathrm{HmacTagSize} \in \{10, \ldots, 64\}\).
- \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + \mathrm{HmacTagSize} + 8\) (나중에 설명하는 대로\(\mathrm{len}(\mathrm{Header}) + \mathrm{HmacTagSize}\) 와 같습니다).
이러한 속성을 충족하지 않는 키는 키가 파싱될 때 또는 상응하는 원시 값이 생성될 때 Tink에서 거부됩니다.
암호화 함수
연결된 데이터\(\mathrm{AssociatedData}\)가 있는 메시지 \(\mathrm{Msg}\) 를 암호화하려면 헤더를 만들고, 메시지를 세그먼트로 분할하고, 각 세그먼트를 암호화하고, 세그먼트를 연결합니다. 다음에서 이러한 단계를 설명합니다.
헤더 만들기
헤더를 만들려면 먼저 \(\mathrm{DerivedKeySize}\)길이의 \(\mathrm{Salt}\)균일한 무작위 문자열을 선택합니다. 다음으로 길이가 7인 균일한 무작위 문자열\(\mathrm{NoncePrefix}\) 을 선택합니다.
그런 다음 헤더 길이가 단일 바이트로 인코딩된\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\)를 설정합니다.\(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\)
다음으로 해시 함수 \(\mathrm{HkdfHashType}\)와 함께 HKDF3을 사용하여 이 메시지(\(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\))의 길이가\(\mathrm{DerivedKeySize} + 32\) 인 키 재료를 계산합니다. 입력은\(\mathrm{HKDF}\)의 상응하는 각 입력에 사용됩니다. \(\mathrm{InitialKeyMaterial}\) 은 \(\mathrm{ikm}\),\(\mathrm{Salt}\) 은 소금,\(\mathrm{AssociatedData}\) 은 \(\mathrm{info}\)로 사용됩니다.
그러면 문자열 \(k\) 이 두 부분 \(k_1 \| k_2 := k\)으로 나뉩니다. 예를 들어\(\mathrm{len}(k_1) = \mathrm{DerivedKeySize}\) 와 \(\mathrm{len}(k_2) = 32\)입니다.
메시지 분할
그런 다음 메시지 \(M\) 는 다음과 같이 여러 부분으로 나뉩니다. \(M = M_0 \| M_1 \| \cdots \| M_{n-1}\)
길이는 다음을 충족하도록 선택됩니다.
- \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{HmacTagSize}\}\).
- \(n > 1\)이면 \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{HmacTagSize}\}\)입니다.
- \(n > 1\)인 경우 \(M_{0}, \ldots, M_{n-2}\) 는 위의 제약 조건에 따라 최대 길이를 가져야 합니다.
이 분할에서 \(n\) 는 최대 \(2^{32}\)일 수 있습니다. 그렇지 않으면 암호화가 실패합니다.
블록 암호화
세그먼트 \(M_i\)를 암호화하려면 먼저\(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b \| 0x00000000\)를 계산합니다. 여기서 빅엔디언 인코딩을 사용하여 \(\mathrm{i}\) 를 4바이트로 인코딩하고, 바이트 $b$ 를 $i < n-1$인 경우 0x00
로, 그렇지 않은 경우에는 0x01
로 설정합니다.
그런 다음 AES CTR 키 \(k_1\)및 초기화 벡터\(\mathrm{IV}_i\)를 사용하여 \(M_i\) 를 암호화합니다. 즉, AES 호출의 입력은\(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\)이며 여기서 \(\mathrm{IV}_i\) 는 big-endian 정수로 해석됩니다. 그러면 \(C'_i\)이 생성됩니다.
\(\mathrm{HmacHashType}\) 에 의해 제공된 해시 함수와 연결된\(\mathrm{IV}_i \| C'_i\)에 대한 키 \(k_2\) 를 사용하여 HMAC를 통해 태그를 계산합니다.
그런 다음 암호문과 태그를 연결하여 \(C_i\)를 가져옵니다.
세그먼트 연결
마지막으로 모든 세그먼트가 최종 암호문인\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\)로 연결됩니다.
복호화 함수
복호화는 암호화를 반전시킵니다. 헤더를 사용하여 nonce를 가져오고 암호 텍스트의 각 세그먼트를 개별적으로 복호화합니다.
API는 무작위 액세스를 허용하거나 파일의 끝을 검사하지 않고 파일의 시작 부분에 액세스할 수 있습니다 (일반적으로 허용됨). 이는 이전의 모든 암호문 블록과 나머지 암호문 블록을 복호화하지 않고도 \(M_i\) \(C_i\)에서 \(M_i\) 를 복호화할 수 있기 때문에 의도적으로 설계된 것입니다.
그러나 API는 사용자가 파일 끝과 복호화 오류를 혼동하지 않도록 주의해야 합니다. 두 경우 모두 API는 오류를 반환해야 할 수 있으며 차이를 무시하면 공격자가 파일을 효과적으로 자르는 결과를 초래할 수 있습니다.
키의 직렬화 및 파싱
'Tink Proto' 형식으로 키를 직렬화하려면 먼저 매개변수를 명시적인 방식으로 aes_ctr_hmac_streaming.proto에 제공된 proto에 매핑합니다.
version
필드를 0으로 설정해야 합니다.
그런 다음 일반 프로토 직렬화를 사용하여 이를 직렬화하고 결과 문자열을 KeyData 프로토의 필드 값에 삽입합니다. type_url
필드를 type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey
로 설정합니다.
그런 다음 key_material_type
를 SYMMETRIC
로 설정하고 키 세트에 삽입합니다. 일반적으로 output_prefix_type
를 RAW
로 설정합니다. 단, 키가 output_prefix_type
에 다른 값이 설정된 상태로 파싱된 경우 Tink는 RAW
또는 이전 값을 쓸 수 있습니다.
키를 파싱하려면 위의 프로세스를 반대로 진행합니다 (proto를 파싱할 때 일반적인 방식). key_material_type
필드는 무시됩니다. output_prefix_type
값은 무시되거나 output_prefix_type
가 RAW
과 다른 키는 거부될 수 있습니다.
version
가 0과 다른 키는 거부됩니다.
참조
-
[HRRV15] 호앙, 레이한니타바르, 로가웨이, 비자르. 온라인 인증 암호화 및 nonce 재사용 오용 방지 CRYPTO 2015. https://eprint.iacr.org/2015/189 ↩
-
[HS20] Google Tink 라이브러리의 스트리밍 암호화 보안 Hoang, Shen, 2020. https://eprint.iacr.org/2020/1019 ↩
-
[HKDF] HMAC 기반 추출-확장 키 파생 함수 (HKDF), RFC 5869. https://www.rfc-editor.org/rfc/rfc5869 ↩