Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Web Crypto Signature Provider and conversion methods #937

Merged
merged 22 commits into from
Sep 7, 2021
Merged

Conversation

bradlhart
Copy link
Contributor

@bradlhart bradlhart commented May 19, 2021

Change Description

The Web Crypto API, or otherwise referred as SubtleCrypto, has the ability to construct or import both public and private keys as well as sign data using the private key CryptoKey. The format of the CryptoKey and Signature are different than eosjs built-in format and elliptic format. This code adds functionality to convert from eosjs built-in format to CryptoKeys as well as CryptoKeys and Signature to eosjs format.

Lastly, this code also includes a Web Crypto Signature Provider that can be used to store keys and sign transactions before sending to nodeos.

API Changes

  • API Changes

Added:
PrivateKey.toWebCrypto(): converts PrivateKey to private CryptoKey
PrivateKey.fromWebCrypto(): converts private CryptoKey to PrivateKey
PrivateKey.webCryptoSign(): signs data in Web Crypto method (sha256 hashing is done within Web Crypto method)
PublicKey.toWebCrypto(): converts PublicKey to public CryptoKey
PublicKey.fromWebCrypto(): converts public CryptoKey to PublicKey
Signature.fromWebCrypto(): converts Web Crypto-created signature to Signature

New:
WebCryptoSignatureProvider signature provider
addCryptoKeyPair: convenient method to add a CryptoKeyPair to the signature provider, rather than populating keys and availableKeys manually
sign: creates a buffer to sign utilizing Web Crypto's sign method and converts the outputted signature to a Signature class

Documentation Additions

  • Documentation Additions

Added a concise section about the new WebCryptoSignatureProvider

@bradlhart bradlhart marked this pull request as ready for review May 29, 2021 00:48
@bradlhart bradlhart requested a review from venu-block1 May 29, 2021 00:53
@bradlhart bradlhart requested a review from bogniq June 14, 2021 15:13
Copy link

@DominicTobias-b1 DominicTobias-b1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. This has been tested out in cornea

Copy link

@bogniq bogniq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Just one comment for clarification.

const derHex = Buffer.from(extractedDecoded, 'binary').toString('hex');
const publicKeyHex = derHex.replace('3059301306072a8648ce3d020106082a8648ce3d030107034200', '');
const publicKeyEc = ec.keyFromPublic(publicKeyHex, 'hex');
return PublicKey.fromElliptic(publicKeyEc, KeyType.r1, ec);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, could ec be initially passed non-empty and of type secp256k1, or only p256 is supported here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only p256 is supported for the Web Crypto API but it is possible that someone could put a k1 ec object and the code would break. I think a check is likely needed, I'll add it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, turns out the elliptic library does not easily label the curve utilized in the object. It would not be as simple as checking ec.curve.label = 'p256';. I will remove the ability of providing an ec object to the functions.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This looks more clear too me.

let recoveredKey: any;
for (let i = 0; i < 4; i++) {
try {
const keyPair = ec.recoverPubKey(digest, signature, i);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name keyPair is a bit confusing as private key is not here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the recoverPubKey function will return an ec keyPair object, although the private will be empty and the public will be non-empty.

@bradlhart bradlhart requested review from praphael and removed request for venu-block1 June 21, 2021 15:59
nksanthosh added a commit that referenced this pull request Jul 1, 2021
CI/CD changes for PRs #937/#963/#964 - merging per a request from Brad

this is a bug with github actions, version 12.14.1 has been replaced by the v15.14.0 ones, can you override and merge it?

It also might be because I have to copy the workflow files to master but I won't be certain until this one is merged

Will be verified and can be reverted if something else breaks.
@nksanthosh nksanthosh self-requested a review September 2, 2021 18:57
Copy link
Collaborator

@nksanthosh nksanthosh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per BLU-20451 this is now ready for merge. Please address the docs change requested.

@@ -14,3 +14,6 @@ The SignatureProvider object must contain the private keys corresponding to the
The Api constructor requires a SignatureProvider. SignatureProviders implement the `dist/eosjs-api-interfaces.SignatureProvider` interface. For development purpose only, a `JsSignatureProvider` object is also provided via the `dist/eosjs-jssig` import to stand-in for an easy option for a signature provider during development, but should only be used in development, as it is not secure.

In production code, it is recommended that you use a secure vault outside of the context of the webpage (which will also implement the `eosjs-api-interfaces.SignatureProvider` interface) to ensure security when signing transactions.

## WebCryptoSignatureProvider
Additionally, `WebCryptoSignatureProvider` is available in `eosjs` as a more secure built-in `SignatureProvider` than `JsSignatureProvider`. Utilizing the [SubtleCrypto interface of the Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto), the `WebCryptoSignatureProvider` provides functionality for signing transactions utilizing CryptoKeys created by Web Crypto. There are several methods available as well to convert extractable CryptoKeys into PrivateKey/PublicKey `eosjs` formats, which can then be converted into string or `elliptic` keypairs. The method `generateWebCryptoKeyPair` is also available to create a CryptoKeyPair where the private CryptoKey is non-extractable and the public CryptoKey is extractable. This is intentional as an extractable private key is more insecure than a non-extractable private key. There are several more security concerns that you will need to address when it comes to utilizing the Web Crypto API, such as secure key management, so only utilize the `WebCryptoSignatureProvider` if you are aware of these security requirements and the risks involved in insecure environments.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this section and provide a stub in its place and once the documentation is created and signed off by Product and Developer Relations - they can PR those changes in via a separate PR. Other than that this PR is now ready to merge per BLU-20451

@alex-radulescu-b1
Copy link

@bradlhart What is the status of this PR?
I can see in Jira it is marked as Done, but still open here.

@bradlhart bradlhart merged commit 22a1a05 into develop Sep 7, 2021
@bradlhart bradlhart deleted the subtleCrypto branch September 7, 2021 13:48
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants