Documentation ¶
Overview ¶
Package sio implements the DARE format. It provides an API for secure en/decrypting IO operations using io.Reader and io.Writer.
Index ¶
- Constants
- func Decrypt(dst io.Writer, src io.Reader, config Config) (n int64, err error)
- func DecryptReader(src io.Reader, config Config) (io.Reader, error)
- func DecryptWriter(dst io.Writer, config Config) (io.WriteCloser, error)
- func DecryptedSize(size uint64) (uint64, error)
- func Encrypt(dst io.Writer, src io.Reader, config Config) (n int64, err error)
- func EncryptReader(src io.Reader, config Config) (io.Reader, error)
- func EncryptWriter(dst io.Writer, config Config) (io.WriteCloser, error)
- func EncryptedSize(size uint64) (uint64, error)
- type Config
- type Error
Examples ¶
Constants ¶
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 )
Variables ¶
This section is empty.
Functions ¶
func Decrypt ¶
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. It returns an error of type sio.Error if decryption fails.
Example ¶
// the master key used to derive encryption keys masterkey, err := hex.DecodeString("000102030405060708090A0B0C0D0E0FF0E0D0C0B0A090807060504030201000") // use your own key here if err != nil { fmt.Printf("Cannot decode hex key: %v", err) // add error handling return } // the nonce used to derive the encryption key nonce, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000001") // use your generated nonce here if err != nil { fmt.Printf("Cannot decode hex key: %v", err) // add error handling return } // derive the encryption key from the master key and the nonce var key [32]byte kdf := hkdf.New(sha256.New, masterkey, nonce, nil) if _, err = io.ReadFull(kdf, key[:]); err != nil { fmt.Printf("Failed to derive encryption key: %v", err) // add error handling return } input := os.Stdin // customize for your needs - the encrypted data output := os.Stdout // customize from your needs - the decrypted output if _, err = Decrypt(output, input, Config{Key: key[:]}); err != nil { if _, ok := err.(Error); ok { fmt.Printf("Malformed encrypted data: %v", err) // add error handling - here we know that the data is malformed/not authentic. return } fmt.Printf("Failed to decrypt data: %v", err) // add error handling return }
Output:
func DecryptReader ¶
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. The returned io.Reader returns an error of type sio.Error if the decryption fails.
func DecryptWriter ¶
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. The returned io.WriteCloser returns an error of type sio.Error if the decryption fails.
func DecryptedSize ¶
DecryptedSize computes the size of a decrypted data stream from the encrypted stream size. It is the inverse of EncryptedSize().
DecryptedSize returns an error if the provided size is to large or if the provided size is an invalid encrypted stream size.
func Encrypt ¶
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.
Example ¶
// the master key used to derive encryption keys // this key must be keep secret masterkey, err := hex.DecodeString("000102030405060708090A0B0C0D0E0FF0E0D0C0B0A090807060504030201000") // use your own key here if err != nil { fmt.Printf("Cannot decode hex key: %v", err) // add error handling return } // generate a random nonce to derive an encryption key from the master key // this nonce must be saved to be able to decrypt the data again - it is not // required to keep it secret var nonce [32]byte if _, err = io.ReadFull(rand.Reader, nonce[:]); err != nil { fmt.Printf("Failed to read random data: %v", err) // add error handling return } // derive an encryption key from the master key and the nonce var key [32]byte kdf := hkdf.New(sha256.New, masterkey, nonce[:], nil) if _, err = io.ReadFull(kdf, key[:]); err != nil { fmt.Printf("Failed to derive encryption key: %v", err) // add error handling return } input := os.Stdin // customize for your needs - the plaintext output := os.Stdout // customize from your needs - the decrypted output if _, err = Encrypt(output, input, Config{Key: key[:]}); err != nil { fmt.Printf("Failed to encrypt data: %v", err) // add error handling return }
Output:
func EncryptReader ¶
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.
Example ¶
// the master key used to derive encryption keys // this key must be keep secret masterkey, err := hex.DecodeString("000102030405060708090A0B0C0D0E0FF0E0D0C0B0A090807060504030201000") // use your own key here if err != nil { fmt.Printf("Cannot decode hex key: %v", err) // add error handling return } // generate a random nonce to derive an encryption key from the master key // this nonce must be saved to be able to decrypt the data again - it is not // required to keep it secret var nonce [32]byte if _, err = io.ReadFull(rand.Reader, nonce[:]); err != nil { fmt.Printf("Failed to read random data: %v", err) // add error handling return } // derive an encryption key from the master key and the nonce var key [32]byte kdf := hkdf.New(sha256.New, masterkey, nonce[:], nil) if _, err = io.ReadFull(kdf, key[:]); err != nil { fmt.Printf("Failed to derive encryption key: %v", err) // add error handling return } input := os.Stdin // customize for your needs - the plaintext input encrypted, err := EncryptReader(input, Config{Key: key[:]}) if err != nil { fmt.Printf("Failed to encrypted reader: %v", err) // add error handling return } // the encrypted io.Reader can be used like every other reader - e.g. for copying if _, err := io.Copy(os.Stdout, encrypted); err != nil { fmt.Printf("Failed to copy data: %v", err) // add error handling return }
Output:
func EncryptWriter ¶
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.
Example ¶
// the master key used to derive encryption keys // this key must be keep secret masterkey, err := hex.DecodeString("000102030405060708090A0B0C0D0E0FF0E0D0C0B0A090807060504030201000") // use your own key here if err != nil { fmt.Printf("Cannot decode hex key: %v", err) // add error handling return } // generate a random nonce to derive an encryption key from the master key // this nonce must be saved to be able to decrypt the data again - it is not // required to keep it secret var nonce [32]byte if _, err = io.ReadFull(rand.Reader, nonce[:]); err != nil { fmt.Printf("Failed to read random data: %v", err) // add error handling return } // derive an encryption key from the master key and the nonce var key [32]byte kdf := hkdf.New(sha256.New, masterkey, nonce[:], nil) if _, err = io.ReadFull(kdf, key[:]); err != nil { fmt.Printf("Failed to derive encryption key: %v", err) // add error handling return } output := os.Stdout // customize for your needs - the encrypted output encrypted, err := EncryptWriter(output, Config{Key: key[:]}) if err != nil { fmt.Printf("Failed to encrypted writer: %v", err) // add error handling return } // the encrypted io.Writer can be used now but it MUST be closed at the end to // finalize the encryption. if _, err = io.Copy(encrypted, os.Stdin); err != nil { fmt.Printf("Failed to copy data: %v", err) // add error handling return } if err = encrypted.Close(); err != nil { fmt.Printf("Failed to finalize encryption: %v", err) // add error handling return }
Output:
func EncryptedSize ¶
EncryptedSize computes the size of an encrypted data stream from the plaintext size. It is the inverse of DecryptedSize().
EncryptedSize returns an error if the provided size is to large.
Types ¶
type Config ¶
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 }
Config contains the format configuration. The only field which must always be set manually is the secret key.