@libp2p/crypto 1.0.11 → 1.0.13

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 (107) hide show
  1. package/dist/index.min.js +7 -7
  2. package/dist/src/aes/cipher-mode.d.ts.map +1 -1
  3. package/dist/src/aes/cipher-mode.js +2 -2
  4. package/dist/src/aes/cipher-mode.js.map +1 -1
  5. package/dist/src/aes/ciphers-browser.d.ts +4 -5
  6. package/dist/src/aes/ciphers-browser.d.ts.map +1 -1
  7. package/dist/src/aes/ciphers-browser.js.map +1 -1
  8. package/dist/src/aes/index.d.ts.map +1 -1
  9. package/dist/src/ciphers/aes-gcm.browser.d.ts.map +1 -1
  10. package/dist/src/ciphers/aes-gcm.d.ts.map +1 -1
  11. package/dist/src/hmac/index-browser.d.ts +1 -1
  12. package/dist/src/hmac/index-browser.d.ts.map +1 -1
  13. package/dist/src/hmac/index-browser.js.map +1 -1
  14. package/dist/src/hmac/index.d.ts +4 -3
  15. package/dist/src/hmac/index.d.ts.map +1 -1
  16. package/dist/src/hmac/index.js.map +1 -1
  17. package/dist/src/keys/ecdh-browser.d.ts.map +1 -1
  18. package/dist/src/keys/ecdh-browser.js +6 -6
  19. package/dist/src/keys/ecdh-browser.js.map +1 -1
  20. package/dist/src/keys/ecdh.js +2 -2
  21. package/dist/src/keys/ecdh.js.map +1 -1
  22. package/dist/src/keys/ed25519-browser.d.ts +3 -8
  23. package/dist/src/keys/ed25519-browser.d.ts.map +1 -1
  24. package/dist/src/keys/ed25519-browser.js.map +1 -1
  25. package/dist/src/keys/ed25519-class.d.ts +3 -3
  26. package/dist/src/keys/ed25519-class.d.ts.map +1 -1
  27. package/dist/src/keys/ed25519-class.js +4 -4
  28. package/dist/src/keys/ed25519-class.js.map +1 -1
  29. package/dist/src/keys/ed25519.d.ts +3 -8
  30. package/dist/src/keys/ed25519.d.ts.map +1 -1
  31. package/dist/src/keys/ed25519.js +16 -3
  32. package/dist/src/keys/ed25519.js.map +1 -1
  33. package/dist/src/keys/exporter.d.ts +2 -1
  34. package/dist/src/keys/exporter.d.ts.map +1 -1
  35. package/dist/src/keys/exporter.js.map +1 -1
  36. package/dist/src/keys/importer.d.ts.map +1 -1
  37. package/dist/src/keys/index.js +4 -4
  38. package/dist/src/keys/index.js.map +1 -1
  39. package/dist/src/keys/interface.d.ts +19 -0
  40. package/dist/src/keys/interface.d.ts.map +1 -1
  41. package/dist/src/keys/jwk2pem.d.ts +6 -2
  42. package/dist/src/keys/jwk2pem.d.ts.map +1 -1
  43. package/dist/src/keys/jwk2pem.js.map +1 -1
  44. package/dist/src/keys/key-stretcher.d.ts +2 -12
  45. package/dist/src/keys/key-stretcher.d.ts.map +1 -1
  46. package/dist/src/keys/key-stretcher.js +3 -3
  47. package/dist/src/keys/key-stretcher.js.map +1 -1
  48. package/dist/src/keys/keys.d.ts.map +1 -1
  49. package/dist/src/keys/keys.js.map +1 -1
  50. package/dist/src/keys/rsa-browser.d.ts +3 -8
  51. package/dist/src/keys/rsa-browser.d.ts.map +1 -1
  52. package/dist/src/keys/rsa-browser.js +2 -2
  53. package/dist/src/keys/rsa-browser.js.map +1 -1
  54. package/dist/src/keys/rsa-class.d.ts +5 -5
  55. package/dist/src/keys/rsa-class.d.ts.map +1 -1
  56. package/dist/src/keys/rsa-class.js +3 -3
  57. package/dist/src/keys/rsa-class.js.map +1 -1
  58. package/dist/src/keys/rsa-utils.d.ts.map +1 -1
  59. package/dist/src/keys/rsa-utils.js +3 -3
  60. package/dist/src/keys/rsa-utils.js.map +1 -1
  61. package/dist/src/keys/rsa.d.ts +3 -4
  62. package/dist/src/keys/rsa.d.ts.map +1 -1
  63. package/dist/src/keys/rsa.js +2 -2
  64. package/dist/src/keys/rsa.js.map +1 -1
  65. package/dist/src/keys/secp256k1-class.d.ts +2 -1
  66. package/dist/src/keys/secp256k1-class.d.ts.map +1 -1
  67. package/dist/src/keys/secp256k1-class.js +3 -3
  68. package/dist/src/keys/secp256k1-class.js.map +1 -1
  69. package/dist/src/keys/secp256k1.d.ts.map +1 -1
  70. package/dist/src/keys/secp256k1.js +6 -6
  71. package/dist/src/keys/secp256k1.js.map +1 -1
  72. package/dist/src/pbkdf2.js +2 -2
  73. package/dist/src/pbkdf2.js.map +1 -1
  74. package/dist/src/random-bytes.js +2 -2
  75. package/dist/src/random-bytes.js.map +1 -1
  76. package/dist/src/util.d.ts.map +1 -1
  77. package/dist/src/util.js.map +1 -1
  78. package/dist/typedoc-urls.json +4 -0
  79. package/package.json +6 -8
  80. package/src/aes/cipher-mode.ts +3 -3
  81. package/src/aes/ciphers-browser.ts +6 -2
  82. package/src/aes/index.ts +1 -1
  83. package/src/ciphers/aes-gcm.browser.ts +3 -3
  84. package/src/ciphers/aes-gcm.ts +5 -5
  85. package/src/hmac/index-browser.ts +2 -2
  86. package/src/hmac/index.ts +6 -1
  87. package/src/keys/ecdh-browser.ts +12 -12
  88. package/src/keys/ecdh.ts +2 -2
  89. package/src/keys/ed25519-browser.ts +6 -5
  90. package/src/keys/ed25519-class.ts +23 -22
  91. package/src/keys/ed25519.ts +25 -9
  92. package/src/keys/exporter.ts +2 -1
  93. package/src/keys/importer.ts +1 -1
  94. package/src/keys/index.ts +6 -6
  95. package/src/keys/interface.ts +15 -0
  96. package/src/keys/jwk2pem.ts +8 -3
  97. package/src/keys/key-stretcher.ts +6 -5
  98. package/src/keys/keys.ts +1 -1
  99. package/src/keys/rsa-browser.ts +12 -11
  100. package/src/keys/rsa-class.ts +24 -23
  101. package/src/keys/rsa-utils.ts +5 -5
  102. package/src/keys/rsa.ts +6 -6
  103. package/src/keys/secp256k1-class.ts +20 -19
  104. package/src/keys/secp256k1.ts +14 -14
  105. package/src/pbkdf2.ts +2 -2
  106. package/src/random-bytes.ts +2 -2
  107. package/src/util.ts +2 -2
@@ -1,15 +1,15 @@
1
- import errcode from 'err-code'
1
+ import { CodeError } from '@libp2p/interfaces/errors'
2
2
 
3
3
  const CIPHER_MODES = {
4
4
  16: 'aes-128-ctr',
5
5
  32: 'aes-256-ctr'
6
6
  }
7
7
 
8
- export function cipherMode (key: Uint8Array) {
8
+ export function cipherMode (key: Uint8Array): string {
9
9
  if (key.length === 16 || key.length === 32) {
10
10
  return CIPHER_MODES[key.length]
11
11
  }
12
12
 
13
13
  const modes = Object.entries(CIPHER_MODES).map(([k, v]) => `${k} (${v})`).join(' / ')
14
- throw errcode(new Error(`Invalid key length ${key.length} bytes. Must be ${modes}`), 'ERR_INVALID_KEY_LENGTH')
14
+ throw new CodeError(`Invalid key length ${key.length} bytes. Must be ${modes}`, 'ERR_INVALID_KEY_LENGTH')
15
15
  }
@@ -5,7 +5,11 @@ import forge from 'node-forge/lib/forge.js'
5
5
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
6
6
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
7
7
 
8
- export function createCipheriv (mode: any, key: Uint8Array, iv: Uint8Array) {
8
+ export interface Cipher {
9
+ update: (data: Uint8Array) => Uint8Array
10
+ }
11
+
12
+ export function createCipheriv (mode: any, key: Uint8Array, iv: Uint8Array): Cipher {
9
13
  const cipher2 = forge.cipher.createCipher('AES-CTR', uint8ArrayToString(key, 'ascii'))
10
14
  cipher2.start({ iv: uint8ArrayToString(iv, 'ascii') })
11
15
  return {
@@ -16,7 +20,7 @@ export function createCipheriv (mode: any, key: Uint8Array, iv: Uint8Array) {
16
20
  }
17
21
  }
18
22
 
19
- export function createDecipheriv (mode: any, key: Uint8Array, iv: Uint8Array) {
23
+ export function createDecipheriv (mode: any, key: Uint8Array, iv: Uint8Array): Cipher {
20
24
  const cipher2 = forge.cipher.createDecipher('AES-CTR', uint8ArrayToString(key, 'ascii'))
21
25
  cipher2.start({ iv: uint8ArrayToString(iv, 'ascii') })
22
26
  return {
package/src/aes/index.ts CHANGED
@@ -6,7 +6,7 @@ export interface AESCipher {
6
6
  decrypt: (data: Uint8Array) => Promise<Uint8Array>
7
7
  }
8
8
 
9
- export async function create (key: Uint8Array, iv: Uint8Array) { // eslint-disable-line require-await
9
+ export async function create (key: Uint8Array, iv: Uint8Array): Promise<AESCipher> { // eslint-disable-line require-await
10
10
  const mode = cipherMode(key)
11
11
  const cipher = ciphers.createCipheriv(mode, key, iv)
12
12
  const decipher = ciphers.createDecipheriv(mode, key, iv)
@@ -5,7 +5,7 @@ import type { CreateOptions, AESCipher } from './interface.js'
5
5
 
6
6
  // Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples
7
7
 
8
- export function create (opts?: CreateOptions) {
8
+ export function create (opts?: CreateOptions): AESCipher {
9
9
  const algorithm = opts?.algorithm ?? 'AES-GCM'
10
10
  let keyLength = opts?.keyLength ?? 16
11
11
  const nonceLength = opts?.nonceLength ?? 12
@@ -20,7 +20,7 @@ export function create (opts?: CreateOptions) {
20
20
  * Uses the provided password to derive a pbkdf2 key. The key
21
21
  * will then be used to encrypt the data.
22
22
  */
23
- async function encrypt (data: Uint8Array, password: string | Uint8Array) { // eslint-disable-line require-await
23
+ async function encrypt (data: Uint8Array, password: string | Uint8Array): Promise<Uint8Array> { // eslint-disable-line require-await
24
24
  const salt = crypto.getRandomValues(new Uint8Array(saltLength))
25
25
  const nonce = crypto.getRandomValues(new Uint8Array(nonceLength))
26
26
  const aesGcm = { name: algorithm, iv: nonce }
@@ -45,7 +45,7 @@ export function create (opts?: CreateOptions) {
45
45
  * this decryption cipher must be the same as those used to create
46
46
  * the encryption cipher.
47
47
  */
48
- async function decrypt (data: Uint8Array, password: string | Uint8Array) {
48
+ async function decrypt (data: Uint8Array, password: string | Uint8Array): Promise<Uint8Array> {
49
49
  const salt = data.subarray(0, saltLength)
50
50
  const nonce = data.subarray(saltLength, saltLength + nonceLength)
51
51
  const ciphertext = data.subarray(saltLength + nonceLength)
@@ -5,7 +5,7 @@ import type { CreateOptions, AESCipher } from './interface.js'
5
5
 
6
6
  // Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples
7
7
 
8
- export function create (opts?: CreateOptions) {
8
+ export function create (opts?: CreateOptions): AESCipher {
9
9
  const algorithm = opts?.algorithm ?? 'aes-128-gcm'
10
10
  const keyLength = opts?.keyLength ?? 16
11
11
  const nonceLength = opts?.nonceLength ?? 12
@@ -14,7 +14,7 @@ export function create (opts?: CreateOptions) {
14
14
  const iterations = opts?.iterations ?? 32767
15
15
  const algorithmTagLength = opts?.algorithmTagLength ?? 16
16
16
 
17
- async function encryptWithKey (data: Uint8Array, key: Uint8Array) { // eslint-disable-line require-await
17
+ async function encryptWithKey (data: Uint8Array, key: Uint8Array): Promise<Uint8Array> { // eslint-disable-line require-await
18
18
  const nonce = crypto.randomBytes(nonceLength)
19
19
 
20
20
  // Create the cipher instance.
@@ -31,7 +31,7 @@ export function create (opts?: CreateOptions) {
31
31
  * Uses the provided password to derive a pbkdf2 key. The key
32
32
  * will then be used to encrypt the data.
33
33
  */
34
- async function encrypt (data: Uint8Array, password: string | Uint8Array) { // eslint-disable-line require-await
34
+ async function encrypt (data: Uint8Array, password: string | Uint8Array): Promise<Uint8Array> { // eslint-disable-line require-await
35
35
  // Generate a 128-bit salt using a CSPRNG.
36
36
  const salt = crypto.randomBytes(saltLength)
37
37
 
@@ -53,7 +53,7 @@ export function create (opts?: CreateOptions) {
53
53
  * this decryption cipher must be the same as those used to create
54
54
  * the encryption cipher.
55
55
  */
56
- async function decryptWithKey (ciphertextAndNonce: Uint8Array, key: Uint8Array) { // eslint-disable-line require-await
56
+ async function decryptWithKey (ciphertextAndNonce: Uint8Array, key: Uint8Array): Promise<Uint8Array> { // eslint-disable-line require-await
57
57
  // Create Uint8Arrays of nonce, ciphertext and tag.
58
58
  const nonce = ciphertextAndNonce.subarray(0, nonceLength)
59
59
  const ciphertext = ciphertextAndNonce.subarray(nonceLength, ciphertextAndNonce.length - algorithmTagLength)
@@ -77,7 +77,7 @@ export function create (opts?: CreateOptions) {
77
77
  * @param {Uint8Array} data - The data to decrypt
78
78
  * @param {string|Uint8Array} password - A plain password
79
79
  */
80
- async function decrypt (data: Uint8Array, password: string | Uint8Array) { // eslint-disable-line require-await
80
+ async function decrypt (data: Uint8Array, password: string | Uint8Array): Promise<Uint8Array> { // eslint-disable-line require-await
81
81
  // Create Uint8Arrays of salt and ciphertextAndNonce.
82
82
  const salt = data.subarray(0, saltLength)
83
83
  const ciphertextAndNonce = data.subarray(saltLength)
@@ -7,12 +7,12 @@ const hashTypes = {
7
7
  SHA512: 'SHA-512'
8
8
  }
9
9
 
10
- const sign = async (key: CryptoKey, data: Uint8Array) => {
10
+ const sign = async (key: CryptoKey, data: Uint8Array): Promise<Uint8Array> => {
11
11
  const buf = await webcrypto.get().subtle.sign({ name: 'HMAC' }, key, data)
12
12
  return new Uint8Array(buf, 0, buf.byteLength)
13
13
  }
14
14
 
15
- export async function create (hashType: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array) {
15
+ export async function create (hashType: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array): Promise<{ digest: (data: Uint8Array) => Promise<Uint8Array>, length: number }> {
16
16
  const hash = hashTypes[hashType]
17
17
 
18
18
  const key = await webcrypto.get().subtle.importKey(
package/src/hmac/index.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import crypto from 'crypto'
2
2
  import lengths from './lengths.js'
3
3
 
4
- export async function create (hash: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array) { // eslint-disable-line require-await
4
+ export interface HMAC {
5
+ digest: (data: Uint8Array) => Promise<Uint8Array>
6
+ length: number
7
+ }
8
+
9
+ export async function create (hash: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array): Promise<HMAC> {
5
10
  const res = {
6
11
  async digest (data: Uint8Array) { // eslint-disable-line require-await
7
12
  const hmac = crypto.createHmac(hash.toLowerCase(), secret)
@@ -1,10 +1,10 @@
1
- import errcode from 'err-code'
1
+ import { CodeError } from '@libp2p/interfaces/errors'
2
2
  import webcrypto from '../webcrypto.js'
3
3
  import { base64urlToBuffer } from '../util.js'
4
4
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
5
5
  import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
6
6
  import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
7
- import type { ECDHKey, ECDHKeyPair } from './interface.js'
7
+ import type { ECDHKey, ECDHKeyPair, JWKEncodedPrivateKey, JWKEncodedPublicKey } from './interface.js'
8
8
 
9
9
  const bits = {
10
10
  'P-256': 256,
@@ -15,9 +15,9 @@ const bits = {
15
15
  const curveTypes = Object.keys(bits)
16
16
  const names = curveTypes.join(' / ')
17
17
 
18
- export async function generateEphmeralKeyPair (curve: string) {
18
+ export async function generateEphmeralKeyPair (curve: string): Promise<ECDHKey> {
19
19
  if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') {
20
- throw errcode(new Error(`Unknown curve: ${curve}. Must be ${names}`), 'ERR_INVALID_CURVE')
20
+ throw new CodeError(`Unknown curve: ${curve}. Must be ${names}`, 'ERR_INVALID_CURVE')
21
21
  }
22
22
 
23
23
  const pair = await webcrypto.get().subtle.generateKey(
@@ -30,7 +30,7 @@ export async function generateEphmeralKeyPair (curve: string) {
30
30
  )
31
31
 
32
32
  // forcePrivate is used for testing only
33
- const genSharedKey = async (theirPub: Uint8Array, forcePrivate?: ECDHKeyPair) => {
33
+ const genSharedKey = async (theirPub: Uint8Array, forcePrivate?: ECDHKeyPair): Promise<Uint8Array> => {
34
34
  let privateKey
35
35
 
36
36
  if (forcePrivate != null) {
@@ -92,13 +92,13 @@ const curveLengths = {
92
92
  // Marshal converts a jwk encoded ECDH public key into the
93
93
  // form specified in section 4.3.6 of ANSI X9.62. (This is the format
94
94
  // go-ipfs uses)
95
- function marshalPublicKey (jwk: JsonWebKey) {
95
+ function marshalPublicKey (jwk: JsonWebKey): Uint8Array {
96
96
  if (jwk.crv == null || jwk.x == null || jwk.y == null) {
97
- throw errcode(new Error('JWK was missing components'), 'ERR_INVALID_PARAMETERS')
97
+ throw new CodeError('JWK was missing components', 'ERR_INVALID_PARAMETERS')
98
98
  }
99
99
 
100
100
  if (jwk.crv !== 'P-256' && jwk.crv !== 'P-384' && jwk.crv !== 'P-521') {
101
- throw errcode(new Error(`Unknown curve: ${jwk.crv}. Must be ${names}`), 'ERR_INVALID_CURVE')
101
+ throw new CodeError(`Unknown curve: ${jwk.crv}. Must be ${names}`, 'ERR_INVALID_CURVE')
102
102
  }
103
103
 
104
104
  const byteLen = curveLengths[jwk.crv]
@@ -111,15 +111,15 @@ function marshalPublicKey (jwk: JsonWebKey) {
111
111
  }
112
112
 
113
113
  // Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
114
- function unmarshalPublicKey (curve: string, key: Uint8Array) {
114
+ function unmarshalPublicKey (curve: string, key: Uint8Array): JWKEncodedPublicKey {
115
115
  if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') {
116
- throw errcode(new Error(`Unknown curve: ${curve}. Must be ${names}`), 'ERR_INVALID_CURVE')
116
+ throw new CodeError(`Unknown curve: ${curve}. Must be ${names}`, 'ERR_INVALID_CURVE')
117
117
  }
118
118
 
119
119
  const byteLen = curveLengths[curve]
120
120
 
121
121
  if (!uint8ArrayEquals(key.subarray(0, 1), Uint8Array.from([4]))) {
122
- throw errcode(new Error('Cannot unmarshal public key - invalid key format'), 'ERR_INVALID_KEY_FORMAT')
122
+ throw new CodeError('Cannot unmarshal public key - invalid key format', 'ERR_INVALID_KEY_FORMAT')
123
123
  }
124
124
 
125
125
  return {
@@ -131,7 +131,7 @@ function unmarshalPublicKey (curve: string, key: Uint8Array) {
131
131
  }
132
132
  }
133
133
 
134
- const unmarshalPrivateKey = (curve: string, key: ECDHKeyPair) => ({
134
+ const unmarshalPrivateKey = (curve: string, key: ECDHKeyPair): JWKEncodedPrivateKey => ({
135
135
  ...unmarshalPublicKey(curve, key.public),
136
136
  d: uint8ArrayToString(key.private, 'base64url')
137
137
  })
package/src/keys/ecdh.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import crypto from 'crypto'
2
- import errcode from 'err-code'
2
+ import { CodeError } from '@libp2p/interfaces/errors'
3
3
  import type { ECDHKey, ECDHKeyPair } from './interface.js'
4
4
 
5
5
  const curves = {
@@ -13,7 +13,7 @@ const names = curveTypes.join(' / ')
13
13
 
14
14
  export async function generateEphmeralKeyPair (curve: string): Promise<ECDHKey> { // eslint-disable-line require-await
15
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')
16
+ throw new CodeError(`Unknown curve: ${curve}. Must be ${names}`, 'ERR_INVALID_CURVE')
17
17
  }
18
18
 
19
19
  const ecdh = crypto.createECDH(curves[curve])
@@ -1,4 +1,5 @@
1
1
  import * as ed from '@noble/ed25519'
2
+ import type { Uint8ArrayKeyPair } from './interface'
2
3
 
3
4
  const PUBLIC_KEY_BYTE_LENGTH = 32
4
5
  const PRIVATE_KEY_BYTE_LENGTH = 64 // private key is actually 32 bytes but for historical reasons we concat private and public keys
@@ -7,7 +8,7 @@ const KEYS_BYTE_LENGTH = 32
7
8
  export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength }
8
9
  export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength }
9
10
 
10
- export async function generateKey () {
11
+ export async function generateKey (): Promise<Uint8ArrayKeyPair> {
11
12
  // the actual private key (32 bytes)
12
13
  const privateKeyRaw = ed.utils.randomPrivateKey()
13
14
  const publicKey = await ed.getPublicKey(privateKeyRaw)
@@ -24,7 +25,7 @@ export async function generateKey () {
24
25
  /**
25
26
  * Generate keypair from a 32 byte uint8array
26
27
  */
27
- export async function generateKeyFromSeed (seed: Uint8Array) {
28
+ export async function generateKeyFromSeed (seed: Uint8Array): Promise<Uint8ArrayKeyPair> {
28
29
  if (seed.length !== KEYS_BYTE_LENGTH) {
29
30
  throw new TypeError('"seed" must be 32 bytes in length.')
30
31
  } else if (!(seed instanceof Uint8Array)) {
@@ -43,17 +44,17 @@ export async function generateKeyFromSeed (seed: Uint8Array) {
43
44
  }
44
45
  }
45
46
 
46
- export async function hashAndSign (privateKey: Uint8Array, msg: Uint8Array) {
47
+ export async function hashAndSign (privateKey: Uint8Array, msg: Uint8Array): Promise<Uint8Array> {
47
48
  const privateKeyRaw = privateKey.subarray(0, KEYS_BYTE_LENGTH)
48
49
 
49
50
  return await ed.sign(msg, privateKeyRaw)
50
51
  }
51
52
 
52
- export async function hashAndVerify (publicKey: Uint8Array, sig: Uint8Array, msg: Uint8Array) {
53
+ export async function hashAndVerify (publicKey: Uint8Array, sig: Uint8Array, msg: Uint8Array): Promise<boolean> {
53
54
  return await ed.verify(sig, msg, publicKey)
54
55
  }
55
56
 
56
- function concatKeys (privateKeyRaw: Uint8Array, publicKey: Uint8Array) {
57
+ function concatKeys (privateKeyRaw: Uint8Array, publicKey: Uint8Array): Uint8Array {
57
58
  const privateKey = new Uint8Array(PRIVATE_KEY_BYTE_LENGTH)
58
59
  for (let i = 0; i < KEYS_BYTE_LENGTH; i++) {
59
60
  privateKey[i] = privateKeyRaw[i]
@@ -1,4 +1,4 @@
1
- import errcode from 'err-code'
1
+ import { CodeError } from '@libp2p/interfaces/errors'
2
2
  import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
3
3
  import { sha256 } from 'multiformats/hashes/sha2'
4
4
  import { base58btc } from 'multiformats/bases/base58'
@@ -6,6 +6,7 @@ import { identity } from 'multiformats/hashes/identity'
6
6
  import * as crypto from './ed25519.js'
7
7
  import * as pbm from './keys.js'
8
8
  import { exporter } from './exporter.js'
9
+ import type { Multibase } from 'multiformats'
9
10
 
10
11
  export class Ed25519PublicKey {
11
12
  private readonly _key: Uint8Array
@@ -14,26 +15,26 @@ export class Ed25519PublicKey {
14
15
  this._key = ensureKey(key, crypto.publicKeyLength)
15
16
  }
16
17
 
17
- async verify (data: Uint8Array, sig: Uint8Array) { // eslint-disable-line require-await
18
+ async verify (data: Uint8Array, sig: Uint8Array): Promise<boolean> { // eslint-disable-line require-await
18
19
  return await crypto.hashAndVerify(this._key, sig, data)
19
20
  }
20
21
 
21
- marshal () {
22
+ marshal (): Uint8Array {
22
23
  return this._key
23
24
  }
24
25
 
25
- get bytes () {
26
+ get bytes (): Uint8Array {
26
27
  return pbm.PublicKey.encode({
27
28
  Type: pbm.KeyType.Ed25519,
28
29
  Data: this.marshal()
29
30
  }).subarray()
30
31
  }
31
32
 
32
- equals (key: any) {
33
+ equals (key: any): boolean {
33
34
  return uint8ArrayEquals(this.bytes, key.bytes)
34
35
  }
35
36
 
36
- async hash () {
37
+ async hash (): Promise<Uint8Array> {
37
38
  const { bytes } = await sha256.digest(this.bytes)
38
39
 
39
40
  return bytes
@@ -51,30 +52,30 @@ export class Ed25519PrivateKey {
51
52
  this._publicKey = ensureKey(publicKey, crypto.publicKeyLength)
52
53
  }
53
54
 
54
- async sign (message: Uint8Array) { // eslint-disable-line require-await
55
+ async sign (message: Uint8Array): Promise<Uint8Array> { // eslint-disable-line require-await
55
56
  return await crypto.hashAndSign(this._key, message)
56
57
  }
57
58
 
58
- get public () {
59
+ get public (): Ed25519PublicKey {
59
60
  return new Ed25519PublicKey(this._publicKey)
60
61
  }
61
62
 
62
- marshal () {
63
+ marshal (): Uint8Array {
63
64
  return this._key
64
65
  }
65
66
 
66
- get bytes () {
67
+ get bytes (): Uint8Array {
67
68
  return pbm.PrivateKey.encode({
68
69
  Type: pbm.KeyType.Ed25519,
69
70
  Data: this.marshal()
70
71
  }).subarray()
71
72
  }
72
73
 
73
- equals (key: any) {
74
+ equals (key: any): boolean {
74
75
  return uint8ArrayEquals(this.bytes, key.bytes)
75
76
  }
76
77
 
77
- async hash () {
78
+ async hash (): Promise<Uint8Array> {
78
79
  const { bytes } = await sha256.digest(this.bytes)
79
80
 
80
81
  return bytes
@@ -89,24 +90,24 @@ export class Ed25519PrivateKey {
89
90
  *
90
91
  * @returns {Promise<string>}
91
92
  */
92
- async id () {
93
- const encoding = await identity.digest(this.public.bytes)
93
+ async id (): Promise<string> {
94
+ const encoding = identity.digest(this.public.bytes)
94
95
  return base58btc.encode(encoding.bytes).substring(1)
95
96
  }
96
97
 
97
98
  /**
98
99
  * Exports the key into a password protected `format`
99
100
  */
100
- async export (password: string, format = 'libp2p-key') { // eslint-disable-line require-await
101
+ async export (password: string, format = 'libp2p-key'): Promise<Multibase<'m'>> {
101
102
  if (format === 'libp2p-key') {
102
103
  return await exporter(this.bytes, password)
103
104
  } else {
104
- throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
105
+ throw new CodeError(`export format '${format}' is not supported`, 'ERR_INVALID_EXPORT_FORMAT')
105
106
  }
106
107
  }
107
108
  }
108
109
 
109
- export function unmarshalEd25519PrivateKey (bytes: Uint8Array) {
110
+ export function unmarshalEd25519PrivateKey (bytes: Uint8Array): Ed25519PrivateKey {
110
111
  // Try the old, redundant public key version
111
112
  if (bytes.length > crypto.privateKeyLength) {
112
113
  bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
@@ -121,25 +122,25 @@ export function unmarshalEd25519PrivateKey (bytes: Uint8Array) {
121
122
  return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
122
123
  }
123
124
 
124
- export function unmarshalEd25519PublicKey (bytes: Uint8Array) {
125
+ export function unmarshalEd25519PublicKey (bytes: Uint8Array): Ed25519PublicKey {
125
126
  bytes = ensureKey(bytes, crypto.publicKeyLength)
126
127
  return new Ed25519PublicKey(bytes)
127
128
  }
128
129
 
129
- export async function generateKeyPair () {
130
+ export async function generateKeyPair (): Promise<Ed25519PrivateKey> {
130
131
  const { privateKey, publicKey } = await crypto.generateKey()
131
132
  return new Ed25519PrivateKey(privateKey, publicKey)
132
133
  }
133
134
 
134
- export async function generateKeyPairFromSeed (seed: Uint8Array) {
135
+ export async function generateKeyPairFromSeed (seed: Uint8Array): Promise<Ed25519PrivateKey> {
135
136
  const { privateKey, publicKey } = await crypto.generateKeyFromSeed(seed)
136
137
  return new Ed25519PrivateKey(privateKey, publicKey)
137
138
  }
138
139
 
139
- function ensureKey (key: Uint8Array, length: number) {
140
+ function ensureKey (key: Uint8Array, length: number): Uint8Array {
140
141
  key = Uint8Array.from(key ?? [])
141
142
  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
+ throw new CodeError(`Key must be a Uint8Array of length ${length}, got ${key.length}`, 'ERR_INVALID_KEY_TYPE')
143
144
  }
144
145
  return key
145
146
  }
@@ -2,6 +2,7 @@ import crypto from 'crypto'
2
2
  import { promisify } from 'util'
3
3
  import { toString as uint8arrayToString } from 'uint8arrays/to-string'
4
4
  import { fromString as uint8arrayFromString } from 'uint8arrays/from-string'
5
+ import type { Uint8ArrayKeyPair } from './interface.js'
5
6
 
6
7
  const keypair = promisify(crypto.generateKeyPair)
7
8
 
@@ -13,13 +14,28 @@ const SIGNATURE_BYTE_LENGTH = 64
13
14
  export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength }
14
15
  export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength }
15
16
 
16
- function derivePublicKey (privateKey: Uint8Array) {
17
- const hash = crypto.createHash('sha512')
18
- hash.update(privateKey)
19
- return hash.digest().subarray(32)
17
+ function derivePublicKey (privateKey: Uint8Array): Uint8Array {
18
+ const keyObject = crypto.createPrivateKey({
19
+ format: 'jwk',
20
+ key: {
21
+ crv: 'Ed25519',
22
+ x: '',
23
+ d: uint8arrayToString(privateKey, 'base64url'),
24
+ kty: 'OKP'
25
+ }
26
+ })
27
+ const jwk = keyObject.export({
28
+ format: 'jwk'
29
+ })
30
+
31
+ if (jwk.x == null || jwk.x === '') {
32
+ throw new Error('Could not export JWK public key')
33
+ }
34
+
35
+ return uint8arrayFromString(jwk.x, 'base64url')
20
36
  }
21
37
 
22
- export async function generateKey () {
38
+ export async function generateKey (): Promise<Uint8ArrayKeyPair> {
23
39
  const key = await keypair('ed25519', {
24
40
  publicKeyEncoding: { type: 'spki', format: 'jwk' },
25
41
  privateKeyEncoding: { type: 'pkcs8', format: 'jwk' }
@@ -39,7 +55,7 @@ export async function generateKey () {
39
55
  /**
40
56
  * Generate keypair from a 32 byte uint8array
41
57
  */
42
- export async function generateKeyFromSeed (seed: Uint8Array) {
58
+ export async function generateKeyFromSeed (seed: Uint8Array): Promise<Uint8ArrayKeyPair> {
43
59
  if (seed.length !== KEYS_BYTE_LENGTH) {
44
60
  throw new TypeError('"seed" must be 32 bytes in length.')
45
61
  } else if (!(seed instanceof Uint8Array)) {
@@ -55,7 +71,7 @@ export async function generateKeyFromSeed (seed: Uint8Array) {
55
71
  }
56
72
  }
57
73
 
58
- export async function hashAndSign (key: Uint8Array, msg: Uint8Array) {
74
+ export async function hashAndSign (key: Uint8Array, msg: Uint8Array): Promise<Buffer> {
59
75
  if (!(key instanceof Uint8Array)) {
60
76
  throw new TypeError('"key" must be a node.js Buffer, or Uint8Array.')
61
77
  }
@@ -86,7 +102,7 @@ export async function hashAndSign (key: Uint8Array, msg: Uint8Array) {
86
102
  return crypto.sign(null, msg, obj)
87
103
  }
88
104
 
89
- export async function hashAndVerify (key: Uint8Array, sig: Uint8Array, msg: Uint8Array) {
105
+ export async function hashAndVerify (key: Uint8Array, sig: Uint8Array, msg: Uint8Array): Promise<boolean> {
90
106
  if (key.byteLength !== PUBLIC_KEY_BYTE_LENGTH) {
91
107
  throw new TypeError('"key" must be 32 bytes in length.')
92
108
  } else if (!(key instanceof Uint8Array)) {
@@ -111,7 +127,7 @@ export async function hashAndVerify (key: Uint8Array, sig: Uint8Array, msg: Uint
111
127
  return crypto.verify(null, msg, obj, sig)
112
128
  }
113
129
 
114
- function concatKeys (privateKeyRaw: Uint8Array, publicKey: Uint8Array) {
130
+ function concatKeys (privateKeyRaw: Uint8Array, publicKey: Uint8Array): Uint8Array {
115
131
  const privateKey = new Uint8Array(PRIVATE_KEY_BYTE_LENGTH)
116
132
  for (let i = 0; i < KEYS_BYTE_LENGTH; i++) {
117
133
  privateKey[i] = privateKeyRaw[i]
@@ -1,3 +1,4 @@
1
+ import type { Multibase } from 'multiformats'
1
2
  import { base64 } from 'multiformats/bases/base64'
2
3
  import * as ciphers from '../ciphers/aes-gcm.js'
3
4
 
@@ -6,7 +7,7 @@ import * as ciphers from '../ciphers/aes-gcm.js'
6
7
  * The PrivateKey is encrypted via a password derived PBKDF2 key
7
8
  * leveraging the aes-gcm cipher algorithm.
8
9
  */
9
- export async function exporter (privateKey: Uint8Array, password: string) {
10
+ export async function exporter (privateKey: Uint8Array, password: string): Promise<Multibase<'m'>> {
10
11
  const cipher = ciphers.create()
11
12
  const encryptedKey = await cipher.encrypt(privateKey, password)
12
13
  return base64.encode(encryptedKey)
@@ -6,7 +6,7 @@ import * as ciphers from '../ciphers/aes-gcm.js'
6
6
  * with the given password. The privateKey must have been exported
7
7
  * using the same password and underlying cipher (aes-gcm)
8
8
  */
9
- export async function importer (privateKey: string, password: string) {
9
+ export async function importer (privateKey: string, password: string): Promise<Uint8Array> {
10
10
  const encryptedKey = base64.decode(privateKey)
11
11
  const cipher = ciphers.create()
12
12
  return await cipher.decrypt(encryptedKey, password)
package/src/keys/index.ts CHANGED
@@ -3,7 +3,7 @@ import 'node-forge/lib/asn1.js'
3
3
  import 'node-forge/lib/pbe.js'
4
4
  // @ts-expect-error types are missing
5
5
  import forge from 'node-forge/lib/forge.js'
6
- import errcode from 'err-code'
6
+ import { CodeError } from '@libp2p/interfaces/errors'
7
7
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
8
8
  import { keyStretcher } from './key-stretcher.js'
9
9
  import generateEphemeralKeyPair from './ephemeral-keys.js'
@@ -25,12 +25,12 @@ export const supportedKeys = {
25
25
  secp256k1: Secp256k1
26
26
  }
27
27
 
28
- function unsupportedKey (type: string) {
28
+ function unsupportedKey (type: string): CodeError<Record<string, never>> {
29
29
  const supported = Object.keys(supportedKeys).join(' / ')
30
- return errcode(new Error(`invalid or unsupported key type ${type}. Must be ${supported}`), 'ERR_UNSUPPORTED_KEY_TYPE')
30
+ return new CodeError(`invalid or unsupported key type ${type}. Must be ${supported}`, 'ERR_UNSUPPORTED_KEY_TYPE')
31
31
  }
32
32
 
33
- function typeToKey (type: string) {
33
+ function typeToKey (type: string): typeof RSA | typeof Ed25519 | typeof Secp256k1 {
34
34
  type = type.toLowerCase()
35
35
 
36
36
  if (type === 'rsa' || type === 'ed25519' || type === 'secp256k1') {
@@ -49,7 +49,7 @@ export async function generateKeyPair (type: KeyTypes, bits?: number): Promise<P
49
49
  // seed is a 32 byte uint8array
50
50
  export async function generateKeyPairFromSeed (type: KeyTypes, seed: Uint8Array, bits?: number): Promise<PrivateKey> { // eslint-disable-line require-await
51
51
  if (type.toLowerCase() !== 'ed25519') {
52
- throw errcode(new Error('Seed key derivation is unimplemented for RSA or secp256k1'), 'ERR_UNSUPPORTED_KEY_DERIVATION_TYPE')
52
+ throw new CodeError('Seed key derivation is unimplemented for RSA or secp256k1', 'ERR_UNSUPPORTED_KEY_DERIVATION_TYPE')
53
53
  }
54
54
 
55
55
  return await Ed25519.generateKeyPairFromSeed(seed)
@@ -121,7 +121,7 @@ export async function importKey (encryptedKey: string, password: string): Promis
121
121
  // Only rsa supports pem right now
122
122
  const key = forge.pki.decryptRsaPrivateKey(encryptedKey, password)
123
123
  if (key === null) {
124
- throw errcode(new Error('Cannot read the key, most likely the password is wrong or not a RSA key'), 'ERR_CANNOT_DECRYPT_PEM')
124
+ throw new CodeError('Cannot read the key, most likely the password is wrong or not a RSA key', 'ERR_CANNOT_DECRYPT_PEM')
125
125
  }
126
126
  let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
127
127
  der = uint8ArrayFromString(der.getBytes(), 'ascii')
@@ -18,3 +18,18 @@ export interface ECDHKey {
18
18
  key: Uint8Array
19
19
  genSharedKey: (theirPub: Uint8Array, forcePrivate?: ECDHKeyPair) => Promise<Uint8Array>
20
20
  }
21
+
22
+ export interface JWKEncodedPublicKey { kty: string, crv: 'P-256' | 'P-384' | 'P-521', x: string, y: string, ext: boolean }
23
+
24
+ export interface JWKEncodedPrivateKey extends JWKEncodedPublicKey { d: string}
25
+
26
+ export interface EnhancedKey {
27
+ iv: Uint8Array
28
+ cipherKey: Uint8Array
29
+ macKey: Uint8Array
30
+ }
31
+
32
+ export interface EnhancedKeyPair {
33
+ k1: EnhancedKey
34
+ k2: EnhancedKey
35
+ }
@@ -3,14 +3,19 @@ import 'node-forge/lib/rsa.js'
3
3
  import forge from 'node-forge/lib/forge.js'
4
4
  import { base64urlToBigInteger } from '../util.js'
5
5
 
6
- function convert (key: any, types: string[]) {
6
+ export interface JWK {
7
+ encrypt: (msg: string) => string
8
+ decrypt: (msg: string) => string
9
+ }
10
+
11
+ function convert (key: any, types: string[]): Array<typeof forge.jsbn.BigInteger> {
7
12
  return types.map(t => base64urlToBigInteger(key[t]))
8
13
  }
9
14
 
10
- export function jwk2priv (key: JsonWebKey) {
15
+ export function jwk2priv (key: JsonWebKey): JWK {
11
16
  return forge.pki.setRsaPrivateKey(...convert(key, ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi']))
12
17
  }
13
18
 
14
- export function jwk2pub (key: JsonWebKey) {
19
+ export function jwk2pub (key: JsonWebKey): JWK {
15
20
  return forge.pki.setRsaPublicKey(...convert(key, ['n', 'e']))
16
21
  }