You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@turnkey/crypto

Package Overview
Dependencies
Maintainers
8
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@turnkey/crypto - npm Package Compare versions

Comparing version
2.3.1
to
2.4.0
+1
-0
./dist/index.js

@@ -24,3 +24,4 @@ 'use strict';

exports.encryptWalletToBundle = turnkey.encryptWalletToBundle;
exports.verifySessionJwtSignature = turnkey.verifySessionJwtSignature;
exports.verifyStampSignature = turnkey.verifyStampSignature;
//# sourceMappingURL=index.js.map
# @turnkey/crypto
## 2.4.0
### Minor Changes
- [#662](https://github.com/tkhq/sdk/pull/662) [`10ee5c5`](https://github.com/tkhq/sdk/commit/10ee5c524b477ce998e4fc635152cd101ae5a9cc) Thanks [@moe-dev](https://github.com/moe-dev)! - Add function `verifySessionJwtSignature` to verify session tokens return from Turnkey and signed by the notarizer
## 2.3.1

@@ -4,0 +10,0 @@

@@ -10,2 +10,3 @@ export declare const SUITE_ID_1: Uint8Array;

export declare const PRODUCTION_SIGNER_PUBLIC_KEY = "04cf288fe433cc4e1aa0ce1632feac4ea26bf2f5a09dcfe5a42c398e06898710330f0572882f4dbdf0f5304b8fc8703acd69adca9a4bbf7f5d00d20a5e364b2569";
export declare const PRODUCTION_NOTARIZER_PUBLIC_KEY = "04d498aa87ac3bf982ac2b5dd9604d0074905cfbda5d62727c5a237b895e6749205e9f7cd566909c4387f6ca25c308445c60884b788560b785f4a96ac33702a469";
//# sourceMappingURL=constants.d.ts.map

@@ -27,2 +27,3 @@ 'use strict';

const PRODUCTION_SIGNER_PUBLIC_KEY = "04cf288fe433cc4e1aa0ce1632feac4ea26bf2f5a09dcfe5a42c398e06898710330f0572882f4dbdf0f5304b8fc8703acd69adca9a4bbf7f5d00d20a5e364b2569";
const PRODUCTION_NOTARIZER_PUBLIC_KEY = "04d498aa87ac3bf982ac2b5dd9604d0074905cfbda5d62727c5a237b895e6749205e9f7cd566909c4387f6ca25c308445c60884b788560b785f4a96ac33702a469";

@@ -35,2 +36,3 @@ exports.AES_KEY_INFO = AES_KEY_INFO;

exports.LABEL_SHARED_SECRET = LABEL_SHARED_SECRET;
exports.PRODUCTION_NOTARIZER_PUBLIC_KEY = PRODUCTION_NOTARIZER_PUBLIC_KEY;
exports.PRODUCTION_SIGNER_PUBLIC_KEY = PRODUCTION_SIGNER_PUBLIC_KEY;

@@ -37,0 +39,0 @@ exports.SUITE_ID_1 = SUITE_ID_1;

+2
-1

@@ -25,4 +25,5 @@ const SUITE_ID_1 = new Uint8Array([75, 69, 77, 0, 16]); //KEM suite ID

const PRODUCTION_SIGNER_PUBLIC_KEY = "04cf288fe433cc4e1aa0ce1632feac4ea26bf2f5a09dcfe5a42c398e06898710330f0572882f4dbdf0f5304b8fc8703acd69adca9a4bbf7f5d00d20a5e364b2569";
const PRODUCTION_NOTARIZER_PUBLIC_KEY = "04d498aa87ac3bf982ac2b5dd9604d0074905cfbda5d62727c5a237b895e6749205e9f7cd566909c4387f6ca25c308445c60884b788560b785f4a96ac33702a469";
export { AES_KEY_INFO, HPKE_VERSION, IV_INFO, LABEL_EAE_PRK, LABEL_SECRET, LABEL_SHARED_SECRET, PRODUCTION_SIGNER_PUBLIC_KEY, SUITE_ID_1, SUITE_ID_2 };
export { AES_KEY_INFO, HPKE_VERSION, IV_INFO, LABEL_EAE_PRK, LABEL_SECRET, LABEL_SHARED_SECRET, PRODUCTION_NOTARIZER_PUBLIC_KEY, PRODUCTION_SIGNER_PUBLIC_KEY, SUITE_ID_1, SUITE_ID_2 };
//# sourceMappingURL=constants.mjs.map

@@ -24,3 +24,4 @@ 'use strict';

exports.encryptWalletToBundle = turnkey.encryptWalletToBundle;
exports.verifySessionJwtSignature = turnkey.verifySessionJwtSignature;
exports.verifyStampSignature = turnkey.verifyStampSignature;
//# sourceMappingURL=index.js.map
export { buildAdditionalAssociatedData, compressRawPublicKey, extractPrivateKeyFromPKCS8Bytes, formatHpkeBuf, fromDerSignature, generateP256KeyPair, getPublicKey, hpkeAuthEncrypt, hpkeDecrypt, hpkeEncrypt, toDerSignature, uncompressRawPublicKey } from './crypto.mjs';
export { decryptCredentialBundle, decryptExportBundle, encryptPrivateKeyToBundle, encryptWalletToBundle, verifyStampSignature } from './turnkey.mjs';
export { decryptCredentialBundle, decryptExportBundle, encryptPrivateKeyToBundle, encryptWalletToBundle, verifySessionJwtSignature, verifyStampSignature } from './turnkey.mjs';
//# sourceMappingURL=index.mjs.map

@@ -87,3 +87,28 @@ /// <reference lib="dom" />

export declare const encryptWalletToBundle: ({ mnemonic, importBundle, userId, organizationId, dangerouslyOverrideSignerPublicKey, }: EncryptWalletToBundleParams) => Promise<string>;
/**
* Verifies that a **session JWT** was signed by Turnkey’s
* notarizer key (P-256 / ES256, compact 64-byte r‖s signature).
*
* How it works
* ------------
* 1. Split the JWT into `header.payload.signature`.
* 2. **Double-hash** the string `"header.payload"`:
* `h1 = sha256(header.payload)`
* `msg = sha256(h1)`
* (The Rust signer feeds `h1` into `SigningKey::sign`, which hashes once
* more internally, yielding `msg`.)
* 3. Base64-URL-decode the signature (`r||s`, 64 bytes).
* 4. Import the notarizer public key (hex `04‖X‖Y` → `Uint8Array`).
* 5. Call `p256.verify(signature, msg, publicKey)`; noble treats the 32-byte
* `msg` as a pre-hashed digest and performs ECDSA verification.
*
* @param jwt The session JWT to validate.
* @param dangerouslyOverrideNotarizerPublicKey *(optional)* Hex-encoded
* uncompressed P-256 public key to verify against (use only in
* tests). Defaults to the production notarizer key.
* @returns `true` if the signature is valid for the given key, else `false`.
* @throws If the JWT is malformed.
*/
export declare const verifySessionJwtSignature: (jwt: string, dangerouslyOverrideNotarizerPublicKey?: string) => Promise<boolean>;
export {};
//# sourceMappingURL=turnkey.d.ts.map

@@ -254,2 +254,46 @@ 'use strict';

};
/**
* Verifies that a **session JWT** was signed by Turnkey’s
* notarizer key (P-256 / ES256, compact 64-byte r‖s signature).
*
* How it works
* ------------
* 1. Split the JWT into `header.payload.signature`.
* 2. **Double-hash** the string `"header.payload"`:
* `h1 = sha256(header.payload)`
* `msg = sha256(h1)`
* (The Rust signer feeds `h1` into `SigningKey::sign`, which hashes once
* more internally, yielding `msg`.)
* 3. Base64-URL-decode the signature (`r||s`, 64 bytes).
* 4. Import the notarizer public key (hex `04‖X‖Y` → `Uint8Array`).
* 5. Call `p256.verify(signature, msg, publicKey)`; noble treats the 32-byte
* `msg` as a pre-hashed digest and performs ECDSA verification.
*
* @param jwt The session JWT to validate.
* @param dangerouslyOverrideNotarizerPublicKey *(optional)* Hex-encoded
* uncompressed P-256 public key to verify against (use only in
* tests). Defaults to the production notarizer key.
* @returns `true` if the signature is valid for the given key, else `false`.
* @throws If the JWT is malformed.
*/
const verifySessionJwtSignature = async (jwt, dangerouslyOverrideNotarizerPublicKey) => {
const notarizerKeyHex = dangerouslyOverrideNotarizerPublicKey ?? constants.PRODUCTION_NOTARIZER_PUBLIC_KEY;
/* 1. split JWT -------------------------------------------------------- */
const [headerB64, payloadB64, signatureB64] = jwt.split(".");
if (!signatureB64)
throw new Error("invalid JWT: need 3 parts");
const signingInput = `${headerB64}.${payloadB64}`;
/* 2. sha256(sha256(header.payload)) ----------------------------------- */
const h1 = sha256.sha256(new TextEncoder().encode(signingInput));
const msgDigest = sha256.sha256(h1); // 32-byte Uint8Array
/* 3. base64-url decode signature -------------------------------------- */
const toB64 = (u) => (u = u.replace(/-/g, "+").replace(/_/g, "/")).padEnd(u.length + ((4 - (u.length % 4)) % 4), "=");
const signature = Uint8Array.from(atob(toB64(signatureB64))
.split("")
.map((c) => c.charCodeAt(0))); // 64 bytes
/* 4. load public key -------------------------------------------------- */
const publicKey = encoding.uint8ArrayFromHexString(notarizerKeyHex);
/* 5. verify ----------------------------------------------------------- */
return p256.p256.verify(signature, msgDigest, publicKey);
};

@@ -260,3 +304,4 @@ exports.decryptCredentialBundle = decryptCredentialBundle;

exports.encryptWalletToBundle = encryptWalletToBundle;
exports.verifySessionJwtSignature = verifySessionJwtSignature;
exports.verifyStampSignature = verifyStampSignature;
//# sourceMappingURL=turnkey.js.map
import bs58check from 'bs58check';
import bs58 from 'bs58';
import { uint8ArrayToHexString, uint8ArrayFromHexString, hexToAscii } from '@turnkey/encoding';
import { PRODUCTION_SIGNER_PUBLIC_KEY } from './constants.mjs';
import { PRODUCTION_SIGNER_PUBLIC_KEY, PRODUCTION_NOTARIZER_PUBLIC_KEY } from './constants.mjs';
import { uncompressRawPublicKey, hpkeDecrypt, fromDerSignature, hpkeEncrypt, formatHpkeBuf } from './crypto.mjs';

@@ -252,4 +252,48 @@ import { p256 } from '@noble/curves/p256';

};
/**
* Verifies that a **session JWT** was signed by Turnkey’s
* notarizer key (P-256 / ES256, compact 64-byte r‖s signature).
*
* How it works
* ------------
* 1. Split the JWT into `header.payload.signature`.
* 2. **Double-hash** the string `"header.payload"`:
* `h1 = sha256(header.payload)`
* `msg = sha256(h1)`
* (The Rust signer feeds `h1` into `SigningKey::sign`, which hashes once
* more internally, yielding `msg`.)
* 3. Base64-URL-decode the signature (`r||s`, 64 bytes).
* 4. Import the notarizer public key (hex `04‖X‖Y` → `Uint8Array`).
* 5. Call `p256.verify(signature, msg, publicKey)`; noble treats the 32-byte
* `msg` as a pre-hashed digest and performs ECDSA verification.
*
* @param jwt The session JWT to validate.
* @param dangerouslyOverrideNotarizerPublicKey *(optional)* Hex-encoded
* uncompressed P-256 public key to verify against (use only in
* tests). Defaults to the production notarizer key.
* @returns `true` if the signature is valid for the given key, else `false`.
* @throws If the JWT is malformed.
*/
const verifySessionJwtSignature = async (jwt, dangerouslyOverrideNotarizerPublicKey) => {
const notarizerKeyHex = dangerouslyOverrideNotarizerPublicKey ?? PRODUCTION_NOTARIZER_PUBLIC_KEY;
/* 1. split JWT -------------------------------------------------------- */
const [headerB64, payloadB64, signatureB64] = jwt.split(".");
if (!signatureB64)
throw new Error("invalid JWT: need 3 parts");
const signingInput = `${headerB64}.${payloadB64}`;
/* 2. sha256(sha256(header.payload)) ----------------------------------- */
const h1 = sha256(new TextEncoder().encode(signingInput));
const msgDigest = sha256(h1); // 32-byte Uint8Array
/* 3. base64-url decode signature -------------------------------------- */
const toB64 = (u) => (u = u.replace(/-/g, "+").replace(/_/g, "/")).padEnd(u.length + ((4 - (u.length % 4)) % 4), "=");
const signature = Uint8Array.from(atob(toB64(signatureB64))
.split("")
.map((c) => c.charCodeAt(0))); // 64 bytes
/* 4. load public key -------------------------------------------------- */
const publicKey = uint8ArrayFromHexString(notarizerKeyHex);
/* 5. verify ----------------------------------------------------------- */
return p256.verify(signature, msgDigest, publicKey);
};
export { decryptCredentialBundle, decryptExportBundle, encryptPrivateKeyToBundle, encryptWalletToBundle, verifyStampSignature };
export { decryptCredentialBundle, decryptExportBundle, encryptPrivateKeyToBundle, encryptWalletToBundle, verifySessionJwtSignature, verifyStampSignature };
//# sourceMappingURL=turnkey.mjs.map
{
"name": "@turnkey/crypto",
"version": "2.3.1",
"version": "2.4.0",
"main": "./dist/index.js",

@@ -23,3 +23,3 @@ "module": "./dist/index.mjs",

"type": "git",
"url": "https://github.com/tkhq/sdk.git",
"url": "git+https://github.com/tkhq/sdk.git",
"directory": "packages/crypto"

@@ -29,3 +29,4 @@ },

"dist/",
"CHANGELOG.md"
"CHANGELOG.md",
"README.md"
],

@@ -43,10 +44,9 @@ "publishConfig": {

"bs58check": "3.0.1",
"bs58": "^5.0.0",
"@turnkey/encoding": "0.4.0"
"bs58": "6.0.0"
},
"devDependencies": {
"jest": "29.7.0",
"@turnkey/encoding": "0.4.0",
"@turnkey/http": "2.18.0",
"@turnkey/sdk-server": "2.0.1"
"@turnkey/http": "3.4.1",
"@turnkey/api-key-stamper": "0.4.6",
"@turnkey/encoding": "0.5.0"
},

@@ -53,0 +53,0 @@ "scripts": {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet