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
-
[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 ↩
-
[HS20] Google'ın Tink Kitaplığında Akış Şifreleme'nin Güvenliği. Hoang, Shen, 2020. https://eprint.iacr.org/2020/1019 ↩
-
[HKDF] HMAC tabanlı Anahtar Çıkarma ve Genişletme İşlevi (HKDF), RFC 5869. https://www.rfc-editor.org/rfc/rfc5869 ↩