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.0
to
2.3.1
+6
-0
CHANGELOG.md
# @turnkey/crypto
## 2.3.1
### Patch Changes
- 2bc0046: Migrated from WebCrypto (crypto.subtle.verify) to Noble for ECDSA signature verification
## 2.3.0

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

+1
-1

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

/**
* Converts an ASN.1 DER-encoded ECDSA signature to the raw format that WebCrypto uses.
* Converts an ASN.1 DER-encoded ECDSA signature to the raw format used for verification.
*

@@ -100,0 +100,0 @@ * @param {string} derSignature - The DER-encoded signature.

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

var aes = require('@noble/ciphers/aes');
var utils = require('@noble/hashes/utils');
var encoding = require('@turnkey/encoding');

@@ -185,3 +186,3 @@ var math = require('./math.js');

const generateP256KeyPair = () => {
const privateKey = randomBytes(32);
const privateKey = utils.randomBytes(32);
const publicKey = getPublicKey(privateKey, true);

@@ -265,9 +266,2 @@ const publicKeyUncompressed = encoding.uint8ArrayToHexString(uncompressRawPublicKey(publicKey));

/**
* Generate a random Uint8Array of a specific length. Note that this ultimately depends on the crypto implementation.
*/
const randomBytes = (length) => {
const array = new Uint8Array(length);
return crypto.getRandomValues(array);
};
/**
* Build labeled Initial Key Material (IKM).

@@ -365,3 +359,3 @@ *

/**
* Converts an ASN.1 DER-encoded ECDSA signature to the raw format that WebCrypto uses.
* Converts an ASN.1 DER-encoded ECDSA signature to the raw format used for verification.
*

@@ -368,0 +362,0 @@ * @param {string} derSignature - The DER-encoded signature.

@@ -5,2 +5,3 @@ import { p256 } from '@noble/curves/p256';

import { gcm } from '@noble/ciphers/aes';
import { randomBytes } from '@noble/hashes/utils';
import { uint8ArrayFromHexString, uint8ArrayToHexString, normalizePadding } from '@turnkey/encoding';

@@ -243,9 +244,2 @@ import { modSqrt, testBit } from './math.mjs';

/**
* Generate a random Uint8Array of a specific length. Note that this ultimately depends on the crypto implementation.
*/
const randomBytes = (length) => {
const array = new Uint8Array(length);
return crypto.getRandomValues(array);
};
/**
* Build labeled Initial Key Material (IKM).

@@ -343,3 +337,3 @@ *

/**
* Converts an ASN.1 DER-encoded ECDSA signature to the raw format that WebCrypto uses.
* Converts an ASN.1 DER-encoded ECDSA signature to the raw format used for verification.
*

@@ -346,0 +340,0 @@ * @param {string} derSignature - The DER-encoded signature.

@@ -37,3 +37,3 @@ 'use strict';

}
let result = b;
let result = b % p;
const exponentBitString = exp.toString(2);

@@ -40,0 +40,0 @@ for (let i = 1; i < exponentBitString.length; ++i) {

@@ -35,3 +35,3 @@ /**

}
let result = b;
let result = b % p;
const exponentBitString = exp.toString(2);

@@ -38,0 +38,0 @@ for (let i = 1; i < exponentBitString.length; ++i) {

@@ -7,4 +7,6 @@ 'use strict';

var constants = require('./constants.js');
var crypto$1 = require('./crypto.js');
var crypto = require('./crypto.js');
var p256 = require('@noble/curves/p256');
var ed25519 = require('@noble/curves/ed25519');
var sha256 = require('@noble/hashes/sha256');

@@ -29,4 +31,4 @@ /// <reference lib="dom" />

const ciphertextBuf = bundleBytes.slice(33);
const encappedKeyBuf = crypto$1.uncompressRawPublicKey(compressedEncappedKeyBuf);
const decryptedData = crypto$1.hpkeDecrypt({
const encappedKeyBuf = crypto.uncompressRawPublicKey(compressedEncappedKeyBuf);
const decryptedData = crypto.hpkeDecrypt({
ciphertextBuf,

@@ -76,3 +78,3 @@ encappedKeyBuf,

const ciphertextBuf = encoding.uint8ArrayFromHexString(signedData.ciphertext);
const decryptedData = crypto$1.hpkeDecrypt({
const decryptedData = crypto.hpkeDecrypt({
ciphertextBuf,

@@ -121,10 +123,11 @@ encappedKeyBuf,

const publicKeyBuffer = encoding.uint8ArrayFromHexString(publicKey);
const loadedPublicKey = await loadPublicKey(publicKeyBuffer);
const loadedPublicKey = loadPublicKey(publicKeyBuffer);
if (!loadedPublicKey) {
throw new Error("failed to load public key");
}
// The ECDSA signature is ASN.1 DER encoded but WebCrypto uses raw format
const publicSignatureBuf = crypto$1.fromDerSignature(signature);
const signedDataBuf = Buffer.from(signedData);
return await crypto.subtle.verify({ name: "ECDSA", hash: { name: "SHA-256" } }, loadedPublicKey, publicSignatureBuf, signedDataBuf);
// Convert the ASN.1 DER-encoded signature for verification
const publicSignatureBuf = crypto.fromDerSignature(signature);
const signedDataBuf = new TextEncoder().encode(signedData);
const hashedData = sha256.sha256(signedDataBuf);
return p256.p256.verify(publicSignatureBuf, hashedData, loadedPublicKey.toHex());
};

@@ -146,10 +149,11 @@ /**

const encryptionQuorumPublicBuf = new Uint8Array(encoding.uint8ArrayFromHexString(enclaveQuorumPublic));
const quorumKey = await loadPublicKey(encryptionQuorumPublicBuf);
const quorumKey = loadPublicKey(encryptionQuorumPublicBuf);
if (!quorumKey) {
throw new Error("failed to load quorum key");
}
// The ECDSA signature is ASN.1 DER encoded but WebCrypto uses raw format
const publicSignatureBuf = crypto$1.fromDerSignature(publicSignature);
// Convert the ASN.1 DER-encoded signature for verification
const publicSignatureBuf = crypto.fromDerSignature(publicSignature);
const signedDataBuf = encoding.uint8ArrayFromHexString(signedData);
return await crypto.subtle.verify({ name: "ECDSA", hash: { name: "SHA-256" } }, quorumKey, publicSignatureBuf, signedDataBuf);
const hashedData = sha256.sha256(signedDataBuf);
return p256.p256.verify(publicSignatureBuf, hashedData, quorumKey.toHex());
};

@@ -159,10 +163,8 @@ /**

*
* @param {Uint8Array} publicKey - The raw public key bytes.
* @returns {Promise<CryptoKey>} - The imported ECDSA public key.
* @param {Uint8Array} publicKey - The raw P-256 public key bytes.
* @returns {ProjPointType<bigint>} - The parsed ECDSA public key.
* @throws {Error} - If the public key is invalid.
*/
const loadPublicKey = async (publicKey) => {
return await crypto.subtle.importKey("raw", publicKey, {
name: "ECDSA",
namedCurve: "P-256",
}, true, ["verify"]);
const loadPublicKey = (publicKey) => {
return p256.p256.ProjectivePoint.fromHex(encoding.uint8ArrayToHexString(publicKey));
};

@@ -222,6 +224,6 @@ /**

}
// Load target public key generated from enclave and set in local storage
// Load target public key generated from enclave
const targetKeyBuf = encoding.uint8ArrayFromHexString(signedData.targetPublic);
const privateKeyBundle = crypto$1.hpkeEncrypt({ plainTextBuf, targetKeyBuf });
return crypto$1.formatHpkeBuf(privateKeyBundle);
const privateKeyBundle = crypto.hpkeEncrypt({ plainTextBuf, targetKeyBuf });
return crypto.formatHpkeBuf(privateKeyBundle);
};

@@ -254,6 +256,6 @@ /**

}
// Load target public key generated from enclave and set in local storage
// Load target public key generated from enclave
const targetKeyBuf = encoding.uint8ArrayFromHexString(signedData.targetPublic);
const privateKeyBundle = crypto$1.hpkeEncrypt({ plainTextBuf, targetKeyBuf });
return crypto$1.formatHpkeBuf(privateKeyBundle);
const privateKeyBundle = crypto.hpkeEncrypt({ plainTextBuf, targetKeyBuf });
return crypto.formatHpkeBuf(privateKeyBundle);
};

@@ -260,0 +262,0 @@

@@ -6,3 +6,5 @@ import bs58check from 'bs58check';

import { uncompressRawPublicKey, hpkeDecrypt, fromDerSignature, hpkeEncrypt, formatHpkeBuf } from './crypto.mjs';
import { p256 } from '@noble/curves/p256';
import { ed25519 } from '@noble/curves/ed25519';
import { sha256 } from '@noble/hashes/sha256';

@@ -117,10 +119,11 @@ /// <reference lib="dom" />

const publicKeyBuffer = uint8ArrayFromHexString(publicKey);
const loadedPublicKey = await loadPublicKey(publicKeyBuffer);
const loadedPublicKey = loadPublicKey(publicKeyBuffer);
if (!loadedPublicKey) {
throw new Error("failed to load public key");
}
// The ECDSA signature is ASN.1 DER encoded but WebCrypto uses raw format
// Convert the ASN.1 DER-encoded signature for verification
const publicSignatureBuf = fromDerSignature(signature);
const signedDataBuf = Buffer.from(signedData);
return await crypto.subtle.verify({ name: "ECDSA", hash: { name: "SHA-256" } }, loadedPublicKey, publicSignatureBuf, signedDataBuf);
const signedDataBuf = new TextEncoder().encode(signedData);
const hashedData = sha256(signedDataBuf);
return p256.verify(publicSignatureBuf, hashedData, loadedPublicKey.toHex());
};

@@ -142,10 +145,11 @@ /**

const encryptionQuorumPublicBuf = new Uint8Array(uint8ArrayFromHexString(enclaveQuorumPublic));
const quorumKey = await loadPublicKey(encryptionQuorumPublicBuf);
const quorumKey = loadPublicKey(encryptionQuorumPublicBuf);
if (!quorumKey) {
throw new Error("failed to load quorum key");
}
// The ECDSA signature is ASN.1 DER encoded but WebCrypto uses raw format
// Convert the ASN.1 DER-encoded signature for verification
const publicSignatureBuf = fromDerSignature(publicSignature);
const signedDataBuf = uint8ArrayFromHexString(signedData);
return await crypto.subtle.verify({ name: "ECDSA", hash: { name: "SHA-256" } }, quorumKey, publicSignatureBuf, signedDataBuf);
const hashedData = sha256(signedDataBuf);
return p256.verify(publicSignatureBuf, hashedData, quorumKey.toHex());
};

@@ -155,10 +159,8 @@ /**

*
* @param {Uint8Array} publicKey - The raw public key bytes.
* @returns {Promise<CryptoKey>} - The imported ECDSA public key.
* @param {Uint8Array} publicKey - The raw P-256 public key bytes.
* @returns {ProjPointType<bigint>} - The parsed ECDSA public key.
* @throws {Error} - If the public key is invalid.
*/
const loadPublicKey = async (publicKey) => {
return await crypto.subtle.importKey("raw", publicKey, {
name: "ECDSA",
namedCurve: "P-256",
}, true, ["verify"]);
const loadPublicKey = (publicKey) => {
return p256.ProjectivePoint.fromHex(uint8ArrayToHexString(publicKey));
};

@@ -218,3 +220,3 @@ /**

}
// Load target public key generated from enclave and set in local storage
// Load target public key generated from enclave
const targetKeyBuf = uint8ArrayFromHexString(signedData.targetPublic);

@@ -250,3 +252,3 @@ const privateKeyBundle = hpkeEncrypt({ plainTextBuf, targetKeyBuf });

}
// Load target public key generated from enclave and set in local storage
// Load target public key generated from enclave
const targetKeyBuf = uint8ArrayFromHexString(signedData.targetPublic);

@@ -253,0 +255,0 @@ const privateKeyBundle = hpkeEncrypt({ plainTextBuf, targetKeyBuf });

{
"name": "@turnkey/crypto",
"version": "2.3.0",
"version": "2.3.1",
"main": "./dist/index.js",

@@ -45,7 +45,6 @@ "module": "./dist/index.mjs",

"devDependencies": {
"crypto": "1.0.1",
"jest": "29.7.0",
"@turnkey/encoding": "0.4.0",
"@turnkey/http": "2.17.0",
"@turnkey/sdk-server": "1.7.0"
"@turnkey/http": "2.18.0",
"@turnkey/sdk-server": "2.0.1"
},

@@ -52,0 +51,0 @@ "scripts": {

# @turnkey/crypto
This package consolidates some common cryptographic utilities used across our applications, particularly primitives related to keys, encryption, and decryption in a pure JS implementation. For react-native you will need to polyfill our random byte generation by importing react-native-get-random-values: https://www.npmjs.com/package/react-native-get-random-values
This package consolidates some common cryptographic utilities used across our applications, particularly primitives related to keys, encryption, and decryption in a pure JS implementation. For react-native you will need to polyfill our random byte generation by importing [react-native-get-random-values](https://www.npmjs.com/package/react-native-get-random-values)
```
import 'react-native-get-random-values'
```
Example usage (Hpke E2E):

@@ -10,0 +6,0 @@

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