Промежуточный коммит: состояние до нормальной Solana-first регистрации

This commit is contained in:
AidarKC
2026-05-27 18:33:26 +04:00
parent b345900459
commit 6f0bb01b61
17 changed files with 661 additions and 72 deletions
+54 -2
View File
@@ -86,14 +86,29 @@ async function derivePasswordSeedArgon2id({ login, password, suffix }) {
const salt = await makeArgon2Salt(normalizedLogin, normalizedSuffix);
const passBytes = utf8Bytes(`${normalizedLogin}\n${normalizedPassword}`);
const out = await argon2idAsync(passBytes, salt, {
t: 3,
m: 262144,
t: 2,
m: 65536,
p: 1,
dkLen: 32,
});
return new Uint8Array(out);
}
async function deriveMasterSecretArgon2id({ login, password, onProgress }) {
const normalizedLogin = normalizeLoginForKdf(login);
const normalizedPassword = String(password ?? '');
const salt = await makeArgon2Salt(normalizedLogin, 'master.secret');
const passBytes = utf8Bytes(`${normalizedLogin}\n${normalizedPassword}`);
const out = await argon2idAsync(passBytes, salt, {
t: 2,
m: 65536,
p: 1,
dkLen: 32,
onProgress,
});
return new Uint8Array(out);
}
function ed25519Pkcs8FromSeed(seed32) {
if (seed32.length !== 32) {
throw new Error('Для Ed25519 нужен seed длиной 32 байта');
@@ -131,6 +146,43 @@ export async function deriveEd25519FromPassword(password, suffix, options = {})
};
}
export async function deriveMasterSecretFromPassword(password, options = {}) {
const normalizedPassword = String(password ?? '');
const normalizedLogin = String(options?.login ?? '');
const onProgress = typeof options?.onProgress === 'function' ? options.onProgress : undefined;
if (normalizedPassword.length === 0) {
const legacy = await derivePasswordSeed(normalizedPassword, 'master.secret');
if (onProgress) onProgress(1);
return legacy;
}
return deriveMasterSecretArgon2id({
login: normalizedLogin,
password: normalizedPassword,
onProgress,
});
}
export async function deriveEd25519FromMasterSecret(masterSecret32, suffix) {
const secretBytes = masterSecret32 instanceof Uint8Array
? masterSecret32
: new Uint8Array(masterSecret32 || []);
if (secretBytes.length !== 32) {
throw new Error('Master secret должен быть длиной 32 байта');
}
const material = `${bytesToBase64(secretBytes)}|${String(suffix || '')}`;
const seed = await sha256Text(material);
const pkcs8 = ed25519Pkcs8FromSeed(seed);
const subtle = getSubtleApi();
const privateKey = await subtle.importKey('pkcs8', pkcs8, { name: 'Ed25519' }, true, ['sign']);
const jwk = await subtle.exportKey('jwk', privateKey);
if (!jwk.x) throw new Error('Не удалось получить публичный ключ Ed25519');
return {
privateKey,
publicKeyB64: bytesToBase64(base64ToBytes(base64UrlToBase64(jwk.x))),
privatePkcs8B64: bytesToBase64(pkcs8),
};
}
export async function deriveAesKeyFromStoragePwd(storagePwd, saltBytes) {
const subtle = getSubtleApi();
const baseKey = await subtle.importKey(