Documentation ¶
Overview ¶
Package doubleratchet implements a variant of the Double Ratchet Algorithm.
The Double Ratchet Algorithm by Perrin and Marlinspike[0] is to be used by two parties to exchange encrypted messages based on a shared secret. Thus, a key agreement protocol needs to be used first, e.g., X3DH as also implemented in this repository.
The following implementation decisions were made; always following the recommendations within the specification.
For the Diffie-Hellman key exchange, X25519 based on Curve25519 is used.
The key derivation functions, both for the root key chain as well as the sending and receiving chains, are based on SHA-256. This hash algorithm was chosen over SHA-512 to save 32 bytes. The root key's KDF is an HKDF and the other KDF uses an HMAC, as recommended by the specification.
For AEAC encryption, AES-256 is used in CBC mode. To fit the AES block size, the input is padded with PKCS#7. Finally, an HMAC is attached.
This implementation does not perform the optional header encryption. Each message header contains the sender's current DH public key next to its position within the current sending chain and the previous chain length. This data is not confidential.
A buffer to allow skipping lost or out-of-order messages is implemented to support up to eight previous chains, with 32 skipped messages in each. This is a compromise between a very lossy link and the possibility for an attacker to reserve lots of memory on the victim's machine.
[0] https://signal.org/docs/specifications/doubleratchet/
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type DoubleRatchet ¶
type DoubleRatchet struct {
// contains filtered or unexported fields
}
DoubleRatchet implements the Double Ratchet Algorithm.
This allows sending and receiving PFS encrypted messages. It is also possible to skipp a certain amount of messages or decrypt them out of order.
For the Double Ratchet's initialization, the roles of an active and passive part (Alice and Bob) needs to be assigned the used application protocol. After the first two messages - starting with Alice, bob follows - the order of encryption and decryption calls is no longer relevant. However, Alice MUST send her first message to Bob in order to synchronize the internal state.
The implementation design and chosen algorithms were documented in this package's documentation.
func CreateActive ¶
func CreateActive(sessKey, associatedData, peerDhPub []byte) (dr *DoubleRatchet, err error)
CreateActive creates a Double Ratchet for the active part, Alice.
The active peer MUST send the first message.
func CreatePassive ¶
func CreatePassive(sessKey, associatedData, dhPub, dhPriv []byte) (dr *DoubleRatchet, err error)
CreatePassive creates a Double Ratchet for the passive part, Bob.
The passive peer MUST receive a message first.
func (*DoubleRatchet) Decrypt ¶
func (dr *DoubleRatchet) Decrypt(ciphertext []byte) (plaintext []byte, err error)
Decrypt a ciphertext from the other party.
The encryption is an AEAD encryption. Thus, a changed message should be detected and result in an error.
func (*DoubleRatchet) Encrypt ¶
func (dr *DoubleRatchet) Encrypt(plaintext []byte) (ciphertext []byte, err error)
Encrypt a plaintext message for the other party.
The resulting ciphertext will include the necessary header.
func (*DoubleRatchet) MarshalBinary ¶
func (dr *DoubleRatchet) MarshalBinary() ([]byte, error)
func (*DoubleRatchet) UnmarshalBinary ¶
func (dr *DoubleRatchet) UnmarshalBinary(b []byte) error