Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ The security of your data is the highest priority. Here is a summary of the secu
- **Strong encryption standard:** IttyBitz uses **AES-256-GCM**, a modern authenticated encryption cipher that provides both confidentiality and data integrity.
- **Strong key derivation:** your password is not used directly as the encryption key. Instead, it is run through the **PBKDF2** (Password-Based Key Derivation Function 2) algorithm with **1,000,000 iterations**. This makes brute-force attacks against your password extremely slow and computationally expensive, even for weak passwords.
- **Cryptographically secure randomness:** the application uses `window.crypto.getRandomValues()` to generate the salt for key derivation, the Initialization Vector (IV) for AES-GCM, the random characters for the password generator, and the data for the key file generator. This is a cryptographically secure pseudo-random number generator (CSPRNG) that is suitable for security-sensitive applications.
- **Password strength indicator:** to encourage strong security practices, the UI provides real-time feedback, guiding users to create passwords that are at least 24 characters long and contain a mix of character types.
- **Password strength indicator:** to encourage strong security practices, the UI provides real-time feedback, guiding users to create passwords that are at least 24 characters long and either contain a mix of character types or form a passphrase of six or more different words (Diceware-style).
- **Best-effort memory clearing:** after an encryption or decryption operation is complete, the application overwrites sensitive variables (like the derived key and salt) in memory. Note: JavaScript's garbage collector may retain copies of data elsewhere in the heap, so this is a best-effort mitigation rather than a guarantee.
- **No user tracking:** the application does not use cookies, analytics, or trackers. Your activity is your own.

Expand Down
2 changes: 1 addition & 1 deletion SHA256SUMS.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
783f720327251aa6b85db63e358b1d1460b0c975d5b9fbb39c9b0de8898e8068 ittybitz.html
2e21c56e52e5b14a715529fe2ffe63a167625f10a8fd1489f5504e9db5ca8e79 ittybitz.html
40dc1cf811d66ecae145c95a651831983c10fc8efa9f01efb7de2acd856fd81d ittybitz-recovery.html
29 changes: 27 additions & 2 deletions scripts/build/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,34 @@
var ICON_EYE_OFF = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"/><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"/><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"/><path d="m2 2 20 20"/></svg>';

