Select programming language for code examples

linkCryptography

Each Keygen account is equipped with multiple unique public/private keypairs**, which are used for example, in signing response payloads using RSA-SHA256, and which can also be used to sign or encrypt license keys for added security and offline-capable license verification using cryptographic schemes. The algorithm used for license key signing and encryption will depend on the cryptographic scheme that the particular policy implements.

You can find your account's public keys within your dashboard settings page, which you can use to verify response payloads, webhooks and license keys. Private keys are kept securely encrypted on our servers and never shared.

To see an example of cryptographic validation, check out our example on GitHub. It will show you how to utilize your account's public key to validate various cryptographic license key schemes.

linkCryptographic keys

Below you will find information on various license key encryption and signature schemes. These can be used verified in offline or air-gapped environments, or to increase security and confidence for embedded key datasets. Most embedded datasets have a default, but they can be changed to include more data, or less data. The sky's the limit.

Once a license key is created, it cannot be changed, i.e. license keys are immutable. This means the dataset that you choose to embed into a license key cannot be changed, and changes to the license object itself have no effect on the embedded dataset.

Please take this into account when crafting your embedded dataset. If you plan on renewing licenses after or before an expiration date, you may wish to embed the amount of time a license is allowed to be used offline, e.g. a numeric duration such as 1 year, instead of a hard expiration date.

If you need to change the dataset, e.g. to extend an embedded expiration date after renewal, a new license key will need to be created. This is not a limitation of cryptographic keys or of Keygen, but a feature of cryptography which actually shows how keys are 100% tamper-proof — any data modification invalidates the signature.

Cryptographic keys can be used as a typical 'license file.' You can pack them up as a text file and distribute them to your users. The integrity of the file can then be verified by verifying the key's signature, or decrypting the key value. Some businesses prefer this over distributing the relatively large cryptographic key in text form.

linkED25519_SIGN

Sign license keys with your account's Ed25519 signing key. This is our recommended signing scheme, due to its smaller signature size, and higher security level, when compared to 2048-bit RSA.

key/emVrZUBrZXlnZW4uZXhhbXBsZQ==.D1pk7hqD_KNV9UNpl1IDQqpa4qaBjFBNrtP74yEM7v0xCmLRrDhZdSHGx47TN2RKARfGIigX9tE4yVOjhQvfAQ==

The final signed key consists of the following format:

SIGNING_PREFIX = "key"
SIGNING_DATA = "{SIGNING_PREFIX}/{BASE64_DATASET}"
BASE64_SIGNATURE = ed25519_sign(SIGNING_DATA)
 
"{SIGNING_DATA}.{BASE64_SIGNATURE}"

An embedded dataset may be given during license creation via the key attribute. This dataset will be used to create the key signature, and it will be encoded for easier transfer. It can be decoded within your software and its authenticity can be verified cryptographically. The default dataset is a JSON object, as follows:

{
"account": {
"id": "fa4e22c6-436f-4134-b976-79df910acf69"
},
"product": {
"id": "2c035cde-aa1b-47c1-bdbe-df0b29d8c5fb"
},
"policy": {
"id": "6e29580f-a3eb-49e3-8820-f6e03ae9230b",
"duration": null
},
"user": null,
"license": {
"id": "fd293be1-f605-422d-a022-37946f58c0fd",
"created": "2021-03-22T12:46:18.217Z",
"expiry": null
}
}

The user property may be null depending on the license's user relationship. The license's expiry and policy's duration attributes may also be null if the license does not expire.

linkRSA_2048_PKCS1_PSS_SIGN_V2

Sign license keys with your account's 2048-bit RSA private key using RSA PKCS1-PSS padding, with a SHA256 digest, max salt length, and a SHA256 MGF1. We recommend verifying with a salt length of auto when available.

key/eyJhY2NvdW50Ijp7ImlkIjoiZmE0ZTIyYzYtNDM2Zi00MTM0LWI5NzYtNzlkZjkxMGFjZjY5In0sInByb2R1Y3QiOnsiaWQiOiIyYzAzNWNkZS1hYTFiLTQ3YzEtYmRiZS1kZjBiMjlkOGM1ZmIifSwicG9saWN5Ijp7ImlkIjoiNmUyOTU4MGYtYTNlYi00OWUzLTg4MjAtZjZlMDNhZTkyMzBiIiwiZHVyYXRpb24iOm51bGx9LCJ1c2VyIjpudWxsLCJsaWNlbnNlIjp7ImlkIjoiZmQyOTNiZTEtZjYwNS00MjJkLWEwMjItMzc5NDZmNThjMGZkIiwiY3JlYXRlZCI6IjIwMjEtMDMtMjJUMTI6NDY6MTguMjE3WiIsImV4cGlyeSI6bnVsbH19.ZIXTH2HhILamEedSXoFSn9EFloOOUtPulq37T7YnJJolRF18-NaMb7L22ozG2v1NtioX5ZK20iSmGnTy6dLsPjaK3PpM1gL4BAD4yQuU979EuyAz7j169lpiyBtx7ytOTIJ_hr1aAMotl97BY8mBQAn-ASctNnmLqeYD0IvVniMBPes64FM5GPfyK8IIdfX23XRue3HW1nHiPBFvmiaH-_WSY81cl6fQYdrmbGJn0FSP9QYK2-CCsw1OzE_q47YmH5-Z_-VzfFnEBWLsrSvlz3HRlD5N6QhT_kl4jkN-7hou76vS1-P_DN-VD5rNXQSxKxPnbFvtSIX3rk0WCSw3rQ==

The final signed key consists of the following format:

SIGNING_PREFIX = "key"
SIGNING_DATA = "{SIGNING_PREFIX}/{BASE64_DATASET}"
BASE64_SIGNATURE = rsa_pkcs1_pss_sign(SIGNING_DATA)
 
"{SIGNING_DATA}.{BASE64_SIGNATURE}"

An embedded dataset may be given during license creation via the key attribute. This dataset will be used to create the key signature, and it will be encoded for easier transfer. It can be decoded within your software and its authenticity can be verified cryptographically. The default dataset is a JSON object, as follows:

{
"account": {
"id": "fa4e22c6-436f-4134-b976-79df910acf69"
},
"product": {
"id": "2c035cde-aa1b-47c1-bdbe-df0b29d8c5fb"
},
"policy": {
"id": "6e29580f-a3eb-49e3-8820-f6e03ae9230b",
"duration": null
},
"user": null,
"license": {
"id": "fd293be1-f605-422d-a022-37946f58c0fd",
"created": "2021-03-22T12:46:18.217Z",
"expiry": null
}
}

The user property may be null depending on the license's user relationship. The license's expiry and policy's duration attributes may also be null if the license does not expire.

linkRSA_2048_PKCS1_SIGN_V2

Sign license keys with your account's 2048-bit RSA private key using RSA PKCS1 v1.5 padding, with a SHA256 digest.

key/eyJhY2NvdW50Ijp7ImlkIjoiZmE0ZTIyYzYtNDM2Zi00MTM0LWI5NzYtNzlkZjkxMGFjZjY5In0sInByb2R1Y3QiOnsiaWQiOiIyYzAzNWNkZS1hYTFiLTQ3YzEtYmRiZS1kZjBiMjlkOGM1ZmIifSwicG9saWN5Ijp7ImlkIjoiNmUyOTU4MGYtYTNlYi00OWUzLTg4MjAtZjZlMDNhZTkyMzBiIiwiZHVyYXRpb24iOjMxNTU2OTUyfSwidXNlciI6eyJpZCI6ImE0OTliYjkzLTk5MDItNGI1Mi04YTA0LTc2OTQ0YWQ3ZjY2MCIsImVtYWlsIjoidXNlckBrZXlnZW4uZXhhbXBsZSJ9LCJsaWNlbnNlIjp7ImlkIjoiZjJjNjU2MDItOTJhOC00MTFmLTlmZWYtZWRhMGE2NjJmOWI2IiwiY3JlYXRlZCI6IjIwMjEtMDMtMjJUMTI6NTE6MjYuMTI5WiIsImV4cGlyeSI6IjIwMjItMDMtMjJUMTI6NTE6MjYuMTI5WiJ9fQ==.Jfs9Xu3_Osqf0dSQpI766WHVG9IacWbIzcQHJrPQR1zwriwjW0v1aR6AYTDOHXfNp81O33kWK23MOf-kkC5U9Gkiq_7ca7FdHLgzLGjZ3216QigxCweOWAHzit37kvaDvXinyS3ceGvDI6tt_FldcoaByHJXTovKjsQzRYaGJmI9r8wfgBor5nQ6NCTm3v6lYA9Ae_6Rs3AR7DgMM2kEr0GAhDNja_VyrZthsrRsU5r5ELo4AlVCdzdhNCD8KzA4PPrD_KsCaKGjQak1sd0kXYx-IOr5vXJpiuhgyGdGyKVSKOejO_2TbY2oxuVGNg6aWGxv0hEiXJuChAzAI7_NmA==

