-
Notifications
You must be signed in to change notification settings - Fork 30
Design
This section explains some design related topics of Orion and how Orion is built.
The types that Orion uses have mostly been based upon how sodiumoxide and Mundane use types.
Types are used extensively in the high-level API and this section gives an overview of how a type that could hold sensitive data might be implemented.
Orion uses the same approach to opaque types as those described by Mundane. Types are represented through a struct, where data is kept in a private field to limit access.
Specifically, in the high-level interface, the type SecretKey
has a private field named value
, which is only accessible from the methods and traits that SecretKey
implements.
Several traits are important to implement when a type is holding sensitive data or otherwise needs extra protection, to avoid a user accidentally misusing it. These are the traits that the SecretKey
in the high-level API implements:
-
Drop
: This trait is theSecretKey
's destructor. As soon as it goes out of scope,Drop
zeroes out the sensitive data located in the fieldvalue
ofSecretKey
. Relevant information on this in the Security section. -
PartialEq
: This trait is implemented forSecretKey
to ensure that, wheneverSecretKey
is compared with another object of that type, the comparison will happen in constant-time. As such, if someone were to unknowingly try to insecurely compare, for example, two authentication tags:A == B
, this would not result in a timing vulnerability. This is mainly implemented for misuse-resistance, as most modules already provide a secure verification function. -
Debug
: This trait is implemented in a way that makes it much harder for sensitive data inSecretKey
to be leaked into logs. Should someone try to print the data contained inSecretKey
, it would displaySecretKey {***OMITTED***}
instead of the actual data in thevalue
field. -
Default
: TheDefault
implementation lets a user initialize an object of typeSecretKey
by callinglet key = SecretKey::default();
. This will use a CSPRNG to generate aSecretKey
of a pre-defined length, which in this case is 256 bits. This is only provided to make it as easy as possible, for the user to useSecretKey
securely.
The functions presented here are what aim to give the minimum amount of access to SecretKey
, while still offering all the functionality one might need.
These are the functions that the SecretKey
in the high-level API implements:
-
from_slice()
: This lets the user initialize aSecretKey
object from a slice passed to this function. Orion does not zero out the source slice, and a user of Orion would have to take care of that themselves. -
unprotected_as_bytes()
: This function returns the data in thevalue
field ofSecretKey
as a byte slice. It is called unprotected because a user could copy the returned byte slice and save it elsewhere, without any of the protections thatSecretKey
offers. The documentation warns about the use of this and the name has been selected to hopefully nudge users towards not using this function, unless strictly necessary. -
len()
: A simple function that returns the length of the data contained in thevalue
field ofSecretKey
. -
generate()
: This lets a user initialize aSecretKey
object by generating it using a CSPRNG with a provided length. This is offered in case users need longer keys than the default 256 bit.
Orion's approach to error-handling has been taken directly from ring. By using an opaque error type we avoid leaking sensitive information as much as possible.
Most of the time an error is returned, the cause of this will also be rather obvious to the user. Situations like trying to finalize a streaming state twice without resetting it first, using invalid key sizes, etc. This is another reason as to why a single error type approach is used.