Got rid off unnecessary errors handling

This commit is contained in:
Ivan Tomilov 2017-06-12 16:16:43 +07:00
parent d83171d325
commit c0ae542945
3 changed files with 30 additions and 52 deletions

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}