AES-CTR एचएमएसी स्ट्रीमिंग AEAD

यह दस्तावेज़ औपचारिक रूप से गणित के उस फ़ंक्शन के बारे में बताता है जिसे AES-CTR एचएमएसी स्ट्रीमिंग कुंजियों (type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey के रूप में प्रोटो फ़ॉर्मैट में एन्कोड किया गया) से दिखाया जाता है.

एन्क्रिप्ट (सुरक्षित) करने का यह तरीका, [HRRV15]1 पर आधारित नहीं है. सुरक्षा का विश्लेषण करने के लिए, हम [HS20]2 को देखते हैं. ध्यान दें कि Tink क्रॉस लैंग्वेज टेस्ट में aes_ctr_hmac_streaming_key_test.py टेस्ट किया जाता है. इसमें test_manually_created_test_vector शामिल है, जिसमें साइफ़रटेक्स्ट पाने के तरीके के बारे में सिलसिलेवार तरीके से बताया गया है.

कुंजी और पैरामीटर

कुंजियों की जानकारी नीचे दिए गए हिस्सों में दी गई है (इस दस्तावेज़ में सभी साइज़ बाइट में हैं):

  • \(\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{Msg}\) उससे जुड़े डेटा के साथ एन्क्रिप्ट (सुरक्षित) करने के लिए\(\mathrm{AssociatedData}\), हम एक हेडर बनाते हैं, मैसेज को सेगमेंट में बांटते हैं, हर सेगमेंट को एन्क्रिप्ट करते हैं, और सेगमेंट को जोड़ते हैं. इन चरणों के बारे में नीचे बताया गया है.

हेडर बनाना

हेडर बनाने के लिए, हम पहले \(\mathrm{Salt}\) लंबाई \(\mathrm{DerivedKeySize}\)की एक रैंडम स्ट्रिंग चुनते हैं. इसके बाद, हम 7 लंबाई की \(\mathrm{NoncePrefix}\) एक रैंडम स्ट्रिंग चुनते हैं.

इसके बाद, हम \(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\)को सेट करते हैं, जहां हेडर की लंबाई को एक बाइट में एन्कोड किया जाता है. हम समझते हैं कि \(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\).

इसके बाद, हम हैश-फ़ंक्शन \(\mathrm{HkdfHashType}\)के साथ HKDF3 का इस्तेमाल करते हैं, ताकि लंबाई के मुख्य कॉन्टेंट की गिनती की जा सके \(\mathrm{DerivedKeySize} + 32\) इस मैसेज के लिए: \(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\). इनपुट का इस्तेमाल, \(\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}\) कोड में बदला जाता है. अगर $i < n-1$ और 0x01, बाइट को 0x00 पर सेट नहीं किया जाता है, तो बाइट $b$ को 0x00 पर सेट किया जाएगा.

इसके बाद, हम \(M_i\) AES सीटीआर कुंजी \(k_1\)और इनिशलाइज़ेशन वेक्टर\(\mathrm{IV}_i\)का इस्तेमाल करके, एन्क्रिप्ट (सुरक्षित) करते हैं. दूसरे शब्दों में, AES को शुरू करने के लिए इनपुट वे होते हैं \(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\) जहां \(\mathrm{IV}_i\) को बिग-एंडियन पूर्णांक के तौर पर दिखाया जाता है. इससे \(C'_i\)मिलता है.

हम एचएमएसी का इस्तेमाल करके, उस हैश फ़ंक्शन का इस्तेमाल करते हैं जो \(\mathrm{HmacHashType}\) और स्ट्रिंग जोड़ने की प्रोसेस के ऊपर कुंजी \(k_2\) का इस्तेमाल करता है \(\mathrm{IV}_i \| C'_i\).

इसके बाद, हम एन्क्रिप्ट (सुरक्षित) किए गए टेक्स्ट को एन्क्रिप्ट करने के बाद, टैग के बाद \(C_i\)को जोड़ते हैं.

सेगमेंट को जोड़ें

आखिर में, सभी सेगमेंट को\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\)के तौर पर जोड़ा जाता है, जो कि फ़ाइनल सादे टेक्स्ट है.

डिक्रिप्शन फ़ंक्शन

डिक्रिप्शन सिर्फ़ एन्क्रिप्शन को बदल देता है. हम हेडर का इस्तेमाल नॉन्स पाने के लिए करते हैं और साइफ़रटेक्स्ट के हर सेगमेंट को अलग-अलग डिक्रिप्ट करते हैं.

एपीआई, फ़ाइल के आखिर में जांच किए बिना ही रैंडम ऐक्सेस या फ़ाइल की शुरुआत में ऐक्सेस दे सकते हैं (और आम तौर पर ऐसा करते हैं). यह जान-बूझकर किया गया है, क्योंकि पिछले और बाकी बचे सभी साइफ़रटेक्स्ट ब्लॉक को डिक्रिप्ट किए बिना, \(M_i\) इन्हें \(C_i\)डिक्रिप्ट किया जा सकता है.

हालांकि, एपीआई को इस बात का ध्यान रखना चाहिए कि उपयोगकर्ता, फ़ाइल के एंड-एंड और डिक्रिप्शन की गड़बड़ी होने के बारे में गुमराह न हों. दोनों मामलों में, हो सकता है कि एपीआई को गड़बड़ी का जवाब देना पड़े. अंतर को अनदेखा करने से, कोई विरोधी फ़ाइल को सही तरीके से छोटा कर सकता है.

कुंजियों को सीरियल में बनाना और पार्स करना

किसी कुंजी को "Tink Proto" फ़ॉर्मैट में क्रम से लगाने के लिए, हम सबसे पहले aes_ctr_hmac_streaming.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 या पिछली वैल्यू सेट हो सकती है.

किसी कुंजी को पार्स करने के लिए, हम ऊपर दी गई प्रक्रिया को उलट देते हैं (प्रोटो को पार्स करते समय सामान्य तरीके से). key_material_type फ़ील्ड को अनदेखा किया जाता है. output_prefix_type की वैल्यू को अनदेखा किया जा सकता है या RAW से output_prefix_type अलग वाली कुंजियों को अस्वीकार किया जा सकता है. जिन कुंजियों के version 0 से अलग होते हैं उन्हें अस्वीकार कर दिया जाता है.

References


  1. [HRRV15] होआंग, रेहानिटाबार, रोगवे, विज़ार. ऑनलाइन प्रमाणित करने के तरीके को सुरक्षित करना और उसे दोबारा इस्तेमाल करने से रोकने में मदद मिलती है. क्रिप्टो करंसी 2015. https://eprint.iacr.org/2015/189 

  2. [HS20] Google की Tink लाइब्रेरी में स्ट्रीमिंग एन्क्रिप्शन की सुरक्षा. होआंग, शेन, 2020. https://eprint.iacr.org/2020/1019 

  3. [HKDF] एचएमएसी-आधारित एक्स्ट्रैक्ट-और-एक्सपैंड की डेरिवेशन फ़ंक्शन (HKDF), RFC 5869. https://www.rfc-editor.org/rfc/rfc5869