Skip to content

tor_llcrypto::pk::ed25519::ExpandedSecretKey::from_bytes() accepts byte buffers which are somehow invalid private keys

Found fuzzing my tor_crypto module in Gosling which wraps tor_llcrypto. The from_bytes method accepts byte buffers which can be used to successfully construct public keys and sign messages which then cannot be verified.

#![no_main]

// extern
use tor_llcrypto::*;
use signature::Verifier;

// fuzzing
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::arbitrary;
use libfuzzer_sys::arbitrary::Arbitrary;

#[derive(Arbitrary, Debug)]
struct CryptoData<'a> {
    ed25519_private_raw: [u8; 64],
    message: &'a [u8],
}

fuzz_target!(|data: CryptoData| {
    // tor_llcrpyto version
    if !data.message.is_empty() {
        let ed25519_private = pk::ed25519::ExpandedSecretKey::from_bytes(&data.ed25519_private_raw).unwrap();
        let ed25519_public = pk::ed25519::PublicKey::from(&ed25519_private);

        let signature = ed25519_private.sign(data.message, &ed25519_public);

        if let Err(err) = ed25519_public.verify(data.message, &signature) {
            panic!("{:?}", err); // panics here
        }
    }
});

Breaking input:

	CryptoData {
	    ed25519_private_raw: [
	        46,
	        38,
	        10,
	        119,
	        119,
	        119,
	        119,
	        119,
	        10,
	        119,
	        119,
	        119,
	        119,
	        93,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        130,
	        180,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        119,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        255,
	        119,
	        119,
	        119,
	        119,
	        119,
	        130,
	        136,
	    ],
	    message: [
	        119,
	    ],
	}

The error triggering the panic is: signature::Error { source: Some(Verification equation was not satisfied) }

I think I would have expected from_bytes() to have returned some error if the bytes are not a valid private key per https://docs.rs/tor-llcrypto/latest/tor_llcrypto/pk/ed25519/struct.ExpandedSecretKey.html#method.from_bytes

EDIT1: updated with more accurate analysis

EDIT2:

Breaking key in a more usable format:

let private_raw: [u8; ED25519_PRIVATE_KEY_SIZE] = [
    0x2eu8, 0x26u8, 0x0au8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x0au8, 0x77u8, 0x77u8,
    0x77u8, 0x77u8, 0x5du8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8,
    0x82u8, 0xb4u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8,
    0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0xffu8,
    0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8,
    0xffu8, 0xffu8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x77u8, 0x82u8, 0x88u8,
];
Edited by morgan