mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-12-27 04:25:44 -05:00
implementation for Shadowsocks AEAD
This commit is contained in:
@@ -2,9 +2,17 @@ package shadowsocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/crypto"
|
||||
"v2ray.com/core/common/protocol"
|
||||
)
|
||||
@@ -22,6 +30,20 @@ func (v *ShadowsocksAccount) Equals(another protocol.Account) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func createAesGcm(key []byte) cipher.AEAD {
|
||||
block, err := aes.NewCipher(key)
|
||||
common.Must(err)
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
common.Must(err)
|
||||
return gcm
|
||||
}
|
||||
|
||||
func createChacha20Poly1305(key []byte) cipher.AEAD {
|
||||
chacha20, err := chacha20poly1305.New(key)
|
||||
common.Must(err)
|
||||
return chacha20
|
||||
}
|
||||
|
||||
func (v *Account) GetCipher() (Cipher, error) {
|
||||
switch v.CipherType {
|
||||
case CipherType_AES_128_CFB:
|
||||
@@ -32,6 +54,24 @@ func (v *Account) GetCipher() (Cipher, error) {
|
||||
return &ChaCha20{IVBytes: 8}, nil
|
||||
case CipherType_CHACHA20_IETF:
|
||||
return &ChaCha20{IVBytes: 12}, nil
|
||||
case CipherType_AES_128_GCM:
|
||||
return &AEADCipher{
|
||||
KeyBytes: 16,
|
||||
IVBytes: 16,
|
||||
AEADAuthCreator: createAesGcm,
|
||||
}, nil
|
||||
case CipherType_AES_256_GCM:
|
||||
return &AEADCipher{
|
||||
KeyBytes: 32,
|
||||
IVBytes: 32,
|
||||
AEADAuthCreator: createAesGcm,
|
||||
}, nil
|
||||
case CipherType_CHACHA20_POLY1305:
|
||||
return &AEADCipher{
|
||||
KeyBytes: 32,
|
||||
IVBytes: 32,
|
||||
AEADAuthCreator: createChacha20Poly1305,
|
||||
}, nil
|
||||
default:
|
||||
return nil, newError("Unsupported cipher.")
|
||||
}
|
||||
@@ -60,8 +100,8 @@ func (v *Account) GetCipherKey() []byte {
|
||||
type Cipher interface {
|
||||
KeySize() int
|
||||
IVSize() int
|
||||
NewEncodingStream(key []byte, iv []byte) (cipher.Stream, error)
|
||||
NewDecodingStream(key []byte, iv []byte) (cipher.Stream, error)
|
||||
NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error)
|
||||
NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error)
|
||||
}
|
||||
|
||||
type AesCfb struct {
|
||||
@@ -76,14 +116,54 @@ func (v *AesCfb) IVSize() int {
|
||||
return 16
|
||||
}
|
||||
|
||||
func (v *AesCfb) NewEncodingStream(key []byte, iv []byte) (cipher.Stream, error) {
|
||||
func (v *AesCfb) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
|
||||
stream := crypto.NewAesEncryptionStream(key, iv)
|
||||
return stream, nil
|
||||
return buf.NewWriter(crypto.NewCryptionWriter(stream, writer)), nil
|
||||
}
|
||||
|
||||
func (v *AesCfb) NewDecodingStream(key []byte, iv []byte) (cipher.Stream, error) {
|
||||
func (v *AesCfb) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
|
||||
stream := crypto.NewAesDecryptionStream(key, iv)
|
||||
return stream, nil
|
||||
return buf.NewReader(crypto.NewCryptionReader(stream, reader)), nil
|
||||
}
|
||||
|
||||
type AEADCipher struct {
|
||||
KeyBytes int
|
||||
IVBytes int
|
||||
AEADAuthCreator func(key []byte) cipher.AEAD
|
||||
}
|
||||
|
||||
func (c *AEADCipher) KeySize() int {
|
||||
return c.KeyBytes
|
||||
}
|
||||
|
||||
func (c *AEADCipher) IVSize() int {
|
||||
return c.IVBytes
|
||||
}
|
||||
|
||||
func (c *AEADCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
|
||||
nonce := crypto.NewIncreasingAEADNonceGenerator()
|
||||
subkey := make([]byte, c.KeyBytes)
|
||||
hkdfSHA1(key, iv, subkey)
|
||||
auth := &crypto.AEADAuthenticator{
|
||||
AEAD: c.AEADAuthCreator(subkey),
|
||||
NonceGenerator: nonce,
|
||||
}
|
||||
return crypto.NewAuthenticationWriter(auth, &crypto.AEADChunkSizeParser{
|
||||
Auth: auth,
|
||||
}, writer, protocol.TransferTypeStream), nil
|
||||
}
|
||||
|
||||
func (c *AEADCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
|
||||
nonce := crypto.NewIncreasingAEADNonceGenerator()
|
||||
subkey := make([]byte, c.KeyBytes)
|
||||
hkdfSHA1(key, iv, subkey)
|
||||
auth := &crypto.AEADAuthenticator{
|
||||
AEAD: c.AEADAuthCreator(subkey),
|
||||
NonceGenerator: nonce,
|
||||
}
|
||||
return crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
|
||||
Auth: auth,
|
||||
}, reader, protocol.TransferTypeStream), nil
|
||||
}
|
||||
|
||||
type ChaCha20 struct {
|
||||
@@ -98,12 +178,14 @@ func (v *ChaCha20) IVSize() int {
|
||||
return v.IVBytes
|
||||
}
|
||||
|
||||
func (v *ChaCha20) NewEncodingStream(key []byte, iv []byte) (cipher.Stream, error) {
|
||||
return crypto.NewChaCha20Stream(key, iv), nil
|
||||
func (v *ChaCha20) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
|
||||
stream := crypto.NewChaCha20Stream(key, iv)
|
||||
return buf.NewWriter(crypto.NewCryptionWriter(stream, writer)), nil
|
||||
}
|
||||
|
||||
func (v *ChaCha20) NewDecodingStream(key []byte, iv []byte) (cipher.Stream, error) {
|
||||
return crypto.NewChaCha20Stream(key, iv), nil
|
||||
func (v *ChaCha20) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
|
||||
stream := crypto.NewChaCha20Stream(key, iv)
|
||||
return buf.NewReader(crypto.NewCryptionReader(stream, reader)), nil
|
||||
}
|
||||
|
||||
func PasswordToCipherKey(password string, keySize int) []byte {
|
||||
@@ -123,3 +205,8 @@ func PasswordToCipherKey(password string, keySize int) []byte {
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func hkdfSHA1(secret, salt, outkey []byte) {
|
||||
r := hkdf.New(sha1.New, secret, salt, []byte("ss-subkey"))
|
||||
common.Must2(io.ReadFull(r, outkey))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user