Table of Contents

Here is a highly advanced, enterprise-grade, offline-first project: a Cryptographic File Fragmenter & Weaver (Splitter & Joiner).

Usually, splitting files relies on command-line utilities (like split/cat in Linux) or paid visual apps, and none of them cryptographically secure your files before fragmenting on the fly. This project utilizes the native browser Web Crypto API (AES-256-GCM with PBKDF2 key derivation), custom binary binary-slicing, performance benchmarking, and re-construction metadata. It allows users to safely split any sensitive file into encrypted Shards (.nxf) offline, and stitch them back together solely with the correct password.

Cryptographic File Fragmenter & Weaver Source Code

1. HTML (index.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Offline Cryptographic File Fragmenter & Weaver (Client-Side AES-256-GCM)</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>

  <header class="navbar">
    <div class="logo">NitroX Web</div>
    <span class="badge">Advanced Crypto Utility</span>
  </header>

  <main class="app-wrapper">
    <!-- Introduction Panel -->
    <section class="intro-bar">
      <h1>Encrypted File Fragmenter & Weaver</h1>
      <p>Securely split a file into multiple encrypted fragment pieces (shards) for distributed backups, or stitch them back together. <strong>Everything happens locally on your machine—your files and passwords never touch a server.</strong></p>
    </section>

    <div class="grid-layout">
      
      <!-- Panel A: Fragment (Split) -->
      <section class="action-card" id="fragmentPanel">
        <div class="card-title">
          <span class="step-num">1</span>
          <h2>Fragment a File (Split & Encrypt)</h2>
        </div>

        <div class="drop-zone" id="fragDropZone">
          <input type="file" id="fragInput" hidden>
          <div class="dz-info">
            <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="accent"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>
            <p><strong>Drag & Drop</strong> or <span class="highlight">browse</span></p>
            <span id="fragFileName" class="file-name-display">No file selected</span>
          </div>
        </div>

        <div class="form-group">
          <label for="fragPassword">Encryption Password</label>
          <input type="password" id="fragPassword" placeholder="Strong security password..." required>
        </div>

        <div class="form-row">
          <div class="form-group">
            <label for="shardCount">Number of Shards (Fragments)</label>
            <select id="shardCount">
              <option value="2">2 Pieces</option>
              <option value="3" selected>3 Pieces</option>
              <option value="4">4 Pieces</option>
              <option value="5">5 Pieces</option>
              <option value="8">8 Pieces</option>
              <option value="10">10 Pieces</option>
            </select>
          </div>
        </div>

        <button class="submit-btn highlight-g" id="btnFragment">Fragment File</button>

        <!-- Dynamic Statistics -->
        <div class="perf-box" id="fragPerf" hidden>
          <div class="stat-row">
            <span>Size: <strong id="statFragSize">0 MB</strong></span>
            <span>Speed: <strong id="statFragSpeed">0 MB/s</strong></span>
          </div>
          <div class="progress-bar-bg">
            <div class="progress-fill" id="fragProgress"></div>
          </div>
          <div id="fragDownloads" class="download-list"></div>
        </div>
      </section>

      <!-- Panel B: Weaver (Reconstruct) -->
      <section class="action-card" id="weaverPanel">
        <div class="card-title">
          <span class="step-num">2</span>
          <h2>Weave Shards (Stitch & Decrypt)</h2>
        </div>

        <div class="drop-zone" id="weaveDropZone">
          <input type="file" id="weaveInput" multiple hidden>
          <div class="dz-info">
            <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="blue"><path d="M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z"></path><path d="m10 8 4 4-4 4"></path></svg>
            <p><strong>Upload ALL .nxf shards</strong> at once</p>
            <span id="weaveFilesDisplay" class="file-name-display">0 shards imported</span>
          </div>
        </div>

        <div class="form-group">
          <label for="weavePassword">Decryption Password</label>
          <input type="password" id="weavePassword" placeholder="Enter original password..." required>
        </div>

        <button class="submit-btn highlight-b" id="btnWeave">Weave & Reconstruct</button>

        <!-- Dynamic Statistics -->
        <div class="perf-box" id="weavePerf" hidden>
          <div class="stat-row">
            <span>Progress: <strong id="statWeaveProgress">0%</strong></span>
            <span>Status: <strong id="statWeaveStatus">Pending</strong></span>
          </div>
          <div class="progress-bar-bg">
            <div class="progress-fill highlight-b" id="weaveProgress"></div>
          </div>
          <div id="weaveDLWrapper" class="download-wrapper-single" hidden>
            <a href="#" id="dlWeavedLink" class="dl-single-btn">
              Download Reassembled File
            </a>
          </div>
        </div>
      </section>

    </div>
  </main>

  <script src="script.js"></script>
</body>
</html>

2. CSS (style.css)

/* ==========================================================================
   Global Theme Settings (Dark Cyberpunk Blue)
   ========================================================================== */
:root {
  --bg-dark: #070a13;
  --bg-card: #101524;
  --bg-input: #060910;
  --border-color: #1a2336;
  --text-main: #f8fafc;
  --text-muted: #94a3b8;
  --accent-mint: #10b981;
  --accent-hover-mint: #059669;
  --accent-blue: #3b82f6;
  --accent-hover-blue: #2563eb;
  --radius-lg: 16px;
  --radius-md: 10px;
  --transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  --shadow-lg: 0 20px 35px -10px rgba(0, 0, 0, 0.7);
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background-color: var(--bg-dark);
  color: var(--text-main);
  line-height: 1.6;
  min-height: 100vh;
  padding-bottom: 4rem;
}

/* ==========================================================================
   Header Navbar
   ========================================================================== */
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.25rem 2.5rem;
  border-bottom: 1px solid var(--border-color);
  background: rgba(16, 21, 36, 0.85);
  backdrop-filter: blur(12px);
  position: sticky;
  top: 0;
  z-index: 100;
}

