Kriptografide temel bir prensip vardır ve bir çıktı belirlenimci veya belirlenimci olmayan olabilir. Belirlenimci bir çıktıda, aynı girdiler için her zaman aynı çıktıyı alırız. Örneğin, düz metinden bir şifre oluşturabiliriz ve çıktısı her zaman aynı şifreli metin olacaktır. Belirlenimci olmayan çıktılarda, süreçte bir tür rastgeleleştirme kullanıldığından çıktının ne olacağını tahmin edemeyiz. İmzalarda, ECDSA belirlenimci değildir ve EdDSA belirlenimcidir.
Simetrik anahtar yöntemlerine gelince, belirlenimci doğa verileri aramada faydalı olabilir, ancak bir saldırgan girdileri çıktıya eşleyebileceğinden güvenlik açısından daha zayıf olacaktır. Bu durumda, belirlenimci doğayı İlişkilendirilmiş Veriyle Kimliği Doğrulanmış Şifreleme (Deterministic AEAD) ile birleştireceğiz ve AES-SIV modunu kullanacağız.
Sırlarımızın çoğunu açığa vuruyoruz ve genellikle en önemli sırrımızı koruyamıyoruz... şifreleme anahtarlarımızı. Bunun üstesinden gelmek için, anahtarı koruyan anahtar sarma adı verilen bir yöntem kullanabiliriz. Bu, özellikle anahtarı güvenilmeyen kanallar üzerinden ilettiğimiz veya güçlü erişim kontrolü olmadan yerlerde sakladığımız durumlarda önemlidir. Bir anahtar sarma için Rogaway ve diğerleri SIV (Sentetik Başlatma Vektörü) yöntemini önerdi [here] ve bu yöntem, anahtarla ilgili herhangi bir ek veriyi kimlik doğrulamanın yanı sıra kimlik doğrular ve şifreler:
Yöntem artık RFC 5297 ile standartlaştırılmıştır [here]. Gelişmiş şifreleme yöntemleriyle, hem şifrenin kimliğini doğrulayabilir hem de bütünlüğünü kanıtlayabiliriz. Bu, İlişkilendirilmiş Veriyle Kimliği Doğrulanmış Şifreleme (AEAD) olarak bilinir. Bunun için, şifreleme sürecini doğrulamak için ek veriler sağlıyoruz ve şifreli metnin nerede değiştirildiğini belirleyebiliriz, böylece şifresi çözülemez. Çoğu geleneksel AEAD yöntemiyle, bir nonce değeri oluşturur ve kimliği doğrulanmış ancak şifrelenmemiş ek veriler (AD) ekleriz. Nonce içermeyen bir yaklaşımla, genellikle şifreleme anahtarlarını korumak için kullanılan bir anahtar sarma yöntemi kullanabiliriz. Ek veriler şunları içerebilir [here]:
adresler, portlar, sıra numaraları, protokol sürüm numaraları ve düz metnin veya şifreli metnin nasıl işlenmesi, iletilmesi veya işlenmesi gerektiğini gösteren diğer alanlar
Bu şekilde, ağ paketlerini şifrelenmiş verilere bağlayabilir ve bir davetsizin diğer iletimlerden geçerli şifreli metni kopyalayıp yapıştıramaması için bütünlük sağlayabiliriz. Örneğin, bir paket sıra numarasına ve porta bağlanırsak, kimlik doğrulama başka bir sıra numarası veya başka bir port için başarısız olur.
Aşağıdaki kodda, "101112131415161718191a1b1c1d1e1f2021222324252627" ek bilgisini kullanacağız, ancak pratikte bu herhangi bir uzunlukta olabilir. SIV içinde de, bu ek verinin birden çok kaynağına (dizeler vektörü olarak bilinir) sahip olabiliriz. Bu bilgi birden çok kaynağa yayılabilir ve bir davetsizin yakalaması ve kopyalaması muhtemelen zor olacaktır. Bu, SIV'in özel özelliklerinden biridir ve ek bilgi için bunları tek bir dizede birleştirmek zorunda kalmak yerine, kimlik doğrulama için birden çok dize kullanılmasına olanak tanır:
byte[] plaintext = pl.getBytes();
String additional="101112131415161718191a1b1c1d1e1f2021222324252627";
byte[] ciphertext = daead.encryptDeterministically(plaintext, Hex.decode(additional));
Geleneksel AEAD yöntemleri, nonce'ın yeniden kullanımı ve ayrıca nonce'ın kötüye kullanılması açısından zayıf olabilir. Birçok sistemde, bir nonce oluşturmanın belirlenimci olmayan bir yöntemini kullanırız, bu nedenle daha önce oluşturulan değerlerin daha önce kullanılmadığını bilmenin bir yolu yoktur. Başka bir zayıflık, bir sanal makineyi geri alarak ve kullanılan nonce değerini keşfederek bir nonce'ın "geri oynatılabileceği" durumlardır. Bu nedenle, çoğu AEAD yöntemi benzersiz bir nonce ile güvenlidir, ancak nonce benzersiz değilse güvenlik garantisi yoktur. Nonce değeri boyut olarak sınırlı olduğundan, aynı anahtarla yeniden kullanma şansı her zaman olacaktır ve bu nedenle, anahtarlarımızı düzenli olarak değiştirmek zorunda kalabiliriz. SIV, nonce'ın yeniden kullanımı/kötüye kullanılması için daha fazla koruma sağlar ve burada bir saldırgan yalnızca belirli bir düz metin değerinin ve belirli bir ilişkili veri kümesinin tanımlı anahtar ve nonce değeri kullanılarak korunduğunu belirleyebilir.
Aşağıdaki kodda, bir SIV anahtarı oluşturuyoruz ve ardından her ikisi de aynı olması gereken şifreli metin değerleri oluşturuyoruz [here]:
package main
import (
"fmt"
"os"
"github.com/tink-crypto/tink-go/v2/daead"
"github.com/tink-crypto/tink-go/v2/keyset"
)
func main() {
msg:="Hello"
associated:="Hello"
argCount := len(os.Args[1:])
if (argCount>0) {msg = os.Args[1]}
if (argCount>1) {associated =os.Args[2]}
handle, _ := keyset.NewHandle(daead.AESSIVKeyTemplate())
primitive, _ := daead.New(handle)
plaintext := []byte(msg)
associatedData := []byte(associated)
ciphertext1, _:= primitive.EncryptDeterministically(plaintext, associatedData)
ciphertext2, _:= primitive.EncryptDeterministically(plaintext, associatedData)
res, _ := primitive.DecryptDeterministically(ciphertext1, associatedData)
fmt.Printf("Plaintext is %s\n",msg)
fmt.Printf("Associated data is %s\n\n",associated)
fmt.Printf("Key is %s\n\n",handle)
fmt.Printf("Cipher1 is %x\n\n",ciphertext1)
fmt.Printf("Cipher2 is %x\n\n",ciphertext2)
fmt.Printf("Decrypted is %s",res)
}
Örnek bir çalıştırma, belirlenimci olarak şifrelediğimizde aynı şifreye sahip olduğumuzu gösteriyor [here]:
Plaintext is Testing 123
Associated data is qwerty123
Key is primary_key_id:1537855825 key_info:{type_url:"type.googleapis.com/google.crypto.tink.AesSivKey" status:ENABLED key_id:1537855825 output_prefix_type:TINK}
Cipher1 is 015ba9d1518f3a5d213ce9630294f87af76ce86011c8631842aa96571d0dee03
Cipher2 is 015ba9d1518f3a5d213ce9630294f87af76ce86011c8631842aa96571d0dee03
Decrypted is Testing 123