43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
/**
|
|
* 仅供测试和调试:把通常不可导出的中间密钥以字节形式导出,用来和测试向量逐字节比对。
|
|
* 正常使用请只依赖主入口。这里的函数会让密钥材料暴露在 JS 变量里,不要在产品代码中使用。
|
|
*/
|
|
|
|
import { Labels } from './constants.js';
|
|
import { utf8, type Bytes } from './bytes.js';
|
|
|
|
export { encodeEnvelope, frameAad, frameIv, padPlaintext, parseEnvelope, sealFrame, tierFor, unpadPlaintext } from './frame.js';
|
|
export { encodeMeta, decodeFirstFrame, planItem } from './item.js';
|
|
export { deriveChannelKeys, deriveItemKey, deriveOwnerToken, sha256 } from './kdf.js';
|
|
|
|
async function hkdfBytes(ikm: Uint8Array, salt: Uint8Array, label: string): Promise<Bytes> {
|
|
const key = await globalThis.crypto.subtle.importKey('raw', ikm as Bytes, 'HKDF', false, ['deriveBits']);
|
|
const bits = await globalThis.crypto.subtle.deriveBits(
|
|
{ name: 'HKDF', hash: 'SHA-256', salt: salt as Bytes, info: utf8(label) },
|
|
key,
|
|
256,
|
|
);
|
|
return new Uint8Array(bits);
|
|
}
|
|
|
|
export interface RawChannelSecrets {
|
|
kEnc: Bytes;
|
|
tRead: Bytes;
|
|
tWrite: Bytes;
|
|
kLabel: Bytes;
|
|
}
|
|
|
|
export async function deriveRawChannelSecrets(channelId: Uint8Array, k: Uint8Array): Promise<RawChannelSecrets> {
|
|
const kEnc = await hkdfBytes(k, channelId, Labels.enc);
|
|
return {
|
|
kEnc,
|
|
tRead: await hkdfBytes(k, channelId, Labels.read),
|
|
tWrite: await hkdfBytes(k, channelId, Labels.write),
|
|
kLabel: await hkdfBytes(kEnc, channelId, Labels.label),
|
|
};
|
|
}
|
|
|
|
export const deriveRawOwnerToken = (channelId: Uint8Array, a: Uint8Array): Promise<Bytes> => hkdfBytes(a, channelId, Labels.owner);
|
|
|
|
export const deriveRawItemKey = (kEnc: Uint8Array, itemId: Uint8Array): Promise<Bytes> => hkdfBytes(kEnc, itemId, Labels.item);
|