.logo {
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -0.02em;
  color: var(--accent-mint);
}

.badge {
  background: rgba(16, 185, 129, 0.12);
  color: var(--accent-mint);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
}

/* ==========================================================================
   Typography & Introductory Bar
   ========================================================================== */
.app-wrapper {
  max-width: 1100px;
  margin: 3rem auto;
  padding: 0 1.5rem;
}

.intro-bar {
  text-align: center;
  margin-bottom: 3.5rem;
}

.intro-bar h1 {
  font-size: 2.25rem;
  font-weight: 900;
  letter-spacing: -0.03em;
  margin-bottom: 0.75rem;
  background: linear-gradient(135deg, #f8fafc, #64748b);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.intro-bar p {
  color: var(--text-muted);
  font-size: 1rem;
  max-width: 720px;
  margin: 0 auto;
}

/* ==========================================================================
   Grid System
   ========================================================================== */
.grid-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.5rem;
  align-items: start;
}

.action-card {
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 2.25rem;
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}

.card-title {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.step-num {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background-color: var(--border-color);
  color: var(--text-main);
  font-weight: 800;
  font-size: 0.95rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-title h2 {
  font-size: 1.25rem;
  font-weight: 850;
  letter-spacing: -0.02em;
}

/* ==========================================================================
   Custom Drop Zones
   ========================================================================== */
.drop-zone {
  border: 2px dashed var(--border-color);
  background-color: var(--bg-input);
  border-radius: var(--radius-md);
  padding: 2rem 1rem;
  text-align: center;
  cursor: pointer;
  transition: border-color var(--transition);
}

.drop-zone:hover {
  border-color: var(--accent-mint);
}

.dz-info {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.dz-info svg.accent { color: var(--accent-mint); }
.dz-info svg.blue { color: var(--accent-blue); }

.dz-info p {
  font-size: 0.92rem;
  color: var(--text-muted);
}

.highlight {
  color: var(--accent-mint);
  font-weight: 600;
}

.file-name-display {
  display: inline-block;
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  padding: 0.35rem 0.85rem;
  font-family: monospace;
  font-size: 0.78rem;
  max-width: 90%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ==========================================================================
   Inputs & Buttons
   ========================================================================== */
.form-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.form-group label {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
}

input[type="password"], select {
  width: 100%;
  background-color: var(--bg-input);
  border: 1.5px solid var(--border-color);
  color: var(--text-main);
  padding: 0.75rem 1rem;
  font-size: 0.95rem;
  border-radius: var(--radius-md);
  outline: none;
  transition: border-color var(--transition);
}

input[type="password"]:focus, select:focus {
  border-color: var(--accent-mint);
}

.submit-btn {
  width: 100%;
  padding: 0.9rem 1.5rem;
  border: none;
  border-radius: var(--radius-md);
  font-size: 0.98rem;
  font-weight: 700;
  cursor: pointer;
  transition: background-color var(--transition), transform var(--transition);
}

.submit-btn.highlight-g {
  background-color: var(--accent-mint);
  color: var(--bg-dark);
}
.submit-btn.highlight-g:hover { background-color: var(--accent-hover-mint); }

.submit-btn.highlight-b {
  background-color: var(--accent-blue);
  color: var(--text-main);
}
.submit-btn.highlight-b:hover { background-color: var(--accent-hover-blue); }

.submit-btn:active {
  transform: translateY(1px);
}

/* ==========================================================================
   Analytics Dashboard
   ========================================================================== */
.perf-box {
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.stat-row {
  display: flex;
  justify-content: space-between;
  font-size: 0.82rem;
  color: var(--text-muted);
}

.progress-bar-bg {
  width: 100%;
  height: 6px;
  background-color: var(--border-color);
  border-radius: 99px;
  overflow: hidden;
}

.progress-fill {
  width: 0%;
  height: 100%;
  background-color: var(--accent-mint);
  border-radius: 99px;
  transition: width 0.1s ease;
}

.progress-fill.highlight-b {
  background-color: var(--accent-blue);
}

/* Downloads Layout */
.download-list {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  max-height: 180px;
  overflow-y: auto;
}

.dl-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.45rem 0.65rem;
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  font-size: 0.78rem;
}

.dl-link {
  color: var(--accent-mint);
  text-decoration: none;
  font-weight: 600;
}

.dl-link:hover { text-decoration: underline; }

.download-wrapper-single {
  text-align: center;
}

.dl-single-btn {
  display: inline-block;
  background-color: var(--accent-blue);
  color: var(--text-main);
  font-size: 0.85rem;
  font-weight: 700;
  padding: 0.65rem 1.25rem;
  border-radius: 6px;
  text-decoration: none;
}

.dl-single-btn:hover { background-color: var(--accent-hover-blue); }

@media (max-width: 868px) {
  .grid-layout {
    grid-template-columns: 1fr;
  }
}

3. JavaScript (script.js)

document.addEventListener('DOMContentLoaded', () => {
  
  // Custom File Shard Marker: 'NXF' in ASCII = [78, 88, 70]
  const NXF_MAGIC = new Uint8Array([78, 88, 70]);

  // ==========================================================================
  // Global States
  // ==========================================================================
  let fragmentFile = null;
  let incomingShards = [];

  // DOM Handles - Panel A
  const fragDropZone = document.getElementById('fragDropZone');
  const fragInput = document.getElementById('fragInput');
  const fragFileName = document.getElementById('fragFileName');
  const fragPassword = document.getElementById('fragPassword');
  const shardCount = document.getElementById('shardCount');
  const btnFragment = document.getElementById('btnFragment');
  const fragPerf = document.getElementById('fragPerf');
  const statFragSize = document.getElementById('statFragSize');
  const statFragSpeed = document.getElementById('statFragSpeed');
  const fragProgress = document.getElementById('fragProgress');
  const fragDownloads = document.getElementById('fragDownloads');

  // DOM Handles - Panel B
  const weaveDropZone = document.getElementById('weaveDropZone');
  const weaveInput = document.getElementById('weaveInput');
  const weaveFilesDisplay = document.getElementById('weaveFilesDisplay');
  const weavePassword = document.getElementById('weavePassword');
  const btnWeave = document.getElementById('btnWeave');
  const weavePerf = document.getElementById('weavePerf');
  const statWeaveProgress = document.getElementById('statWeaveProgress');
  const statWeaveStatus = document.getElementById('statWeaveStatus');
  const weaveProgress = document.getElementById('weaveProgress');
  const weaveDLWrapper = document.getElementById('weaveDLWrapper');
  const dlWeavedLink = document.getElementById('dlWeavedLink');

  // Drag and Drop listeners
  const setupDragDrop = (zone, input, onSelect) => {
    zone.addEventListener('click', () => input.click());
    zone.addEventListener('dragover', (e) => { e.preventDefault(); zone.style.borderColor = 'var(--accent-mint)'; });
    zone.addEventListener('dragleave', () => { zone.style.borderColor = 'var(--border-color)'; });
    zone.addEventListener('drop', (e) => {
      e.preventDefault();
      zone.style.borderColor = 'var(--border-color)';
      if (e.dataTransfer.files.length) onSelect(e.dataTransfer.files);
    });
    input.addEventListener('change', (e) => {
      if (e.target.files.length) onSelect(e.target.files);
    });
  };

  setupDragDrop(fragDropZone, fragInput, (files) => {
    fragmentFile = files[0];
    fragFileName.textContent = `${fragmentFile.name} (${(fragmentFile.size / (1024 * 1024)).toFixed(2)} MB)`;
  });

  setupDragDrop(weaveDropZone, weaveInput, (files) => {
    incomingShards = Array.from(files);
    weaveFilesDisplay.textContent = `${incomingShards.length} shards selected`;
  });

  // ==========================================================================
  // Cryptography Mechanics
  // ==========================================================================
  const deriveKey = async (password, salt) => {
    const enc = new TextEncoder();
    const keyMaterial = await window.crypto.subtle.importKey(
      "raw",
      enc.encode(password),
      "PBKDF2",
      false,
      ["deriveBits", "deriveKey"]
    );
    return window.crypto.subtle.deriveKey(
      {
        name: "PBKDF2",
        salt: salt,
        iterations: 40000,
        hash: "SHA-256"
      },
      keyMaterial,
      { name: "AES-GCM", length: 256 },
      false,
      ["encrypt", "decrypt"]
    );
  };

  // ==========================================================================
  // Task Logic: Fragment (Encrypt & Split)
  // ==========================================================================
  btnFragment.addEventListener('click', async () => {
    if (!fragmentFile || !fragPassword.value) {
      alert('Please select a file and enter a password.');
      return;
    }

    btnFragment.disabled = true;
    fragPerf.hidden = false;
    fragDownloads.innerHTML = '';
    fragProgress.style.width = '10%';
    statFragSize.textContent = `${(fragmentFile.size / (1024 * 1024)).toFixed(2)} MB`;
    
    const timeStart = performance.now();

    try {
      // 1. ArrayBuffer Read
      const originalBuffer = await fragmentFile.arrayBuffer();
      fragProgress.style.width = '30%';

      // 2. Encryption Setup (AES-GCM-256)
      const salt = window.crypto.getRandomValues(new Uint8Array(16));
      const iv = window.crypto.getRandomValues(new Uint8Array(12));
      const key = await deriveKey(fragPassword.value, salt);

      const cipherBuffer = await window.crypto.subtle.encrypt(
        { name: "AES-GCM", iv: iv },
        key,
        originalBuffer
      );
      fragProgress.style.width = '60%';

      const encryptedData = new Uint8Array(cipherBuffer);
      const parts = parseInt(shardCount.value);
      const totalEncryptedLen = encryptedData.length;
      const baseChunkSize = Math.floor(totalEncryptedLen / parts);

      // Metainfo
      const nameEnc = new TextEncoder().encode(fragmentFile.name);
      
      for (let i = 0; i < parts; i++) {
        const start = i * baseChunkSize;
        const end = (i === parts - 1) ? totalEncryptedLen : start + baseChunkSize;
        const payloadSlice = encryptedData.subarray(start, end);

        // Calculate Header Buffer dimensions: magic (3) + index (1) + count (1) + salt (16) + iv (12) + fileLen (1) + filename
        const headerLen = 3 + 1 + 1 + 16 + 12 + 1 + nameEnc.length;
        const shardBuffer = new Uint8Array(headerLen + payloadSlice.length);

        // Inject Shard Markers
        shardBuffer.set(NXF_MAGIC, 0);
        shardBuffer[3] = i; 
        shardBuffer[4] = parts;
        shardBuffer.set(salt, 5);
        shardBuffer.set(iv, 21);
        shardBuffer[33] = nameEnc.length;
        shardBuffer.set(nameEnc, 34);
        shardBuffer.set(payloadSlice, headerLen);

        // Make Download Blob
        const blob = new Blob([shardBuffer], { type: 'application/octet-stream' });
        const url = URL.createObjectURL(blob);
        const fileName = `${fragmentFile.name}.part${i + 1}of${parts}.nxf`;

        // Render download list item
        const item = document.createElement('div');
        item.className = 'dl-item';
        item.innerHTML = `
          <span>${fileName} (${(blob.size / 1024).toFixed(1)} KB)</span>
          <a href="${url}" download="${fileName}" class="dl-link">Save</a>
        `;
        fragDownloads.appendChild(item);
      }

      fragProgress.style.width = '100%';
      const elapsed = (performance.now() - timeStart) / 1000;
      const mbps = (fragmentFile.size / (1024 * 1024)) / elapsed;
      statFragSpeed.textContent = `${mbps.toFixed(1)} MB/s`;

    } catch (err) {
      alert('Encryption or splitting failed. check settings.');
      console.error(err);
    } finally {
      btnFragment.disabled = false;
    }
  });

  // ==========================================================================
  // Task Logic: Weaver (Stitch & Decrypt)
  // ==========================================================================
  btnWeave.addEventListener('click', async () => {
    if (incomingShards.length < 2 || !weavePassword.value) {
      alert('Upload at least 2 .nxf shards and provide the decryption password.');
      return;
    }

    btnWeave.disabled = true;
    weaveDLWrapper.hidden = true;
    weavePerf.hidden = false;
    statWeaveProgress.textContent = '10%';
    statWeaveStatus.textContent = 'Parsing...';
    weaveProgress.style.width = '10%';

    try {
      const parsedFragments = [];
      let totalPartsExpected = 0;
      let originalFileName = "";
      let salt = null;
      let iv = null;

      // Validate & unpack headers
      for (const file of incomingShards) {
        const buffer = await file.arrayBuffer();
        const raw = new Uint8Array(buffer);

        // Check magic
        if (raw[0] !== NXF_MAGIC[0] || raw[1] !== NXF_MAGIC[1] || raw[2] !== NXF_MAGIC[2]) {
          throw new Error(`File "${file.name}" is not a valid NitroX fragment (.nxf).`);
        }

        const index = raw[3];
        const total = raw[4];
        if (totalPartsExpected === 0) totalPartsExpected = total;
        
        // Grab Crypto nonces & tags once
        if (!salt) salt = raw.subarray(5, 21);
        if (!iv) iv = raw.subarray(21, 33);

        const nameLen = raw[33];
        const nameBytes = raw.subarray(34, 34 + nameLen);
        if (!originalFileName) originalFileName = new TextDecoder().decode(nameBytes);

        const headerSize = 34 + nameLen;
        const payload = raw.subarray(headerSize);

        parsedFragments[index] = payload;
      }

      // Check for gap holes
      for (let i = 0; i < totalPartsExpected; i++) {
        if (!parsedFragments[i]) {
          throw new Error(`Missing Shard Piece #${i + 1}. Upload all ${totalPartsExpected} shards.`);
        }
      }

      statWeaveProgress.textContent = '50%';
      statWeaveStatus.textContent = 'Stitching & Decrypting...';
      weaveProgress.style.width = '50%';

      // Flatten & stitch
      let totalEncryptedLength = 0;
      for (const slice of parsedFragments) totalEncryptedLength += slice.length;

      const flatCipher = new Uint8Array(totalEncryptedLength);
      let offset = 0;
      for (const slice of parsedFragments) {
        flatCipher.set(slice, offset);
        offset += slice.length;
      }

      // 4. Derivation & Decryption
      const key = await deriveKey(weavePassword.value, salt);
      const decryptedBuffer = await window.crypto.subtle.decrypt(
        { name: "AES-GCM", iv: iv },
        key,
        flatCipher
      );

      // Build & publish re-assembled resource
      const reconstructedBlob = new Blob([decryptedBuffer], { type: 'application/octet-stream' });
      const reconstructedUrl = URL.createObjectURL(reconstructedBlob);

      dlWeavedLink.href = reconstructedUrl;
      dlWeavedLink.download = originalFileName;
      dlWeavedLink.textContent = `Save: ${originalFileName} (${(reconstructedBlob.size / (1024 * 1024)).toFixed(2)} MB)`;
      
      weaveDLWrapper.hidden = false;
      statWeaveProgress.textContent = '100%';
      statWeaveStatus.textContent = 'Reconstruction Complete!';
      weaveProgress.style.width = '100%';

    } catch (err) {
      statWeaveStatus.textContent = 'Error processing shards.';
      weaveProgress.style.width = '0%';
      alert(`Reconstruction failed: ${err.message || 'Check password and verify you have uploaded every shard file.'}`);
      console.error(err);
    } finally {
      btnWeave.disabled = false;
    }
  });

});

High-Performance Offline-First Cryptographic File Fragmenter & Weaver in HTML, CSS & JS

Whether backing up cold storage to different cloud services, partitioning sensitive file systems, or bypassing payload upload limits, splitting files can be highly practical. Typically, splitting relies on file chunks being stored as raw binary segments. If someone inspects or acquires any single shard, however, they will immediately have a piece of your unencrypted private data.

To overcome this, developers need a robust process to first encrypt data with modern symmetric algorithms, and then segment the data into distinct pieces (shards) wrapped in metadata that allows you to reassemble them.

This guide details the internal mechanisms of our Offline Cryptographic File Fragmenter & Weaver, showing you how to handle encryption and chunking locally using Web API technologies.

Anatomy of our Shard: Behind the Header Specification

To stitch back dynamic files, the software has to understand exactly how to handle chunk ordering, key derivations, and filename recovery. Instead of using complex auxiliary files, this tool merges all data into a unique file type: the NitroX Fragment (.nxf).

+------------------------------------------------------------------------------------+
| Bytes 0-2  | Byte 3 | Byte 4 | Bytes 5-20 | Bytes 21-32 | Byte 33 | Bytes 34-X  | Rest      |
| "NXF" Magic| Shard# | Total  | 16-B Salt  | 12-B AES IV | Fn Length| UTF-8 Name  | Payload   |
+------------------------------------------------------------------------------------+

Each shard begins with standard binary identification tags:

  • “NXF” Signature (3 Bytes): Validates that the imported file is indeed a custom .nxf fragment.
  • Metadata Block (2 Bytes): Stores the specific index of the piece and the grand total needed to assemble the file safely.
  • Cryptography nonces (28 Bytes): Houses unique salt (used to map PBKDF2 keys) and Initialization Vector parameters.
  • The Filename block: Stores original filename lengths and values so we can rename reassembled files precisely.

Security Analysis: PBKDF2 with AES-256-GCM

When encrypting browser-based content, relying on simple string-to-key conversions is highly insecure. To make decryption robust, our utility relies on standard Web Crypto API systems:

  1. Entropy Amplification (PBKDF2): Instead of passing your password as raw text, we run it through Key Derivation with a unique 16-byte salt and 40,000 iterations of HMAC-SHA-256. This makes the generated password secure and resistant to hardware brute-force attacks.
  2. Symmetric Integrity (AES-256-GCM): This AEAD cipher doesn’t just encrypt; it adds tag verification. GCM ensures that if an attacker alters even a single byte in any of the .nxf shards, browser decryption will immediately fail, protecting you from malicious tampering.

How Offline-First Slicing Works inside memory

By processing everything asynchronously inside the client, files are loaded, encrypted, and sliced without ever hitting the web:

const originalBuffer = await fragmentFile.arrayBuffer(); // 1. Read files locally into byte buffers
const cipherBuffer = await window.crypto.subtle.encrypt(  // 2. Encrypt entirely inside browser
  { name: "AES-GCM", iv: iv }, key, originalBuffer
);
const baseChunkSize = Math.floor(totalEncryptedLen / parts); // 3. Subdivide binary cipher segments

By reading everything into ArrayBuffer blocks, we can precisely control and allocate fragment dimensions manually inside RAM. The resulting slices are packaged alongside custom nonces directly into standard Blob objects, allowing users to download their shards in just one click.