Bu belgede, proto biçiminde type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey
olarak kodlanmış AES-GCM-HKDF akış anahtarlarıyla temsil edilen matematiksel işlev resmi olarak tanımlanmaktadır.
Bu şifreleme, HRRV15'e1 dayanır. Güvenlik analizi için HS202'yi kullanırız.
Anahtar ve parametreler
Anahtarlar aşağıdaki bölümlerle açıklanır (bu belgedeki tüm boyutlar bayt cinsindendir):
- \(\mathrm{KeyValue}\), bayt dizesi.
- \(\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\) (Daha sonra açıklanacağı gibi bu, \(\mathrm{len}(\mathrm{Header}) + 16\) değerine eşittir).
Bu özelliklerin hiçbirini karşılamayan anahtarlar, anahtar ayrıştırıldığında veya ilgili ilkel oluşturulduğunda Tink tarafından reddedilir.
Ş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 şifrelenmiş segmentleri birleştiririz.
Üstbilgi oluşturma
\(\mathrm{DerivedKeySize}\) uzunluğunda \(\mathrm{Salt}\) tekdüze bir rastgele dize ve 7 uzunluğunda \(\mathrm{NoncePrefix}\)tekdüze bir rastgele dize seçeriz.
Ardından, başlığın uzunluğunun tek bir bayt olarak kodlandığı \(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\)değerini belirleriz. \(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\)
Ardından, \(\mathrm{HkdfHashType}\)tarafından sağlanan karma işleviyle HKDF3'ü ve \(\mathrm{ikm} := \mathrm{KeyValue}\), \(\mathrm{salt} := \mathrm{Salt}\)ve \(\mathrm{info} := \mathrm{AssociatedData}\)girişlerini, \(\mathrm{DerivedKeySize}\)çıkış uzunluğuyla kullanırız. Sonuç, \(\mathrm{DerivedKey}\)olarak adlandırılır.
İletiyi bölme
Ardından mesaj \(\mathrm{Msg}\) aşağıdaki bölümlere ayrılır: \(\mathrm{Msg} = 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{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 uzunlukta olmalıdır.
\(n\) en fazla \(2^{32}\)karakter olabilir. Aksi takdirde şifreleme başarısız olur.
Blokları şifreleme
\(M_i\)segmentini şifrelemek için \(\mathrm{IV}_i := \mathrm{NoncePrefix}
\| \mathrm{i} \| b\)değerini hesaplarız. Burada \(\mathrm{i}\) , büyük endian kodlamasında 4 bayttır ve $b$ baytı, $i < n-1$ ise 0x00
, aksi takdirde 0x01
olur.
Ardından,\(\mathrm{DerivedKey}\)anahtarının, \(\mathrm{IV}_i\)başlatma vektörünün ve boş dizenin ilişkili olduğu veriler olduğu AES-GCM4 kullanılarak \(M_i\) şifrelenir. \(C_i\) , bu şifrelemenin sonucudur (yani, bağlantı verilen AES-GCM referansının 5.2.1.2 numaralı bölümündeki \(C\) ve \(T\) dizelerinin birleştirilmesi).
Şifrelenmiş segmentleri birbirine bağlama
Son olarak tüm segmentler, nihai şifre metni olan \(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\)olarak birleştirilir.
Şifre çözme
Şifre çözme işlemi, şifrelemeyi tersine çevirir.\(\mathrm{NoncePrefix}\)değerini almak için başlığı kullanı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\)'den ş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_gcm_hkdf_streaming.proto adresinde 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.AesGcmHkdfStreamingKey
olarak ayarladık. 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 belirleriz. Bunun istisnası, anahtar output_prefix_type
için farklı bir değer ayarlanarak 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
ile farklı output_prefix_type
değerlerine sahip anahtarlar reddedilebilir. version
değeri 0'dan farklı olan anahtarlar reddedilmelidir.
Bilinen sorunlar
Yukarıdaki şifreleme işlevinin uygulamalarının çatallamaya karşı güvenli olması beklenmez. Fork Safety başlıklı makaleyi inceleyin.
Referanslar
-
Hoang, Reyhanitabar, Rogaway, Vizar, 2015. Online kimlik doğrulaması yapılmış şifreleme ve tek seferlik rastgele sayı yeniden kullanımıyla ilgili kötüye kullanıma karşı direnç. CRYPTO 2015. https://eprint.iacr.org/2015/189 ↩
-
Hoang, Shen, 2020. Google'ın Tink Kitaplığında Akış Şifreleme'nin Güvenliği. https://eprint.iacr.org/2020/1019 ↩
-
RFC 5869. HMAC tabanlı Anahtar Çıkarma ve Genişletme İşlevi (HKDF). https://www.rfc-editor.org/rfc/rfc5869 ↩
-
NIST SP 800-38D. Blok Şifre Çalışma Modları için Öneri: Galois/Karşı Mod (GCM) ve GMAC. https://csrc.nist.gov/pubs/sp/800/38/d/final ↩