package shadowstream import ( "crypto/aes" "crypto/cipher" "crypto/md5" "crypto/rc4" "strconv" ) // 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 } 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) } 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) } func AESCFB(key []byte) (Cipher, error) { blk, err := aes.NewCipher(key) if err != nil { return nil, err } return &cfbStream{blk}, nil } type rc4Md5Key []byte func (k rc4Md5Key) IVSize() int { return 16 } func (k rc4Md5Key) Encrypter(iv []byte) cipher.Stream { h := md5.New() h.Write([]byte(k)) h.Write(iv) rc4key := h.Sum(nil) c, _ := rc4.NewCipher(rc4key) return c } func (k rc4Md5Key) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) } func RC4MD5(key []byte) (Cipher, error) { return rc4Md5Key(key), nil }