@metamask-previews/profile-sync-controller 3.0.0-preview-3280bd3 → 3.0.0-preview-9c296dcb
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/controllers/authentication/AuthenticationController.cjs +1 -0
- package/dist/controllers/authentication/AuthenticationController.cjs.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.d.cts.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.d.mts.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.mjs +1 -0
- package/dist/controllers/authentication/AuthenticationController.mjs.map +1 -1
- package/dist/controllers/user-storage/UserStorageController.cjs.map +1 -1
- package/dist/controllers/user-storage/UserStorageController.d.cts +1 -1
- package/dist/controllers/user-storage/UserStorageController.d.cts.map +1 -1
- package/dist/controllers/user-storage/UserStorageController.d.mts +1 -1
- package/dist/controllers/user-storage/UserStorageController.d.mts.map +1 -1
- package/dist/controllers/user-storage/UserStorageController.mjs +1 -2
- package/dist/controllers/user-storage/UserStorageController.mjs.map +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockAccounts.cjs.map +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockAccounts.d.cts.map +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockAccounts.d.mts.map +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockAccounts.mjs +1 -2
- package/dist/controllers/user-storage/__fixtures__/mockAccounts.mjs.map +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockMessenger.d.cts +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockMessenger.d.mts +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockResponses.cjs +6 -7
- package/dist/controllers/user-storage/__fixtures__/mockResponses.cjs.map +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockResponses.d.cts.map +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockResponses.d.mts.map +1 -1
- package/dist/controllers/user-storage/__fixtures__/mockResponses.mjs +6 -7
- package/dist/controllers/user-storage/__fixtures__/mockResponses.mjs.map +1 -1
- package/dist/controllers/user-storage/accounts/user-storage.cjs.map +1 -1
- package/dist/controllers/user-storage/accounts/user-storage.d.cts +1 -1
- package/dist/controllers/user-storage/accounts/user-storage.d.cts.map +1 -1
- package/dist/controllers/user-storage/accounts/user-storage.d.mts +1 -1
- package/dist/controllers/user-storage/accounts/user-storage.d.mts.map +1 -1
- package/dist/controllers/user-storage/accounts/user-storage.mjs.map +1 -1
- package/dist/controllers/user-storage/services.cjs +1 -47
- package/dist/controllers/user-storage/services.cjs.map +1 -1
- package/dist/controllers/user-storage/services.d.cts +0 -8
- package/dist/controllers/user-storage/services.d.cts.map +1 -1
- package/dist/controllers/user-storage/services.d.mts +0 -8
- package/dist/controllers/user-storage/services.d.mts.map +1 -1
- package/dist/controllers/user-storage/services.mjs +0 -45
- package/dist/controllers/user-storage/services.mjs.map +1 -1
- package/dist/sdk/__fixtures__/mock-userstorage.cjs +6 -29
- package/dist/sdk/__fixtures__/mock-userstorage.cjs.map +1 -1
- package/dist/sdk/__fixtures__/mock-userstorage.d.cts +6 -4
- package/dist/sdk/__fixtures__/mock-userstorage.d.cts.map +1 -1
- package/dist/sdk/__fixtures__/mock-userstorage.d.mts +6 -4
- package/dist/sdk/__fixtures__/mock-userstorage.d.mts.map +1 -1
- package/dist/sdk/__fixtures__/mock-userstorage.mjs +6 -6
- package/dist/sdk/__fixtures__/mock-userstorage.mjs.map +1 -1
- package/dist/sdk/user-storage.cjs +9 -62
- package/dist/sdk/user-storage.cjs.map +1 -1
- package/dist/sdk/user-storage.d.cts +1 -5
- package/dist/sdk/user-storage.d.cts.map +1 -1
- package/dist/sdk/user-storage.d.mts +1 -5
- package/dist/sdk/user-storage.d.mts.map +1 -1
- package/dist/sdk/user-storage.mjs +9 -62
- package/dist/sdk/user-storage.mjs.map +1 -1
- package/dist/shared/encryption/cache.cjs +14 -12
- package/dist/shared/encryption/cache.cjs.map +1 -1
- package/dist/shared/encryption/cache.d.cts +3 -4
- package/dist/shared/encryption/cache.d.cts.map +1 -1
- package/dist/shared/encryption/cache.d.mts +3 -4
- package/dist/shared/encryption/cache.d.mts.map +1 -1
- package/dist/shared/encryption/cache.mjs +13 -11
- package/dist/shared/encryption/cache.mjs.map +1 -1
- package/dist/shared/encryption/encryption.cjs +25 -49
- package/dist/shared/encryption/encryption.cjs.map +1 -1
- package/dist/shared/encryption/encryption.d.cts +0 -2
- package/dist/shared/encryption/encryption.d.cts.map +1 -1
- package/dist/shared/encryption/encryption.d.mts +0 -2
- package/dist/shared/encryption/encryption.d.mts.map +1 -1
- package/dist/shared/encryption/encryption.mjs +14 -38
- package/dist/shared/encryption/encryption.mjs.map +1 -1
- package/package.json +2 -1
- package/dist/shared/encryption/constants.cjs +0 -18
- package/dist/shared/encryption/constants.cjs.map +0 -1
- package/dist/shared/encryption/constants.d.cts +0 -8
- package/dist/shared/encryption/constants.d.cts.map +0 -1
- package/dist/shared/encryption/constants.d.mts +0 -8
- package/dist/shared/encryption/constants.d.mts.map +0 -1
- package/dist/shared/encryption/constants.mjs +0 -15
- package/dist/shared/encryption/constants.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.cjs","sourceRoot":"","sources":["../../../src/shared/encryption/cache.ts"],"names":[],"mappings":";;;AAAA
|
|
1
|
+
{"version":3,"file":"cache.cjs","sourceRoot":"","sources":["../../../src/shared/encryption/cache.ts"],"names":[],"mappings":";;;AAAA,uCAA+D;AAQ/D,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,eAAe,GAAG,GAAG,CAAC;AAQ5B,IAAI,cAAc,GAAyB,EAAE,CAAC;AAC9C,MAAM,gBAAgB,GAAG,CAAC,cAAsB,EAAE,EAAE;IAClD,cAAc,CAAC,cAAc,MAA7B,cAAc,CAAC,cAAc,IAAM,IAAI,GAAG,EAAE,EAAC;IAC7C,OAAO,cAAc,CAAC,cAAc,CAAC,CAAC;AACxC,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAChC,cAAsB,EACtB,IAAgB;IAEhB,MAAM,KAAK,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,IAAA,yBAAiB,EAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,CAAC,SAAS,EAAE;QACd,OAAO,SAAS,CAAC;KAClB;IAED,OAAO;QACL,IAAI;QACJ,UAAU;QACV,GAAG,EAAE,SAAS;KACf,CAAC;AACJ,CAAC;AAhBD,gDAgBC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAC7B,cAAsB;IAEtB,MAAM,KAAK,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAE/C,kDAAkD;IAClD,MAAM,WAAW,GAAqC,KAAK;SACxD,OAAO,EAAE;SACT,IAAI,EAAE,CAAC,KAAK,CAAC;IAEhB,IAAI,CAAC,WAAW,EAAE;QAChB,OAAO,SAAS,CAAC;KAClB;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,IAAA,yBAAiB,EAAC,UAAU,CAAC,CAAC;IAChD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,UAAU;QACV,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;KACpB,CAAC;AACJ,CAAC;AArBD,0CAqBC;AAED;;;;;;;GAOG;AACH,SAAgB,YAAY,CAC1B,cAAsB,EACtB,IAAgB,EAChB,GAAe;IAEf,sBAAsB;IACtB,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,GAAG,mBAAmB,EAAE;QAC5D,cAAc,GAAG,EAAE,CAAC;KACrB;IAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,IAAA,yBAAiB,EAAC,IAAI,CAAC,CAAC;IAE3C,kBAAkB;IAClB,IAAI,KAAK,CAAC,IAAI,GAAG,eAAe,EAAE;QAChC,KAAK,CAAC,KAAK,EAAE,CAAC;KACf;IAED,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AAC7B,CAAC;AAnBD,oCAmBC","sourcesContent":["import { base64ToByteArray, byteArrayToBase64 } from './utils';\n\ntype CachedEntry = {\n salt: Uint8Array;\n base64Salt: string;\n key: Uint8Array;\n};\n\nconst MAX_PASSWORD_CACHES = 100;\nconst MAX_SALT_CACHES = 100;\n\n/**\n * In-Memory Caching derived keys based from a given salt and password.\n */\ntype PasswordMemCachedKDF = {\n [hashedPassword: string]: Map<string, Uint8Array>;\n};\nlet inMemCachedKDF: PasswordMemCachedKDF = {};\nconst getPasswordCache = (hashedPassword: string) => {\n inMemCachedKDF[hashedPassword] ??= new Map();\n return inMemCachedKDF[hashedPassword];\n};\n\n/**\n * Returns a given cached derived key from a hashed password and salt\n *\n * @param hashedPassword - hashed password for cache lookup\n * @param salt - provide salt to receive cached key\n * @returns cached key\n */\nexport function getCachedKeyBySalt(\n hashedPassword: string,\n salt: Uint8Array,\n): CachedEntry | undefined {\n const cache = getPasswordCache(hashedPassword);\n const base64Salt = byteArrayToBase64(salt);\n const cachedKey = cache.get(base64Salt);\n if (!cachedKey) {\n return undefined;\n }\n\n return {\n salt,\n base64Salt,\n key: cachedKey,\n };\n}\n\n/**\n * Gets any cached key for a given hashed password\n *\n * @param hashedPassword - hashed password for cache lookup\n * @returns any (the first) cached key\n */\nexport function getAnyCachedKey(\n hashedPassword: string,\n): CachedEntry | undefined {\n const cache = getPasswordCache(hashedPassword);\n\n // Takes 1 item from an Iterator via Map.entries()\n const cachedEntry: [string, Uint8Array] | undefined = cache\n .entries()\n .next().value;\n\n if (!cachedEntry) {\n return undefined;\n }\n\n const base64Salt = cachedEntry[0];\n const bytesSalt = base64ToByteArray(base64Salt);\n return {\n salt: bytesSalt,\n base64Salt,\n key: cachedEntry[1],\n };\n}\n\n/**\n * Sets a key to the in memory cache.\n * We have set an arbitrary size of 10 cached keys per hashed password.\n *\n * @param hashedPassword - hashed password for cache lookup\n * @param salt - salt to set new derived key\n * @param key - derived key we are setting\n */\nexport function setCachedKey(\n hashedPassword: string,\n salt: Uint8Array,\n key: Uint8Array,\n): void {\n // Max password caches\n if (Object.keys(inMemCachedKDF).length > MAX_PASSWORD_CACHES) {\n inMemCachedKDF = {};\n }\n\n const cache = getPasswordCache(hashedPassword);\n const base64Salt = byteArrayToBase64(salt);\n\n // Max salt caches\n if (cache.size > MAX_SALT_CACHES) {\n cache.clear();\n }\n\n cache.set(base64Salt, key);\n}\n"]}
|
|
@@ -12,13 +12,12 @@ type CachedEntry = {
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function getCachedKeyBySalt(hashedPassword: string, salt: Uint8Array): CachedEntry | undefined;
|
|
14
14
|
/**
|
|
15
|
-
* Gets
|
|
16
|
-
* This is unique per hashed password.
|
|
15
|
+
* Gets any cached key for a given hashed password
|
|
17
16
|
*
|
|
18
17
|
* @param hashedPassword - hashed password for cache lookup
|
|
19
|
-
* @returns the cached key
|
|
18
|
+
* @returns any (the first) cached key
|
|
20
19
|
*/
|
|
21
|
-
export declare function
|
|
20
|
+
export declare function getAnyCachedKey(hashedPassword: string): CachedEntry | undefined;
|
|
22
21
|
/**
|
|
23
22
|
* Sets a key to the in memory cache.
|
|
24
23
|
* We have set an arbitrary size of 10 cached keys per hashed password.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.cts","sourceRoot":"","sources":["../../../src/shared/encryption/cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cache.d.cts","sourceRoot":"","sources":["../../../src/shared/encryption/cache.ts"],"names":[],"mappings":"AAEA,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,UAAU,CAAC;CACjB,CAAC;AAiBF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,UAAU,GACf,WAAW,GAAG,SAAS,CAazB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,MAAM,GACrB,WAAW,GAAG,SAAS,CAmBzB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,UAAU,GACd,IAAI,CAeN"}
|
|
@@ -12,13 +12,12 @@ type CachedEntry = {
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function getCachedKeyBySalt(hashedPassword: string, salt: Uint8Array): CachedEntry | undefined;
|
|
14
14
|
/**
|
|
15
|
-
* Gets
|
|
16
|
-
* This is unique per hashed password.
|
|
15
|
+
* Gets any cached key for a given hashed password
|
|
17
16
|
*
|
|
18
17
|
* @param hashedPassword - hashed password for cache lookup
|
|
19
|
-
* @returns the cached key
|
|
18
|
+
* @returns any (the first) cached key
|
|
20
19
|
*/
|
|
21
|
-
export declare function
|
|
20
|
+
export declare function getAnyCachedKey(hashedPassword: string): CachedEntry | undefined;
|
|
22
21
|
/**
|
|
23
22
|
* Sets a key to the in memory cache.
|
|
24
23
|
* We have set an arbitrary size of 10 cached keys per hashed password.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.mts","sourceRoot":"","sources":["../../../src/shared/encryption/cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cache.d.mts","sourceRoot":"","sources":["../../../src/shared/encryption/cache.ts"],"names":[],"mappings":"AAEA,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,UAAU,CAAC;CACjB,CAAC;AAiBF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,UAAU,GACf,WAAW,GAAG,SAAS,CAazB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,MAAM,GACrB,WAAW,GAAG,SAAS,CAmBzB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,UAAU,GACd,IAAI,CAeN"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { byteArrayToBase64 } from "./utils.mjs";
|
|
1
|
+
import { base64ToByteArray, byteArrayToBase64 } from "./utils.mjs";
|
|
3
2
|
const MAX_PASSWORD_CACHES = 100;
|
|
4
3
|
const MAX_SALT_CACHES = 100;
|
|
5
4
|
let inMemCachedKDF = {};
|
|
@@ -28,23 +27,26 @@ export function getCachedKeyBySalt(hashedPassword, salt) {
|
|
|
28
27
|
};
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
|
-
* Gets
|
|
32
|
-
* This is unique per hashed password.
|
|
30
|
+
* Gets any cached key for a given hashed password
|
|
33
31
|
*
|
|
34
32
|
* @param hashedPassword - hashed password for cache lookup
|
|
35
|
-
* @returns the cached key
|
|
33
|
+
* @returns any (the first) cached key
|
|
36
34
|
*/
|
|
37
|
-
export function
|
|
35
|
+
export function getAnyCachedKey(hashedPassword) {
|
|
38
36
|
const cache = getPasswordCache(hashedPassword);
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
37
|
+
// Takes 1 item from an Iterator via Map.entries()
|
|
38
|
+
const cachedEntry = cache
|
|
39
|
+
.entries()
|
|
40
|
+
.next().value;
|
|
41
|
+
if (!cachedEntry) {
|
|
42
42
|
return undefined;
|
|
43
43
|
}
|
|
44
|
+
const base64Salt = cachedEntry[0];
|
|
45
|
+
const bytesSalt = base64ToByteArray(base64Salt);
|
|
44
46
|
return {
|
|
45
|
-
salt:
|
|
47
|
+
salt: bytesSalt,
|
|
46
48
|
base64Salt,
|
|
47
|
-
key:
|
|
49
|
+
key: cachedEntry[1],
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.mjs","sourceRoot":"","sources":["../../../src/shared/encryption/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cache.mjs","sourceRoot":"","sources":["../../../src/shared/encryption/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAgB;AAQ/D,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,eAAe,GAAG,GAAG,CAAC;AAQ5B,IAAI,cAAc,GAAyB,EAAE,CAAC;AAC9C,MAAM,gBAAgB,GAAG,CAAC,cAAsB,EAAE,EAAE;IAClD,cAAc,CAAC,cAAc,MAA7B,cAAc,CAAC,cAAc,IAAM,IAAI,GAAG,EAAE,EAAC;IAC7C,OAAO,cAAc,CAAC,cAAc,CAAC,CAAC;AACxC,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,cAAsB,EACtB,IAAgB;IAEhB,MAAM,KAAK,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,CAAC,SAAS,EAAE;QACd,OAAO,SAAS,CAAC;KAClB;IAED,OAAO;QACL,IAAI;QACJ,UAAU;QACV,GAAG,EAAE,SAAS;KACf,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,cAAsB;IAEtB,MAAM,KAAK,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAE/C,kDAAkD;IAClD,MAAM,WAAW,GAAqC,KAAK;SACxD,OAAO,EAAE;SACT,IAAI,EAAE,CAAC,KAAK,CAAC;IAEhB,IAAI,CAAC,WAAW,EAAE;QAChB,OAAO,SAAS,CAAC;KAClB;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAChD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,UAAU;QACV,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;KACpB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,cAAsB,EACtB,IAAgB,EAChB,GAAe;IAEf,sBAAsB;IACtB,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,GAAG,mBAAmB,EAAE;QAC5D,cAAc,GAAG,EAAE,CAAC;KACrB;IAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAE3C,kBAAkB;IAClB,IAAI,KAAK,CAAC,IAAI,GAAG,eAAe,EAAE;QAChC,KAAK,CAAC,KAAK,EAAE,CAAC;KACf;IAED,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AAC7B,CAAC","sourcesContent":["import { base64ToByteArray, byteArrayToBase64 } from './utils';\n\ntype CachedEntry = {\n salt: Uint8Array;\n base64Salt: string;\n key: Uint8Array;\n};\n\nconst MAX_PASSWORD_CACHES = 100;\nconst MAX_SALT_CACHES = 100;\n\n/**\n * In-Memory Caching derived keys based from a given salt and password.\n */\ntype PasswordMemCachedKDF = {\n [hashedPassword: string]: Map<string, Uint8Array>;\n};\nlet inMemCachedKDF: PasswordMemCachedKDF = {};\nconst getPasswordCache = (hashedPassword: string) => {\n inMemCachedKDF[hashedPassword] ??= new Map();\n return inMemCachedKDF[hashedPassword];\n};\n\n/**\n * Returns a given cached derived key from a hashed password and salt\n *\n * @param hashedPassword - hashed password for cache lookup\n * @param salt - provide salt to receive cached key\n * @returns cached key\n */\nexport function getCachedKeyBySalt(\n hashedPassword: string,\n salt: Uint8Array,\n): CachedEntry | undefined {\n const cache = getPasswordCache(hashedPassword);\n const base64Salt = byteArrayToBase64(salt);\n const cachedKey = cache.get(base64Salt);\n if (!cachedKey) {\n return undefined;\n }\n\n return {\n salt,\n base64Salt,\n key: cachedKey,\n };\n}\n\n/**\n * Gets any cached key for a given hashed password\n *\n * @param hashedPassword - hashed password for cache lookup\n * @returns any (the first) cached key\n */\nexport function getAnyCachedKey(\n hashedPassword: string,\n): CachedEntry | undefined {\n const cache = getPasswordCache(hashedPassword);\n\n // Takes 1 item from an Iterator via Map.entries()\n const cachedEntry: [string, Uint8Array] | undefined = cache\n .entries()\n .next().value;\n\n if (!cachedEntry) {\n return undefined;\n }\n\n const base64Salt = cachedEntry[0];\n const bytesSalt = base64ToByteArray(base64Salt);\n return {\n salt: bytesSalt,\n base64Salt,\n key: cachedEntry[1],\n };\n}\n\n/**\n * Sets a key to the in memory cache.\n * We have set an arbitrary size of 10 cached keys per hashed password.\n *\n * @param hashedPassword - hashed password for cache lookup\n * @param salt - salt to set new derived key\n * @param key - derived key we are setting\n */\nexport function setCachedKey(\n hashedPassword: string,\n salt: Uint8Array,\n key: Uint8Array,\n): void {\n // Max password caches\n if (Object.keys(inMemCachedKDF).length > MAX_PASSWORD_CACHES) {\n inMemCachedKDF = {};\n }\n\n const cache = getPasswordCache(hashedPassword);\n const base64Salt = byteArrayToBase64(salt);\n\n // Max salt caches\n if (cache.size > MAX_SALT_CACHES) {\n cache.clear();\n }\n\n cache.set(base64Salt, key);\n}\n"]}
|
|
@@ -13,8 +13,18 @@ const scrypt_1 = require("@noble/hashes/scrypt");
|
|
|
13
13
|
const sha256_1 = require("@noble/hashes/sha256");
|
|
14
14
|
const utils_1 = require("@noble/hashes/utils");
|
|
15
15
|
const cache_1 = require("./cache.cjs");
|
|
16
|
-
const constants_1 = require("./constants.cjs");
|
|
17
16
|
const utils_2 = require("./utils.cjs");
|
|
17
|
+
// Nonce/Key Sizes
|
|
18
|
+
const ALGORITHM_NONCE_SIZE = 12; // 12 bytes
|
|
19
|
+
const ALGORITHM_KEY_SIZE = 16; // 16 bytes
|
|
20
|
+
// Scrypt settings
|
|
21
|
+
// see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt
|
|
22
|
+
const SCRYPT_SALT_SIZE = 16; // 16 bytes
|
|
23
|
+
const SCRYPT_N = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1)
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
25
|
+
const SCRYPT_r = 8; // Block size parameter
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
27
|
+
const SCRYPT_p = 1; // Parallelization parameter
|
|
18
28
|
class EncryptorDecryptor {
|
|
19
29
|
constructor() {
|
|
20
30
|
_EncryptorDecryptor_instances.add(this);
|
|
@@ -43,47 +53,13 @@ class EncryptorDecryptor {
|
|
|
43
53
|
throw new Error(`Unable to decrypt string - ${errorMessage}`);
|
|
44
54
|
}
|
|
45
55
|
}
|
|
46
|
-
getSalt(encryptedDataStr) {
|
|
47
|
-
try {
|
|
48
|
-
const encryptedData = JSON.parse(encryptedDataStr);
|
|
49
|
-
if (encryptedData.v === '1') {
|
|
50
|
-
if (encryptedData.t === 'scrypt') {
|
|
51
|
-
const { d: base64CiphertextAndNonceAndSalt, saltLen } = encryptedData;
|
|
52
|
-
// Decode the base64.
|
|
53
|
-
const ciphertextAndNonceAndSalt = (0, utils_2.base64ToByteArray)(base64CiphertextAndNonceAndSalt);
|
|
54
|
-
// Create buffers of salt and ciphertextAndNonce.
|
|
55
|
-
const salt = ciphertextAndNonceAndSalt.slice(0, saltLen);
|
|
56
|
-
return salt;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
throw new Error(`Unsupported encrypted data payload - ${encryptedDataStr}`);
|
|
60
|
-
}
|
|
61
|
-
catch (e) {
|
|
62
|
-
const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);
|
|
63
|
-
throw new Error(`Unable to get salt - ${errorMessage}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
getIfEntriesHaveDifferentSalts(entries) {
|
|
67
|
-
const salts = entries
|
|
68
|
-
.map((e) => {
|
|
69
|
-
try {
|
|
70
|
-
return this.getSalt(e);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
.filter((s) => s !== undefined);
|
|
77
|
-
const strSet = new Set(salts.map((arr) => arr.toString()));
|
|
78
|
-
return strSet.size === salts.length;
|
|
79
|
-
}
|
|
80
56
|
}
|
|
81
57
|
_EncryptorDecryptor_instances = new WeakSet(), _EncryptorDecryptor_encryptStringV1 = async function _EncryptorDecryptor_encryptStringV1(plaintext, password, nativeScryptCrypto) {
|
|
82
58
|
const { key, salt } = await __classPrivateFieldGet(this, _EncryptorDecryptor_instances, "m", _EncryptorDecryptor_getOrGenerateScryptKey).call(this, password, {
|
|
83
|
-
N:
|
|
84
|
-
r:
|
|
85
|
-
p:
|
|
86
|
-
dkLen:
|
|
59
|
+
N: SCRYPT_N,
|
|
60
|
+
r: SCRYPT_r,
|
|
61
|
+
p: SCRYPT_p,
|
|
62
|
+
dkLen: ALGORITHM_KEY_SIZE,
|
|
87
63
|
}, undefined, nativeScryptCrypto);
|
|
88
64
|
// Encrypt and prepend salt.
|
|
89
65
|
const plaintextRaw = (0, utils_1.utf8ToBytes)(plaintext);
|
|
@@ -95,12 +71,12 @@ _EncryptorDecryptor_instances = new WeakSet(), _EncryptorDecryptor_encryptString
|
|
|
95
71
|
t: 'scrypt',
|
|
96
72
|
d: encryptedData,
|
|
97
73
|
o: {
|
|
98
|
-
N:
|
|
99
|
-
r:
|
|
100
|
-
p:
|
|
101
|
-
dkLen:
|
|
74
|
+
N: SCRYPT_N,
|
|
75
|
+
r: SCRYPT_r,
|
|
76
|
+
p: SCRYPT_p,
|
|
77
|
+
dkLen: ALGORITHM_KEY_SIZE,
|
|
102
78
|
},
|
|
103
|
-
saltLen:
|
|
79
|
+
saltLen: SCRYPT_SALT_SIZE,
|
|
104
80
|
};
|
|
105
81
|
return JSON.stringify(encryptedPayload);
|
|
106
82
|
}, _EncryptorDecryptor_decryptStringV1 = async function _EncryptorDecryptor_decryptStringV1(data, password, nativeScryptCrypto) {
|
|
@@ -120,28 +96,28 @@ _EncryptorDecryptor_instances = new WeakSet(), _EncryptorDecryptor_encryptString
|
|
|
120
96
|
// Decrypt and return result.
|
|
121
97
|
return (0, utils_2.bytesToUtf8)(__classPrivateFieldGet(this, _EncryptorDecryptor_instances, "m", _EncryptorDecryptor_decrypt).call(this, ciphertextAndNonce, key));
|
|
122
98
|
}, _EncryptorDecryptor_encrypt = function _EncryptorDecryptor_encrypt(plaintext, key) {
|
|
123
|
-
const nonce = (0, webcrypto_1.randomBytes)(
|
|
99
|
+
const nonce = (0, webcrypto_1.randomBytes)(ALGORITHM_NONCE_SIZE);
|
|
124
100
|
// Encrypt and prepend nonce.
|
|
125
101
|
const ciphertext = (0, aes_1.gcm)(key, nonce).encrypt(plaintext);
|
|
126
102
|
return (0, utils_1.concatBytes)(nonce, ciphertext);
|
|
127
103
|
}, _EncryptorDecryptor_decrypt = function _EncryptorDecryptor_decrypt(ciphertextAndNonce, key) {
|
|
128
104
|
// Create buffers of nonce and ciphertext.
|
|
129
|
-
const nonce = ciphertextAndNonce.slice(0,
|
|
130
|
-
const ciphertext = ciphertextAndNonce.slice(
|
|
105
|
+
const nonce = ciphertextAndNonce.slice(0, ALGORITHM_NONCE_SIZE);
|
|
106
|
+
const ciphertext = ciphertextAndNonce.slice(ALGORITHM_NONCE_SIZE, ciphertextAndNonce.length);
|
|
131
107
|
// Decrypt and return result.
|
|
132
108
|
return (0, aes_1.gcm)(key, nonce).decrypt(ciphertext);
|
|
133
109
|
}, _EncryptorDecryptor_getOrGenerateScryptKey = async function _EncryptorDecryptor_getOrGenerateScryptKey(password, o, salt, nativeScryptCrypto) {
|
|
134
110
|
const hashedPassword = createSHA256Hash(password);
|
|
135
111
|
const cachedKey = salt
|
|
136
112
|
? (0, cache_1.getCachedKeyBySalt)(hashedPassword, salt)
|
|
137
|
-
: (0, cache_1.
|
|
113
|
+
: (0, cache_1.getAnyCachedKey)(hashedPassword);
|
|
138
114
|
if (cachedKey) {
|
|
139
115
|
return {
|
|
140
116
|
key: cachedKey.key,
|
|
141
117
|
salt: cachedKey.salt,
|
|
142
118
|
};
|
|
143
119
|
}
|
|
144
|
-
const newSalt = salt ??
|
|
120
|
+
const newSalt = salt ?? (0, webcrypto_1.randomBytes)(SCRYPT_SALT_SIZE);
|
|
145
121
|
let newKey;
|
|
146
122
|
if (nativeScryptCrypto) {
|
|
147
123
|
newKey = await nativeScryptCrypto((0, utils_2.stringToByteArray)(password), newSalt, o.N, o.r, o.p, o.dkLen);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.cjs","sourceRoot":"","sources":["../../../src/shared/encryption/encryption.ts"],"names":[],"mappings":"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","sourcesContent":["import { gcm } from '@noble/ciphers/aes';\nimport { randomBytes } from '@noble/ciphers/webcrypto';\nimport { scryptAsync } from '@noble/hashes/scrypt';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { utf8ToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils';\n\nimport type { NativeScrypt } from '../types/encryption';\nimport {\n getCachedKeyBySalt,\n getCachedKeyGeneratedWithSharedSalt,\n setCachedKey,\n} from './cache';\nimport {\n ALGORITHM_KEY_SIZE,\n ALGORITHM_NONCE_SIZE,\n SCRYPT_N,\n SCRYPT_p,\n SCRYPT_r,\n SCRYPT_SALT_SIZE,\n SHARED_SALT,\n} from './constants';\nimport {\n base64ToByteArray,\n byteArrayToBase64,\n bytesToUtf8,\n stringToByteArray,\n} from './utils';\n\nexport type EncryptedPayload = {\n // version\n v: '1';\n\n // key derivation function algorithm - scrypt\n t: 'scrypt';\n\n // data\n d: string;\n\n // encryption options - scrypt\n o: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n N: number;\n r: number;\n p: number;\n dkLen: number;\n };\n\n // Salt options\n saltLen: number;\n};\n\nclass EncryptorDecryptor {\n async encryptString(\n plaintext: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n try {\n return await this.#encryptStringV1(\n plaintext,\n password,\n nativeScryptCrypto,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to encrypt string - ${errorMessage}`);\n }\n }\n\n async decryptString(\n encryptedDataStr: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n try {\n const encryptedData: EncryptedPayload = JSON.parse(encryptedDataStr);\n if (encryptedData.v === '1') {\n if (encryptedData.t === 'scrypt') {\n return await this.#decryptStringV1(\n encryptedData,\n password,\n nativeScryptCrypto,\n );\n }\n }\n throw new Error(\n `Unsupported encrypted data payload - ${encryptedDataStr}`,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to decrypt string - ${errorMessage}`);\n }\n }\n\n async #encryptStringV1(\n plaintext: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n const { key, salt } = await this.#getOrGenerateScryptKey(\n password,\n {\n N: SCRYPT_N,\n r: SCRYPT_r,\n p: SCRYPT_p,\n dkLen: ALGORITHM_KEY_SIZE,\n },\n undefined,\n nativeScryptCrypto,\n );\n\n // Encrypt and prepend salt.\n const plaintextRaw = utf8ToBytes(plaintext);\n const ciphertextAndNonceAndSalt = concatBytes(\n salt,\n this.#encrypt(plaintextRaw, key),\n );\n\n // Convert to Base64\n const encryptedData = byteArrayToBase64(ciphertextAndNonceAndSalt);\n\n const encryptedPayload: EncryptedPayload = {\n v: '1',\n t: 'scrypt',\n d: encryptedData,\n o: {\n N: SCRYPT_N,\n r: SCRYPT_r,\n p: SCRYPT_p,\n dkLen: ALGORITHM_KEY_SIZE,\n },\n saltLen: SCRYPT_SALT_SIZE,\n };\n\n return JSON.stringify(encryptedPayload);\n }\n\n async #decryptStringV1(\n data: EncryptedPayload,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n const { o, d: base64CiphertextAndNonceAndSalt, saltLen } = data;\n\n // Decode the base64.\n const ciphertextAndNonceAndSalt = base64ToByteArray(\n base64CiphertextAndNonceAndSalt,\n );\n\n // Create buffers of salt and ciphertextAndNonce.\n const salt = ciphertextAndNonceAndSalt.slice(0, saltLen);\n const ciphertextAndNonce = ciphertextAndNonceAndSalt.slice(\n saltLen,\n ciphertextAndNonceAndSalt.length,\n );\n\n // Derive the key.\n const { key } = await this.#getOrGenerateScryptKey(\n password,\n {\n N: o.N,\n r: o.r,\n p: o.p,\n dkLen: o.dkLen,\n },\n salt,\n nativeScryptCrypto,\n );\n\n // Decrypt and return result.\n return bytesToUtf8(this.#decrypt(ciphertextAndNonce, key));\n }\n\n getSalt(encryptedDataStr: string) {\n try {\n const encryptedData: EncryptedPayload = JSON.parse(encryptedDataStr);\n if (encryptedData.v === '1') {\n if (encryptedData.t === 'scrypt') {\n const { d: base64CiphertextAndNonceAndSalt, saltLen } = encryptedData;\n\n // Decode the base64.\n const ciphertextAndNonceAndSalt = base64ToByteArray(\n base64CiphertextAndNonceAndSalt,\n );\n\n // Create buffers of salt and ciphertextAndNonce.\n const salt = ciphertextAndNonceAndSalt.slice(0, saltLen);\n return salt;\n }\n }\n throw new Error(\n `Unsupported encrypted data payload - ${encryptedDataStr}`,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to get salt - ${errorMessage}`);\n }\n }\n\n getIfEntriesHaveDifferentSalts(entries: string[]): boolean {\n const salts = entries\n .map((e) => {\n try {\n return this.getSalt(e);\n } catch {\n return undefined;\n }\n })\n .filter((s): s is Uint8Array => s !== undefined);\n\n const strSet = new Set(salts.map((arr) => arr.toString()));\n return strSet.size === salts.length;\n }\n\n #encrypt(plaintext: Uint8Array, key: Uint8Array): Uint8Array {\n const nonce = randomBytes(ALGORITHM_NONCE_SIZE);\n\n // Encrypt and prepend nonce.\n const ciphertext = gcm(key, nonce).encrypt(plaintext);\n\n return concatBytes(nonce, ciphertext);\n }\n\n #decrypt(ciphertextAndNonce: Uint8Array, key: Uint8Array): Uint8Array {\n // Create buffers of nonce and ciphertext.\n const nonce = ciphertextAndNonce.slice(0, ALGORITHM_NONCE_SIZE);\n const ciphertext = ciphertextAndNonce.slice(\n ALGORITHM_NONCE_SIZE,\n ciphertextAndNonce.length,\n );\n\n // Decrypt and return result.\n return gcm(key, nonce).decrypt(ciphertext);\n }\n\n async #getOrGenerateScryptKey(\n password: string,\n o: EncryptedPayload['o'],\n salt?: Uint8Array,\n nativeScryptCrypto?: NativeScrypt,\n ) {\n const hashedPassword = createSHA256Hash(password);\n const cachedKey = salt\n ? getCachedKeyBySalt(hashedPassword, salt)\n : getCachedKeyGeneratedWithSharedSalt(hashedPassword);\n\n if (cachedKey) {\n return {\n key: cachedKey.key,\n salt: cachedKey.salt,\n };\n }\n\n const newSalt = salt ?? SHARED_SALT;\n\n let newKey: Uint8Array;\n\n if (nativeScryptCrypto) {\n newKey = await nativeScryptCrypto(\n stringToByteArray(password),\n newSalt,\n o.N,\n o.r,\n o.p,\n o.dkLen,\n );\n } else {\n newKey = await scryptAsync(password, newSalt, {\n N: o.N,\n r: o.r,\n p: o.p,\n dkLen: o.dkLen,\n });\n }\n\n setCachedKey(hashedPassword, newSalt, newKey);\n\n return {\n key: newKey,\n salt: newSalt,\n };\n }\n}\n\nconst encryption = new EncryptorDecryptor();\nexport default encryption;\n\n/**\n * Receive a SHA256 hash from a given string\n * @param data - input\n * @returns sha256 hash\n */\nexport function createSHA256Hash(data: string): string {\n const hashedData = sha256(data);\n return bytesToHex(hashedData);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"encryption.cjs","sourceRoot":"","sources":["../../../src/shared/encryption/encryption.ts"],"names":[],"mappings":"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","sourcesContent":["import { gcm } from '@noble/ciphers/aes';\nimport { randomBytes } from '@noble/ciphers/webcrypto';\nimport { scryptAsync } from '@noble/hashes/scrypt';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { utf8ToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils';\n\nimport type { NativeScrypt } from '../types/encryption';\nimport { getAnyCachedKey, getCachedKeyBySalt, setCachedKey } from './cache';\nimport {\n base64ToByteArray,\n byteArrayToBase64,\n bytesToUtf8,\n stringToByteArray,\n} from './utils';\n\nexport type EncryptedPayload = {\n // version\n v: '1';\n\n // key derivation function algorithm - scrypt\n t: 'scrypt';\n\n // data\n d: string;\n\n // encryption options - scrypt\n o: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n N: number;\n r: number;\n p: number;\n dkLen: number;\n };\n\n // Salt options\n saltLen: number;\n};\n\n// Nonce/Key Sizes\nconst ALGORITHM_NONCE_SIZE = 12; // 12 bytes\nconst ALGORITHM_KEY_SIZE = 16; // 16 bytes\n\n// Scrypt settings\n// see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt\nconst SCRYPT_SALT_SIZE = 16; // 16 bytes\nconst SCRYPT_N = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1)\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst SCRYPT_r = 8; // Block size parameter\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst SCRYPT_p = 1; // Parallelization parameter\n\nclass EncryptorDecryptor {\n async encryptString(\n plaintext: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n try {\n return await this.#encryptStringV1(\n plaintext,\n password,\n nativeScryptCrypto,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to encrypt string - ${errorMessage}`);\n }\n }\n\n async decryptString(\n encryptedDataStr: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n try {\n const encryptedData: EncryptedPayload = JSON.parse(encryptedDataStr);\n if (encryptedData.v === '1') {\n if (encryptedData.t === 'scrypt') {\n return await this.#decryptStringV1(\n encryptedData,\n password,\n nativeScryptCrypto,\n );\n }\n }\n throw new Error(\n `Unsupported encrypted data payload - ${encryptedDataStr}`,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to decrypt string - ${errorMessage}`);\n }\n }\n\n async #encryptStringV1(\n plaintext: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n const { key, salt } = await this.#getOrGenerateScryptKey(\n password,\n {\n N: SCRYPT_N,\n r: SCRYPT_r,\n p: SCRYPT_p,\n dkLen: ALGORITHM_KEY_SIZE,\n },\n undefined,\n nativeScryptCrypto,\n );\n\n // Encrypt and prepend salt.\n const plaintextRaw = utf8ToBytes(plaintext);\n const ciphertextAndNonceAndSalt = concatBytes(\n salt,\n this.#encrypt(plaintextRaw, key),\n );\n\n // Convert to Base64\n const encryptedData = byteArrayToBase64(ciphertextAndNonceAndSalt);\n\n const encryptedPayload: EncryptedPayload = {\n v: '1',\n t: 'scrypt',\n d: encryptedData,\n o: {\n N: SCRYPT_N,\n r: SCRYPT_r,\n p: SCRYPT_p,\n dkLen: ALGORITHM_KEY_SIZE,\n },\n saltLen: SCRYPT_SALT_SIZE,\n };\n\n return JSON.stringify(encryptedPayload);\n }\n\n async #decryptStringV1(\n data: EncryptedPayload,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n const { o, d: base64CiphertextAndNonceAndSalt, saltLen } = data;\n\n // Decode the base64.\n const ciphertextAndNonceAndSalt = base64ToByteArray(\n base64CiphertextAndNonceAndSalt,\n );\n\n // Create buffers of salt and ciphertextAndNonce.\n const salt = ciphertextAndNonceAndSalt.slice(0, saltLen);\n const ciphertextAndNonce = ciphertextAndNonceAndSalt.slice(\n saltLen,\n ciphertextAndNonceAndSalt.length,\n );\n\n // Derive the key.\n const { key } = await this.#getOrGenerateScryptKey(\n password,\n {\n N: o.N,\n r: o.r,\n p: o.p,\n dkLen: o.dkLen,\n },\n salt,\n nativeScryptCrypto,\n );\n\n // Decrypt and return result.\n return bytesToUtf8(this.#decrypt(ciphertextAndNonce, key));\n }\n\n #encrypt(plaintext: Uint8Array, key: Uint8Array): Uint8Array {\n const nonce = randomBytes(ALGORITHM_NONCE_SIZE);\n\n // Encrypt and prepend nonce.\n const ciphertext = gcm(key, nonce).encrypt(plaintext);\n\n return concatBytes(nonce, ciphertext);\n }\n\n #decrypt(ciphertextAndNonce: Uint8Array, key: Uint8Array): Uint8Array {\n // Create buffers of nonce and ciphertext.\n const nonce = ciphertextAndNonce.slice(0, ALGORITHM_NONCE_SIZE);\n const ciphertext = ciphertextAndNonce.slice(\n ALGORITHM_NONCE_SIZE,\n ciphertextAndNonce.length,\n );\n\n // Decrypt and return result.\n return gcm(key, nonce).decrypt(ciphertext);\n }\n\n async #getOrGenerateScryptKey(\n password: string,\n o: EncryptedPayload['o'],\n salt?: Uint8Array,\n nativeScryptCrypto?: NativeScrypt,\n ) {\n const hashedPassword = createSHA256Hash(password);\n const cachedKey = salt\n ? getCachedKeyBySalt(hashedPassword, salt)\n : getAnyCachedKey(hashedPassword);\n\n if (cachedKey) {\n return {\n key: cachedKey.key,\n salt: cachedKey.salt,\n };\n }\n\n const newSalt = salt ?? randomBytes(SCRYPT_SALT_SIZE);\n\n let newKey: Uint8Array;\n\n if (nativeScryptCrypto) {\n newKey = await nativeScryptCrypto(\n stringToByteArray(password),\n newSalt,\n o.N,\n o.r,\n o.p,\n o.dkLen,\n );\n } else {\n newKey = await scryptAsync(password, newSalt, {\n N: o.N,\n r: o.r,\n p: o.p,\n dkLen: o.dkLen,\n });\n }\n setCachedKey(hashedPassword, newSalt, newKey);\n\n return {\n key: newKey,\n salt: newSalt,\n };\n }\n}\n\nconst encryption = new EncryptorDecryptor();\nexport default encryption;\n\n/**\n * Receive a SHA256 hash from a given string\n * @param data - input\n * @returns sha256 hash\n */\nexport function createSHA256Hash(data: string): string {\n const hashedData = sha256(data);\n return bytesToHex(hashedData);\n}\n"]}
|
|
@@ -15,8 +15,6 @@ declare class EncryptorDecryptor {
|
|
|
15
15
|
#private;
|
|
16
16
|
encryptString(plaintext: string, password: string, nativeScryptCrypto?: NativeScrypt): Promise<string>;
|
|
17
17
|
decryptString(encryptedDataStr: string, password: string, nativeScryptCrypto?: NativeScrypt): Promise<string>;
|
|
18
|
-
getSalt(encryptedDataStr: string): Uint8Array;
|
|
19
|
-
getIfEntriesHaveDifferentSalts(entries: string[]): boolean;
|
|
20
18
|
}
|
|
21
19
|
declare const encryption: EncryptorDecryptor;
|
|
22
20
|
export default encryption;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.d.cts","sourceRoot":"","sources":["../../../src/shared/encryption/encryption.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,gCAA4B;
|
|
1
|
+
{"version":3,"file":"encryption.d.cts","sourceRoot":"","sources":["../../../src/shared/encryption/encryption.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,gCAA4B;AASxD,MAAM,MAAM,gBAAgB,GAAG;IAE7B,CAAC,EAAE,GAAG,CAAC;IAGP,CAAC,EAAE,QAAQ,CAAC;IAGZ,CAAC,EAAE,MAAM,CAAC;IAGV,CAAC,EAAE;QAED,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAGF,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAeF,cAAM,kBAAkB;;IAChB,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,CAAC,EAAE,YAAY,GAChC,OAAO,CAAC,MAAM,CAAC;IAaZ,aAAa,CACjB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,CAAC,EAAE,YAAY,GAChC,OAAO,CAAC,MAAM,CAAC;CAuKnB;AAED,QAAA,MAAM,UAAU,oBAA2B,CAAC;AAC5C,eAAe,UAAU,CAAC;AAE1B;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD"}
|
|
@@ -15,8 +15,6 @@ declare class EncryptorDecryptor {
|
|
|
15
15
|
#private;
|
|
16
16
|
encryptString(plaintext: string, password: string, nativeScryptCrypto?: NativeScrypt): Promise<string>;
|
|
17
17
|
decryptString(encryptedDataStr: string, password: string, nativeScryptCrypto?: NativeScrypt): Promise<string>;
|
|
18
|
-
getSalt(encryptedDataStr: string): Uint8Array;
|
|
19
|
-
getIfEntriesHaveDifferentSalts(entries: string[]): boolean;
|
|
20
18
|
}
|
|
21
19
|
declare const encryption: EncryptorDecryptor;
|
|
22
20
|
export default encryption;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.d.mts","sourceRoot":"","sources":["../../../src/shared/encryption/encryption.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,gCAA4B;
|
|
1
|
+
{"version":3,"file":"encryption.d.mts","sourceRoot":"","sources":["../../../src/shared/encryption/encryption.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,gCAA4B;AASxD,MAAM,MAAM,gBAAgB,GAAG;IAE7B,CAAC,EAAE,GAAG,CAAC;IAGP,CAAC,EAAE,QAAQ,CAAC;IAGZ,CAAC,EAAE,MAAM,CAAC;IAGV,CAAC,EAAE;QAED,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAGF,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAeF,cAAM,kBAAkB;;IAChB,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,CAAC,EAAE,YAAY,GAChC,OAAO,CAAC,MAAM,CAAC;IAaZ,aAAa,CACjB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,CAAC,EAAE,YAAY,GAChC,OAAO,CAAC,MAAM,CAAC;CAuKnB;AAED,QAAA,MAAM,UAAU,oBAA2B,CAAC;AAC5C,eAAe,UAAU,CAAC;AAE1B;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD"}
|
|
@@ -9,9 +9,19 @@ import { randomBytes } from "@noble/ciphers/webcrypto";
|
|
|
9
9
|
import { scryptAsync } from "@noble/hashes/scrypt";
|
|
10
10
|
import { sha256 } from "@noble/hashes/sha256";
|
|
11
11
|
import { utf8ToBytes, concatBytes, bytesToHex } from "@noble/hashes/utils";
|
|
12
|
-
import {
|
|
13
|
-
import { ALGORITHM_KEY_SIZE, ALGORITHM_NONCE_SIZE, SCRYPT_N, SCRYPT_p, SCRYPT_r, SCRYPT_SALT_SIZE, SHARED_SALT } from "./constants.mjs";
|
|
12
|
+
import { getAnyCachedKey, getCachedKeyBySalt, setCachedKey } from "./cache.mjs";
|
|
14
13
|
import { base64ToByteArray, byteArrayToBase64, bytesToUtf8, stringToByteArray } from "./utils.mjs";
|
|
14
|
+
// Nonce/Key Sizes
|
|
15
|
+
const ALGORITHM_NONCE_SIZE = 12; // 12 bytes
|
|
16
|
+
const ALGORITHM_KEY_SIZE = 16; // 16 bytes
|
|
17
|
+
// Scrypt settings
|
|
18
|
+
// see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt
|
|
19
|
+
const SCRYPT_SALT_SIZE = 16; // 16 bytes
|
|
20
|
+
const SCRYPT_N = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1)
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
22
|
+
const SCRYPT_r = 8; // Block size parameter
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
24
|
+
const SCRYPT_p = 1; // Parallelization parameter
|
|
15
25
|
class EncryptorDecryptor {
|
|
16
26
|
constructor() {
|
|
17
27
|
_EncryptorDecryptor_instances.add(this);
|
|
@@ -40,40 +50,6 @@ class EncryptorDecryptor {
|
|
|
40
50
|
throw new Error(`Unable to decrypt string - ${errorMessage}`);
|
|
41
51
|
}
|
|
42
52
|
}
|
|
43
|
-
getSalt(encryptedDataStr) {
|
|
44
|
-
try {
|
|
45
|
-
const encryptedData = JSON.parse(encryptedDataStr);
|
|
46
|
-
if (encryptedData.v === '1') {
|
|
47
|
-
if (encryptedData.t === 'scrypt') {
|
|
48
|
-
const { d: base64CiphertextAndNonceAndSalt, saltLen } = encryptedData;
|
|
49
|
-
// Decode the base64.
|
|
50
|
-
const ciphertextAndNonceAndSalt = base64ToByteArray(base64CiphertextAndNonceAndSalt);
|
|
51
|
-
// Create buffers of salt and ciphertextAndNonce.
|
|
52
|
-
const salt = ciphertextAndNonceAndSalt.slice(0, saltLen);
|
|
53
|
-
return salt;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
throw new Error(`Unsupported encrypted data payload - ${encryptedDataStr}`);
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
59
|
-
const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);
|
|
60
|
-
throw new Error(`Unable to get salt - ${errorMessage}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
getIfEntriesHaveDifferentSalts(entries) {
|
|
64
|
-
const salts = entries
|
|
65
|
-
.map((e) => {
|
|
66
|
-
try {
|
|
67
|
-
return this.getSalt(e);
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
.filter((s) => s !== undefined);
|
|
74
|
-
const strSet = new Set(salts.map((arr) => arr.toString()));
|
|
75
|
-
return strSet.size === salts.length;
|
|
76
|
-
}
|
|
77
53
|
}
|
|
78
54
|
_EncryptorDecryptor_instances = new WeakSet(), _EncryptorDecryptor_encryptStringV1 = async function _EncryptorDecryptor_encryptStringV1(plaintext, password, nativeScryptCrypto) {
|
|
79
55
|
const { key, salt } = await __classPrivateFieldGet(this, _EncryptorDecryptor_instances, "m", _EncryptorDecryptor_getOrGenerateScryptKey).call(this, password, {
|
|
@@ -131,14 +107,14 @@ _EncryptorDecryptor_instances = new WeakSet(), _EncryptorDecryptor_encryptString
|
|
|
131
107
|
const hashedPassword = createSHA256Hash(password);
|
|
132
108
|
const cachedKey = salt
|
|
133
109
|
? getCachedKeyBySalt(hashedPassword, salt)
|
|
134
|
-
:
|
|
110
|
+
: getAnyCachedKey(hashedPassword);
|
|
135
111
|
if (cachedKey) {
|
|
136
112
|
return {
|
|
137
113
|
key: cachedKey.key,
|
|
138
114
|
salt: cachedKey.salt,
|
|
139
115
|
};
|
|
140
116
|
}
|
|
141
|
-
const newSalt = salt ??
|
|
117
|
+
const newSalt = salt ?? randomBytes(SCRYPT_SALT_SIZE);
|
|
142
118
|
let newKey;
|
|
143
119
|
if (nativeScryptCrypto) {
|
|
144
120
|
newKey = await nativeScryptCrypto(stringToByteArray(password), newSalt, o.N, o.r, o.p, o.dkLen);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.mjs","sourceRoot":"","sources":["../../../src/shared/encryption/encryption.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,GAAG,EAAE,2BAA2B;AACzC,OAAO,EAAE,WAAW,EAAE,iCAAiC;AACvD,OAAO,EAAE,WAAW,EAAE,6BAA6B;AACnD,OAAO,EAAE,MAAM,EAAE,6BAA6B;AAC9C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,4BAA4B;AAG3E,OAAO,EACL,kBAAkB,EAClB,mCAAmC,EACnC,YAAY,EACb,oBAAgB;AACjB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACZ,wBAAoB;AACrB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EAClB,oBAAgB;AAyBjB,MAAM,kBAAkB;IAAxB;;IAuOA,CAAC;IAtOC,KAAK,CAAC,aAAa,CACjB,SAAiB,EACjB,QAAgB,EAChB,kBAAiC;QAEjC,IAAI;YACF,OAAO,MAAM,uBAAA,IAAI,0EAAiB,MAArB,IAAI,EACf,SAAS,EACT,QAAQ,EACR,kBAAkB,CACnB,CAAC;SACH;QAAC,OAAO,CAAC,EAAE;YACV,MAAM,YAAY,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,8BAA8B,YAAY,EAAE,CAAC,CAAC;SAC/D;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,gBAAwB,EACxB,QAAgB,EAChB,kBAAiC;QAEjC,IAAI;YACF,MAAM,aAAa,GAAqB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACrE,IAAI,aAAa,CAAC,CAAC,KAAK,GAAG,EAAE;gBAC3B,IAAI,aAAa,CAAC,CAAC,KAAK,QAAQ,EAAE;oBAChC,OAAO,MAAM,uBAAA,IAAI,0EAAiB,MAArB,IAAI,EACf,aAAa,EACb,QAAQ,EACR,kBAAkB,CACnB,CAAC;iBACH;aACF;YACD,MAAM,IAAI,KAAK,CACb,wCAAwC,gBAAgB,EAAE,CAC3D,CAAC;SACH;QAAC,OAAO,CAAC,EAAE;YACV,MAAM,YAAY,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,8BAA8B,YAAY,EAAE,CAAC,CAAC;SAC/D;IACH,CAAC;IAiFD,OAAO,CAAC,gBAAwB;QAC9B,IAAI;YACF,MAAM,aAAa,GAAqB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACrE,IAAI,aAAa,CAAC,CAAC,KAAK,GAAG,EAAE;gBAC3B,IAAI,aAAa,CAAC,CAAC,KAAK,QAAQ,EAAE;oBAChC,MAAM,EAAE,CAAC,EAAE,+BAA+B,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC;oBAEtE,qBAAqB;oBACrB,MAAM,yBAAyB,GAAG,iBAAiB,CACjD,+BAA+B,CAChC,CAAC;oBAEF,iDAAiD;oBACjD,MAAM,IAAI,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;oBACzD,OAAO,IAAI,CAAC;iBACb;aACF;YACD,MAAM,IAAI,KAAK,CACb,wCAAwC,gBAAgB,EAAE,CAC3D,CAAC;SACH;QAAC,OAAO,CAAC,EAAE;YACV,MAAM,YAAY,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAC;SACzD;IACH,CAAC;IAED,8BAA8B,CAAC,OAAiB;QAC9C,MAAM,KAAK,GAAG,OAAO;aAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,IAAI;gBACF,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;aACxB;YAAC,MAAM;gBACN,OAAO,SAAS,CAAC;aAClB;QACH,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAmB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QAEnD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC3D,OAAO,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,CAAC;IACtC,CAAC;CAsEF;qFA5LC,KAAK,8CACH,SAAiB,EACjB,QAAgB,EAChB,kBAAiC;IAEjC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,uBAAA,IAAI,iFAAwB,MAA5B,IAAI,EAC9B,QAAQ,EACR;QACE,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,QAAQ;QACX,KAAK,EAAE,kBAAkB;KAC1B,EACD,SAAS,EACT,kBAAkB,CACnB,CAAC;IAEF,4BAA4B;IAC5B,MAAM,YAAY,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAC5C,MAAM,yBAAyB,GAAG,WAAW,CAC3C,IAAI,EACJ,uBAAA,IAAI,kEAAS,MAAb,IAAI,EAAU,YAAY,EAAE,GAAG,CAAC,CACjC,CAAC;IAEF,oBAAoB;IACpB,MAAM,aAAa,GAAG,iBAAiB,CAAC,yBAAyB,CAAC,CAAC;IAEnE,MAAM,gBAAgB,GAAqB;QACzC,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,aAAa;QAChB,CAAC,EAAE;YACD,CAAC,EAAE,QAAQ;YACX,CAAC,EAAE,QAAQ;YACX,CAAC,EAAE,QAAQ;YACX,KAAK,EAAE,kBAAkB;SAC1B;QACD,OAAO,EAAE,gBAAgB;KAC1B,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;AAC1C,CAAC,wCAED,KAAK,8CACH,IAAsB,EACtB,QAAgB,EAChB,kBAAiC;IAEjC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,+BAA+B,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAEhE,qBAAqB;IACrB,MAAM,yBAAyB,GAAG,iBAAiB,CACjD,+BAA+B,CAChC,CAAC;IAEF,iDAAiD;IACjD,MAAM,IAAI,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACzD,MAAM,kBAAkB,GAAG,yBAAyB,CAAC,KAAK,CACxD,OAAO,EACP,yBAAyB,CAAC,MAAM,CACjC,CAAC;IAEF,kBAAkB;IAClB,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,uBAAA,IAAI,iFAAwB,MAA5B,IAAI,EACxB,QAAQ,EACR;QACE,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,EACD,IAAI,EACJ,kBAAkB,CACnB,CAAC;IAEF,6BAA6B;IAC7B,OAAO,WAAW,CAAC,uBAAA,IAAI,kEAAS,MAAb,IAAI,EAAU,kBAAkB,EAAE,GAAG,CAAC,CAAC,CAAC;AAC7D,CAAC,qEA2CQ,SAAqB,EAAE,GAAe;IAC7C,MAAM,KAAK,GAAG,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAEhD,6BAA6B;IAC7B,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEtD,OAAO,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC,qEAEQ,kBAA8B,EAAE,GAAe;IACtD,0CAA0C;IAC1C,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CACzC,oBAAoB,EACpB,kBAAkB,CAAC,MAAM,CAC1B,CAAC;IAEF,6BAA6B;IAC7B,OAAO,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAC7C,CAAC,+CAED,KAAK,qDACH,QAAgB,EAChB,CAAwB,EACxB,IAAiB,EACjB,kBAAiC;IAEjC,MAAM,cAAc,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI;QACpB,CAAC,CAAC,kBAAkB,CAAC,cAAc,EAAE,IAAI,CAAC;QAC1C,CAAC,CAAC,mCAAmC,CAAC,cAAc,CAAC,CAAC;IAExD,IAAI,SAAS,EAAE;QACb,OAAO;YACL,GAAG,EAAE,SAAS,CAAC,GAAG;YAClB,IAAI,EAAE,SAAS,CAAC,IAAI;SACrB,CAAC;KACH;IAED,MAAM,OAAO,GAAG,IAAI,IAAI,WAAW,CAAC;IAEpC,IAAI,MAAkB,CAAC;IAEvB,IAAI,kBAAkB,EAAE;QACtB,MAAM,GAAG,MAAM,kBAAkB,CAC/B,iBAAiB,CAAC,QAAQ,CAAC,EAC3B,OAAO,EACP,CAAC,CAAC,CAAC,EACH,CAAC,CAAC,CAAC,EACH,CAAC,CAAC,CAAC,EACH,CAAC,CAAC,KAAK,CACR,CAAC;KACH;SAAM;QACL,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE;YAC5C,CAAC,EAAE,CAAC,CAAC,CAAC;YACN,CAAC,EAAE,CAAC,CAAC,CAAC;YACN,CAAC,EAAE,CAAC,CAAC,CAAC;YACN,KAAK,EAAE,CAAC,CAAC,KAAK;SACf,CAAC,CAAC;KACJ;IAED,YAAY,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAE9C,OAAO;QACL,GAAG,EAAE,MAAM;QACX,IAAI,EAAE,OAAO;KACd,CAAC;AACJ,CAAC;AAGH,MAAM,UAAU,GAAG,IAAI,kBAAkB,EAAE,CAAC;AAC5C,eAAe,UAAU,CAAC;AAE1B;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC;AAChC,CAAC","sourcesContent":["import { gcm } from '@noble/ciphers/aes';\nimport { randomBytes } from '@noble/ciphers/webcrypto';\nimport { scryptAsync } from '@noble/hashes/scrypt';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { utf8ToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils';\n\nimport type { NativeScrypt } from '../types/encryption';\nimport {\n getCachedKeyBySalt,\n getCachedKeyGeneratedWithSharedSalt,\n setCachedKey,\n} from './cache';\nimport {\n ALGORITHM_KEY_SIZE,\n ALGORITHM_NONCE_SIZE,\n SCRYPT_N,\n SCRYPT_p,\n SCRYPT_r,\n SCRYPT_SALT_SIZE,\n SHARED_SALT,\n} from './constants';\nimport {\n base64ToByteArray,\n byteArrayToBase64,\n bytesToUtf8,\n stringToByteArray,\n} from './utils';\n\nexport type EncryptedPayload = {\n // version\n v: '1';\n\n // key derivation function algorithm - scrypt\n t: 'scrypt';\n\n // data\n d: string;\n\n // encryption options - scrypt\n o: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n N: number;\n r: number;\n p: number;\n dkLen: number;\n };\n\n // Salt options\n saltLen: number;\n};\n\nclass EncryptorDecryptor {\n async encryptString(\n plaintext: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n try {\n return await this.#encryptStringV1(\n plaintext,\n password,\n nativeScryptCrypto,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to encrypt string - ${errorMessage}`);\n }\n }\n\n async decryptString(\n encryptedDataStr: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n try {\n const encryptedData: EncryptedPayload = JSON.parse(encryptedDataStr);\n if (encryptedData.v === '1') {\n if (encryptedData.t === 'scrypt') {\n return await this.#decryptStringV1(\n encryptedData,\n password,\n nativeScryptCrypto,\n );\n }\n }\n throw new Error(\n `Unsupported encrypted data payload - ${encryptedDataStr}`,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to decrypt string - ${errorMessage}`);\n }\n }\n\n async #encryptStringV1(\n plaintext: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n const { key, salt } = await this.#getOrGenerateScryptKey(\n password,\n {\n N: SCRYPT_N,\n r: SCRYPT_r,\n p: SCRYPT_p,\n dkLen: ALGORITHM_KEY_SIZE,\n },\n undefined,\n nativeScryptCrypto,\n );\n\n // Encrypt and prepend salt.\n const plaintextRaw = utf8ToBytes(plaintext);\n const ciphertextAndNonceAndSalt = concatBytes(\n salt,\n this.#encrypt(plaintextRaw, key),\n );\n\n // Convert to Base64\n const encryptedData = byteArrayToBase64(ciphertextAndNonceAndSalt);\n\n const encryptedPayload: EncryptedPayload = {\n v: '1',\n t: 'scrypt',\n d: encryptedData,\n o: {\n N: SCRYPT_N,\n r: SCRYPT_r,\n p: SCRYPT_p,\n dkLen: ALGORITHM_KEY_SIZE,\n },\n saltLen: SCRYPT_SALT_SIZE,\n };\n\n return JSON.stringify(encryptedPayload);\n }\n\n async #decryptStringV1(\n data: EncryptedPayload,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n const { o, d: base64CiphertextAndNonceAndSalt, saltLen } = data;\n\n // Decode the base64.\n const ciphertextAndNonceAndSalt = base64ToByteArray(\n base64CiphertextAndNonceAndSalt,\n );\n\n // Create buffers of salt and ciphertextAndNonce.\n const salt = ciphertextAndNonceAndSalt.slice(0, saltLen);\n const ciphertextAndNonce = ciphertextAndNonceAndSalt.slice(\n saltLen,\n ciphertextAndNonceAndSalt.length,\n );\n\n // Derive the key.\n const { key } = await this.#getOrGenerateScryptKey(\n password,\n {\n N: o.N,\n r: o.r,\n p: o.p,\n dkLen: o.dkLen,\n },\n salt,\n nativeScryptCrypto,\n );\n\n // Decrypt and return result.\n return bytesToUtf8(this.#decrypt(ciphertextAndNonce, key));\n }\n\n getSalt(encryptedDataStr: string) {\n try {\n const encryptedData: EncryptedPayload = JSON.parse(encryptedDataStr);\n if (encryptedData.v === '1') {\n if (encryptedData.t === 'scrypt') {\n const { d: base64CiphertextAndNonceAndSalt, saltLen } = encryptedData;\n\n // Decode the base64.\n const ciphertextAndNonceAndSalt = base64ToByteArray(\n base64CiphertextAndNonceAndSalt,\n );\n\n // Create buffers of salt and ciphertextAndNonce.\n const salt = ciphertextAndNonceAndSalt.slice(0, saltLen);\n return salt;\n }\n }\n throw new Error(\n `Unsupported encrypted data payload - ${encryptedDataStr}`,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to get salt - ${errorMessage}`);\n }\n }\n\n getIfEntriesHaveDifferentSalts(entries: string[]): boolean {\n const salts = entries\n .map((e) => {\n try {\n return this.getSalt(e);\n } catch {\n return undefined;\n }\n })\n .filter((s): s is Uint8Array => s !== undefined);\n\n const strSet = new Set(salts.map((arr) => arr.toString()));\n return strSet.size === salts.length;\n }\n\n #encrypt(plaintext: Uint8Array, key: Uint8Array): Uint8Array {\n const nonce = randomBytes(ALGORITHM_NONCE_SIZE);\n\n // Encrypt and prepend nonce.\n const ciphertext = gcm(key, nonce).encrypt(plaintext);\n\n return concatBytes(nonce, ciphertext);\n }\n\n #decrypt(ciphertextAndNonce: Uint8Array, key: Uint8Array): Uint8Array {\n // Create buffers of nonce and ciphertext.\n const nonce = ciphertextAndNonce.slice(0, ALGORITHM_NONCE_SIZE);\n const ciphertext = ciphertextAndNonce.slice(\n ALGORITHM_NONCE_SIZE,\n ciphertextAndNonce.length,\n );\n\n // Decrypt and return result.\n return gcm(key, nonce).decrypt(ciphertext);\n }\n\n async #getOrGenerateScryptKey(\n password: string,\n o: EncryptedPayload['o'],\n salt?: Uint8Array,\n nativeScryptCrypto?: NativeScrypt,\n ) {\n const hashedPassword = createSHA256Hash(password);\n const cachedKey = salt\n ? getCachedKeyBySalt(hashedPassword, salt)\n : getCachedKeyGeneratedWithSharedSalt(hashedPassword);\n\n if (cachedKey) {\n return {\n key: cachedKey.key,\n salt: cachedKey.salt,\n };\n }\n\n const newSalt = salt ?? SHARED_SALT;\n\n let newKey: Uint8Array;\n\n if (nativeScryptCrypto) {\n newKey = await nativeScryptCrypto(\n stringToByteArray(password),\n newSalt,\n o.N,\n o.r,\n o.p,\n o.dkLen,\n );\n } else {\n newKey = await scryptAsync(password, newSalt, {\n N: o.N,\n r: o.r,\n p: o.p,\n dkLen: o.dkLen,\n });\n }\n\n setCachedKey(hashedPassword, newSalt, newKey);\n\n return {\n key: newKey,\n salt: newSalt,\n };\n }\n}\n\nconst encryption = new EncryptorDecryptor();\nexport default encryption;\n\n/**\n * Receive a SHA256 hash from a given string\n * @param data - input\n * @returns sha256 hash\n */\nexport function createSHA256Hash(data: string): string {\n const hashedData = sha256(data);\n return bytesToHex(hashedData);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"encryption.mjs","sourceRoot":"","sources":["../../../src/shared/encryption/encryption.ts"],"names":[],"mappings":"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","sourcesContent":["import { gcm } from '@noble/ciphers/aes';\nimport { randomBytes } from '@noble/ciphers/webcrypto';\nimport { scryptAsync } from '@noble/hashes/scrypt';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { utf8ToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils';\n\nimport type { NativeScrypt } from '../types/encryption';\nimport { getAnyCachedKey, getCachedKeyBySalt, setCachedKey } from './cache';\nimport {\n base64ToByteArray,\n byteArrayToBase64,\n bytesToUtf8,\n stringToByteArray,\n} from './utils';\n\nexport type EncryptedPayload = {\n // version\n v: '1';\n\n // key derivation function algorithm - scrypt\n t: 'scrypt';\n\n // data\n d: string;\n\n // encryption options - scrypt\n o: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n N: number;\n r: number;\n p: number;\n dkLen: number;\n };\n\n // Salt options\n saltLen: number;\n};\n\n// Nonce/Key Sizes\nconst ALGORITHM_NONCE_SIZE = 12; // 12 bytes\nconst ALGORITHM_KEY_SIZE = 16; // 16 bytes\n\n// Scrypt settings\n// see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt\nconst SCRYPT_SALT_SIZE = 16; // 16 bytes\nconst SCRYPT_N = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1)\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst SCRYPT_r = 8; // Block size parameter\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst SCRYPT_p = 1; // Parallelization parameter\n\nclass EncryptorDecryptor {\n async encryptString(\n plaintext: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n try {\n return await this.#encryptStringV1(\n plaintext,\n password,\n nativeScryptCrypto,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to encrypt string - ${errorMessage}`);\n }\n }\n\n async decryptString(\n encryptedDataStr: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n try {\n const encryptedData: EncryptedPayload = JSON.parse(encryptedDataStr);\n if (encryptedData.v === '1') {\n if (encryptedData.t === 'scrypt') {\n return await this.#decryptStringV1(\n encryptedData,\n password,\n nativeScryptCrypto,\n );\n }\n }\n throw new Error(\n `Unsupported encrypted data payload - ${encryptedDataStr}`,\n );\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(`Unable to decrypt string - ${errorMessage}`);\n }\n }\n\n async #encryptStringV1(\n plaintext: string,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n const { key, salt } = await this.#getOrGenerateScryptKey(\n password,\n {\n N: SCRYPT_N,\n r: SCRYPT_r,\n p: SCRYPT_p,\n dkLen: ALGORITHM_KEY_SIZE,\n },\n undefined,\n nativeScryptCrypto,\n );\n\n // Encrypt and prepend salt.\n const plaintextRaw = utf8ToBytes(plaintext);\n const ciphertextAndNonceAndSalt = concatBytes(\n salt,\n this.#encrypt(plaintextRaw, key),\n );\n\n // Convert to Base64\n const encryptedData = byteArrayToBase64(ciphertextAndNonceAndSalt);\n\n const encryptedPayload: EncryptedPayload = {\n v: '1',\n t: 'scrypt',\n d: encryptedData,\n o: {\n N: SCRYPT_N,\n r: SCRYPT_r,\n p: SCRYPT_p,\n dkLen: ALGORITHM_KEY_SIZE,\n },\n saltLen: SCRYPT_SALT_SIZE,\n };\n\n return JSON.stringify(encryptedPayload);\n }\n\n async #decryptStringV1(\n data: EncryptedPayload,\n password: string,\n nativeScryptCrypto?: NativeScrypt,\n ): Promise<string> {\n const { o, d: base64CiphertextAndNonceAndSalt, saltLen } = data;\n\n // Decode the base64.\n const ciphertextAndNonceAndSalt = base64ToByteArray(\n base64CiphertextAndNonceAndSalt,\n );\n\n // Create buffers of salt and ciphertextAndNonce.\n const salt = ciphertextAndNonceAndSalt.slice(0, saltLen);\n const ciphertextAndNonce = ciphertextAndNonceAndSalt.slice(\n saltLen,\n ciphertextAndNonceAndSalt.length,\n );\n\n // Derive the key.\n const { key } = await this.#getOrGenerateScryptKey(\n password,\n {\n N: o.N,\n r: o.r,\n p: o.p,\n dkLen: o.dkLen,\n },\n salt,\n nativeScryptCrypto,\n );\n\n // Decrypt and return result.\n return bytesToUtf8(this.#decrypt(ciphertextAndNonce, key));\n }\n\n #encrypt(plaintext: Uint8Array, key: Uint8Array): Uint8Array {\n const nonce = randomBytes(ALGORITHM_NONCE_SIZE);\n\n // Encrypt and prepend nonce.\n const ciphertext = gcm(key, nonce).encrypt(plaintext);\n\n return concatBytes(nonce, ciphertext);\n }\n\n #decrypt(ciphertextAndNonce: Uint8Array, key: Uint8Array): Uint8Array {\n // Create buffers of nonce and ciphertext.\n const nonce = ciphertextAndNonce.slice(0, ALGORITHM_NONCE_SIZE);\n const ciphertext = ciphertextAndNonce.slice(\n ALGORITHM_NONCE_SIZE,\n ciphertextAndNonce.length,\n );\n\n // Decrypt and return result.\n return gcm(key, nonce).decrypt(ciphertext);\n }\n\n async #getOrGenerateScryptKey(\n password: string,\n o: EncryptedPayload['o'],\n salt?: Uint8Array,\n nativeScryptCrypto?: NativeScrypt,\n ) {\n const hashedPassword = createSHA256Hash(password);\n const cachedKey = salt\n ? getCachedKeyBySalt(hashedPassword, salt)\n : getAnyCachedKey(hashedPassword);\n\n if (cachedKey) {\n return {\n key: cachedKey.key,\n salt: cachedKey.salt,\n };\n }\n\n const newSalt = salt ?? randomBytes(SCRYPT_SALT_SIZE);\n\n let newKey: Uint8Array;\n\n if (nativeScryptCrypto) {\n newKey = await nativeScryptCrypto(\n stringToByteArray(password),\n newSalt,\n o.N,\n o.r,\n o.p,\n o.dkLen,\n );\n } else {\n newKey = await scryptAsync(password, newSalt, {\n N: o.N,\n r: o.r,\n p: o.p,\n dkLen: o.dkLen,\n });\n }\n setCachedKey(hashedPassword, newSalt, newKey);\n\n return {\n key: newKey,\n salt: newSalt,\n };\n }\n}\n\nconst encryption = new EncryptorDecryptor();\nexport default encryption;\n\n/**\n * Receive a SHA256 hash from a given string\n * @param data - input\n * @returns sha256 hash\n */\nexport function createSHA256Hash(data: string): string {\n const hashedData = sha256(data);\n return bytesToHex(hashedData);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/profile-sync-controller",
|
|
3
|
-
"version": "3.0.0-preview-
|
|
3
|
+
"version": "3.0.0-preview-9c296dcb",
|
|
4
4
|
"description": "The profile sync helps developers synchronize data across multiple clients and devices in a privacy-preserving way. All data saved in the user storage database is encrypted client-side to preserve privacy. The user storage provides a modular design, giving developers the flexibility to construct and manage their storage spaces in a way that best suits their needs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"MetaMask",
|
|
@@ -117,6 +117,7 @@
|
|
|
117
117
|
"@lavamoat/preinstall-always-fail": "^2.1.0",
|
|
118
118
|
"@metamask/accounts-controller": "^20.0.1",
|
|
119
119
|
"@metamask/auto-changelog": "^3.4.4",
|
|
120
|
+
"@metamask/keyring-internal-api": "^0.0.1",
|
|
120
121
|
"@metamask/providers": "^18.1.1",
|
|
121
122
|
"@metamask/snaps-controllers": "^9.10.0",
|
|
122
123
|
"@types/jest": "^27.4.1",
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SHARED_SALT = exports.SCRYPT_p = exports.SCRYPT_r = exports.SCRYPT_N = exports.SCRYPT_SALT_SIZE = exports.ALGORITHM_KEY_SIZE = exports.ALGORITHM_NONCE_SIZE = void 0;
|
|
4
|
-
// Nonce/Key Sizes
|
|
5
|
-
exports.ALGORITHM_NONCE_SIZE = 12; // 12 bytes
|
|
6
|
-
exports.ALGORITHM_KEY_SIZE = 16; // 16 bytes
|
|
7
|
-
// Scrypt settings
|
|
8
|
-
// see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt
|
|
9
|
-
exports.SCRYPT_SALT_SIZE = 16; // 16 bytes
|
|
10
|
-
exports.SCRYPT_N = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1)
|
|
11
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
12
|
-
exports.SCRYPT_r = 8; // Block size parameter
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
14
|
-
exports.SCRYPT_p = 1; // Parallelization parameter
|
|
15
|
-
exports.SHARED_SALT = new Uint8Array([
|
|
16
|
-
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
17
|
-
]);
|
|
18
|
-
//# sourceMappingURL=constants.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../../../src/shared/encryption/constants.ts"],"names":[],"mappings":";;;AAAA,kBAAkB;AACL,QAAA,oBAAoB,GAAG,EAAE,CAAC,CAAC,WAAW;AACtC,QAAA,kBAAkB,GAAG,EAAE,CAAC,CAAC,WAAW;AAEjD,kBAAkB;AAClB,+FAA+F;AAClF,QAAA,gBAAgB,GAAG,EAAE,CAAC,CAAC,WAAW;AAClC,QAAA,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,wDAAwD;AACzF,gEAAgE;AACnD,QAAA,QAAQ,GAAG,CAAC,CAAC,CAAC,uBAAuB;AAClD,gEAAgE;AACnD,QAAA,QAAQ,GAAG,CAAC,CAAC,CAAC,4BAA4B;AAE1C,QAAA,WAAW,GAAG,IAAI,UAAU,CAAC;IACxC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;CACrD,CAAC,CAAC","sourcesContent":["// Nonce/Key Sizes\nexport const ALGORITHM_NONCE_SIZE = 12; // 12 bytes\nexport const ALGORITHM_KEY_SIZE = 16; // 16 bytes\n\n// Scrypt settings\n// see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt\nexport const SCRYPT_SALT_SIZE = 16; // 16 bytes\nexport const SCRYPT_N = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1)\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const SCRYPT_r = 8; // Block size parameter\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const SCRYPT_p = 1; // Parallelization parameter\n\nexport const SHARED_SALT = new Uint8Array([\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n]);\n"]}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare const ALGORITHM_NONCE_SIZE = 12;
|
|
2
|
-
export declare const ALGORITHM_KEY_SIZE = 16;
|
|
3
|
-
export declare const SCRYPT_SALT_SIZE = 16;
|
|
4
|
-
export declare const SCRYPT_N: number;
|
|
5
|
-
export declare const SCRYPT_r = 8;
|
|
6
|
-
export declare const SCRYPT_p = 1;
|
|
7
|
-
export declare const SHARED_SALT: Uint8Array;
|
|
8
|
-
//# sourceMappingURL=constants.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../../src/shared/encryption/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAIrC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,QAAQ,QAAU,CAAC;AAEhC,eAAO,MAAM,QAAQ,IAAI,CAAC;AAE1B,eAAO,MAAM,QAAQ,IAAI,CAAC;AAE1B,eAAO,MAAM,WAAW,YAEtB,CAAC"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare const ALGORITHM_NONCE_SIZE = 12;
|
|
2
|
-
export declare const ALGORITHM_KEY_SIZE = 16;
|
|
3
|
-
export declare const SCRYPT_SALT_SIZE = 16;
|
|
4
|
-
export declare const SCRYPT_N: number;
|
|
5
|
-
export declare const SCRYPT_r = 8;
|
|
6
|
-
export declare const SCRYPT_p = 1;
|
|
7
|
-
export declare const SHARED_SALT: Uint8Array;
|
|
8
|
-
//# sourceMappingURL=constants.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../../src/shared/encryption/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAIrC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,QAAQ,QAAU,CAAC;AAEhC,eAAO,MAAM,QAAQ,IAAI,CAAC;AAE1B,eAAO,MAAM,QAAQ,IAAI,CAAC;AAE1B,eAAO,MAAM,WAAW,YAEtB,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// Nonce/Key Sizes
|
|
2
|
-
export const ALGORITHM_NONCE_SIZE = 12; // 12 bytes
|
|
3
|
-
export const ALGORITHM_KEY_SIZE = 16; // 16 bytes
|
|
4
|
-
// Scrypt settings
|
|
5
|
-
// see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt
|
|
6
|
-
export const SCRYPT_SALT_SIZE = 16; // 16 bytes
|
|
7
|
-
export const SCRYPT_N = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1)
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
9
|
-
export const SCRYPT_r = 8; // Block size parameter
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
11
|
-
export const SCRYPT_p = 1; // Parallelization parameter
|
|
12
|
-
export const SHARED_SALT = new Uint8Array([
|
|
13
|
-
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
14
|
-
]);
|
|
15
|
-
//# sourceMappingURL=constants.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../../src/shared/encryption/constants.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAClB,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC,CAAC,WAAW;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC,CAAC,WAAW;AAEjD,kBAAkB;AAClB,+FAA+F;AAC/F,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC,CAAC,WAAW;AAC/C,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,wDAAwD;AACzF,gEAAgE;AAChE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,uBAAuB;AAClD,gEAAgE;AAChE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,4BAA4B;AAEvD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,UAAU,CAAC;IACxC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;CACrD,CAAC,CAAC","sourcesContent":["// Nonce/Key Sizes\nexport const ALGORITHM_NONCE_SIZE = 12; // 12 bytes\nexport const ALGORITHM_KEY_SIZE = 16; // 16 bytes\n\n// Scrypt settings\n// see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt\nexport const SCRYPT_SALT_SIZE = 16; // 16 bytes\nexport const SCRYPT_N = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1)\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const SCRYPT_r = 8; // Block size parameter\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport const SCRYPT_p = 1; // Parallelization parameter\n\nexport const SHARED_SALT = new Uint8Array([\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n]);\n"]}
|