🐛 fix: Refactor key generation logic and update dependencies for ML-KEM-768 integration
This commit is contained in:
parent
5ce5d62b22
commit
b8f630f8ab
@ -1,6 +1,10 @@
|
||||
import { z } from 'zod';
|
||||
import { generatePassword, generateRealityKeyPair, generateRealityShortId } from './generate';
|
||||
import { generateVlessX25519Pair } from './generate/mlkem768x25519plus';
|
||||
import {
|
||||
generateMLKEM768KeyPair,
|
||||
generatePassword,
|
||||
generateRealityKeyPair,
|
||||
generateRealityShortId,
|
||||
} from './generate';
|
||||
|
||||
export const protocols = [
|
||||
'shadowsocks',
|
||||
@ -700,10 +704,10 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
|
||||
placeholder: (t) => t('encryption_private_key_placeholder'),
|
||||
group: 'encryption',
|
||||
generate: {
|
||||
function: () => generateVlessX25519Pair(),
|
||||
function: generateMLKEM768KeyPair,
|
||||
updateFields: {
|
||||
encryption_private_key: 'privateKeyB64',
|
||||
encryption_password: 'passwordB64',
|
||||
encryption_private_key: 'privateKey',
|
||||
encryption_password: 'publicKey',
|
||||
},
|
||||
},
|
||||
condition: (p) => p.encryption === 'mlkem768x25519plus',
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
export { generatePassword } from './random';
|
||||
export {
|
||||
generateRealityKeyPair,
|
||||
generateRealityShortId,
|
||||
publicKeyFromPrivate,
|
||||
} from './reality-key';
|
||||
export { generateMLKEM768KeyPair } from './mlkem768';
|
||||
export { generateRealityShortId } from './short-id';
|
||||
export { generatePassword } from './uid';
|
||||
export { generateRealityKeyPair } from './x25519';
|
||||
|
||||
34
apps/admin/app/dashboard/servers/generate/mlkem768.ts
Normal file
34
apps/admin/app/dashboard/servers/generate/mlkem768.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import mlkem from 'mlkem-wasm';
|
||||
import { toB64Url } from './util';
|
||||
|
||||
export async function generateMLKEM768KeyPair() {
|
||||
const mlkemKeyPair = await mlkem.generateKey({ name: 'ML-KEM-768' }, true, [
|
||||
'encapsulateBits',
|
||||
'decapsulateBits',
|
||||
]);
|
||||
const mlkemPublicKeyRaw = await mlkem.exportKey('raw-public', mlkemKeyPair.publicKey);
|
||||
const mlkemPrivateKeyRaw = await mlkem.exportKey('raw-seed', mlkemKeyPair.privateKey);
|
||||
|
||||
return {
|
||||
publicKey: toB64Url(new Uint8Array(mlkemPublicKeyRaw)),
|
||||
privateKey: toB64Url(new Uint8Array(mlkemPrivateKeyRaw)),
|
||||
};
|
||||
}
|
||||
const test = await generateMLKEM768KeyPair();
|
||||
|
||||
console.log('生成的密钥信息:');
|
||||
console.log('私钥长度:', test.privateKey.length);
|
||||
console.log('公钥长度:', test.publicKey.length);
|
||||
console.log(test);
|
||||
|
||||
// 从 VLESS 配置字符串中提取的密钥
|
||||
const extractedKeys = {
|
||||
decryptionKey:
|
||||
'B2qLcDHhiztvBaB4BhMCnU-fM-axE4DZowMK9TIvL5qma2M5fVAmFswPdfej2N1SmlJa5ppidC1ksHLVfoEvjw',
|
||||
encryptionKey:
|
||||
'FgEI5sTIzBgZS4psemcdGDCRb5JvdDFqzOeVvLJYEmmZFSgxG1SkYxx8DUO-txGqvYdhFruja-ZzmIQoGOCQEMd0RbK4BhYRm4jE96GXTytu7Hi7pYo9-2SEuKC10righ2ceqis0LoggubajmAFvkop6igZfcmEA3MJ9aHpjGiUszDWy0pA99WY7c1ebTom8xQetW2J2OnkrA_UE8Cuy8AhMPvSBQrsFNmBqnttfVlmKzPS3RWBkIpAZIie1XMGk76nDEXgEsBulEhmYO2Mc-oRfirQfGmYfD1ybYBs9gAKgzQixTrkJtOuRU4GjkwQpxuyeVuww8Pin19IzAlVpUdeEJPVlRHwQDNJ__YsZDJB6rSIaY4tM4ysSs3N-1mmYvkVs1WSa0uy14KRheqMIPfsw_KxLBvp2_ZdZeQIrW3dDxgOuxXWip-g78desyONwwkx0bQK-JDcELHEH0TVmTOe4mSqW1fPI6jJI_ZChmQwBxZKpp2RN2xKmw6W3z4ETdUQDTZgePEkXDveneltNHrGT73WJQ7uEs6hwfXwD2vGcuFx6DKybfYAzgWh9t4IM3mBI7OiGqDItigqIDgaBF6LPTXwby3VxgfEVXXqXzMVdc0BL4da1BPGF-lAtvVJtbpBp7_O_JlB1wWajv8eLCpKjRiKGQey7oLZyRROQ3loNFyRDBjoBVSa2etCmFRCV1wegIBqmJRImJQxPsIV_kkIxeWmPfUIik1GpSTtrWkAFCXZAl4oSFiNhLwlmW_g_s_glGeqcZBNAkiw-OlssPESmqLti-bSJPbmoJMNE0poJXCYX27YyPKVyCtJKM5pzOkUBqMIVsxliU4N2IaWHb8uMYKW8U0tQ8aaeR3Bf5ll0fza78aY3lSQw7At21XkN9LhugzWv-_CPGZQpStGCWtJl5dChLPlmZbRddmekp7UEfXAPW6ONyNrFZ9WUvBCwsdmXcChTXwkg-FIMFHpU25c6IwWqyveuZrQmpvZYEQSgyWhsUBMPywI1vqiLfuhnaqBNU9wPbGA0IrG-w9UGpQErl9ssqPdZRjaIbiM-PKKooehp34QzU3ENj5h944gC4yHMkMzOPUaFl8YUWwmkGCsTNnJyq7NLucTOdQSUsLM2QWEkxWk9c6YyQkwx2mUsR1eGmrsbo8BGK6ppbgotpzMjGZfPOQRdHYh0lzGQ28HGetJ97Vei8Vxxl2u4j6CfHTPET4EHZ_uTuPtRIaaMegKOtUgyKqKj4BqsB5tatIECz8N1H_LP5qlRvUxYqrU-JikuRCoAdfl7VFYLLhe_80cny2UoWFpJ1iovprnALDbIIKZ03LG0OXI8dfEolQijO1xhwoUb7Ci3Xma-wKyEWHhSw0e600SRT0RhDuOh5hVg4KVLILUDDuMIJQyiPRBW3qwAMCk1SzCeXvFqbWFU-TQnVoLGNboaygQ6aumgP_B4DBcmEdyVqAMHIOdAPENvLauALKSiBHVjEHgeB7KpVCGsIGOjdCgb4UmKdsxnXBxC7peXspcmGgmHL-VU6KdMhwHwq1mYeNVEzeshb5mWYj5fgysp_e5U--geYKefs5Y',
|
||||
};
|
||||
|
||||
console.log('提取的密钥信息:');
|
||||
console.log('私钥长度:', extractedKeys.decryptionKey.length);
|
||||
console.log('公钥长度:', extractedKeys.encryptionKey.length);
|
||||
@ -1,23 +0,0 @@
|
||||
import { x25519 } from '@noble/curves/ed25519';
|
||||
|
||||
const toB64Url = (u8: Uint8Array) =>
|
||||
(typeof Buffer !== 'undefined'
|
||||
? Buffer.from(u8).toString('base64')
|
||||
: btoa(String.fromCharCode(...u8))
|
||||
)
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/g, '');
|
||||
|
||||
export type VlessX25519Pair = {
|
||||
passwordB64: string;
|
||||
privateKeyB64: string;
|
||||
};
|
||||
|
||||
export function generateVlessX25519Pair(): VlessX25519Pair {
|
||||
const { secretKey, publicKey } = x25519.keygen();
|
||||
return {
|
||||
passwordB64: toB64Url(publicKey),
|
||||
privateKeyB64: toB64Url(secretKey),
|
||||
};
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
import { x25519 } from '@noble/curves/ed25519.js';
|
||||
|
||||
function toB64Url(bytes: Uint8Array) {
|
||||
return btoa(String.fromCharCode(...bytes))
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/g, '');
|
||||
}
|
||||
function fromB64Url(s: string) {
|
||||
const b64 = s
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/')
|
||||
.padEnd(Math.ceil(s.length / 4) * 4, '=');
|
||||
const bin = atob(b64);
|
||||
return new Uint8Array([...bin].map((c) => c.charCodeAt(0)));
|
||||
}
|
||||
/**
|
||||
* Generate a Reality key pair
|
||||
* @returns An object containing the private and public keys in base64url format
|
||||
*/
|
||||
export function generateRealityKeyPair() {
|
||||
const { secretKey, publicKey } = x25519.keygen();
|
||||
return { privateKey: toB64Url(secretKey), publicKey: toB64Url(publicKey) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive public key from private key
|
||||
* @param privateKeyB64Url Private key in base64url format
|
||||
* @returns Public key in base64url format
|
||||
*/
|
||||
export function publicKeyFromPrivate(privateKeyB64Url: string) {
|
||||
return toB64Url(x25519.getPublicKey(fromB64Url(privateKeyB64Url)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a short ID for Reality
|
||||
* @returns A random hexadecimal string of length 2, 4, 6, 8, 10, 12, 14, or 16
|
||||
*/
|
||||
export function generateRealityShortId() {
|
||||
const hex = '0123456789abcdef';
|
||||
const lengths = [2, 4, 6, 8, 10, 12, 14, 16];
|
||||
const idx = Math.floor(Math.random() * lengths.length);
|
||||
const len = lengths[idx] ?? 16;
|
||||
let out = '';
|
||||
for (let i = 0; i < len; i++) {
|
||||
out += hex.charAt(Math.floor(Math.random() * hex.length));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
15
apps/admin/app/dashboard/servers/generate/short-id.ts
Normal file
15
apps/admin/app/dashboard/servers/generate/short-id.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Generate a short ID for Reality
|
||||
* @returns A random hexadecimal string of length 2, 4, 6, 8, 10, 12, 14, or 16
|
||||
*/
|
||||
export function generateRealityShortId() {
|
||||
const hex = '0123456789abcdef';
|
||||
const lengths = [2, 4, 6, 8, 10, 12, 14, 16];
|
||||
const idx = Math.floor(Math.random() * lengths.length);
|
||||
const len = lengths[idx] ?? 16;
|
||||
let out = '';
|
||||
for (let i = 0; i < len; i++) {
|
||||
out += hex.charAt(Math.floor(Math.random() * hex.length));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
6
apps/admin/app/dashboard/servers/generate/util.ts
Normal file
6
apps/admin/app/dashboard/servers/generate/util.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export function toB64Url(bytes: Uint8Array) {
|
||||
return btoa(String.fromCharCode(...bytes))
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/g, '');
|
||||
}
|
||||
11
apps/admin/app/dashboard/servers/generate/x25519.ts
Normal file
11
apps/admin/app/dashboard/servers/generate/x25519.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { x25519 } from '@noble/curves/ed25519';
|
||||
import { toB64Url } from './util';
|
||||
|
||||
/**
|
||||
* Generate a Reality key pair
|
||||
* @returns An object containing the private and public keys in base64url format
|
||||
*/
|
||||
export function generateRealityKeyPair() {
|
||||
const { secretKey, publicKey } = x25519.keygen();
|
||||
return { privateKey: toB64Url(secretKey), publicKey: toB64Url(publicKey) };
|
||||
}
|
||||
@ -18,6 +18,7 @@
|
||||
"ahooks": "^3.9.4",
|
||||
"axios": "^1.11.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"mlkem-wasm": "^0.0.6",
|
||||
"nanoid": "^5.1.5",
|
||||
"next": "^15.5.2",
|
||||
"next-intl": "^3.26.3",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user