Skip to content

Commit c4a0670

Browse files
committed
Improved documentation
1 parent ec149ca commit c4a0670

File tree

5 files changed

+135
-9
lines changed

5 files changed

+135
-9
lines changed

lib/src/impl_ffi/impl_ffi.rsa_common.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ ffi.Pointer<ssl.EVP_PKEY> _importJwkRsaPrivateOrPublicKey(
8484
'must be "$expectedUse", if present',
8585
);
8686

87+
// TODO: Consider rejecting private keys with 'use', as it's only valid for
88+
// public keys according to the RFC -- maybe read the RFC again to be
89+
// perfectly sure this is correct behavior.
90+
// Also the web crypto spec on this, which says to reject invalid 'use'
8791
// TODO: Consider rejecting keys with key_ops inconsistent with isPrivateKey
8892
// See also JWK import logic for EC keys
8993

lib/src/impl_js/impl_js.utils.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ Future<subtle.CryptoKey> _importJsonWebKey(
133133
) {
134134
return _handleDomException(() async {
135135
final jwkObj = subtle.JsonWebKey.fromJson(jwk);
136+
// TODO: Validate expected 'use' the way we have it in the FFI implementation
137+
136138
// Remove 'key_ops' and 'ext' as this library doesn't configuring
137139
// _usages_ and _extractable_.
138140
// Notice that we also strip 'key_ops' and 'ext' in [_exportJsonWebKey].
@@ -286,6 +288,7 @@ Future<Uint8List> _exportKey(
286288
/// Adapt `crypto.subtle.export` to Dart types.
287289
Future<Map<String, Object>> _exportJsonWebKey(
288290
subtle.CryptoKey key,
291+
// TODO: Add expected 'use' the way we have it in the FFI implementation
289292
) {
290293
return _handleDomException(() async {
291294
final result = await subtle.promiseAsFuture(subtle.exportJsonWebKey(

lib/src/webcrypto/webcrypto.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
library webcrypto;
1616

1717
import 'package:meta/meta.dart';
18+
import 'dart:convert';
1819
import 'dart:async';
1920
import 'dart:typed_data';
2021
import '../impl_stub.dart'

lib/src/webcrypto/webcrypto.digest.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,13 @@ part of webcrypto;
2323
/// * [Hash.sha384], and,
2424
/// * [Hash.sha512].
2525
///
26+
/// For a guidance on choice of hash function see
27+
/// [NIST SP 800-57 Part 1 Rev 5][1].
28+
///
2629
/// **WARNING:** Custom implementations of this class cannot be passed to
2730
/// to other methods in this library.
31+
///
32+
/// [1]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf
2833
@sealed
2934
abstract class Hash {
3035
Hash._(); // keep the constructor private.

lib/src/webcrypto/webcrypto.rsassapkcs1v15.dart

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,44 @@ abstract class RsassaPkcs1V15PrivateKey {
7272

7373
/// Import RSASSA-PKCS1-v1_5 private key in [JWK][1] format.
7474
///
75-
/// TODO: finish documentation.
75+
/// The [jwk] should be given as [Map], [String], [List] the same way
76+
/// [json.decode] from `dart:convert` represents decoded JSON values.
77+
/// The hash algorithm to be used is specified by [hash].
78+
///
79+
/// JSON Web Keys imported using [RsassaPkcs1V15PrivateKey.importJsonWebKey]
80+
/// must have `"kty": "RSA"`, and the [hash] given must match the hash
81+
/// algorithm implied by the `"alg"` property of the imported [jwk].
82+
/// For importing a JWK with:
83+
///
84+
/// * `"alg": "RS1"` use [Hash.sha1] (**SHA-1 is weak**),
85+
/// * `"alg": "RS256"` use [Hash.sha256],
86+
/// * `"alg": "RS384"` use [Hash.sha384], and,
87+
/// * `"alg": "RS512"` use [Hash.sha512].
88+
///
89+
/// **Example**
90+
/// ```dart
91+
/// import 'package:webcrypto/webcrypto.dart';
92+
/// import 'dart:convert' show json;
93+
///
94+
/// // JSON Web Key as a string containing JSON.
95+
/// final jwk = '{"kty": "RSA", "alg": "RS256", ...}';
96+
///
97+
/// // Import private key from decoded JSON.
98+
/// final privateKey = await RsassaPkcs1V15PrivateKey.importJsonWebKey(
99+
/// json.decode(jwk),
100+
/// Hash.sha256, // Must match the hash used the JWK key "alg"
101+
/// );
102+
///
103+
/// // Export the key (print it in same format as it was given).
104+
/// Map<String, dynamic> keyData = await privateKey.exportJsonWebKey();
105+
/// print(json.encode(keyData));
106+
/// ```
107+
///
108+
/// **Warning**, the `"use"` and `"key_ops"` properties from the [jwk],
109+
/// specifying intended usage for public keys and allowed key operations,
110+
/// are ignored. If these properties are present they will have no effect.
111+
/// This is also the case when running on the web, as they will be stripped
112+
/// before the JWK is passed to the browser.
76113
///
77114
/// [1]: https://tools.ietf.org/html/rfc7517
78115
static Future<RsassaPkcs1V15PrivateKey> importJsonWebKey(
@@ -87,12 +124,26 @@ abstract class RsassaPkcs1V15PrivateKey {
87124

88125
/// Generate an RSASSA-PKCS1-v1_5 public/private key-pair.
89126
///
90-
/// Generate an RSA key with given [modulusLength], this should be at-least
91-
/// `2048` (though `4096` is often recommended). [publicExponent] should be
92-
/// `3` or `65537` these are the only values [supported by Chrome][1], unless
93-
/// you have a good reason to use something else `65537` is recommended.
127+
/// The [modulusLength], given in bits, determines the size of the RSA key.
128+
/// A larger key size (higher [modulusLength]) is often consider more secure,
129+
/// but generally associated with decreased performance. This can be
130+
/// particularly noticible during key-generation on limited devices CPUs.
94131
///
95-
/// The hash algorithm to be used is specified by [hash].
132+
/// Using a [modulusLength] less than `2048` is often discouraged
133+
/// (see [NIST SP 800-57 Part 1 Rev 5, section 5.6][3]). Common key size
134+
/// include `2048`, `3072` and `4096` for guidance on key-size see
135+
/// [NIST SP 800-57 Part 1 Rev 5][3] or [keylength.com][2] for a comparison of
136+
/// various recommendations.
137+
///
138+
/// The [publicExponent] must be given as [BigInt]. Currently, this package
139+
/// has opted to only support `3` and `65537` as [publicExponent], these are
140+
/// also the only values [supported by Chrome][1]. To generate RSA keys with a
141+
/// different [publicExponent] use a different package for key generation.
142+
/// It is common to use `65537` as [publicExponent], see [Wikipedia on RSA][4]
143+
/// for an explanation of [publicExponent] (and RSA in general).
144+
///
145+
/// The hash algorithm to be used is specified by [hash]. Be ware that
146+
/// **use of [Hash.sha1] is discouraged**.
96147
///
97148
/// **Example**
98149
/// ```dart
@@ -135,6 +186,9 @@ abstract class RsassaPkcs1V15PrivateKey {
135186
/// ```
136187
///
137188
/// [1]: https://chromium.googlesource.com/chromium/src/+/43d62c50b705f88c67b14539e91fd8fd017f70c4/components/webcrypto/algorithms/rsa.cc#286
189+
/// [2]: https://www.keylength.com/en/
190+
/// [3]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf
191+
/// [4]: https://en.wikipedia.org/wiki/RSA_(cryptosystem)
138192
static Future<KeyPair<RsassaPkcs1V15PrivateKey, RsassaPkcs1V15PublicKey>>
139193
generateKey(
140194
int modulusLength,
@@ -251,7 +305,29 @@ abstract class RsassaPkcs1V15PrivateKey {
251305

252306
/// Export RSASSA-PKCS1-v1_5 private key in [JWK][1] format.
253307
///
254-
/// TODO: finish documentation.
308+
/// The output will be given as [Map], [String], [List] the same way
309+
/// [json.decode] from `dart:convert` represents decoded JSON values.
310+
///
311+
/// **Example**
312+
/// ```dart
313+
/// import 'package:webcrypto/webcrypto.dart';
314+
/// import 'dart:convert' show json;
315+
///
316+
/// // Generate a key-pair.
317+
/// final keyPair = await RsassaPkcs1V15PrivateKey.generateKey(
318+
/// 4096,
319+
/// BigInt.from(65537),
320+
/// Hash.sha256,
321+
/// );
322+
///
323+
/// // Export the private key.
324+
/// final jwk = await keypair.privateKey.exportJsonWebKey();
325+
///
326+
/// // The Map returned by `exportJsonWebKey()` can be converted to JSON with
327+
/// // `json.encode` from `dart:convert`, this will print something like:
328+
/// // {"kty": "RSA", "alg": "RS256", ...}
329+
/// print(json.encode(jwk));
330+
/// ```
255331
///
256332
/// [1]: https://tools.ietf.org/html/rfc7517
257333
Future<Map<String, dynamic>> exportJsonWebKey();
@@ -314,9 +390,46 @@ abstract class RsassaPkcs1V15PublicKey {
314390
return impl.rsassaPkcs1V15PublicKey_importSpkiKey(keyData, hash);
315391
}
316392

317-
/// Import RSASSA-PKCS1-v1_5 public key from [JWK][1].
393+
/// Import RSASSA-PKCS1-v1_5 public key in [JWK][1] format.
318394
///
319-
/// TODO: finish documentation.
395+
/// The [jwk] should be given as [Map], [String], [List] the same way
396+
/// [json.decode] from `dart:convert` represents decoded JSON values.
397+
/// The hash algorithm to be used is specified by [hash].
398+
///
399+
/// JSON Web Keys imported using [RsassaPkcs1V15PublicKey.importJsonWebKey]
400+
/// must have `"kty": "RSA"`, and the [hash] given must match the hash
401+
/// algorithm implied by the `"alg"` property of the imported [jwk].
402+
/// For importing a JWK with:
403+
///
404+
/// * `"alg": "RS1"` use [Hash.sha1] (**SHA-1 is weak**),
405+
/// * `"alg": "RS256"` use [Hash.sha256],
406+
/// * `"alg": "RS384"` use [Hash.sha384], and,
407+
/// * `"alg": "RS512"` use [Hash.sha512].
408+
///
409+
/// **Example**
410+
/// ```dart
411+
/// import 'package:webcrypto/webcrypto.dart';
412+
/// import 'dart:convert' show json;
413+
///
414+
/// // JSON Web Key as a string containing JSON.
415+
/// final jwk = '{"kty": "RSA", "alg": "RS256", ...}';
416+
///
417+
/// // Import public key from decoded JSON.
418+
/// final publicKey = await RsassaPkcs1V15PublicKey.importJsonWebKey(
419+
/// json.decode(jwk),
420+
/// Hash.sha256, // Must match the hash used the JWK key "alg"
421+
/// );
422+
///
423+
/// // Export the key (print it in same format as it was given).
424+
/// Map<String, dynamic> keyData = await publicKey.exportJsonWebKey();
425+
/// print(json.encode(keyData));
426+
/// ```
427+
///
428+
/// **Warning**, the `"use"` and `"key_ops"` properties from the [jwk],
429+
/// specifying intended usage for public keys and allowed key operations,
430+
/// are ignored. If these properties are present they will have no effect.
431+
/// This is also the case when running on the web, as they will be stripped
432+
/// before the JWK is passed to the browser.
320433
///
321434
/// [1]: https://tools.ietf.org/html/rfc7517
322435
static Future<RsassaPkcs1V15PublicKey> importJsonWebKey(

0 commit comments

Comments
 (0)