npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@qiwitech/cryptopro

v0.1.2

Published

Web Cryptography and Key Discovery API wrapper for Crypto-Pro CAdES browser plugin

Downloads

10

Readme

Web Cryptography and Key Discovery API wrapper for Crypto-Pro CAdES browser plugin

This package exports the following.

  1. High-level Web Cryptography and WebCrypto Key Discovery API with essential methods.
  2. Mid-level wrapper classes for essential Crypto-Pro CAdES API objects.
  3. Low-level API for communicating with the Crypto-Pro CAdES browser plugin.

To use plugin, you should load its vendor script cadesplugin_api.js which isn't included to this package.

<script type="text/javascript" src="https://www.cryptopro.ru/sites/default/files/products/cades/cadesplugin_api.js"></script>

Differences from W3 specification

Please note that Crypto-Pro client software relies on X.509 certificates rather than PKI cryptography keys. At the same time, Web Cryptography API does not define any methods to manipulate X.509 certificates. So it's impossible to conform the current W3 specification by means of Crypto-Pro CAdES browser plugin.

The NamedCryptoKey and CryptoKey instances represent X.509 certificates and reference internal plugin objects.

The SubtleCrypto.generateKey and SubtleCrypto.exportKey may be used to generate HMAC keys and PKCS#10 Certificate Signing Requests, while SubtleCrypto.importKey is able to import X.509 certificates.

The SubtleCrypto.verify resolves to true for successfully verified signatures and to false otherwise. But it may reject in case of any other error, e.g. corrupted CAdES message or any issues with certificate chain.

Web Cryptography API

import { createSubtleCrypto, createCryptoKeys, createHelper, getPlugin } form '@qiwitech/cryptopro';

const plugin = await getPlugin(window),
	helper = await createHelper(plugin),
	subtle = await createSubtleCrypto(helper),
	cryptokeys = await createCryptoKeys(helper);

digest

digest(algo: AlgorithmIdentifier, buffer: ArrayBuffer): Promise<ArrayBuffer>

exportKey

exportKey(format: KeyFormat, key: CryptoKey | NamedCryptoKey): Promise<ArrayBuffer>

generateKey

generateKey(algorithm: AlgorithmIdentifier, extractable: bool, keyUsages: Array<KeyUsage>): Promise<ArrayBuffer>

importKey

importKey(format: KeyFormat, keyData: ArrayBuffer, algorithm: AlgorithmIdentifier, extractable: bool, keyUsages: Array<KeyUsage>): Promise<CryptoKey>

sign

sign(algo: AlgorithmIdentifier, key: CryptoKey | NamedCryptoKey, buffer: ArrayBuffer): Promise<ArrayBuffer>

verify

verify(algo: AlgorithmIdentifier, key: CryptoKey | NamedCryptoKey, signature: ArrayBuffer, buffer: ArrayBuffer): Promise<void>

WebCrypto Key Discovery API

getKeyById

getKeyById(id: string): Promise<?NamedCryptoKey>

getKeyByName

getKeyByName(name: string): Promise<?NamedCryptoKey>

getKeyByExtendedKeyUsage

getKeyByExtendedKeyUsage(oid: string): Promise<?NamedCryptoKey>

getKeysByExtendedKeyUsages

getKeysByExtendedKeyUsages(oids: Array<string>): Promise<Array<NamedCryptoKey>>

API helper

createHelper

createHelper(plugin: Plugin): Promise<Helper>

Note that cadesplugin is actually an instance of Promise with injected methods and constants, which resolves to undefined instead of actual API object. So it's recommended to use getPlugin helper function.

import { createHelper, getPlugin } form '@qiwitech/cryptopro';

const helper = await createHelper(
	await getPlugin(window)
);

It's possible to directly pass a cadesplugin reference to createHelper.

import { createHelper } form '@qiwitech/cryptopro';

window.cadesplugin.then(
	() => createHelper(window.cadesplugin)
).then(
	(helper) => ...
);

createSubtleCrypto

