Code Monkey home page Code Monkey logo

webcrypto's Introduction

@peculiar/webcrypto

License test Coverage Status npm version

We wanted to be able to write Javascript that used crypto on both the client and the server but we did not want to rely on Javascript implementations of crypto. The only native cryptography available in browser is Web Crypto, this resulted in us creating a @peculiar/webcrypto.

Table Of Contents

WARNING

At this time this solution should be considered suitable for research and experimentation, further code and security review is needed before utilization in a production application.

Module is based on NodeJS v10 Crypto API. It would work only with Node v10 and higher.

Installing

npm install @peculiar/webcrypto

Supported algorithms

Algorithm name generateKey digest export/import sign/verify encrypt/decrypt wrapKey/unwrapKey derive
SHA-1 X
SHA-256 X
SHA-384 X
SHA-512 X
HMAC X X X
RSASSA-PKCS1-v1_5 X X X
RSAES-PKCS1-v1_52 X X X X
RSA-PSS X X X
RSA-OAEP X X X X
AES-CMAC X X X
AES-CBC X X X X
AES-CTR X X X X
AES-ECB X X X X
AES-GCM X X X X
AES-KW X X X
ECDSA1 X X X
ECDH1 X X X
EdDSA2,3 X X X
ECDH-ES2,4 X X X
HKDF X X
PBKDF2 X X
DES-CBC2 X X X X
DES-EDE3-CBC2 X X X X
shake1282 X
shake2562 X

1 Mechanism supports extended list of named curves P-256, P-384, P-521, K-256, brainpoolP160r1, brainpoolP160t1, brainpoolP192r1, brainpoolP192t1, brainpoolP224r1, brainpoolP224t1, brainpoolP256r1, brainpoolP256t1, brainpoolP320r1, brainpoolP320t1, brainpoolP384r1, brainpoolP384t1, brainpoolP512r1, and brainpoolP512t1

2 Mechanism is not defined by the WebCrypto specifications. Use of mechanism in a safe way is hard, it was added for the purpose of enabling interoperability with an existing system. We recommend against its use unless needed for interoperability.

3 Mechanism supports extended list of named curves Ed25519, and Ed448

4 Mechanism supports extended list of named curves X25519, and X448

Using

const { Crypto } = require("@peculiar/webcrypto");

const crypto = new Crypto();

Examples

See WebCrypto Docs for examples

Bug Reporting

Please report bugs either as pull requests or as issues in the issue tracker. @peculiar/webcrypto has a full disclosure vulnerability policy. Please do NOT attempt to report any security vulnerability in this code privately to anybody.

Related

webcrypto's People

Contributors

achingbrain avatar dependabot[bot] avatar liranuna avatar microshine avatar miguel-a-calles-mba avatar panva avatar shamilovtim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webcrypto's Issues

Error: Wrong parameter: inputBuffer must be "ArrayBuffer" at `crypto.subtle.exportKey` in a nwjs environment but not in node

I am hitting the following error in an nw.js (which is an electron like) environment:

Error: Wrong parameter: inputBuffer must be "ArrayBuffer" 
    at Function.parse 
    at RsaPublicKey.getKey 
    at RsaPublicKey.toJSON
    at Function.toJSON 
    at Function.exportKey 
    at RsaSsaProvider.onExportKey 
    at RsaSsaProvider.exportKey 
    at SubtleCrypto.exportKey 
    at crypto.subtle.generateKey.then 

(Sorry about the line numbers, I am pulling these out of a bundle and sourcemaps are giving me grief)

The happens at crypto.subtle.exportKey in the snippet below. This is despite the fact that the key is being generated by this library itself. The key is generated and exported using the following code:

static generateSessionKeys () {
    return crypto.subtle.generateKey(
      {
        name: "RSASSA-PKCS1-v1_5",
        modulusLength: 2048,
        publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
        hash: { name: "SHA-256" },
      },
      true,
      ["sign", "verify"]
    )
      .then((keyPair) => {
        // returns a keypair object
        return Promise.all([
          crypto.subtle.exportKey('jwk', keyPair.publicKey),
          crypto.subtle.exportKey('jwk', keyPair.privateKey)
        ])
      })
  }

[webview-crypto] error in `parse` of message & ReferenceError: Property 'abvs' doesn't exist

Hey all!

I am trying to get the package to work with react-native and gundb but facing a couple of errors and warnings. Below is one of the more confusing warnings I am getting. Hopefully someone recognizes it and offers some insight.

[webview-crypto] error inparseof message: "%7B%22id%22%3A%22c510-9fc9-53c0-72ed-63de-5b05-7515-35a7%22%2C%22value%22%3A%7B%22__serializer_id%22%3A%22CryptoKey%22%2C%22value%22%3A%7B%22serialized%22%3Atrue%2C%22_import%22%3A%7B%22format%22%3A%22raw%22%2C%22keyData%22%3A%7B%22__serializer_id%22%3A%22ArrayBufferView%22%2C%22value%22%3A%7B%22name%22%3A%22Uint8Array%22%2C%22buffer%22%3A%7B%22__serializer_id%22%3A%22ArrayBuffer%22%2C%22value%22%3A%22password%22%7D%7D%7D%7D%2C%22type%22%3A%22secret%22%2C%22extractable%22%3Afalse%2C%22algorithm%22%3A%7B%22name%22%3A%22PBKDF2%22%7D%2C%22usages%22%3A%5B%22deriveBits%22%5D%7D%7D%7D" reason: {"name":"ReferenceError","message":"Property 'abvs' doesn't exist","stack":"ReferenceError: Property 'abvs' doesn't exist\n at eval (JavaScript:1:16)\n at anonymous

Thanks!

crypto3.getCiphers is not a function

I am using your package in one of my subpackages in the browser with Angular. However when I call it, I am getting this error:

webcrypto.es.js:2233 Uncaught TypeError: crypto3.getCiphers is not a function
    at new SubtleCrypto2 (webcrypto.es.js:2233:32)
    at new Crypto2 (webcrypto.es.js:2276:23)
    at node_modules/@transmute/web-crypto-key-pair/dist/web-crypto-key-pair.esm.js (web-crypto-key-pair.esm.js:814:27)
    at __init (chunk-QPLMLQ3O.js?v=8ada0fd4:45:56)
    at node_modules/@transmute/json-web-signature/dist/json-web-signature.esm.js (json-web-signature.esm.js:5:1)
    at __init (chunk-QPLMLQ3O.js?v=8ada0fd4:45:56)
    at node_modules/@cef-ebsi/verifiable-credential/dist/index.js (index.js:18:30)
    at __require2 (chunk-QPLMLQ3O.js?v=8ada0fd4:48:50)
    at node_modules/@cef-ebsi/verifiable-presentation/dist/index.js (index.js:20:33)
    at __require2 (chunk-QPLMLQ3O.js?v=8ada0fd4:48:50)

I am using esbuild and added the polyfills like

import { polyfillNode } from 'esbuild-plugin-polyfill-node';

export default polyfillNode();

On the backend it's working fine, it seems to be a problem with the browser. Do you know if there needs to be an extra import?

Missing Algorithm: AES-KW

This algorithm is missing from this library. I would love to use it, but since AES-KW is required for JOSE for both ECDH-ES and PKES2 based key wrapping, I can't.

Would you accept a PR if I try to tackle this?

Incompatibility with Node's Webcrypto when using Ed25519 keys

I've been using the https://github.com/PeculiarVentures/x509 library.

At first since webcrypto already available in nodejs, I thought it was sufficient to do this:

x509.cryptoProvider.set(webcrypto as Crypto);

However subsequently I found that that there's an API difference between the way x509 expects Ed25519 algorithm objects that are based on this library, compared to the ones that in NodeJS (https://nodejs.org/api/webcrypto.html#ed25519ed448x25519x448-key-pairs).

For example in NodeJS's webcrypto, the alg parameter can just be: { name: 'Ed25519' }.

However for peculiar's webcrypto, the alg parameter has to be { name: 'EdDSA', namedCurve: 'Ed25519' }.

This caused some incompatibilities in webcrypto.subtle.importKey and in x509.X509CertificateGenerator.createSelfSigned

In the case of the importKey, I have to use a webcrypto's expected alg parameter:

  const privateCryptoKey = await webcrypto.subtle.importKey(
    'jwk',
    privateKeyJWK,
    // { name: 'Ed25519' }, // This is nodejs webcrypto
    { name: 'EdDSA', namedCurve: 'Ed25519' }, // This is peculiar's webcrypto
    true,
    ['sign']
  );

During the generation of the certificate, if I used node's webcrypto, the certificate generation works without exceptions, however I notice that the signatureAlgorithm field is empty, and stays as:

signatureAlgorithm: { name: '', parameters: undefined },

The resulting certificate when output to PEM is not readable by openssl x509 -in ./tmp/cert -text.

unable to load certificate
140330083047232:error:0D0C40D8:asn1 encoding routines:c2i_ASN1_OBJECT:invalid object encoding:crypto/asn1/a_object.c:254:
140330083047232:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=algorithm, Type=X509_ALGOR
140330083047232:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=signature, Type=X509_CINF
140330083047232:error:0D08303A:asn1 encoding routines:asn1_template_noexp_                                                             d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=cert_info, Type=X509                     AES-GCM', length: 256 },
140330083047232:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:crypto/pem/pem_oth.c:33:
CUSTOM CALLED

So it seems that if I want to use ed25519 with https://github.com/PeculiarVentures/x509, I have to use peculiar's webcrypto and not node's webcrypto.

ArrayBuffer type error on Jest in ESM mode

I use Jest and TS with ESM mode:

  "jest": {
    "preset": "ts-jest/presets/default-esm",
    "globals": {
      "ts-jest": {
        "useESM": true
      }
    },
    "testEnvironment": "jsdom"
  }
node --experimental-vm-modules node_modules/.bin/jest

After switching to ESM I start to have ArrayBuffer error:

    TypeError: The provided value is not of type '(ArrayBuffer or ArrayBufferView)'

      52 |   let key
      53 |   async function getKey () {
    > 54 |     key = await crypto.subtle.importKey(
         |                               ^
      55 |       'raw',
      56 |       await sha256(secret),
      57 |       { name: 'AES-GCM' },

      at Function.toUint8Array (node_modules/pvtsutils/build/index.js:29:17)
      at Function.toArrayBuffer (node_modules/pvtsutils/build/index.js:13:28)
      at SubtleCrypto.importKey (node_modules/webcrypto-core/build/webcrypto-core.js:847:66)
      at getKey (encrypt-actions/index.js:54:31)
      at outMap (encrypt-actions/index.js:69:23)
      at syncMappedEvent (node_modules/@logux/core/base-node/index.js:37:21)

Sources:

function sha256 (string) {
  return crypto.subtle.digest('SHA-256', new TextEncoder().encode(string))
}

let key
async function getKey () {
  key = await crypto.subtle.importKey(
    'raw',
    await sha256(secret),
    { name: 'AES-GCM' },
    false,
    ['encrypt', 'decrypt']
  )
  return key
}

Seems like switching to ESM created two ArrayBuffer instances and data instanceof ArrayBuffer start to return false.

Will it be more stable to now using instanceof?

Object.prototype.toString.call(value) === '[object ArrayBuffer]'

Honour hash algo and set salt length when generating RSA-PSS key pairs

As shown in the snipped below, this library isn't currently honouring the hashing algorithm or setting a salt length when generating RSA-PSS keys, as it wasn't supported in older versions of Node.js:

const keys = crypto.generateKeyPairSync("rsa", {
modulusLength: algorithm.modulusLength,
publicExponent,
publicKeyEncoding: {
format: "der",
type: "spki",
},
privateKeyEncoding: {
format: "der",
type: "pkcs8",
},
});

I think this crypto.generateKeyPairSync() call should be changed to set the type to rsa-pss (only if using RSA-PSS) and add the following options if the current Node.js version is >= 16.10.0:

  • hashAlgorithm and mgf1HashAlgorithm: This value is already available in the context (algorithm.hash.name).
  • saltLength: Should match the length of the digest from hashAlgorithm (e.g., 32 for SHA-256), following industry best practices (see, for example, TLS 1.3 and GCP KMS key algorithms).

I suspect this might be a breaking change in those apps/libs using the default values of MGF1 with SHA-1 and saltLength=20 (I think PKI.js' SignedData and Certificate might be affected from a cursory look at CryptoEngine but haven't had the time to double check).

Cannot import private and public key

`import { Crypto } from "@peculiar/webcrypto";

// GENERATE AND EXPORT KEYS
export async function generateKeysTest() {
const WebCrypto = new Crypto();
const { publicKey, privateKey } = await WebCrypto.subtle.generateKey(
{
name: "RSA-PSS",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
true,
["sign", "verify"]
);
const publicExport = await WebCrypto.subtle.exportKey("spki", publicKey);
const privateExport = await WebCrypto.subtle.exportKey("pkcs8", privateKey);

const pubExportedAsString = ab2str(publicExport);
const pubExportedAsBase64 = stringToBase64(pubExportedAsString);
const publicKeyPem = ${pubExportedAsBase64};

const privExportedAsString = ab2str(privateExport);
const privExportedAsBase64 = stringToBase64(privExportedAsString);
const privateKeyPem = ${privExportedAsBase64};

// IMPORT KEYS
const pubKeyImportedAsString = base64ToString(publicKeyPem);
const pubKeyImportedAsArrayBuffer = str2ab(pubKeyImportedAsString);
const publicKeyImport = await WebCrypto.subtle.importKey(
"spki",
pubKeyImportedAsArrayBuffer,
{ name: "RSA-PSS", hash: "SHA-256" },
true,
["verify"]
);

const privateKeyImportedAsString = base64ToString(privateKeyPem);
const privateKeyImportedAsArrayBuffer = str2ab(privateKeyImportedAsString);

const privateKeyImport = await WebCrypto.subtle.importKey(
"pkcs8",
privateKeyImportedAsArrayBuffer,
{ name: "RSA-PSS", hash: "SHA-256" },
true,
["sign"]
);
}

// HELPERS
const ab2str = (buffer: ArrayBuffer) => String.fromCharCode.apply(null, Array.from(new Uint8Array(buffer)));

const str2ab = (str: string): ArrayBuffer => {
const buffer = new ArrayBuffer(str.length * 2);
const bufferInterface = new Uint8Array(buffer);
Array.from(str).forEach((_, index: number) => (bufferInterface[index] = str.charCodeAt(index)));
return buffer;
};

function stringToBase64(value: string) {
return Buffer.from(value).toString("base64");
}

function base64ToString(encryptedString: string) {
return Buffer.from(encryptedString, "base64").toString("binary");
}
`
I'm trying to generate the key, export it and import back, but on key import i get "Too big integer error".

image

RSA Public Key re-export results in malformed buffer

When @peculiar/webcrypto is used as a crypto engine, RSA public key re-export result is invalid.

Here is a sample code:

import { Crypto } from '@peculiar/webcrypto';

const crypto = new Crypto();

const algorithm = {
  name: 'RSASSA-PKCS1-v1_5',
  hash: 'SHA-256',
  publicExponent: new Uint8Array([1, 0, 1]),
  modulusLength: 2048,
};
const keys = await crypto.subtle.generateKey(algorithm, true, ['sign', 'verify'])

const cryptoKeyBuffer = await crypto.subtle.exportKey('spki', keys.publicKey);
console.log(cryptoKeyBuffer.byteLength); // will log 294

const reImportedKey = await crypto.subtle.importKey('spki', cryptoKeyBuffer, algorithm, true, ['verify']);
const reExportedKey = await crypto.subtle.exportKey('spki', reImportedKey);

console.log(reExportedKey.byteLength); // will log 22, invalid bytelength.

The same code for WebCrypto in browser implementation or WebCrypto in the node will result in a valid re-exported buffer with the same length and ability to import/export countless times.

exportKey fails since upgrading to v1.1.4

I upgraded from 1.1.3 to 1.1.4, and a series of tests have started to fail. All of them fail when using exportKey. For example:

    Error: Cannot get CryptoKey from secure storage

      at getCryptoKey (node_modules/@relaycorp/relaynet-core/node_modules/@peculiar/webcrypto/build/webcrypto.js:91:15)
      at RsaPssProvider.checkCryptoKey (node_modules/@relaycorp/relaynet-core/node_modules/@peculiar/webcrypto/build/webcrypto.js:1044:29)
      at RsaPssProvider.checkExportKey (node_modules/webcrypto-core/build/webcrypto-core.js:207:14)
      at RsaPssProvider.exportKey (node_modules/webcrypto-core/build/webcrypto-core.js:202:29)
      at SubtleCrypto.exportKey (node_modules/webcrypto-core/build/webcrypto-core.js:838:39)
      at CryptoEngine.exportKey (node_modules/pkijs/src/CryptoEngine.js:604:30)
      at Object.derSerializePublicKey (node_modules/@relaycorp/relaynet-core/src/lib/crypto_wrappers/keys.ts:76:43)
      at PoWebClient.preRegisterNode (src/lib/PoWebClient.ts:123:43)
      at Object.<anonymous> (src/lib/PoWebClient.spec.ts:223:20)

Having seeing the changes between the two releases (https://github.com/PeculiarVentures/webcrypto/compare/v1.1.3..v1.1.4), I thought the culprit could've been the upgrade of webcrypto-core, but I couldn't see any change in it that could lead to this behaviour (https://github.com/PeculiarVentures/webcrypto-core/compare/v1.1.6..v1.1.8).

require statements mixed in ESM code

In a number of files I find that there are cjs require statements even though they otherwise use import. Is there some specific reason for this? It is making my bundler mad. Please fix!

"Error: Unknown message digest" caused by crypto.subtle.verify({'name':'ECDSA', 'hash':'SHA-256'}, ...) when bundling via browserify

I'm trying to bundle the PageSigner pgsg-node.js (written in NodeJS) using browserify, such that I can run it via QuickJS and eventually compile it to WASM. (Not for a browser application however - I need to run it on a WASM VM).

After some necessary edits to the code of pgsg-node.js, I managed to successfully execute both node bundle.js and the QuickJS analogue qjs bundle.js and log the final output to the console. However, that only works if I remove this crucial line:

var result = await crypto.subtle.verify({'name':'ECDSA', 'hash':'SHA-256'}, notary_pk_CryptoKey, ba2ab(sig_p1363), ba2ab(signed_data_ba))

and replace it with var result = true. Otherwise I get the following error after executing node bundle.js:

Error: Unknown message digest
    at new Verify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:13849:20)
    at Object.createVerify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:13882:10)
    at Function.verify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:33318:51)
    at EcdsaProvider.onVerify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:33496:25)
    at EcdsaProvider.verify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:82175:30)
    at SubtleCrypto.verify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:82832:39)
    at verifyNotarySig (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:2724:39)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async verifyPgsgV4 (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:723:10)
    at async Object.verifyPgsg (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:661:12) Error
(node:7830) UnhandledPromiseRejectionWarning: Error: Unknown message digest
    at new Verify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:13849:20)
    at Object.createVerify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:13882:10)
    at Function.verify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:33318:51)
    at EcdsaProvider.onVerify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:33496:25)
    at EcdsaProvider.verify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:82175:30)
    at SubtleCrypto.verify (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:82832:39)
    at verifyNotarySig (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:2724:39)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async verifyPgsgV4 (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:723:10)
    at async Object.verifyPgsg (/home/metzgerj/CoaseContract/pagesigner/webextension/content/pgsg-node/bundle.js:661:12)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:7830) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:7830) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

What's weird is that at least some of the crypto.subtle functionality works, the line right before

var notary_pk_CryptoKey = await crypto.subtle.importKey(
      "raw", ba2ab(notaryPubkey_ba), {name: 'ECDSA', namedCurve:'P-256'}, true, ["verify"]);

works flawlessly. Also, executing my modified unbundled file node pgsg-node.js does not produce this error.

Improve JWK importing

  • Compare jwk.alg (if presents) with algorithm argument and throw DOMException if they are not equal

Example

var key = await crypto.subtle.generateKey({name: "AES-CBC", length: 256}, true, ["encrypt", "decrypt"]);
var jwk = await crypto.subtle.exportKey("jwk", key);
delete jwk.key_ops
var hmacKey = await crypto.subtle.importKey("jwk", jwk, {name: "AES-KW"}, false, ["wrapKey"]);

DOMException (Chrome)

DOMException: The JWK "alg" member was inconsistent with that specified by the Web Crypto call
  • Compare jwk.key_ops (if presents) with keyUsages argument and throw DOMException if they are not equal

Example

var key = await crypto.subtle.generateKey({name: "AES-CBC", length: 256}, true, ["encrypt", "decrypt"]);
var jwk = await crypto.subtle.exportKey("jwk", key);
var hmacKey = await crypto.subtle.importKey("jwk", jwk, {name: "AES-KW"}, false, ["wrapKey"]);

DOMException (Chrome)

DOMException: The JWK "key_ops" member was inconsistent with that specified by the Web Crypto call. The JWK usage must be a superset of those requested

node14.5安装失败

node14.5安装失败
错误提示
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE package: '[email protected]',
npm WARN EBADENGINE required: { node: '^12.22.0 || ^14.17.0 || >=16.0.0' },
npm WARN EBADENGINE current: { node: 'v14.15.0', npm: '7.24.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE package: '[email protected]',
npm WARN EBADENGINE required: { node: '^12.22.0 || ^14.17.0 || >=16.0.0' },
npm WARN EBADENGINE current: { node: 'v14.15.0', npm: '7.24.1' }
npm WARN EBADENGINE }

Can't use AES-WRAP in Electron apps

