SHA256
Auth/UI: Argon2id derivation для login/register + блок Расширенные
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
const encoder = new TextEncoder();
|
||||
const WEB_CRYPTO_REQUIRED_MESSAGE = 'Регистрация и подпись блоков требуют WebCrypto (crypto.subtle). Откройте приложение через HTTPS или localhost в современном браузере и повторите попытку.';
|
||||
import { argon2idAsync } from 'https://esm.sh/@noble/hashes@1.8.0/argon2.js';
|
||||
|
||||
function getCryptoApi() {
|
||||
const api = globalThis.crypto;
|
||||
@@ -66,6 +67,33 @@ export async function derivePasswordSeed(password, suffix) {
|
||||
return sha256Text(concat);
|
||||
}
|
||||
|
||||
function normalizeLoginForKdf(login) {
|
||||
return String(login || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
async function makeArgon2Salt(login, suffix) {
|
||||
const normalizedLogin = normalizeLoginForKdf(login);
|
||||
const normalizedSuffix = String(suffix || '').trim();
|
||||
const saltSource = `shine-auth-v2|login=${normalizedLogin}|suffix=${normalizedSuffix}`;
|
||||
const digest = await sha256Text(saltSource);
|
||||
return digest.slice(0, 16);
|
||||
}
|
||||
|
||||
async function derivePasswordSeedArgon2id({ login, password, suffix }) {
|
||||
const normalizedLogin = normalizeLoginForKdf(login);
|
||||
const normalizedPassword = String(password ?? '');
|
||||
const normalizedSuffix = String(suffix || '').trim();
|
||||
const salt = await makeArgon2Salt(normalizedLogin, normalizedSuffix);
|
||||
const passBytes = utf8Bytes(`${normalizedLogin}\n${normalizedPassword}`);
|
||||
const out = await argon2idAsync(passBytes, salt, {
|
||||
t: 3,
|
||||
m: 262144,
|
||||
p: 1,
|
||||
dkLen: 32,
|
||||
});
|
||||
return new Uint8Array(out);
|
||||
}
|
||||
|
||||
function ed25519Pkcs8FromSeed(seed32) {
|
||||
if (seed32.length !== 32) {
|
||||
throw new Error('Для Ed25519 нужен seed длиной 32 байта');
|
||||
@@ -79,8 +107,17 @@ function ed25519Pkcs8FromSeed(seed32) {
|
||||
return out;
|
||||
}
|
||||
|
||||
export async function deriveEd25519FromPassword(password, suffix) {
|
||||
const seed = await derivePasswordSeed(password, suffix);
|
||||
export async function deriveEd25519FromPassword(password, suffix, options = {}) {
|
||||
const normalizedPassword = String(password ?? '');
|
||||
const normalizedLogin = String(options?.login ?? '');
|
||||
const useLegacyEmptyPassword = normalizedPassword.length === 0;
|
||||
const seed = useLegacyEmptyPassword
|
||||
? await derivePasswordSeed(normalizedPassword, suffix)
|
||||
: await derivePasswordSeedArgon2id({
|
||||
login: normalizedLogin,
|
||||
password: normalizedPassword,
|
||||
suffix,
|
||||
});
|
||||
const pkcs8 = ed25519Pkcs8FromSeed(seed);
|
||||
const subtle = getSubtleApi();
|
||||
const privateKey = await subtle.importKey('pkcs8', pkcs8, { name: 'Ed25519' }, true, ['sign']);
|
||||
|
||||
Reference in New Issue
Block a user