github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/internal/x/crypto/chacha20poly1305/chacha20poly1305_generic.go (about)

     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  
     5  package chacha20poly1305
     6  
     7  import (
     8  	"encoding/binary"
     9  
    10  	"github.com/icodeface/tls/internal/x/crypto/internal/chacha20"
    11  	"github.com/icodeface/tls/internal/x/crypto/poly1305"
    12  )
    13  
    14  func roundTo16(n int) int {
    15  	return 16 * ((n + 15) / 16)
    16  }
    17  
    18  func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
    19  	ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
    20  
    21  	var polyKey [32]byte
    22  	s := chacha20.New(c.key, [3]uint32{
    23  		binary.LittleEndian.Uint32(nonce[0:4]),
    24  		binary.LittleEndian.Uint32(nonce[4:8]),
    25  		binary.LittleEndian.Uint32(nonce[8:12]),
    26  	})
    27  	s.XORKeyStream(polyKey[:], polyKey[:])
    28  	s.Advance() // skip the next 32 bytes
    29  	s.XORKeyStream(out, plaintext)
    30  
    31  	polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8)
    32  	copy(polyInput, additionalData)
    33  	copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)])
    34  	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
    35  	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext)))
    36  
    37  	var tag [poly1305.TagSize]byte
    38  	poly1305.Sum(&tag, polyInput, &polyKey)
    39  	copy(out[len(plaintext):], tag[:])
    40  
    41  	return ret
    42  }
    43  
    44  func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
    45  	var tag [poly1305.TagSize]byte
    46  	copy(tag[:], ciphertext[len(ciphertext)-16:])
    47  	ciphertext = ciphertext[:len(ciphertext)-16]
    48  
    49  	var polyKey [32]byte
    50  	s := chacha20.New(c.key, [3]uint32{
    51  		binary.LittleEndian.Uint32(nonce[0:4]),
    52  		binary.LittleEndian.Uint32(nonce[4:8]),
    53  		binary.LittleEndian.Uint32(nonce[8:12]),
    54  	})
    55  	s.XORKeyStream(polyKey[:], polyKey[:])
    56  	s.Advance() // skip the next 32 bytes
    57  
    58  	polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8)
    59  	copy(polyInput, additionalData)
    60  	copy(polyInput[roundTo16(len(additionalData)):], ciphertext)
    61  	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
    62  	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
    63  
    64  	ret, out := sliceForAppend(dst, len(ciphertext))
    65  	if !poly1305.Verify(&tag, polyInput, &polyKey) {
    66  		for i := range out {
    67  			out[i] = 0
    68  		}
    69  		return nil, errOpen
    70  	}
    71  
    72  	s.XORKeyStream(out, ciphertext)
    73  	return ret, nil
    74  }