mirror of
https://github.com/nadoo/glider.git
synced 2025-02-24 01:45:39 +08:00
144 lines
3.7 KiB
Go
144 lines
3.7 KiB
Go
package shadowstream
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/md5"
|
|
"crypto/rc4"
|
|
"strconv"
|
|
|
|
"github.com/aead/chacha20"
|
|
"github.com/aead/chacha20/chacha"
|
|
)
|
|
|
|
// Cipher generates a pair of stream ciphers for encryption and decryption.
|
|
type Cipher interface {
|
|
IVSize() int
|
|
Encrypter(iv []byte) cipher.Stream
|
|
Decrypter(iv []byte) cipher.Stream
|
|
}
|
|
|
|
// KeySizeError is an error about the key size.
|
|
type KeySizeError int
|
|
|
|
func (e KeySizeError) Error() string {
|
|
return "key size error: need " + strconv.Itoa(int(e)) + " bytes"
|
|
}
|
|
|
|
// CTR mode
|
|
type ctrStream struct{ cipher.Block }
|
|
|
|
func (b *ctrStream) IVSize() int { return b.BlockSize() }
|
|
func (b *ctrStream) Decrypter(iv []byte) cipher.Stream { return b.Encrypter(iv) }
|
|
func (b *ctrStream) Encrypter(iv []byte) cipher.Stream { return cipher.NewCTR(b, iv) }
|
|
|
|
// AESCTR returns an aesctr cipher.
|
|
func AESCTR(key []byte) (Cipher, error) {
|
|
blk, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ctrStream{blk}, nil
|
|
}
|
|
|
|
// CFB mode
|
|
type cfbStream struct{ cipher.Block }
|
|
|
|
func (b *cfbStream) IVSize() int { return b.BlockSize() }
|
|
func (b *cfbStream) Decrypter(iv []byte) cipher.Stream { return cipher.NewCFBDecrypter(b, iv) }
|
|
func (b *cfbStream) Encrypter(iv []byte) cipher.Stream { return cipher.NewCFBEncrypter(b, iv) }
|
|
|
|
// AESCFB returns an aescfb cipher.
|
|
func AESCFB(key []byte) (Cipher, error) {
|
|
blk, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &cfbStream{blk}, nil
|
|
}
|
|
|
|
// IETF-variant of chacha20
|
|
type chacha20ietfkey []byte
|
|
|
|
func (k chacha20ietfkey) IVSize() int { return chacha.INonceSize }
|
|
func (k chacha20ietfkey) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) }
|
|
func (k chacha20ietfkey) Encrypter(iv []byte) cipher.Stream {
|
|
ciph, err := chacha20.NewCipher(iv, k)
|
|
if err != nil {
|
|
panic(err) // should never happen
|
|
}
|
|
return ciph
|
|
}
|
|
|
|
// Chacha20IETF returns a Chacha20IETF cipher.
|
|
func Chacha20IETF(key []byte) (Cipher, error) {
|
|
if len(key) != chacha.KeySize {
|
|
return nil, KeySizeError(chacha.KeySize)
|
|
}
|
|
return chacha20ietfkey(key), nil
|
|
}
|
|
|
|
// xchacha20
|
|
type xchacha20key []byte
|
|
|
|
func (k xchacha20key) IVSize() int { return chacha.XNonceSize }
|
|
func (k xchacha20key) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) }
|
|
func (k xchacha20key) Encrypter(iv []byte) cipher.Stream {
|
|
ciph, err := chacha20.NewCipher(iv, k)
|
|
if err != nil {
|
|
panic(err) // should never happen
|
|
}
|
|
return ciph
|
|
}
|
|
|
|
// Xchacha20 returns a Xchacha20 cipher.
|
|
func Xchacha20(key []byte) (Cipher, error) {
|
|
if len(key) != chacha.KeySize {
|
|
return nil, KeySizeError(chacha.KeySize)
|
|
}
|
|
return xchacha20key(key), nil
|
|
}
|
|
|
|
// chacah20
|
|
type chacha20key []byte
|
|
|
|
func (k chacha20key) IVSize() int { return chacha.NonceSize }
|
|
func (k chacha20key) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) }
|
|
func (k chacha20key) Encrypter(iv []byte) cipher.Stream {
|
|
ciph, err := chacha20.NewCipher(iv, k)
|
|
if err != nil {
|
|
panic(err) // should never happen
|
|
}
|
|
return ciph
|
|
}
|
|
|
|
// ChaCha20 returns a ChaCha20 cipher.
|
|
func ChaCha20(key []byte) (Cipher, error) {
|
|
if len(key) != chacha.KeySize {
|
|
return nil, KeySizeError(chacha.KeySize)
|
|
}
|
|
return chacha20key(key), nil
|
|
}
|
|
|
|
// rc4md5
|
|
type rc4Md5Key []byte
|
|
|
|
func (k rc4Md5Key) IVSize() int { return 16 }
|
|
func (k rc4Md5Key) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) }
|
|
func (k rc4Md5Key) Encrypter(iv []byte) cipher.Stream {
|
|
h := md5.New()
|
|
h.Write([]byte(k))
|
|
h.Write(iv)
|
|
rc4key := h.Sum(nil)
|
|
ciph, err := rc4.NewCipher(rc4key)
|
|
if err != nil {
|
|
panic(err) // should never happen
|
|
}
|
|
return ciph
|
|
}
|
|
|
|
// RC4MD5 returns a RC4MD5 cipher.
|
|
func RC4MD5(key []byte) (Cipher, error) {
|
|
return rc4Md5Key(key), nil
|
|
}
|