Verileri uzaktan imzalayan bir kişiyle imzalamak istiyorum

Özel anahtarın, mesajın gönderilemediği bir yerde bulunduğu durumlarda ML_DSA_65 anahtarıyla Prehash ve SignPrehash ilkel yöntemlerini kullanmanızı öneririz.

Bazen imzalama anahtarını elinde bulunduran taraf, iletinin kendisini alamaz veya almamalıdır: Anahtar bir HSM'de ya da KMS'de bulunur veya ileti, imzalayanın istek boyutu sınırından daha büyüktür.

Prehash ve SignPrehash temel işlevleri, imzalamayı iki adıma bölerek bu sorunu çözer. Yalnızca ortak anahtarı kullanarak mesajın bulunduğu yerde kısa bir ön karma değeri hesaplar ve bunu imzalayana gönderirsiniz. İmzalayan, iletiyi hiç görmeden özel anahtarı kullanarak imzaya dönüştürür. Tink'in desteklediği algoritma olan External Mu modunda ML-DSA ile, mesajın boyutu ne olursa olsun ön karma değeri 69 bayttır.

Geri aldığınız imza, orijinal ileti üzerindeki normal bir imzadır: Doğrulayıcılar, normal dijital imza öğesini kullanır ve iki adımın kullanıldığını bilmeleri gerekmez.

Başlamadan önce

Anahtarlarının kimlik şartı olan bir ML-DSA anahtar grubu oluşturun. Bu, TINK varyantı veya sonuçtaki imzaya çıkış öneki eklemek istemiyorsanız NO_PREFIX_WITH_PREHASH_ID olabilir. İmzalayana özel anahtar kümesini, ön karma oluşturma tarafına ise ilgili ortak anahtar kümesini verin. İmzalayan, ön karma oluşturma tarafının oluşturabileceği her anahtar kimliği için etkin bir anahtara sahip olmalıdır. Anahtar kümeleri bölümüne bakın.

1. adım: Karma öncesi değeri hesaplayın

Bu işlevi, mesajın bulunduğu her yerde çalıştırın. Yalnızca ortak anahtar kümesi gerekir.

C++

#include "tink/keyset_handle.h"
#include "tink/signature/config_2026.h"
#include "tink/signature/prehash.h"

absl::StatusOr<std::unique_ptr<crypto::tink::Prehash>> prehasher =
    public_handle.GetPrimitive<crypto::tink::Prehash>(
        crypto::tink::ConfigSignature2026());
if (!prehasher.ok()) return prehasher.status();

absl::StatusOr<std::string> prehash = (*prehasher)->Compute(message);
if (!prehash.ok()) return prehash.status();

Go

import "github.com/tink-crypto/tink-go/v2/signprehash"

prehasher, err := signprehash.NewPrehash(publicHandle)
if err != nil {
    return err
}
prehash, err := prehasher.ComputePrehash(message)
if err != nil {
    return err
}

2. adım: Ön karma değerini imzalayana gönderin

Ön karma değerini, özel anahtarı tutan yere gönderin. Gizli olmasa da iletim sırasında bütünlüğünü korumanız gerekir: Uçuş sırasında değiştirebilen bir saldırgan, neyin imzalanacağını kontrol eder.

3. adım: Ön karma değerini imzalayın

Bu komutu özel anahtarın bulunduğu her yerde çalıştırın.

C++

#include "tink/keyset_handle.h"
#include "tink/signature/config_2026.h"
#include "tink/signature/sign_prehash.h"

absl::StatusOr<std::unique_ptr<crypto::tink::SignPrehash>> signer =
    private_handle.GetPrimitive<crypto::tink::SignPrehash>(
        crypto::tink::ConfigSignature2026());
if (!signer.ok()) return signer.status();

absl::StatusOr<std::string> signature = (*signer)->Sign(prehash);
if (!signature.ok()) return signature.status();

Go

import "github.com/tink-crypto/tink-go/v2/signprehash"

signer, err := signprehash.NewPrehashSigner(privateHandle)
if err != nil {
    return err
}
sig, err := signer.SignPrehash(prehash)
if err != nil {
    return err
}

4. adım: İmzayı doğrulayın

Doğrulama, ön karma değeri üzerinden değil, orijinal ileti üzerinden yapılan normal dijital imza akışıdır.

C++

absl::StatusOr<std::unique_ptr<crypto::tink::PublicKeyVerify>> verifier =
    public_handle.GetPrimitive<crypto::tink::PublicKeyVerify>(
        crypto::tink::ConfigSignature2026());
if (!verifier.ok()) return verifier.status();

absl::Status verified = (*verifier)->Verify(signature, message);

Go

import "github.com/tink-crypto/tink-go/v2/signature"

verifier, err := signature.NewVerifier(publicHandle)
if err != nil {
    return err
}
if err := verifier.Verify(sig, message); err != nil {
    return err
}

Prehash ve SignPrehash

Prehash ve SignPrehash temel işlevleri, dijital imza hesaplamasını iki adıma böler:

  1. Prehash için yalnızca ortak anahtar gerekir. İstediğiniz uzunluktaki bir mesajı kısa ve sabit boyutlu bir ön karma değerine dönüştürür.
  2. SignPrehash için özel anahtar gerekir. Önceden karma oluşturulmuş bir değeri imzaya dönüştürür.

Ortaya çıkan imza, orijinal mesajın üzerindeki normal bir imzadır. Bu imzayı normal dijital imza PublicKeyVerify öğesiyle doğruladığınızda doğrulayıcıların, imzanın iki adımda oluşturulduğunu bilmesi veya bu durumla ilgilenmesi gerekmez.

Önceden karma oluşturulmuş değeri opak baytlar olarak ele alın. Sabit bir boyutu vardır ve hesaplandığı anahtarın kimliğini taşır. Ancak düzeni Tink'in kablo biçiminin bir parçasıdır ve kendiniz ayrıştırmamalı veya oluşturmamalısınız. Tink'i taşıyorsanız veya bayt düzeyindeki ayrıntılara ihtiyacınız varsa Tink wire format başlıklı makaleyi inceleyin.

Bu temel öğe çiftini şu durumlarda kullanın:

  • İmzalama anahtarı başka bir yerde (ör. HSM, KMS veya RPC sınırı arkasında) bulunuyor ve tam mesajı bu sınırın ötesine göndermek istemiyorsunuz.
  • İleti büyük ve uzaktan imzalayan, istek boyutu sınırı uyguluyor.

Bu iki durumdan hiçbiri geçerli değilse bunun yerine basit Digital Signature (Dijital İmza) öğesini kullanın. Bu öğe daha basittir ve kötüye kullanılması daha zordur.

Anahtar kümeleri

İki temel işlem, anahtarları farklı şekilde seçer. Bu durum, imzalama ve doğrulamanın dijital imza temel işleminde yaptığıyla aynıdır:

  • Prehash.Compute her zaman ortak anahtar kümesinin birincil anahtarını kullanır ve bu anahtarın kimliğini karma öncesi değerine kaydeder. İmzanın hangi anahtarla oluşturulacağını seçen taraftır.
  • SignPrehash.Sign, anahtar kimliğini ön karma değerinden okur ve özel anahtar kümesinin eşleşen etkin anahtarıyla imzalar. Bu taraf, başka birinin daha önce yaptığı bir seçimi takip eder. Anahtar kümesinde bu kimliğe sahip etkin bir anahtar yoksa çağrı başarısız olur.

SignPrehash anahtar kümesindeki her anahtarın bir kimlik koşulu olmalıdır. Aksi takdirde, temel öğe oluşturma işlemi başarısız olur.

Minimum güvenlik garantileri

  • Elde edilen imza, aynı anahtar türüyle Digital Signature (Dijital İmza) öğesi tarafından oluşturulan imza ile aynı özelliklere sahiptir.
  • Tink, ön karma değerine özel ayrılmış bir değer ve hesaplandığı anahtarın kimliğini içeren 5 baytlık bir önek ekler. SignPrehash yalnızca bu anahtarla değeri imzalar. Değerin bu anahtara kriptografik olarak bağlı olup olmadığı algoritmaya bağlıdır. External Mu ML-DSA için bu durum geçerlidir. Tink wire format'a bakın.
  • Mesajlar herhangi bir uzunlukta olabilir.

Dikkat etmeniz gerekenler

  • İmzalayan kişi, imzaladığı şeyi inceleyemez. SignPrehash kullanıcısını arayabilen herkes rastgele bir mesajı imzalatabilir ve imzalayan, mesaj içeriklerine politika uygulayamaz. SignPrehash hizmetine erişimi, PublicKeySign hizmetine erişimi koruduğunuz şekilde koruyun.
  • Geçiş hâlindeki ön karma değerini koruyun. Gizli değildir ancak iletim sırasında bunu değiştirebilen bir saldırgan, neyin imzalanacağını kontrol eder.

Anahtar türü seçin

RFC 9881'de açıklandığı gibi, External Mu modundaki ML-DSA, Tink'in Prehash ve SignPrehash için desteklediği tek algoritmadır. Bu temel öğelerle birlikte standart bir ML-DSA anahtarı kullanmanız gerekir.

Çoğu kullanım alanı için ML_DSA_65'i kullanmanızı öneririz.

Her ön karma değeri, hesaplandığı anahtarın kimliğini içeren bir önekle başladığından anahtarın kimlik koşulu olmalıdır. Aşağıdaki varyantlar kabul edilir:

  • TINK -- Sonuçta ortaya çıkan imza, Tink'in normal 5 baytlık çıkış ön ekiyle başlar.
  • NO_PREFIX_WITH_PREHASH_ID: Sonuçta elde edilen imza, çıktı öneki içermez. Anahtar ise karma oluşturma öncesi değerin ihtiyaç duyduğu kimliğe sahiptir.

NO_PREFIX (ham) varyantını kullanan anahtarlar, anahtar kimliği içermediğinden desteklenmez.