| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- package fte
- import (
- "crypto/rand"
- "encoding/binary"
- "errors"
- "io"
- "math/big"
- )
- var (
- ErrInsufficientCapacity = errors.New("fte: insufficient capacity")
- )
- type Cipher struct {
- dfa *DFA
- enc *Encrypter
- dec *Decrypter
- }
- // NewCipher returns a new instance of Cipher.
- func NewCipher(regex string, n int) (_ *Cipher, err error) {
- var c Cipher
- if c.enc, err = NewEncrypter(); err != nil {
- return nil, err
- } else if c.dec, err = NewDecrypter(); err != nil {
- return nil, err
- } else if c.dfa, err = NewDFA(regex, n); err != nil {
- return nil, err
- }
- return &c, nil
- }
- func (c *Cipher) Close() error {
- if c.dfa != nil {
- err := c.dfa.Close()
- c.dfa = nil
- return err
- }
- return nil
- }
- // Capacity returns the capacity left in the encoder.
- func (c *Cipher) Capacity() int {
- return c.dfa.Capacity()
- }
- // Encrypt encrypts plaintext into ciphertext.
- func (c *Cipher) Encrypt(plaintext []byte) (ciphertext []byte, err error) {
- if len(plaintext) == 0 {
- return nil, nil
- }
- if ciphertext, err = c.enc.Encrypt(plaintext); err != nil {
- return nil, err
- }
- maximumBytesToRank := c.Capacity()
- unrank_payload_len := (maximumBytesToRank - COVERTEXT_HEADER_LEN_CIPHERTTEXT)
- if len(ciphertext) < unrank_payload_len {
- unrank_payload_len = len(ciphertext)
- }
- if unrank_payload_len <= 0 {
- return nil, ErrInsufficientCapacity
- }
- msg_len_header := make([]byte, 16)
- if _, err := io.ReadFull(rand.Reader, msg_len_header[:8]); err != nil {
- return nil, err
- }
- binary.BigEndian.PutUint64(msg_len_header[8:], uint64(unrank_payload_len))
- encryptedHeader := make([]byte, len(msg_len_header))
- c.enc.block.Encrypt(encryptedHeader, msg_len_header)
- msg_len_header = encryptedHeader
- unrank_payload := encryptedHeader
- if len(ciphertext) <= maximumBytesToRank-16 {
- unrank_payload = append(unrank_payload, ciphertext...)
- } else {
- unrank_payload = append(unrank_payload, ciphertext[:maximumBytesToRank-16]...)
- }
- random_padding_len := maximumBytesToRank - len(unrank_payload)
- if random_padding_len > 0 {
- randomPadding := make([]byte, random_padding_len)
- if _, err := io.ReadFull(rand.Reader, randomPadding); err != nil {
- return nil, err
- }
- unrank_payload = append(unrank_payload, randomPadding...)
- }
- var unrankValue big.Int
- unrankValue.SetBytes(unrank_payload)
- formatted_covertext_header, err := c.dfa.Unrank(&unrankValue)
- if err != nil {
- return nil, err
- }
- var unformatted_covertext_body []byte
- if len(ciphertext) > maximumBytesToRank-16 {
- unformatted_covertext_body = ciphertext[maximumBytesToRank-16:]
- }
- return append([]byte(formatted_covertext_header), unformatted_covertext_body...), nil
- }
- // Decrypt decrypts ciphertext into plaintext.
- // Returns ErrShortCiphertext if the ciphertext is too short to be decrypted.
- func (c *Cipher) Decrypt(ciphertext []byte) (plaintext, remainder []byte, err error) {
- if len(ciphertext) < c.dfa.N() {
- return nil, nil, ErrShortCiphertext
- }
- maximumBytesToRank := c.Capacity()
- rank_payload, err := c.dfa.Rank(string(ciphertext[:c.dfa.N()]))
- if err != nil {
- return nil, nil, err
- }
- X := rank_payload.Bytes()
- if len(X) < maximumBytesToRank {
- X = append(make([]byte, maximumBytesToRank-len(X)), X...)
- }
- msg_len_header := make([]byte, 16)
- c.dec.block.Decrypt(msg_len_header, X[:16])
- msg_len := binary.BigEndian.Uint64(msg_len_header[8:16])
- retval := X[16 : 16+msg_len]
- retval = append(retval, ciphertext[c.dfa.N():]...)
- ctxt_len := c.dec.CiphertextLen(retval)
- var remaining_buffer []byte
- if len(retval) > ctxt_len {
- remaining_buffer = retval[ctxt_len:]
- }
- if len(retval) > ctxt_len {
- retval = retval[:ctxt_len]
- }
- if retval, err = c.dec.Decrypt(retval); err != nil {
- return nil, nil, err
- }
- return retval, remaining_buffer, nil
- }
|