You'd get an error like this:

          Error: Unknown cipher
              at Cipheriv.createCipherBase (node:internal/crypto/cipher:116:19)
              at Cipheriv.createCipherWithIV (node:internal/crypto/cipher:135:3)
              at new Cipheriv (node:internal/crypto/cipher:243:3)
              at Object.createCipheriv (node:crypto:138:10)
              at Function.encryptAesKW (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/@peculiar/webcrypto/build/webcrypto.js:260:51)
              at Function.encrypt (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/@peculiar/webcrypto/build/webcrypto.js:182:29)
              at AesKwProvider.onEncrypt (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/@peculiar/webcrypto/build/webcrypto.js:506:26)
              at AesKwProvider.encrypt (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/webcrypto-core/build/webcrypto-core.js:184:31)
              at SubtleCrypto.wrapKey (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/webcrypto-core/build/webcrypto-core.js:1393:25)
              at async Promise.all (index 0)

This is due to electron/electron#31874

This means that you can't use PKI.js with EnvelopedData and DH, for example.

I don't think there's anything to change in this repo, but I wanted to create this issue to save some time to anyone that comes across this issue. Feel free to close it.

Crypto.randomUUID() definition breaks on TypeScript 5

node_modules/@peculiar/webcrypto/index.d.ts:4:10 - error TS2416: Property 'randomUUID' in type 'Crypto' is not assignable to the same property in base type 'Crypto'.
  Type '() => string' is not assignable to type '() => `${string}-${string}-${string}-${string}-${string}`'.
    Type 'string' is not assignable to type '`${string}-${string}-${string}-${string}-${string}`'.

