@libp2p/crypto 3.0.4-856ccd708 → 3.0.4-ddaa59a60

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 (80) hide show
  1. package/dist/index.min.js +14 -72
  2. package/dist/src/aes/cipher-mode.d.ts +2 -0
  3. package/dist/src/aes/cipher-mode.d.ts.map +1 -0
  4. package/dist/src/aes/cipher-mode.js +13 -0
  5. package/dist/src/aes/cipher-mode.js.map +1 -0
  6. package/dist/src/aes/ciphers-browser.d.ts +7 -0
  7. package/dist/src/aes/ciphers-browser.d.ts.map +1 -0
  8. package/dist/src/aes/ciphers-browser.js +26 -0
  9. package/dist/src/aes/ciphers-browser.js.map +1 -0
  10. package/dist/src/aes/ciphers.d.ts +5 -0
  11. package/dist/src/aes/ciphers.d.ts.map +1 -0
  12. package/dist/src/aes/ciphers.js +4 -0
  13. package/dist/src/aes/ciphers.js.map +1 -0
  14. package/dist/src/aes/index.d.ts +50 -0
  15. package/dist/src/aes/index.d.ts.map +1 -0
  16. package/dist/src/aes/index.js +61 -0
  17. package/dist/src/aes/index.js.map +1 -0
  18. package/dist/src/index.d.ts +2 -0
  19. package/dist/src/index.d.ts.map +1 -1
  20. package/dist/src/index.js +2 -0
  21. package/dist/src/index.js.map +1 -1
  22. package/dist/src/keys/ed25519-browser.d.ts +1 -1
  23. package/dist/src/keys/ed25519-browser.d.ts.map +1 -1
  24. package/dist/src/keys/index.d.ts +2 -4
  25. package/dist/src/keys/index.d.ts.map +1 -1
  26. package/dist/src/keys/index.js +12 -7
  27. package/dist/src/keys/index.js.map +1 -1
  28. package/dist/src/keys/jwk2pem.d.ts +8 -0
  29. package/dist/src/keys/jwk2pem.d.ts.map +1 -0
  30. package/dist/src/keys/jwk2pem.js +14 -0
  31. package/dist/src/keys/jwk2pem.js.map +1 -0
  32. package/dist/src/keys/rsa-browser.d.ts +2 -0
  33. package/dist/src/keys/rsa-browser.d.ts.map +1 -1
  34. package/dist/src/keys/rsa-browser.js +25 -0
  35. package/dist/src/keys/rsa-browser.js.map +1 -1
  36. package/dist/src/keys/rsa-class.d.ts +5 -6
  37. package/dist/src/keys/rsa-class.d.ts.map +1 -1
  38. package/dist/src/keys/rsa-class.js +25 -11
  39. package/dist/src/keys/rsa-class.js.map +1 -1
  40. package/dist/src/keys/rsa-utils.d.ts +2 -15
  41. package/dist/src/keys/rsa-utils.d.ts.map +1 -1
  42. package/dist/src/keys/rsa-utils.js +39 -304
  43. package/dist/src/keys/rsa-utils.js.map +1 -1
  44. package/dist/src/keys/rsa.d.ts +2 -0
  45. package/dist/src/keys/rsa.d.ts.map +1 -1
  46. package/dist/src/keys/rsa.js +22 -2
  47. package/dist/src/keys/rsa.js.map +1 -1
  48. package/dist/src/pbkdf2.d.ts +1 -1
  49. package/dist/src/pbkdf2.d.ts.map +1 -1
  50. package/dist/src/pbkdf2.js +10 -14
  51. package/dist/src/pbkdf2.js.map +1 -1
  52. package/dist/src/util.d.ts +7 -0
  53. package/dist/src/util.d.ts.map +1 -1
  54. package/dist/src/util.js +25 -0
  55. package/dist/src/util.js.map +1 -1
  56. package/dist/src/webcrypto.d.ts +1 -3
  57. package/dist/src/webcrypto.d.ts.map +1 -1
  58. package/dist/src/webcrypto.js +11 -4
  59. package/dist/src/webcrypto.js.map +1 -1
  60. package/package.json +15 -8
  61. package/src/aes/cipher-mode.ts +15 -0
  62. package/src/aes/ciphers-browser.ts +31 -0
  63. package/src/aes/ciphers.ts +4 -0
  64. package/src/aes/index.ts +70 -0
  65. package/src/index.ts +2 -0
  66. package/src/keys/ed25519-browser.ts +1 -1
  67. package/src/keys/index.ts +12 -10
  68. package/src/keys/jwk2pem.ts +21 -0
  69. package/src/keys/rsa-browser.ts +29 -0
  70. package/src/keys/rsa-class.ts +28 -11
  71. package/src/keys/rsa-utils.ts +39 -373
  72. package/src/keys/rsa.ts +23 -2
  73. package/src/pbkdf2.ts +15 -17
  74. package/src/util.ts +29 -0
  75. package/src/webcrypto.ts +18 -5
  76. package/dist/src/webcrypto-browser.d.ts +0 -5
  77. package/dist/src/webcrypto-browser.d.ts.map +0 -1
  78. package/dist/src/webcrypto-browser.js +0 -17
  79. package/dist/src/webcrypto-browser.js.map +0 -1
  80. package/src/webcrypto-browser.ts +0 -24
