Skip to content

Symbol-only password silently disables encryption #3

Description

@trevorallenw

Description

A password composed entirely of characters outside the Base64 alphabet (A–Z, a–z, 0–9, +, /) is silently reduced to an empty string by cleanPassword(), which makes encode() apply a shift of 0 to every codon. The result is byte-for-byte identical to encoding with no password at all. A user who deliberately chooses a password like !@#$% believes their message is encrypted when it is not, and receives no warning.

Steps to reproduce

  1. Enter secret in Plaintext.
  2. Enter !@#$% in the Password field.
  3. Click Encode ➜.
    • Ciphertext = CTATCGCCCGATCTAGCGCCCTCA.
  4. Clear the Password field and click Encode ➜ again.
    • Ciphertext = CTATCGCCCGATCTAGCGCCCTCA — identical.

Expected: a non-empty password produces ciphertext distinct from the no-password output (or the user is told the password was rejected).
Actual: the two ciphertexts are identical; the password had no effect and no warning was shown.

Conditions

Occurs whenever every character of the password is stripped by PASSWORD_REGEX — i.e. the password contains no A–Z, a–z, 0–9, +, or /. Passwords with at least one valid character are only partially affected: their invalid characters are silently dropped, so e.g. k!e!y encrypts as key, which is a weaker but less visible variant of the same problem.

Impact

Medium (security). The tool presents password-based encryption as a feature, so a silently-ignored password is a confidentiality failure: the user ships what they think is protected ciphertext but is actually the unprotected default encoding. The partial-stripping case also means two different passwords can silently map to the same key.

Root cause

site/js/codon64.js:

const PASSWORD_REGEX = /[^A-Za-z\d\/+]/g;

function cleanPassword(password) {
    return password.replaceAll(PASSWORD_REGEX, '')
}

and in getShift():

if (password === '') {
    return 0;
}

cleanPassword('!@#$%') returns '', so getShift() takes the no-password branch and returns shift 0 for every codon. The stripping is silent — there is no signal that characters were removed or that the effective password is empty.

Proposed fix

Surface the condition instead of silently degrading. At minimum, when the raw password is non-empty but cleanPassword() returns '', warn the user that the password contained no usable characters and was ignored. Optionally, widen the accepted alphabet or map arbitrary characters into the shift space so that any non-empty password contributes to the key rather than being discarded.

A minimal UI-level guard in site/js/home.js, at the encode/decode click handlers:

if (password.value !== '' && cleanPassword(password.value) === '') {
    // e.g. highlight the field / show a message
    console.warn('Password contained no usable characters and was ignored.');
}

This keeps the existing encoding behavior but removes the silent-no-encryption surprise.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions