8 ms·
Auditing Rust Crypto: The First Hours
- Animats 8y agoIf you have unsafe Rust code in your crypto code, you're doing it wrong.
- adwn 8y agoEven unsafe Rust code is a bit safer than C. For example, in Rust unsafe code, using an uninitialized variable leads to a compiler error – you have to use something explicit like std::mem::uninitialized.
- oconnor663 8y agoI'm not aware of any SIMD frameworks that are advanced enough to spare me from writing unsafe code yet, particularly if I want to ship multiple implementations and detect support dynamically. Also I'm not sure you can get any constant time guarantees today without calling into C or asm.
- saagarjha 8y ago> Look for any recursive function calls and see if they could be abused to overflow the stack. This isn't an exploitable vulnerability in Rust, though? I thought the program would just abort if it overflowed the stack.
- Hello71 8y agoDoS is a vulnerability
- saagarjha 8y agoOk, point taken. It's generally much less severe than the other types of vulnerabilities, though.
- muricula 8y agoIf you can make a truly enormous stack array you can sometimes skip past the end of the stack onto the heap (or another section of memory). Then any writes to the array which the program thinks are going to the stack are actually going to the heap. This is sometimes known as stack clashing.
- saagarjha 8y agoIs this something you can do in Rust?
- eridius 8y agoI haven't tried, but maybe with something like let huge_ary: [u8; 2097152 /* 2MiB */] = unsafe { ::std::mem::uninitialized() }; // hopefully huge_ary has bumped the stack pointer past any guard pages // and any further stack values will overwrite the heap
- saagarjha 8y agoWell, you're doing unsafe things there, so all bets are off.
- eridius 8y agoYou might be able to hack it by saying something like let huge_ary: [u8; 2097152]; if false_value_compiler_cant_prove_is_false { huge_ary = [0; 2097152]; } // hopefully huge_ary has reserved space on the stack despite not being initialized // and so any further stack values would overwrite the heap
- hyperman1 8y agoWhy do you need the if construction? The stack grows downards (at least on x86_64), and clearing with zeroes in general starts at the first adress (even if this isnt guaranteed). So the CPU sees a write 2097152 bytes below the last used stack location. Which might be in the heap if ther is no stack protection. Then again, 2Mb is nothing on a 64 bit processor, so I don't think the chanse of hitting the heap is very big.
- deleted 8y ago[deleted]
- richardwhiuk 8y ago> Review the dependencies listed in Cargo.toml: Will the latest version be used? (preferable but not always the right choice) Are these established, trustworthy packages? The author seems to have forgotten about Cargo.lock....
- eridius 8y agoCargo.lock is something the top-level program uses. If you're writing a library that does crypto, your Cargo.lock will be ignored by any upstream libraries/applications that depend on you (and because of this the recommendation is to not even check your library's Cargo.lock into version control).
- richardwhiuk 8y agoAh right - I thought this was regarding security tool behaviour not an app - I'm aware Cargo.lock doesn't provide locking at an app level. I consider a library insisting on locking it's second level dependencies for no good reason to be obnoxious behaviour. As producer of an app, I want the ability to upgrade your dependencies to patch security problems. In my experience, excessive locking can make security problems worse not better.
- SilasX 8y agoSorry if too off-topic, but I figured this was a good place to share my experience with trying to use the Rust `crypto` library, which I recounted in this comment [1]. It's not a security concern, but it does affect usability. I had the simple task[2] of encrypting bytes with AES using the library. But (as detailed in the post), they didn't expose a simple, "give us plaintext bytes, give us key bytes, give us options, we'll spit back the ciphertext bytes". Instead, you have to delve into the irrelevant details of constructing mutable buffers (which require special care in Rust), so it can read from and write to them, and without even any good examples in the docs for how to construct those buffers. It seems designed from the perspective of "I have extremely limited memory" -- which is fine, but why not have a simple wrapper on top of that for the common, non-embedded use case, and some example code? [1] https://news.ycombinator.com/item?id=18943940 https://news.ycombinator.com/item?id=18943940 [2] for the Matasano/cryptopals challenge. Interestingly, I found that the hardest parts weren't figuring out the vulnerabilities, but in implementing a spec (every writeup was poor) or getting "off-the-shelf" software to behave as expected so I can have a utility function for it and forget about it from then on!
- tptacek 8y agoWhich writeups were "poor"?
- SilasX 8y agoNot the Cryptopal writeups -- I mean every explanation of the Mersenne Twister I found, how the values were scattered all over the place and it was difficult to get the expected result. Wikipedia's, example, is a mess to sort through: https://en.wikipedia.org/wiki/Mersenne_Twister#Pseudocode https://en.wikipedia.org/wiki/Mersenne_Twister#Pseudocode (I use the plural because I'm lumping that in with the difficulty of getting openssl to yield the expected results for AES encryption.)
- cetra3 8y agoAre you talking about the crate `crypto` or `rust-crypto`? Both have not been updated in a couple of years. The `ring` library is a bit more modern, but still requires a bit of a run around. Here's an example of encrypting a cookie: https://github.com/alexcrichton/cookie-rs/blob/master/src/secure/private.rs#L144 https://github.com/alexcrichton/cookie-rs/blob/master/src/se...
- drexlspivey 8y agoThe author JP Aumasson (known for inventing the BLAKE hash, SHA3 finalist) recently audited grin's underlying crypto library. Report here https://grin-tech.org/audits/jpa-audit-report.html https://grin-tech.org/audits/jpa-audit-report.html
- vardump 8y agoIt's a bit surprising that the article didn't mention ensuring constant time algorithms are used. If latency or the emissions of the CPU (etc. externally observable) are data dependent on something secret, that secret might leak through the side channel. One way to combat these side channels is to use constant time multiplication, loop conditions (including functions that might return early, like memcmp), etc. Is it possible for Rust to have any new or surprising mechanisms that cause loss of constant time execution? (Of course also other aspects can leak than the CPU instruction execution latency itself. For example cache effects might be measurable.)
- GordonS 8y agoI've only read about the relevance of constant-time comparisons in relation to comparisons, such as checking that a calculated hash is the same as a stored hash - could you elaborate on how it applied to symmetric encryption?
- vardump 8y agoSome operations, such as integer multiplication and division have data dependent latency. Depends on CPU model. See for example this page: https://bearssl.org/ctmul.html https://bearssl.org/ctmul.html > could you elaborate on how it applied to symmetric encryption? Non-constant time multiplication is mostly (only?) an issue with asymmetric crypto.
- fpgaminer 8y agoIf an implementation isn't constant time it can potentially leak information about the key. i.e. the relative length of time it takes to encrypt may be dependent on properties of the key. So an attacker that can measure how long it takes you to encrypt something can begin to derive the key. Similar attacks occur when your encryption uses lookup tables depending on key bits, uses different amounts of power, etc. It's a surprisingly effective attack surface, and why the industry is moving away from older style schemes like AES and towards ARX based constructions like ChaCha.
- nicoburns 8y ago
- firethief 8y ago> Are sensitive values set to zero after being used? In Rust this may be done using the Drop trait rather than explicitly. A zeroing Drop is theater unless the sensitive data is Pinned too. Rust likes to copy things around.
- eridius 8y agoI'm not particularly familiar with Pinned but the documentation on std::pin suggests it prevents moving data, not copying data (and is primarily designed around enabling self-referential structs).
- legulere 8y agoMoves are exactly the problem, as the data is just copied, without drop running on the source, and they happen implicitly.
- eridius 8y agoRust isn't going to just silently move the pointed-to data in something like Box<[u8; 32]>. It looks like the point of Pinned is to protect against operations like swap() that would move the pointed-to data, but the point here is to maintain the data's invariants (e.g. a self-referential struct cannot be moved or its self-references would be invalid) rather than to protect against silent moves (a call to swap() is definitely not silent).
- masklinn 8y ago> Rust isn't going to just silently move the pointed-to data in something like Box<[u8; 32]>. Of course not, but for efficiency you might have an [u8;32][0] instead and that will get memcpy'd when it's moved around. [0] 32 bytes on the stack isn't much, a single Vec or String is 24
- eridius 8y agoA [u8;32] doesn't work with Pin. Pin only works when you wrap it around a pointer type. From the documentation on Unpin: > Since Rust itself has no notion of immovable types, and will consider moves to always be safe, this trait cannot prevent types from moving by itself. From the documentation on std::pin: > In order to prevent objects from moving, they must be pinned by wrapping a pointer to the data in the Pin type. A pointer wrapped in a Pin is otherwise equivalent to its normal version, e.g. Pin<Box<T>> and Box<T> work the same way except that the first is pinning the value of T in place. > First of all, these are pointer types because pinned data mustn't be passed around by value (that would change its location in memory). … Looking at Pin itself, it appears that it works by only implementing DerefMut if its target is Unpin, thus preventing you from mutating (and therefore swapping/replacing) the data unless the data supports Unpin. But beyond that, it also only implements Deref and DerefMut if its wrapped type itself implements Deref/DerefMut, which means using Pin around a non-pointer basically prevents you from accessing the wrapped data.
- CaliforniaKarl 8y agoLooking at the article, I like the Drop trait, as a way to ensure memory are cleaned before being released. What is the preferred way in Rust to say "If at all possible, please do not allow this value/object/whatever to be paged out of RAM?"
- Grollicus 8y agoWith security mindset, "if at all possible do not allow" is the basically the same as "always allow". As mlock / VirtualProtect are OS dependent I strongly suspect this is not part of Rust itself. Additionally, I suspect there would be some design problems for example putting this protected thing on the stack (protect the whole stack? Or just parts? Bookkeeping wether a stack lock can be released after a function exits?). How do you move values into / out of such an object? So I don't think this exists, but I've been pleasantly surprised by Rust before. My general solution for this case is to either mlockall the whole process if it is small / short-living or to have no swap in the machine, for example long running crypto servers. Who runs servers with swap anyways?
- deleted 8y ago[deleted]
- monocasa 8y agoThose system calls don't really work like that; there isn't really a public way to say "don't save a copy of this page on disk" on Windows, OSX, or Linux. For instance see Raymond Chen's explanation here > Is VirtualLock safe to use for cryptographic purposes – that is, to avoid sensitive memory being written to disk? > ... > [There does not appear to be any guarantee that the memory won't be written to disk while locked. As you noted, the machine may be hibernated, or it may be running in a VM that gets snapshotted. -Raymond] VirtualLock and the equivalents only guarantee that the canonical copy of that page stays in RAM, not that other copies won't make their way out to disk. Edit: add link https://blogs.msdn.microsoft.com/oldnewthing/20140207-00/?p=1833 https://blogs.msdn.microsoft.com/oldnewthing/20140207-00/?p=...
- codys 8y ago