메일을 보낼 수 없는 위치에 비공개 키가 있는 경우 ML_DSA_65 키와 함께 Prehash 및 SignPrehash 기본 요소를 사용하는 것이 좋습니다.
서명 키를 보유한 당사자가 메시지를 직접 수신할 수 없거나 수신해서는 안 되는 경우가 있습니다. 키가 HSM 또는 KMS에 있거나 메시지가 서명자의 요청 크기 제한보다 큰 경우입니다.
Prehash 및 SignPrehash 기본 요소는 서명을 두 단계로 분할하여 이 문제를 해결합니다. 메시지가 있는 곳에서 공개 키만 사용하여 짧은 사전 해시 값을 계산하고 서명자에게 전송합니다. 서명자는 메시지를 확인하지 않고 비공개 키를 사용하여 서명으로 변환합니다. 외부 Mu 모드의 ML-DSA(여기서 알고리즘 Tink가 지원됨)를 사용하면 메시지 크기와 관계없이 사전 해시 값은 69바이트입니다.
돌아오는 서명은 원래 메시지에 대한 일반 서명입니다. 검증자는 일반 디지털 서명 기본 요소를 사용하며 두 단계가 포함되었음을 알 필요가 없습니다.
시작하기 전에
키에 ID 요구사항이 있는 ML-DSA 키 세트를 만듭니다. TINK 변형 또는 결과 서명에 출력 접두사를 원하지 않는 경우 NO_PREFIX_WITH_PREHASH_ID입니다. 서명자에게 비공개 키 세트를 제공하고 사전 해싱 측에 해당 공개 키 세트를 제공합니다. 서명자에게는 사전 해싱 측에서 생성할 수 있는 모든 키 ID에 대해 사용 설정된 키가 있어야 합니다(키 세트 참고).
1단계: 사전 해시 값 계산
메시지가 있는 곳에서 이 명령어를 실행합니다. 공개 키 세트만 필요합니다.
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단계: 서명자에게 사전 해시 값 전송
비공개 키를 보유한 항목에 사전 해시 값을 전송합니다. 비밀은 아니지만 전송 중에 무결성을 보호해야 합니다. 전송 중에 수정할 수 있는 공격자는 서명되는 내용을 제어합니다.
3단계: 사전 해시 값 서명
비공개 키가 있는 위치에서 실행합니다.
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단계: 서명 확인
확인은 사전 해시 값이 아닌 원래 메시지에 대한 일반적인 디지털 서명 흐름입니다.
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 및 SignPrehash
Prehash 및 SignPrehash 기본 요소는 디지털 서명 계산을 다음 두 단계로 분할합니다.
- Prehash에는 public 키만 필요합니다. 임의 길이의 메시지를 고정 크기의 짧은 사전 해시 값으로 변환합니다.
- SignPrehash에는 private 키가 필요합니다. 사전 해시 값을 서명으로 변환합니다.
결과로 나오는 서명은 원래 메시지에 대한 일반 서명입니다. 일반적인 디지털 서명 PublicKeyVerify 기본 요소로 이를 확인하며, 검증자는 서명이 2단계로 생성되었음을 알거나 신경 쓸 필요가 없습니다.
사전 해시 값을 불투명 바이트로 취급합니다. 크기가 고정되어 있고 계산된 키의 ID를 전달하지만 레이아웃은 Tink의 와이어 형식의 일부이므로 직접 파싱하거나 구성해서는 안 됩니다. Tink를 포팅하거나 바이트 수준 세부정보가 필요한 경우 Tink 와이어 형식을 참고하세요.
다음과 같은 경우 이 기본 요소 쌍을 사용하세요.
- 서명 키가 다른 곳에 있음(예: HSM, KMS 또는 RPC 경계 뒤) 및 해당 경계를 넘어 전체 메시지를 전송하지 않으려는 경우
- 메시지가 크고 원격 서명자가 요청 크기 제한을 적용합니다.
둘 다 적용되지 않으면 대신 일반 디지털 서명 기본 요소를 사용하세요. 더 간단하고 오용하기가 더 어렵습니다.
키 세트
두 프리미티브는 디지털 서명 프리미티브의 서명 및 확인과 마찬가지로 키를 다르게 선택합니다.
Prehash.Compute는 항상 공개 키 세트의 기본 키를 사용하고 해당 키의 ID를 사전 해시 값에 기록합니다. 서명에 사용할 키를 선택하는 측입니다.SignPrehash.Sign는 사전 해시 값에서 키 ID를 읽고 비공개 키 세트의 일치하는 사용 설정된 키로 서명합니다. 다른 사용자가 이미 선택한 항목을 따르는 쪽입니다. 키 세트에서 사용 설정된 키에 해당 ID가 없으면 호출이 실패합니다.
SignPrehash 키 세트의 모든 키에는 ID 요구사항이 있어야 합니다. 그렇지 않으면 기본 요소 생성이 실패합니다.
최소한의 보안 보장
- 결과 서명은 동일한 키 유형으로 디지털 서명 기본 요소에 의해 생성된 서명과 동일한 속성을 갖습니다.
- Tink는 사전 해시 값에 특수 예약 값과 계산된 키의 ID를 포함하는 5바이트를 접두사로 추가합니다.
SignPrehash는 해당 키로만 값을 서명합니다. 값이 해당 키에 암호화로 바인딩되는지 여부는 알고리즘에 따라 다릅니다. 외부 Mu ML-DSA의 경우 바인딩됩니다(Tink 와이어 형식 참고). - 메시지의 길이는 임의로 지정할 수 있습니다.
주의사항
- 서명자는 서명하는 내용을 검사할 수 없습니다.
SignPrehash에 전화를 걸 수 있는 사용자는 누구나 임의의 메시지에 서명을 받을 수 있으며 서명자는 메시지 콘텐츠에 정책을 적용할 방법이 없습니다.PublicKeySign에 대한 액세스를 보호하는 것과 똑같이SignPrehash에 대한 액세스를 보호합니다. - 전송 중인 사전 해시 값 보호 비밀은 아니지만 이동 중에 수정할 수 있는 공격자가 서명되는 항목을 제어합니다.
키 유형 선택
RFC 9881에 설명된 대로 외부 Mu 모드의 ML-DSA는 Tink가 Prehash 및 SignPrehash에 지원하는 유일한 알고리즘입니다. 이러한 기본 요소와 함께 표준 ML-DSA 키를 사용해야 합니다.
대부분의 사용 사례에는 ML_DSA_65가 권장됩니다.
모든 사전 해시 값은 계산된 키의 ID가 포함된 접두사로 시작하므로 키에는 ID 요구사항이 있어야 합니다. 다음 변형이 허용됩니다.
TINK- 결과 서명은 Tink의 일반적인 5바이트 출력 접두사로 시작합니다.NO_PREFIX_WITH_PREHASH_ID- 결과 서명에는 출력 접두사가 없지만 키에는 사전 해시 값에 필요한 ID가 여전히 있습니다.
NO_PREFIX (원시) 변형을 사용하는 키는 키 ID가 없으므로 지원되지 않습니다.