4   public randomUUID(): string;
           ~~~~~~~~~~

Found 1 error in node_modules/@peculiar/webcrypto/index.d.ts:

And this is how the base Crypto interface is defined in TS 5:

interface Crypto {
    /** Available only in secure contexts. */
    readonly subtle: SubtleCrypto;
    getRandomValues<T extends ArrayBufferView | null>(array: T): T;
    /** Available only in secure contexts. */
    randomUUID(): `${string}-${string}-${string}-${string}-${string}`;
}

It all works after downgrading to TS 4.

The only fix I can think of would be using ${string}-${string}-${string}-${string}-${string} from now on, but that'd then break on TS 4, so it'd be a breaking change.

Browser support

Hello!

I'm trying to use the library in a react app, but getting an error trying to generate basic keys:

crypto__WEBPACK_IMPORTED_MODULE_1___default.a.generateKeyPairSync is not a function

const crypto = new Crypto(); await crypto.subtle.generateKey( { name: 'ECDH', namedCurve: 'P-256', true, ['deriveBits'] );

Should the webcrypto library actually work in the browser, or have I missed something in the docs?

Is there a way to bundle only subtle.digest() "SHA-1" support?

I'm implementing a JavaScript runtime agnostic WebSocket server. txiki.js does not support subtle. The only capability I need is Web Cryptography API subtle for digest() function, e.g.,

// https://stackoverflow.com/a/77398427
async function digest(message, algo = "SHA-1") {
  const { promise, resolve } = Promise.withResolvers();
  const reader = new FileReader();
  reader.onload = () => resolve(reader.result);
  reader.readAsDataURL(
    new Blob([
      new Uint8Array(
        await crypto.subtle.digest(
          algo,
          new TextEncoder().encode(
            `${message}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`,
          ),
        ),
      ),
    ]),
  );
  const result = await promise;
  return result.split(",").pop();
}

I've fetched the repository and tried to bundle with

bun build ./src/index.ts --outfile=webcrypto.js --target=browser 

yet have to substitute every Buffer import for

import * as Buffer from "node:buffer";

where I'm not going to be using Node.js' Buffer at all, rather I'll be using Uint8Array and/or ArrayBuffer and DataView.

Usage in browser

Hello,

Is this library supposed to work in a browser? I'm hitting the below error in a fresh Vite app using v1.1.6.

Pre-bundling dependencies:
  @peculiar/webcrypto
(this will be run only when your dependencies or config have changed)
 > node_modules/@peculiar/webcrypto/build/webcrypto.es.js:7:17: error: No matching export in "browser-external:crypto" for import "createCipheriv"
    7 │ import crypto, { createCipheriv, publicEncrypt, privateDecrypt, constants } from 'crypto';
      ╵                  ~~~~~~~~~~~~~~

 > node_modules/@peculiar/webcrypto/build/webcrypto.es.js:7:33: error: No matching export in "browser-external:crypto" for import "publicEncrypt"
    7 │ import crypto, { createCipheriv, publicEncrypt, privateDecrypt, constants } from 'crypto';
      ╵                                  ~~~~~~~~~~~~~

 > node_modules/@peculiar/webcrypto/build/webcrypto.es.js:7:48: error: No matching export in "browser-external:crypto" for import "privateDecrypt"
    7 │ import crypto, { createCipheriv, publicEncrypt, privateDecrypt, constants } from 'crypto';
      ╵                                                 ~~~~~~~~~~~~~~

 > node_modules/@peculiar/webcrypto/build/webcrypto.es.js:7:64: error: No matching export in "browser-external:crypto" for import "constants"
    7 │ import crypto, { createCipheriv, publicEncrypt, privateDecrypt, constants } from 'crypto';
      ╵                                                                 ~~~~~~~~~

 > node_modules/@peculiar/webcrypto/build/webcrypto.es.js:8:9: error: No matching export in "browser-external:process" for import "version"
    8 │ import { version } from 'process';
      ╵          ~~~~~~~

IIUC, the above error is because crypto and process are included as external node objects in rollup.config.js. Is there a missing shim for use in the browser?

Fails to build with the latest typescript

Problem

TypeScript 4.6.2 was just released and added crypto.randomUUID() in microsoft/TypeScript@4e689bc

This causes @peculiar/webcrypto to fail to build.

Steps to reproduce

Create a new project and install the latest dependencies.

mkdir example
cd example
npm init -y
npm install @peculiar/[email protected] [email protected]
echo '{ "compilerOptions": { "module": "commonjs" } }' > tsconfig.json
echo 'import { Crypto } from "@peculiar/webcrypto"' > index.ts
./node_modules/.bin/tsc

Error

@peculiar/webcrypto/index.d.ts:1:22 - error TS2420: Class 'import("@peculiar/webcrypto/index").Crypto' incorrectly implements interface 'Crypto'.
  Property 'randomUUID' is missing in type 'import("@peculiar/webcrypto/index").Crypto' but required in type 'Crypto'.

1 export declare class Crypto implements globalThis.Crypto {
                       ~~~~~~

  node_modules/typescript/lib/lib.dom.d.ts:3652:5
    3652     randomUUID(): string;

`oct` JWK should not require alg during importKey

The HmacCryptoKey and AesCryptoKey interfaces wrongfully require the alg attribute to be present when importing keyData in jwk key format.

Every other webcrypto runtime allows these to omitted and in order to have interoperable behaviour between runtimes it is in fact better to remove the alg attribute.

generatekeypairsync is not a function on Angular 9.14, node 14

Hey, I'm trying to use your implementation of subtle crypto in a package (https://github.com/QuestNetwork/quest-pubsub-js) to make it portable for use in nodejs and in an angular browser/electron app. Works great for my nodejs test case, but unfortunately the browser/electron app (angular 9) throws the error in title. Any clue what's going on there? If it's a browser related issue, maybe you could test if subtle crypto is available and use that when it's possible instead of your package or should I be doing that in my package (It's what I'm doing right now)? What's your perspective?

PS: Also considered just browserifying but feels kind of ridiculous

Need to make work inside Electron

Currently, it seems that Electron does not correctly implement WebCrypto interfaces. Specifically it seems that It doesn't have generateKey functions. Without this, we will not be able to deprecate the node-webcrypto-ossl library.

Passing a TypedArray with an offset to importKey, the offset is ignored.

var keyDatasource = new Uint8Array([0,221,184,11,6,126,13,73,147,25,127,225,15,38,87,168,68,163,132,88,152,71,96,45,86,240,198,41,200,26,174,50,1,210,138,62,83,207,250,65,158,193,34,201,104,179,37,158,22,182,80,118,73,84,148,217,124,174,16,187,254,195,195,111])
var rawKey = keyDatasource.subarray(32, 64)
var key = await crypto.subtle.importKey('raw', rawKey, {name:'HMAC', hash:'SHA-512'}, true, ['sign'])
var exportedKey = new Uint8Array(await crypto.subtle.exportKey('raw', key))
assert(exportedKey.length === 64) // should be 32

Tested in browser, the byte offset is respected and the imported key is the latter 32 bytes of the source data. In this library, the imported key is all 64 bytes of the underlying ArrayBuffer.

Export key error

With the latest release of this library v1.1.7 I get the following error

Cannot get schema for 'PrivateKeyInfo' target

When running the following

const crypto = new Crypto();

const cryptoKeyPair = (await crypto.subtle.generateKey(
    {
      name: "ECDSA",
      namedCurve: "P-256",
    },
    true,
    [KeyUsage.SIGN]
  ));

  const exportedKey = (await subtleCrypto.exportKey("jwk", cryptoKeyPair.privateKey));

Issue is not present with v1.1.6

For additional context i'm running NodeJS 12.22.1

Error: Cannot get schema for 'PrivateKeyInfo' target

I am generating keys with ecdh

const { Crypto } = require("@peculiar/webcrypto");
const crypto = new Crypto();

const { publicKey, privateKey } = await crypto.subtle.generateKey(
  {
    name: "ECDH",
    namedCurve: "P-256", // P-256, P-384, or P-521
  },
  true,
  ["deriveKey", "deriveBits"],
);

but when exporting them it throws me this error

Error: Cannot get schema for 'PrivateKeyInfo' target

Can someone guide me how to solve this problem?

AES encrypt / decrypt with a passphrase

Hi,

Great work !

I'm currently switching from CryptoJS and couldn't figure out how to reach this outcome:

var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");
var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");

Any hint please?

Thank you again for the quality of this repo

@peculiar/webcrypto is vulnerable to the Marvin Attack

I've tested @peculiar/webcrypto package 1.4.3 on node 21.1.0 and verified that's it's vulnerable to the Marvin Attack.

The size of the side channel is very large, so even remote exploitation will be rather easy. Both correctness of the PKCS#1 v1.5 ciphertext is leaking as well as the length of the returned message. Less than 100 measurements per probe are necessary for highly statistically significant results, so a local attack taking as little as few hours is quite realistic.

I've executed the reproducer in the marvin-toolkit repo on an AMD Ryze 5 5600X CPU running with core isolation.

After collecting 10 thousand measurements per sample, I've got the following results:

Sign test mean p-value: 0.3282, median p-value: 0.2048, min p-value: 0.0
Friedman test (chisquare approximation) for all samples
p-value: 0.0
Worst pair: 6(valid_48), 11(zero_byte_in_padding_48_4)
Mean of differences: 1.39286e-05s, 95% CI: -3.92232e-06s, 3.116315e-05s (±1.754e-05s)
Median of differences: 2.03415e-05s, 95% CI: 2.01400e-05s, 2.054000e-05s (±2.000e-07s)
Trimmed mean (5%) of differences: 2.02399e-05s, 95% CI: 2.00630e-05s, 2.041578e-05s (±1.764e-07s)
Trimmed mean (25%) of differences: 2.02831e-05s, 95% CI: 2.01000e-05s, 2.045879e-05s (±1.794e-07s)
Trimmed mean (45%) of differences: 2.03165e-05s, 95% CI: 2.01283e-05s, 2.050997e-05s (±1.908e-07s)
Trimean of differences: 2.02808e-05s, 95% CI: 2.01023e-05s, 2.045544e-05s (±1.766e-07s)
Layperson explanation: Definite side-channel detected, implementation is VULNERABLE

With a graph of confidence intervals of:
conf_interval_plot_trim_mean_05
legend for the graph:

ID,Name
0,header_only
1,no_header_with_payload_48
2,no_padding_48
3,no_structure
4,signature_padding_8
5,valid_0
6,valid_48
7,valid_192
8,valid_246
9,valid_repeated_byte_payload_246_1
10,valid_repeated_byte_payload_246_255
11,zero_byte_in_padding_48_4

explanation of the probes is in the step2.py script.

Results of the pairwise statistical tests are in this file:
report.txt

note: the p-values of 0 mean that the actual calculated p-value is smaller than what double precision floating point number can represent

Migrating from node-webcrypto-ossl

Hello,
I am using pki.js library with node-webcrypto-ossl in an electron app. While using node-webcrypto-ossl on windows for electron it produces various error and I was thinking of migrating to this library. Is there any difference between this library and node-webcrypto-ossl? Will it be fine to use any as replacement in any project?

Node.js package

Hi,
thanks for this great wrapper.

I think from node version 15.14.0 there is webcrypto in the official crytpo library.
like so: require('crypto').webcrypto
this might be a good idea to offer isomorphic package.

thanks!

exportkey returns octet instead of oct

Hi,

I am trying to migrate my code from node-webcrypto-ossl to webcrypto.
I have a problem that exportkey of an hmac key returns octet instead of oct as kty.

This is my flow:
key generation
let key = await this._crypto.subtle.generateKey(
{ hash:"SHA-256", name:"hmac"},
true,
["sign"]
);

exportkey
const jwk = await this._crypto.subtle.exportKey(
'jwk',
key);

results in:
{
alg:"HS256"
ext:true
k:"ji4zeVsT2I7ZkzKomSTSSXxaj7cq33U5mbs2SMrdAsA"
key_ops: ["sign"]
kty:"octet"
}
Can you change kty to oct as it should be?
Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.