@libp2p/crypto 0.0.0 → 0.22.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/LICENSE +2 -0
  2. package/README.md +314 -0
  3. package/dist/src/aes/cipher-mode.d.ts +2 -0
  4. package/dist/src/aes/cipher-mode.d.ts.map +1 -0
  5. package/dist/src/aes/cipher-mode.js +13 -0
  6. package/dist/src/aes/cipher-mode.js.map +1 -0
  7. package/dist/src/aes/ciphers-browser.d.ts +8 -0
  8. package/dist/src/aes/ciphers-browser.d.ts.map +1 -0
  9. package/dist/src/aes/ciphers-browser.js +26 -0
  10. package/dist/src/aes/ciphers-browser.js.map +1 -0
  11. package/dist/src/aes/ciphers.d.ts +5 -0
  12. package/dist/src/aes/ciphers.d.ts.map +1 -0
  13. package/dist/src/aes/ciphers.js +4 -0
  14. package/dist/src/aes/ciphers.js.map +1 -0
  15. package/dist/src/aes/index.d.ts +6 -0
  16. package/dist/src/aes/index.d.ts.map +1 -0
  17. package/dist/src/aes/index.js +17 -0
  18. package/dist/src/aes/index.js.map +1 -0
  19. package/dist/src/ciphers/aes-gcm.browser.d.ts +3 -0
  20. package/dist/src/ciphers/aes-gcm.browser.d.ts.map +1 -0
  21. package/dist/src/ciphers/aes-gcm.browser.js +61 -0
  22. package/dist/src/ciphers/aes-gcm.browser.js.map +1 -0
  23. package/dist/src/ciphers/aes-gcm.d.ts +3 -0
  24. package/dist/src/ciphers/aes-gcm.d.ts.map +1 -0
  25. package/dist/src/ciphers/aes-gcm.js +83 -0
  26. package/dist/src/ciphers/aes-gcm.js.map +1 -0
  27. package/dist/src/ciphers/interface.d.ts +14 -0
  28. package/dist/src/ciphers/interface.d.ts.map +1 -0
  29. package/dist/src/ciphers/interface.js +2 -0
  30. package/dist/src/ciphers/interface.js.map +1 -0
  31. package/dist/src/hmac/index-browser.d.ts +5 -0
  32. package/dist/src/hmac/index-browser.d.ts.map +1 -0
  33. package/dist/src/hmac/index-browser.js +25 -0
  34. package/dist/src/hmac/index-browser.js.map +1 -0
  35. package/dist/src/hmac/index.d.ts +5 -0
  36. package/dist/src/hmac/index.d.ts.map +1 -0
  37. package/dist/src/hmac/index.js +14 -0
  38. package/dist/src/hmac/index.js.map +1 -0
  39. package/dist/src/hmac/lengths.d.ts +7 -0
  40. package/dist/src/hmac/lengths.d.ts.map +1 -0
  41. package/dist/src/hmac/lengths.js +6 -0
  42. package/dist/src/hmac/lengths.js.map +1 -0
  43. package/dist/src/index.d.ts +11 -0
  44. package/dist/src/index.d.ts.map +1 -0
  45. package/dist/src/index.js +11 -0
  46. package/dist/src/index.js.map +1 -0
  47. package/dist/src/keys/ecdh-browser.d.ts +3 -0
  48. package/dist/src/keys/ecdh-browser.d.ts.map +1 -0
  49. package/dist/src/keys/ecdh-browser.js +97 -0
  50. package/dist/src/keys/ecdh-browser.js.map +1 -0
  51. package/dist/src/keys/ecdh.d.ts +3 -0
  52. package/dist/src/keys/ecdh.d.ts.map +1 -0
  53. package/dist/src/keys/ecdh.js +26 -0
  54. package/dist/src/keys/ecdh.js.map +1 -0
  55. package/dist/src/keys/ed25519-class.d.ts +39 -0
  56. package/dist/src/keys/ed25519-class.d.ts.map +1 -0
  57. package/dist/src/keys/ed25519-class.js +119 -0
  58. package/dist/src/keys/ed25519-class.js.map +1 -0
  59. package/dist/src/keys/ed25519.d.ts +18 -0
  60. package/dist/src/keys/ed25519.d.ts.map +1 -0
  61. package/dist/src/keys/ed25519.js +52 -0
  62. package/dist/src/keys/ed25519.js.map +1 -0
  63. package/dist/src/keys/ephemeral-keys.d.ts +9 -0
  64. package/dist/src/keys/ephemeral-keys.d.ts.map +1 -0
  65. package/dist/src/keys/ephemeral-keys.js +9 -0
  66. package/dist/src/keys/ephemeral-keys.js.map +1 -0
  67. package/dist/src/keys/exporter.d.ts +7 -0
  68. package/dist/src/keys/exporter.d.ts.map +1 -0
  69. package/dist/src/keys/exporter.js +13 -0
  70. package/dist/src/keys/exporter.js.map +1 -0
  71. package/dist/src/keys/importer.d.ts +7 -0
  72. package/dist/src/keys/importer.d.ts.map +1 -0
  73. package/dist/src/keys/importer.js +13 -0
  74. package/dist/src/keys/importer.js.map +1 -0
  75. package/dist/src/keys/index.d.ts +33 -0
  76. package/dist/src/keys/index.d.ts.map +1 -0
  77. package/dist/src/keys/index.js +111 -0
  78. package/dist/src/keys/index.js.map +1 -0
  79. package/dist/src/keys/interface.d.ts +17 -0
  80. package/dist/src/keys/interface.d.ts.map +1 -0
  81. package/dist/src/keys/interface.js +2 -0
  82. package/dist/src/keys/interface.js.map +1 -0
  83. package/dist/src/keys/jwk2pem.d.ts +4 -0
  84. package/dist/src/keys/jwk2pem.d.ts.map +1 -0
  85. package/dist/src/keys/jwk2pem.js +14 -0
  86. package/dist/src/keys/jwk2pem.js.map +1 -0
  87. package/dist/src/keys/key-stretcher.d.ts +17 -0
  88. package/dist/src/keys/key-stretcher.d.ts.map +1 -0
  89. package/dist/src/keys/key-stretcher.js +65 -0
  90. package/dist/src/keys/key-stretcher.js.map +1 -0
  91. package/dist/src/keys/keys.d.ts +225 -0
  92. package/dist/src/keys/keys.d.ts.map +1 -0
  93. package/dist/src/keys/keys.js +345 -0
  94. package/dist/src/keys/keys.js.map +1 -0
  95. package/dist/src/keys/rsa-browser.d.ts +17 -0
  96. package/dist/src/keys/rsa-browser.d.ts.map +1 -0
  97. package/dist/src/keys/rsa-browser.js +99 -0
  98. package/dist/src/keys/rsa-browser.js.map +1 -0
  99. package/dist/src/keys/rsa-class.d.ts +42 -0
  100. package/dist/src/keys/rsa-class.d.ts.map +1 -0
  101. package/dist/src/keys/rsa-class.js +126 -0
  102. package/dist/src/keys/rsa-class.js.map +1 -0
  103. package/dist/src/keys/rsa-utils.d.ts +7 -0
  104. package/dist/src/keys/rsa-utils.d.ts.map +1 -0
  105. package/dist/src/keys/rsa-utils.js +65 -0
  106. package/dist/src/keys/rsa-utils.js.map +1 -0
  107. package/dist/src/keys/rsa.d.ts +13 -0
  108. package/dist/src/keys/rsa.d.ts.map +1 -0
  109. package/dist/src/keys/rsa.js +58 -0
  110. package/dist/src/keys/rsa.js.map +1 -0
  111. package/dist/src/keys/secp256k1-class.d.ts +36 -0
  112. package/dist/src/keys/secp256k1-class.d.ts.map +1 -0
  113. package/dist/src/keys/secp256k1-class.js +95 -0
  114. package/dist/src/keys/secp256k1-class.js.map +1 -0
  115. package/dist/src/keys/secp256k1.d.ts +17 -0
  116. package/dist/src/keys/secp256k1.d.ts.map +1 -0
  117. package/dist/src/keys/secp256k1.js +65 -0
  118. package/dist/src/keys/secp256k1.js.map +1 -0
  119. package/dist/src/pbkdf2.d.ts +5 -0
  120. package/dist/src/pbkdf2.d.ts.map +1 -0
  121. package/dist/src/pbkdf2.js +30 -0
  122. package/dist/src/pbkdf2.js.map +1 -0
  123. package/dist/src/random-bytes.d.ts +2 -0
  124. package/dist/src/random-bytes.d.ts.map +1 -0
  125. package/dist/src/random-bytes.js +9 -0
  126. package/dist/src/random-bytes.js.map +1 -0
  127. package/dist/src/util.d.ts +9 -0
  128. package/dist/src/util.d.ts.map +1 -0
  129. package/dist/src/util.js +37 -0
  130. package/dist/src/util.js.map +1 -0
  131. package/dist/src/webcrypto.d.ts +5 -0
  132. package/dist/src/webcrypto.d.ts.map +1 -0
  133. package/dist/src/webcrypto.js +17 -0
  134. package/dist/src/webcrypto.js.map +1 -0
  135. package/package.json +178 -4
  136. package/src/aes/cipher-mode.ts +15 -0
  137. package/src/aes/ciphers-browser.ts +28 -0
  138. package/src/aes/ciphers.ts +4 -0
  139. package/src/aes/index.ts +25 -0
  140. package/src/ciphers/aes-gcm.browser.ts +74 -0
  141. package/src/ciphers/aes-gcm.ts +102 -0
  142. package/src/ciphers/interface.ts +15 -0
  143. package/src/hmac/index-browser.ts +35 -0
  144. package/src/hmac/index.ts +15 -0
  145. package/src/hmac/lengths.ts +6 -0
  146. package/src/index.ts +11 -0
  147. package/src/keys/ecdh-browser.ts +138 -0
  148. package/src/keys/ecdh.ts +33 -0
  149. package/src/keys/ed25519-class.ts +145 -0
  150. package/src/keys/ed25519.ts +63 -0
  151. package/src/keys/ephemeral-keys.ts +9 -0
  152. package/src/keys/exporter.ts +13 -0
  153. package/src/keys/importer.ts +13 -0
  154. package/src/keys/index.ts +126 -0
  155. package/src/keys/interface.ts +20 -0
  156. package/src/keys/jwk2pem.ts +16 -0
  157. package/src/keys/key-stretcher.ts +77 -0
  158. package/src/keys/keys.d.ts +146 -0
  159. package/src/keys/keys.js +366 -0
  160. package/src/keys/keys.proto +15 -0
  161. package/src/keys/rsa-browser.ts +156 -0
  162. package/src/keys/rsa-class.ts +155 -0
  163. package/src/keys/rsa-utils.ts +74 -0
  164. package/src/keys/rsa.ts +69 -0
  165. package/src/keys/secp256k1-class.ts +118 -0
  166. package/src/keys/secp256k1.ts +69 -0
  167. package/src/pbkdf2.ts +39 -0
  168. package/src/random-bytes.ts +9 -0
  169. package/src/util.ts +42 -0
  170. package/src/webcrypto.ts +24 -0
