github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/shadowsocks/shadowaead/cipher.go (about)

     1  package shadowaead
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/sha1"
     7  	"errors"
     8  	"io"
     9  	"strconv"
    10  
    11  	"golang.org/x/crypto/chacha20poly1305"
    12  	"golang.org/x/crypto/hkdf"
    13  )
    14  
    15  // ErrRepeatedSalt means detected a reused salt
    16  var ErrRepeatedSalt = errors.New("repeated salt detected")
    17  
    18  type Cipher interface {
    19  	KeySize() int
    20  	SaltSize() int
    21  	Encrypter(salt []byte) (cipher.AEAD, error)
    22  	Decrypter(salt []byte) (cipher.AEAD, error)
    23  }
    24  
    25  type KeySizeError int
    26  
    27  func (e KeySizeError) Error() string {
    28  	return "key size error: need " + strconv.Itoa(int(e)) + " bytes"
    29  }
    30  
    31  func hkdfSHA1(secret, salt, info, outkey []byte) {
    32  	r := hkdf.New(sha1.New, secret, salt, info)
    33  	if _, err := io.ReadFull(r, outkey); err != nil {
    34  		panic(err) // should never happen
    35  	}
    36  }
    37  
    38  type metaCipher struct {
    39  	psk      []byte
    40  	makeAEAD func(key []byte) (cipher.AEAD, error)
    41  }
    42  
    43  func (a *metaCipher) KeySize() int { return len(a.psk) }
    44  func (a *metaCipher) SaltSize() int {
    45  	if ks := a.KeySize(); ks > 16 {
    46  		return ks
    47  	}
    48  	return 16
    49  }
    50  func (a *metaCipher) Encrypter(salt []byte) (cipher.AEAD, error) {
    51  	subkey := make([]byte, a.KeySize())
    52  	hkdfSHA1(a.psk, salt, []byte("ss-subkey"), subkey)
    53  	return a.makeAEAD(subkey)
    54  }
    55  func (a *metaCipher) Decrypter(salt []byte) (cipher.AEAD, error) {
    56  	subkey := make([]byte, a.KeySize())
    57  	hkdfSHA1(a.psk, salt, []byte("ss-subkey"), subkey)
    58  	return a.makeAEAD(subkey)
    59  }
    60  
    61  func aesGCM(key []byte) (cipher.AEAD, error) {
    62  	blk, err := aes.NewCipher(key)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	return cipher.NewGCM(blk)
    67  }
    68  
    69  // AESGCM creates a new Cipher with a pre-shared key. len(psk) must be
    70  // one of 16, 24, or 32 to select AES-128/196/256-GCM.
    71  func AESGCM(psk []byte) (Cipher, error) {
    72  	switch l := len(psk); l {
    73  	case 16, 24, 32: // AES 128/196/256
    74  	default:
    75  		return nil, aes.KeySizeError(l)
    76  	}
    77  	return &metaCipher{psk: psk, makeAEAD: aesGCM}, nil
    78  }
    79  
    80  // Chacha20Poly1305 creates a new Cipher with a pre-shared key. len(psk)
    81  // must be 32.
    82  func Chacha20Poly1305(psk []byte) (Cipher, error) {
    83  	if len(psk) != chacha20poly1305.KeySize {
    84  		return nil, KeySizeError(chacha20poly1305.KeySize)
    85  	}
    86  	return &metaCipher{psk: psk, makeAEAD: chacha20poly1305.New}, nil
    87  }