• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package chacha20poly1305
6
7import (
8	"encoding/binary"
9
10	"golang.org/x/crypto/chacha20"
11	"golang.org/x/crypto/internal/alias"
12	"golang.org/x/crypto/internal/poly1305"
13)
14
15func writeWithPadding(p *poly1305.MAC, b []byte) {
16	p.Write(b)
17	if rem := len(b) % 16; rem != 0 {
18		var buf [16]byte
19		padLen := 16 - rem
20		p.Write(buf[:padLen])
21	}
22}
23
24func writeUint64(p *poly1305.MAC, n int) {
25	var buf [8]byte
26	binary.LittleEndian.PutUint64(buf[:], uint64(n))
27	p.Write(buf[:])
28}
29
30func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
31	ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
32	ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
33	if alias.InexactOverlap(out, plaintext) {
34		panic("chacha20poly1305: invalid buffer overlap")
35	}
36
37	var polyKey [32]byte
38	s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
39	s.XORKeyStream(polyKey[:], polyKey[:])
40	s.SetCounter(1) // set the counter to 1, skipping 32 bytes
41	s.XORKeyStream(ciphertext, plaintext)
42
43	p := poly1305.New(&polyKey)
44	writeWithPadding(p, additionalData)
45	writeWithPadding(p, ciphertext)
46	writeUint64(p, len(additionalData))
47	writeUint64(p, len(plaintext))
48	p.Sum(tag[:0])
49
50	return ret
51}
52
53func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
54	tag := ciphertext[len(ciphertext)-16:]
55	ciphertext = ciphertext[:len(ciphertext)-16]
56
57	var polyKey [32]byte
58	s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
59	s.XORKeyStream(polyKey[:], polyKey[:])
60	s.SetCounter(1) // set the counter to 1, skipping 32 bytes
61
62	p := poly1305.New(&polyKey)
63	writeWithPadding(p, additionalData)
64	writeWithPadding(p, ciphertext)
65	writeUint64(p, len(additionalData))
66	writeUint64(p, len(ciphertext))
67
68	ret, out := sliceForAppend(dst, len(ciphertext))
69	if alias.InexactOverlap(out, ciphertext) {
70		panic("chacha20poly1305: invalid buffer overlap")
71	}
72	if !p.Verify(tag) {
73		for i := range out {
74			out[i] = 0
75		}
76		return nil, errOpen
77	}
78
79	s.XORKeyStream(out, ciphertext)
80	return ret, nil
81}
82