AES-TO HMAC Akış AEAD

Bu belgede, AES-TO HMAC Akış anahtarları (type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey olarak proto biçiminde kodlanmıştır) tarafından temsil edilen matematik işlevi açıklanmaktadır.

Bu şifreleme genel olarak [HRRV15]1'e dayalıdır. Güvenlik analizi için [HS20]2 adresini ziyaret edebilirsiniz. Tink diller arası testlerinde, şifrelenmiş metnin nasıl edinileceği konusunda eksiksiz bir adım adım açıklamalı kılavuz içeren test_manually_created_test_vector içeren bir test aes_ctr_hmac_streaming_key_test.py bulunduğunu da unutmayın.

Anahtar ve parametreler

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

  • \(\mathrm{InitialKeyMaterial}\), bir bayt dizesidir: ilk anahtar materyali.
  • \(\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}\).
  • Varsa \(\mathrm{HmacHashType} = \mathrm{SHA1}\) o zaman \(\mathrm{HmacTagSize} \in \{10, \ldots, 20\}\).
  • Varsa \(\mathrm{HmacHashType} = \mathrm{SHA256}\) o zaman \(\mathrm{HmacTagSize} \in \{10, \ldots, 32\}\).
  • Varsa \(\mathrm{HmacHashType} = \mathrm{SHA512}\) o zaman \(\mathrm{HmacTagSize} \in \{10, \ldots, 64\}\).
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + \mathrm{HmacTagSize} + 8\) (Bu, daha sonra açıklandığı gibi \(\mathrm{len}(\mathrm{Header}) + \mathrm{HmacTagSize}\) eşittir).

Bu özelliklerden herhangi birine uymayan anahtarlar Tink tarafından reddedilir (anahtar ayrıştırıldığında veya karşılık gelen temel öğe oluşturulduğunda).

Şifreleme işlevi

Bir iletiyi \(\mathrm{Msg}\) ilişkili verilerle\(\mathrm{AssociatedData}\)şifrelemek için bir başlık oluşturur, iletiyi segmentlere ayırır, her bir segmenti şifreler ve segmentleri birleştiririz. Bu adımlar aşağıda açıklanmıştır.

Başlık oluşturma

Üstbilgiyi oluşturmak için önce \(\mathrm{Salt}\) uzunluğunda \(\mathrm{DerivedKeySize}\)tek tip bir rastgele dize seçeriz. Sonra, 7 uzunluğunda tek tip bir rastgele \(\mathrm{NoncePrefix}\) dize seçeriz.

Daha sonra, başlığın uzunluğu tek bayt olarak kodlanan\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\)öğesini ayarlarız. Not: \(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\).

Ardından, şu mesaj için anahtar materyalini hesaplamak üzere HKDF3 öğesini karma işleviyle \(\mathrm{HkdfHashType}\)kullanacağız:\(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\).\(\mathrm{DerivedKeySize} + 32\) Girişler \(\mathrm{HKDF}\): \(\mathrm{InitialKeyMaterial}\) eşittir \(\mathrm{ikm}\), \(\mathrm{Salt}\) tuzaktır ve \(\mathrm{AssociatedData}\) olarak kullanılır \(\mathrm{info}\).

Daha sonra dize \(k\) iki bölüme ayrılır \(k_1 \| k_2 := k\), yani\(\mathrm{len}(k_1) = \mathrm{DerivedKeySize}\) ve \(\mathrm{len}(k_2) = 32\).

İletiyi bölme

Bu ileti \(M\) daha sonra parçalara ayrılacaktır: \(M = M_0 \| M_1 \| \cdots \| M_{n-1}\).

Uzunlukları aşağıdaki gereksinimleri 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 uzunluğa sahip olmalıdır.

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

Blokları şifreleme

Segmenti \(M_i\)şifrelemek için ilk olarak\(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b \| 0x00000000\)işlemini hesaplarız. Bu hesaplamada, büyük uçlu kodlamayı kullanarak \(\mathrm{i}\) 4 baytta kodlarız ve $i <n-1$ olması halinde $b$ baytını 0x00, aksi takdirde 0x01 olarak ayarlarız.

Daha sonra \(M_i\) AES TO anahtarı \(k_1\)ve başlatma vektörü\(\mathrm{IV}_i\)kullanarak şifrelemeyi yaparız. 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\)olur. Burada \(\mathrm{IV}_i\) , büyük uçlu tam sayı olarak yorumlanır. Bu, \(C'_i\)sonucunu verir.

Etiketi, HMAC kullanarak \(\mathrm{HmacHashType}\) tarafından verilen karma işlevi ve anahtarla \(k_2\) birleştirmeyi\(\mathrm{IV}_i \| C'_i\)kullanarak hesaplarız.

Daha sonra, \(C_i\)kodunu almak için şifrelenmiş metni ve ardından etiketi birleştiririz.

Segmentleri birleştirin

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

Şifre çözme işlevi

Şifre çözme, şifrelemeyi tersine çevirir. Tek seferlik rastgele sayıyı elde etmek ve her bir şifreli metnin şifresini çözmek için başlığı kullanırız.

API'ler, rastgele erişime veya dosyanın sonunu incelemeden dosyanın başlangıcına erişime izin verebilir (ve tipik olarak bunu yapar). Önceki ve kalan tüm şifrelenmiş metin bloklarının şifresini çözmeden \(M_i\) \(C_i\)ürününün şifresini çözmek mümkün olduğundan bu yöntem kasıtlıdır.

Ancak API'ler, kullanıcıların dosya sonu ve şifre çözme hatalarını karıştırmasına izin vermemeye dikkat etmelidir: Her iki durumda da API'nin bir hata döndürmesi gerekir ve fark göz ardı edildiğinde kötü niyetli kişi dosyaları etkili bir şekilde kırpabilir.

Anahtarların serileştirilmesi ve ayrıştırılması

Bir anahtarı "Tink Proto" biçiminde serileştirmek için önce parametreleri açık bir şekilde aes_ctr_hmac_streaming.proto adresinde verilen proto ile eşliyoruz. version alanı 0 olarak ayarlanmalıdır. Daha sonra, bunu normal proto serileştirmeyi kullanarak serileştiririz ve elde edilen dizeyi, bir KeyData protokolünün alanı değerine yerleştiririz. type_url alanını type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey olarak ayarlıyoruz. Ardından key_material_type öğesini SYMMETRIC olarak ayarlayıp bir anahtar kümesine yerleştiriyoruz. output_prefix_type genellikle RAW olarak ayarlanır. İstisna olarak, anahtar output_prefix_type için farklı bir değerle ayrıştırılırsa Tink, RAW değerini veya önceki değeri yazabilir.

Bir anahtarı ayrıştırmak için yukarıdaki işlemi geri alırız (proto'ları ayrıştırırken normal şekilde). key_material_type alanı yoksayılır. output_prefix_type değeri yoksayılabilir veya output_prefix_type değeri RAW değerinden farklı olan anahtarlar reddedilebilir. version değeri 0'dan farklı olan anahtarlar reddedilir.

Referanslar


  1. [HRRV15] Hoang, Reyhanitabar, Rogaway, Vizar. Online kimliği doğrulanmış şifreleme ve tek seferlik tekrar olmayan hatalı kullanım direnci. KRİPTO 2015. https://eprint.iacr.org/2015/189 

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

  3. [HKDF] HMAC Tabanlı Ayıklama ve Genişletme Anahtar Türetme İşlevi (HKDF), RFC 5869. https://www.rfc-editor.org/rfc/rfc5869