بث AE-GCM-HKDF AEAD
تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
يحدّد هذا المستند بشكل رسمي الدالة الرياضية التي تمثلها مفاتيح بث AES-GCM-HKDF، والمرمّزة بتنسيق Proto على النحو التالي: type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey
.
يستند هذا التشفير بشكل غير دقيق إلى HRRV151. لتحليل الأمان، نشير إلى
HS202.
المفتاح والمعلمات
يتم وصف المفاتيح بالأجزاء التالية (جميع الأحجام في هذا المستند بالبايت):
- \(\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\}\).
بعد ذلك، نستخدم HKDF3 مع دالة التجزئة التي يوفّرها \(\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}\) هي 4 بايت بترميز واسع النطاق والبايت $b$ يساوي 0x00
إذا كانت $i < n-1$ و0x01
بخلاف ذلك.
ثم نقوم بالتشفير \(M_i\) باستخدام AES-GCM4، حيث يكون المفتاح هو\(\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}\)وفك تشفير كل مقطع من النص المُشفر على حدة.
قد تسمح واجهات برمجة التطبيقات (وعادةً ما تسمح بذلك) بالوصول العشوائي أو الوصول إلى بداية الملف بدون فحص نهاية الملف. وهذا مقصود، لأنّه من الممكن
فك تشفير \(M_i\) من \(C_i\)، بدون فك تشفير جميع مجموعات النص المُشفر السابقة
والمتبقية.
ومع ذلك، يجب أن تحرص واجهات برمجة التطبيقات على عدم السماح للمستخدمين بالخلط بين أخطاء نهاية الملف وأخطاء فك التشفير: وفي كلتا الحالتين، من المحتمل أن تعرض واجهة برمجة التطبيقات خطأً، وقد يؤدي تجاهل الاختلاف إلى قدرة الخصم على اقتطاع الملفات بشكل فعّال.
تسلسل المفاتيح وتحليلها
لإنشاء تسلسل لمفتاح بتنسيق "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 ما لم يُنصّ على خلاف ذلك، ونماذج الرموز مرخّصة بموجب ترخيص Apache 2.0. للاطّلاع على التفاصيل، يُرجى مراجعة سياسات موقع Google Developers. إنّ Java هي علامة تجارية مسجَّلة لشركة 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)"]]