Initial commit
This commit is contained in:
73
record.go
Normal file
73
record.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package lafsession
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
const (
|
||||
recordHeaderLen = 1 + 8
|
||||
|
||||
recordTypeData byte = 0x10
|
||||
recordTypeClose byte = 0x11
|
||||
)
|
||||
|
||||
func newAEAD(key []byte) (cipher.AEAD, error) {
|
||||
return chacha20poly1305.New(key)
|
||||
}
|
||||
|
||||
func sealRecord(aead cipher.AEAD, seq uint64, recType byte, plaintext, dst []byte, nonce *[nonceLen]byte, aad *[recordHeaderLen]byte) []byte {
|
||||
aad[0] = recType
|
||||
binary.BigEndian.PutUint64(aad[1:], seq)
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
nonce[i] = 0
|
||||
}
|
||||
binary.BigEndian.PutUint64(nonce[4:], seq)
|
||||
|
||||
need := recordHeaderLen + len(plaintext) + aead.Overhead()
|
||||
if cap(dst) < need {
|
||||
dst = make([]byte, need)
|
||||
} else {
|
||||
dst = dst[:need]
|
||||
}
|
||||
dst[0] = recType
|
||||
binary.BigEndian.PutUint64(dst[1:9], seq)
|
||||
_ = aead.Seal(dst[recordHeaderLen:recordHeaderLen], nonce[:], plaintext, aad[:])
|
||||
return dst
|
||||
}
|
||||
|
||||
// openRecord decrypts a full frame. Returns record type and plaintext (reusing dst when possible).
|
||||
func openRecord(aead cipher.AEAD, frame, dst []byte, nonce *[nonceLen]byte, aad *[recordHeaderLen]byte) (recType byte, plaintext []byte, err error) {
|
||||
if len(frame) < recordHeaderLen+aead.Overhead() {
|
||||
return 0, nil, ErrShortMessage
|
||||
}
|
||||
recType = frame[0]
|
||||
seq := binary.BigEndian.Uint64(frame[1:9])
|
||||
|
||||
aad[0] = recType
|
||||
binary.BigEndian.PutUint64(aad[1:], seq)
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
nonce[i] = 0
|
||||
}
|
||||
binary.BigEndian.PutUint64(nonce[4:], seq)
|
||||
|
||||
ct := frame[recordHeaderLen:]
|
||||
ptLen := len(ct) - aead.Overhead()
|
||||
if ptLen < 0 {
|
||||
return 0, nil, ErrShortMessage
|
||||
}
|
||||
if cap(dst) < ptLen {
|
||||
dst = make([]byte, ptLen)
|
||||
} else {
|
||||
dst = dst[:ptLen]
|
||||
}
|
||||
out, err := aead.Open(dst[:0], nonce[:], ct, aad[:])
|
||||
if err != nil {
|
||||
return 0, nil, ErrBadTag
|
||||
}
|
||||
return recType, out, nil
|
||||
}
|
||||
Reference in New Issue
Block a user