KDPika Licensing Sign inStart free
API v1
Show all languages
Browse documentation

Choose a page in the navigation drawer.

KDPika Licensing · API v1 Advanced

Signature test vectors

Download real public-safe Signer vectors and test authenticity separately from expiry, trust and license policy.

On this page
Updated 2026-10-17 UTCDownload Markdown

Use synthetic, reproducible signed payloads to check whether your verifier accepts authentic bytes and rejects unsafe input.

What you will learn

  • Download the public keys and envelopes.
  • Interpret positive, negative and expired expectations.
  • Run one repeatable self-test without network calls.

Prerequisites

Vector catalogue

The machine-readable index lists each trusted-key filename, envelope filename and expected cryptographic result. Download all files and the runner, or use the individually linked JSON below. Keys and payloads are synthetic; no private key or activation token is included.

CaseSignatureLicense permissionInput
positivetrueActive at the captured server time with the documented bindingEnvelope
integral-floattrueActive at captured time; preserves 19.0Envelope
tamperedfalseRejectEnvelope
wrong-keyfalseReject with the separately supplied wrong trusted keyEnvelope
expiredtrueReject: expiry is in 2020Envelope
unicodetrueCanonicalization test, not a complete licenseEnvelope
numberstrueCanonicalization test, not a complete licenseEnvelope
key-ordertrueCanonicalization test, not a complete licenseEnvelope
normalizationtrueTwo distinct Unicode names remain distinctEnvelope
nestedtrueLists, nulls and nested objects preserve their types/orderEnvelope
wrong-algorithm / wrong-key-idfalseReject untrusted envelope metadataSee index
short-signature / padded-signaturefalseReject malformed base64url/signatureSee index
missing-payload / array-payloadfalseReject malformed envelopeSee index
duplicate-property / escaped-duplicatefalseReject ambiguous JSON namesSee index
trailing-content / invalid-unicode / depth-limitfalseReject malformed or excessive inputSee index
replacement-surrogate / replacement-invalid-utf8falseReject malformed input instead of silently repairing it to a valid signed replacement characterSee index

Captured public key

positive.key.json is the separately trusted test anchor for the captured positive response.

positive.key.jsonjson
{"algorithm":"Ed25519","key_id":"ed25519_c8beae78c32584df","public_key":"HC1rqDdeN-nHyHTRmNL3s_sVfhtD6VOk6INbzSR26UA","encoding":"base64url"}

Complete captured envelope

The positive response was captured from a real isolated local Sandbox activation. Its dates describe that capture, not a currently valid purchase. The expired and stress cases were signed by the unchanged server Signer using isolated synthetic keys; they are not claimed successful API activations of expired licenses.

positive.envelope.jsonjson
{"payload":{"license_id":"lic_18d0daa92fddced51a44ed14","product_id":"app_f6cc3e1e2b2db33273b3","product":"Docs fixture product","plan":"fixture-plan","status":"active","environment":"sandbox","expires_at":"2026-11-13T17:43:50+00:00","license_key_mask":"TESTDOCS-••••-••••-7CCL","starts_at":"2026-10-14T17:43:50+00:00","created_at":"2026-10-14T19:43:50+00:00","max_devices":2,"max_activations":4,"activation_count":1,"min_version":null,"max_version":null,"active_devices":1,"customer":{"id":"cus_9df14dc98f63999a6adf69c8","name":"Synthetic Example User","email":"customer@example.invalid","company":null,"country":null},"product_details":{"id":"app_f6cc3e1e2b2db33273b3","name":"Docs fixture product","platform":"desktop"},"plan_details":{"id":"plan_4de2dfbe92a4aac4b0e880ac","name":"Fixture plan","slug":"fixture-plan","billing_type":"monthly","price":19.5,"currency":"EUR","duration_days":30,"trial_days":null},"features":{"pdf_export":true},"device":{"id":"dev_af3087ec2eeb536a4f4c61a7","installation_hash":"d46f8ccf48213ab042bf83539f20aae1bd14056475471aa40b32e2565ad0ea73","name":"Synthetic local fixture","platform":"test","app_version":"1.0.0"},"server_time":"2026-10-14T17:43:50+00:00","next_validation_at":"2026-10-15T17:43:50+00:00","offline_grace_until":"2026-10-21T17:43:50+00:00"},"signature":"TvLKHsvFR2O2ip13W2XqwMjA_PyUa7Q26TiVL5LcAS7nIFGOUuuU6oto9lAhYLwwyQoWaKls5sUFWLgOzdkgAg","algorithm":"Ed25519","key_id":"ed25519_c8beae78c32584df"}

Repeatable procedure

  1. Extract the archive into a new directory.
  2. Open the selected language page and build its verifier.
  3. Run the shared runner with --command followed by the verifier command and no input filenames.
  4. Confirm PASS23 and exit 0.
  5. Change one byte in a copy of a valid payload and verify refusal.
  6. Run the expired vector and confirm signature_valid=true, then reject it in your expiry policy.

Expected result: every signature expectation matches; the runner treats a required refusal as a passing test. It does not compare a test vector's claimed result to itself without executing your verifier.

Shared test runner

selftest.pypython
"""Run every public vector using your verifier; Python 3.9+, standard library.
Run: python3 selftest.py --command python3 python/verify.py
Expected: PASS23 and exit0. A mismatched result prints FAIL and exits1.
No network, database, credentials, SDK monkey-patching or access decision.
"""
import argparse
import json
import pathlib
import subprocess
import sys

parser = argparse.ArgumentParser()
parser.add_argument('--command', nargs=argparse.REMAINDER, required=True)
args = parser.parse_args()
root = pathlib.Path(__file__).resolve().parent
vectors = json.loads((root / 'vectors/index.json').read_text())['vectors']
failures = []
for row in vectors:
    command = args.command + [str(root / 'vectors' / row['key']), str(root / 'vectors' / row['envelope'])]
    try:
        result = subprocess.run(command, capture_output=True, text=True, timeout=30)
        expected = row['signature_valid']
        ok = (result.returncode == (0 if expected else 1)
              and result.stdout.strip() == 'signature_valid=' + str(expected).lower()
              and not result.stderr)
    except (OSError, subprocess.TimeoutExpired):
        ok = False
    if not ok:
        failures.append(row['name'])
if failures:
    print('FAIL: ' + ', '.join(failures))
    sys.exit(1)
print('PASS' + str(len(vectors)))

Why expiry is not a negative signature

Ed25519 proves authenticity of bytes. It does not read the clock. The expired case is deliberately signature-positive and authorization-negative. Your app must also enforce the expected product, environment, installation hash, active state, start/expiry and validation/grace deadlines. Stress cases lack complete license fields and must never grant access.

The captured installation ID is the public synthetic value p1-installation-0000000001. Semantic checks use its SHA-256 and the captured server_time; the runner itself tests only authenticity.

Expected result

All 23 cases match the index in every listed language; expired is authentic but unusable.

Common mistakes

  • Expecting an authentic expired signature to fail cryptographically.
  • Running a vector with another case's key file.
  • Editing numbers while formatting the envelope.

Security notes

Treat all vector keys as disposable test anchors. Malformed-vector files intentionally contain invalid JSON or duplicate names; refusal is required. Never import their payloads as real customers or licenses.

Troubleshooting

SymptomCauseAction
Positive failsWrong key or changed representationUse the exact pair named in index.json
Expired returns trueCorrect authenticity resultApply expiry separately
Duplicate case cannot parseExpected security refusalPreserve the nonzero result

Next steps

Read signed responses and the threat model, then validate your own integration in Sandbox.

Was this page helpful?

Choose an answer

Do not include personal data, license keys or credentials. Retained for up to 30 days. This is not a support inbox.

Search documentation

Arrow keys to move, Enter to open, Escape to close. Search stays in your browser.

Cookie settings