SHA256
Реализовать SHiNE_DM v1 с E2EE и tombstone
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
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';
|
||||
import { edwardsToMontgomeryPriv, edwardsToMontgomeryPub, x25519 } from 'https://esm.sh/@noble/curves@1.8.1/ed25519';
|
||||
const SHINE_KEY_DERIVATION_PREFIX = 'SHiNE-key';
|
||||
|
||||
function getCryptoApi() {
|
||||
@@ -340,3 +341,56 @@ export async function signBytes(privateKey, bytes) {
|
||||
const signature = await getSubtleApi().sign({ name: 'Ed25519' }, privateKey, bytes);
|
||||
return new Uint8Array(signature);
|
||||
}
|
||||
|
||||
export function extractEd25519SeedFromPkcs8B64(pkcs8B64) {
|
||||
const bytes = base64ToBytes(String(pkcs8B64 || '').trim());
|
||||
if (bytes.length < 32) throw new Error('Некорректный PKCS8 ключ client.key');
|
||||
return bytes.slice(bytes.length - 32);
|
||||
}
|
||||
|
||||
export function ed25519SeedToX25519Private(seed32) {
|
||||
const seed = seed32 instanceof Uint8Array ? seed32 : new Uint8Array(seed32 || []);
|
||||
if (seed.length !== 32) throw new Error('Seed Ed25519 должен быть 32 байта');
|
||||
return new Uint8Array(edwardsToMontgomeryPriv(seed));
|
||||
}
|
||||
|
||||
export function ed25519PublicToX25519Public(ed25519Pub32) {
|
||||
const pub = ed25519Pub32 instanceof Uint8Array ? ed25519Pub32 : new Uint8Array(ed25519Pub32 || []);
|
||||
if (pub.length !== 32) throw new Error('Публичный Ed25519 ключ должен быть 32 байта');
|
||||
return new Uint8Array(edwardsToMontgomeryPub(pub));
|
||||
}
|
||||
|
||||
export function x25519RandomPrivateKey() {
|
||||
return new Uint8Array(x25519.utils.randomPrivateKey());
|
||||
}
|
||||
|
||||
export function x25519PublicFromPrivate(privateKey32) {
|
||||
const key = privateKey32 instanceof Uint8Array ? privateKey32 : new Uint8Array(privateKey32 || []);
|
||||
if (key.length !== 32) throw new Error('Приватный X25519 ключ должен быть 32 байта');
|
||||
return new Uint8Array(x25519.getPublicKey(key));
|
||||
}
|
||||
|
||||
export function x25519SharedSecret(privateKey32, publicKey32) {
|
||||
const priv = privateKey32 instanceof Uint8Array ? privateKey32 : new Uint8Array(privateKey32 || []);
|
||||
const pub = publicKey32 instanceof Uint8Array ? publicKey32 : new Uint8Array(publicKey32 || []);
|
||||
if (priv.length !== 32 || pub.length !== 32) {
|
||||
throw new Error('X25519 ключи должны быть по 32 байта');
|
||||
}
|
||||
return new Uint8Array(x25519.getSharedSecret(priv, pub));
|
||||
}
|
||||
|
||||
export async function hkdfSha256(ikmBytes, saltBytes, infoBytes, outLen) {
|
||||
const subtle = getSubtleApi();
|
||||
const baseKey = await subtle.importKey('raw', ikmBytes, 'HKDF', false, ['deriveBits']);
|
||||
const bits = await subtle.deriveBits(
|
||||
{
|
||||
name: 'HKDF',
|
||||
hash: 'SHA-256',
|
||||
salt: saltBytes instanceof Uint8Array ? saltBytes : new Uint8Array(saltBytes || []),
|
||||
info: infoBytes instanceof Uint8Array ? infoBytes : new Uint8Array(infoBytes || []),
|
||||
},
|
||||
baseKey,
|
||||
Number(outLen) * 8,
|
||||
);
|
||||
return new Uint8Array(bits);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user