in otr/otr.go [867:959]
func (c *Conversation) processData(in []byte) (out []byte, tlvs []tlv, err error) {
origIn := in
flags, in, ok1 := getU8(in)
theirKeyId, in, ok2 := getU32(in)
myKeyId, in, ok3 := getU32(in)
y, in, ok4 := getMPI(in)
counter, in, ok5 := getNBytes(in, 8)
encrypted, in, ok6 := getData(in)
macedData := origIn[:len(origIn)-len(in)]
theirMAC, in, ok7 := getNBytes(in, macPrefixBytes)
_, in, ok8 := getData(in)
if !ok1 || !ok2 || !ok3 || !ok4 || !ok5 || !ok6 || !ok7 || !ok8 || len(in) > 0 {
err = errors.New("otr: corrupt data message")
return
}
ignoreErrors := flags&1 != 0
slot, err := c.calcDataKeys(myKeyId, theirKeyId)
if err != nil {
if ignoreErrors {
err = nil
}
return
}
mac := hmac.New(sha1.New, slot.recvMACKey)
mac.Write([]byte{0, 2, 3})
mac.Write(macedData)
myMAC := mac.Sum(nil)
if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
if !ignoreErrors {
err = errors.New("otr: bad MAC on data message")
}
return
}
if bytes.Compare(counter, slot.theirLastCtr[:]) <= 0 {
err = errors.New("otr: counter regressed")
return
}
copy(slot.theirLastCtr[:], counter)
var iv [aes.BlockSize]byte
copy(iv[:], counter)
aesCipher, err := aes.NewCipher(slot.recvAESKey)
if err != nil {
panic(err.Error())
}
ctr := cipher.NewCTR(aesCipher, iv[:])
ctr.XORKeyStream(encrypted, encrypted)
decrypted := encrypted
if myKeyId == c.myKeyId {
c.rotateDHKeys()
}
if theirKeyId == c.theirKeyId {
// evict slots using their retired key id
for i := range c.keySlots {
slot := &c.keySlots[i]
if slot.used && slot.theirKeyId == theirKeyId-1 {
slot.used = false
c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
}
}
c.theirLastDHPub = c.theirCurrentDHPub
c.theirKeyId++
c.theirCurrentDHPub = y
}
if nulPos := bytes.IndexByte(decrypted, 0); nulPos >= 0 {
out = decrypted[:nulPos]
tlvData := decrypted[nulPos+1:]
for len(tlvData) > 0 {
var t tlv
var ok1, ok2, ok3 bool
t.typ, tlvData, ok1 = getU16(tlvData)
t.length, tlvData, ok2 = getU16(tlvData)
t.data, tlvData, ok3 = getNBytes(tlvData, int(t.length))
if !ok1 || !ok2 || !ok3 {
err = errors.New("otr: corrupt tlv data")
return
}
tlvs = append(tlvs, t)
}
} else {
out = decrypted
}
return
}