Files
CloudSSH/src/ssh/keys.ts
T
IT b95635bdd5 feat: 纯 Cloudflare 架构 Web SSH 工具
- Cloudflare Workers + Durable Objects
- 自实现 SSH 协议引擎(ECDH-P256 + AES-256-GCM)
- 前端:Vite + TypeScript + xterm.js
- 支持密码认证、终端渲染、窗口自适应
2026-06-12 15:09:29 +08:00

62 lines
1.9 KiB
TypeScript

import { SessionKeys } from '../types';
import { concat } from './utils';
export class KeyDerivation {
static async deriveKeys(
sharedSecret: Uint8Array,
exchangeHash: Uint8Array,
sessionID: Uint8Array
): Promise<SessionKeys> {
const ivC2S = await this.expandKey(sharedSecret, exchangeHash, 'A', sessionID, 12);
const ivS2C = await this.expandKey(sharedSecret, exchangeHash, 'B', sessionID, 12);
const keyC2S = await this.expandKey(sharedSecret, exchangeHash, 'C', sessionID, 32);
const keyS2C = await this.expandKey(sharedSecret, exchangeHash, 'D', sessionID, 32);
const intKeyC2S = await this.expandKey(sharedSecret, exchangeHash, 'E', sessionID, 32);
const intKeyS2C = await this.expandKey(sharedSecret, exchangeHash, 'F', sessionID, 32);
return {
ivClientToServer: ivC2S,
ivServerToClient: ivS2C,
encKeyClientToServer: keyC2S,
encKeyServerToClient: keyS2C,
integrityKeyC2S: intKeyC2S,
integrityKeyS2C: intKeyS2C,
sessionID,
};
}
private static async expandKey(
K: Uint8Array,
H: Uint8Array,
X: string,
sessionId: Uint8Array,
needed: number
): Promise<Uint8Array> {
const hashLen = 32;
const rounds = Math.ceil(needed / hashLen);
const result = new Uint8Array(needed);
let offset = 0;
let key = new Uint8Array(
await crypto.subtle.digest('SHA-256',
concat(K, H, new TextEncoder().encode(X), sessionId)
)
);
result.set(key.slice(0, Math.min(hashLen, needed)), 0);
offset += hashLen;
for (let i = 1; i < rounds; i++) {
key = new Uint8Array(
await crypto.subtle.digest('SHA-256',
concat(K, H, key, sessionId)
)
);
const remaining = needed - offset;
result.set(key.slice(0, Math.min(hashLen, remaining)), offset);
offset += hashLen;
}
return result;
}
}