shogun-core 6.2.3 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_ed448_js.shogun-core.js +93 -341
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_ed448_js.shogun-core.js.map +1 -1
- package/dist/browser/shogun-core.js +138850 -146638
- package/dist/browser/shogun-core.js.map +1 -1
- package/dist/{core.js → src/core.js} +167 -107
- package/dist/src/crypto/asymmetric.js +168 -0
- package/dist/src/crypto/double-ratchet.js +908 -0
- package/dist/src/crypto/file-encryption.js +352 -0
- package/dist/src/crypto/hashing.js +160 -0
- package/dist/src/crypto/index.js +18 -0
- package/dist/{crypto → src/crypto}/mls-codec.js +24 -34
- package/dist/src/crypto/mls.js +734 -0
- package/dist/src/crypto/pgp.js +619 -0
- package/dist/{crypto → src/crypto}/random-generation.js +125 -103
- package/dist/src/crypto/sframe.js +466 -0
- package/dist/src/crypto/signal-protocol.js +943 -0
- package/dist/src/crypto/symmetric.js +165 -0
- package/dist/src/crypto/utils.js +220 -0
- package/dist/src/examples/auth-test.js +535 -0
- package/dist/src/examples/crypto-identity-example.js +294 -0
- package/dist/src/examples/crypto-working-test.js +149 -0
- package/dist/src/examples/double-ratchet-test.js +240 -0
- package/dist/src/examples/mls-3-member-test.js +183 -0
- package/dist/src/examples/mls-multi-member.js +439 -0
- package/dist/src/examples/mls-sframe-test.js +491 -0
- package/dist/src/examples/mls-simple-test.js +122 -0
- package/dist/src/examples/pgp-example.js +354 -0
- package/dist/src/examples/random-generation-test.js +191 -0
- package/dist/src/examples/shogun-core-example.js +204 -0
- package/dist/src/examples/signal-protocol-test.js +82 -0
- package/dist/src/examples/zkproof-credentials-example.js +357 -0
- package/dist/src/examples/zkproof-example.js +357 -0
- package/dist/src/gundb/crypto.js +420 -0
- package/dist/src/gundb/db.js +728 -0
- package/dist/src/gundb/derive.js +327 -0
- package/dist/src/gundb/errors.js +115 -0
- package/dist/src/gundb/gun-es.js +8 -0
- package/dist/src/gundb/index.js +5 -0
- package/dist/{gundb → src/gundb}/rxjs.js +147 -111
- package/dist/{gundb → src/gundb}/types.js +1 -2
- package/dist/src/index.js +19 -0
- package/dist/src/interfaces/events.js +57 -0
- package/dist/{interfaces → src/interfaces}/shogun.js +4 -7
- package/dist/src/managers/AuthManager.js +301 -0
- package/dist/src/managers/CoreInitializer.js +304 -0
- package/dist/src/managers/CryptoIdentityManager.js +230 -0
- package/dist/{managers → src/managers}/EventManager.js +19 -21
- package/dist/{managers → src/managers}/PluginManager.js +123 -89
- package/dist/src/plugins/base.js +90 -0
- package/dist/src/plugins/index.js +17 -0
- package/dist/src/plugins/nostr/index.js +4 -0
- package/dist/src/plugins/nostr/nostrConnector.js +539 -0
- package/dist/src/plugins/nostr/nostrConnectorPlugin.js +663 -0
- package/dist/src/plugins/nostr/nostrSigner.js +414 -0
- package/dist/src/plugins/smartwallet/index.js +2 -0
- package/dist/src/plugins/smartwallet/smartWalletPlugin.js +824 -0
- package/dist/src/plugins/web3/index.js +4 -0
- package/dist/src/plugins/web3/types.js +1 -0
- package/dist/src/plugins/web3/web3Connector.js +738 -0
- package/dist/src/plugins/web3/web3ConnectorPlugin.js +639 -0
- package/dist/src/plugins/web3/web3Signer.js +432 -0
- package/dist/src/plugins/webauthn/index.js +3 -0
- package/dist/{plugins → src/plugins}/webauthn/types.js +2 -5
- package/dist/src/plugins/webauthn/webauthn.js +647 -0
- package/dist/src/plugins/webauthn/webauthnPlugin.js +689 -0
- package/dist/src/plugins/webauthn/webauthnSigner.js +419 -0
- package/dist/{plugins → src/plugins}/zkproof/index.js +3 -10
- package/dist/src/plugins/zkproof/types.js +1 -0
- package/dist/src/plugins/zkproof/zkCredentials.js +287 -0
- package/dist/src/plugins/zkproof/zkProofConnector.js +267 -0
- package/dist/src/plugins/zkproof/zkProofPlugin.js +405 -0
- package/dist/src/storage/storage.js +189 -0
- package/dist/src/utils/errorHandler.js +339 -0
- package/dist/{utils → src/utils}/eventEmitter.js +26 -26
- package/dist/{utils → src/utils}/seedPhrase.js +23 -32
- package/dist/{utils → src/utils}/validation.js +14 -21
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/{crypto → src/crypto}/double-ratchet.d.ts +1 -1
- package/dist/types/{crypto → src/crypto}/signal-protocol.d.ts +25 -0
- package/dist/types/{crypto → src/crypto}/types.d.ts +3 -1
- package/dist/types/src/examples/crypto-working-test.d.ts +1 -0
- package/dist/types/src/examples/double-ratchet-test.d.ts +1 -0
- package/dist/types/src/examples/mls-sframe-test.d.ts +1 -0
- package/dist/types/src/examples/random-generation-test.d.ts +1 -0
- package/dist/types/src/examples/signal-protocol-test.d.ts +1 -0
- package/dist/types/{gundb → src/gundb}/db.d.ts +14 -1
- package/dist/types/src/gundb/gun-es.d.ts +8 -0
- package/dist/types/src/gundb/min.d.ts +3 -0
- package/dist/types/{index.d.ts → src/index.d.ts} +1 -0
- package/package.json +14 -11
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_abstract_curve_js-node_modules_noble_curves_esm_-1ce4ed.shogun-core.js +0 -1651
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_abstract_curve_js-node_modules_noble_curves_esm_-1ce4ed.shogun-core.js.map +0 -1
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_nist_js.shogun-core.js +0 -1608
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_nist_js.shogun-core.js.map +0 -1
- package/dist/crypto/asymmetric.js +0 -99
- package/dist/crypto/double-ratchet.js +0 -370
- package/dist/crypto/file-encryption.js +0 -213
- package/dist/crypto/hashing.js +0 -87
- package/dist/crypto/index.js +0 -34
- package/dist/crypto/mls.js +0 -569
- package/dist/crypto/pgp.js +0 -390
- package/dist/crypto/sframe.js +0 -352
- package/dist/crypto/signal-protocol.js +0 -456
- package/dist/crypto/symmetric.js +0 -91
- package/dist/crypto/types.js +0 -2
- package/dist/crypto/utils.js +0 -140
- package/dist/examples/auth-test.js +0 -453
- package/dist/examples/crypto-identity-example.js +0 -196
- package/dist/examples/crypto-working-test.js +0 -83
- package/dist/examples/double-ratchet-test.js +0 -155
- package/dist/examples/mls-3-member-test.js +0 -97
- package/dist/examples/mls-multi-member.js +0 -153
- package/dist/examples/mls-sframe-test.js +0 -307
- package/dist/examples/mls-simple-test.js +0 -58
- package/dist/examples/pgp-example.js +0 -200
- package/dist/examples/random-generation-test.js +0 -151
- package/dist/examples/shogun-core-example.js +0 -150
- package/dist/examples/signal-protocol-test.js +0 -38
- package/dist/examples/zkproof-credentials-example.js +0 -217
- package/dist/examples/zkproof-example.js +0 -242
- package/dist/gundb/crypto.js +0 -306
- package/dist/gundb/db.js +0 -485
- package/dist/gundb/derive.js +0 -232
- package/dist/gundb/errors.js +0 -76
- package/dist/gundb/gun-es.js +0 -12
- package/dist/gundb/index.js +0 -21
- package/dist/gundb/min.js +0 -10
- package/dist/index.esm.js +0 -22
- package/dist/index.js +0 -47
- package/dist/interfaces/common.js +0 -2
- package/dist/interfaces/events.js +0 -40
- package/dist/interfaces/plugin.js +0 -2
- package/dist/managers/AuthManager.js +0 -226
- package/dist/managers/CoreInitializer.js +0 -250
- package/dist/managers/CryptoIdentityManager.js +0 -138
- package/dist/plugins/base.js +0 -50
- package/dist/plugins/index.js +0 -32
- package/dist/plugins/nostr/index.js +0 -20
- package/dist/plugins/nostr/nostrConnector.js +0 -419
- package/dist/plugins/nostr/nostrConnectorPlugin.js +0 -453
- package/dist/plugins/nostr/nostrSigner.js +0 -319
- package/dist/plugins/nostr/types.js +0 -2
- package/dist/plugins/smartwallet/index.js +0 -18
- package/dist/plugins/smartwallet/smartWalletPlugin.js +0 -511
- package/dist/plugins/smartwallet/types.js +0 -2
- package/dist/plugins/web3/index.js +0 -20
- package/dist/plugins/web3/types.js +0 -2
- package/dist/plugins/web3/web3Connector.js +0 -533
- package/dist/plugins/web3/web3ConnectorPlugin.js +0 -455
- package/dist/plugins/web3/web3Signer.js +0 -314
- package/dist/plugins/webauthn/index.js +0 -19
- package/dist/plugins/webauthn/webauthn.js +0 -496
- package/dist/plugins/webauthn/webauthnPlugin.js +0 -490
- package/dist/plugins/webauthn/webauthnSigner.js +0 -310
- package/dist/plugins/zkproof/types.js +0 -2
- package/dist/plugins/zkproof/zkCredentials.js +0 -216
- package/dist/plugins/zkproof/zkProofConnector.js +0 -198
- package/dist/plugins/zkproof/zkProofPlugin.js +0 -272
- package/dist/storage/storage.js +0 -145
- package/dist/types/gundb/gun-es.d.ts +0 -8
- package/dist/utils/errorHandler.js +0 -246
- /package/dist/{types/examples/crypto-working-test.d.ts → src/crypto/types.js} +0 -0
- /package/dist/{types/gundb/min.d.ts → src/gundb/min.js} +0 -0
- /package/dist/{types/examples/double-ratchet-test.d.ts → src/interfaces/common.js} +0 -0
- /package/dist/{types/examples/mls-sframe-test.d.ts → src/interfaces/plugin.js} +0 -0
- /package/dist/{types/examples/random-generation-test.d.ts → src/plugins/nostr/types.js} +0 -0
- /package/dist/{types/examples/signal-protocol-test.d.ts → src/plugins/smartwallet/types.js} +0 -0
- /package/dist/types/{core.d.ts → src/core.d.ts} +0 -0
- /package/dist/types/{crypto → src/crypto}/asymmetric.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/file-encryption.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/hashing.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/index.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/mls-codec.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/mls.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/pgp.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/random-generation.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/sframe.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/symmetric.d.ts +0 -0
- /package/dist/types/{crypto → src/crypto}/utils.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/auth-test.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/crypto-identity-example.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/mls-3-member-test.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/mls-multi-member.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/mls-simple-test.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/pgp-example.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/shogun-core-example.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/zkproof-credentials-example.d.ts +0 -0
- /package/dist/types/{examples → src/examples}/zkproof-example.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/crypto.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/derive.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/errors.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/index.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/rxjs.d.ts +0 -0
- /package/dist/types/{gundb → src/gundb}/types.d.ts +0 -0
- /package/dist/types/{interfaces → src/interfaces}/common.d.ts +0 -0
- /package/dist/types/{interfaces → src/interfaces}/events.d.ts +0 -0
- /package/dist/types/{interfaces → src/interfaces}/plugin.d.ts +0 -0
- /package/dist/types/{interfaces → src/interfaces}/shogun.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/AuthManager.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/CoreInitializer.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/CryptoIdentityManager.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/EventManager.d.ts +0 -0
- /package/dist/types/{managers → src/managers}/PluginManager.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/base.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/nostrConnector.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/nostrConnectorPlugin.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/nostrSigner.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/nostr/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/smartwallet/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/smartwallet/smartWalletPlugin.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/smartwallet/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/web3Connector.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/web3ConnectorPlugin.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/web3/web3Signer.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/webauthn.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/webauthnPlugin.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/webauthn/webauthnSigner.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/zkproof/index.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/zkproof/types.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/zkproof/zkCredentials.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/zkproof/zkProofConnector.d.ts +0 -0
- /package/dist/types/{plugins → src/plugins}/zkproof/zkProofPlugin.d.ts +0 -0
- /package/dist/types/{storage → src/storage}/storage.d.ts +0 -0
- /package/dist/types/{utils → src/utils}/errorHandler.d.ts +0 -0
- /package/dist/types/{utils → src/utils}/eventEmitter.d.ts +0 -0
- /package/dist/types/{utils → src/utils}/seedPhrase.d.ts +0 -0
- /package/dist/types/{utils → src/utils}/validation.d.ts +0 -0
package/dist/crypto/sframe.js
DELETED
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* SFrame (Secure Frame) Manager
|
|
4
|
-
* End-to-end encryption for real-time media frames (audio/video)
|
|
5
|
-
* Designed for low overhead and high performance
|
|
6
|
-
*
|
|
7
|
-
* SFrame adds ~10 bytes per frame overhead
|
|
8
|
-
* Compatible with WebRTC Insertable Streams API
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.SFrameManager = void 0;
|
|
12
|
-
class SFrameManager {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.keys = new Map();
|
|
15
|
-
this.currentKeyId = 0;
|
|
16
|
-
this.frameCounter = 0;
|
|
17
|
-
this.initialized = false;
|
|
18
|
-
console.log("🎥 [SFrame] Manager created");
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Initialize the SFrame manager
|
|
22
|
-
*/
|
|
23
|
-
async initialize() {
|
|
24
|
-
if (this.initialized) {
|
|
25
|
-
console.warn("[SFrame] Already initialized");
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
console.log("🔐 [SFrame] Initializing...");
|
|
30
|
-
// Generate initial key
|
|
31
|
-
await this.generateKey(0);
|
|
32
|
-
this.initialized = true;
|
|
33
|
-
console.log("✅ [SFrame] Initialized successfully");
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
console.error("❌ [SFrame] Initialization failed:", error);
|
|
37
|
-
throw new Error(`SFrame initialization failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Generate a new SFrame encryption key
|
|
42
|
-
*/
|
|
43
|
-
async generateKey(keyId) {
|
|
44
|
-
try {
|
|
45
|
-
console.log(`🔑 [SFrame] Generating key ${keyId}...`);
|
|
46
|
-
// Generate AES-GCM key (128-bit for low overhead)
|
|
47
|
-
const key = await crypto.subtle.generateKey({
|
|
48
|
-
name: "AES-GCM",
|
|
49
|
-
length: 128, // 128-bit for performance, 256-bit for maximum security
|
|
50
|
-
}, false, // Not extractable for security
|
|
51
|
-
["encrypt", "decrypt"]);
|
|
52
|
-
// Generate salt for key derivation
|
|
53
|
-
const salt = crypto.getRandomValues(new Uint8Array(16));
|
|
54
|
-
const sframeKey = {
|
|
55
|
-
keyId,
|
|
56
|
-
key,
|
|
57
|
-
salt,
|
|
58
|
-
};
|
|
59
|
-
this.keys.set(keyId, sframeKey);
|
|
60
|
-
console.log(`✅ [SFrame] Key ${keyId} generated`);
|
|
61
|
-
return sframeKey;
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
console.error(`❌ [SFrame] Key generation failed:`, error);
|
|
65
|
-
throw new Error(`SFrame key generation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Derive an SFrame key from MLS shared secret
|
|
70
|
-
* This allows SFrame to use keys derived from MLS for media encryption
|
|
71
|
-
* RFC 9605 Section 5.2: MLS-based key management
|
|
72
|
-
*/
|
|
73
|
-
async deriveKeyFromMLSSecret(mlsSecret, keyId, context = "SFrame") {
|
|
74
|
-
try {
|
|
75
|
-
console.log(`🔗 [SFrame] Deriving key ${keyId} from MLS secret (RFC 9605 Section 5.2)...`);
|
|
76
|
-
// RFC 9605 Section 5.2: Use specific labels for MLS-based derivation
|
|
77
|
-
const secretLabel = new TextEncoder().encode("SFrame 1.0 Secret");
|
|
78
|
-
const saltLabel = new TextEncoder().encode("SFrame 1.0 Salt");
|
|
79
|
-
// Import MLS secret as key material
|
|
80
|
-
const baseKey = await crypto.subtle.importKey("raw", mlsSecret, "HKDF", false, ["deriveKey", "deriveBits"]);
|
|
81
|
-
// Derive salt using HKDF (RFC 9605)
|
|
82
|
-
const derivedSaltBits = await crypto.subtle.deriveBits({
|
|
83
|
-
name: "HKDF",
|
|
84
|
-
hash: "SHA-256",
|
|
85
|
-
salt: new Uint8Array(0), // Empty salt for salt derivation
|
|
86
|
-
info: saltLabel,
|
|
87
|
-
}, baseKey, 128);
|
|
88
|
-
const salt = new Uint8Array(derivedSaltBits);
|
|
89
|
-
// Derive AES-GCM key using HKDF with RFC 9605 label
|
|
90
|
-
const key = await crypto.subtle.deriveKey({
|
|
91
|
-
name: "HKDF",
|
|
92
|
-
hash: "SHA-256",
|
|
93
|
-
salt: new Uint8Array(0), // Empty salt for key derivation
|
|
94
|
-
info: secretLabel,
|
|
95
|
-
}, baseKey, {
|
|
96
|
-
name: "AES-GCM",
|
|
97
|
-
length: 128,
|
|
98
|
-
}, false, ["encrypt", "decrypt"]);
|
|
99
|
-
const sframeKey = {
|
|
100
|
-
keyId,
|
|
101
|
-
key,
|
|
102
|
-
salt,
|
|
103
|
-
};
|
|
104
|
-
this.keys.set(keyId, sframeKey);
|
|
105
|
-
console.log(`✅ [SFrame] Key ${keyId} derived from MLS (RFC 9605 compliant)`);
|
|
106
|
-
return sframeKey;
|
|
107
|
-
}
|
|
108
|
-
catch (error) {
|
|
109
|
-
console.error(`❌ [SFrame] Key derivation failed:`, error);
|
|
110
|
-
throw new Error(`SFrame key derivation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Set a shared SFrame key (e.g., from another member)
|
|
115
|
-
*/
|
|
116
|
-
async setSharedKey(sframeKey) {
|
|
117
|
-
this.keys.set(sframeKey.keyId, sframeKey);
|
|
118
|
-
console.log(`✅ [SFrame] Shared key ${sframeKey.keyId} set.`);
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Set the active encryption key
|
|
122
|
-
*/
|
|
123
|
-
setActiveKey(keyId) {
|
|
124
|
-
if (!this.keys.has(keyId)) {
|
|
125
|
-
throw new Error(`SFrame key ${keyId} not found`);
|
|
126
|
-
}
|
|
127
|
-
this.currentKeyId = keyId;
|
|
128
|
-
console.log(`🔄 [SFrame] Active key set to ${keyId}`);
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Encrypt a media frame using SFrame
|
|
132
|
-
*/
|
|
133
|
-
async encryptFrame(frameData) {
|
|
134
|
-
this.ensureInitialized();
|
|
135
|
-
try {
|
|
136
|
-
const sframeKey = this.keys.get(this.currentKeyId);
|
|
137
|
-
if (!sframeKey) {
|
|
138
|
-
throw new Error(`SFrame key ${this.currentKeyId} not found`);
|
|
139
|
-
}
|
|
140
|
-
// RFC 9605: IV = salt XOR counter
|
|
141
|
-
// Generate counter bytes (96-bit/12-byte)
|
|
142
|
-
const counterBytes = new Uint8Array(12);
|
|
143
|
-
const counterView = new DataView(counterBytes.buffer);
|
|
144
|
-
// Store frame counter in last 8 bytes (big-endian uint64-like)
|
|
145
|
-
counterView.setUint32(4, Math.floor(this.frameCounter / 0x100000000), false);
|
|
146
|
-
counterView.setUint32(8, this.frameCounter & 0xffffffff, false);
|
|
147
|
-
// SFrame header: 1 byte for key ID + frame counter encoding
|
|
148
|
-
// Simplified header: 1 byte key ID + 4 bytes frame counter
|
|
149
|
-
const header = new Uint8Array(5);
|
|
150
|
-
header[0] = this.currentKeyId;
|
|
151
|
-
new DataView(header.buffer).setUint32(1, this.frameCounter, false);
|
|
152
|
-
// XOR salt with counter to create IV (RFC 9605 Section 4.3)
|
|
153
|
-
const iv = new Uint8Array(12);
|
|
154
|
-
for (let i = 0; i < 12; i++) {
|
|
155
|
-
iv[i] = sframeKey.salt[i] ^ counterBytes[i];
|
|
156
|
-
}
|
|
157
|
-
// Encrypt the frame with header authentication (RFC 9605 Section 4.3)
|
|
158
|
-
const ciphertext = await crypto.subtle.encrypt({
|
|
159
|
-
name: "AES-GCM",
|
|
160
|
-
iv,
|
|
161
|
-
additionalData: header, // RFC 9605: Header included in AAD
|
|
162
|
-
tagLength: 128, // 128-bit authentication tag
|
|
163
|
-
}, sframeKey.key, frameData);
|
|
164
|
-
// RFC 9605: SFrame format = header + ciphertext (IV is derived, not transmitted)
|
|
165
|
-
const encrypted = new Uint8Array(header.length + ciphertext.byteLength);
|
|
166
|
-
encrypted.set(header, 0);
|
|
167
|
-
encrypted.set(new Uint8Array(ciphertext), header.length);
|
|
168
|
-
// Increment frame counter
|
|
169
|
-
this.frameCounter++;
|
|
170
|
-
return encrypted;
|
|
171
|
-
}
|
|
172
|
-
catch (error) {
|
|
173
|
-
console.error("❌ [SFrame] Frame encryption failed:", error);
|
|
174
|
-
throw new Error(`SFrame encryption failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Decrypt a media frame using SFrame
|
|
179
|
-
*/
|
|
180
|
-
async decryptFrame(encryptedFrame) {
|
|
181
|
-
this.ensureInitialized();
|
|
182
|
-
try {
|
|
183
|
-
// Parse SFrame header (5 bytes: 1 byte key ID + 4 bytes frame counter)
|
|
184
|
-
const header = encryptedFrame.slice(0, 5);
|
|
185
|
-
const keyId = header[0];
|
|
186
|
-
const frameCount = new DataView(header.buffer, header.byteOffset).getUint32(1, false);
|
|
187
|
-
// Get the key
|
|
188
|
-
const sframeKey = this.keys.get(keyId);
|
|
189
|
-
if (!sframeKey) {
|
|
190
|
-
throw new Error(`SFrame key ${keyId} not found`);
|
|
191
|
-
}
|
|
192
|
-
// RFC 9605: IV is derived from frame count and salt (not transmitted)
|
|
193
|
-
const counterBytes = new Uint8Array(12);
|
|
194
|
-
const counterView = new DataView(counterBytes.buffer);
|
|
195
|
-
counterView.setUint32(4, Math.floor(frameCount / 0x100000000), false);
|
|
196
|
-
counterView.setUint32(8, frameCount & 0xffffffff, false);
|
|
197
|
-
const iv = new Uint8Array(12);
|
|
198
|
-
for (let i = 0; i < 12; i++) {
|
|
199
|
-
iv[i] = sframeKey.salt[i] ^ counterBytes[i];
|
|
200
|
-
}
|
|
201
|
-
// Extract ciphertext (rest of the data)
|
|
202
|
-
const ciphertext = encryptedFrame.slice(header.length);
|
|
203
|
-
// Decrypt the frame with header authentication (RFC 9605 Section 4.3)
|
|
204
|
-
const plaintext = await crypto.subtle.decrypt({
|
|
205
|
-
name: "AES-GCM",
|
|
206
|
-
iv,
|
|
207
|
-
additionalData: header, // RFC 9605: Header included in AAD
|
|
208
|
-
tagLength: 128,
|
|
209
|
-
}, sframeKey.key, ciphertext);
|
|
210
|
-
return plaintext;
|
|
211
|
-
}
|
|
212
|
-
catch (error) {
|
|
213
|
-
console.error("❌ [SFrame] Frame decryption failed:", error);
|
|
214
|
-
throw new Error(`SFrame decryption failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Encrypt transform function for Insertable Streams
|
|
219
|
-
* Use this with RTCRtpSender.createEncodedStreams()
|
|
220
|
-
*/
|
|
221
|
-
createEncryptTransform() {
|
|
222
|
-
const manager = this;
|
|
223
|
-
return new TransformStream({
|
|
224
|
-
async transform(encodedFrame, controller) {
|
|
225
|
-
try {
|
|
226
|
-
// Get frame data
|
|
227
|
-
const frameData = encodedFrame.data;
|
|
228
|
-
// Encrypt the frame
|
|
229
|
-
const encrypted = await manager.encryptFrame(frameData);
|
|
230
|
-
// Create new encoded frame with encrypted data
|
|
231
|
-
encodedFrame.data = encrypted.buffer;
|
|
232
|
-
// Forward the encrypted frame
|
|
233
|
-
controller.enqueue(encodedFrame);
|
|
234
|
-
}
|
|
235
|
-
catch (error) {
|
|
236
|
-
console.error("[SFrame] Encrypt transform error:", error);
|
|
237
|
-
// Forward unencrypted frame on error (fallback)
|
|
238
|
-
controller.enqueue(encodedFrame);
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Decrypt transform function for Insertable Streams
|
|
245
|
-
* Use this with RTCRtpReceiver.createEncodedStreams()
|
|
246
|
-
*/
|
|
247
|
-
createDecryptTransform() {
|
|
248
|
-
const manager = this;
|
|
249
|
-
return new TransformStream({
|
|
250
|
-
async transform(encodedFrame, controller) {
|
|
251
|
-
try {
|
|
252
|
-
// Get encrypted frame data
|
|
253
|
-
const encryptedData = new Uint8Array(encodedFrame.data);
|
|
254
|
-
// Decrypt the frame
|
|
255
|
-
const decrypted = await manager.decryptFrame(encryptedData);
|
|
256
|
-
// Create new encoded frame with decrypted data
|
|
257
|
-
encodedFrame.data = decrypted;
|
|
258
|
-
// Forward the decrypted frame
|
|
259
|
-
controller.enqueue(encodedFrame);
|
|
260
|
-
}
|
|
261
|
-
catch (error) {
|
|
262
|
-
console.error("[SFrame] Decrypt transform error:", error);
|
|
263
|
-
// Skip frame on decryption error
|
|
264
|
-
// (better to drop frame than show corrupted video)
|
|
265
|
-
}
|
|
266
|
-
},
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Rotate encryption keys
|
|
271
|
-
* RFC 9605: Frame counter should be reset on key rotation to prevent exhaustion
|
|
272
|
-
*/
|
|
273
|
-
async rotateKey() {
|
|
274
|
-
try {
|
|
275
|
-
const newKeyId = this.currentKeyId + 1;
|
|
276
|
-
console.log(`🔄 [SFrame] Rotating to key ${newKeyId}...`);
|
|
277
|
-
await this.generateKey(newKeyId);
|
|
278
|
-
this.setActiveKey(newKeyId);
|
|
279
|
-
// RFC 9605: Reset frame counter on key rotation
|
|
280
|
-
this.resetFrameCounter();
|
|
281
|
-
console.log(`🔄 [SFrame] Frame counter reset to 0 for new key`);
|
|
282
|
-
console.log(`✅ [SFrame] Key rotated to ${newKeyId}`);
|
|
283
|
-
return newKeyId;
|
|
284
|
-
}
|
|
285
|
-
catch (error) {
|
|
286
|
-
console.error("❌ [SFrame] Key rotation failed:", error);
|
|
287
|
-
throw new Error(`SFrame key rotation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Get current key ID
|
|
292
|
-
*/
|
|
293
|
-
getCurrentKeyId() {
|
|
294
|
-
return this.currentKeyId;
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Get frame counter (for debugging)
|
|
298
|
-
*/
|
|
299
|
-
getFrameCounter() {
|
|
300
|
-
return this.frameCounter;
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Reset frame counter (use when rotating keys)
|
|
304
|
-
*/
|
|
305
|
-
resetFrameCounter() {
|
|
306
|
-
this.frameCounter = 0;
|
|
307
|
-
console.log("🔄 [SFrame] Frame counter reset");
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Remove old keys to prevent memory bloat
|
|
311
|
-
*/
|
|
312
|
-
cleanupOldKeys(keepLast = 2) {
|
|
313
|
-
const keyIds = Array.from(this.keys.keys()).sort((a, b) => b - a);
|
|
314
|
-
if (keyIds.length > keepLast) {
|
|
315
|
-
const toDelete = keyIds.slice(keepLast);
|
|
316
|
-
toDelete.forEach((keyId) => {
|
|
317
|
-
this.keys.delete(keyId);
|
|
318
|
-
console.log(`🧹 [SFrame] Deleted old key ${keyId}`);
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Get statistics
|
|
324
|
-
*/
|
|
325
|
-
getStats() {
|
|
326
|
-
return {
|
|
327
|
-
keyCount: this.keys.size,
|
|
328
|
-
currentKeyId: this.currentKeyId,
|
|
329
|
-
frameCounter: this.frameCounter,
|
|
330
|
-
initialized: this.initialized,
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
/**
|
|
334
|
-
* Clean up resources
|
|
335
|
-
*/
|
|
336
|
-
destroy() {
|
|
337
|
-
this.keys.clear();
|
|
338
|
-
this.initialized = false;
|
|
339
|
-
this.frameCounter = 0;
|
|
340
|
-
console.log("✅ [SFrame] Manager destroyed");
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Ensure the manager is initialized
|
|
344
|
-
*/
|
|
345
|
-
ensureInitialized() {
|
|
346
|
-
if (!this.initialized) {
|
|
347
|
-
throw new Error("SFrame Manager not initialized. Call initialize() first.");
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
exports.SFrameManager = SFrameManager;
|
|
352
|
-
exports.default = SFrameManager;
|