Skip to content
ecdsa.com
Java · Kotlin

Tink (Java)

Google's Tink for Java, a misuse-resistant crypto API built around keysets and templates: default signatures carry a 5-byte Tink prefix no other library understands, and the template names hide which encoding you get.
License
Apache-2.0
Checked version
1.24.0 ·
Source
github.com/tink-crypto/tink-java
Documentation
developers.google.com/tink

Compatibility at a glance

ECDSAEdDSA

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

Tink replaces individual keys with keysets — collections of keys with ids, one marked primary — and algorithms with named templates such as ECDSA_P256 or ED25519. The primitives (PublicKeySign, PublicKeyVerify) rotate keys transparently, which is the point of the design and the source of its interop surprises. Keysets are stored as Tink JSON or binary protobuf, not PEM.

The default ECDSA_P256 template prepends an output prefix: 0x01 and the 4-byte key id, followed by a DER signature. The JDK rejected such a signature with Invalid encoding for signature, as will every non-Tink verifier. Templates ending in _WITHOUT_PREFIX or _RAW drop the prefix, but the names also hide the encoding: ECDSA_P256_RAW produced 64 bytes of IEEE P1363 r‖s, not DER — it verified with the JDK's SHA256withECDSAinP1363Format and failed with SHA256withECDSA. Pick the template by the exact encoding the other side expects, as the sample does with ECDSA_P256_IEEE_P1363_WITHOUT_PREFIX, and check the bytes with the DER ⇄ raw converter.

Importing a foreign public key goes through SignaturePemKeysetReader, and the resulting key verified DER signatures only: the same raw signature that its own P1363 key accepted failed against the PEM-imported key until it was re-encoded as DER. Signatures use random nonces, s is not normalized and verification accepts high-S; invalid input raises GeneralSecurityException: invalid signature.

Tink for Java 1.24.0 offers ECDSA on P-256, P-384 and P-521, Ed25519 and RSA (PKCS#1 v1.5 and PSS) templates; no ML-DSA or SLH-DSA template is registered in this release (Name ML_DSA_65 does not exist). For post-quantum signatures on the JVM today see Java JCA or Bouncy Castle.

Facts and the checks behind them

Nothing below is copied from documentation. The check content/libraries/verify/tink/run.sh ran Tink (Java) 1.24.0 in the container image maven:3.9.16-eclipse-temurin-25 on October 20, 2026; the page must match what it printed, and each fact lists those lines.

  • ECDSA signature encoding

    der

    ECDSA_P256 signatures are DER after the output prefix.

    Recorded by the check
    fact ecdsa-signature-encoding = der
  • Signature prefix

    tink-5-byte

    Default templates prepend a 5-byte prefix — 0x01 and the key id — which the JDK rejected with Invalid encoding for signature.

    Recorded by the check
    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
  • Encoding of the RAW template

    ieee-p1363

    ECDSA_P256_RAW produced 64 bytes of IEEE P1363 r‖s (no prefix, not DER); it verified with SHA256withECDSAinP1363Format.

    Recorded by the check
    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
  • Signature encoding after PEM import

    der

    A public key imported from PEM through SignaturePemKeysetReader verified DER signatures only; a raw r‖s signature failed until re-encoded as DER.

    Recorded by the check
    fact pem-import-encoding = der
  • ECDSA nonce

    random

    Random nonce: two signatures of the same message differ.

    Recorded by the check
    fact ecdsa-nonce = random
  • Low-S when signing

    either

    s is not normalized: high-S values appeared among 64 signatures.

    Recorded by the check
    fact ecdsa-low-s-sign = either
  • High-S when verifying

    accepts-high-s

    A signature with s replaced by n − s verified.

    Recorded by the check
    fact ecdsa-low-s-verify = accepts-high-s
  • What the signing call hashes

    hashes-message

    Primitives sign the message; there is no API for signing a digest.

    Recorded by the check
    fact ecdsa-prehash = hashes-message
  • Malformed ECDSA signature

    throws

    A malformed signature raises GeneralSecurityException: invalid signature.

    Recorded by the check
    fact ecdsa-malformed-signature = throws
    evidence ecdsa-malformed-signature: GeneralSecurityException: invalid signature
  • ECDSA curves

    P-256P-384P-521

    P-256, P-384 and P-521 templates signed and verified.

    Recorded by the check
    fact ecdsa-curves = P-256, P-384, P-521
  • EdDSA

    Ed25519

    Ed25519 templates, with and without the output prefix.

    Recorded by the check
    fact eddsa = Ed25519
  • Post-quantum algorithms

    none

    No ML-DSA or SLH-DSA templates are registered in Tink for Java 1.24.0.

    Recorded by the check
    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
  • Public key formats

    spki-pem

    SPKI PEM through SignaturePemKeysetReader; otherwise keys live in Tink keysets.

    Recorded by the check
    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 serialize as Tink JSON or binary protobuf; the public keyset round-tripped through JSON.

    Recorded by the check
    fact keyset-format = tink-json, tink-binary

Usage

Compare a default prefixed signature with a portable 64-byte signature from a template without the prefix.
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");
    }
}

The snippet harness runs every sample verbatim in the container image maven:3.9.16-eclipse-temurin-25, and the run fails unless the output matches.

Setup
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Command
java -cp 'lib/*' Usage.java 2>/dev/null
Output must match (regular expression)
prefixed first byte: 0x01, portable signature: 64 bytes, verified

Libraries