package/dist/src/util.js CHANGED
@@ -1,5 +1,30 @@
1
+ import 'node-forge/lib/util.js';
2
+ import 'node-forge/lib/jsbn.js';
3
+ // @ts-expect-error types are missing
4
+ import forge from 'node-forge/lib/forge.js';
1
5
  import { concat as uint8ArrayConcat } from 'uint8arrays/concat';
2
6
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
7
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
8
+ export function bigIntegerToUintBase64url(num, len) {
9
+ // Call `.abs()` to convert to unsigned
10
+ let buf = Uint8Array.from(num.abs().toByteArray()); // toByteArray converts to big endian
11
+ // toByteArray() gives us back a signed array, which will include a leading 0
12
+ // byte if the most significant bit of the number is 1:
13
+ // https://docs.microsoft.com/en-us/windows/win32/seccertenroll/about-integer
14
+ // Our number will always be positive so we should remove the leading padding.
15
+ buf = buf[0] === 0 ? buf.subarray(1) : buf;
16
+ if (len != null) {
17
+ if (buf.length > len)
18
+ throw new Error('byte array longer than desired length');
19
+ buf = uint8ArrayConcat([new Uint8Array(len - buf.length), buf]);
20
+ }
21
+ return uint8ArrayToString(buf, 'base64url');
22
+ }
23
+ // Convert a base64url encoded string to a BigInteger
24
+ export function base64urlToBigInteger(str) {
25
+ const buf = base64urlToBuffer(str);
26
+ return new forge.jsbn.BigInteger(uint8ArrayToString(buf, 'base16'), 16);
27
+ }
3
28
  export function base64urlToBuffer(str, len) {
4
29
  let buf = uint8ArrayFromString(str, 'base64urlpad');
5
30
  if (len != null) {
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAE5E,MAAM,UAAU,iBAAiB,CAAE,GAAW,EAAE,GAAY;IAC1D,IAAI,GAAG,GAAG,oBAAoB,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;IAEnD,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;QAC9E,GAAG,GAAG,gBAAgB,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IACjE,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,SAAS,CAAgB,KAAU;IACjD,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU;QACrC,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU;QACjC,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,CAAA;AACvC,CAAC"}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,wBAAwB,CAAA;AAC/B,OAAO,wBAAwB,CAAA;AAC/B,qCAAqC;AACrC,OAAO,KAAK,MAAM,yBAAyB,CAAA;AAC3C,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAEtE,MAAM,UAAU,yBAAyB,CAAE,GAAmB,EAAE,GAAY;IAC1E,uCAAuC;IACvC,IAAI,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,CAAA,CAAC,qCAAqC;IAExF,6EAA6E;IAC7E,uDAAuD;IACvD,6EAA6E;IAC7E,8EAA8E;IAC9E,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;IAE1C,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;QAC9E,GAAG,GAAG,gBAAgB,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IACjE,CAAC;IAED,OAAO,kBAAkB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;AAC7C,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,qBAAqB,CAAE,GAAW;IAChD,MAAM,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;IAClC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;AACzE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAE,GAAW,EAAE,GAAY;IAC1D,IAAI,GAAG,GAAG,oBAAoB,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;IAEnD,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;QAC9E,GAAG,GAAG,gBAAgB,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IACjE,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,SAAS,CAAgB,KAAU;IACjD,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU;QACrC,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU;QACjC,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,CAAA;AACvC,CAAC"}
@@ -1,7 +1,5 @@
1
- /// <reference types="node" />
2
- import { webcrypto } from 'crypto';
3
1
  declare const _default: {
4
- get(win?: typeof globalThis): webcrypto.Crypto;
2
+ get(win?: typeof globalThis): Crypto;
5
3
  };
6
4
  export default _default;
7
5
  //# sourceMappingURL=webcrypto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webcrypto.d.ts","sourceRoot":"","sources":["../../src/webcrypto.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;;;;AAIlC,wBAIC"}
1
+ {"version":3,"file":"webcrypto.d.ts","sourceRoot":"","sources":["../../src/webcrypto.ts"],"names":[],"mappings":";;;AAIA,wBAmBC"}
@@ -1,10 +1,17 @@
1
1
  /* eslint-env browser */
2
- import { webcrypto } from 'crypto';
3
- // globalThis `SubtleCrypto` shipped in node.js 19.x, Electron currently uses
4
- // v18.x so this override file is necessary until Electron updates
2
+ // Check native crypto exists and is enabled (In insecure context `self.crypto`
3
+ // exists but `self.crypto.subtle` does not).
5
4
  export default {
6
5
  get(win = globalThis) {
7
- return webcrypto;
6
+ const nativeCrypto = win.crypto;
7
+ if (nativeCrypto == null || nativeCrypto.subtle == null) {
8
+ throw Object.assign(new Error('Missing Web Crypto API. ' +
9
+ 'The most likely cause of this error is that this page is being accessed ' +
10
+ 'from an insecure context (i.e. not HTTPS). For more information and ' +
11
+ 'possible resolutions see ' +
12
+ 'https://github.com/libp2p/js-libp2p/blob/main/packages/crypto/README.md#web-crypto-api'), { code: 'ERR_MISSING_WEB_CRYPTO' });
13
+ }
14
+ return nativeCrypto;
8
15
  }
9
16
  };
10
17
  //# sourceMappingURL=webcrypto.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"webcrypto.js","sourceRoot":"","sources":["../../src/webcrypto.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,6EAA6E;AAC7E,kEAAkE;AAClE,eAAe;IACb,GAAG,CAAE,GAAG,GAAG,UAAU;QACnB,OAAO,SAAS,CAAA;IAClB,CAAC;CACF,CAAA"}
1
+ {"version":3,"file":"webcrypto.js","sourceRoot":"","sources":["../../src/webcrypto.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,+EAA+E;AAC/E,6CAA6C;AAC7C,eAAe;IACb,GAAG,CAAE,GAAG,GAAG,UAAU;QACnB,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAA;QAE/B,IAAI,YAAY,IAAI,IAAI,IAAI,YAAY,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YACxD,MAAM,MAAM,CAAC,MAAM,CACjB,IAAI,KAAK,CACP,0BAA0B;gBAC1B,0EAA0E;gBAC1E,sEAAsE;gBACtE,2BAA2B;gBAC3B,wFAAwF,CACzF,EACD,EAAE,IAAI,EAAE,wBAAwB,EAAE,CACnC,CAAA;QACH,CAAC;QAED,OAAO,YAAY,CAAA;IACrB,CAAC;CACF,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@libp2p/crypto",
3
- "version": "3.0.4-856ccd708",
3
+ "version": "3.0.4-ddaa59a60",
4
4
  "description": "Crypto primitives for libp2p",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/crypto#readme",
@@ -51,6 +51,10 @@
51
51
  "types": "./src/index.d.ts",
52
52
  "import": "./dist/src/index.js"
53
53
  },
54
+ "./aes": {
55
+ "types": "./dist/src/aes/index.d.ts",
56
+ "import": "./dist/src/aes/index.js"
57
+ },
54
58
  "./hmac": {
55
59
  "types": "./dist/src/hmac/index.d.ts",
56
60
  "import": "./dist/src/hmac/index.js"
@@ -65,7 +69,10 @@
65
69
  "parserOptions": {
66
70
  "project": true,
67
71
  "sourceType": "module"
68
- }
72
+ },
73
+ "ignorePatterns": [
74
+ "src/*.d.ts"
75
+ ]
69
76
  },
70
77
  "scripts": {
71
78
  "clean": "aegir clean",
@@ -83,13 +90,13 @@
83
90
  "generate": "protons ./src/keys/keys.proto"
84
91
  },
85
92
  "dependencies": {
86
- "@libp2p/interface": "1.1.1-856ccd708",
93
+ "@libp2p/interface": "1.1.1-ddaa59a60",
87
94
  "@noble/curves": "^1.1.0",
88
- "@noble/hashes": "^1.3.3",
89
- "asn1js": "^3.0.5",
95
+ "@noble/hashes": "^1.3.1",
90
96
  "multiformats": "^13.0.0",
97
+ "node-forge": "^1.1.0",
91
98
  "protons-runtime": "^5.0.0",
92
- "uint8arraylist": "^2.4.7",
99
+ "uint8arraylist": "^2.4.3",
93
100
  "uint8arrays": "^5.0.0"
94
101
  },
95
102
  "devDependencies": {
@@ -99,12 +106,12 @@
99
106
  "protons": "^7.3.0"
100
107
  },
101
108
  "browser": {
109
+ "./dist/src/aes/ciphers.js": "./dist/src/aes/ciphers-browser.js",
102
110
  "./dist/src/ciphers/aes-gcm.js": "./dist/src/ciphers/aes-gcm.browser.js",
103
111
  "./dist/src/hmac/index.js": "./dist/src/hmac/index-browser.js",
104
112
  "./dist/src/keys/ecdh.js": "./dist/src/keys/ecdh-browser.js",
105
113
  "./dist/src/keys/ed25519.js": "./dist/src/keys/ed25519-browser.js",
106
114
  "./dist/src/keys/rsa.js": "./dist/src/keys/rsa-browser.js",
107
- "./dist/src/keys/secp256k1.js": "./dist/src/keys/secp256k1-browser.js",
108
- "./dist/src/webcrypto.js": "./dist/src/webcrypto-browser.js"
115
+ "./dist/src/keys/secp256k1.js": "./dist/src/keys/secp256k1-browser.js"
109
116
  }
110
117
  }
