← Double Ratchet/
Double Ratchet · Bölüm 03 cryptography / double-ratchet

3. Double Ratchet

3.1. Dış işlevler

Double Ratchet'ı somutlaştırmak için aşağıdaki işlevlerin tanımlanması gerekir. Öneriler için Bölüm 7.2'ye bakın.

Ayrıca bir MAX_SKIP sabitinin de tanımlanması gerekir. Bu, tek bir zincirde atlanabilecek azami mesaj anahtarı sayısını belirtir. Rutin olarak kaybolan veya geciken mesajları tolere edecek kadar yüksek, ancak kötü niyetli bir gönderenin alıcı tarafında aşırı hesaplama yükü doğuramayacağı kadar düşük ayarlanmalıdır.

3.2. Durum değişkenleri

Aşağıdaki durum değişkenleri her iki tarafça da izlenir:

Aşağıdaki sözde kodda durum değişkenlerine, bir state nesnesinin üyeleri olarak erişilir.

3.3. Başlatma

Başlatmadan önce her iki taraf da, 32 baytlık paylaşılan gizli anahtar SK üzerinde ve Bob'un ratchet açık anahtarında anlaşmak için bir anahtar anlaşma protokolü kullanmalıdır. Bu değerler, Alice'in gönderme zinciri anahtarını ve Bob'un kök anahtarını doldurmak için kullanılacaktır. Bob'un zincir anahtarları ile Alice'in alma zinciri anahtarı boş bırakılacaktır; çünkü bunlar her iki tarafın ilk DH adımıyla doldurulur.

(Bu, mesaj göndermeye önce Alice'in başladığını ve Bob'un, Alice'in mesajlarından birini almadan mesaj göndermediğini varsayar. Bob'un başlatmadan hemen sonra mesaj gönderebilmesini sağlamak için Bob'un gönderme zinciri anahtarı ile Alice'in alma zinciri anahtarı paylaşılan bir sır ile başlatılabilirdi. Basitlik adına bunu ayrıca ele almayacağız.)

Alice ile Bob, SK ve Bob'un ratchet açık anahtarı üzerinde anlaştıktan sonra Alice RatchetInitAlice() çağrısını, Bob ise RatchetInitBob() çağrısını yapar:

function RatchetInitAlice(state, SK, bob_dh_public_key):
    state.DHs = GENERATE_DH()
    state.DHr = bob_dh_public_key
    state.RK, state.CKs = KDF_RK(SK, DH(state.DHs, state.DHr))
    state.CKr = None
    state.Ns = 0
    state.Nr = 0
    state.PN = 0
    state.MKSKIPPED = {}

function RatchetInitBob(state, SK, bob_dh_key_pair):
    state.DHs = bob_dh_key_pair
    state.DHr = None
    state.RK = SK
    state.CKs = None
    state.CKr = None
    state.Ns = 0
    state.Nr = 0
    state.PN = 0
    state.MKSKIPPED = {}

3.4. Mesajların şifrelenmesi

Mesajları şifrelemek için RatchetEncrypt() çağrılır. Bu işlev önce bir simetrik anahtar adımı uygular, ardından elde edilen mesaj anahtarıyla mesajı şifreler. Mesajın plaintext değerine ek olarak, alttaki AEAD şifrelemesi için ilişkili veriyi oluşturmak üzere başlığın önüne eklenecek bir AD bayt dizisi alır:

function RatchetSendKey(state):
    state.CKs, mk = KDF_CK(state.CKs)
    Ns = state.Ns
    state.Ns = state.Ns + 1
    return Ns, mk

function RatchetEncrypt(state, plaintext, AD):
    Ns, mk = RatchetSendKey(state)
    header = HEADER(state.DHs, state.PN, Ns)
    return header, ENCRYPT(mk, plaintext, CONCAT(AD, header))

3.5. Mesajların şifresinin çözülmesi

Mesajların şifresini çözmek için RatchetDecrypt() çağrılır. Bu işlev aşağıdakileri yapar:

Bir istisna fırlatılırsa (örneğin mesaj doğrulaması başarısız olursa) mesaj göz ardı edilir ve durum nesnesindeki değişiklikler atılır. Aksi halde, çözülen düz metin kabul edilir ve durum nesnesindeki değişiklikler saklanır:

function RatchetReceiveKey(state, header):
    mk = TrySkippedMessageKeys(state, header)
    if mk is not None:
        return mk
    if header.dh != state.DHr:
        SkipMessageKeys(state, header.pn)
        DHRatchet(state, header)
    SkipMessageKeys(state, header.n)
    state.CKr, mk = KDF_CK(state.CKr)
    state.Nr = state.Nr + 1
    return mk

function RatchetDecrypt(state, header, ciphertext, AD):
    mk = RatchetReceiveKey(state, header)
    return DECRYPT(mk, ciphertext, CONCAT(AD, header))

function TrySkippedMessageKeys(state, header):
    if (header.dh, header.n) in state.MKSKIPPED:
        mk = state.MKSKIPPED[header.dh, header.n]
        remove state.MKSKIPPED[header.dh, header.n]
        return mk
    else:
        return None

function SkipMessageKeys(state, until):
    if state.Nr + MAX_SKIP < until:
        signal Error
    if state.CKr is not None:
        while state.Nr < until:
            state.CKr, mk = KDF_CK(state.CKr)
            state.MKSKIPPED[state.DHr, state.Nr] = mk
            state.Nr = state.Nr + 1

function DHRatchet(state, header):
    state.PN = state.Ns
    state.Ns = 0
    state.Nr = 0
    state.DHr = header.dh
    state.RK, state.CKr = KDF_RK(state.RK, DH(state.DHs, state.DHr))
    state.DHs = GENERATE_DH()
    state.RK, state.CKs = KDF_RK(state.RK, DH(state.DHs, state.DHr))