aboutsummaryrefslogblamecommitdiff
path: root/cipher.go
blob: a75e3f70027376c423147d5ad0d0d73611154576 (plain) (tree)
1
2
3
4
5
6
7
8
9







                          
                                 




                                                                     


















                                                                           
                                 












                                                                              
                                                  
                                                               












































                                                                                        
                                                   
                                                               


















                                                                                  



                                               



                                                      





                                                                        



                                                     

                                                      
package rabaead

import (
	"crypto/cipher"
	"errors"

	"snix.ir/poly1305"
	"snix.ir/rabbitio"
	"snix.ir/rabbitio/subtle"
)

const polykeylen = 0x20 // poly1305 key len: 32byte

var ErrAuthMsg = errors.New("rabaead: message authentication failed")

type rabbitPoly1305 struct {
	key       []byte // rabbit cipher key
	noncesize int    // rabbit iv size
}

// NewAEAD returns a rabbit aead data-type
// key must be 16 byte len
func NewAEAD(key []byte) (cipher.AEAD, error) { return newRabbitAead(key) }

func newRabbitAead(key []byte) (cipher.AEAD, error) {
	if len(key) != rabbitio.KeyLen {
		return nil, rabbitio.ErrInvalidKey
	}

	rabbitAead := &rabbitPoly1305{
		noncesize: rabbitio.IVXLen,
		key:       make([]byte, rabbitio.KeyLen),
	}
	copy(rabbitAead.key, key)
	return rabbitAead, nil

}

// Overhead returns poly1305 tag size: 16byte
func (c *rabbitPoly1305) Overhead() int { return poly1305.TagSize }

// NonceSize returns rabbit iv len: 8byte
func (c *rabbitPoly1305) NonceSize() int { return c.noncesize }

func (c *rabbitPoly1305) sealRabbit(dst, nonce, plaintext, ad []byte) []byte {
	ret, out := headtail(dst, len(plaintext)+poly1305.TagSize)
	ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
	if subtle.InexactOverlap(out, plaintext) {
		panic("rabaead: invalid buffer memory overlap")
	}

	var polyKey [polykeylen]byte
	s, err := rabbitio.NewCipher(c.key, nonce)
	if err != nil {
		panic(err)
	}
	s.XORKeyStream(polyKey[:], polyKey[:])
	p := poly1305.New(&polyKey)
	writePadding(p, ad)

	s, err = rabbitio.NewCipher(c.key, nonce)
	if err != nil {
		panic(err)
	}
	s.XORKeyStream(ciphertext, plaintext)

	writePadding(p, ciphertext)

	writeUint64(p, len(ad))
	writeUint64(p, len(plaintext))
	p.Sum(tag[:0x00])

	return ret
}

func (c *rabbitPoly1305) openRabbit(dst, nonce, ciphertext, ad []byte) ([]byte, error) {
	tag := ciphertext[len(ciphertext)-poly1305.TagSize:]
	ciphertext = ciphertext[:len(ciphertext)-poly1305.TagSize]

	var polyKey [polykeylen]byte
	s, err := rabbitio.NewCipher(c.key, nonce)
	if err != nil {
		panic(err)
	}
	s.XORKeyStream(polyKey[:], polyKey[:])

	p := poly1305.New(&polyKey)
	writePadding(p, ad)
	writePadding(p, ciphertext)

	writeUint64(p, len(ad))
	writeUint64(p, len(ciphertext))

	ret, out := headtail(dst, len(ciphertext))
	if subtle.InexactOverlap(out, ciphertext) {
		panic("rabaead: invalid buffer memory overlap")
	}

	// check data integrity
	if !p.Verify(tag) {
		return nil, ErrAuthMsg
	}

	s, err = rabbitio.NewCipher(c.key, nonce)
	if err != nil {
		panic(err)
	}
	s.XORKeyStream(out, ciphertext)
	return ret, nil
}

// Open opens a rabbit aead ciphertext.
// panic occurs if nonce len is not equal to IVXLen (8byte) or zero
// if data is not verified, ErrAuthMsg will be returned
func (c *rabbitPoly1305) Open(dst, nonce, ciphertext, ad []byte) ([]byte, error) {
	if len(ciphertext) < poly1305.TagSize {
		return nil, ErrAuthMsg
	}

	if uint64(len(ciphertext)) > (1<<38)-48 {
		panic("rabaead: ciphertext too large")
	}

	return c.openRabbit(dst, nonce, ciphertext, ad)
}

// Seal seals a plaintext into the rabbit aead ciphertext.
// panic occurs if nonce len is not equal to IVXLen (8byte) or zero
func (c *rabbitPoly1305) Seal(dst, nonce, plaintext, ad []byte) []byte {
	if uint64(len(plaintext)) > (1<<38)-64 {
		panic("rabaead: plaintext too large")
	}

	return c.sealRabbit(dst, nonce, plaintext, ad)
}

Snix LLC Git Repository Holder Copyright(C) 2022 All Rights Reserved Email To Snix.IR