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، و بایت $b$ را 0x00
تنظیم کنید اگر $i < n-1$ و در غیر این صورت 0x01
باشد.
سپس رمزگذاری می کنیم \(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\) به عنوان عدد صحیح بزرگ اندین تفسیر می شود. این بازده \(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 دارند رد می شوند.
مراجع
جز در مواردی که غیر از این ذکر شده باشد،محتوای این صفحه تحت مجوز Creative Commons Attribution 4.0 License است. نمونه کدها نیز دارای مجوز Apache 2.0 License است. برای اطلاع از جزئیات، به خطمشیهای سایت Google Developers مراجعه کنید. جاوا علامت تجاری ثبتشده Oracle و/یا شرکتهای وابسته به آن است.
تاریخ آخرین بهروزرسانی 2025-07-25 بهوقت ساعت هماهنگ جهانی.
[[["درک آسان","easyToUnderstand","thumb-up"],["مشکلم را برطرف کرد","solvedMyProblem","thumb-up"],["غیره","otherUp","thumb-up"]],[["اطلاعاتی که نیاز دارم وجود ندارد","missingTheInformationINeed","thumb-down"],["بیشازحد پیچیده/ مراحل بسیار زیاد","tooComplicatedTooManySteps","thumb-down"],["قدیمی","outOfDate","thumb-down"],["مشکل ترجمه","translationIssue","thumb-down"],["مشکل کد / نمونهها","samplesCodeIssue","thumb-down"],["غیره","otherDown","thumb-down"]],["تاریخ آخرین بهروزرسانی 2025-07-25 بهوقت ساعت هماهنگ جهانی."],[[["\u003cp\u003eThis document defines the AES-CTR HMAC Streaming key and its mathematical function for encryption and decryption, loosely based on the HRRV15 and HS20 security analyses.\u003c/p\u003e\n"],["\u003cp\u003eThe encryption process involves creating a header, splitting the message into segments, encrypting each segment using AES CTR with a derived key, and concatenating the segments along with the header.\u003c/p\u003e\n"],["\u003cp\u003eKeys are described by parameters including InitialKeyMaterial, CiphertextSegmentSize, DerivedKeySize, HkdfHashType, HmacHashType, and HmacTagSize, with specific validity constraints.\u003c/p\u003e\n"],["\u003cp\u003eDecryption reverses the encryption process, allowing for potential random access to segments but requiring careful handling of end-of-file and decryption errors.\u003c/p\u003e\n"],["\u003cp\u003eSerialization and parsing of keys involve mapping parameters to a proto format, embedding them in a KeyData proto, and setting specific fields like type_url, key_material_type, and output_prefix_type.\u003c/p\u003e\n"]]],["AES-CTR HMAC Streaming keys define an encryption method involving key parameters like `InitialKeyMaterial`, `CiphertextSegmentSize`, `DerivedKeySize`, `HkdfHashType`, `HmacHashType`, and `HmacTagSize`. Encryption creates a header with a random salt and nonce prefix, derives key material using HKDF, and splits the message into segments. Each segment is encrypted using AES-CTR with a unique IV and HMAC tag, then concatenated to form the ciphertext. Decryption reverses this process. Keys are serialized into a specific proto format.\n"],null,["# AES-CTR HMAC Streaming AEAD\n\nThis document formally defines the mathematical function represented by\nAES-CTR HMAC Streaming keys (encoded in proto format as\n`type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey`).\n\nThis encryption is loosely based on \\[HRRV15\\]^[1](#fn1)^. For an analysis of the\nsecurity we refer to \\[HS20\\]^[2](#fn2)^. Note also that the Tink cross language tests\nhave a test\n[aes_ctr_hmac_streaming_key_test.py](https://github.com/google/tink/blob/master/testing/cross_language/streaming_aead/aes_ctr_hmac_streaming_key_test.py) which\ncontains `test_manually_created_test_vector` with a complete walkthrough on how\nto get a ciphertext.\n\nKey and parameters\n------------------\n\nKeys are described by the following parts (all sizes in this document are in\nbytes):\n\n- \\\\(\\\\mathrm{InitialKeyMaterial}\\\\), a byte string: the initial key material.\n- \\\\(\\\\mathrm{CiphertextSegmentSize} \\\\in \\\\{1, 2, \\\\ldots, 2\\^{31}-1\\\\}\\\\).\n- \\\\(\\\\mathrm{DerivedKeySize} \\\\in \\\\{16, 32\\\\}\\\\).\n- \\\\(\\\\mathrm{HkdfHashType} \\\\in \\\\{\\\\mathrm{SHA1}, \\\\mathrm{SHA256}, \\\\mathrm{SHA512}\\\\}\\\\).\n- \\\\(\\\\mathrm{HmacHashType} \\\\in \\\\{\\\\mathrm{SHA1}, \\\\mathrm{SHA256}, \\\\mathrm{SHA512}\\\\}\\\\).\n- \\\\(\\\\mathrm{HmacTagSize} \\\\in \\\\mathbb{N}\\\\).\n\nValid keys additionally satisfy the following properties:\n\n- \\\\(\\\\mathrm{len}(\\\\mathrm{InitialKeyMaterial}) \\\\geq \\\\mathrm{DerivedKeySize}\\\\).\n- If \\\\(\\\\mathrm{HmacHashType} = \\\\mathrm{SHA1}\\\\) then \\\\(\\\\mathrm{HmacTagSize} \\\\in \\\\{10, \\\\ldots, 20\\\\}\\\\).\n- If \\\\(\\\\mathrm{HmacHashType} = \\\\mathrm{SHA256}\\\\) then \\\\(\\\\mathrm{HmacTagSize} \\\\in \\\\{10, \\\\ldots, 32\\\\}\\\\).\n- If \\\\(\\\\mathrm{HmacHashType} = \\\\mathrm{SHA512}\\\\) then \\\\(\\\\mathrm{HmacTagSize} \\\\in \\\\{10, \\\\ldots, 64\\\\}\\\\).\n- \\\\(\\\\mathrm{CiphertextSegmentSize} \\\u003e \\\\mathrm{DerivedKeySize} + \\\\mathrm{HmacTagSize} + 8\\\\) (This equals \\\\(\\\\mathrm{len}(\\\\mathrm{Header}) + \\\\mathrm{HmacTagSize}\\\\) as explained later).\n\nKeys which do not satisfy any of these properties are rejected by Tink (either\nwhen the key is parsed or when the corresponding primitive is created).\n\nEncryption function\n-------------------\n\nTo encrypt a message \\\\(\\\\mathrm{Msg}\\\\) with associated data\n\\\\(\\\\mathrm{AssociatedData}\\\\), we create a header,\nsplit the message into segments, encrypt each segment, and concatenate\nthe segments. We explain these steps in the following.\n\n### Creating the header\n\nTo create the header, we first pick a uniform random string \\\\(\\\\mathrm{Salt}\\\\)\nof length \\\\(\\\\mathrm{DerivedKeySize}\\\\). We next pick a uniform random string\n\\\\(\\\\mathrm{NoncePrefix}\\\\) of length 7.\n\nWe then set\n\\\\(\\\\mathrm{Header} := \\\\mathrm{len}(\\\\mathrm{Header}) \\\\\\| \\\\mathrm{Salt} \\\\\\|\n\\\\mathrm{NoncePrefix}\\\\),\nwhere the length of the header is encoded as a single byte. We note that\n\\\\(\\\\mathrm{len}(\\\\mathrm{Header}) \\\\in \\\\{24, 40\\\\}\\\\).\n\nNext, we use HKDF^[3](#fn3)^ with hash-function \\\\(\\\\mathrm{HkdfHashType}\\\\)\nto compute key material of length\n\\\\(\\\\mathrm{DerivedKeySize} + 32\\\\) for this message:\n\\\\(k := \\\\mathrm{HKDF}(\\\\mathrm{InitialKeyMaterial}, \\\\mathrm{Salt},\n\\\\mathrm{AssociatedData})\\\\).\nThe inputs are used in the corresponding respective inputs of\n\\\\(\\\\mathrm{HKDF}\\\\): \\\\(\\\\mathrm{InitialKeyMaterial}\\\\) is \\\\(\\\\mathrm{ikm}\\\\),\n\\\\(\\\\mathrm{Salt}\\\\) is the salt, and\n\\\\(\\\\mathrm{AssociatedData}\\\\) is used as \\\\(\\\\mathrm{info}\\\\).\n\nThe string \\\\(k\\\\) is then split into two parts \\\\(k_1 \\\\\\| k_2 := k\\\\),\nsuch that\n\\\\(\\\\mathrm{len}(k_1) = \\\\mathrm{DerivedKeySize}\\\\) and \\\\(\\\\mathrm{len}(k_2) = 32\\\\).\n\n### Splitting the message\n\nThe message \\\\(M\\\\) is next split into parts: \\\\(M = M_0 \\\\\\| M_1 \\\\\\| \\\\cdots\n\\\\\\| M_{n-1}\\\\).\n\nTheir lengths are chosen so that they satisfy:\n\n- \\\\(\\\\mathrm{len}(M_0) \\\\in \\\\{0,\\\\ldots, \\\\mathrm{CiphertextSegmentSize} - \\\\mathrm{len}(\\\\mathrm{Header}) - \\\\mathrm{HmacTagSize}\\\\}\\\\).\n- If \\\\(n \\\u003e 1\\\\), then \\\\(\\\\mathrm{len}(M_1), \\\\ldots, \\\\mathrm{len}(M_{n-1}) \\\\in \\\\{1,\\\\ldots, \\\\mathrm{CiphertextSegmentSize} - \\\\mathrm{HmacTagSize}\\\\}\\\\).\n- If \\\\(n \\\u003e 1\\\\), then \\\\(M_{0}, \\\\ldots, M_{n-2}\\\\) must have maximal length according to the above to constraints.\n\nIn this splitting, \\\\(n\\\\) may at most be \\\\(2\\^{32}\\\\). Otherwise, encryption fails.\n\n### Encrypting the blocks\n\nTo encrypt segment \\\\(M_i\\\\), we first compute\n\\\\(\\\\mathrm{IV}_i := \\\\mathrm{NoncePrefix} \\\\\\| \\\\mathrm{i} \\\\\\| b \\\\\\| 0x00000000\\\\),\nwhere we encode \\\\(\\\\mathrm{i}\\\\) in 4\nbytes using big-endian encoding, and set the byte $b$ to be `0x00` if $i \\\u003c n-1$\nand `0x01` otherwise.\n\nWe then encrypt \\\\(M_i\\\\) using AES CTR key \\\\(k_1\\\\), and initialization vector\n\\\\(\\\\mathrm{IV}_i\\\\). In other words, the inputs to the invocations of AES are\n\\\\(\\\\mathrm{IV}_i, \\\\mathrm{IV}_i + 1, \\\\mathrm{IV}_i + 2, \\\\ldots\\\\)\nwhere \\\\(\\\\mathrm{IV}_i\\\\) is interpreted as big-endian integer.\nThis yields \\\\(C'_i\\\\).\n\nWe compute the tag using HMAC with the hash function given\nby \\\\(\\\\mathrm{HmacHashType}\\\\) and with key \\\\(k_2\\\\) over the concatenation\n\\\\(\\\\mathrm{IV}_i \\\\\\| C'_i\\\\).\n\nWe then concatenate the ciphertext followed by the tag to get \\\\(C_i\\\\).\n\n### Concatenate the segments\n\nFinally, all segments are concatenated as\n\\\\(\\\\mathrm{Header} \\\\\\| C_0 \\\\\\| \\\\cdots \\\\\\| C_{n-1}\\\\), which is the final ciphertext.\n\nDecryption function\n-------------------\n\nDecryption simply inverts the encryption. We use the header to obtain the nonce,\nand decrypt each segment of ciphertext individually.\n\nAPIs may (and typically do) allow random access, or access to the\nbeginning of a file without inspecting the end of the file. This is\nintentional, since it is possible to decrypt \\\\(M_i\\\\) from \\\\(C_i\\\\),\nwithout decrypting all previous and remaining ciphertext blocks.\n\nHowever, APIs should be careful to not allow users to confuse end-of-file and\ndecryption errors: in both cases the API probably has to return an error, and\nignoring the difference can lead to an adversary being able to effectively\ntruncate files.\n\nSerialization and parsing of keys\n---------------------------------\n\nTo serialize a key in the \"Tink Proto\" format, we first map the parameters\nin the obvious way into the proto given at\n[aes_ctr_hmac_streaming.proto](https://github.com/tink-crypto/tink-java/blob/main/proto/aes_ctr_hmac_streaming.proto).\nThe field `version` needs to be set to 0.\nWe then serialize this using normal proto serialization, and embed the resulting\nstring in the value of field of a\n[KeyData](https://github.com/tink-crypto/tink-java/blob/main/proto/tink.proto) proto. We set the `type_url` field\nto `type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey`.\nWe then set `key_material_type` to `SYMMETRIC`, and embed this into a keyset. We\nusually set the `output_prefix_type` to `RAW`. The exception is that if the key\nwas parsed with a different value set for `output_prefix_type`,\nTink may either write `RAW` or the previous value.\n\nTo parse a key, we reverse the above process (in the usual way when parsing\nprotos). The field `key_material_type` is ignored. The value of\n`output_prefix_type` can either be ignored, or keys which\nhave `output_prefix_type` different from `RAW` can be rejected.\nKeys which have a `version` different from 0 are be rejected.\n\nReferences\n----------\n\n*** ** * ** ***\n\n1. \\[HRRV15\\] Hoang, Reyhanitabar, Rogaway, Vizar. Online\n authenticated-encryption and its nonce-reuse misuse-resistance. CRYPTO 2015.\n \u003chttps://eprint.iacr.org/2015/189\u003e [↩](#fnref1)\n\n2. \\[HS20\\] Security of Streaming Encryption in Google's Tink Library.\n Hoang, Shen, 2020.\n \u003chttps://eprint.iacr.org/2020/1019\u003e [↩](#fnref2)\n\n3. \\[HKDF\\] HMAC-based Extract-and-Expand Key Derivation Function (HKDF),\n RFC 5869. \u003chttps://www.rfc-editor.org/rfc/rfc5869\u003e [↩](#fnref3)"]]