Ich implementiere eine Ende-zu-Ende-Verschlüsselung für große Dateien mithilfe von libsodium.js mit crypto_secretstream_xchacha20poly1305. Die Verschlüsselung funktioniert einwandfrei, aber die Entschlüsselung schlägt mit „State konnte nicht initialisiert werden“ fehl.
Der Versuch, den Entschlüsselungsstatus mit crypto_secretstream_xchacha20poly1305_init_pull() zu initialisieren, schlägt fehl, obwohl:
Der Schlüssel ist 32 Bytes (richtige Länge für crypto_secretstream_xchacha20poly1305_KEYBYTES)
/>
Datei Encrypt/Decrypt Test
Datei Encrypt/Decrypt Test
Start Verschlüsselung/Entschlüsselung
const log = (msg) => {
console.log(msg);
const outDiv = document.getElementById("output");
outDiv.innerHTML += msg + "
";
};
const DEBUG_ENCRYPTOR = true; // Setze auf false, wenn kein Logging
class Encryptor {
sodium = null;
key = null;
state = null;
cryptoHeader = null;
encoder = new TextEncoder();
CHUNK_SIZE = 64 * 1024; // 64 KB, kann auf 1MB hochgesetzt werden
constructor(keyString = null) {
this.userKeyString = keyString;
}
async init() {
this.sodium = await SodiumLoader.getInstance();
if (DEBUG_ENCRYPTOR) console.log("Encryptor: Zufälliger Key erzeugt");
this.key = this.sodium.randombytes_buf(this.sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES);
const result = this.sodium.crypto_secretstream_xchacha20poly1305_init_push(this.key);
this.state = result.state;
this.cryptoHeader = result.header;
if (DEBUG_ENCRYPTOR) console.log("Encryptor: Crypto-State initialisiert");
}
__encryptChunk(data) {
return this.sodium.crypto_secretstream_xchacha20poly1305_push(
this.state,
data,
null,
this.sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE
);
}
async __streamFile(file, outputChunks, progressCallback, offsetStart, totalSize) {
if (DEBUG_ENCRYPTOR) console.log(`Encryptor: Verschlüssele Datei ${file.name}, Größe: ${file.size}`);
const reader = file.stream().getReader();
let leftover = new Uint8Array(0);
let processed = 0;
while (true) {
const { value, done } = await reader.read();
if (done) break;
let buffer = new Uint8Array(leftover.length + value.length);
buffer.set(leftover, 0);
buffer.set(value, leftover.length);
let offset = 0;
while (offset + this.CHUNK_SIZE ({ name: f.name, size: f.size }))
}));
const headerLengthBytes = new Uint8Array(4);
new DataView(headerLengthBytes.buffer).setUint32(0, headerBytes.length, false);
const [headerLenFrame, headerLenData] = this.__encryptChunk(headerLengthBytes);
outputChunks.push(headerLenFrame, headerLenData);
const [headerJsonFrameLen, headerJsonFrame] = this.__encryptChunk(headerBytes);
outputChunks.push(headerJsonFrameLen, headerJsonFrame);
// Dateien verschlüsseln
let offsetStart = 0;
for (const file of fileRefs) {
await this.__streamFile(file, outputChunks, progressCallback, offsetStart, totalSize);
offsetStart += file.size;
}
if (DEBUG_ENCRYPTOR) console.log("Encryptor: Verschlüsselung abgeschlossen, Blob erzeugen");
// Blob / File erzeugen
const result = new File(outputChunks, 'container.mycnt', { type: 'application/octet-stream' });
return result;
}
getKey() {
return this.key;
}
getKeyB64() {
return btoa(String.fromCharCode(...this.key));
}
getKeyB64URL() {
return sodium.to_base64(
this.key,
sodium.base64_variants.URLSAFE_NO_PADDING
);
}
}
const DEBUG_DECRYPTOR = true; // Setze auf false, um Logs auszuschalten
class Decryptor {
sodium = null;
key = null;
state = null;
cryptoHeader = null;
decoder = new TextDecoder();
reader = null;
leftover = new Uint8Array(0);
constructor(file, keyInput) {
this.payload = file;
this.keyInput = keyInput; // nur speichern, NICHT dekodieren
}
async init() {
try {
this.sodium = await SodiumLoader.getInstance();
if (typeof this.keyInput === "string") {
this.key = this.sodium.from_base64(
this.keyInput,
this.sodium.base64_variants.URLSAFE_NO_PADDING
);
} else if (this.keyInput instanceof Uint8Array) {
this.key = this.keyInput;
} else {
throw new Error("Key muss Base64URL-String oder Uint8Array sein");
}
const expectedKeyLength = this.sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES;
if (this.key.length !== expectedKeyLength) {
throw new Error(`Falsche Key-Länge: ${this.key.length} Bytes (erwarte ${expectedKeyLength})`);
}
// Header direkt aus File lesen
const headerSize = this.sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES;
const arrayBuffer = await this.payload.slice(0, headerSize).arrayBuffer();
this.cryptoHeader = new Uint8Array(arrayBuffer);
if (DEBUG_DECRYPTOR) console.warn("Decryptor: CryptoHeader: ", this.cryptoHeader);
// Reader starten
this.reader = this.payload.slice(headerSize).stream().getReader();
if (DEBUG_DECRYPTOR) {
console.log("Decryptor: Key bytes:", this.key);
console.log("Decryptor: Header length:", this.cryptoHeader.length);
console.log("Decryptor: Key length:", this.key.length);
}
// State initialisieren
const initResult = this.sodium.crypto_secretstream_xchacha20poly1305_init_pull(
this.cryptoHeader,
this.key
);
if (!initResult || !initResult.state) {
throw new Error("State konnte nicht initialisiert werden");
}
this.state = initResult.state;
if (DEBUG_DECRYPTOR) console.log("Decryptor: Erfolgreich initialisiert");
} catch (error) {
console.error("Decryptor init error:", error);
throw error;
}
}
async readNextFrame() {
const { value, done } = await this.reader.read();
if (done) return null;
return value;
}
async __decryptChunk(chunk) {
if (!chunk || chunk.length === 0) return null;
try {
if (!this.state) throw new Error("State nicht initialisiert");
const result = this.sodium.crypto_secretstream_xchacha20poly1305_pull(this.state, chunk);
i
Die Schlüssellänge beträgt genau 32 Bytes
Die Headerlänge beträgt genau 24 Bytes
Die Schlüsselkodierung/-dekodierung verwendet konsistent URLSAFE_NO_PADDING
Keine Datenbeschädigung bei der Dateiübertragung
Verwendung derselben libsodium.js-Version für beide Vorgänge
libsodium.js (neueste)
Chrome 120+, Firefox 146+
Dateigrößen: 1 MB – 100 MB
Abhängigkeiten:
LibSodium-Version
Was könnte dazu führen, dass crypto_secretstream_xchacha20poly1305_init_pull() selbst bei korrekten Schlüssel- und Headerlängen fehlschlägt? Gibt es häufige Fallstricke bei der Header-Extraktion oder Schlüsseldekodierung, die mir möglicherweise entgangen sind?
Ich implementiere eine Ende-zu-Ende-Verschlüsselung für große Dateien mithilfe von libsodium.js mit crypto_secretstream_xchacha20poly1305. Die Verschlüsselung funktioniert einwandfrei, aber die Entschlüsselung schlägt mit „State konnte nicht initialisiert werden“ fehl. Der Versuch, den Entschlüsselungsstatus mit crypto_secretstream_xchacha20poly1305_init_pull() zu initialisieren, schlägt fehl, obwohl: [list] [*]Der Schlüssel ist 32 Bytes (richtige Länge für crypto_secretstream_xchacha20poly1305_KEYBYTES) />[/list] [code]Encryptor: Crypto Header Uint8Array(24) [ 119, 236, 242, 100, 144, 128, 29, 94, 227, 167, … ]
try { if (!this.state) throw new Error("State nicht initialisiert");
const result = this.sodium.crypto_secretstream_xchacha20poly1305_pull(this.state, chunk); i [/code] [list] [*]Die Schlüssellänge beträgt genau 32 Bytes
[*]Die Headerlänge beträgt genau 24 Bytes
[*]Die Schlüsselkodierung/-dekodierung verwendet konsistent URLSAFE_NO_PADDING
[*]Keine Datenbeschädigung bei der Dateiübertragung
[*]Verwendung derselben libsodium.js-Version für beide Vorgänge
libsodium.js (neueste)
[*]Chrome 120+, Firefox 146+
[*]Dateigrößen: 1 MB – 100 MB
[/list]
Abhängigkeiten: [list] [*]LibSodium-Version [/list] Was könnte dazu führen, dass crypto_secretstream_xchacha20poly1305_init_pull() selbst bei korrekten Schlüssel- und Headerlängen fehlschlägt? Gibt es häufige Fallstricke bei der Header-Extraktion oder Schlüsseldekodierung, die mir möglicherweise entgangen sind?
Ich baue einen kleinen Python-Client für einen FastAPI-Dienst, der einmalig verschlüsselte Nachrichten sendet. Schlüssel müssen auf dem Client verbleiben (niemals an den Server gesendet oder dort...
Ich versuche, dieses Beispiel für einen gemeinsamen Cache zu verstehen:
Ich habe diesen Zähler zum hinzugefügt init :
> self.cache_load_counter = Metrics.counter(self.__class__, 'cache_loads')
Ich habe cxf-rt-transports-http v2.2.10 von meinem Projekt verwendet, wenn ich es aktualisiere, um es zu aktualisieren, um zu cxf-rt-transports-http v3.5.5 , alle meine Testfälle und Code geben mir...
Ich verwende diese Datei aus der Swift-Snapshot-Testing-Bibliothek. Nachdem ich mein Projekt auf iOS 26 aktualisiert habe, muss ich alle Warnungen beheben. Aber ich bin mir nicht sicher, wie ich...
Ich verwende diese Datei aus der Swift-Snapshot-Testing-Bibliothek. Nachdem ich mein Projekt auf iOS 26 aktualisiert habe, muss ich alle Warnungen beheben. Aber ich bin mir nicht sicher, wie ich...