func (c *cipher) DecryptHandshake(localKey cipherset.Key, p []byte) (cipherset.Handshake, error) { if len(p) < 21+4+4 { return nil, cipherset.ErrInvalidMessage } var ( ctLen = len(p) - (21 + 4 + 4) out = bufpool.New() cs1aLocalKey, _ = localKey.(*key) remoteKey *key remoteLineKey *key hshake *handshake remoteLineKeyData = p[:21] iv = p[21 : 21+4] ciphertext = p[21+4 : 21+4+ctLen] mac = p[21+4+ctLen:] ) if cs1aLocalKey == nil { return nil, cipherset.ErrInvalidState } { // decrypt inner ephemX, ephemY := eccp.Unmarshal(secp160r1.P160(), remoteLineKeyData) if ephemX == nil || ephemY == nil { return nil, cipherset.ErrInvalidMessage } shared := ecdh.ComputeShared(secp160r1.P160(), ephemX, ephemY, cs1aLocalKey.prv.d) if shared == nil { return nil, cipherset.ErrInvalidMessage } aharedSum := sha256.Sum256(shared) aesKey := fold(aharedSum[:], 16) if aesKey == nil { return nil, cipherset.ErrInvalidMessage } aesBlock, err := aes.NewCipher(aesKey) if err != nil { return nil, cipherset.ErrInvalidMessage } var aesIv [16]byte copy(aesIv[:], iv) aes := Cipher.NewCTR(aesBlock, aesIv[:]) if aes == nil { return nil, cipherset.ErrInvalidMessage } out.SetLen(ctLen) aes.XORKeyStream(out.RawBytes(), ciphertext) remoteLineKey = &key{} remoteLineKey.pub.x, remoteLineKey.pub.y = ephemX, ephemY } { // decode inner inner, err := lob.Decode(out) if err != nil { return nil, cipherset.ErrInvalidMessage } at, hasAt := inner.Header().GetUint32("at") if !hasAt { return nil, cipherset.ErrInvalidMessage } delete(inner.Header().Extra, "at") parts, err := cipherset.PartsFromHeader(inner.Header()) if err != nil { return nil, cipherset.ErrInvalidMessage } if inner.BodyLen() != 21 { return nil, cipherset.ErrInvalidMessage } remoteKey = &key{} remoteKey.pub.x, remoteKey.pub.y = eccp.Unmarshal(secp160r1.P160(), inner.Body(nil)) if !remoteKey.CanEncrypt() { return nil, cipherset.ErrInvalidMessage } hshake = &handshake{} hshake.at = at hshake.key = remoteKey hshake.lineKey = remoteLineKey hshake.parts = parts } { // verify mac var nonce [16]byte copy(nonce[:], iv) macKey := ecdh.ComputeShared(secp160r1.P160(), remoteKey.pub.x, remoteKey.pub.y, cs1aLocalKey.prv.d) macKey = append(macKey, nonce[:]...) h := hmac.New(sha256.New, macKey) h.Write(p[:21+4+ctLen]) if subtle.ConstantTimeCompare(mac, fold(h.Sum(nil), 4)) != 1 { return nil, cipherset.ErrInvalidMessage } } return hshake, nil }
func (c *cipher) DecryptHandshake(localKey cipherset.Key, p []byte) (cipherset.Handshake, error) { if len(p) < lenKey+lenNonce+lenAuth { return nil, cipherset.ErrInvalidMessage } var ( ctLen = len(p) - (lenKey + lenNonce + lenAuth) out = bufpool.New() handshake = &handshake{} cs3aLocalKey, _ = localKey.(*key) at uint32 hasAt bool mac [lenAuth]byte nonce [lenNonce]byte macKey [lenKey]byte agreedKey [lenKey]byte remoteKey [lenKey]byte remoteLineKey [lenKey]byte ciphertext []byte ok bool ) if cs3aLocalKey == nil { return nil, cipherset.ErrInvalidState } copy(remoteLineKey[:], p[:lenKey]) copy(nonce[:], p[lenKey:lenKey+lenNonce]) copy(mac[:], p[lenKey+lenNonce+ctLen:]) ciphertext = p[lenKey+lenNonce : lenKey+lenNonce+ctLen] // make agreedKey box.Precompute(&agreedKey, &remoteLineKey, cs3aLocalKey.prv) // decode BODY outBuf, ok := box.OpenAfterPrecomputation(out.RawBytes(), ciphertext, &nonce, &agreedKey) if !ok { return nil, cipherset.ErrInvalidMessage } out.SetLen(len(outBuf)) { // decode inner inner, err := lob.Decode(out) if err != nil { return nil, cipherset.ErrInvalidMessage } at, hasAt = inner.Header().GetUint32("at") if !hasAt { return nil, cipherset.ErrInvalidMessage } delete(inner.Header().Extra, "at") parts, err := cipherset.PartsFromHeader(inner.Header()) if err != nil { return nil, cipherset.ErrInvalidMessage } if inner.BodyLen() != lenKey { return nil, cipherset.ErrInvalidMessage } inner.Body(remoteKey[:0]) handshake.at = at handshake.key = makeKey(nil, &remoteKey) handshake.lineKey = makeKey(nil, &remoteLineKey) handshake.parts = parts } { // make macKey box.Precompute(&macKey, &remoteKey, cs3aLocalKey.prv) var ( sha = sha256.New() ) sha.Write(p[lenKey : lenKey+lenNonce]) sha.Write(macKey[:]) sha.Sum(macKey[:0]) } if !poly1305.Verify(&mac, p[:lenKey+lenNonce+ctLen], &macKey) { return nil, cipherset.ErrInvalidMessage } return handshake, nil }