diff --git a/packages/util-crypto/src/scrypt/defaults.ts b/packages/util-crypto/src/scrypt/defaults.ts index 978b46815..fbe250b81 100644 --- a/packages/util-crypto/src/scrypt/defaults.ts +++ b/packages/util-crypto/src/scrypt/defaults.ts @@ -3,8 +3,17 @@ import type { ScryptParams } from './types.js'; +export const ALLOWED_PARAMS: ScryptParams[] = [ + { N: 1 << 13, p: 10, r: 8 }, + { N: 1 << 14, p: 5, r: 8 }, + { N: 1 << 15, p: 3, r: 8 }, + { N: 1 << 15, p: 1, r: 8 }, + { N: 1 << 16, p: 2, r: 8 }, + { N: 1 << 17, p: 1, r: 8 } +]; + export const DEFAULT_PARAMS: ScryptParams = { - N: 1 << 15, + N: 1 << 17, p: 1, r: 8 }; diff --git a/packages/util-crypto/src/scrypt/encode.spec.ts b/packages/util-crypto/src/scrypt/encode.spec.ts index 1b68cd200..b3204dba5 100644 --- a/packages/util-crypto/src/scrypt/encode.spec.ts +++ b/packages/util-crypto/src/scrypt/encode.spec.ts @@ -13,7 +13,7 @@ import { scryptEncode } from './index.js'; export const KNOWN_TEST = 'testing, 123'; // eslint-disable-next-line jest/no-export -export const KNOWN_PASS = new Uint8Array([223, 185, 241, 135, 125, 17, 195, 27, 64, 64, 154, 69, 47, 82, 123, 38, 255, 230, 199, 200, 101, 115, 21, 116, 119, 59, 67, 43, 58, 220, 112, 70, 124, 139, 240, 206, 42, 148, 140, 132, 64, 226, 164, 25, 104, 80, 49, 92, 144, 132, 109, 178, 76, 225, 171, 116, 151, 181, 34, 243, 177, 235, 134, 76]); +export const KNOWN_PASS = new Uint8Array([225, 18, 85, 30, 46, 178, 200, 63, 147, 225, 37, 46, 88, 224, 151, 132, 48, 206, 104, 234, 120, 112, 243, 198, 92, 52, 101, 127, 242, 22, 116, 55, 74, 29, 17, 197, 38, 191, 128, 39, 255, 119, 175, 113, 180, 252, 171, 10, 78, 93, 226, 7, 166, 120, 99, 198, 225, 158, 107, 132, 226, 73, 129, 35]); // eslint-disable-next-line jest/no-export export const KNOWN_SALT = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8]); diff --git a/packages/util-crypto/src/scrypt/fromU8a.ts b/packages/util-crypto/src/scrypt/fromU8a.ts index bbe1550af..74b0e97c8 100644 --- a/packages/util-crypto/src/scrypt/fromU8a.ts +++ b/packages/util-crypto/src/scrypt/fromU8a.ts @@ -6,7 +6,7 @@ import type { ScryptParams } from './types.js'; import { u8aToBn } from '@polkadot/util'; import { BN_LE_OPTS } from '../bn.js'; -import { DEFAULT_PARAMS } from './defaults.js'; +import { ALLOWED_PARAMS } from './defaults.js'; interface Result { params: ScryptParams, @@ -28,12 +28,15 @@ export function scryptFromU8a (data: Uint8Array): Result { const p = u8aToBn(data.subarray(36, 40), BN_LE_OPTS).toNumber(); const r = u8aToBn(data.subarray(40, 44), BN_LE_OPTS).toNumber(); - // FIXME At this moment we assume these to be fixed params, this is not a great idea - // since we lose flexibility and updates for greater security. However we need some - // protection against carefully-crafted params that can eat up CPU since these are user - // inputs. So we need to get very clever here, but atm we only allow the defaults - // and if no match, bail out - if (N !== DEFAULT_PARAMS.N || p !== DEFAULT_PARAMS.p || r !== DEFAULT_PARAMS.r) { + if (N > (1 << 20) || p > 4 || r > 16) { + throw new Error('Scrypt parameters exceed safe limits'); + } + + const isAllowed = ALLOWED_PARAMS.some((preset) => + preset.N === N && preset.p === p && preset.r === r + ); + + if (!isAllowed) { throw new Error('Invalid injected scrypt params found'); }