Bu belgede, AES-GCM-HKDF Akış anahtarları (type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey
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.
Anahtar ve parametreler
Anahtarlar aşağıdaki bölümlerde açıklanmıştır (bu belgedeki tüm boyutlar bayt cinsindendir):
- \(\mathrm{KeyValue}\), bir baytlık dizedir.
- \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
- \(\mathrm{DerivedKeySize} \in \{16, 32\}\).
- \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).
Geçerli anahtarlar ayrıca aşağıdaki özellikleri karşılar:
- \(\mathrm{len}(\mathrm{KeyValue}) \geq \mathrm{DerivedKeySize}\).
- \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + 24\) (Bu, daha sonra açıklandığı gibi \(\mathrm{len}(\mathrm{Header}) + 16\) 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, \(\mathrm{HkdfHashType}\)ve girişlerin \(\mathrm{ikm} := \mathrm{KeyValue}\),\(\mathrm{salt} := \mathrm{Salt}\)ve\(\mathrm{info} := \mathrm{AssociatedData}\)girişlerinin yanı sıra çıkış uzunluğu \(\mathrm{DerivedKeySize}\)ile HKDF3'ü kullanıyoruz. Bu sonuca \(k\)diyoruz.
İletiyi bölme
Mesaj \(\mathrm{Msg}\) daha sonra bölümlere ayrılır: \(\mathrm{Msg} = 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{16}\}\).
- \(n>1\)ise \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{16}\}\).
- \(n>1\)ise \(\mathrm{len}(M_{0}), \ldots, \mathrm{len}(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\)işlemini hesaplarız. Bu hesaplamada,\(\mathrm{i}\) büyük uçlu kodlama kullanarak\(\mathrm{i}\) 4 baytı kodlar, $i <n-1$ olması halinde $b$ baytını 0x00
, aksi takdirde 0x01
olarak ayarlarız.
Daha sonra \(M_i\) AES GCM kullanarak4 şifrelemeleri yaparız. Burada anahtar \(\mathrm{DerivedKey}\), başlatma vektörü \(\mathrm{IV}_i\) ve ilişkili veriler \(A\) boş dizedir. \(C_i\) öğesini bu şifrelemenin sonucu olacak şekilde ayarladık (yani, \(C\) ve \(T\) yukarıdaki referansta birleştirilmesi).
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
Şifre çözme, şifrelemeyi tersine çevirir. Tek seferlik rastgele metni 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_gcm_hkdf_streaming.proto adresinde verilen protoda 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 protosunun alan değerine yerleştiririz.
type_url
alanını type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey
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 reddedilmelidir.
Bilinen sorunlar
Yukarıdaki şifreleme işlevinin uygulamalarının, çatallama açısından güvenli olması beklenmez. Çatal Güvenliği bölümüne bakın.
Referanslar
-
[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 ↩
-
[HS20] Google'ın Tink Library'de Akış Şifreleme Güvenliği. Hoang, Shen, 2020. https://eprint.iacr.org/2020/1019 ↩
-
[HKDF] HMAC Tabanlı Ayıklama ve Genişletme Anahtar Türetme İşlevi (HKDF), RFC 5869. https://www.rfc-editor.org/rfc/rfc5869 ↩
-
NIST SP 800-38D, Blok Şifre Çalışma Modları için Öneri: Galois/Sayaç Modu (GCM) ve GMAC. ↩