Bug Description
toByteArray(str, 'hex') in lib/utils/encoding.ts silently strips all non-hex characters via a regex before parsing, instead of throwing a validation error. This causes silent data corruption — callers receive a wrong byte array with no indication that the input was invalid.
Steps to Reproduce
- Call
toByteArray('xyz', 'hex') — any non-hex string works.
- Observe: no error is thrown, and a 0-byte array is returned.
- Reproduce in the app: select any hex-input cipher (RC4, OTP, 3DES), enter
xyz as ciphertext, and trigger decryption — wrong output, no error shown.
Expected Behavior
toByteArray(str, 'hex') should throw a CipherError with code INVALID_INPUT and a message like "Invalid hex string: contains non-hex characters." whenever the input contains any character outside [0-9a-fA-F].
Actual Behavior
The function runs str.replace(/[^0-9a-fA-F]/g, '') which silently removes all invalid characters. Because the stripped string can have even length (including length 0), the even-length check passes and no error is ever thrown:
toByteArray('xyz', 'hex') → Uint8Array(0) — 0 bytes, no error
toByteArray('0x1a', 'hex') → strips 0x, silently returns [0x1a]
toByteArray('AES!key', 'hex') → strips !, returns wrong bytes
Root cause:
lib/utils/encoding.ts line 9. All cipher decrypt() functions are affected: rc4.ts, otp.ts, 3des.ts, chacha20.ts, aes.ts, des.ts.
Screenshots
N/A — reproducible via unit test or browser console.
Environment
- OS: Any
- Browser: Any
- Version: Latest (
main branch)
Additional Context
Proposed fix (lib/utils/encoding.ts):
- const clean = str.replace(/[^0-9a-fA-F]/g, '')
- if (clean.length % 2 !== 0) {
- throw new CipherError('INVALID_KEY', 'Hex string must have an even length.')
- }
- const arr = new Uint8Array(clean.length / 2)
+ if (str.length > 0 && /[^0-9a-fA-F]/.test(str)) {
+ throw new CipherError('INVALID_INPUT', 'Invalid hex string: contains non-hex characters.')
+ }
+ if (str.length % 2 !== 0) {
+ throw new CipherError('INVALID_INPUT', 'Hex string must have an even number of characters.')
+ }
+ const arr = new Uint8Array(str.length / 2)
Bug Description
toByteArray(str, 'hex')inlib/utils/encoding.tssilently strips all non-hex characters via a regex before parsing, instead of throwing a validation error. This causes silent data corruption — callers receive a wrong byte array with no indication that the input was invalid.Steps to Reproduce
toByteArray('xyz', 'hex')— any non-hex string works.xyzas ciphertext, and trigger decryption — wrong output, no error shown.Expected Behavior
toByteArray(str, 'hex')should throw aCipherErrorwith codeINVALID_INPUTand a message like "Invalid hex string: contains non-hex characters." whenever the input contains any character outside[0-9a-fA-F].Actual Behavior
The function runs
str.replace(/[^0-9a-fA-F]/g, '')which silently removes all invalid characters. Because the stripped string can have even length (including length 0), the even-length check passes and no error is ever thrown:toByteArray('xyz', 'hex')→Uint8Array(0)— 0 bytes, no errortoByteArray('0x1a', 'hex')→ strips0x, silently returns[0x1a]toByteArray('AES!key', 'hex')→ strips!, returns wrong bytesRoot cause:
lib/utils/encoding.tsline 9. All cipherdecrypt()functions are affected:rc4.ts,otp.ts,3des.ts,chacha20.ts,aes.ts,des.ts.Screenshots
N/A — reproducible via unit test or browser console.
Environment
mainbranch)Additional Context
Proposed fix (
lib/utils/encoding.ts):