This key consists of the following format:

SIGNING_PREFIX = "key"
SIGNING_DATA = "{SIGNING_PREFIX}/{BASE64_DATASET}"
BASE64_SIGNATURE = rsa_pkcs1_sign(SIGNING_DATA)
 
"{SIGNING_DATA}.{BASE64_SIGNATURE}"

An embedded dataset may be given during license creation via the key attribute. This dataset will be used to create the key signature, and it will be encoded for easier transfer. It can be decoded within your software and its authenticity can be verified cryptographically. The default dataset is a JSON object, as follows:

{
"account": {
"id": "fa4e22c6-436f-4134-b976-79df910acf69"
},
"product": {
"id": "2c035cde-aa1b-47c1-bdbe-df0b29d8c5fb"
},
"policy": {
"id": "6e29580f-a3eb-49e3-8820-f6e03ae9230b",
"duration": 31556952
},
"user": {
"id": "a499bb93-9902-4b52-8a04-76944ad7f660",
"email": "[email protected]"
},
"license": {
"id": "f2c65602-92a8-411f-9fef-eda0a662f9b6",
"created": "2021-03-22T12:51:26.129Z",
"expiry": "2022-03-22T12:51:26.129Z"
}
}

The user property may be null depending on the license's user relationship. The license's expiry and policy's duration attributes may also be null if the license does not expire.

linkRSA_2048_PKCS1_ENCRYPT

Encrypt license keys with your account's 2048-bit RSA private key using RSA PKCS1 v1.5 padding.

S-Pg5rnVDE-7hG5Ep0RlL_6yah04aDqo9zhQR04VFurWJyq9GrQdODh90DlkzNBeFoypt6tD1_QxUecw24XqLQrhu3wRBiD4sDxWKIWX5PehyLSdGxD-U_zpZ5yVDw1Cexp9bivIWcV_Ld7Og5H56cN092iFjlctJ-HI1IPuk6W1hYxWlVGchasOshMyQdE-BLsW7PaeYqUHC5jQdo3huHX17p0GcaRMepvXzBbqjABJyUFZIwXue-ApadK2H0ActISG-zMJGF7uqpNrFCKMYISDWPAkmYSa_jZHIvR7uoTGNlaAcWwVhQDKt7XH1eVaZxZZtvQrTvoH72Mcv5-0kA==

This key consists of the following format:

BASE64_CIPHERTEXT = rsa_pkcs1_encrypt(BASE64_DATASET)
 
"{BASE64_CIPHERTEXT}"

An embedded dataset may be given during license creation via the key attribute. The dataset must contain no more than 245 bytes (please note this is byte length not string length). The default dataset is a JSON object, as follows:

{
"id": "4040b22a-73df-48b5-8f90-bacacd2b6602",
"created": "2021-03-15T19:27:50.440Z",
"expiry": "2022-03-15T19:27:50.440Z",
"duration": 31556952
}

The expiry and duration attributes may be null if the license does not expire.

linkRSA_2048_JWT_RS256

Encode a license claims payload into a JWT using the RS256 algorithm.

eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiJjMGM4ZGMyMy03MDI1LTRmNjQtYWUwOC1iMzg4OWZlYmEwM2IiLCJpc3MiOiJodHRwczovL2tleWdlbi5zaCIsImF1ZCI6ImJmOWI1MjNmLWRkNjUtNDhhMi05NTEyLWZiNjZiYTZjMzcxNCIsInN1YiI6IjU0YjI5ODU2LWE0MjgtNGQyNy05NjY2LTliNjRlMWJmODZlZSIsImlhdCI6MTYxNTgzNzEyOCwibmJmIjoxNjE1ODM3MTI4LCJleHAiOjE2NDczNzMxMjh9.MSoZ4dqwTU0TIS_oOXMT20ViVoYDhLVn7dbOmo5Y3LAoy2DIt54jGL2PXl2G-Ov3DBSGhkp-nYbO6miigoXSPhx9okVnoyM78qbVUZVLmxcEiQ3SUrL_9oUhJul3DleQSFGvYPhGGtmK1H0xZuN5yodBY5OY6w2OJ5omOnq6hE8NdxLgZSwUb2POmtUlzUzx0kSqiG2tt1NW-j5OnGGgy1nqMDj1Cv5suoplmnCEajYd1x2w6G0Gmb9tg_iZbBkfh4tlidltK9uCiNWnHvsg3S-X3biSWQeRXP-2_BRdGAyrI5cvwZbWHPr8QdSsHTnOqUwCQ22A5YTEAGiSYp9lvQ

A custom JWT claims payload may be given during license creation via the key attribute. The default claims are as follows:

{
"jti": "c0c8dc23-7025-4f64-ae08-b3889feba03b",
"iss": "https://keygen.sh",
"aud": "bf9b523f-dd65-48a2-9512-fb66ba6c3714",
"sub": "54b29856-a428-4d27-9666-9b64e1bf86ee",
"iat": 1615837128,
"nbf": 1615837128,
"exp": 1647373128
}

Where aud is the account ID and sub is the license ID. The exp attribute may be omitted if the license does not expire.

linkRSA_2048_PKCS1_PSS_SIGN

Deprecated: use RSA_2048_PKCS1_PSS_SIGN_V2. Sign license keys with your account's 2048-bit RSA private key using RSA PKCS1-PSS padding, with a SHA256 digest, max salt length, and a SHA256 MGF1.

eyJhY2NvdW50Ijp7ImlkIjoiZmE0ZTIyYzYtNDM2Zi00MTM0LWI5NzYtNzlkZjkxMGFjZjY5In0sInByb2R1Y3QiOnsiaWQiOiIyYzAzNWNkZS1hYTFiLTQ3YzEtYmRiZS1kZjBiMjlkOGM1ZmIifSwicG9saWN5Ijp7ImlkIjoiNmUyOTU4MGYtYTNlYi00OWUzLTg4MjAtZjZlMDNhZTkyMzBiIiwiZHVyYXRpb24iOjMxNTU2OTUyfSwidXNlciI6eyJpZCI6ImE0OTliYjkzLTk5MDItNGI1Mi04YTA0LTc2OTQ0YWQ3ZjY2MCIsImVtYWlsIjoidXNlckBrZXlnZW4uZXhhbXBsZSJ9LCJsaWNlbnNlIjp7ImlkIjoiOGIwZmU2MGQtMGJjOS00Zjk4LWEwNDctZTZmOGNhMWQyNThjIiwiY3JlYXRlZCI6IjIwMjEtMDMtMjJUMTI6NTI6NTAuNjgyWiIsImV4cGlyeSI6IjIwMjItMDMtMjJUMTI6NTI6NTAuNjgyWiJ9fQ==.l2ZyC7Hc-0XrEtkhldI5c1tsLt_AY8eeW96PdeR1C3Z8F6X7xrdtXBum5UDCR2dIEf552eJY91l3cVwmFVvLTqNUWGFRDzoKHVH8w2ddwocWXSHRevBLCbfj6BLMLxBCFZOiCxQdEsoA93JcsuZmijwvphG3s26F3u5MRz5wIciE6Q4a9adKnCBhcPYP4B_ZfUwXmImMsTkqlP7x5jr8yIViFSFkEiiH4tp_xQySWtMpKBuV18LWq07KrIorHT8mrSET7EzHUNRrbE7x9J2lol5-aR8A2-7_rmM042sqvhS6EQOYqxTigPpAWILK8pT3AqnJ8o2WnZI-bks8Lbc3Mg==

This key consists of the following format:

BASE64_SIGNATURE = rsa_pkcs1_pss_sign(BASE64_DATASET)
 
"{BASE64_DATASET}.{BASE64_SIGNATURE}"

An embedded dataset may be given during license creation via the key attribute. The default dataset is a JSON object, as follows:

{
"account": {
"id": "fa4e22c6-436f-4134-b976-79df910acf69"
},
"product": {
"id": "2c035cde-aa1b-47c1-bdbe-df0b29d8c5fb"
},
"policy": {
"id": "6e29580f-a3eb-49e3-8820-f6e03ae9230b",
"duration": 31556952
},
"user": {
"id": "a499bb93-9902-4b52-8a04-76944ad7f660",
"email": "[email protected]"
},
"license": {
"id": "8b0fe60d-0bc9-4f98-a047-e6f8ca1d258c",
"created": "2021-03-22T12:52:50.682Z",
"expiry": "2022-03-22T12:52:50.682Z"
}
}

The user property may be null depending on the license's user relationship. The license's expiry and policy's duration attributes may also be null if the license does not expire.

linkRSA_2048_PKCS1_SIGN

Deprecated: use RSA_2048_PKCS1_SIGN_V2. Sign license keys with your account's 2048-bit RSA private key using RSA PKCS1 v1.5 padding, with a SHA256 digest.

Here is an example of a cryptographically signed key using RSA_2048_PKCS1_PSS_SIGN:

eyJhY2NvdW50Ijp7ImlkIjoiZmE0ZTIyYzYtNDM2Zi00MTM0LWI5NzYtNzlkZjkxMGFjZjY5In0sInByb2R1Y3QiOnsiaWQiOiIyYzAzNWNkZS1hYTFiLTQ3YzEtYmRiZS1kZjBiMjlkOGM1ZmIifSwicG9saWN5Ijp7ImlkIjoiNmUyOTU4MGYtYTNlYi00OWUzLTg4MjAtZjZlMDNhZTkyMzBiIiwiZHVyYXRpb24iOjMxNTU2OTUyfSwidXNlciI6eyJpZCI6ImE0OTliYjkzLTk5MDItNGI1Mi04YTA0LTc2OTQ0YWQ3ZjY2MCIsImVtYWlsIjoidXNlckBrZXlnZW4uZXhhbXBsZSJ9LCJsaWNlbnNlIjp7ImlkIjoiZTI2NDdkMzAtYmYyOS00N2U0LTliYjktZWU4NzRmNDI2YjI2IiwiY3JlYXRlZCI6IjIwMjEtMDMtMjJUMTI6NTM6MjAuNDE0WiIsImV4cGlyeSI6IjIwMjItMDMtMjJUMTI6NTM6MjAuNDE0WiJ9fQ==.QmWjSqJ8yfvTcf3T0sKWUXrImaFudHVR8_WLatIVNfAciJW7__70RtOyZ2ZnN4WvyDEb37Df-hal5-zKugrS9a9OCXP_NbNusQALdSqigQH-Jkekd_X0Xnp6F2v6z9SQVgrt2_kMxQ9m2WzFXVn6R_SfW-ey_aGcX3JW7th8CsX5rGr93sb7DjR7-femwS-rGLy_t3cyqf-kYP6XX0krv4BUJi5vYcEC9MnTNDkoTervk6nczAjQhybJmD5aah2c9opbRT4R0k0wCosEYkNrsdnmj1uB2AshcmpmhemnmTxjmNvKvYO3gfgGbfIDSXSzRQhzErVwN_wLr1XANmzQYQ==

This key consists of the following format:

BASE64_SIGNATURE = rsa_pkcs1_sign(BASE64_DATASET)
 
"{BASE64_DATASET}.{BASE64_SIGNATURE}"

An embedded dataset may be given during license creation via the key attribute. The default dataset is a JSON object, as follows:

{
"account": {
"id": "fa4e22c6-436f-4134-b976-79df910acf69"
},
"product": {
"id": "2c035cde-aa1b-47c1-bdbe-df0b29d8c5fb"
},
"policy": {
"id": "6e29580f-a3eb-49e3-8820-f6e03ae9230b",
"duration": 31556952
},
"user": {
"id": "a499bb93-9902-4b52-8a04-76944ad7f660",
"email": "[email protected]"
},
"license": {
"id": "e2647d30-bf29-47e4-9bb9-ee874f426b26",
"created": "2021-03-22T12:53:20.414Z",
"expiry": "2022-03-22T12:53:20.414Z"
}
}

The user property may be null depending on the license's user relationship. The license's expiry and policy's duration attributes may also be null if the license does not expire.