github.com/fiagdao/tendermint@v0.32.11-0.20220824195748-2087fcc480c1/crypto/xchacha20poly1305/xchachapoly.go (about)

     1  // Package xchacha20poly1305 creates an AEAD using hchacha, chacha, and poly1305
     2  // This allows for randomized nonces to be used in conjunction with chacha.
     3  package xchacha20poly1305
     4  
     5  import (
     6  	"crypto/cipher"
     7  	"encoding/binary"
     8  	"errors"
     9  	"fmt"
    10  
    11  	"golang.org/x/crypto/chacha20poly1305"
    12  )
    13  
    14  // Implements crypto.AEAD
    15  type xchacha20poly1305 struct {
    16  	key [KeySize]byte
    17  }
    18  
    19  const (
    20  	// KeySize is the size of the key used by this AEAD, in bytes.
    21  	KeySize = 32
    22  	// NonceSize is the size of the nonce used with this AEAD, in bytes.
    23  	NonceSize = 24
    24  	// TagSize is the size added from poly1305
    25  	TagSize = 16
    26  	// MaxPlaintextSize is the max size that can be passed into a single call of Seal
    27  	MaxPlaintextSize = (1 << 38) - 64
    28  	// MaxCiphertextSize is the max size that can be passed into a single call of Open,
    29  	// this differs from plaintext size due to the tag
    30  	MaxCiphertextSize = (1 << 38) - 48
    31  
    32  	// sigma are constants used in xchacha.
    33  	// Unrolled from a slice so that they can be inlined, as slices can't be constants.
    34  	sigma0 = uint32(0x61707865)
    35  	sigma1 = uint32(0x3320646e)
    36  	sigma2 = uint32(0x79622d32)
    37  	sigma3 = uint32(0x6b206574)
    38  )
    39  
    40  // New returns a new xchachapoly1305 AEAD
    41  func New(key []byte) (cipher.AEAD, error) {
    42  	if len(key) != KeySize {
    43  		return nil, errors.New("xchacha20poly1305: bad key length")
    44  	}
    45  	ret := new(xchacha20poly1305)
    46  	copy(ret.key[:], key)
    47  	return ret, nil
    48  }
    49  
    50  // nolint
    51  func (c *xchacha20poly1305) NonceSize() int {
    52  	return NonceSize
    53  }
    54  
    55  // nolint
    56  func (c *xchacha20poly1305) Overhead() int {
    57  	return TagSize
    58  }
    59  
    60  func (c *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
    61  	if len(nonce) != NonceSize {
    62  		panic("xchacha20poly1305: bad nonce length passed to Seal")
    63  	}
    64  
    65  	if uint64(len(plaintext)) > MaxPlaintextSize {
    66  		panic("xchacha20poly1305: plaintext too large")
    67  	}
    68  
    69  	var subKey [KeySize]byte
    70  	var hNonce [16]byte
    71  	var subNonce [chacha20poly1305.NonceSize]byte
    72  	copy(hNonce[:], nonce[:16])
    73  
    74  	HChaCha20(&subKey, &hNonce, &c.key)
    75  
    76  	// This can't error because we always provide a correctly sized key
    77  	chacha20poly1305, _ := chacha20poly1305.New(subKey[:])
    78  
    79  	copy(subNonce[4:], nonce[16:])
    80  
    81  	return chacha20poly1305.Seal(dst, subNonce[:], plaintext, additionalData)
    82  }
    83  
    84  func (c *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
    85  	if len(nonce) != NonceSize {
    86  		return nil, fmt.Errorf("xchacha20poly1305: bad nonce length passed to Open")
    87  	}
    88  	if uint64(len(ciphertext)) > MaxCiphertextSize {
    89  		return nil, fmt.Errorf("xchacha20poly1305: ciphertext too large")
    90  	}
    91  	var subKey [KeySize]byte
    92  	var hNonce [16]byte
    93  	var subNonce [chacha20poly1305.NonceSize]byte
    94  	copy(hNonce[:], nonce[:16])
    95  
    96  	HChaCha20(&subKey, &hNonce, &c.key)
    97  
    98  	// This can't error because we always provide a correctly sized key
    99  	chacha20poly1305, _ := chacha20poly1305.New(subKey[:])
   100  
   101  	copy(subNonce[4:], nonce[16:])
   102  
   103  	return chacha20poly1305.Open(dst, subNonce[:], ciphertext, additionalData)
   104  }
   105  
   106  // HChaCha exported from
   107  // https://github.com/aead/chacha20/blob/8b13a72661dae6e9e5dea04f344f0dc95ea29547/chacha/chacha_generic.go#L194
   108  // TODO: Add support for the different assembly instructions used there.
   109  
   110  // The MIT License (MIT)
   111  
   112  // Copyright (c) 2016 Andreas Auernhammer
   113  
   114  // Permission is hereby granted, free of charge, to any person obtaining a copy
   115  // of this software and associated documentation files (the "Software"), to deal
   116  // in the Software without restriction, including without limitation the rights
   117  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   118  // copies of the Software, and to permit persons to whom the Software is
   119  // furnished to do so, subject to the following conditions:
   120  
   121  // The above copyright notice and this permission notice shall be included in all
   122  // copies or substantial portions of the Software.
   123  
   124  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   125  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   126  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   127  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   128  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   129  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   130  // SOFTWARE.
   131  
   132  // HChaCha20 generates 32 pseudo-random bytes from a 128 bit nonce and a 256 bit secret key.
   133  // It can be used as a key-derivation-function (KDF).
   134  func HChaCha20(out *[32]byte, nonce *[16]byte, key *[32]byte) { hChaCha20Generic(out, nonce, key) }
   135  
   136  func hChaCha20Generic(out *[32]byte, nonce *[16]byte, key *[32]byte) {
   137  	v00 := sigma0
   138  	v01 := sigma1
   139  	v02 := sigma2
   140  	v03 := sigma3
   141  	v04 := binary.LittleEndian.Uint32(key[0:])
   142  	v05 := binary.LittleEndian.Uint32(key[4:])
   143  	v06 := binary.LittleEndian.Uint32(key[8:])
   144  	v07 := binary.LittleEndian.Uint32(key[12:])
   145  	v08 := binary.LittleEndian.Uint32(key[16:])
   146  	v09 := binary.LittleEndian.Uint32(key[20:])
   147  	v10 := binary.LittleEndian.Uint32(key[24:])
   148  	v11 := binary.LittleEndian.Uint32(key[28:])
   149  	v12 := binary.LittleEndian.Uint32(nonce[0:])
   150  	v13 := binary.LittleEndian.Uint32(nonce[4:])
   151  	v14 := binary.LittleEndian.Uint32(nonce[8:])
   152  	v15 := binary.LittleEndian.Uint32(nonce[12:])
   153  
   154  	for i := 0; i < 20; i += 2 {
   155  		v00 += v04
   156  		v12 ^= v00
   157  		v12 = (v12 << 16) | (v12 >> 16)
   158  		v08 += v12
   159  		v04 ^= v08
   160  		v04 = (v04 << 12) | (v04 >> 20)
   161  		v00 += v04
   162  		v12 ^= v00
   163  		v12 = (v12 << 8) | (v12 >> 24)
   164  		v08 += v12
   165  		v04 ^= v08
   166  		v04 = (v04 << 7) | (v04 >> 25)
   167  		v01 += v05
   168  		v13 ^= v01
   169  		v13 = (v13 << 16) | (v13 >> 16)
   170  		v09 += v13
   171  		v05 ^= v09
   172  		v05 = (v05 << 12) | (v05 >> 20)
   173  		v01 += v05
   174  		v13 ^= v01
   175  		v13 = (v13 << 8) | (v13 >> 24)
   176  		v09 += v13
   177  		v05 ^= v09
   178  		v05 = (v05 << 7) | (v05 >> 25)
   179  		v02 += v06
   180  		v14 ^= v02
   181  		v14 = (v14 << 16) | (v14 >> 16)
   182  		v10 += v14
   183  		v06 ^= v10
   184  		v06 = (v06 << 12) | (v06 >> 20)
   185  		v02 += v06
   186  		v14 ^= v02
   187  		v14 = (v14 << 8) | (v14 >> 24)
   188  		v10 += v14
   189  		v06 ^= v10
   190  		v06 = (v06 << 7) | (v06 >> 25)
   191  		v03 += v07
   192  		v15 ^= v03
   193  		v15 = (v15 << 16) | (v15 >> 16)
   194  		v11 += v15
   195  		v07 ^= v11
   196  		v07 = (v07 << 12) | (v07 >> 20)
   197  		v03 += v07
   198  		v15 ^= v03
   199  		v15 = (v15 << 8) | (v15 >> 24)
   200  		v11 += v15
   201  		v07 ^= v11
   202  		v07 = (v07 << 7) | (v07 >> 25)
   203  		v00 += v05
   204  		v15 ^= v00
   205  		v15 = (v15 << 16) | (v15 >> 16)
   206  		v10 += v15
   207  		v05 ^= v10
   208  		v05 = (v05 << 12) | (v05 >> 20)
   209  		v00 += v05
   210  		v15 ^= v00
   211  		v15 = (v15 << 8) | (v15 >> 24)
   212  		v10 += v15
   213  		v05 ^= v10
   214  		v05 = (v05 << 7) | (v05 >> 25)
   215  		v01 += v06
   216  		v12 ^= v01
   217  		v12 = (v12 << 16) | (v12 >> 16)
   218  		v11 += v12
   219  		v06 ^= v11
   220  		v06 = (v06 << 12) | (v06 >> 20)
   221  		v01 += v06
   222  		v12 ^= v01
   223  		v12 = (v12 << 8) | (v12 >> 24)
   224  		v11 += v12
   225  		v06 ^= v11
   226  		v06 = (v06 << 7) | (v06 >> 25)
   227  		v02 += v07
   228  		v13 ^= v02
   229  		v13 = (v13 << 16) | (v13 >> 16)
   230  		v08 += v13
   231  		v07 ^= v08
   232  		v07 = (v07 << 12) | (v07 >> 20)
   233  		v02 += v07
   234  		v13 ^= v02
   235  		v13 = (v13 << 8) | (v13 >> 24)
   236  		v08 += v13
   237  		v07 ^= v08
   238  		v07 = (v07 << 7) | (v07 >> 25)
   239  		v03 += v04
   240  		v14 ^= v03
   241  		v14 = (v14 << 16) | (v14 >> 16)
   242  		v09 += v14
   243  		v04 ^= v09
   244  		v04 = (v04 << 12) | (v04 >> 20)
   245  		v03 += v04
   246  		v14 ^= v03
   247  		v14 = (v14 << 8) | (v14 >> 24)
   248  		v09 += v14
   249  		v04 ^= v09
   250  		v04 = (v04 << 7) | (v04 >> 25)
   251  	}
   252  
   253  	binary.LittleEndian.PutUint32(out[0:], v00)
   254  	binary.LittleEndian.PutUint32(out[4:], v01)
   255  	binary.LittleEndian.PutUint32(out[8:], v02)
   256  	binary.LittleEndian.PutUint32(out[12:], v03)
   257  	binary.LittleEndian.PutUint32(out[16:], v12)
   258  	binary.LittleEndian.PutUint32(out[20:], v13)
   259  	binary.LittleEndian.PutUint32(out[24:], v14)
   260  	binary.LittleEndian.PutUint32(out[28:], v15)
   261  }