// ---- Helpers ----
function isPasswordStrong(pwd) {
// Two ways to clear the strength gate:
// 1. a mixed-character password: 24+ chars with upper, lower, digit, symbol
// (what the Generate button produces);
// 2. a passphrase: 24+ chars made of 6+ different words of 3+ letters,
// separated by spaces, hyphens or underscores (Diceware-style).
// Composition rules alone reject long, high-entropy passphrases such as a
// 7-word Diceware phrase (~90 bits) while passing "Aaaaaaaaaaaaaaaaaaaaaa1!".
// NIST SP 800-63B advises length over composition; this keeps the existing
// rule for people who use it and stops punishing the stronger alternative.
var WORD_SEP = /[\s\-_]+/;
function hasMixedComposition(pwd) {
return pwd.length >= 24 && /[A-Z]/.test(pwd) && /[a-z]/.test(pwd) && /\d/.test(pwd) && SYMBOL_RE.test(pwd);
}
function isPassphrase(pwd) {
if (pwd.length < 24) return false;
var words = pwd.trim().split(WORD_SEP).filter(Boolean);
if (words.length < 6) return false;
var distinct = {}, count = 0;
for (var i = 0; i < words.length; i++) {
var w = words[i].toLowerCase();
if (w.length < 3) return false;
if (!distinct[w]) { distinct[w] = 1; count++; }
}
return count >= 6;
}
function isPasswordStrong(pwd) {
return hasMixedComposition(pwd) || isPassphrase(pwd);
}

function generatePassword() {
var len = 32, n = GEN_CHARSET.length;
Expand Down Expand Up @@ -540,7 +565,7 @@
var pw = $('p').value;
if (!pw) { status('err', 'A password is required.'); return; }
if (mode === 'encrypt' && !isPasswordStrong(pw)) {
status('err', 'Weak password. Use at least 24 characters with uppercase, lowercase, numbers, and symbols.'); return;
status('err', 'Weak password. Use at least 24 characters with uppercase, lowercase, numbers and symbols — or a passphrase of 6+ different words (24+ characters in total).'); return;
}
if (useKeyFile && !keyFile) { status('err', '"Use key file" is on but no key file is selected. Choose one, or turn the option off.'); return; }

Expand Down
2 changes: 1 addition & 1 deletion scripts/build/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ <h3>Drop a file here</h3>

<!-- Password -->
<div class="row">
<label for="p">Password <span class="muted" id="pw-hint" style="color:var(--faint);font-weight:400">· min 24 chars, upper, lower, number, symbol</span></label>
<label for="p">Password <span class="muted" id="pw-hint" style="color:var(--faint);font-weight:400">· 24+ chars with upper, lower, number, symbol — or a passphrase of 6+ words</span></label>
<div class="field">
<input type="password" id="p" class="pw" autocomplete="off" spellcheck="false" placeholder="Enter a strong password">
<button type="button" class="toggle-btn" id="p-toggle">Show</button>
Expand Down
33 changes: 29 additions & 4 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
canvas and downloads use blob:/data:, none of which are network fetches.
Nothing here can phone home. -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; script-src 'sha256-4GSOHG1PWgpqNwON0DpmpOBDoMdMXoBzQI2KhDuK9js=' 'sha256-SJVUXJNlOay+2TG0PE+o+T46Wt7Qxe1B1XpRTxfVTCE=' 'sha256-W+IzleLCL30nXjyiCRp8Rl3j2GFDMC9KAJFnnygxQ8c=' 'sha256-XlgOklfvkE1YTG+BSxN2kJFwnn+L4EhXLVb01Ma4YsM=' 'sha256-NYQ0hM7SpKRLIsnbuTkqUcaQqX7Tt/p2OBOYLmZTRVY='; style-src 'unsafe-inline'; img-src data:; connect-src 'none'; font-src 'none'; form-action 'none'; base-uri 'none'">
content="default-src 'none'; script-src 'sha256-4GSOHG1PWgpqNwON0DpmpOBDoMdMXoBzQI2KhDuK9js=' 'sha256-SJVUXJNlOay+2TG0PE+o+T46Wt7Qxe1B1XpRTxfVTCE=' 'sha256-W+IzleLCL30nXjyiCRp8Rl3j2GFDMC9KAJFnnygxQ8c=' 'sha256-XlgOklfvkE1YTG+BSxN2kJFwnn+L4EhXLVb01Ma4YsM=' 'sha256-1JVp8/SC8kqeAtUfFZpIE7n0eESU0r7Xk0p0rk626BQ='; style-src 'unsafe-inline'; img-src data:; connect-src 'none'; font-src 'none'; form-action 'none'; base-uri 'none'">
<!--
═══════════════════════════════════════════════════════════════════════
IttyBitz — single-file client-side encryption
Expand Down Expand Up @@ -373,7 +373,7 @@ <h3>Drop a file here</h3>

<!-- Password -->
<div class="row">
<label for="p">Password <span class="muted" id="pw-hint" style="color:var(--faint);font-weight:400">· min 24 chars, upper, lower, number, symbol</span></label>
<label for="p">Password <span class="muted" id="pw-hint" style="color:var(--faint);font-weight:400">· 24+ chars with upper, lower, number, symbol — or a passphrase of 6+ words</span></label>
<div class="field">
<input type="password" id="p" class="pw" autocomplete="off" spellcheck="false" placeholder="Enter a strong password">
<button type="button" class="toggle-btn" id="p-toggle">Show</button>
Expand Down Expand Up @@ -3238,9 +3238,34 @@ <h2>Support IttyBitz</h2>
var ICON_EYE_OFF = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"/><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"/><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"/><path d="m2 2 20 20"/></svg>';

// ---- Helpers ----
function isPasswordStrong(pwd) {
// Two ways to clear the strength gate:
// 1. a mixed-character password: 24+ chars with upper, lower, digit, symbol
// (what the Generate button produces);
// 2. a passphrase: 24+ chars made of 6+ different words of 3+ letters,
// separated by spaces, hyphens or underscores (Diceware-style).
// Composition rules alone reject long, high-entropy passphrases such as a
// 7-word Diceware phrase (~90 bits) while passing "Aaaaaaaaaaaaaaaaaaaaaa1!".
// NIST SP 800-63B advises length over composition; this keeps the existing
// rule for people who use it and stops punishing the stronger alternative.
var WORD_SEP = /[\s\-_]+/;
function hasMixedComposition(pwd) {
return pwd.length >= 24 && /[A-Z]/.test(pwd) && /[a-z]/.test(pwd) && /\d/.test(pwd) && SYMBOL_RE.test(pwd);
}
function isPassphrase(pwd) {
if (pwd.length < 24) return false;
var words = pwd.trim().split(WORD_SEP).filter(Boolean);
if (words.length < 6) return false;
var distinct = {}, count = 0;
for (var i = 0; i < words.length; i++) {
var w = words[i].toLowerCase();
if (w.length < 3) return false;
if (!distinct[w]) { distinct[w] = 1; count++; }
}
return count >= 6;
}
function isPasswordStrong(pwd) {
return hasMixedComposition(pwd) || isPassphrase(pwd);
}

function generatePassword() {
var len = 32, n = GEN_CHARSET.length;
Expand Down Expand Up @@ -3669,7 +3694,7 @@ <h2>Support IttyBitz</h2>
var pw = $('p').value;
if (!pw) { status('err', 'A password is required.'); return; }
if (mode === 'encrypt' && !isPasswordStrong(pw)) {
status('err', 'Weak password. Use at least 24 characters with uppercase, lowercase, numbers, and symbols.'); return;
status('err', 'Weak password. Use at least 24 characters with uppercase, lowercase, numbers and symbols — or a passphrase of 6+ different words (24+ characters in total).'); return;
}
if (useKeyFile && !keyFile) { status('err', '"Use key file" is on but no key file is selected. Choose one, or turn the option off.'); return; }

Expand Down