createSubtleCrypto(helper: Helper): Promise<SubtleCrypto>

createCryptoKeys

createCryptoKeys(helper: Helper): Promise<CryptoKeys>

Wrapper classes

Wrapper classes utilize API similar to Node.js Crypto module. It's generally not recommended to use them, but they could be useful for special cases not covered by high-level Web Cryptography API.

There are helper functions available to create instance of any class.

const hash = await helper.createHash(helper.plugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256);
await hash.update('cWl3aXRlY2g=', helper.plugin.CADESCOM_BASE64_TO_BINARY);
const hex = await hash.digest();

It's not recommended, but is possible to use actual classes with the new keyword. Note they always take Helper and Handle instances as first and second arguments respectively. Some classes have an async populate method that must be called before any other one.

const hash = new cryptopro.Hash(
	helper,
	await helper.createHandle('CAdESCOM.HashedData'),
	helper.plugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256
);
await hash.populate();

Plugin API

getPlugin

getPlugin(scope: Object, options?: PluginOptions): Promise<Plugin>

The getPlugin function accepts the scope (generally, window) and returns the reference to the Crypto-Pro CAdES browser plugin.

import { getPlugin } form '@qiwitech/cryptopro';

const plugin = await getPlugin(window);

Examples

Get started

import { createSubtleCrypto, createCryptoKeys, createHelper, getPlugin } form '@qiwitech/cryptopro';

const plugin = await getPlugin(window),
	helper = await createHelper(plugin),
	crypto = {
		subtle: await createSubtleCrypto(helper)
	},
	cryptokeys = await createCryptoKeys(helper);

Sign

const digestAlgo = 'GOST R 34.11-2012-256',
	signAlgo = 'GOST R 34.10-2012-256',
	text = 'Hello World',
	data = new TextEncoder().encode(text).buffer;

const namedKey = await cryptokeys.getKeyByName('...'),
	hash = await crypto.subtle.digest(digestAlgo, data);
	signature = await crypto.subtle.sign(signAlgo, namedKey, hash),
	certificate = await crypto.subtle.exportKey('x509', namedKey),
	valid = await crypto.subtle.verify(signAlgo, namedKey, siganture, hash);
await sendToOtherParty(hash, signature, certificate);

// NOTE this also works: both sign() and verify() can pre-hash data for you.
const signature = await crypto.subtle.sign(digestAlgo, namedKey, data),
	valid = await crypto.subtle.verify(digestAlgo, namedKey, signature, data);
await sendToOtherParty(data, signature, certificate);

Verify

const digestAlgo = 'GOST R 34.11-2012-256',
	signAlgo = 'GOST R 34.10-2012';

const { data, signature, certificate } = await getFromOtherParty(),
	publicKey = await crypto.subtle.importKey('x509', certificate, ['verify']),
	hash = await crypto.subtle.digest(digestAlgo, data);
	valid = await crypto.subtle.verify(signAlgo, publicKey, siganture, hash);

// NOTE this also works: verify() can pre-hash data for you.
const valid = await crypto.subtle.verify(digestAlgo, publicKey, signature, data);

Generate PKCS#10 CSR and install response

The only way to create new keypair is to call SubtleCrypto.generateKey method to generate a keypair, then use SubtleCrypto.exportKey to format a PKCS#10 Certificate Signing Request, send it to the trusted Certificate Authority, then receive a newly issued X.509 Certificate and finally import it into available certificate storage using the SubtleCrypto.importKey method.

const signAlgo = 'GOST R 34.10-2012-256';

const { publicKey, privateKey } = await crypto.subtle.generateKey(signAlgo, false, ['sign', 'verify']);

// NOTE publicKey.name may be used to define certificate Common name (CN).
publicKey.name = 'New certificate';

const csr = await crypto.subtle.exportKey('pkcs10', publicKey),
	certificate = await sendToCertificateAutority(csr),
	{ publicKey, privateKey } = await crypto.subtle.importKey('x509', certificate, signAlgo, false, ['sign', 'verify']);