Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: improve Sign/Verify examples and docs #25452

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 45 additions & 64 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ This can be called many times with new data as it is streamed.
added: v0.1.94
-->

The `Hmac` Class is a utility for creating cryptographic HMAC digests. It can
The `Hmac` class is a utility for creating cryptographic HMAC digests. It can
be used in one of two ways:

- As a [stream][] that is both readable and writable, where data is written
Expand Down Expand Up @@ -1196,7 +1196,7 @@ or `'private'` for private (asymmetric) keys.
added: v0.1.92
-->

The `Sign` Class is a utility for generating signatures. It can be used in one
The `Sign` class is a utility for generating signatures. It can be used in one
of two ways:

- As a writable [stream][], where data to be signed is written and the
Expand All @@ -1208,51 +1208,46 @@ The [`crypto.createSign()`][] method is used to create `Sign` instances. The
argument is the string name of the hash function to use. `Sign` objects are not
to be created directly using the `new` keyword.

Example: Using `Sign` objects as streams:
Example: Using `Sign` and [`Verify`][] objects as streams:

```js
const crypto = require('crypto');
const sign = crypto.createSign('SHA256');

const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'sect239k1'
});

const sign = crypto.createSign('SHA256');
sign.write('some data to sign');
sign.end();
const signature = sign.sign(privateKey, 'hex');

const privateKey = getPrivateKeySomehow();
console.log(sign.sign(privateKey, 'hex'));
// Prints: the calculated signature using the specified private key and
// SHA-256. For RSA keys, the algorithm is RSASSA-PKCS1-v1_5 (see padding
// parameter below for RSASSA-PSS). For EC keys, the algorithm is ECDSA.
const verify = crypto.createVerify('SHA256');
verify.write('some data to sign');
verify.end();
console.log(verify.verify(publicKey, signature));
// Prints: true or false
```

Example: Using the [`sign.update()`][] and [`sign.sign()`][] methods:
Example: Using the [`sign.update()`][] and [`verify.update()`][] methods:

```js
const crypto = require('crypto');
const sign = crypto.createSign('SHA256');

sign.update('some data to sign');

const privateKey = getPrivateKeySomehow();
console.log(sign.sign(privateKey, 'hex'));
// Prints: the calculated signature
```

In some cases, a `Sign` instance can also be created by passing in a signature
algorithm name, such as 'RSA-SHA256'. This will use the corresponding digest
algorithm. This does not work for all signature algorithms, such as
'ecdsa-with-SHA256'. Use digest names instead.

Example: signing using legacy signature algorithm name

```js
const crypto = require('crypto');
const sign = crypto.createSign('RSA-SHA256');
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});

const sign = crypto.createSign('SHA256');
sign.update('some data to sign');
sign.end();
const signature = sign.sign(privateKey);

const privateKey = getPrivateKeySomehow();
console.log(sign.sign(privateKey, 'hex'));
// Prints: the calculated signature
const verify = crypto.createVerify('SHA256');
verify.update('some data to sign');
verify.end();
console.log(verify.verify(publicKey, signature));
// Prints: true
```

### sign.sign(privateKey[, outputEncoding])
Expand Down Expand Up @@ -1332,34 +1327,7 @@ of two ways:
The [`crypto.createVerify()`][] method is used to create `Verify` instances.
`Verify` objects are not to be created directly using the `new` keyword.

Example: Using `Verify` objects as streams:

```js
const crypto = require('crypto');
const verify = crypto.createVerify('SHA256');

verify.write('some data to sign');
verify.end();

const publicKey = getPublicKeySomehow();
const signature = getSignatureToVerify();
console.log(verify.verify(publicKey, signature));
// Prints: true or false
```

Example: Using the [`verify.update()`][] and [`verify.verify()`][] methods:

```js
const crypto = require('crypto');
const verify = crypto.createVerify('SHA256');

verify.update('some data to sign');

const publicKey = getPublicKeySomehow();
const signature = getSignatureToVerify();
console.log(verify.verify(publicKey, signature));
// Prints: true or false
```
See [`Sign`][] for examples.

### verify.update(data[, inputEncoding])
<!-- YAML
Expand Down Expand Up @@ -1886,10 +1854,15 @@ added: v0.1.92
* `options` {Object} [`stream.Writable` options][]
* Returns: {Sign}

Creates and returns a `Sign` object that uses the given `algorithm`.
Use [`crypto.getHashes()`][] to obtain an array of names of the available
signing algorithms. Optional `options` argument controls the
`stream.Writable` behavior.
Creates and returns a `Sign` object that uses the given `algorithm`. Use
[`crypto.getHashes()`][] to obtain the names of the available digest algorithms.
Optional `options` argument controls the `stream.Writable` behavior.

In some cases, a `Sign` instance can be created using the name of a signature
algorithm, such as `'RSA-SHA256'`, instead of a digest algorithm. This will use
the corresponding digest algorithm. This does not work for all signature
algorithms, such as `'ecdsa-with-SHA256'`, so it is best to always use digest
algorithm names.
Copy link
Member

Choose a reason for hiding this comment

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

I would probably express this in an even stronger way, as far as I know, this is specific to OpenSSL.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm just moving the existing text closer to the API it refers to, I don't want to rework too much unless its got a serious problem. In this case, we never build with anything other than OpenSSL, so doesn't all the docs apply to OpenSSL? I'll add some specific text if you suggest, but I'm not sure what else to say, myself.


### crypto.createVerify(algorithm[, options])
<!-- YAML
Expand All @@ -1904,6 +1877,12 @@ Use [`crypto.getHashes()`][] to obtain an array of names of the available
signing algorithms. Optional `options` argument controls the
`stream.Writable` behavior.

In some cases, a `Verify` instance can be created using the name of a signature
algorithm, such as `'RSA-SHA256'`, instead of a digest algorithm. This will use
the corresponding digest algorithm. This does not work for all signature
algorithms, such as `'ecdsa-with-SHA256'`, so it is best to always use digest
algorithm names.

### crypto.generateKeyPair(type, options, callback)
<!-- YAML
added: v10.12.0
Expand Down Expand Up @@ -2084,7 +2063,7 @@ added: v10.0.0
added: v0.9.3
-->
* Returns: {string[]} An array of the names of the supported hash algorithms,
such as `'RSA-SHA256'`.
such as `'RSA-SHA256'`. Hash algorithms are also called "digest" algorithms.

```js
const hashes = crypto.getHashes();
Expand Down Expand Up @@ -3103,7 +3082,9 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL.
[`Buffer`]: buffer.html
[`EVP_BytesToKey`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_BytesToKey.html
[`KeyObject`]: #crypto_class_keyobject
[`Sign`]: #crypto_class_sign
[`UV_THREADPOOL_SIZE`]: cli.html#cli_uv_threadpool_size_size
[`Verify`]: #crypto_class_verify
[`cipher.final()`]: #crypto_cipher_final_outputencoding
[`cipher.update()`]: #crypto_cipher_update_data_inputencoding_outputencoding
[`crypto.createCipher()`]: #crypto_crypto_createcipher_algorithm_password_options
Expand Down