aboutsummaryrefslogtreecommitdiff
path: root/cipher.go
blob: a75e3f70027376c423147d5ad0d0d73611154576 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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