AES-GCM-HKDF جریان AEAD
با مجموعهها، منظم بمانید
ذخیره و طبقهبندی محتوا براساس اولویتهای شما.
این سند به طور رسمی تابع ریاضی نشاندادهشده توسط کلیدهای جریانی AES-GCM-HKDF را تعریف میکند که در قالب پروتو بهعنوان type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey
کدگذاری شدهاند.
این رمزگذاری بر اساس HRRV15 1 است. برای تجزیه و تحلیل امنیتی، به HS20 2 مراجعه می کنیم.
کلید و پارامترها
کلیدها با قسمت های زیر توصیف می شوند (همه اندازه های این سند بر حسب بایت هستند):
- \(\mathrm{KeyValue}\)، یک رشته بایت.
- \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
- \(\mathrm{DerivedKeySize} \in \{16, 32\}\).
- \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256},
\mathrm{SHA512}\}\).
کلیدهای معتبر علاوه بر این ویژگی های زیر را برآورده می کنند:
- \(\mathrm{len}(\mathrm{KeyValue}) \geq \mathrm{DerivedKeySize}\).
- \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + 24\) (این برابر است \(\mathrm{len}(\mathrm{Header}) + 16\) همانطور که بعدا توضیح داده شد).
کلیدهایی که هر یک از این ویژگیها را نقض میکنند توسط 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{ikm} := \mathrm{KeyValue}\)، \(\mathrm{salt} :=
\mathrm{Salt}\)، و \(\mathrm{info} := \mathrm{AssociatedData}\)، با طول خروجی \(\mathrm{DerivedKeySize}\). ما نتیجه را می نامیم \(\mathrm{DerivedKey}\).
پیام را تقسیم کنید
پیام \(\mathrm{Msg}\) در مرحله بعدی به بخش هایی تقسیم می شود: \(\mathrm{Msg} = M_0 \|
M_1 \| \cdots \| M_{n-1}\).
طول آنها برای برآوردن موارد زیر انتخاب شده است:
- \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} -
\mathrm{len}(\mathrm{Header}) - \mathrm{16}\}\).
- اگر \(n>1\)، سپس \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in
\{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{16}\}\).
- اگر \(n>1\)، سپس \(\mathrm{len}(M_{0}), \ldots, \mathrm{len}(M_{n-2})\) باید حداکثر طول مطابق با محدودیت های بالا داشته باشد.
\(n\) ممکن است حداکثر باشد \(2^{32}\). در غیر این صورت، رمزگذاری با شکست مواجه می شود.
بلوک ها را رمزگذاری کنید
برای رمزگذاری بخش \(M_i\)، محاسبه می کنیم \(\mathrm{IV}_i := \mathrm{NoncePrefix}
\| \mathrm{i} \| b\)، کجا \(\mathrm{i}\) در رمزگذاری big-endian 4 بایت است و بایت $b$ 0x00
است اگر $i < n-1$ و در غیر این صورت 0x01
.
سپس رمزگذاری می کنیم \(M_i\) با استفاده از AES-GCM 4 ، که در آن کلید است\(\mathrm{DerivedKey}\)، بردار مقداردهی اولیه است \(\mathrm{IV}_i\)و داده های مرتبط رشته خالی است. \(C_i\) نتیجه این رمزگذاری است (یعنی الحاق \(C\) و \(T\) در بخش 5.2.1.2 مرجع مرتبط AES-GCM).
بخش های رمزگذاری شده را به هم متصل کنید
در نهایت، تمام بخش ها به صورت الحاق می شوند \(\mathrm{Header} \| C_0 \| \cdots \|
C_{n-1}\)، که متن رمز نهایی است.
رمزگشایی
رمزگشایی رمزگذاری را معکوس می کند. برای بدست آوردن از هدر استفاده می کنیم\(\mathrm{NoncePrefix}\)، و هر بخش از متن رمز شده را به صورت جداگانه رمزگشایی کنید.
APIها ممکن است (و معمولاً اجازه می دهند) دسترسی تصادفی یا دسترسی به ابتدای یک فایل را بدون بازرسی انتهای فایل مجاز کنند. این عمدی است، زیرا امکان رمزگشایی وجود دارد \(M_i\) از \(C_i\)، بدون رمزگشایی تمام بلوک های متن رمز شده قبلی و باقی مانده.
با این حال، APIها باید مراقب باشند که به کاربران اجازه ندهند خطاهای انتهای فایل و رمزگشایی را با هم اشتباه بگیرند: در هر دو مورد، API احتمالاً باید یک خطا را برگرداند، و نادیده گرفتن تفاوت میتواند منجر به این شود که حریف بتواند به طور مؤثر فایلها را کوتاه کند.
سریال سازی و تجزیه کلیدها
برای سریال سازی یک کلید در قالب "Tink Proto"، ابتدا پارامترها را به روشی واضح در پروتوی ارائه شده در aes_gcm_hkdf_streaming.proto نگاشت می کنیم. version
فیلد باید روی 0 تنظیم شود. سپس این را با استفاده از سریالسازی پروتو معمولی سریال میکنیم و رشته حاصل را در مقدار فیلد یک پروتوی KeyData قرار میدهیم. فیلد type_url
را روی type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey
تنظیم کردیم. سپس 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 specifies the \u003ccode\u003eAesGcmHkdfStreamingKey\u003c/code\u003e encryption function, based on HRRV15 and analyzed in HS20, for secure streaming data encryption.\u003c/p\u003e\n"],["\u003cp\u003eKeys consist of \u003ccode\u003eKeyValue\u003c/code\u003e, \u003ccode\u003eCiphertextSegmentSize\u003c/code\u003e, \u003ccode\u003eDerivedKeySize\u003c/code\u003e, and \u003ccode\u003eHkdfHashType\u003c/code\u003e, with specific size and validity constraints.\u003c/p\u003e\n"],["\u003cp\u003eEncryption involves creating a header, splitting the message into segments, encrypting each segment using AES-GCM with a derived key, and concatenating the results.\u003c/p\u003e\n"],["\u003cp\u003eDecryption reverses this process, allowing random access to segments for efficient retrieval of specific message parts.\u003c/p\u003e\n"],["\u003cp\u003eSerialization and parsing of keys utilize Tink Proto format with specific requirements for \u003ccode\u003eversion\u003c/code\u003e, \u003ccode\u003etype_url\u003c/code\u003e, and \u003ccode\u003ekey_material_type\u003c/code\u003e fields.\u003c/p\u003e\n"]]],["The document defines AES-GCM-HKDF Streaming key encryption. Encryption involves creating a header with a random salt and nonce prefix, deriving a key using HKDF with associated data, and splitting the message into segments. Each segment is encrypted using AES-GCM with a unique initialization vector. The encrypted segments are concatenated with the header to form the final ciphertext. Decryption reverses this process. Key serialization follows the Tink Proto format, with specific field settings. Keys can be parsed in the same way.\n"],null,["# AES-GCM-HKDF Streaming AEAD\n\nThis document formally defines the mathematical function represented by\nAES-GCM-HKDF Streaming keys, encoded in proto format as\n`type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey`.\n\nThis encryption is loosely based on HRRV15^[1](#fn1)^. For security analysis, we refer\nto HS20^[2](#fn2)^.\n\nKey and parameters\n------------------\n\nKeys are described by the following parts (all sizes in this document are in\nbytes):\n\n- \\\\(\\\\mathrm{KeyValue}\\\\), a byte string.\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\nValid keys additionally satisfy the following properties:\n\n- \\\\(\\\\mathrm{len}(\\\\mathrm{KeyValue}) \\\\geq \\\\mathrm{DerivedKeySize}\\\\).\n- \\\\(\\\\mathrm{CiphertextSegmentSize} \\\u003e \\\\mathrm{DerivedKeySize} + 24\\\\) (This equals \\\\(\\\\mathrm{len}(\\\\mathrm{Header}) + 16\\\\) as explained later).\n\nKeys that violate 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, split the message into\nsegments, encrypt each segment, and concatenate the encrypted segments.\n\n### Create the header\n\nWe pick a uniform random string \\\\(\\\\mathrm{Salt}\\\\) of length\n\\\\(\\\\mathrm{DerivedKeySize}\\\\) and a uniform random string \\\\(\\\\mathrm{NoncePrefix}\\\\)\nof length 7.\n\nWe then set \\\\(\\\\mathrm{Header} := \\\\mathrm{len}(\\\\mathrm{Header}) \\\\\\| \\\\mathrm{Salt}\n\\\\\\| \\\\mathrm{NoncePrefix}\\\\), where the length of the header is encoded as a single\nbyte. Note that \\\\(\\\\mathrm{len}(\\\\mathrm{Header}) \\\\in \\\\{24, 40\\\\}\\\\).\n\nNext, we use HKDF^[3](#fn3)^ with the hash function given by \\\\(\\\\mathrm{HkdfHashType}\\\\)\nand inputs \\\\(\\\\mathrm{ikm} := \\\\mathrm{KeyValue}\\\\), \\\\(\\\\mathrm{salt} :=\n\\\\mathrm{Salt}\\\\), and \\\\(\\\\mathrm{info} := \\\\mathrm{AssociatedData}\\\\), with output\nlength \\\\(\\\\mathrm{DerivedKeySize}\\\\). We call the result \\\\(\\\\mathrm{DerivedKey}\\\\).\n\n### Split the message\n\nThe message \\\\(\\\\mathrm{Msg}\\\\) is next split into parts: \\\\(\\\\mathrm{Msg} = M_0 \\\\\\|\nM_1 \\\\\\| \\\\cdots \\\\\\| M_{n-1}\\\\).\n\nTheir lengths are chosen to satisfy:\n\n- \\\\(\\\\mathrm{len}(M_0) \\\\in \\\\{0,\\\\ldots, \\\\mathrm{CiphertextSegmentSize} - \\\\mathrm{len}(\\\\mathrm{Header}) - \\\\mathrm{16}\\\\}\\\\).\n- If \\\\(n\\\u003e1\\\\), then \\\\(\\\\mathrm{len}(M_1), \\\\ldots, \\\\mathrm{len}(M_{n-1}) \\\\in \\\\{1,\\\\ldots, \\\\mathrm{CiphertextSegmentSize} - \\\\mathrm{16}\\\\}\\\\).\n- If \\\\(n\\\u003e1\\\\), then \\\\(\\\\mathrm{len}(M_{0}), \\\\ldots, \\\\mathrm{len}(M_{n-2})\\\\) must have maximal length according to the above to constraints.\n\n\\\\(n\\\\) may be at most \\\\(2\\^{32}\\\\). Otherwise, encryption fails.\n\n### Encrypt the blocks\n\nTo encrypt segment \\\\(M_i\\\\), we compute \\\\(\\\\mathrm{IV}_i := \\\\mathrm{NoncePrefix}\n\\\\\\| \\\\mathrm{i} \\\\\\| b\\\\), where \\\\(\\\\mathrm{i}\\\\) is 4 bytes in big-endian encoding and\nbyte $b$ is `0x00` if $i \\\u003c n-1$ and `0x01` otherwise.\n\nWe then encrypt \\\\(M_i\\\\) using AES-GCM^[4](#fn4)^, where the key is\n\\\\(\\\\mathrm{DerivedKey}\\\\), the initialization vector is \\\\(\\\\mathrm{IV}_i\\\\), and the\nassociated data is the empty string. \\\\(C_i\\\\) is the result of this encryption\n(i.e. the concatenation of \\\\(C\\\\) and \\\\(T\\\\) in section 5.2.1.2 of the linked\nAES-GCM reference).\n\n### Concatenate the encrypted segments\n\nFinally, all segments are concatenated as \\\\(\\\\mathrm{Header} \\\\\\| C_0 \\\\\\| \\\\cdots \\\\\\|\nC_{n-1}\\\\), which is the final ciphertext.\n\nDecryption\n----------\n\nDecryption inverts the encryption. We use the header to obtain\n\\\\(\\\\mathrm{NoncePrefix}\\\\), and decrypt each segment of ciphertext individually.\n\nAPIs may (and typically do) allow random access, or access to the beginning of a\nfile without inspecting the end of the file. This is intentional, since it is\npossible to decrypt \\\\(M_i\\\\) from \\\\(C_i\\\\), without decrypting all previous and\nremaining 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 in\nthe obvious way into the proto given at\n[aes_gcm_hkdf_streaming.proto](https://github.com/tink-crypto/tink-java/blob/main/proto/aes_gcm_hkdf_streaming.proto). The field `version` needs to\nbe set to 0. We then serialize this using normal proto serialization, and embed\nthe resulting string in the value of field of a [KeyData](https://github.com/tink-crypto/tink-java/blob/main/proto/tink.proto) proto. We\nset the `type_url` field to\n`type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey`. We then set\n`key_material_type` to `SYMMETRIC`, and embed this into a keyset. We usually set\nthe `output_prefix_type` to `RAW`. The exception is that if the key was parsed\nwith a different value set for `output_prefix_type`, Tink may either write `RAW`\nor 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 have\n`output_prefix_type` different from `RAW` can be rejected. Keys which have a\n`version` different from 0 must be rejected.\n\nKnown issues\n------------\n\nImplementations of the above encryption function are not expected to be fork\nsafe. See [Fork Safety](/tink/issues/fork-safety).\n\nReferences\n----------\n\n*** ** * ** ***\n\n1. Hoang, Reyhanitabar, Rogaway, Vizar, 2015. Online authenticated-encryption\n and its nonce-reuse misuse-resistance. CRYPTO 2015.\n \u003chttps://eprint.iacr.org/2015/189\u003e [↩](#fnref1)\n\n2. Hoang, Shen, 2020. Security of Streaming Encryption in Google's\n Tink Library. \u003chttps://eprint.iacr.org/2020/1019\u003e [↩](#fnref2)\n\n3. RFC 5869. HMAC-based Extract-and-Expand Key Derivation Function (HKDF).\n \u003chttps://www.rfc-editor.org/rfc/rfc5869\u003e [↩](#fnref3)\n\n4. NIST SP 800-38D. Recommendation for Block Cipher Modes of Operation:\n Galois/Counter Mode (GCM) and GMAC. \u003chttps://csrc.nist.gov/pubs/sp/800/38/d/final\u003e [↩](#fnref4)"]]