@@ -0,0 +1,33 @@
1
+ import crypto from 'crypto'
2
+ import errcode from 'err-code'
3
+ import type { ECDHKey, ECDHKeyPair } from './interface.js'
4
+
5
+ const curves = {
6
+ 'P-256': 'prime256v1',
7
+ 'P-384': 'secp384r1',
8
+ 'P-521': 'secp521r1'
9
+ }
10
+
11
+ const curveTypes = Object.keys(curves)
12
+ const names = curveTypes.join(' / ')
13
+
14
+ export async function generateEphmeralKeyPair (curve: string): Promise<ECDHKey> { // eslint-disable-line require-await
15
+ if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') {
16
+ throw errcode(new Error(`Unknown curve: ${curve}. Must be ${names}`), 'ERR_INVALID_CURVE')
17
+ }
18
+
19
+ const ecdh = crypto.createECDH(curves[curve])
20
+ ecdh.generateKeys()
21
+
22
+ return {
23
+ key: ecdh.getPublicKey() as Uint8Array,
24
+
25
+ async genSharedKey (theirPub: Uint8Array, forcePrivate?: ECDHKeyPair): Promise<Uint8Array> { // eslint-disable-line require-await
26
+ if (forcePrivate != null) {
27
+ ecdh.setPrivateKey(forcePrivate.private)
28
+ }
29
+
30
+ return ecdh.computeSecret(theirPub)
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,145 @@
1
+ import errcode from 'err-code'
2
+ import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
3
+ import { sha256 } from 'multiformats/hashes/sha2'
4
+ import { base58btc } from 'multiformats/bases/base58'
5
+ import { identity } from 'multiformats/hashes/identity'
6
+ import * as crypto from './ed25519.js'
7
+ import * as pbm from './keys.js'
8
+ import { exporter } from './exporter.js'
9
+
10
+ export class Ed25519PublicKey {
11
+ private readonly _key: Uint8Array
12
+
13
+ constructor (key: Uint8Array) {
14
+ this._key = ensureKey(key, crypto.publicKeyLength)
15
+ }
16
+
17
+ async verify (data: Uint8Array, sig: Uint8Array) { // eslint-disable-line require-await
18
+ return await crypto.hashAndVerify(this._key, sig, data)
19
+ }
20
+
21
+ marshal () {
22
+ return this._key
23
+ }
24
+
25
+ get bytes () {
26
+ return pbm.PublicKey.encode({
27
+ Type: pbm.KeyType.Ed25519,
28
+ Data: this.marshal()
29
+ }).finish()
30
+ }
31
+
32
+ equals (key: any) {
33
+ return uint8ArrayEquals(this.bytes, key.bytes)
34
+ }
35
+
36
+ async hash () {
37
+ const { bytes } = await sha256.digest(this.bytes)
38
+
39
+ return bytes
40
+ }
41
+ }
42
+
43
+ export class Ed25519PrivateKey {
44
+ private readonly _key: Uint8Array
45
+ private readonly _publicKey: Uint8Array
46
+
47
+ // key - 64 byte Uint8Array containing private key
48
+ // publicKey - 32 byte Uint8Array containing public key
49
+ constructor (key: Uint8Array, publicKey: Uint8Array) {
50
+ this._key = ensureKey(key, crypto.privateKeyLength)
51
+ this._publicKey = ensureKey(publicKey, crypto.publicKeyLength)
52
+ }
53
+
54
+ async sign (message: Uint8Array) { // eslint-disable-line require-await
55
+ return await crypto.hashAndSign(this._key, message)
56
+ }
57
+
58
+ get public () {
59
+ return new Ed25519PublicKey(this._publicKey)
60
+ }
61
+
62
+ marshal () {
63
+ return this._key
64
+ }
65
+
66
+ get bytes () {
67
+ return pbm.PrivateKey.encode({
68
+ Type: pbm.KeyType.Ed25519,
69
+ Data: this.marshal()
70
+ }).finish()
71
+ }
72
+
73
+ equals (key: any) {
74
+ return uint8ArrayEquals(this.bytes, key.bytes)
75
+ }
76
+
77
+ async hash () {
78
+ const { bytes } = await sha256.digest(this.bytes)
79
+
80
+ return bytes
81
+ }
82
+
83
+ /**
84
+ * Gets the ID of the key.
85
+ *
86
+ * The key id is the base58 encoding of the identity multihash containing its public key.
87
+ * The public key is a protobuf encoding containing a type and the DER encoding
88
+ * of the PKCS SubjectPublicKeyInfo.
89
+ *
90
+ * @returns {Promise<string>}
91
+ */
92
+ async id () {
93
+ const encoding = await identity.digest(this.public.bytes)
94
+ return base58btc.encode(encoding.bytes).substring(1)
95
+ }
96
+
97
+ /**
98
+ * Exports the key into a password protected `format`
99
+ */
100
+ async export (password: string, format = 'libp2p-key') { // eslint-disable-line require-await
101
+ if (format === 'libp2p-key') {
102
+ return await exporter(this.bytes, password)
103
+ } else {
104
+ throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
105
+ }
106
+ }
107
+ }
108
+
109
+ export function unmarshalEd25519PrivateKey (bytes: Uint8Array) {
110
+ // Try the old, redundant public key version
111
+ if (bytes.length > crypto.privateKeyLength) {
112
+ bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
113
+ const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
114
+ const publicKeyBytes = bytes.slice(crypto.privateKeyLength, bytes.length)
115
+ return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
116
+ }
117
+
118
+ bytes = ensureKey(bytes, crypto.privateKeyLength)
119
+ const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
120
+ const publicKeyBytes = bytes.slice(crypto.publicKeyLength)
121
+ return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
122
+ }
123
+
124
+ export function unmarshalEd25519PublicKey (bytes: Uint8Array) {
125
+ bytes = ensureKey(bytes, crypto.publicKeyLength)
126
+ return new Ed25519PublicKey(bytes)
127
+ }
128
+
129
+ export async function generateKeyPair () {
130
+ const { privateKey, publicKey } = await crypto.generateKey()
131
+ return new Ed25519PrivateKey(privateKey, publicKey)
132
+ }
133
+
134
+ export async function generateKeyPairFromSeed (seed: Uint8Array) {
135
+ const { privateKey, publicKey } = await crypto.generateKeyFromSeed(seed)
136
+ return new Ed25519PrivateKey(privateKey, publicKey)
137
+ }
138
+
139
+ function ensureKey (key: Uint8Array, length: number) {
140
+ key = Uint8Array.from(key ?? [])
141
+ if (key.length !== length) {
142
+ throw errcode(new Error(`Key must be a Uint8Array of length ${length}, got ${key.length}`), 'ERR_INVALID_KEY_TYPE')
143
+ }
144
+ return key
145
+ }
@@ -0,0 +1,63 @@
1
+ import * as ed from '@noble/ed25519'
2
+
3
+ const PUBLIC_KEY_BYTE_LENGTH = 32
4
+ const PRIVATE_KEY_BYTE_LENGTH = 64 // private key is actually 32 bytes but for historical reasons we concat private and public keys
5
+ const KEYS_BYTE_LENGTH = 32
6
+
7
+ export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength }
8
+ export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength }
9
+
10
+ export async function generateKey () {
11
+ // the actual private key (32 bytes)
12
+ const privateKeyRaw = ed.utils.randomPrivateKey()
13
+ const publicKey = await ed.getPublicKey(privateKeyRaw)
14
+
15
+ // concatenated the public key to the private key
16
+ const privateKey = concatKeys(privateKeyRaw, publicKey)
17
+
18
+ return {
19
+ privateKey,
20
+ publicKey
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Generate keypair from a 32 byte uint8array
26
+ */
27
+ export async function generateKeyFromSeed (seed: Uint8Array) {
28
+ if (seed.length !== KEYS_BYTE_LENGTH) {
29
+ throw new TypeError('"seed" must be 32 bytes in length.')
30
+ } else if (!(seed instanceof Uint8Array)) {
31
+ throw new TypeError('"seed" must be a node.js Buffer, or Uint8Array.')
32
+ }
33
+
34
+ // based on node forges algorithm, the seed is used directly as private key
35
+ const privateKeyRaw = seed
36
+ const publicKey = await ed.getPublicKey(privateKeyRaw)
37
+
38
+ const privateKey = concatKeys(privateKeyRaw, publicKey)
39
+
40
+ return {
41
+ privateKey,
42
+ publicKey
43
+ }
44
+ }
45
+
46
+ export async function hashAndSign (privateKey: Uint8Array, msg: Uint8Array) {
47
+ const privateKeyRaw = privateKey.slice(0, KEYS_BYTE_LENGTH)
48
+
49
+ return await ed.sign(msg, privateKeyRaw)
50
+ }
51
+
52
+ export async function hashAndVerify (publicKey: Uint8Array, sig: Uint8Array, msg: Uint8Array) {
53
+ return await ed.verify(sig, msg, publicKey)
54
+ }
55
+
56
+ function concatKeys (privateKeyRaw: Uint8Array, publicKey: Uint8Array) {
57
+ const privateKey = new Uint8Array(PRIVATE_KEY_BYTE_LENGTH)
58
+ for (let i = 0; i < KEYS_BYTE_LENGTH; i++) {
59
+ privateKey[i] = privateKeyRaw[i]
60
+ privateKey[KEYS_BYTE_LENGTH + i] = publicKey[i]
61
+ }
62
+ return privateKey
63
+ }
@@ -0,0 +1,9 @@
1
+ import { generateEphmeralKeyPair } from './ecdh.js'
2
+
3
+ /**
4
+ * Generates an ephemeral public key and returns a function that will compute
5
+ * the shared secret key.
6
+ *
7
+ * Focuses only on ECDH now, but can be made more general in the future.
8
+ */
9
+ export default generateEphmeralKeyPair
@@ -0,0 +1,13 @@
1
+ import { base64 } from 'multiformats/bases/base64'
2
+ import * as ciphers from '../ciphers/aes-gcm.js'
3
+
4
+ /**
5
+ * Exports the given PrivateKey as a base64 encoded string.
6
+ * The PrivateKey is encrypted via a password derived PBKDF2 key
7
+ * leveraging the aes-gcm cipher algorithm.
8
+ */
9
+ export async function exporter (privateKey: Uint8Array, password: string) {
10
+ const cipher = ciphers.create()
11
+ const encryptedKey = await cipher.encrypt(privateKey, password)
12
+ return base64.encode(encryptedKey)
13
+ }
@@ -0,0 +1,13 @@
1
+ import { base64 } from 'multiformats/bases/base64'
2
+ import * as ciphers from '../ciphers/aes-gcm.js'
3
+
4
+ /**
5
+ * Attempts to decrypt a base64 encoded PrivateKey string
6
+ * with the given password. The privateKey must have been exported
7
+ * using the same password and underlying cipher (aes-gcm)
8
+ */
9
+ export async function importer (privateKey: string, password: string) {
10
+ const encryptedKey = base64.decode(privateKey)
11
+ const cipher = ciphers.create()
12
+ return await cipher.decrypt(encryptedKey, password)
13
+ }
@@ -0,0 +1,126 @@
1
+ import * as keysPBM from './keys.js'
2
+ import 'node-forge/lib/asn1.js'
3
+ import 'node-forge/lib/pbe.js'
4
+ // @ts-expect-error types are missing
5
+ import forge from 'node-forge/lib/forge.js'
6
+ import errcode from 'err-code'
7
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
8
+ import { keyStretcher } from './key-stretcher.js'
9
+ import generateEphemeralKeyPair from './ephemeral-keys.js'
10
+ import { importer } from './importer.js'
11
+ import * as RSA from './rsa-class.js'
12
+ import * as Ed25519 from './ed25519-class.js'
13
+ import * as Secp256k1 from './secp256k1-class.js'
14
+
15
+ export { keyStretcher }
16
+ export { generateEphemeralKeyPair }
17
+ export { keysPBM }
18
+
19
+ export const supportedKeys = {
20
+ rsa: RSA,
21
+ ed25519: Ed25519,
22
+ secp256k1: Secp256k1
23
+ }
24
+
25
+ function unsupportedKey (type: string) {
26
+ const supported = Object.keys(supportedKeys).join(' / ')
27
+ return errcode(new Error(`invalid or unsupported key type ${type}. Must be ${supported}`), 'ERR_UNSUPPORTED_KEY_TYPE')
28
+ }
29
+
30
+ function typeToKey (type: string) {
31
+ type = type.toLowerCase()
32
+
33
+ if (type === 'rsa' || type === 'ed25519' || type === 'secp256k1') {
34
+ return supportedKeys[type]
35
+ }
36
+
37
+ throw unsupportedKey(type)
38
+ }
39
+
40
+ // Generates a keypair of the given type and bitsize
41
+ export async function generateKeyPair (type: 'RSA' | 'Ed25519' | 'secp256k1', bits?: number) { // eslint-disable-line require-await
42
+ return await typeToKey(type).generateKeyPair(bits ?? 2048)
43
+ }
44
+
45
+ // Generates a keypair of the given type and bitsize
46
+ // seed is a 32 byte uint8array
47
+ export async function generateKeyPairFromSeed (type: 'RSA' | 'Ed25519' | 'secp256k1', seed: Uint8Array, bits?: number) { // eslint-disable-line require-await
48
+ if (type.toLowerCase() !== 'ed25519') {
49
+ throw errcode(new Error('Seed key derivation is unimplemented for RSA or secp256k1'), 'ERR_UNSUPPORTED_KEY_DERIVATION_TYPE')
50
+ }
51
+
52
+ return await Ed25519.generateKeyPairFromSeed(seed)
53
+ }
54
+
55
+ // Converts a protobuf serialized public key into its
56
+ // representative object
57
+ export function unmarshalPublicKey (buf: Uint8Array) {
58
+ const decoded = keysPBM.PublicKey.decode(buf)
59
+ const data = decoded.Data
60
+
61
+ switch (decoded.Type) {
62
+ case keysPBM.KeyType.RSA:
63
+ return supportedKeys.rsa.unmarshalRsaPublicKey(data)
64
+ case keysPBM.KeyType.Ed25519:
65
+ return supportedKeys.ed25519.unmarshalEd25519PublicKey(data)
66
+ case keysPBM.KeyType.Secp256k1:
67
+ return supportedKeys.secp256k1.unmarshalSecp256k1PublicKey(data)
68
+ default:
69
+ throw unsupportedKey(decoded.Type)
70
+ }
71
+ }
72
+
73
+ // Converts a public key object into a protobuf serialized public key
74
+ export function marshalPublicKey (key: { bytes: Uint8Array }, type?: string) {
75
+ type = (type ?? 'rsa').toLowerCase()
76
+ typeToKey(type) // check type
77
+ return key.bytes
78
+ }
79
+
80
+ // Converts a protobuf serialized private key into its
81
+ // representative object
82
+ export async function unmarshalPrivateKey (buf: Uint8Array) { // eslint-disable-line require-await
83
+ const decoded = keysPBM.PrivateKey.decode(buf)
84
+ const data = decoded.Data
85
+
86
+ switch (decoded.Type) {
87
+ case keysPBM.KeyType.RSA:
88
+ return await supportedKeys.rsa.unmarshalRsaPrivateKey(data)
89
+ case keysPBM.KeyType.Ed25519:
90
+ return supportedKeys.ed25519.unmarshalEd25519PrivateKey(data)
91
+ case keysPBM.KeyType.Secp256k1:
92
+ return supportedKeys.secp256k1.unmarshalSecp256k1PrivateKey(data)
93
+ default:
94
+ throw unsupportedKey(decoded.Type)
95
+ }
96
+ }
97
+
98
+ // Converts a private key object into a protobuf serialized private key
99
+ export function marshalPrivateKey (key: { bytes: Uint8Array }, type?: string) {
100
+ type = (type ?? 'rsa').toLowerCase()
101
+ typeToKey(type) // check type
102
+ return key.bytes
103
+ }
104
+
105
+ /**
106
+ *
107
+ * @param {string} encryptedKey
108
+ * @param {string} password
109
+ */
110
+ export async function importKey (encryptedKey: string, password: string) { // eslint-disable-line require-await
111
+ try {
112
+ const key = await importer(encryptedKey, password)
113
+ return await unmarshalPrivateKey(key)
114
+ } catch (_) {
115
+ // Ignore and try the old pem decrypt
116
+ }
117
+
118
+ // Only rsa supports pem right now
119
+ const key = forge.pki.decryptRsaPrivateKey(encryptedKey, password)
120
+ if (key === null) {
121
+ throw errcode(new Error('Cannot read the key, most likely the password is wrong or not a RSA key'), 'ERR_CANNOT_DECRYPT_PEM')
122
+ }
123
+ let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
124
+ der = uint8ArrayFromString(der.getBytes(), 'ascii')
125
+ return await supportedKeys.rsa.unmarshalRsaPrivateKey(der)
126
+ }
@@ -0,0 +1,20 @@
1
+
2
+ export interface JWKKeyPair {
3
+ privateKey: JsonWebKey
4
+ publicKey: JsonWebKey
5
+ }
6
+
7
+ export interface Uint8ArrayKeyPair {
8
+ privateKey: Uint8Array
9
+ publicKey: Uint8Array
10
+ }
11
+
12
+ export interface ECDHKeyPair {
13
+ private: Uint8Array
14
+ public: Uint8Array
15
+ }
16
+
17
+ export interface ECDHKey {
18
+ key: Uint8Array
19
+ genSharedKey: (theirPub: Uint8Array, forcePrivate?: ECDHKeyPair) => Promise<Uint8Array>
20
+ }
@@ -0,0 +1,16 @@
1
+ import 'node-forge/lib/rsa.js'
2
+ // @ts-expect-error types are missing
3
+ import forge from 'node-forge/lib/forge.js'
4
+ import { base64urlToBigInteger } from '../util'
5
+
6
+ function convert (key: any, types: string[]) {
7
+ return types.map(t => base64urlToBigInteger(key[t]))
8
+ }
9
+
10
+ export function jwk2priv (key: JsonWebKey) {
11
+ return forge.pki.setRsaPrivateKey(...convert(key, ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi']))
12
+ }
13
+
14
+ export function jwk2pub (key: JsonWebKey) {
15
+ return forge.pki.setRsaPublicKey(...convert(key, ['n', 'e']))
16
+ }
@@ -0,0 +1,77 @@
1
+ import errcode from 'err-code'
2
+ import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
3
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
4
+ import * as hmac from '../hmac/index.js'
5
+
6
+ const cipherMap = {
7
+ 'AES-128': {
8
+ ivSize: 16,
9
+ keySize: 16
10
+ },
11
+ 'AES-256': {
12
+ ivSize: 16,
13
+ keySize: 32
14
+ },
15
+ Blowfish: {
16
+ ivSize: 8,
17
+ keySize: 32
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Generates a set of keys for each party by stretching the shared key.
23
+ * (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
24
+ */
25
+ export async function keyStretcher (cipherType: 'AES-128' | 'AES-256' | 'Blowfish', hash: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array) {
26
+ const cipher = cipherMap[cipherType]
27
+
28
+ if (cipher == null) {
29
+ const allowed = Object.keys(cipherMap).join(' / ')
30
+ throw errcode(new Error(`unknown cipher type '${cipherType}'. Must be ${allowed}`), 'ERR_INVALID_CIPHER_TYPE')
31
+ }
32
+
33
+ if (hash == null) {
34
+ throw errcode(new Error('missing hash type'), 'ERR_MISSING_HASH_TYPE')
35
+ }
36
+
37
+ const cipherKeySize = cipher.keySize
38
+ const ivSize = cipher.ivSize
39
+ const hmacKeySize = 20
40
+ const seed = uint8ArrayFromString('key expansion')
41
+ const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
42
+
43
+ const m = await hmac.create(hash, secret)
44
+ let a = await m.digest(seed)
45
+
46
+ const result = []
47
+ let j = 0
48
+
49
+ while (j < resultLength) {
50
+ const b = await m.digest(uint8ArrayConcat([a, seed]))
51
+ let todo = b.length
52
+
53
+ if (j + todo > resultLength) {
54
+ todo = resultLength - j
55
+ }
56
+
57
+ result.push(b)
58
+ j += todo
59
+ a = await m.digest(a)
60
+ }
61
+
62
+ const half = resultLength / 2
63
+ const resultBuffer = uint8ArrayConcat(result)
64
+ const r1 = resultBuffer.slice(0, half)
65
+ const r2 = resultBuffer.slice(half, resultLength)
66
+
67
+ const createKey = (res: Uint8Array) => ({
68
+ iv: res.slice(0, ivSize),
69
+ cipherKey: res.slice(ivSize, ivSize + cipherKeySize),
70
+ macKey: res.slice(ivSize + cipherKeySize)
71
+ })
72
+
73
+ return {
74
+ k1: createKey(r1),
75
+ k2: createKey(r2)
76
+ }
77
+ }
@@ -0,0 +1,146 @@
1
+ import $protobuf from 'protobufjs'
2
+
3
+ /** KeyType enum. */
4
+ export enum KeyType {
5
+ RSA = 0,
6
+ Ed25519 = 1,
7
+ Secp256k1 = 2
8
+ }
9
+
10
+ export interface IPublicKey {
11
+
12
+ /** PublicKey Type. */
13
+ Type: KeyType
14
+
15
+ /** PublicKey Data. */
16
+ Data: Uint8Array
17
+ }
18
+
19
+ /** Represents a PublicKey. */
20
+ export class PublicKey implements IPublicKey {
21
+ /**
22
+ * Constructs a new PublicKey.
23
+ *
24
+ * @param [p] - Properties to set
25
+ */
26
+ constructor (p?: IPublicKey);
27
+
28
+ /** PublicKey Type. */
29
+ public Type: KeyType
30
+
31
+ /** PublicKey Data. */
32
+ public Data: Uint8Array
33
+
34
+ /**
35
+ * Encodes the specified PublicKey message. Does not implicitly {@link PublicKey.verify|verify} messages.
36
+ *
37
+ * @param m - PublicKey message or plain object to encode
38
+ * @param [w] - Writer to encode to
39
+ * @returns Writer
40
+ */
41
+ public static encode (m: IPublicKey, w?: $protobuf.Writer): $protobuf.Writer;
42
+
43
+ /**
44
+ * Decodes a PublicKey message from the specified reader or buffer.
45
+ *
46
+ * @param r - Reader or buffer to decode from
47
+ * @param [l] - Message length if known beforehand
48
+ * @returns PublicKey
49
+ * @throws {Error} If the payload is not a reader or valid buffer
50
+ * @throws {$protobuf.util.ProtocolError} If required fields are missing
51
+ */
52
+ public static decode (r: ($protobuf.Reader|Uint8Array), l?: number): PublicKey;
53
+
54
+ /**
55
+ * Creates a PublicKey message from a plain object. Also converts values to their respective internal types.
56
+ *
57
+ * @param d - Plain object
58
+ * @returns PublicKey
59
+ */
60
+ public static fromObject (d: { [k: string]: any }): PublicKey;
61
+
62
+ /**
63
+ * Creates a plain object from a PublicKey message. Also converts values to other types if specified.
64
+ *
65
+ * @param m - PublicKey
66
+ * @param [o] - Conversion options
67
+ * @returns Plain object
68
+ */
69
+ public static toObject (m: PublicKey, o?: $protobuf.IConversionOptions): { [k: string]: any };
70
+
71
+ /**
72
+ * Converts this PublicKey to JSON.
73
+ *
74
+ * @returns JSON object
75
+ */
76
+ public toJSON (): { [k: string]: any };
77
+ }
78
+
79
+ export interface IPrivateKey {
80
+
81
+ /** PrivateKey Type. */
82
+ Type: KeyType
83
+
84
+ /** PrivateKey Data. */
85
+ Data: Uint8Array
86
+ }
87
+
88
+ /** Represents a PrivateKey. */
89
+ export class PrivateKey implements IPrivateKey {
90
+ /**
91
+ * Constructs a new PrivateKey.
92
+ *
93
+ * @param [p] - Properties to set
94
+ */
95
+ constructor (p?: IPrivateKey);
96
+
97
+ /** PrivateKey Type. */
98
+ public Type: KeyType
99
+
100
+ /** PrivateKey Data. */
101
+ public Data: Uint8Array
102
+
103
+ /**
104
+ * Encodes the specified PrivateKey message. Does not implicitly {@link PrivateKey.verify|verify} messages.
105
+ *
106
+ * @param m - PrivateKey message or plain object to encode
107
+ * @param [w] - Writer to encode to
108
+ * @returns Writer
109
+ */
110
+ public static encode (m: IPrivateKey, w?: $protobuf.Writer): $protobuf.Writer;
111
+
112
+ /**
113
+ * Decodes a PrivateKey message from the specified reader or buffer.
114
+ *
115
+ * @param r - Reader or buffer to decode from
116
+ * @param [l] - Message length if known beforehand
117
+ * @returns PrivateKey
118
+ * @throws {Error} If the payload is not a reader or valid buffer
119
+ * @throws {$protobuf.util.ProtocolError} If required fields are missing
120
+ */
121
+ public static decode (r: ($protobuf.Reader|Uint8Array), l?: number): PrivateKey;
122
+
123
+ /**
124
+ * Creates a PrivateKey message from a plain object. Also converts values to their respective internal types.
125
+ *
126
+ * @param d - Plain object
127
+ * @returns PrivateKey
128
+ */
129
+ public static fromObject (d: { [k: string]: any }): PrivateKey;
130
+
131
+ /**
132
+ * Creates a plain object from a PrivateKey message. Also converts values to other types if specified.
133
+ *
134
+ * @param m - PrivateKey
135
+ * @param [o] - Conversion options
136
+ * @returns Plain object
137
+ */
138
+ public static toObject (m: PrivateKey, o?: $protobuf.IConversionOptions): { [k: string]: any };
139
+
140
+ /**
141
+ * Converts this PrivateKey to JSON.
142
+ *
143
+ * @returns JSON object
144
+ */
145
+ public toJSON (): { [k: string]: any };
146
+ }