From c0ae542945b6f29d9d5935a7e5a77081a08a743c Mon Sep 17 00:00:00 2001 From: Ivan Tomilov Date: Mon, 12 Jun 2017 16:16:43 +0700 Subject: [PATCH] Got rid off unnecessary errors handling --- crypto.go | 4 ++-- crypto_recommended.go | 51 ++++++++++++++++++------------------------- state.go | 27 ++++++----------------- 3 files changed, 30 insertions(+), 52 deletions(-) diff --git a/crypto.go b/crypto.go index 614f8d2..b9e7708 100644 --- a/crypto.go +++ b/crypto.go @@ -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) diff --git a/crypto_recommended.go b/crypto_recommended.go index 51960a8..40b1a82 100644 --- a/crypto_recommended.go +++ b/crypto_recommended.go @@ -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) } diff --git a/state.go b/state.go index d2d8b81..2f45a4a 100644 --- a/state.go +++ b/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 }