AES-TO HMAC Akış AEAD

Bu belgede, AES-CTR HMAC akış anahtarları (type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey olarak proto biçiminde kodlanmıştır) tarafından temsil edilen matematiksel işlev resmi olarak tanımlanmaktadır.

Bu şifreleme, [HRRV15]1'e dayanır. Güvenliğin analizi için [HS20]2 başlıklı makaleyi inceleyin. Tink dil ötesi testlerinde, şifrelenmiş metin elde etmeyle ilgili tam bir açıklama içeren test_manually_created_test_vector dosyasını içeren aes_ctr_hmac_streaming_key_test.py adlı bir testin de bulunduğunu unutmayın.

Anahtar ve parametreler

Anahtarlar aşağıdaki bölümlerle açıklanır (bu belgedeki tüm boyutlar bayt cinsindendir):

  • \(\mathrm{InitialKeyMaterial}\), bayt dizesi: İlk anahtar malzemesi.
  • \(\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}\).

Geçerli anahtarlar ayrıca aşağıdaki özellikleri karşılar:

  • \(\mathrm{len}(\mathrm{InitialKeyMaterial}) \geq \mathrm{DerivedKeySize}\).
  • If \(\mathrm{HmacHashType} = \mathrm{SHA1}\) then \(\mathrm{HmacTagSize} \in \{10, \ldots, 20\}\).
  • If \(\mathrm{HmacHashType} = \mathrm{SHA256}\) then \(\mathrm{HmacTagSize} \in \{10, \ldots, 32\}\).
  • If \(\mathrm{HmacHashType} = \mathrm{SHA512}\) then \(\mathrm{HmacTagSize} \in \{10, \ldots, 64\}\).
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + \mathrm{HmacTagSize} + 8\) (Bu, daha sonra açıklanacağı gibi\(\mathrm{len}(\mathrm{Header}) + \mathrm{HmacTagSize}\) eşittir).

Bu özelliklerin hiçbirini karşılamayan anahtarlar Tink tarafından reddedilir (anahtar ayrıştırıldığında veya ilgili ilkel oluşturulduğunda).

Şifreleme işlevi

Bir mesajı \(\mathrm{Msg}\) ilişkili verilerle\(\mathrm{AssociatedData}\)şifrelemek için bir başlık oluşturur, mesajı segmentlere böler, her segmenti şifreler ve segmentleri birleştiririz. Bu adımları aşağıda açıklıyoruz.

Üstbilgi oluşturma

Başlığı oluşturmak için önce \(\mathrm{DerivedKeySize}\)uzunluğunda \(\mathrm{Salt}\)tekdüze bir rastgele dize seçeriz. Ardından 7 uzunluğunda rastgele bir dize seçeriz.\(\mathrm{NoncePrefix}\)

Ardından, üstbilginin uzunluğunun tek bir bayt olarak kodlandığı\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\)değerini ayarlarız.\(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\)olduğunu belirtmek isteriz.

Ardından, bu mesaj için\(\mathrm{DerivedKeySize} + 32\) uzunluğunda anahtar materyali hesaplamak üzere karma işlevi \(\mathrm{HkdfHashType}\)ile HKDF3'ü kullanırız: \(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\). Girişler,\(\mathrm{HKDF}\)'ün ilgili girişlerinde kullanılır: \(\mathrm{InitialKeyMaterial}\) \(\mathrm{ikm}\),\(\mathrm{Salt}\) tuz,\(\mathrm{AssociatedData}\) ise \(\mathrm{info}\)olarak kullanılır.

Ardından dize \(k\) iki bölüme ayrılır \(k_1 \| k_2 := k\). Bu bölümler\(\mathrm{len}(k_1) = \mathrm{DerivedKeySize}\) ve \(\mathrm{len}(k_2) = 32\)şeklindedir.

İletiyi bölme

Ardından mesaj \(M\) aşağıdaki bölümlere ayrılır: \(M = M_0 \| M_1 \| \cdots \| M_{n-1}\).

Uzunlukları şu koşulları karşılayacak şekilde seçilir:

  • \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{HmacTagSize}\}\).
  • \(n > 1\)ise \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{HmacTagSize}\}\).
  • \(n > 1\)ise \(M_{0}, \ldots, M_{n-2}\) , yukarıdaki kısıtlamalara göre maksimum uzunlukta olmalıdır.

Bu bölme işleminde \(n\) en fazla \(2^{32}\)olabilir. Aksi takdirde şifreleme başarısız olur.

Blokları şifreleme

\(M_i\)segmentini şifrelemek için önce\(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b \| 0x00000000\)değerini hesaplarız. Bu hesaplamada, \(\mathrm{i}\) değerini büyük endian kodlama kullanarak 4 bayt olarak kodlarız ve $b$ baytını $i < n-1$ ise 0x00, aksi takdirde 0x01 olarak ayarlarız.

Ardından, \(M_i\) AES CTR anahtarını \(k_1\)ve başlatma vektörünü\(\mathrm{IV}_i\)kullanarak şifreleriz. Başka bir deyişle, AES çağrılarının girişleri\(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\)şeklindedir. \(\mathrm{IV}_i\) , büyük endian tam sayı olarak yorumlanır. Bu işlem sonucunda \(C'_i\)elde edilir.

Etiketi, \(\mathrm{HmacHashType}\) tarafından sağlanan karma işleviyle ve\(\mathrm{IV}_i \| C'_i\)dizilişi üzerinde \(k_2\) anahtarıyla HMAC kullanarak hesaplarız.

Ardından, \(C_i\)değerini elde etmek için şifrelenmiş metni ve ardından etiketi birleştiririz.

Segmentleri birleştirme

Son olarak tüm segmentler\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\)olarak birleştirilir. Bu, nihai şifre metnidir.

Şifre çözme işlevi

Şifre çözme işlemi, şifrelemeyi tersine çevirir. Başlığı kullanarak nonce değerini alır ve şifrelenmiş metnin her segmentinin şifresini tek tek çözeriz.

API'ler rastgele erişime veya dosyanın sonunu incelemeden dosyanın başına erişime izin verebilir (ve genellikle verir). Önceki ve kalan tüm şifrelenmiş metin bloklarının şifresini çözmeden \(M_i\) \(C_i\)'dan şifresini çözmek mümkün olduğundan bu durum bilinçli olarak tasarlanmıştır.

Ancak API'ler, kullanıcıların dosya sonu ve şifre çözme hatalarını karıştırmasına izin vermemelidir: Her iki durumda da API'nin bir hata döndürmesi muhtemeldir ve bu farkın göz ardı edilmesi, saldırganların dosyaları etkili bir şekilde kısaltmasına neden olabilir.

Anahtarları serileştirme ve ayrıştırma

Bir anahtarı "Tink Proto" biçiminde serileştirmek için önce parametreleri aes_ctr_hmac_streaming.proto dosyasında verilen proto ile açık bir şekilde eşleriz. version alanının 0 olarak ayarlanması gerekir. Ardından, normal proto serileştirmesini kullanarak bunu serileştiririz ve elde edilen dizeyi bir KeyData protosunun value alanına yerleştiririz. type_url alanını type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey olarak ayarlıyoruz. Ardından key_material_type değerini SYMMETRIC olarak ayarlayıp bunu bir anahtar grubuna yerleştiririz. Genellikle output_prefix_type değerini RAW olarak ayarlıyoruz. Bunun istisnası, anahtar output_prefix_type için farklı bir değerle ayrıştırılmışsa Tink'in RAW veya önceki değeri yazabilmesidir.

Bir anahtarı ayrıştırmak için yukarıdaki işlemi tersine çeviririz (protoları ayrıştırırken kullanılan normal şekilde). key_material_type alanı yoksayılır. output_prefix_type değeri yoksayılabilir veya RAW'dan farklı bir output_prefix_type değerine sahip anahtarlar reddedilebilir. version değeri 0'dan farklı olan anahtarlar reddedilir.

Referanslar


  1. [HRRV15] Hoang, Reyhanitabar, Rogaway, Vizar. Online kimlik doğrulaması yapılmış şifreleme ve tek seferlik anahtarların yeniden kullanımıyla ilgili kötüye kullanıma karşı direnç. CRYPTO 2015. https://eprint.iacr.org/2015/189 

  2. [HS20] Google'ın Tink Kitaplığında Akış Şifreleme'nin Güvenliği. Hoang, Shen, 2020. https://eprint.iacr.org/2020/1019 

  3. [HKDF] HMAC tabanlı Anahtar Çıkarma ve Genişletme İşlevi (HKDF), RFC 5869. https://www.rfc-editor.org/rfc/rfc5869