@@ -0,0 +1,15 @@
1
+ import { CodeError } from '@libp2p/interface'
2
+
3
+ const CIPHER_MODES = {
4
+ 16: 'aes-128-ctr',
5
+ 32: 'aes-256-ctr'
6
+ }
7
+
8
+ export function cipherMode (key: Uint8Array): string {
9
+ if (key.length === 16 || key.length === 32) {
10
+ return CIPHER_MODES[key.length]
11
+ }
12
+
13
+ const modes = Object.entries(CIPHER_MODES).map(([k, v]) => `${k} (${v})`).join(' / ')
14
+ throw new CodeError(`Invalid key length ${key.length} bytes. Must be ${modes}`, 'ERR_INVALID_KEY_LENGTH')
15
+ }
@@ -0,0 +1,31 @@
1
+ import 'node-forge/lib/aes.js'
2
+ // @ts-expect-error types are missing
3
+ import forge from 'node-forge/lib/forge.js'
4
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
5
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
6
+
7
+ export interface Cipher {
8
+ update(data: Uint8Array): Uint8Array
9
+ }
10
+
11
+ export function createCipheriv (mode: any, key: Uint8Array, iv: Uint8Array): Cipher {
12
+ const cipher2 = forge.cipher.createCipher('AES-CTR', uint8ArrayToString(key, 'ascii'))
13
+ cipher2.start({ iv: uint8ArrayToString(iv, 'ascii') })
14
+ return {
15
+ update: (data: Uint8Array) => {
16
+ cipher2.update(forge.util.createBuffer(uint8ArrayToString(data, 'ascii')))
17
+ return uint8ArrayFromString(cipher2.output.getBytes(), 'ascii')
18
+ }
19
+ }
20
+ }
21
+
22
+ export function createDecipheriv (mode: any, key: Uint8Array, iv: Uint8Array): Cipher {
23
+ const cipher2 = forge.cipher.createDecipher('AES-CTR', uint8ArrayToString(key, 'ascii'))
24
+ cipher2.start({ iv: uint8ArrayToString(iv, 'ascii') })
25
+ return {
26
+ update: (data: Uint8Array) => {
27
+ cipher2.update(forge.util.createBuffer(uint8ArrayToString(data, 'ascii')))
28
+ return uint8ArrayFromString(cipher2.output.getBytes(), 'ascii')
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,4 @@
1
+ import crypto from 'crypto'
2
+
3
+ export const createCipheriv = crypto.createCipheriv
4
+ export const createDecipheriv = crypto.createDecipheriv
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Exposes an interface to AES encryption (formerly Rijndael), as defined in U.S. Federal Information Processing Standards Publication 197.
5
+ *
6
+ * This uses `CTR` mode.
7
+ *
8
+ * /**
9
+ * @example
10
+ *
11
+ * ```js
12
+ * import { create } from '@libp2p/crypto/aes'
13
+ *
14
+ * // Setting up Key and IV
15
+ *
16
+ * // A 16 bytes array, 128 Bits, AES-128 is chosen
17
+ * const key128 = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
18
+ *
19
+ * // A 16 bytes array, 128 Bits,
20
+ * const IV = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
21
+ *
22
+ * const decryptedMessage = 'Hello, world!'
23
+ *
24
+ * // Encrypting
25
+ * const cipher = await crypto.aes.create(key128, IV)
26
+ * const encryptedBuffer = await encrypt(Uint8Array.from(decryptedMessage))
27
+ * console.log(encryptedBuffer)
28
+ * // prints: <Uint8Array 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
29
+ *
30
+ * // Decrypting
31
+ * const decipher = await crypto.aes.create(key128, IV)
32
+ * const decryptedBuffer = await decrypt(encryptedBuffer)
33
+ *
34
+ * console.log(decryptedBuffer)
35
+ * // prints: <Uint8Array 42 f1 67 d9 2e 42 d0 32 9e b1 f8 3c>
36
+ *
37
+ * console.log(decryptedBuffer.toString('utf-8'))
38
+ * // prints: Hello, world!
39
+ * ```
40
+ */
41
+
42
+ import { cipherMode } from './cipher-mode.js'
43
+ import * as ciphers from './ciphers.js'
44
+
45
+ export interface AESCipher {
46
+ encrypt(data: Uint8Array): Promise<Uint8Array>
47
+ decrypt(data: Uint8Array): Promise<Uint8Array>
48
+ }
49
+
50
+ /**
51
+ * @param key - The key, if length `16` then `AES 128` is used. For length `32`, `AES 256` is used
52
+ * @param iv - Must have length `16`
53
+ */
54
+ export function create (key: Uint8Array, iv: Uint8Array): AESCipher {
55
+ const mode = cipherMode(key)
56
+ const cipher = ciphers.createCipheriv(mode, key, iv)
57
+ const decipher = ciphers.createDecipheriv(mode, key, iv)
58
+
59
+ const res: AESCipher = {
60
+ async encrypt (data) {
61
+ return cipher.update(data)
62
+ },
63
+
64
+ async decrypt (data) {
65
+ return decipher.update(data)
66
+ }
67
+ }
68
+
69
+ return res
70
+ }
package/src/index.ts CHANGED
@@ -8,11 +8,13 @@
8
8
  * To enable the Web Crypto API and allow `@libp2p/crypto` to work fully, please serve your page over HTTPS.
9
9
  */
10
10
 
11
+ import * as aes from './aes/index.js'
11
12
  import * as hmac from './hmac/index.js'
12
13
  import * as keys from './keys/index.js'
13
14
  import pbkdf2 from './pbkdf2.js'
14
15
  import randomBytes from './random-bytes.js'
15
16
 
17
+ export { aes }
16
18
  export { hmac }
17
19
  export { keys }
18
20
  export { randomBytes }
@@ -1,5 +1,5 @@
1
1
  import { ed25519 as ed } from '@noble/curves/ed25519'
2
- import type { Uint8ArrayKeyPair } from './interface.js'
2
+ import type { Uint8ArrayKeyPair } from './interface'
3
3
  import type { Uint8ArrayList } from 'uint8arraylist'
4
4
 
5
5
  const PUBLIC_KEY_BYTE_LENGTH = 32
package/src/keys/index.ts CHANGED
@@ -10,14 +10,18 @@
10
10
  * For encryption / decryption support, RSA keys should be used.
11
11
  */
12
12
 
13
+ import 'node-forge/lib/asn1.js'
14
+ import 'node-forge/lib/pbe.js'
13
15
  import { CodeError } from '@libp2p/interface'
16
+ // @ts-expect-error types are missing
17
+ import forge from 'node-forge/lib/forge.js'
18
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
14
19
  import * as Ed25519 from './ed25519-class.js'
15
20
  import generateEphemeralKeyPair from './ephemeral-keys.js'
16
21
  import { importer } from './importer.js'
17
22
  import { keyStretcher } from './key-stretcher.js'
18
23
  import * as keysPBM from './keys.js'
19
24
  import * as RSA from './rsa-class.js'
20
- import { importFromPem } from './rsa-utils.js'
21
25
  import * as Secp256k1 from './secp256k1-class.js'
22
26
  import type { PrivateKey, PublicKey } from '@libp2p/interface'
23
27
 
@@ -27,11 +31,6 @@ export { keysPBM }
27
31
 
28
32
  export type KeyTypes = 'RSA' | 'Ed25519' | 'secp256k1'
29
33
 
30
- export { RsaPrivateKey, RsaPublicKey, MAX_RSA_KEY_SIZE } from './rsa-class.js'
31
- export { Ed25519PrivateKey, Ed25519PublicKey } from './ed25519-class.js'
32
- export { Secp256k1PrivateKey, Secp256k1PublicKey } from './secp256k1-class.js'
33
- export type { JWKKeyPair } from './interface.js'
34
-
35
34
  export const supportedKeys = {
36
35
  rsa: RSA,
37
36
  ed25519: Ed25519,
@@ -145,9 +144,12 @@ export async function importKey (encryptedKey: string, password: string): Promis
145
144
  // Ignore and try the old pem decrypt
146
145
  }
147
146
 
148
- if (!encryptedKey.includes('BEGIN')) {
149
- throw new CodeError('Encrypted key was not a libp2p-key or a PEM file', 'ERR_INVALID_IMPORT_FORMAT')
147
+ // Only rsa supports pem right now
148
+ const key = forge.pki.decryptRsaPrivateKey(encryptedKey, password)
149
+ if (key === null) {
150
+ throw new CodeError('Cannot read the key, most likely the password is wrong or not a RSA key', 'ERR_CANNOT_DECRYPT_PEM')
150
151
  }
151
-
152
- return importFromPem(encryptedKey, password)
152
+ let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
153
+ der = uint8ArrayFromString(der.getBytes(), 'ascii')
154
+ return supportedKeys.rsa.unmarshalRsaPrivateKey(der)
153
155
  }
@@ -0,0 +1,21 @@
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.js'
5
+
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> {
12
+ return types.map(t => base64urlToBigInteger(key[t]))
13
+ }
14
+
15
+ export function jwk2priv (key: JsonWebKey): JWK {
16
+ return forge.pki.setRsaPrivateKey(...convert(key, ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi']))
17
+ }
18
+
19
+ export function jwk2pub (key: JsonWebKey): JWK {
20
+ return forge.pki.setRsaPublicKey(...convert(key, ['n', 'e']))
21
+ }
@@ -1,7 +1,9 @@
1
1
  import { CodeError } from '@libp2p/interface'
2
2
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
3
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
3
4
  import randomBytes from '../random-bytes.js'
4
5
  import webcrypto from '../webcrypto.js'
6
+ import { jwk2pub, jwk2priv } from './jwk2pem.js'
5
7
  import * as utils from './rsa-utils.js'
6
8
  import type { JWKKeyPair } from './interface.js'
7
9
  import type { Uint8ArrayList } from 'uint8arraylist'
@@ -128,6 +130,33 @@ async function derivePublicFromPrivate (jwKey: JsonWebKey): Promise<CryptoKey> {
128
130
  )
129
131
  }
130
132
 
133
+ /*
134
+
135
+ RSA encryption/decryption for the browser with webcrypto workaround
136
+ "bloody dark magic. webcrypto's why."
137
+
138
+ Explanation:
139
+ - Convert JWK to nodeForge
140
+ - Convert msg Uint8Array to nodeForge buffer: ByteBuffer is a "binary-string backed buffer", so let's make our Uint8Array a binary string
141
+ - Convert resulting nodeForge buffer to Uint8Array: it returns a binary string, turn that into a Uint8Array
142
+
143
+ */
144
+
145
+ function convertKey (key: JsonWebKey, pub: boolean, msg: Uint8Array | Uint8ArrayList, handle: (msg: string, key: { encrypt(msg: string): string, decrypt(msg: string): string }) => string): Uint8Array {
146
+ const fkey = pub ? jwk2pub(key) : jwk2priv(key)
147
+ const fmsg = uint8ArrayToString(msg instanceof Uint8Array ? msg : msg.subarray(), 'ascii')
148
+ const fomsg = handle(fmsg, fkey)
149
+ return uint8ArrayFromString(fomsg, 'ascii')
150
+ }
151
+
152
+ export function encrypt (key: JsonWebKey, msg: Uint8Array | Uint8ArrayList): Uint8Array {
153
+ return convertKey(key, true, msg, (msg, key) => key.encrypt(msg))
154
+ }
155
+
156
+ export function decrypt (key: JsonWebKey, msg: Uint8Array | Uint8ArrayList): Uint8Array {
157
+ return convertKey(key, false, msg, (msg, key) => key.decrypt(msg))
158
+ }
159
+
131
160
  export function keySize (jwk: JsonWebKey): number {
132
161
  if (jwk.kty !== 'RSA') {
133
162
  throw new CodeError('invalid key type', 'ERR_INVALID_KEY_TYPE')
@@ -1,6 +1,9 @@
1
1
  import { CodeError } from '@libp2p/interface'
2
2
  import { sha256 } from 'multiformats/hashes/sha2'
3
+ // @ts-expect-error types are missing
4
+ import forge from 'node-forge/lib/forge.js'
3
5
  import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
6
+ import 'node-forge/lib/sha512.js'
4
7
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
5
8
  import { isPromise } from '../util.js'
6
9
  import { exporter } from './exporter.js'
@@ -9,7 +12,7 @@ import * as crypto from './rsa.js'
9
12
  import type { Multibase } from 'multiformats'
10
13
  import type { Uint8ArrayList } from 'uint8arraylist'
11
14
 
12
- export const MAX_RSA_KEY_SIZE = 8192
15
+ export const MAX_KEY_SIZE = 8192
13
16
 
14
17
  export class RsaPublicKey {
15
18
  private readonly _key: JsonWebKey
@@ -33,6 +36,10 @@ export class RsaPublicKey {
33
36
  }).subarray()
34
37
  }
35
38
 
39
+ encrypt (bytes: Uint8Array | Uint8ArrayList): Uint8Array {
40
+ return crypto.encrypt(this._key, bytes)
41
+ }
42
+
36
43
  equals (key: any): boolean | boolean {
37
44
  return uint8ArrayEquals(this.bytes, key.bytes)
38
45
  }
@@ -73,6 +80,10 @@ export class RsaPrivateKey {
73
80
  return new RsaPublicKey(this._publicKey)
74
81
  }
75
82
 
83
+ decrypt (bytes: Uint8Array | Uint8ArrayList): Uint8Array {
84
+ return crypto.decrypt(this._key, bytes)
85
+ }
86
+
76
87
  marshal (): Uint8Array {
77
88
  return crypto.utils.jwkToPkcs1(this._key)
78
89
  }
@@ -111,15 +122,21 @@ export class RsaPrivateKey {
111
122
  }
112
123
 
113
124
  /**
114
- * Exports the key as libp2p-key - a aes-gcm encrypted value with the key
115
- * derived from the password.
116
- *
117
- * To export it as a password protected PEM file, please use the `exportPEM`
118
- * function from `@libp2p/rsa`.
125
+ * Exports the key into a password protected PEM format
119
126
  */
120
127
  async export (password: string, format = 'pkcs-8'): Promise<Multibase<'m'>> {
121
128
  if (format === 'pkcs-8') {
122
- return crypto.utils.exportToPem(this, password)
129
+ const buffer = new forge.util.ByteBuffer(this.marshal())
130
+ const asn1 = forge.asn1.fromDer(buffer)
131
+ const privateKey = forge.pki.privateKeyFromAsn1(asn1)
132
+
133
+ const options = {
134
+ algorithm: 'aes256',
135
+ count: 10000,
136
+ saltSize: 128 / 8,
137
+ prfAlgorithm: 'sha512'
138
+ }
139
+ return forge.pki.encryptRsaPrivateKey(privateKey, password, options)
123
140
  } else if (format === 'libp2p-key') {
124
141
  return exporter(this.bytes, password)
125
142
  } else {
@@ -131,7 +148,7 @@ export class RsaPrivateKey {
131
148
  export async function unmarshalRsaPrivateKey (bytes: Uint8Array): Promise<RsaPrivateKey> {
132
149
  const jwk = crypto.utils.pkcs1ToJwk(bytes)
133
150
 
134
- if (crypto.keySize(jwk) > MAX_RSA_KEY_SIZE) {
151
+ if (crypto.keySize(jwk) > MAX_KEY_SIZE) {
135
152
  throw new CodeError('key size is too large', 'ERR_KEY_SIZE_TOO_LARGE')
136
153
  }
137
154
 
@@ -143,7 +160,7 @@ export async function unmarshalRsaPrivateKey (bytes: Uint8Array): Promise<RsaPri
143
160
  export function unmarshalRsaPublicKey (bytes: Uint8Array): RsaPublicKey {
144
161
  const jwk = crypto.utils.pkixToJwk(bytes)
145
162
 
146
- if (crypto.keySize(jwk) > MAX_RSA_KEY_SIZE) {
163
+ if (crypto.keySize(jwk) > MAX_KEY_SIZE) {
147
164
  throw new CodeError('key size is too large', 'ERR_KEY_SIZE_TOO_LARGE')
148
165
  }
149
166
 
@@ -151,7 +168,7 @@ export function unmarshalRsaPublicKey (bytes: Uint8Array): RsaPublicKey {
151
168
  }
152
169
 
153
170
  export async function fromJwk (jwk: JsonWebKey): Promise<RsaPrivateKey> {
154
- if (crypto.keySize(jwk) > MAX_RSA_KEY_SIZE) {
171
+ if (crypto.keySize(jwk) > MAX_KEY_SIZE) {
155
172
  throw new CodeError('key size is too large', 'ERR_KEY_SIZE_TOO_LARGE')
156
173
  }
157
174
 
@@ -161,7 +178,7 @@ export async function fromJwk (jwk: JsonWebKey): Promise<RsaPrivateKey> {
161
178
  }
162
179
 
163
180
  export async function generateKeyPair (bits: number): Promise<RsaPrivateKey> {
164
- if (bits > MAX_RSA_KEY_SIZE) {
181
+ if (bits > MAX_KEY_SIZE) {
165
182
  throw new CodeError('key size is too large', 'ERR_KEY_SIZE_TOO_LARGE')
166
183
  }
167
184