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