@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.
- package/dist/index.min.js +14 -72
- package/dist/src/aes/cipher-mode.d.ts +2 -0
- package/dist/src/aes/cipher-mode.d.ts.map +1 -0
- package/dist/src/aes/cipher-mode.js +13 -0
- package/dist/src/aes/cipher-mode.js.map +1 -0
- package/dist/src/aes/ciphers-browser.d.ts +7 -0
- package/dist/src/aes/ciphers-browser.d.ts.map +1 -0
- package/dist/src/aes/ciphers-browser.js +26 -0
- package/dist/src/aes/ciphers-browser.js.map +1 -0
- package/dist/src/aes/ciphers.d.ts +5 -0
- package/dist/src/aes/ciphers.d.ts.map +1 -0
- package/dist/src/aes/ciphers.js +4 -0
- package/dist/src/aes/ciphers.js.map +1 -0
- package/dist/src/aes/index.d.ts +50 -0
- package/dist/src/aes/index.d.ts.map +1 -0
- package/dist/src/aes/index.js +61 -0
- package/dist/src/aes/index.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/keys/ed25519-browser.d.ts +1 -1
- package/dist/src/keys/ed25519-browser.d.ts.map +1 -1
- package/dist/src/keys/index.d.ts +2 -4
- package/dist/src/keys/index.d.ts.map +1 -1
- package/dist/src/keys/index.js +12 -7
- package/dist/src/keys/index.js.map +1 -1
- package/dist/src/keys/jwk2pem.d.ts +8 -0
- package/dist/src/keys/jwk2pem.d.ts.map +1 -0
- package/dist/src/keys/jwk2pem.js +14 -0
- package/dist/src/keys/jwk2pem.js.map +1 -0
- package/dist/src/keys/rsa-browser.d.ts +2 -0
- package/dist/src/keys/rsa-browser.d.ts.map +1 -1
- package/dist/src/keys/rsa-browser.js +25 -0
- package/dist/src/keys/rsa-browser.js.map +1 -1
- package/dist/src/keys/rsa-class.d.ts +5 -6
- package/dist/src/keys/rsa-class.d.ts.map +1 -1
- package/dist/src/keys/rsa-class.js +25 -11
- package/dist/src/keys/rsa-class.js.map +1 -1
- package/dist/src/keys/rsa-utils.d.ts +2 -15
- package/dist/src/keys/rsa-utils.d.ts.map +1 -1
- package/dist/src/keys/rsa-utils.js +39 -304
- package/dist/src/keys/rsa-utils.js.map +1 -1
- package/dist/src/keys/rsa.d.ts +2 -0
- package/dist/src/keys/rsa.d.ts.map +1 -1
- package/dist/src/keys/rsa.js +22 -2
- package/dist/src/keys/rsa.js.map +1 -1
- package/dist/src/pbkdf2.d.ts +1 -1
- package/dist/src/pbkdf2.d.ts.map +1 -1
- package/dist/src/pbkdf2.js +10 -14
- package/dist/src/pbkdf2.js.map +1 -1
- package/dist/src/util.d.ts +7 -0
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +25 -0
- package/dist/src/util.js.map +1 -1
- package/dist/src/webcrypto.d.ts +1 -3
- package/dist/src/webcrypto.d.ts.map +1 -1
- package/dist/src/webcrypto.js +11 -4
- package/dist/src/webcrypto.js.map +1 -1
- package/package.json +15 -8
- package/src/aes/cipher-mode.ts +15 -0
- package/src/aes/ciphers-browser.ts +31 -0
- package/src/aes/ciphers.ts +4 -0
- package/src/aes/index.ts +70 -0
- package/src/index.ts +2 -0
- package/src/keys/ed25519-browser.ts +1 -1
- package/src/keys/index.ts +12 -10
- package/src/keys/jwk2pem.ts +21 -0
- package/src/keys/rsa-browser.ts +29 -0
- package/src/keys/rsa-class.ts +28 -11
- package/src/keys/rsa-utils.ts +39 -373
- package/src/keys/rsa.ts +23 -2
- package/src/pbkdf2.ts +15 -17
- package/src/util.ts +29 -0
- package/src/webcrypto.ts +18 -5
- package/dist/src/webcrypto-browser.d.ts +0 -5
- package/dist/src/webcrypto-browser.d.ts.map +0 -1
- package/dist/src/webcrypto-browser.js +0 -17
- package/dist/src/webcrypto-browser.js.map +0 -1
- 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) {
|
package/dist/src/util.js.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/src/webcrypto.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webcrypto.d.ts","sourceRoot":"","sources":["../../src/webcrypto.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webcrypto.d.ts","sourceRoot":"","sources":["../../src/webcrypto.ts"],"names":[],"mappings":";;;AAIA,wBAmBC"}
|
package/dist/src/webcrypto.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
/* eslint-env browser */
|
|
2
|
-
|
|
3
|
-
//
|
|
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
|
-
|
|
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,
|
|
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-
|
|
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-
|
|
93
|
+
"@libp2p/interface": "1.1.1-ddaa59a60",
|
|
87
94
|
"@noble/curves": "^1.1.0",
|
|
88
|
-
"@noble/hashes": "^1.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.
|
|
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
|
+
}
|
package/src/aes/index.ts
ADDED
|
@@ -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 }
|
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
|
-
|
|
149
|
-
|
|
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
|
-
|
|
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
|
+
}
|
package/src/keys/rsa-browser.ts
CHANGED
|
@@ -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')
|
package/src/keys/rsa-class.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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) >
|
|
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) >
|
|
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) >
|
|
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 >
|
|
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
|
|