AES-CTR HMAC Streaming AEAD

این سند به طور رسمی تابع ریاضی نشان‌داده‌شده توسط کلیدهای جریانی AES-CTR HMAC را تعریف می‌کند (که در قالب پروتو به‌عنوان 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}\)انتخاب می کنیم. سپس یک رشته تصادفی یکنواخت\(\mathrm{NoncePrefix}\) به طول 7 را انتخاب می کنیم.

سپس\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\)تنظیم می کنیم، جایی که طول هدر به صورت یک بایت کدگذاری می شود. توجه می کنیم که\(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\).

در مرحله بعد، از HKDF 3 با تابع هش \(\mathrm{HkdfHashType}\)برای محاسبه مواد کلیدی به طول\(\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}\) در 4 بایت با استفاده از رمزگذاری big-endian رمزگذاری می کنیم، و اگر $i < n-1$ و 0x01 در غیر این صورت 0x00 باشد، بایت $b$ را 0x00 تنظیم می کنیم. .

سپس \(M_i\) با استفاده از کلید AES CTR \(k_1\)و بردار مقداردهی اولیه\(\mathrm{IV}_i\)رمزگذاری می کنیم. به عبارت دیگر، ورودی های فراخوانی های AES\(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\)هستند که در آن \(\mathrm{IV}_i\) به عنوان عدد صحیح بزرگ endian تفسیر می شود. این \(C'_i\)به دست می آورد.

ما تگ را با استفاده از HMAC با تابع هش ارائه شده توسط \(\mathrm{HmacHashType}\) و با کلید \(k_2\) بر روی الحاق\(\mathrm{IV}_i \| C'_i\)محاسبه می کنیم.

سپس متن رمز شده را با تگ به هم متصل می کنیم تا \(C_i\)بدست آوریم.

بخش ها را به هم متصل کنید

در نهایت، همه بخش‌ها به‌عنوان\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\)به هم متصل می‌شوند که متن رمز نهایی است.

عملکرد رمزگشایی

رمزگشایی به سادگی رمزگذاری را معکوس می کند. ما از هدر برای به دست آوردن nonce استفاده می کنیم و هر بخش از متن رمز شده را جداگانه رمزگشایی می کنیم.

APIها ممکن است (و معمولاً اجازه می دهند) دسترسی تصادفی یا دسترسی به ابتدای یک فایل را بدون بازرسی انتهای فایل مجاز کنند. این عمدی است، زیرا رمزگشایی \(M_i\) از \(C_i\)امکان پذیر است، بدون رمزگشایی تمام بلوک های متن رمز شده قبلی و باقی مانده.

با این حال، APIها باید مراقب باشند که به کاربران اجازه ندهند خطاهای انتهای فایل و رمزگشایی را با هم اشتباه بگیرند: در هر دو مورد، API احتمالاً باید یک خطا را برگرداند، و نادیده گرفتن تفاوت می‌تواند منجر به این شود که حریف بتواند به طور مؤثر فایل‌ها را کوتاه کند.

سریال سازی و تجزیه کلیدها

برای سریال سازی یک کلید در قالب "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 را می توان نادیده گرفت یا کلیدهایی را که output_prefix_type متفاوت از RAW دارند رد کرد. کلیدهایی که version متفاوت از 0 دارند رد می شوند.

منابع


  1. [HRRV15] Hoang، Reyhanitabar، Rogaway، Vizar. رمزگذاری آنلاین تأیید شده و عدم استفاده مجدد از آن، مقاومت در برابر استفاده نادرست. CRYPTO 2015. https://eprint.iacr.org/2015/189

  2. [HS20] امنیت رمزگذاری جریان در کتابخانه تینک گوگل. Hoang، Shen، 2020. https://eprint.iacr.org/2020/1019

  3. [HKDF] تابع مشتق کلید استخراج و بسط مبتنی بر HMAC (HKDF)، RFC 5869. https://www.rfc-editor.org/rfc/rfc5869