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(),
|
||||
);
|
||||
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);
|
||||
}
|
||||
let (body, check) = rest.split_at(26);
|
||||
@@ -96,6 +97,13 @@ fn decode(s: &str) -> Result<[u8; 16]> {
|
||||
mod tests {
|
||||
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]
|
||||
fn roundtrip() {
|
||||
for _ in 0..200 {
|
||||
|
||||
Reference in New Issue
Block a user