kv-crypto: SecretKey::parse rejects non-ASCII input instead of panicking
parse() checked the cleaned key's byte length and then split it at byte 26, which panics when a multibyte character straddles that index (found by fuzz/secret_key_parse). Under panic = "abort" this would crash the app on a mistyped or pasted Secret Key. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -47,7 +47,8 @@ impl SecretKey {
|
|||||||
s.chars().filter(|c| !c.is_whitespace() && *c != '-').map(|c| c.to_ascii_uppercase()).collect(),
|
s.chars().filter(|c| !c.is_whitespace() && *c != '-').map(|c| c.to_ascii_uppercase()).collect(),
|
||||||
);
|
);
|
||||||
let rest = cleaned.strip_prefix(PREFIX).ok_or(CryptoError::BadSecretKey)?;
|
let rest = cleaned.strip_prefix(PREFIX).ok_or(CryptoError::BadSecretKey)?;
|
||||||
if rest.len() != 27 {
|
// ASCII only: `split_at` below works on bytes and must not land inside a character.
|
||||||
|
if !rest.is_ascii() || rest.len() != 27 {
|
||||||
return Err(CryptoError::BadSecretKey);
|
return Err(CryptoError::BadSecretKey);
|
||||||
}
|
}
|
||||||
let (body, check) = rest.split_at(26);
|
let (body, check) = rest.split_at(26);
|
||||||
@@ -96,6 +97,13 @@ fn decode(s: &str) -> Result<[u8; 16]> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_ascii_is_rejected_without_panicking() {
|
||||||
|
// Found by fuzz/secret_key_parse: 27 bytes whose 26th..27th byte is a Cyrillic 'е'.
|
||||||
|
assert!(SecretKey::parse("K1-10Y5-00Y0-000000p00-000000p0\u{435}-").is_err());
|
||||||
|
assert!(SecretKey::parse("K1-000000-00000-00000-00000-0000\u{e9}-0").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn roundtrip() {
|
fn roundtrip() {
|
||||||
for _ in 0..200 {
|
for _ in 0..200 {
|
||||||
|
|||||||
Reference in New Issue
Block a user