Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Beyond the simple matter of Rust being much newer than OpenSSL, one concern for some cryptographic primitives is the timing side-channel.

https://en.wikipedia.org/wiki/Timing_attack

In high level languages like Rust, the compiler does not prioritise trying to emit machine code which executes in constant time for all inputs. OpenSSL has implementations for some primitives which are known to be constant time, which can be important.

One option if you're working with Rust anyway would be use something like Ring:

https://github.com/briansmith/ring

Ring's primitives are just taken from BoringSSL which is Google's fork of OpenSSL, they're a mix of C and assembly language, it's possible (though fraught) to write some constant time algorithms in C if you know which compiler will be used, and of course it's possible (if you read the performance manuals carefully) to write constant time assembly in many cases.

In the C / assembly language code of course you do not have any safety benefits.

It can certainly make sense to do this very tricky primitive stuff in dangerous C or assembly, but then write all the higher level stuff in Rust, and that's the sort of thing Ring is intended for. BoringSSL for example includes code to do X.509 parsing and signature validation in C, but those things aren't sensitive, a timing attack on my X.509 parsing tells you nothing of value, and it's complicated to do correctly so Rust could make sense.



C does not make any guarantees about timing. It's not considered "observable behavior" by the standard.

The usual way to create constant-time code for C is to inspect the output assembly for a number of (compiler, options, host system, target system) tuples and verify that it will take constant time on all of them. Even that isn't enough in general, since there are other side-channels. The "Hertzbleed" attack exploits variable execution time in "constant time" code due to CPU dynamic frequency scaling being dependent on the input (secret) data. That effectively means that power side-channels are remotely observable.


> The usual way to create constant-time code for C is to inspect the output assembly

Sure, I hoped that sort of thing was implicit in what I wrote, some people do it, perhaps they should not, but they clearly feel like it's their best option. In particular for the context: writing this code in Rust doesn't help and would usually make it harder.

If we don't want to hand roll machine code, maybe somebody should make yet another "it's C but for the 21st century" language with constant time output as a deliberate feature, like maybe the const flag on your functions means produce constant time machine code or error - rather than "You can execute this function at compile time". (Not necessarily a serious syntactic suggestion, just spit-balling).


The problem is that ISAs don't support any sort of side-channel resistance mode, so even hand-rolling assembly (or machine code) won't fix every possible leak. If such a mode could be added, then any language could add appropriate intrinsics to set it.

More likely is that cryptography-specific instructions (like AES-NI or ARM's SHA hash instructions) will get added for more relevant operations.


You can write Assembly in Rust. The point would then be to shut down the usage around it so that you can only do it safely. Of course it won't stop issues but atleast you know which parts are risky and which aren't. There is also Miri, which allows you to check for Rust code that behaves memory unsafe.

And it's also quite possible to writing timing resistant code in Rust. Rust is not as high level as people think, it lets you get right down to the machine level with no issue.


What do you think of crates like subtle[1] which bills itself as "Pure-Rust traits and utilities for constant-time cryptographic implementations."

[1] https://crates.io/crates/subtle/


Speaking as a compiler developer: compilers for standard languages make no attempts to guarantee constant-time properties, nor to provide any primitives that can be used implement constant-time guarantees. Indeed, the developers are likely to be moderately hostile to proposals to add such primitives--it is a pretty different beast if you're worrying about constant-time.

As such, if you're using a standard compiler for a language to implement a constant-time guarantee, you need to be doing verification of the resulting assembly to make sure that it actually is constant-time. If you're not doing that, or you're not verifying the generated assembly itself, your constant-time guarantee is not worth the paper it's printed on. Even if it's not even printed on any paper.


Speaking as a compiler user, how much longer until we can expect better support for Mixed Boolean Arithmetic (MBA) simplification from compilers? For example, it's problematic that GCC and Clang aren't able to tell that `((((x ^ y) | (~(x ^ y) + 1)) >> 63) - 1)` is equivalent to `x==y` or that `(((x ^ ((x ^ y) | ((x - y) ^ y))) >> 63) - 1)` is equivalent to `x>=y`. We need MBA simplification because the algebra engines don't support it and malware authors frequently use it to obfuscate programs. But if we could plug it into a C compiler that shows us in assembly what the code is actually doing, then it would help a lot with software analysis.


Compilers that did this would break a lot of the constant time code.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: