Got rid off unnecessary errors handling
This commit is contained in:
parent
d83171d325
commit
c0ae542945
|
@ -15,7 +15,7 @@ type Crypto interface {
|
|||
|
||||
// KdfRK returns a pair (32-byte root key, 32-byte chain key) as the output of applying
|
||||
// a KDF keyed by a 32-byte root key rk to a Diffie-Hellman output dhOut.
|
||||
KdfRK(rk, dhOut [32]byte) (rootKey, chainKey [32]byte, err error)
|
||||
KdfRK(rk, dhOut [32]byte) (rootKey, chainKey [32]byte)
|
||||
|
||||
// KdfCK returns a pair (32-byte chain key, 32-byte message key) as the output of applying
|
||||
// a KDF keyed by a 32-byte chain key ck to some constant.
|
||||
|
@ -23,7 +23,7 @@ type Crypto interface {
|
|||
|
||||
// Encrypt returns an AEAD encryption of plaintext with message key mk. The associated_data
|
||||
// is authenticated but is not included in the ciphertext. The AEAD nonce may be set to a constant.
|
||||
Encrypt(mk [32]byte, plaintext, associatedData []byte) (authCiphertext []byte, err error)
|
||||
Encrypt(mk [32]byte, plaintext, associatedData []byte) (authCiphertext []byte)
|
||||
|
||||
// Decrypt returns the AEAD decryption of ciphertext with message key mk.
|
||||
Decrypt(mk [32]byte, ciphertext, associatedData []byte) (plaintext []byte, err error)
|
||||
|
|
|
@ -42,17 +42,17 @@ func (c DefaultCrypto) DH(dhPair DHPair, dhPub [32]byte) [32]byte {
|
|||
return dhOut
|
||||
}
|
||||
|
||||
func (c DefaultCrypto) KdfRK(rk, dhOut [32]byte) (rootKey [32]byte, chainKey [32]byte, err error) {
|
||||
func (c DefaultCrypto) KdfRK(rk, dhOut [32]byte) (rootKey [32]byte, chainKey [32]byte) {
|
||||
// TODO: Use sha512? Think about how to switch the implementation later if not.
|
||||
var (
|
||||
// TODO: Check if HKDF is set up correctly.
|
||||
r = hkdf.New(sha256.New, dhOut[:], rk[:], []byte("rsZUpEuXUqqwXBvSy3EcievAh4cMj6QL"))
|
||||
buf = make([]byte, 64)
|
||||
)
|
||||
if _, err = io.ReadFull(r, buf); err != nil {
|
||||
err = fmt.Errorf("failed to generate keys: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// The only error here is an entropy limit which won't be reached for such a short buffer.
|
||||
_, _ = io.ReadFull(r, buf)
|
||||
|
||||
copy(rootKey[:], buf[:32])
|
||||
copy(rootKey[:], buf[32:])
|
||||
return
|
||||
|
@ -82,23 +82,19 @@ func (c DefaultCrypto) KdfCK(ck [32]byte) (chainKey [32]byte, msgKey [32]byte) {
|
|||
// Encrypt uses a slightly different approach over what is stated in the algorithm specification:
|
||||
// it uses AES-256-CTR instead of AES-256-CBC for security, ciphertext length and implementation
|
||||
// complexity considerations.
|
||||
func (c DefaultCrypto) Encrypt(mk [32]byte, plaintext, associatedData []byte) ([]byte, error) {
|
||||
encKey, authKey, iv, err := c.deriveEncKeys(mk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (c DefaultCrypto) Encrypt(mk [32]byte, plaintext, associatedData []byte) []byte {
|
||||
encKey, authKey, iv := c.deriveEncKeys(mk)
|
||||
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
copy(ciphertext[:len(iv)], iv[:])
|
||||
|
||||
block, err := aes.NewCipher(encKey[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create aes block cipher: %s", err)
|
||||
}
|
||||
// No error will occur here as encKey is guaranteed to be 32 bytes.
|
||||
block, _ := aes.NewCipher(encKey[:])
|
||||
|
||||
stream := cipher.NewCTR(block, iv[:])
|
||||
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
return c.authCiphertext(authKey[:], ciphertext, associatedData), nil
|
||||
return c.authCiphertext(authKey[:], ciphertext, associatedData)
|
||||
}
|
||||
|
||||
func (c DefaultCrypto) Decrypt(mk [32]byte, authCiphertext, associatedData []byte) ([]byte, error) {
|
||||
|
@ -110,19 +106,16 @@ func (c DefaultCrypto) Decrypt(mk [32]byte, authCiphertext, associatedData []byt
|
|||
)
|
||||
|
||||
// Check the signature.
|
||||
encKey, authKey, _, err := c.deriveEncKeys(mk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encKey, authKey, _ := c.deriveEncKeys(mk)
|
||||
if s := c.authCiphertext(authKey[:], ciphertext, associatedData)[l-aes.BlockSize:]; !bytes.Equal(s, signature) {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
}
|
||||
|
||||
// Decrypt.
|
||||
block, err := aes.NewCipher(encKey[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create aes block cipher: %s", err)
|
||||
}
|
||||
|
||||
// No error will occur here as encKey is guaranteed to be 32 bytes.
|
||||
block, _ := aes.NewCipher(encKey[:])
|
||||
|
||||
var (
|
||||
stream = cipher.NewCTR(block, iv)
|
||||
plaintext = make([]byte, len(ciphertext))
|
||||
|
@ -133,7 +126,7 @@ func (c DefaultCrypto) Decrypt(mk [32]byte, authCiphertext, associatedData []byt
|
|||
}
|
||||
|
||||
// deriveEncKeys derive keys for message encryption and decryption. Returns (encKey, authKey, iv, err).
|
||||
func (c DefaultCrypto) deriveEncKeys(mk [32]byte) (encKey [32]byte, authKey [32]byte, iv [16]byte, err error) {
|
||||
func (c DefaultCrypto) deriveEncKeys(mk [32]byte) (encKey [32]byte, authKey [32]byte, iv [16]byte) {
|
||||
// TODO: Think about switching to sha512
|
||||
// First, derive encryption and authentication key out of mk.
|
||||
salt := make([]byte, 32)
|
||||
|
@ -142,10 +135,10 @@ func (c DefaultCrypto) deriveEncKeys(mk [32]byte) (encKey [32]byte, authKey [32]
|
|||
r = hkdf.New(sha256.New, mk[:], salt, []byte("pcwSByyx2CRdryCffXJwy7xgVZWtW5Sh"))
|
||||
buf = make([]byte, 80)
|
||||
)
|
||||
if _, err = io.ReadFull(r, buf); err != nil {
|
||||
err = fmt.Errorf("failed to generate encryption keys: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// The only error here is an entropy limit which won't be reached for such a short buffer.
|
||||
_, _ = io.ReadFull(r, buf)
|
||||
|
||||
copy(encKey[:], buf[0:32])
|
||||
copy(authKey[:], buf[32:64])
|
||||
copy(iv[:], buf[64:80])
|
||||
|
@ -154,9 +147,7 @@ func (c DefaultCrypto) deriveEncKeys(mk [32]byte) (encKey [32]byte, authKey [32]
|
|||
|
||||
func (c DefaultCrypto) authCiphertext(authKey, ciphertext, associatedData []byte) []byte {
|
||||
h := hmac.New(sha256.New, authKey)
|
||||
// TODO: Handle error?
|
||||
h.Write(associatedData)
|
||||
// TODO: Handle error?
|
||||
h.Write(ciphertext)
|
||||
return h.Sum(ciphertext)
|
||||
}
|
||||
|
|
27
state.go
27
state.go
|
@ -79,17 +79,14 @@ func New(sharedKey, dhRemotePubKey [32]byte) (*State, error) {
|
|||
}
|
||||
// FIXME: Make dhRemotePubKey optional.
|
||||
if len(dhRemotePubKey) > 0 {
|
||||
s.RK, s.CKs, err = s.Crypto.KdfRK(sharedKey, s.Crypto.DH(s.DHs, s.DHr))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to apply KdfRk: %s", err)
|
||||
}
|
||||
s.RK, s.CKs = s.Crypto.KdfRK(sharedKey, s.Crypto.DH(s.DHs, s.DHr))
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// RatchetEncrypt performs a symmetric-key ratchet step, then encrypts the message with
|
||||
// the resulting message key.
|
||||
func (s *State) RatchetEncrypt(plaintext []byte, ad AssociatedData) (Message, error) {
|
||||
func (s *State) RatchetEncrypt(plaintext []byte, ad AssociatedData) Message {
|
||||
var mk [32]byte
|
||||
s.CKs, mk = s.Crypto.KdfCK(s.CKs)
|
||||
h := MessageHeader{
|
||||
|
@ -98,15 +95,11 @@ func (s *State) RatchetEncrypt(plaintext []byte, ad AssociatedData) (Message, er
|
|||
PN: s.PN,
|
||||
}
|
||||
s.Ns++
|
||||
ciphertext, err := s.Crypto.Encrypt(mk, plaintext, h.EncodeWithAD(ad))
|
||||
// TODO: Rollback state when an error occurs.
|
||||
if err != nil {
|
||||
return Message{}, fmt.Errorf("failed to encrypt plaintext: %s", err)
|
||||
}
|
||||
ciphertext := s.Crypto.Encrypt(mk, plaintext, h.EncodeWithAD(ad))
|
||||
return Message{
|
||||
Header: h,
|
||||
Ciphertext: ciphertext,
|
||||
}, err
|
||||
}
|
||||
}
|
||||
|
||||
// RatchetDecrypt is called to decrypt messages.
|
||||
|
@ -121,7 +114,7 @@ func (s *State) RatchetDecrypt(m Message, ad AssociatedData) ([]byte, error) {
|
|||
if m.Header.DH != s.DHs.PublicKey {
|
||||
s.skipMessageKeys(m.Header.PN)
|
||||
if err := s.dhRatchet(m.Header); err != nil {
|
||||
// TODO: Discard state changes.
|
||||
// TODO: Rollback state changes.
|
||||
return nil, fmt.Errorf("failed to perform ratchet step: %s", err)
|
||||
}
|
||||
}
|
||||
|
@ -179,17 +172,11 @@ func (s *State) dhRatchet(mh MessageHeader) error {
|
|||
s.Ns = 0
|
||||
s.Nr = 0
|
||||
s.DHr = mh.DH
|
||||
s.RK, s.CKr, err = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to apply KdfRk: %s", err)
|
||||
}
|
||||
s.RK, s.CKr = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
|
||||
s.DHs, err = s.Crypto.GenerateDH()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate dh pair: %s", err)
|
||||
}
|
||||
s.RK, s.CKs, err = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to apply KdfRk: %s", err)
|
||||
}
|
||||
s.RK, s.CKs = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue