Zum Inhalt springen
ecdsa.com
Java · Kotlin

Tink (Java)

Googles Tink für Java, eine missbrauchsresistente Krypto-API rund um Keysets und Templates: Standardsignaturen tragen ein 5-Byte-Präfix von Tink, das keine andere Bibliothek versteht, und die Namen der Templates verraten nicht, welche Kodierung du bekommst.
Lizenz
Apache-2.0
Geprüfte Version
1.24.0 ·
Quellcode
github.com/tink-crypto/tink-java
Dokumentation
developers.google.com/tink

Kompatibilität auf einen Blick

ECDSAEdDSA

ECDSA-Kurven
P-256P-384P-521
EdDSA
Ed25519

Tink ersetzt einzelne Schlüssel durch Keysets – Sammlungen von Schlüsseln mit IDs, von denen einer als primär markiert ist – und Algorithmen durch benannte Templates wie ECDSA_P256 oder ED25519. Die Primitive (PublicKeySign, PublicKeyVerify) rotieren Schlüssel transparent; das ist der Sinn des Designs und zugleich die Quelle seiner Überraschungen bei der Interoperabilität. Keysets werden als Tink-JSON oder binäres Protobuf gespeichert, nicht als PEM.

Das Standard-Template ECDSA_P256 stellt ein Ausgabepräfix voran: 0x01 und die 4 Byte lange Schlüssel-ID, gefolgt von einer DER-Signatur. Das JDK lehnte eine solche Signatur mit Invalid encoding for signature ab, und genauso wird es jeder Verifizierer außerhalb von Tink tun. Templates, deren Name auf _WITHOUT_PREFIX oder _RAW endet, lassen das Präfix weg, aber die Namen verbergen auch die Kodierung: ECDSA_P256_RAW erzeugte 64 Byte r‖s nach IEEE P1363, kein DER – die Signatur bestand die Prüfung mit SHA256withECDSAinP1363Format des JDK und scheiterte mit SHA256withECDSA. Wähle das Template nach der genauen Kodierung, die die Gegenseite erwartet, wie es das Beispiel mit ECDSA_P256_IEEE_P1363_WITHOUT_PREFIX tut, und prüfe die Bytes mit dem Konverter DER ⇄ Raw.

Ein fremder öffentlicher Schlüssel wird über SignaturePemKeysetReader importiert, und der so entstandene Schlüssel prüfte nur DER-Signaturen: Dieselbe rohe Signatur, die Tinks eigener P1363-Schlüssel akzeptierte, scheiterte am aus PEM importierten Schlüssel, bis sie in DER umkodiert wurde. Signaturen verwenden zufällige Nonces, s wird nicht normalisiert, und die Prüfung akzeptiert High-S; ungültige Eingaben lösen GeneralSecurityException: invalid signature aus.

Tink für Java 1.24.0 bietet Templates für ECDSA auf P-256, P-384 und P-521, für Ed25519 und für RSA (PKCS#1 v1.5 und PSS); ein Template für ML-DSA oder SLH-DSA ist in diesem Release nicht registriert (Name ML_DSA_65 does not exist). Für Post-Quanten-Signaturen auf der JVM greifst du heute zu Java JCA oder Bouncy Castle.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/tink/run.sh hat Tink (Java) 1.24.0 am 20. Oktober 2026 im Container-Image maven:3.9.16-eclipse-temurin-25 ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • Kodierung von ECDSA-Signaturen

    der

    Signaturen des Templates ECDSA_P256 sind nach dem Ausgabepräfix DER-kodiert.

    Von der Prüfung aufgezeichnet
    fact ecdsa-signature-encoding = der
  • Signaturpräfix

    tink-5-byte

    Standard-Templates stellen ein 5-Byte-Präfix voran – 0x01 und die Schlüssel-ID –; das JDK lehnte solche Signaturen mit Invalid encoding for signature ab.

    Von der Prüfung aufgezeichnet
    fact output-prefix = tink-5-byte
    evidence output-prefix: ECDSA_P256 signature starts with 0x01 followed by the 4-byte key id, then the DER signature
    evidence output-prefix: ECDSA_P256_IEEE_P1363 signature: 69 bytes (5-byte prefix + 64)
    evidence output-prefix: ECDSA_P256 signature given to the JDK with the prefix: SignatureException: Invalid encoding for signature
  • Kodierung des RAW-Templates

    ieee-p1363

    ECDSA_P256_RAW erzeugte 64 Byte r‖s nach IEEE P1363 (ohne Präfix, kein DER); die Signatur bestand die Prüfung mit SHA256withECDSAinP1363Format.

    Von der Prüfung aufgezeichnet
    fact raw-template-encoding = ieee-p1363
    evidence raw-template-encoding: ECDSA_P256_RAW signature: 64 bytes, parses as DER: false
    evidence raw-template-encoding: ECDSA_P256_RAW signature verifies in the JDK's SHA256withECDSAinP1363Format: true
  • Signaturkodierung nach PEM-Import

    der

    Ein über SignaturePemKeysetReader aus PEM importierter öffentlicher Schlüssel prüfte nur DER-Signaturen; eine rohe r‖s-Signatur scheiterte, bis sie in DER umkodiert wurde.

    Von der Prüfung aufgezeichnet
    fact pem-import-encoding = der
  • ECDSA-Nonce

    random

    Zufällige Nonce: Zwei Signaturen derselben Nachricht unterscheiden sich.

    Von der Prüfung aufgezeichnet
    fact ecdsa-nonce = random
  • Low-S beim Signieren

    either

    s wird nicht normalisiert: Unter 64 Signaturen traten High-S-Werte auf.

    Von der Prüfung aufgezeichnet
    fact ecdsa-low-s-sign = either
  • High-S bei der Prüfung

    accepts-high-s

    Eine Signatur, in der s durch n − s ersetzt war, bestand die Prüfung.

    Von der Prüfung aufgezeichnet
    fact ecdsa-low-s-verify = accepts-high-s
  • Was der Signaturaufruf hasht

    hashes-message

    Die Primitive signieren die Nachricht; eine API zum Signieren eines Digests gibt es nicht.

    Von der Prüfung aufgezeichnet
    fact ecdsa-prehash = hashes-message
  • Fehlerhafte ECDSA-Signatur

    throws

    Eine fehlerhafte Signatur löst GeneralSecurityException: invalid signature aus.

    Von der Prüfung aufgezeichnet
    fact ecdsa-malformed-signature = throws
    evidence ecdsa-malformed-signature: GeneralSecurityException: invalid signature
  • ECDSA-Kurven

    P-256P-384P-521

    Signieren und Prüfen funktionierten mit den Templates für P-256, P-384 und P-521.

    Von der Prüfung aufgezeichnet
    fact ecdsa-curves = P-256, P-384, P-521
  • EdDSA

    Ed25519

    Ed25519-Templates, mit und ohne Ausgabepräfix.

    Von der Prüfung aufgezeichnet
    fact eddsa = Ed25519
  • Post-Quanten-Algorithmen

    none

    In Tink für Java 1.24.0 sind keine Templates für ML-DSA oder SLH-DSA registriert.

    Von der Prüfung aufgezeichnet
    fact pqc = none
    evidence pqc: ML_DSA_65: GeneralSecurityException: Name ML_DSA_65 does not exist
    evidence pqc: SLH_DSA_SHA2_128S: GeneralSecurityException: Name SLH_DSA_SHA2_128S does not exist
  • Formate öffentlicher Schlüssel

    spki-pem

    SPKI als PEM über SignaturePemKeysetReader; ansonsten liegen Schlüssel in Tink-Keysets.

    Von der Prüfung aufgezeichnet
    fact public-key-formats = spki-pem
    evidence public-key-formats: SPKI PEM through SignaturePemKeysetReader, then verifying the RAW template's raw signature: GeneralSecurityException: invalid signature
    evidence public-key-formats: the same signature re-encoded as DER against the PEM-imported key: ok
    evidence public-key-formats: Tink JSON public keyset round trip: ok
  • Keyset-Format

    tink-jsontink-binary

    Keysets werden als Tink-JSON oder binäres Protobuf serialisiert; das öffentliche Keyset ließ sich als JSON schreiben und unverändert wieder einlesen.

    Von der Prüfung aufgezeichnet
    fact keyset-format = tink-json, tink-binary

Verwendung

Vergleiche eine Standardsignatur mit Präfix mit einer portablen 64-Byte-Signatur aus einem Template ohne Präfix.
import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.RegistryConfiguration;
import com.google.crypto.tink.signature.SignatureConfig;
import java.nio.charset.StandardCharsets;

public class Usage {
    public static void main(String[] args) throws Exception {
        SignatureConfig.register();
        byte[] message = "order #1042 approved".getBytes(StandardCharsets.UTF_8);

        // Default templates prepend a 5-byte key-id prefix that no other library expects.
        KeysetHandle tinkOnly = KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
        byte[] prefixed = tinkOnly.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class).sign(message);

        // For signatures other systems verify, pick a *_WITHOUT_PREFIX / *_RAW template.
        KeysetHandle portable = KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256_IEEE_P1363_WITHOUT_PREFIX"));
        byte[] raw = portable.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class).sign(message);
        portable.getPublicKeysetHandle().getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class).verify(raw, message);

        System.out.println("prefixed first byte: 0x0" + prefixed[0] + ", portable signature: " + raw.length + " bytes, verified");
    }
}

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image maven:3.9.16-eclipse-temurin-25 aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Befehl
java -cp 'lib/*' Usage.java 2>/dev/null
Ausgabe muss passen (regulärer Ausdruck)
prefixed first byte: 0x01, portable signature: 64 bytes, verified

Bibliotheken