diff --git a/.gitignore b/.gitignore index a08d6a0..9c44668 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,5 @@ src-svelte gpui-component packaging .cargo-packager -llm-texts \ No newline at end of file +llm-texts +opencode.jsonc diff --git a/Cargo.lock b/Cargo.lock index 36d537a..33d37b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,11 +15,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher", + "cipher 0.4.4", "cpufeatures 0.2.17", "zeroize", ] +[[package]] +name = "aes" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +dependencies = [ + "cipher 0.5.2", + "cpubits", + "cpufeatures 0.3.0", +] + [[package]] name = "ahash" version = "0.8.12" @@ -644,6 +655,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block2" version = "0.6.2" @@ -758,7 +778,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ - "cipher", + "cipher 0.4.4", +] + +[[package]] +name = "cbc" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" +dependencies = [ + "cipher 0.5.2", ] [[package]] @@ -851,11 +880,21 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", - "inout", + "crypto-common 0.1.7", + "inout 0.1.4", "zeroize", ] +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "crypto-common 0.2.2", + "inout 0.2.2", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -1165,6 +1204,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1243,6 +1288,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "ctor" version = "0.4.3" @@ -1319,7 +1373,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "crypto-common", + "crypto-common 0.1.7", "subtle", ] @@ -2655,6 +2709,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.10.1" @@ -2939,10 +3002,20 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "block-padding", + "block-padding 0.3.3", "generic-array", ] +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "block-padding 0.4.2", + "hybrid-array", +] + [[package]] name = "instant" version = "0.1.13" @@ -3414,9 +3487,9 @@ checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "memmap2" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" dependencies = [ "libc", ] @@ -3915,14 +3988,14 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3299dd401feaf1d45afd8fd1c0586f10fcfb22f244bb9afa942cec73503b89d" dependencies = [ - "aes", + "aes 0.8.4", "ashpd 0.12.3", "async-fs", "async-io", "async-lock", "blocking", - "cbc", - "cipher", + "cbc 0.1.2", + "cipher 0.4.4", "digest", "endi", "futures-lite 2.6.1", @@ -4135,12 +4208,12 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" name = "picoforge" version = "0.6.0" dependencies = [ - "aes", + "aes 0.9.1", "anyhow", "base64", "bitflags 2.13.0", "byteorder", - "cbc", + "cbc 0.2.1", "directories", "gpui", "gpui-component", @@ -4415,9 +4488,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.9" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ "bytes", "cfg_aliases", @@ -4435,9 +4508,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" dependencies = [ "bytes", "getrandom 0.3.4", @@ -4948,9 +5021,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.40" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "once_cell", "ring", diff --git a/Cargo.toml b/Cargo.toml index 041fb37..d8b9eeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,19 +15,19 @@ log4rs = "1" # For logging to output (like s directories = "6" # For Applcation config/data dir handling # For device management backend: -pcsc = "2" # Standard Smart Card API (connect to the key) -hex = "0.4" # For parsing VID/PID strings -byteorder = "1.5" # Required for writing Big-Endian numbers (firmware requirement) -thiserror = "2" # Makes custom error handling much easier -anyhow = "1" # For easy error propagation -hidapi = "2.6" # For fido2 interface operations but non-standard commands +pcsc = "2" # Standard Smart Card API (connect to the key) +hex = "0.4" # For parsing VID/PID strings +byteorder = "1.5" # Required for writing Big-Endian numbers (firmware requirement) +thiserror = "2" # Makes custom error handling much easier +anyhow = "1" # For easy error propagation +hidapi = "2.6" # For fido2 interface operations but non-standard commands serde_cbor_2 = "0.13" rand = "0.10" -bitflags = "2.11" -base64 = "0.22" # For PEM encoding of DER certificates -ring = "0.17" # For signing fido2 messages with pin token -aes = "0.8" -cbc = "0.1" +bitflags = "2.13.0" +base64 = "0.22" # For PEM encoding of DER certificates +ring = "0.17" # For signing fido2 messages with pin token +aes = "0.9" +cbc = "0.2" # For Application UI: gpui = { version = "0.2.2", features = [] } diff --git a/src/device/fido/hid.rs b/src/device/fido/hid.rs index 1ba78db..5a22bf8 100644 --- a/src/device/fido/hid.rs +++ b/src/device/fido/hid.rs @@ -1,5 +1,4 @@ -use aes::cipher::generic_array::GenericArray; -use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, block_padding::NoPadding}; +use cbc::cipher::{Block, BlockModeDecrypt, BlockModeEncrypt, KeyIvInit, block_padding::NoPadding}; use rand::RngExt; use ring::{agreement, digest, hmac}; use serde_cbor_2::{Value, from_slice, to_vec}; @@ -738,14 +737,15 @@ impl HidTransport { let pin_hash_16 = &pin_hash.as_ref()[0..16]; let iv = [0u8; 16]; - let mut block = *GenericArray::from_slice(pin_hash_16); + let mut block = Block::::try_from(pin_hash_16).unwrap(); let shared_secret_bytes = shared_secret.as_ref(); - let mut encryptor = cbc::Encryptor::::new( - GenericArray::from_slice(shared_secret_bytes), - GenericArray::from_slice(&iv), - ); - encryptor.encrypt_block_mut(&mut block); + let mut encryptor = cbc::Encryptor::::new_from_slices( + shared_secret_bytes, + &iv, + ) + .unwrap(); + encryptor.encrypt_block(&mut block); let pin_hash_enc = block.to_vec(); // 6. Send getPinToken command (Subcommand 0x05) @@ -777,11 +777,12 @@ impl HidTransport { Some(Value::Bytes(token_enc)) => { // Decrypt the PIN token using shared secret (AES-256-CBC, IV=0) let mut token_buf = token_enc.clone(); - let decrypted = cbc::Decryptor::::new( - GenericArray::from_slice(shared_secret_bytes), - GenericArray::from_slice(&iv), + let decrypted = cbc::Decryptor::::new_from_slices( + shared_secret_bytes, + &iv, ) - .decrypt_padded_mut::(&mut token_buf) + .map_err(|_| PFError::Device("Failed to create decryptor".into()))? + .decrypt_padded::(&mut token_buf) .map_err(|_| PFError::Device("Failed to decrypt PIN token".into()))?; log::info!("Successfully obtained and decrypted PIN token (Subcommand 0x05)."); Ok(decrypted.to_vec()) @@ -853,14 +854,15 @@ impl HidTransport { let pin_hash_16 = &pin_hash.as_ref()[0..16]; let iv = [0u8; 16]; - let mut block = *GenericArray::from_slice(pin_hash_16); + let mut block = Block::::try_from(pin_hash_16).unwrap(); let shared_secret_bytes = shared_secret.as_ref(); - let mut encryptor = cbc::Encryptor::::new( - GenericArray::from_slice(shared_secret_bytes), - GenericArray::from_slice(&iv), - ); - encryptor.encrypt_block_mut(&mut block); + let mut encryptor = cbc::Encryptor::::new_from_slices( + shared_secret_bytes, + &iv, + ) + .unwrap(); + encryptor.encrypt_block(&mut block); let pin_hash_enc = block.to_vec(); // 6. Send getPinUvAuthTokenUsingPinWithPermissions command (Subcommand 0x09) @@ -900,11 +902,12 @@ impl HidTransport { Some(Value::Bytes(token_enc)) => { // Decrypt the PIN token using shared secret (AES-256-CBC, IV=0) let mut token_buf = token_enc.clone(); - let decrypted = cbc::Decryptor::::new( - GenericArray::from_slice(shared_secret_bytes), - GenericArray::from_slice(&iv), + let decrypted = cbc::Decryptor::::new_from_slices( + shared_secret_bytes, + &iv, ) - .decrypt_padded_mut::(&mut token_buf) + .map_err(|_| PFError::Device("Failed to create decryptor".into()))? + .decrypt_padded::(&mut token_buf) .map_err(|_| PFError::Device("Failed to decrypt PIN token".into()))?; log::info!("Successfully obtained and decrypted PIN token (Subcommand 0x09)."); Ok(decrypted.to_vec()) @@ -983,13 +986,14 @@ impl HidTransport { let iv = [0u8; 16]; let mut new_pin_enc = Vec::new(); - let mut encryptor = cbc::Encryptor::::new( - GenericArray::from_slice(shared_secret_bytes), - GenericArray::from_slice(&iv), - ); + let mut encryptor = cbc::Encryptor::::new_from_slices( + shared_secret_bytes, + &iv, + ) + .unwrap(); for chunk in padded_new_pin.chunks_exact(16) { - let mut block = *GenericArray::from_slice(chunk); - encryptor.encrypt_block_mut(&mut block); + let mut block = Block::::try_from(chunk).unwrap(); + encryptor.encrypt_block(&mut block); new_pin_enc.extend_from_slice(&block); } @@ -1101,12 +1105,13 @@ impl HidTransport { let pin_hash = digest::digest(&digest::SHA256, current_pin.as_bytes()); let pin_hash_16 = &pin_hash.as_ref()[0..16]; let iv = [0u8; 16]; - let mut block = *GenericArray::from_slice(pin_hash_16); - cbc::Encryptor::::new( - GenericArray::from_slice(shared_secret_bytes), - GenericArray::from_slice(&iv), + let mut block = Block::::try_from(pin_hash_16).unwrap(); + cbc::Encryptor::::new_from_slices( + shared_secret_bytes, + &iv, ) - .encrypt_block_mut(&mut block); + .unwrap() + .encrypt_block(&mut block); let pin_hash_enc = block.to_vec(); // 6. Encrypt newPinEnc @@ -1115,13 +1120,14 @@ impl HidTransport { padded_new_pin[..bytes.len()].copy_from_slice(bytes); let mut new_pin_enc = Vec::new(); - let mut encryptor = cbc::Encryptor::::new( - GenericArray::from_slice(shared_secret_bytes), - GenericArray::from_slice(&iv), - ); + let mut encryptor = cbc::Encryptor::::new_from_slices( + shared_secret_bytes, + &iv, + ) + .unwrap(); for chunk in padded_new_pin.chunks_exact(16) { - let mut block = *GenericArray::from_slice(chunk); - encryptor.encrypt_block_mut(&mut block); + let mut block = Block::::try_from(chunk).unwrap(); + encryptor.encrypt_block(&mut block); new_pin_enc.extend_from_slice(&block); } @@ -1722,10 +1728,9 @@ mod tests { #[test] fn test_pin_hash_encryption_actually_encrypts() { // Verify that our AES-CBC encryption actually modifies the data. - // This guards against the previous bug where encrypt_block_mut + // This guards against the previous bug where encrypt_block // was called on a temporary copy (buffer.into()), discarding the result. - use aes::cipher::generic_array::GenericArray; - use cbc::cipher::{BlockEncryptMut, KeyIvInit}; + use cbc::cipher::BlockModeEncrypt; use ring::digest; let pin = "123456"; @@ -1736,14 +1741,15 @@ mod tests { let key = [0u8; 32]; let iv = [0u8; 16]; - let mut block = *GenericArray::from_slice(pin_hash_16); + let mut block = Block::::try_from(pin_hash_16).unwrap(); let original = block; - let mut encryptor = cbc::Encryptor::::new( - GenericArray::from_slice(&key), - GenericArray::from_slice(&iv), - ); - encryptor.encrypt_block_mut(&mut block); + let mut encryptor = cbc::Encryptor::::new_from_slices( + &key, + &iv, + ) + .unwrap(); + encryptor.encrypt_block(&mut block); // The encrypted block MUST differ from the original assert_ne!( diff --git a/src/device/fido/mod.rs b/src/device/fido/mod.rs index d266815..d78cc46 100644 --- a/src/device/fido/mod.rs +++ b/src/device/fido/mod.rs @@ -1070,7 +1070,9 @@ mod tests { power_cycle_on_reset: None, led_steady: None, enable_secp256k1: None, + raw_curves_mask: None, led_order: None, + enabled_usb_itf: None, } } diff --git a/src/ui/views/config.rs b/src/ui/views/config.rs index 7909557..3ff94a9 100644 --- a/src/ui/views/config.rs +++ b/src/ui/views/config.rs @@ -908,9 +908,7 @@ impl ConfigView { let dec_bright_listener = cx.listener(move |this, _, _, cx| { let mut b = this.led_status_brightness[c_i]; - if b > 0 { - b -= 1; - } + b = b.saturating_sub(1); this.led_status_brightness[c_i] = b; cx.notify(); }); diff --git a/src/ui/views/passkeys.rs b/src/ui/views/passkeys.rs index 3d8b3ec..2736626 100644 --- a/src/ui/views/passkeys.rs +++ b/src/ui/views/passkeys.rs @@ -1029,10 +1029,10 @@ impl PasskeysView { .child("Reset Device") .custom( ButtonCustomVariant::new(cx) - .color(theme.danger.into()) - .hover(theme.danger_hover.into()) - .active(theme.danger_active.into()) - .foreground(theme.danger_foreground.into()), + .color(theme.danger) + .hover(theme.danger_hover) + .active(theme.danger_active) + .foreground(theme.danger_foreground), ) .disabled(self.loading) .on_click(cx.listener(|this, _, window, cx| {