I am using k256
library, and want to make sure that the contents of SecretKey
are zeroized on drop. I wrote a small test, but I am confused by the results.
// k256 = { version = "0.9.2", default-features = false, features = ["ecdsa", "zeroize"] }
use k256::SecretKey;
// rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
use rand_core::OsRng;
fn drop_sk() -> usize {
let sk = SecretKey::random(&mut OsRng);
let ptr = &sk as *const SecretKey;
let ptr_u8 = ptr as *const u8;
// Line 1
// println!("Memory in drop_sk() #1: {:?}", unsafe { core::slice::from_raw_parts(ptr_u8, 4) });
// Line 2
// drop(sk);
// Line 3
// println!("Memory in drop_sk() #2: {:?}", unsafe { core::slice::from_raw_parts(ptr_u8, 4) });
ptr_u8 as usize
}
fn main() {
let ptr_u8 = drop_sk();
println!("Memory in main(): {:?}", unsafe { core::slice::from_raw_parts(ptr_u8 as *const u8, 4) });
}
Now, before running it, I expected the output in main()
always be the same regardless of which of Lines 1-3 are commented or not in drop_sk()
, because either way it is dropped at the end of it, and should be zeroized. But the results actually differ:
# all commented
Memory in main(): [1, 0, 0, 0]
# only line 1 uncommented (or only line 3 uncommented)
Memory in drop_sk() #1: [122, 34, 83, 67]
Memory in main(): [0, 0, 0, 0]
# (so, zeroized as expected)
# only line 2 uncommented
Memory in main(): [2, 0, 0, 0]
# lines 1 and 2 uncommented (or lines 2 and 3 uncommented)
Memory in drop_sk() #1: [95, 249, 139, 251]
Memory in main(): [95, 249, 139, 251]
# (no zeroization)
# lines 1 and 3 uncommented
Memory in drop_sk() #1: [134, 166, 37, 46]
Memory in drop_sk() #2: [134, 166, 37, 46]
Memory in main(): [3, 0, 0, 0]
# all lines uncommented
Memory in drop_sk() #1: [212, 233, 107, 78]
Memory in drop_sk() #2: [212, 233, 107, 78]
Memory in main(): [0, 0, 0, 0]
For reference, the structure of SecretKey
is SecretKey { inner: ScalarBytes { inner: GenericArray<...> } }
, where neither SecretKey
nor ScalarBytes
have Copy
implemented.
I do not know how to interpret these results. Somehow an explicit drop()
call leaves the secret data in memory, but if you print it again, the zeroization happens. Does explicit drop()
and automatic going-out-of-scope drop work differently? Does taking a pointer on an object somehow prevents it from being dropped?