mirror of
https://github.com/minio/minio.git
synced 2025-01-23 20:53:18 -05:00
vendor update github.com/minio/sio (#5599)
This change updates the sio library and adds DARE 2.0 support to the server.
This commit is contained in:
parent
1b7b8f14c9
commit
4e5237b02a
7
vendor/github.com/minio/sio/README.md
generated
vendored
7
vendor/github.com/minio/sio/README.md
generated
vendored
@ -56,6 +56,11 @@ Its main properties are:
|
||||
|
||||
DARE and `github.com/minio/sio` are finalized and can be used in production.
|
||||
|
||||
We also provide a CLI tool to en/decrypt arbitrary data streams directly from
|
||||
your command line:
|
||||
|
||||
**Install ncrypt:** `go get -u github.com/minio/sio/cmd/ncrypt && ncrypt -h`
|
||||
|
||||
## Performance
|
||||
|
||||
Cipher | 8 KB | 64 KB | 512 KB | 1 MB
|
||||
@ -63,4 +68,4 @@ Cipher | 8 KB | 64 KB | 512 KB | 1 MB
|
||||
AES_256_GCM | 90 MB/s | 1.96 GB/s | 2.64 GB/s | 2.83 GB/s
|
||||
CHACHA20_POLY1305 | 97 MB/s | 1.23 GB/s | 1.54 GB/s | 1.57 GB/s
|
||||
|
||||
*On i7-6500U 2 x 2.5 GHz | Linux 4.10.0-32-generic | Go 1.8.3 | AES-NI & AVX2*
|
||||
*On i7-6500U 2 x 2.5 GHz | Linux 4.10.0-32-generic | Go 1.8.3 | AES-NI & AVX2*
|
451
vendor/github.com/minio/sio/dare.go
generated
vendored
451
vendor/github.com/minio/sio/dare.go
generated
vendored
@ -12,266 +12,261 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package sio implements the DARE format. It provides an API
|
||||
// for secure en/decrypting IO operations.
|
||||
package sio // import "github.com/minio/sio"
|
||||
package sio
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
// Version10 specifies version 1.0
|
||||
const Version10 byte = 0x10
|
||||
type headerV10 []byte
|
||||
|
||||
const (
|
||||
// AES_256_GCM specifies the cipher suite AES-GCM with 256 bit keys.
|
||||
AES_256_GCM byte = iota
|
||||
// CHACHA20_POLY1305 specifies the cipher suite ChaCha20Poly1305 with 256 bit keys.
|
||||
CHACHA20_POLY1305
|
||||
)
|
||||
func (h headerV10) Version() byte { return h[0] }
|
||||
func (h headerV10) Cipher() byte { return h[1] }
|
||||
func (h headerV10) Len() int { return int(binary.LittleEndian.Uint16(h[2:])) + 1 }
|
||||
func (h headerV10) SequenceNumber() uint32 { return binary.LittleEndian.Uint32(h[4:]) }
|
||||
func (h headerV10) SetVersion() { h[0] = Version10 }
|
||||
func (h headerV10) SetCipher(suite byte) { h[1] = suite }
|
||||
func (h headerV10) SetLen(length int) { binary.LittleEndian.PutUint16(h[2:], uint16(length-1)) }
|
||||
func (h headerV10) SetSequenceNumber(num uint32) { binary.LittleEndian.PutUint32(h[4:], num) }
|
||||
func (h headerV10) SetRand(randVal []byte) { copy(h[8:headerSize], randVal[:]) }
|
||||
func (h headerV10) Nonce() []byte { return h[4:headerSize] }
|
||||
func (h headerV10) AddData() []byte { return h[:4] }
|
||||
|
||||
const (
|
||||
headerSize = 16
|
||||
payloadSize = 64 * 1024
|
||||
tagSize = 16
|
||||
)
|
||||
type packageV10 []byte
|
||||
|
||||
var (
|
||||
errMissingHeader = errors.New("sio: incomplete header")
|
||||
errPayloadTooShort = errors.New("sio: payload too short")
|
||||
errPackageOutOfOrder = errors.New("sio: sequence number mismatch")
|
||||
errTagMismatch = errors.New("sio: authentication failed")
|
||||
errUnsupportedVersion = errors.New("sio: unsupported version")
|
||||
errUnsupportedCipher = errors.New("sio: unsupported cipher suite")
|
||||
)
|
||||
func (p packageV10) Header() headerV10 { return headerV10(p[:headerSize]) }
|
||||
func (p packageV10) Payload() []byte { return p[headerSize : p.Length()-tagSize] }
|
||||
func (p packageV10) Ciphertext() []byte { return p[headerSize:p.Length()] }
|
||||
func (p packageV10) Length() int { return headerSize + tagSize + p.Header().Len() }
|
||||
|
||||
var newAesGcm = func(key []byte) (cipher.AEAD, error) {
|
||||
aes256, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
type headerV20 []byte
|
||||
|
||||
func (h headerV20) Version() byte { return h[0] }
|
||||
func (h headerV20) SetVersion() { h[0] = Version20 }
|
||||
func (h headerV20) Cipher() byte { return h[1] }
|
||||
func (h headerV20) SetCipher(cipher byte) { h[1] = cipher }
|
||||
func (h headerV20) Length() int { return int(binary.LittleEndian.Uint16(h[2:4])) + 1 }
|
||||
func (h headerV20) SetLength(length int) { binary.LittleEndian.PutUint16(h[2:4], uint16(length-1)) }
|
||||
func (h headerV20) IsFinal() bool { return h[4]&0x80 == 0x80 }
|
||||
func (h headerV20) Nonce() []byte { return h[4:headerSize] }
|
||||
func (h headerV20) AddData() []byte { return h[:4] }
|
||||
func (h headerV20) SetRand(randVal []byte, final bool) {
|
||||
copy(h[4:], randVal)
|
||||
if final {
|
||||
h[4] |= 0x80
|
||||
} else {
|
||||
h[4] &= 0x7F
|
||||
}
|
||||
return cipher.NewGCM(aes256)
|
||||
}
|
||||
|
||||
var supportedCiphers = [...]func([]byte) (cipher.AEAD, error){
|
||||
AES_256_GCM: newAesGcm,
|
||||
CHACHA20_POLY1305: chacha20poly1305.New,
|
||||
type packageV20 []byte
|
||||
|
||||
func (p packageV20) Header() headerV20 { return headerV20(p[:headerSize]) }
|
||||
func (p packageV20) Payload() []byte { return p[headerSize : headerSize+p.Header().Length()] }
|
||||
func (p packageV20) Ciphertext() []byte { return p[headerSize:p.Length()] }
|
||||
func (p packageV20) Length() int { return headerSize + tagSize + p.Header().Length() }
|
||||
|
||||
type authEnc struct {
|
||||
CipherID byte
|
||||
SeqNum uint32
|
||||
Cipher cipher.AEAD
|
||||
RandVal []byte
|
||||
}
|
||||
|
||||
// Encrypt reads from src until it encounters an io.EOF and encrypts all received
|
||||
// data. The encrypted data is written to dst. It returns the number of bytes
|
||||
// encrypted and the first error encountered while encrypting, if any.
|
||||
//
|
||||
// Encrypt returns the number of bytes written to dst.
|
||||
func Encrypt(dst io.Writer, src io.Reader, config Config) (n int64, err error) {
|
||||
encReader, err := EncryptReader(src, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return io.CopyBuffer(dst, encReader, make([]byte, payloadSize))
|
||||
type authDec struct {
|
||||
SeqNum uint32
|
||||
Ciphers [2]cipher.AEAD
|
||||
}
|
||||
|
||||
// Decrypt reads from src until it encounters an io.EOF and decrypts all received
|
||||
// data. The decrypted data is written to dst. It returns the number of bytes
|
||||
// decrypted and the first error encountered while decrypting, if any.
|
||||
//
|
||||
// Decrypt returns the number of bytes written to dst. Decrypt only writes data to
|
||||
// dst if the data was decrypted successfully.
|
||||
func Decrypt(dst io.Writer, src io.Reader, config Config) (n int64, err error) {
|
||||
decReader, err := DecryptReader(src, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return io.CopyBuffer(dst, decReader, make([]byte, headerSize+payloadSize+tagSize))
|
||||
}
|
||||
type authEncV10 authEnc
|
||||
|
||||
// EncryptReader wraps the given src and returns an io.Reader which encrypts
|
||||
// all received data. EncryptReader returns an error if the provided encryption
|
||||
// configuration is invalid.
|
||||
func EncryptReader(src io.Reader, config Config) (io.Reader, error) {
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipher, err := supportedCiphers[config.CipherSuites[0]](config.Key)
|
||||
func newAuthEncV10(cfg *Config) (authEncV10, error) {
|
||||
cipherID := cfg.CipherSuites[0]
|
||||
cipher, err := supportedCiphers[cipherID](cfg.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return authEncV10{}, err
|
||||
}
|
||||
nonce, err := config.generateNonce()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var randVal [8]byte
|
||||
if _, err = io.ReadFull(cfg.Rand, randVal[:]); err != nil {
|
||||
return authEncV10{}, err
|
||||
}
|
||||
return &encryptedReader{
|
||||
src: src,
|
||||
config: config,
|
||||
nonce: nonce,
|
||||
cipher: cipher,
|
||||
sequenceNumber: config.SequenceNumber,
|
||||
return authEncV10{
|
||||
CipherID: cipherID,
|
||||
RandVal: randVal[:],
|
||||
Cipher: cipher,
|
||||
SeqNum: cfg.SequenceNumber,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DecryptReader wraps the given src and returns an io.Reader which decrypts
|
||||
// all received data. DecryptReader returns an error if the provided decryption
|
||||
// configuration is invalid.
|
||||
func DecryptReader(src io.Reader, config Config) (io.Reader, error) {
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ciphers, err := config.createCiphers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decryptedReader{
|
||||
src: src,
|
||||
config: config,
|
||||
ciphers: ciphers,
|
||||
sequenceNumber: config.SequenceNumber,
|
||||
}, nil
|
||||
func (ae *authEncV10) Seal(dst, src []byte) {
|
||||
header := headerV10(dst[:headerSize])
|
||||
header.SetVersion()
|
||||
header.SetCipher(ae.CipherID)
|
||||
header.SetLen(len(src))
|
||||
header.SetSequenceNumber(ae.SeqNum)
|
||||
header.SetRand(ae.RandVal)
|
||||
ae.Cipher.Seal(dst[headerSize:headerSize], header.Nonce(), src, header.AddData())
|
||||
ae.SeqNum++
|
||||
}
|
||||
|
||||
// EncryptWriter wraps the given dst and returns an io.WriteCloser which
|
||||
// encrypts all data written to it. EncryptWriter returns an error if the
|
||||
// provided decryption configuration is invalid.
|
||||
//
|
||||
// The returned io.WriteCloser must be closed successfully to finalize the
|
||||
// encryption process.
|
||||
func EncryptWriter(dst io.Writer, config Config) (io.WriteCloser, error) {
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipher, err := supportedCiphers[config.CipherSuites[0]](config.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nonce, err := config.generateNonce()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &encryptedWriter{
|
||||
dst: dst,
|
||||
config: config,
|
||||
nonce: nonce,
|
||||
cipher: cipher,
|
||||
sequenceNumber: config.SequenceNumber,
|
||||
}, nil
|
||||
}
|
||||
type authDecV10 authDec
|
||||
|
||||
// DecryptWriter wraps the given dst and returns an io.WriteCloser which
|
||||
// decrypts all data written to it. DecryptWriter returns an error if the
|
||||
// provided decryption configuration is invalid.
|
||||
//
|
||||
// The returned io.WriteCloser must be closed successfully to finalize the
|
||||
// decryption process.
|
||||
func DecryptWriter(dst io.Writer, config Config) (io.WriteCloser, error) {
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ciphers, err := config.createCiphers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decryptedWriter{
|
||||
dst: dst,
|
||||
config: config,
|
||||
ciphers: ciphers,
|
||||
sequenceNumber: config.SequenceNumber,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *Config) error {
|
||||
if config.MinVersion > Version10 {
|
||||
return errors.New("sio: unknown minimum version")
|
||||
}
|
||||
if config.MaxVersion > Version10 {
|
||||
return errors.New("dare: unknown maximum version")
|
||||
}
|
||||
if len(config.Key) != 32 {
|
||||
return errors.New("sio: invalid key size")
|
||||
}
|
||||
if len(config.CipherSuites) > 2 {
|
||||
return errors.New("sio: too many cipher suites")
|
||||
}
|
||||
for _, c := range config.CipherSuites {
|
||||
if int(c) >= len(supportedCiphers) {
|
||||
return errors.New("sio: unknown cipher suite")
|
||||
}
|
||||
}
|
||||
if config.MinVersion < Version10 {
|
||||
config.MinVersion = Version10
|
||||
}
|
||||
if config.MaxVersion < Version10 {
|
||||
config.MaxVersion = config.MinVersion
|
||||
}
|
||||
if len(config.CipherSuites) == 0 {
|
||||
config.CipherSuites = []byte{AES_256_GCM, CHACHA20_POLY1305}
|
||||
}
|
||||
if config.Rand == nil {
|
||||
config.Rand = rand.Reader
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Config contains the format configuration. The only field
|
||||
// which must always be set manually is the secret key.
|
||||
type Config struct {
|
||||
// The minimal supported version of the format. If
|
||||
// not set the default value is used.
|
||||
MinVersion byte
|
||||
// The highest supported version of the format. If
|
||||
// not set the default value is used.
|
||||
MaxVersion byte
|
||||
// A list of supported cipher suites. If not set the
|
||||
// default value is used.
|
||||
CipherSuites []byte
|
||||
// The secret encryption key. It must be 32 bytes long.
|
||||
Key []byte
|
||||
// The first expected sequence number. It should only
|
||||
// be set manually when appending data to an existing
|
||||
// sequence of packages or decrypting a range within
|
||||
// a sequence of packages.
|
||||
SequenceNumber uint32
|
||||
// The RNG used to generate random values. If not set
|
||||
// the default value (crypto/rand.Reader) is used.
|
||||
Rand io.Reader
|
||||
}
|
||||
|
||||
func (c *Config) verifyHeader(header headerV10) error {
|
||||
if version := header.Version(); version < c.MinVersion || version > c.MaxVersion {
|
||||
return errUnsupportedVersion
|
||||
}
|
||||
if !c.isCipherSuiteSupported(header.Cipher()) {
|
||||
return errUnsupportedCipher
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) createCiphers() ([]cipher.AEAD, error) {
|
||||
ciphers := make([]cipher.AEAD, len(supportedCiphers))
|
||||
for _, v := range c.CipherSuites {
|
||||
aeadCipher, err := supportedCiphers[v](c.Key)
|
||||
func newAuthDecV10(cfg *Config) (authDecV10, error) {
|
||||
var ciphers [2]cipher.AEAD
|
||||
for _, v := range cfg.CipherSuites {
|
||||
aeadCipher, err := supportedCiphers[v](cfg.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return authDecV10{}, err
|
||||
}
|
||||
ciphers[v] = aeadCipher
|
||||
}
|
||||
return ciphers, nil
|
||||
return authDecV10{
|
||||
SeqNum: cfg.SequenceNumber,
|
||||
Ciphers: ciphers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Config) generateNonce() (nonce [8]byte, err error) {
|
||||
_, err = io.ReadFull(c.Rand, nonce[:])
|
||||
return nonce, err
|
||||
}
|
||||
|
||||
func (c *Config) isCipherSuiteSupported(suite byte) bool {
|
||||
for _, c := range c.CipherSuites {
|
||||
if suite == c {
|
||||
return true
|
||||
}
|
||||
func (ad *authDecV10) Open(dst, src []byte) error {
|
||||
header := headerV10(src[:headerSize])
|
||||
if header.Version() != Version10 {
|
||||
return errUnsupportedVersion
|
||||
}
|
||||
return false
|
||||
if header.Cipher() > CHACHA20_POLY1305 {
|
||||
return errUnsupportedCipher
|
||||
}
|
||||
aeadCipher := ad.Ciphers[header.Cipher()]
|
||||
if aeadCipher == nil {
|
||||
return errUnsupportedCipher
|
||||
}
|
||||
if headerSize+header.Len()+tagSize != len(src) {
|
||||
return errInvalidPayloadSize
|
||||
}
|
||||
if header.SequenceNumber() != ad.SeqNum {
|
||||
return errPackageOutOfOrder
|
||||
}
|
||||
ciphertext := src[headerSize : headerSize+header.Len()+tagSize]
|
||||
if _, err := aeadCipher.Open(dst[:0], header.Nonce(), ciphertext, header.AddData()); err != nil {
|
||||
return errTagMismatch
|
||||
}
|
||||
ad.SeqNum++
|
||||
return nil
|
||||
}
|
||||
|
||||
type authEncV20 struct {
|
||||
authEnc
|
||||
finalized bool
|
||||
}
|
||||
|
||||
func newAuthEncV20(cfg *Config) (authEncV20, error) {
|
||||
cipherID := cfg.CipherSuites[0]
|
||||
cipher, err := supportedCiphers[cipherID](cfg.Key)
|
||||
if err != nil {
|
||||
return authEncV20{}, err
|
||||
}
|
||||
var randVal [12]byte
|
||||
if _, err = io.ReadFull(cfg.Rand, randVal[:]); err != nil {
|
||||
return authEncV20{}, err
|
||||
}
|
||||
return authEncV20{
|
||||
authEnc: authEnc{
|
||||
CipherID: cipherID,
|
||||
RandVal: randVal[:],
|
||||
Cipher: cipher,
|
||||
SeqNum: cfg.SequenceNumber,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ae *authEncV20) Seal(dst, src []byte) { ae.seal(dst, src, false) }
|
||||
func (ae *authEncV20) SealFinal(dst, src []byte) { ae.seal(dst, src, true) }
|
||||
|
||||
func (ae *authEncV20) seal(dst, src []byte, finalize bool) {
|
||||
if ae.finalized { // callers are not supposed to call Seal(Final) after a SealFinal call happened
|
||||
panic("sio: cannot seal any package after final one")
|
||||
}
|
||||
ae.finalized = finalize
|
||||
|
||||
header := headerV20(dst[:headerSize])
|
||||
header.SetVersion()
|
||||
header.SetCipher(ae.CipherID)
|
||||
header.SetLength(len(src))
|
||||
header.SetRand(ae.RandVal, finalize)
|
||||
|
||||
var nonce [12]byte
|
||||
copy(nonce[:], header.Nonce())
|
||||
binary.LittleEndian.PutUint32(nonce[8:], binary.LittleEndian.Uint32(nonce[8:])^ae.SeqNum)
|
||||
|
||||
ae.Cipher.Seal(dst[headerSize:headerSize], nonce[:], src, header.AddData())
|
||||
ae.SeqNum++
|
||||
}
|
||||
|
||||
type authDecV20 struct {
|
||||
authDec
|
||||
refHeader headerV20
|
||||
finalized bool
|
||||
}
|
||||
|
||||
func newAuthDecV20(cfg *Config) (authDecV20, error) {
|
||||
var ciphers [2]cipher.AEAD
|
||||
for _, v := range cfg.CipherSuites {
|
||||
aeadCipher, err := supportedCiphers[v](cfg.Key)
|
||||
if err != nil {
|
||||
return authDecV20{}, err
|
||||
}
|
||||
ciphers[v] = aeadCipher
|
||||
}
|
||||
return authDecV20{
|
||||
authDec: authDec{
|
||||
SeqNum: cfg.SequenceNumber,
|
||||
Ciphers: ciphers,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ad *authDecV20) Open(dst, src []byte) error {
|
||||
if ad.finalized {
|
||||
return errUnexpectedData
|
||||
}
|
||||
if len(src) <= headerSize+tagSize {
|
||||
return errInvalidPayloadSize
|
||||
}
|
||||
|
||||
header := packageV20(src).Header()
|
||||
if ad.refHeader == nil {
|
||||
ad.refHeader = make([]byte, headerSize)
|
||||
copy(ad.refHeader, header)
|
||||
}
|
||||
if header.Version() != Version20 {
|
||||
return errUnsupportedVersion
|
||||
}
|
||||
if c := header.Cipher(); c > CHACHA20_POLY1305 || ad.Ciphers[c] == nil || c != ad.refHeader.Cipher() {
|
||||
return errUnsupportedCipher
|
||||
}
|
||||
if headerSize+header.Length()+tagSize != len(src) {
|
||||
return errInvalidPayloadSize
|
||||
}
|
||||
if !header.IsFinal() && header.Length() != maxPayloadSize {
|
||||
return errInvalidPayloadSize
|
||||
}
|
||||
refNonce := ad.refHeader.Nonce()
|
||||
if header.IsFinal() {
|
||||
ad.finalized = true
|
||||
refNonce[0] |= 0x80 // set final flag
|
||||
}
|
||||
if subtle.ConstantTimeCompare(header.Nonce(), refNonce[:]) != 1 {
|
||||
return errNonceMismatch
|
||||
}
|
||||
|
||||
var nonce [12]byte
|
||||
copy(nonce[:], header.Nonce())
|
||||
binary.LittleEndian.PutUint32(nonce[8:], binary.LittleEndian.Uint32(nonce[8:])^ad.SeqNum)
|
||||
cipher := ad.Ciphers[header.Cipher()]
|
||||
if _, err := cipher.Open(dst[:0], nonce[:], src[headerSize:headerSize+header.Length()+tagSize], header.AddData()); err != nil {
|
||||
return errTagMismatch
|
||||
}
|
||||
ad.SeqNum++
|
||||
return nil
|
||||
}
|
||||
|
117
vendor/github.com/minio/sio/generic.go
generated
vendored
Normal file
117
vendor/github.com/minio/sio/generic.go
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
// Copyright (C) 2018 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
type decWriter struct {
|
||||
config Config
|
||||
dst io.Writer
|
||||
|
||||
firstWrite bool
|
||||
}
|
||||
|
||||
// decryptWriter returns an io.WriteCloser wrapping the given io.Writer.
|
||||
// The returned io.WriteCloser detects whether the data written to it is
|
||||
// encrypted using DARE 1.0 or 2.0 and decrypts it using the correct DARE
|
||||
// version.
|
||||
func decryptWriter(w io.Writer, config *Config) *decWriter {
|
||||
return &decWriter{
|
||||
config: *config,
|
||||
dst: w,
|
||||
firstWrite: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *decWriter) Write(p []byte) (n int, err error) {
|
||||
if w.firstWrite {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
w.firstWrite = false
|
||||
switch p[0] {
|
||||
default:
|
||||
return 0, errUnsupportedVersion
|
||||
case Version10:
|
||||
w.dst, err = decryptWriterV10(w.dst, &w.config)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
case Version20:
|
||||
w.dst, err = decryptWriterV20(w.dst, &w.config)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return w.dst.Write(p)
|
||||
}
|
||||
|
||||
func (w *decWriter) Close() error {
|
||||
if closer, ok := w.dst.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type decReader struct {
|
||||
config Config
|
||||
src io.Reader
|
||||
|
||||
firstRead bool
|
||||
}
|
||||
|
||||
// decryptReader returns an io.Reader wrapping the given io.Reader.
|
||||
// The returned io.Reader detects whether the underlying io.Reader returns
|
||||
// DARE 1.0 or 2.0 encrypted data and decrypts it using the correct DARE version.
|
||||
func decryptReader(r io.Reader, config *Config) *decReader {
|
||||
return &decReader{
|
||||
config: *config,
|
||||
src: r,
|
||||
firstRead: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *decReader) Read(p []byte) (n int, err error) {
|
||||
if r.firstRead {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
var version [1]byte
|
||||
if _, err = io.ReadFull(r.src, version[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
r.firstRead = false
|
||||
r.src = io.MultiReader(bytes.NewReader(version[:]), r.src)
|
||||
switch version[0] {
|
||||
default:
|
||||
return 0, errUnsupportedVersion
|
||||
case Version10:
|
||||
r.src, err = decryptReaderV10(r.src, &r.config)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
case Version20:
|
||||
r.src, err = decryptReaderV20(r.src, &r.config)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return r.src.Read(p)
|
||||
}
|
39
vendor/github.com/minio/sio/header.go
generated
vendored
39
vendor/github.com/minio/sio/header.go
generated
vendored
@ -1,39 +0,0 @@
|
||||
// Copyright (C) 2017 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sio
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
type headerV10 []byte
|
||||
|
||||
func header(b []byte) headerV10 { return headerV10(b[:headerSize]) }
|
||||
|
||||
func (h headerV10) Version() byte { return h[0] }
|
||||
|
||||
func (h headerV10) Cipher() byte { return h[1] }
|
||||
|
||||
func (h headerV10) Len() int { return int(binary.LittleEndian.Uint16(h[2:])) + 1 }
|
||||
|
||||
func (h headerV10) SequenceNumber() uint32 { return binary.LittleEndian.Uint32(h[4:]) }
|
||||
|
||||
func (h headerV10) SetVersion(version byte) { h[0] = version }
|
||||
|
||||
func (h headerV10) SetCipher(suite byte) { h[1] = suite }
|
||||
|
||||
func (h headerV10) SetLen(length int) { binary.LittleEndian.PutUint16(h[2:], uint16(length-1)) }
|
||||
|
||||
func (h headerV10) SetSequenceNumber(num uint32) { binary.LittleEndian.PutUint32(h[4:], num) }
|
||||
|
||||
func (h headerV10) SetNonce(nonce [8]byte) { copy(h[8:], nonce[:]) }
|
20
vendor/github.com/minio/sio/internal/cpu/aes.go
generated
vendored
Normal file
20
vendor/github.com/minio/sio/internal/cpu/aes.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (C) 2018 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cpu
|
||||
|
||||
// SupportsAES returns true if the CPU offers special
|
||||
// AES instructions. It indicates whether an AES hardware
|
||||
// implementation is available.
|
||||
func SupportsAES() bool { return hasAESNISupport() }
|
20
vendor/github.com/minio/sio/internal/cpu/aesni_amd64.go
generated
vendored
Normal file
20
vendor/github.com/minio/sio/internal/cpu/aesni_amd64.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (C) 2017 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
package cpu
|
||||
|
||||
//go:noescape
|
||||
func hasAESNISupport() bool
|
27
vendor/github.com/minio/sio/internal/cpu/aesni_amd64.s
generated
vendored
Normal file
27
vendor/github.com/minio/sio/internal/cpu/aesni_amd64.s
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2017 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func hasAESNISupport() bool
|
||||
TEXT ·hasAESNISupport(SB),NOSPLIT,$0
|
||||
XORQ AX, AX
|
||||
INCL AX
|
||||
CPUID
|
||||
SHRQ $25, CX
|
||||
ANDQ $1, CX
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
19
vendor/github.com/minio/sio/internal/cpu/aesni_generic.go
generated
vendored
Normal file
19
vendor/github.com/minio/sio/internal/cpu/aesni_generic.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (C) 2017 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !amd64 gccgo appengine
|
||||
|
||||
package cpu
|
||||
|
||||
func hasAESNISupport() bool { return false }
|
163
vendor/github.com/minio/sio/reader-v1.go
generated
vendored
Normal file
163
vendor/github.com/minio/sio/reader-v1.go
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
// Copyright (C) 2017 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sio
|
||||
|
||||
import "io"
|
||||
|
||||
type encReaderV10 struct {
|
||||
authEncV10
|
||||
src io.Reader
|
||||
|
||||
buffer packageV10
|
||||
offset int
|
||||
payloadSize int
|
||||
}
|
||||
|
||||
// encryptReaderV10 returns an io.Reader wrapping the given io.Reader.
|
||||
// The returned io.Reader encrypts everything it reads using DARE 1.0.
|
||||
func encryptReaderV10(src io.Reader, config *Config) (*encReaderV10, error) {
|
||||
ae, err := newAuthEncV10(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &encReaderV10{
|
||||
authEncV10: ae,
|
||||
src: src,
|
||||
buffer: make(packageV10, maxPackageSize),
|
||||
payloadSize: config.PayloadSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *encReaderV10) Read(p []byte) (int, error) {
|
||||
var n int
|
||||
if r.offset > 0 { // write the buffered package to p
|
||||
remaining := r.buffer.Length() - r.offset // remaining encrypted bytes
|
||||
if len(p) < remaining {
|
||||
n = copy(p, r.buffer[r.offset:r.offset+len(p)])
|
||||
r.offset += n
|
||||
return n, nil
|
||||
}
|
||||
n = copy(p, r.buffer[r.offset:r.offset+remaining])
|
||||
p = p[remaining:]
|
||||
r.offset = 0
|
||||
}
|
||||
for len(p) >= headerSize+r.payloadSize+tagSize {
|
||||
nn, err := io.ReadFull(r.src, p[headerSize:headerSize+r.payloadSize]) // read plaintext from src
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
return n, err // return if reading from src fails or reached EOF
|
||||
}
|
||||
r.Seal(p, p[headerSize:headerSize+nn])
|
||||
n += headerSize + nn + tagSize
|
||||
p = p[headerSize+nn+tagSize:]
|
||||
}
|
||||
if len(p) > 0 {
|
||||
nn, err := io.ReadFull(r.src, r.buffer[headerSize:headerSize+r.payloadSize]) // read plaintext from src
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
return n, err // return if reading from src fails or reached EOF
|
||||
}
|
||||
r.Seal(r.buffer, r.buffer[headerSize:headerSize+nn])
|
||||
if length := r.buffer.Length(); length < len(p) {
|
||||
r.offset = copy(p, r.buffer[:length])
|
||||
} else {
|
||||
r.offset = copy(p, r.buffer[:len(p)])
|
||||
}
|
||||
n += r.offset
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
type decReaderV10 struct {
|
||||
authDecV10
|
||||
src io.Reader
|
||||
|
||||
buffer packageV10
|
||||
offset int
|
||||
}
|
||||
|
||||
// decryptReaderV10 returns an io.Reader wrapping the given io.Reader.
|
||||
// The returned io.Reader decrypts everything it reads using DARE 1.0.
|
||||
func decryptReaderV10(src io.Reader, config *Config) (*decReaderV10, error) {
|
||||
ad, err := newAuthDecV10(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decReaderV10{
|
||||
authDecV10: ad,
|
||||
src: src,
|
||||
buffer: make(packageV10, maxPackageSize),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *decReaderV10) Read(p []byte) (n int, err error) {
|
||||
if r.offset > 0 { // write the buffered plaintext to p
|
||||
payload := r.buffer.Payload()
|
||||
remaining := len(payload) - r.offset // remaining plaintext bytes
|
||||
if len(p) < remaining {
|
||||
n = copy(p, payload[r.offset:+r.offset+len(p)])
|
||||
r.offset += n
|
||||
return
|
||||
}
|
||||
n = copy(p, payload[r.offset:r.offset+remaining])
|
||||
p = p[remaining:]
|
||||
r.offset = 0
|
||||
}
|
||||
for len(p) >= maxPayloadSize {
|
||||
if err = r.readPackage(r.buffer); err != nil {
|
||||
return n, err
|
||||
}
|
||||
length := len(r.buffer.Payload())
|
||||
if err = r.Open(p[:length], r.buffer[:r.buffer.Length()]); err != nil { // notice: buffer.Length() may be smaller than len(buffer)
|
||||
return n, err // decryption failed
|
||||
}
|
||||
p = p[length:]
|
||||
n += length
|
||||
}
|
||||
if len(p) > 0 {
|
||||
if err = r.readPackage(r.buffer); err != nil {
|
||||
return n, err
|
||||
}
|
||||
payload := r.buffer.Payload()
|
||||
if err = r.Open(payload, r.buffer[:r.buffer.Length()]); err != nil { // notice: buffer.Length() may be smaller than len(buffer)
|
||||
return n, err // decryption failed
|
||||
}
|
||||
if len(payload) < len(p) {
|
||||
r.offset = copy(p, payload)
|
||||
} else {
|
||||
r.offset = copy(p, payload[:len(p)])
|
||||
}
|
||||
n += r.offset
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (r *decReaderV10) readPackage(dst packageV10) error {
|
||||
header := dst.Header()
|
||||
_, err := io.ReadFull(r.src, header)
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return errInvalidPayloadSize // partial header
|
||||
}
|
||||
if err != nil {
|
||||
return err // reading from src failed or reached EOF
|
||||
}
|
||||
|
||||
_, err = io.ReadFull(r.src, dst.Ciphertext())
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
return errInvalidPayloadSize // reading less data than specified by header
|
||||
}
|
||||
if err != nil {
|
||||
return err // reading from src failed or reached EOF
|
||||
}
|
||||
return nil
|
||||
}
|
178
vendor/github.com/minio/sio/reader-v2.go
generated
vendored
Normal file
178
vendor/github.com/minio/sio/reader-v2.go
generated
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
// Copyright (C) 2018 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sio
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type encReaderV20 struct {
|
||||
authEncV20
|
||||
src io.Reader
|
||||
|
||||
buffer packageV20
|
||||
offset int
|
||||
lastByte byte
|
||||
|
||||
firstRead bool
|
||||
}
|
||||
|
||||
// encryptReaderV20 returns an io.Reader wrapping the given io.Reader.
|
||||
// The returned io.Reader encrypts everything it reads using DARE 2.0.
|
||||
func encryptReaderV20(src io.Reader, config *Config) (*encReaderV20, error) {
|
||||
ae, err := newAuthEncV20(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &encReaderV20{
|
||||
authEncV20: ae,
|
||||
src: src,
|
||||
buffer: make(packageV20, maxPackageSize),
|
||||
firstRead: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *encReaderV20) Read(p []byte) (n int, err error) {
|
||||
if r.firstRead {
|
||||
r.firstRead = false
|
||||
_, err = io.ReadFull(r.src, r.buffer[headerSize:headerSize+1])
|
||||
if err != nil && err != io.EOF { // ErrUnexpectedEOF cannot happen b/c we read just one single byte
|
||||
return 0, err
|
||||
}
|
||||
if err == io.EOF {
|
||||
r.finalized = true
|
||||
return 0, io.EOF
|
||||
}
|
||||
r.lastByte = r.buffer[headerSize]
|
||||
}
|
||||
|
||||
if r.offset > 0 { // write the buffered package to p
|
||||
remaining := r.buffer.Length() - r.offset
|
||||
if len(p) < remaining {
|
||||
r.offset += copy(p, r.buffer[r.offset:r.offset+len(p)])
|
||||
return len(p), nil
|
||||
}
|
||||
n = copy(p, r.buffer[r.offset:r.offset+remaining])
|
||||
p = p[remaining:]
|
||||
r.offset = 0
|
||||
}
|
||||
if r.finalized {
|
||||
return n, io.EOF
|
||||
}
|
||||
for len(p) >= maxPackageSize {
|
||||
r.buffer[headerSize] = r.lastByte
|
||||
nn, err := io.ReadFull(r.src, r.buffer[headerSize+1:headerSize+1+maxPayloadSize]) // try to read the max. payload
|
||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
return n, err // failed to read from src
|
||||
}
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF { // read less than 64KB -> final package
|
||||
r.SealFinal(p, r.buffer[headerSize:headerSize+1+nn])
|
||||
return n + headerSize + tagSize + 1 + nn, io.EOF
|
||||
}
|
||||
r.lastByte = r.buffer[headerSize+maxPayloadSize] // save last read byte for the next package
|
||||
r.Seal(p, r.buffer[headerSize:headerSize+maxPayloadSize])
|
||||
p = p[maxPackageSize:]
|
||||
n += maxPackageSize
|
||||
}
|
||||
if len(p) > 0 {
|
||||
r.buffer[headerSize] = r.lastByte
|
||||
nn, err := io.ReadFull(r.src, r.buffer[headerSize+1:headerSize+1+maxPayloadSize]) // try to read the max. payload
|
||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
return n, err // failed to read from src
|
||||
}
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF { // read less than 64KB -> final package
|
||||
r.SealFinal(r.buffer, r.buffer[headerSize:headerSize+1+nn])
|
||||
if len(p) > r.buffer.Length() {
|
||||
n += copy(p, r.buffer[:r.buffer.Length()])
|
||||
return n, io.EOF
|
||||
}
|
||||
} else {
|
||||
r.lastByte = r.buffer[headerSize+maxPayloadSize] // save last read byte for the next package
|
||||
r.Seal(r.buffer, r.buffer[headerSize:headerSize+maxPayloadSize])
|
||||
}
|
||||
r.offset = copy(p, r.buffer[:len(p)]) // len(p) < len(r.buffer) - otherwise we would be still in the for-loop
|
||||
n += r.offset
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
type decReaderV20 struct {
|
||||
authDecV20
|
||||
src io.Reader
|
||||
|
||||
buffer packageV20
|
||||
offset int
|
||||
}
|
||||
|
||||
// decryptReaderV20 returns an io.Reader wrapping the given io.Reader.
|
||||
// The returned io.Reader decrypts everything it reads using DARE 2.0.
|
||||
func decryptReaderV20(src io.Reader, config *Config) (*decReaderV20, error) {
|
||||
ad, err := newAuthDecV20(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decReaderV20{
|
||||
authDecV20: ad,
|
||||
src: src,
|
||||
buffer: make(packageV20, maxPackageSize),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *decReaderV20) Read(p []byte) (n int, err error) {
|
||||
if r.offset > 0 { // write the buffered plaintext to p
|
||||
remaining := len(r.buffer.Payload()) - r.offset
|
||||
if len(p) < remaining {
|
||||
n = copy(p, r.buffer.Payload()[r.offset:r.offset+len(p)])
|
||||
r.offset += n
|
||||
return n, nil
|
||||
}
|
||||
n = copy(p, r.buffer.Payload()[r.offset:])
|
||||
p = p[remaining:]
|
||||
r.offset = 0
|
||||
}
|
||||
for len(p) >= maxPayloadSize {
|
||||
nn, err := io.ReadFull(r.src, r.buffer)
|
||||
if err == io.EOF && !r.finalized {
|
||||
return n, errUnexpectedEOF // reached EOF but not seen final package yet
|
||||
}
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
return n, err // reading from src failed or reached EOF
|
||||
}
|
||||
if err = r.Open(p, r.buffer[:nn]); err != nil {
|
||||
return n, err // decryption failed
|
||||
}
|
||||
p = p[len(r.buffer.Payload()):]
|
||||
n += len(r.buffer.Payload())
|
||||
}
|
||||
if len(p) > 0 {
|
||||
nn, err := io.ReadFull(r.src, r.buffer)
|
||||
if err == io.EOF && !r.finalized {
|
||||
return n, errUnexpectedEOF // reached EOF but not seen final package yet
|
||||
}
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
return n, err // reading from src failed or reached EOF
|
||||
}
|
||||
if err = r.Open(r.buffer[headerSize:], r.buffer[:nn]); err != nil {
|
||||
return n, err // decryption failed
|
||||
}
|
||||
if payload := r.buffer.Payload(); len(p) < len(payload) {
|
||||
r.offset = copy(p, payload[:len(p)])
|
||||
n += r.offset
|
||||
} else {
|
||||
n += copy(p, payload)
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
169
vendor/github.com/minio/sio/reader.go
generated
vendored
169
vendor/github.com/minio/sio/reader.go
generated
vendored
@ -1,169 +0,0 @@
|
||||
// Copyright (C) 2017 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sio
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"io"
|
||||
)
|
||||
|
||||
type encryptedReader struct {
|
||||
src io.Reader
|
||||
config Config
|
||||
|
||||
sequenceNumber uint32
|
||||
nonce [8]byte
|
||||
cipher cipher.AEAD
|
||||
|
||||
pack [headerSize + payloadSize + tagSize]byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (r *encryptedReader) Read(p []byte) (n int, err error) {
|
||||
if r.offset > 0 {
|
||||
remaining := headerSize + header(r.pack[:]).Len() + tagSize - r.offset
|
||||
if len(p) < remaining {
|
||||
n = copy(p, r.pack[r.offset:r.offset+len(p)])
|
||||
r.offset += n
|
||||
return
|
||||
}
|
||||
n = copy(p, r.pack[r.offset:r.offset+remaining])
|
||||
p = p[remaining:]
|
||||
r.offset = 0
|
||||
}
|
||||
for len(p) >= headerSize+payloadSize+tagSize {
|
||||
nn, err := io.ReadFull(r.src, r.pack[headerSize:headerSize+payloadSize])
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
return n, err
|
||||
}
|
||||
r.encrypt(p, nn)
|
||||
n += headerSize + nn + tagSize
|
||||
p = p[headerSize+nn+tagSize:]
|
||||
}
|
||||
if len(p) > 0 {
|
||||
nn, err := io.ReadFull(r.src, r.pack[headerSize:headerSize+payloadSize])
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
return n, err
|
||||
}
|
||||
r.encrypt(r.pack[:], nn)
|
||||
if headerSize+nn+tagSize < len(p) {
|
||||
r.offset = copy(p, r.pack[:headerSize+nn+tagSize])
|
||||
} else {
|
||||
r.offset = copy(p, r.pack[:len(p)])
|
||||
}
|
||||
n += r.offset
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *encryptedReader) encrypt(dst []byte, length int) {
|
||||
header := header(dst)
|
||||
header.SetVersion(r.config.MaxVersion)
|
||||
header.SetCipher(r.config.CipherSuites[0])
|
||||
header.SetLen(length)
|
||||
header.SetSequenceNumber(r.sequenceNumber)
|
||||
header.SetNonce(r.nonce)
|
||||
|
||||
copy(dst[:headerSize], header)
|
||||
r.cipher.Seal(dst[headerSize:headerSize], header[4:headerSize], r.pack[headerSize:headerSize+length], header[:4])
|
||||
|
||||
r.sequenceNumber++
|
||||
}
|
||||
|
||||
type decryptedReader struct {
|
||||
src io.Reader
|
||||
config Config
|
||||
|
||||
sequenceNumber uint32
|
||||
ciphers []cipher.AEAD
|
||||
|
||||
pack [headerSize + payloadSize + tagSize]byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (r *decryptedReader) Read(p []byte) (n int, err error) {
|
||||
if r.offset > 0 {
|
||||
remaining := header(r.pack[:]).Len() - r.offset
|
||||
if len(p) < remaining {
|
||||
n = copy(p, r.pack[headerSize+r.offset:headerSize+r.offset+len(p)])
|
||||
r.offset += n
|
||||
return
|
||||
}
|
||||
n = copy(p, r.pack[headerSize+r.offset:headerSize+r.offset+remaining])
|
||||
p = p[remaining:]
|
||||
r.offset = 0
|
||||
}
|
||||
for len(p) >= payloadSize {
|
||||
if err = r.readHeader(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
nn, err := r.decrypt(p[:payloadSize])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
p = p[nn:]
|
||||
n += nn
|
||||
}
|
||||
if len(p) > 0 {
|
||||
if err = r.readHeader(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
nn, err := r.decrypt(r.pack[headerSize:])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if nn < len(p) {
|
||||
r.offset = copy(p, r.pack[headerSize:headerSize+nn])
|
||||
} else {
|
||||
r.offset = copy(p, r.pack[headerSize:headerSize+len(p)])
|
||||
}
|
||||
n += r.offset
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *decryptedReader) readHeader() error {
|
||||
n, err := io.ReadFull(r.src, header(r.pack[:]))
|
||||
if n != headerSize && err == io.ErrUnexpectedEOF {
|
||||
return errMissingHeader
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *decryptedReader) decrypt(dst []byte) (n int, err error) {
|
||||
header := header(r.pack[:])
|
||||
if err = r.config.verifyHeader(header); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if header.SequenceNumber() != r.sequenceNumber {
|
||||
return 0, errPackageOutOfOrder
|
||||
}
|
||||
ciphertext := r.pack[headerSize : headerSize+header.Len()+tagSize]
|
||||
n, err = io.ReadFull(r.src, ciphertext)
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
return 0, errPayloadTooShort
|
||||
} else if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
aeadCipher := r.ciphers[header.Cipher()]
|
||||
plaintext, err := aeadCipher.Open(dst[:0], header[4:], ciphertext, header[:4])
|
||||
if err != nil {
|
||||
return 0, errTagMismatch
|
||||
}
|
||||
r.sequenceNumber++
|
||||
return len(plaintext), nil
|
||||
}
|
257
vendor/github.com/minio/sio/sio.go
generated
vendored
Normal file
257
vendor/github.com/minio/sio/sio.go
generated
vendored
Normal file
@ -0,0 +1,257 @@
|
||||
// Copyright (C) 2018 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package sio implements the DARE format. It provides an API for secure
|
||||
// en/decrypting IO operations using io.Reader and io.Writer.
|
||||
package sio // import "github.com/minio/sio"
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/minio/sio/internal/cpu"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version20 specifies version 2.0
|
||||
Version20 byte = 0x20
|
||||
// Version10 specifies version 1.0
|
||||
Version10 byte = 0x10
|
||||
)
|
||||
|
||||
const (
|
||||
// AES_256_GCM specifies the cipher suite AES-GCM with 256 bit keys.
|
||||
AES_256_GCM byte = iota
|
||||
// CHACHA20_POLY1305 specifies the cipher suite ChaCha20Poly1305 with 256 bit keys.
|
||||
CHACHA20_POLY1305
|
||||
)
|
||||
|
||||
const (
|
||||
keySize = 32
|
||||
|
||||
headerSize = 16
|
||||
maxPayloadSize = 1 << 16
|
||||
tagSize = 16
|
||||
maxPackageSize = headerSize + maxPayloadSize + tagSize
|
||||
)
|
||||
|
||||
var newAesGcm = func(key []byte) (cipher.AEAD, error) {
|
||||
aes256, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cipher.NewGCM(aes256)
|
||||
}
|
||||
|
||||
var supportedCiphers = [...]func([]byte) (cipher.AEAD, error){
|
||||
AES_256_GCM: newAesGcm,
|
||||
CHACHA20_POLY1305: chacha20poly1305.New,
|
||||
}
|
||||
|
||||
var (
|
||||
errUnsupportedVersion = errors.New("sio: unsupported version")
|
||||
errUnsupportedCipher = errors.New("sio: unsupported cipher suite")
|
||||
errInvalidPayloadSize = errors.New("sio: invalid payload size")
|
||||
errTagMismatch = errors.New("sio: authentication failed")
|
||||
|
||||
// Version 1.0 specific
|
||||
errPackageOutOfOrder = errors.New("sio: sequence number mismatch")
|
||||
|
||||
// Version 2.0 specific
|
||||
errNonceMismatch = errors.New("sio: header nonce mismatch")
|
||||
errUnexpectedEOF = errors.New("sio: unexpected EOF")
|
||||
errUnexpectedData = errors.New("sio: unexpected data after final package")
|
||||
)
|
||||
|
||||
// Config contains the format configuration. The only field
|
||||
// which must always be set manually is the secret key.
|
||||
type Config struct {
|
||||
// The minimal supported version of the format. If
|
||||
// not set the default value - Version10 - is used.
|
||||
MinVersion byte
|
||||
|
||||
// The highest supported version of the format. If
|
||||
// not set the default value - Version20 - is used.
|
||||
MaxVersion byte
|
||||
|
||||
// A list of supported cipher suites. If not set the
|
||||
// default value is used.
|
||||
CipherSuites []byte
|
||||
|
||||
// The secret encryption key. It must be 32 bytes long.
|
||||
Key []byte
|
||||
|
||||
// The first expected sequence number. It should only
|
||||
// be set manually when decrypting a range within a
|
||||
// stream.
|
||||
SequenceNumber uint32
|
||||
|
||||
// The RNG used to generate random values. If not set
|
||||
// the default value (crypto/rand.Reader) is used.
|
||||
Rand io.Reader
|
||||
|
||||
// The size of the encrypted payload in bytes. The
|
||||
// default value is 64KB. It should be used to restrict
|
||||
// the size of encrypted packages. The payload size
|
||||
// must be between 1 and 64 KB.
|
||||
//
|
||||
// This field is specific for version 1.0 and is
|
||||
// deprecated.
|
||||
PayloadSize int
|
||||
}
|
||||
|
||||
// Encrypt reads from src until it encounters an io.EOF and encrypts all received
|
||||
// data. The encrypted data is written to dst. It returns the number of bytes
|
||||
// encrypted and the first error encountered while encrypting, if any.
|
||||
//
|
||||
// Encrypt returns the number of bytes written to dst.
|
||||
func Encrypt(dst io.Writer, src io.Reader, config Config) (n int64, err error) {
|
||||
encReader, err := EncryptReader(src, config)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return io.CopyBuffer(dst, encReader, make([]byte, headerSize+maxPayloadSize+tagSize))
|
||||
}
|
||||
|
||||
// Decrypt reads from src until it encounters an io.EOF and decrypts all received
|
||||
// data. The decrypted data is written to dst. It returns the number of bytes
|
||||
// decrypted and the first error encountered while decrypting, if any.
|
||||
//
|
||||
// Decrypt returns the number of bytes written to dst. Decrypt only writes data to
|
||||
// dst if the data was decrypted successfully.
|
||||
func Decrypt(dst io.Writer, src io.Reader, config Config) (n int64, err error) {
|
||||
decReader, err := DecryptReader(src, config)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return io.CopyBuffer(dst, decReader, make([]byte, maxPayloadSize))
|
||||
}
|
||||
|
||||
// EncryptReader wraps the given src and returns an io.Reader which encrypts
|
||||
// all received data. EncryptReader returns an error if the provided encryption
|
||||
// configuration is invalid.
|
||||
func EncryptReader(src io.Reader, config Config) (io.Reader, error) {
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.MaxVersion == Version20 {
|
||||
return encryptReaderV20(src, &config)
|
||||
}
|
||||
return encryptReaderV10(src, &config)
|
||||
}
|
||||
|
||||
// DecryptReader wraps the given src and returns an io.Reader which decrypts
|
||||
// all received data. DecryptReader returns an error if the provided decryption
|
||||
// configuration is invalid.
|
||||
func DecryptReader(src io.Reader, config Config) (io.Reader, error) {
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.MinVersion == Version10 && config.MaxVersion == Version10 {
|
||||
return decryptReaderV10(src, &config)
|
||||
}
|
||||
if config.MinVersion == Version20 && config.MaxVersion == Version20 {
|
||||
return decryptReaderV20(src, &config)
|
||||
}
|
||||
return decryptReader(src, &config), nil
|
||||
}
|
||||
|
||||
// EncryptWriter wraps the given dst and returns an io.WriteCloser which
|
||||
// encrypts all data written to it. EncryptWriter returns an error if the
|
||||
// provided decryption configuration is invalid.
|
||||
//
|
||||
// The returned io.WriteCloser must be closed successfully to finalize the
|
||||
// encryption process.
|
||||
func EncryptWriter(dst io.Writer, config Config) (io.WriteCloser, error) {
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.MaxVersion == Version20 {
|
||||
return encryptWriterV20(dst, &config)
|
||||
}
|
||||
return encryptWriterV10(dst, &config)
|
||||
}
|
||||
|
||||
// DecryptWriter wraps the given dst and returns an io.WriteCloser which
|
||||
// decrypts all data written to it. DecryptWriter returns an error if the
|
||||
// provided decryption configuration is invalid.
|
||||
//
|
||||
// The returned io.WriteCloser must be closed successfully to finalize the
|
||||
// decryption process.
|
||||
func DecryptWriter(dst io.Writer, config Config) (io.WriteCloser, error) {
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.MinVersion == Version10 && config.MaxVersion == Version10 {
|
||||
return decryptWriterV10(dst, &config)
|
||||
}
|
||||
if config.MinVersion == Version20 && config.MaxVersion == Version20 {
|
||||
return decryptWriterV20(dst, &config)
|
||||
}
|
||||
return decryptWriter(dst, &config), nil
|
||||
}
|
||||
|
||||
func defaultCipherSuites() []byte {
|
||||
if cpu.SupportsAES() {
|
||||
return []byte{AES_256_GCM, CHACHA20_POLY1305}
|
||||
}
|
||||
return []byte{CHACHA20_POLY1305, AES_256_GCM}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *Config) error {
|
||||
if config.MinVersion > Version20 {
|
||||
return errors.New("sio: unknown minimum version")
|
||||
}
|
||||
if config.MaxVersion > Version20 {
|
||||
return errors.New("sio: unknown maximum version")
|
||||
}
|
||||
if len(config.Key) != keySize {
|
||||
return errors.New("sio: invalid key size")
|
||||
}
|
||||
if len(config.CipherSuites) > 2 {
|
||||
return errors.New("sio: too many cipher suites")
|
||||
}
|
||||
for _, c := range config.CipherSuites {
|
||||
if int(c) >= len(supportedCiphers) {
|
||||
return errors.New("sio: unknown cipher suite")
|
||||
}
|
||||
}
|
||||
if config.PayloadSize > maxPayloadSize {
|
||||
return errors.New("sio: payload size is too large")
|
||||
}
|
||||
|
||||
if config.MinVersion < Version10 {
|
||||
config.MinVersion = Version10
|
||||
}
|
||||
if config.MaxVersion < Version10 {
|
||||
config.MaxVersion = Version20
|
||||
}
|
||||
if config.MinVersion > config.MaxVersion {
|
||||
return errors.New("sio: minimum version cannot be larger than maximum version")
|
||||
}
|
||||
if len(config.CipherSuites) == 0 {
|
||||
config.CipherSuites = defaultCipherSuites()
|
||||
}
|
||||
if config.Rand == nil {
|
||||
config.Rand = rand.Reader
|
||||
}
|
||||
if config.PayloadSize == 0 {
|
||||
config.PayloadSize = maxPayloadSize
|
||||
}
|
||||
return nil
|
||||
}
|
199
vendor/github.com/minio/sio/writer-v1.go
generated
vendored
Normal file
199
vendor/github.com/minio/sio/writer-v1.go
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
// Copyright (C) 2017 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sio
|
||||
|
||||
import "io"
|
||||
|
||||
type decWriterV10 struct {
|
||||
authDecV10
|
||||
dst io.Writer
|
||||
|
||||
buffer packageV10
|
||||
offset int
|
||||
}
|
||||
|
||||
// decryptWriterV10 returns an io.WriteCloser wrapping the given io.Writer.
|
||||
// The returned io.WriteCloser decrypts everything written to it using DARE 1.0
|
||||
// and writes all decrypted plaintext to the wrapped io.Writer.
|
||||
//
|
||||
// The io.WriteCloser must be closed to finalize the decryption successfully.
|
||||
func decryptWriterV10(dst io.Writer, config *Config) (*decWriterV10, error) {
|
||||
ad, err := newAuthDecV10(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decWriterV10{
|
||||
authDecV10: ad,
|
||||
dst: dst,
|
||||
buffer: make(packageV10, maxPackageSize),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *decWriterV10) Write(p []byte) (n int, err error) {
|
||||
if w.offset > 0 && w.offset < headerSize { // buffer the header -> special code b/c we don't know when to decrypt without header
|
||||
remaining := headerSize - w.offset
|
||||
if len(p) < remaining {
|
||||
n = copy(w.buffer[w.offset:], p)
|
||||
w.offset += n
|
||||
return
|
||||
}
|
||||
n = copy(w.buffer[w.offset:], p[:remaining])
|
||||
p = p[remaining:]
|
||||
w.offset += n
|
||||
}
|
||||
if w.offset >= headerSize { // buffer the ciphertext and tag -> here we know when to decrypt
|
||||
remaining := w.buffer.Length() - w.offset
|
||||
if len(p) < remaining {
|
||||
nn := copy(w.buffer[w.offset:], p)
|
||||
w.offset += nn
|
||||
return n + nn, err
|
||||
}
|
||||
n += copy(w.buffer[w.offset:], p[:remaining])
|
||||
if err = w.Open(w.buffer.Payload(), w.buffer[:w.buffer.Length()]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
if err = flush(w.dst, w.buffer.Payload()); err != nil { // write to underlying io.Writer
|
||||
return n, err
|
||||
}
|
||||
p = p[remaining:]
|
||||
w.offset = 0
|
||||
}
|
||||
for len(p) > headerSize {
|
||||
packageLen := headerSize + tagSize + headerV10(p).Len()
|
||||
if len(p) < packageLen { // p contains not the full package -> cannot decrypt
|
||||
w.offset = copy(w.buffer[:], p)
|
||||
n += w.offset
|
||||
return n, err
|
||||
}
|
||||
if err = w.Open(w.buffer[headerSize:packageLen-tagSize], p[:packageLen]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
if err = flush(w.dst, w.buffer[headerSize:packageLen-tagSize]); err != nil { // write to underlying io.Writer
|
||||
return n, err
|
||||
}
|
||||
p = p[packageLen:]
|
||||
n += packageLen
|
||||
}
|
||||
if len(p) > 0 {
|
||||
w.offset = copy(w.buffer[:], p)
|
||||
n += w.offset
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (w *decWriterV10) Close() error {
|
||||
if w.offset > 0 {
|
||||
if w.offset <= headerSize+tagSize {
|
||||
return errInvalidPayloadSize // the payload is always > 0
|
||||
}
|
||||
header := headerV10(w.buffer[:headerSize])
|
||||
if w.offset < headerSize+header.Len()+tagSize {
|
||||
return errInvalidPayloadSize // there is less data than specified by the header
|
||||
}
|
||||
if err := w.Open(w.buffer.Payload(), w.buffer[:w.buffer.Length()]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := flush(w.dst, w.buffer.Payload()); err != nil { // write to underlying io.Writer
|
||||
return err
|
||||
}
|
||||
}
|
||||
if dst, ok := w.dst.(io.Closer); ok {
|
||||
return dst.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type encWriterV10 struct {
|
||||
authEncV10
|
||||
dst io.Writer
|
||||
|
||||
buffer packageV10
|
||||
offset int
|
||||
payloadSize int
|
||||
}
|
||||
|
||||
// encryptWriterV10 returns an io.WriteCloser wrapping the given io.Writer.
|
||||
// The returned io.WriteCloser encrypts everything written to it using DARE 1.0
|
||||
// and writes all encrypted ciphertext as well as the package header and tag
|
||||
// to the wrapped io.Writer.
|
||||
//
|
||||
// The io.WriteCloser must be closed to finalize the encryption successfully.
|
||||
func encryptWriterV10(dst io.Writer, config *Config) (*encWriterV10, error) {
|
||||
ae, err := newAuthEncV10(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &encWriterV10{
|
||||
authEncV10: ae,
|
||||
dst: dst,
|
||||
buffer: make(packageV10, maxPackageSize),
|
||||
payloadSize: config.PayloadSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *encWriterV10) Write(p []byte) (n int, err error) {
|
||||
if w.offset > 0 { // buffer the plaintext
|
||||
remaining := w.payloadSize - w.offset
|
||||
if len(p) < remaining {
|
||||
n = copy(w.buffer[headerSize+w.offset:], p)
|
||||
w.offset += n
|
||||
return
|
||||
}
|
||||
n = copy(w.buffer[headerSize+w.offset:], p[:remaining])
|
||||
w.Seal(w.buffer, w.buffer[headerSize:headerSize+w.payloadSize])
|
||||
if err = flush(w.dst, w.buffer[:w.buffer.Length()]); err != nil { // write to underlying io.Writer
|
||||
return n, err
|
||||
}
|
||||
p = p[remaining:]
|
||||
w.offset = 0
|
||||
}
|
||||
for len(p) >= w.payloadSize {
|
||||
w.Seal(w.buffer[:], p[:w.payloadSize])
|
||||
if err = flush(w.dst, w.buffer[:w.buffer.Length()]); err != nil { // write to underlying io.Writer
|
||||
return n, err
|
||||
}
|
||||
p = p[w.payloadSize:]
|
||||
n += w.payloadSize
|
||||
}
|
||||
if len(p) > 0 {
|
||||
w.offset = copy(w.buffer[headerSize:], p)
|
||||
n += w.offset
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *encWriterV10) Close() error {
|
||||
if w.offset > 0 {
|
||||
w.Seal(w.buffer[:], w.buffer[headerSize:headerSize+w.offset])
|
||||
if err := flush(w.dst, w.buffer[:w.buffer.Length()]); err != nil { // write to underlying io.Writer
|
||||
return err
|
||||
}
|
||||
}
|
||||
if dst, ok := w.dst.(io.Closer); ok {
|
||||
return dst.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func flush(w io.Writer, p []byte) error {
|
||||
n, err := w.Write(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(p) { // not neccasary if the w follows the io.Writer doc *precisly*
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
return nil
|
||||
}
|
177
vendor/github.com/minio/sio/writer-v2.go
generated
vendored
Normal file
177
vendor/github.com/minio/sio/writer-v2.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright (C) 2018 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sio
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type encWriterV20 struct {
|
||||
authEncV20
|
||||
dst io.Writer
|
||||
|
||||
buffer packageV20
|
||||
offset int
|
||||
}
|
||||
|
||||
// encryptWriterV20 returns an io.WriteCloser wrapping the given io.Writer.
|
||||
// The returned io.WriteCloser encrypts everything written to it using DARE 2.0
|
||||
// and writes all encrypted ciphertext as well as the package header and tag
|
||||
// to the wrapped io.Writer.
|
||||
//
|
||||
// The io.WriteCloser must be closed to finalize the encryption successfully.
|
||||
func encryptWriterV20(dst io.Writer, config *Config) (*encWriterV20, error) {
|
||||
ae, err := newAuthEncV20(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &encWriterV20{
|
||||
authEncV20: ae,
|
||||
dst: dst,
|
||||
buffer: make(packageV20, maxPackageSize),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *encWriterV20) Write(p []byte) (n int, err error) {
|
||||
if w.finalized {
|
||||
// The caller closed the encWriterV20 instance (called encWriterV20.Close()).
|
||||
// This is a bug in the calling code - Write after Close is not allowed.
|
||||
panic("sio: write to stream after close")
|
||||
}
|
||||
if w.offset > 0 { // buffer the plaintext data
|
||||
remaining := maxPayloadSize - w.offset
|
||||
if len(p) <= remaining { // <= is important here to buffer up to 64 KB (inclusivly) - see: Close()
|
||||
w.offset += copy(w.buffer[headerSize+w.offset:], p)
|
||||
return len(p), nil
|
||||
}
|
||||
n = copy(w.buffer[headerSize+w.offset:], p[:remaining])
|
||||
w.Seal(w.buffer, w.buffer[headerSize:headerSize+maxPayloadSize])
|
||||
if err = flush(w.dst, w.buffer); err != nil { // write to underlying io.Writer
|
||||
return n, err
|
||||
}
|
||||
p = p[remaining:]
|
||||
w.offset = 0
|
||||
}
|
||||
for len(p) > maxPayloadSize { // > is important here to call Seal (not SealFinal) only if there is at least on package left - see: Close()
|
||||
w.Seal(w.buffer, p[:maxPayloadSize])
|
||||
if err = flush(w.dst, w.buffer); err != nil { // write to underlying io.Writer
|
||||
return n, err
|
||||
}
|
||||
p = p[maxPayloadSize:]
|
||||
n += maxPayloadSize
|
||||
}
|
||||
if len(p) > 0 {
|
||||
w.offset = copy(w.buffer[headerSize:], p)
|
||||
n += w.offset
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (w *encWriterV20) Close() error {
|
||||
if w.offset > 0 { // true if at least one Write call happend
|
||||
w.SealFinal(w.buffer, w.buffer[headerSize:headerSize+w.offset])
|
||||
if err := flush(w.dst, w.buffer[:headerSize+w.offset+tagSize]); err != nil { // write to underlying io.Writer
|
||||
return err
|
||||
}
|
||||
w.offset = 0
|
||||
}
|
||||
if closer, ok := w.dst.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type decWriterV20 struct {
|
||||
authDecV20
|
||||
dst io.Writer
|
||||
|
||||
buffer packageV20
|
||||
offset int
|
||||
}
|
||||
|
||||
// decryptWriterV20 returns an io.WriteCloser wrapping the given io.Writer.
|
||||
// The returned io.WriteCloser decrypts everything written to it using DARE 2.0
|
||||
// and writes all decrypted plaintext to the wrapped io.Writer.
|
||||
//
|
||||
// The io.WriteCloser must be closed to finalize the decryption successfully.
|
||||
func decryptWriterV20(dst io.Writer, config *Config) (*decWriterV20, error) {
|
||||
ad, err := newAuthDecV20(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decWriterV20{
|
||||
authDecV20: ad,
|
||||
dst: dst,
|
||||
buffer: make(packageV20, maxPackageSize),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *decWriterV20) Write(p []byte) (n int, err error) {
|
||||
if w.offset > 0 { // buffer package
|
||||
remaining := headerSize + maxPayloadSize + tagSize - w.offset
|
||||
if len(p) < remaining {
|
||||
w.offset += copy(w.buffer[w.offset:], p)
|
||||
return len(p), nil
|
||||
}
|
||||
n = copy(w.buffer[w.offset:], p[:remaining])
|
||||
plaintext := w.buffer[headerSize : headerSize+maxPayloadSize]
|
||||
if err = w.Open(plaintext, w.buffer); err != nil {
|
||||
return n, err
|
||||
}
|
||||
if err = flush(w.dst, plaintext); err != nil { // write to underlying io.Writer
|
||||
return n, err
|
||||
}
|
||||
p = p[remaining:]
|
||||
w.offset = 0
|
||||
}
|
||||
for len(p) >= maxPackageSize {
|
||||
plaintext := w.buffer[headerSize : headerSize+maxPayloadSize]
|
||||
if err = w.Open(plaintext, p[:maxPackageSize]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
if err = flush(w.dst, plaintext); err != nil { // write to underlying io.Writer
|
||||
return n, err
|
||||
}
|
||||
p = p[maxPackageSize:]
|
||||
n += maxPackageSize
|
||||
}
|
||||
if len(p) > 0 {
|
||||
if w.finalized {
|
||||
return n, errUnexpectedData
|
||||
}
|
||||
w.offset = copy(w.buffer[:], p)
|
||||
n += w.offset
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (w *decWriterV20) Close() error {
|
||||
if w.offset > 0 {
|
||||
if w.offset <= headerSize+tagSize { // the payload is always > 0
|
||||
return errInvalidPayloadSize
|
||||
}
|
||||
if err := w.Open(w.buffer[headerSize:w.offset-tagSize], w.buffer[:w.offset]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := flush(w.dst, w.buffer[headerSize:w.offset-tagSize]); err != nil { // write to underlying io.Writer
|
||||
return err
|
||||
}
|
||||
w.offset = 0
|
||||
}
|
||||
if closer, ok := w.dst.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
193
vendor/github.com/minio/sio/writer.go
generated
vendored
193
vendor/github.com/minio/sio/writer.go
generated
vendored
@ -1,193 +0,0 @@
|
||||
// Copyright (C) 2017 Minio Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sio
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"io"
|
||||
)
|
||||
|
||||
type decryptedWriter struct {
|
||||
dst io.Writer
|
||||
config Config
|
||||
|
||||
sequenceNumber uint32
|
||||
ciphers []cipher.AEAD
|
||||
|
||||
pack [headerSize + payloadSize + tagSize]byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (w *decryptedWriter) Write(p []byte) (n int, err error) {
|
||||
if w.offset > 0 && w.offset < headerSize {
|
||||
remaining := headerSize - w.offset
|
||||
if len(p) < remaining {
|
||||
n = copy(w.pack[w.offset:], p)
|
||||
w.offset += n
|
||||
return
|
||||
}
|
||||
n = copy(w.pack[w.offset:], p[:remaining])
|
||||
p = p[remaining:]
|
||||
w.offset += n
|
||||
}
|
||||
if w.offset >= headerSize {
|
||||
remaining := headerSize + header(w.pack[:]).Len() + tagSize - w.offset
|
||||
if len(p) < remaining {
|
||||
nn := copy(w.pack[w.offset:], p)
|
||||
w.offset += nn
|
||||
return n + nn, err
|
||||
}
|
||||
n += copy(w.pack[w.offset:], p[:remaining])
|
||||
if err = w.decrypt(w.pack[:]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
p = p[remaining:]
|
||||
w.offset = 0
|
||||
}
|
||||
for len(p) > headerSize {
|
||||
header := header(p)
|
||||
if len(p) < headerSize+header.Len()+tagSize {
|
||||
w.offset = copy(w.pack[:], p)
|
||||
n += w.offset
|
||||
return
|
||||
}
|
||||
if err = w.decrypt(p); err != nil {
|
||||
return n, err
|
||||
}
|
||||
p = p[headerSize+header.Len()+tagSize:]
|
||||
n += headerSize + header.Len() + tagSize
|
||||
}
|
||||
w.offset = copy(w.pack[:], p)
|
||||
n += w.offset
|
||||
return
|
||||
}
|
||||
|
||||
func (w *decryptedWriter) Close() error {
|
||||
if w.offset > 0 {
|
||||
if w.offset < headerSize {
|
||||
return errMissingHeader
|
||||
}
|
||||
if w.offset < headerSize+header(w.pack[:]).Len()+tagSize {
|
||||
return errPayloadTooShort
|
||||
}
|
||||
if err := w.decrypt(w.pack[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if dst, ok := w.dst.(io.Closer); ok {
|
||||
return dst.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *decryptedWriter) decrypt(src []byte) error {
|
||||
header := header(src)
|
||||
if err := w.config.verifyHeader(header); err != nil {
|
||||
return err
|
||||
}
|
||||
if header.SequenceNumber() != w.sequenceNumber {
|
||||
return errPackageOutOfOrder
|
||||
}
|
||||
|
||||
aeadCipher := w.ciphers[header.Cipher()]
|
||||
plaintext, err := aeadCipher.Open(w.pack[headerSize:headerSize], header[4:headerSize], src[headerSize:headerSize+header.Len()+tagSize], header[:4])
|
||||
if err != nil {
|
||||
return errTagMismatch
|
||||
}
|
||||
|
||||
n, err := w.dst.Write(plaintext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(plaintext) {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
|
||||
w.sequenceNumber++
|
||||
return nil
|
||||
}
|
||||
|
||||
type encryptedWriter struct {
|
||||
dst io.Writer
|
||||
config Config
|
||||
|
||||
nonce [8]byte
|
||||
sequenceNumber uint32
|
||||
cipher cipher.AEAD
|
||||
|
||||
pack [headerSize + payloadSize + tagSize]byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (w *encryptedWriter) Write(p []byte) (n int, err error) {
|
||||
if w.offset > 0 {
|
||||
remaining := payloadSize - w.offset
|
||||
if len(p) < remaining {
|
||||
n = copy(w.pack[headerSize+w.offset:], p)
|
||||
w.offset += n
|
||||
return
|
||||
}
|
||||
n = copy(w.pack[headerSize+w.offset:], p[:remaining])
|
||||
if err = w.encrypt(w.pack[headerSize : headerSize+payloadSize]); err != nil {
|
||||
return
|
||||
}
|
||||
p = p[remaining:]
|
||||
w.offset = 0
|
||||
}
|
||||
for len(p) >= payloadSize {
|
||||
if err = w.encrypt(p[:payloadSize]); err != nil {
|
||||
return
|
||||
}
|
||||
p = p[payloadSize:]
|
||||
n += payloadSize
|
||||
}
|
||||
if len(p) > 0 {
|
||||
w.offset = copy(w.pack[headerSize:], p)
|
||||
n += w.offset
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *encryptedWriter) Close() error {
|
||||
if w.offset > 0 {
|
||||
return w.encrypt(w.pack[headerSize : headerSize+w.offset])
|
||||
}
|
||||
if dst, ok := w.dst.(io.Closer); ok {
|
||||
return dst.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *encryptedWriter) encrypt(src []byte) error {
|
||||
header := header(w.pack[:])
|
||||
header.SetVersion(w.config.MaxVersion)
|
||||
header.SetCipher(w.config.CipherSuites[0])
|
||||
header.SetLen(len(src))
|
||||
header.SetSequenceNumber(w.sequenceNumber)
|
||||
header.SetNonce(w.nonce)
|
||||
|
||||
w.cipher.Seal(w.pack[headerSize:headerSize], header[4:headerSize], src, header[:4])
|
||||
|
||||
n, err := w.dst.Write(w.pack[:headerSize+len(src)+tagSize])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != headerSize+len(src)+tagSize {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
|
||||
w.sequenceNumber++
|
||||
return nil
|
||||
}
|
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@ -456,10 +456,10 @@
|
||||
"revisionTime": "2017-08-28T17:39:33Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "/VYXTlcksV92qL4Avr5S3NJ/Fxs=",
|
||||
"checksumSHA1": "pvBHvHfubwxgvXNz35PDMbBWY9s=",
|
||||
"path": "github.com/minio/sio",
|
||||
"revision": "d8be2518a912f0db0dd17dc55f46da4360ee60d8",
|
||||
"revisionTime": "2017-09-06T19:57:40Z"
|
||||
"revision": "83dd737d26dbcf4847f48ecec77c2c13f739eb25",
|
||||
"revisionTime": "2018-03-01T21:58:29Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "zvQr4zOz1/g/Fui6co0sctxrJ28=",
|
||||
|
Loading…
x
Reference in New Issue
Block a user