e15b908983
* EE-319: backup endpoint (#193) * feat(backup): * add an orbiter to block writes while backup * add backup handler * add an ability to tar.gz a dir * add aes encryption support * EE-320: restore endpoint (#196) * feat(backup): * add restore handler * re-init system state after restore * feat(backup): Update server to respect readonly lock (#199) * feat(backup): EE-322 Add backup and restore screen (#198) Co-authored-by: Simon Meng <simon.meng@portainer.io> * name archive as portainer-backup_yyyy-mm-dd_hh-mm-ss * backup custom templates and edge jobs * restart http and proxy servers after restore to re-init internal state * feat(backup): EE-322 hide password field if password protect toggle is off * feat(backup): EE-322 add tooltip for password field of restore backup * feat(backup): EE-322 wait for backend restart after restoring * Shutdown background go-routines * changed restore err message when cannot extract * fix: symlinks are ignored from backups * replace single admin check with a restartable monitor (#238) * clean log Co-authored-by: Maxime Bajeux <max.bajeux@gmail.com> Co-authored-by: cong meng <mcpacino@gmail.com> Co-authored-by: Simon Meng <simon.meng@portainer.io>
71 lines
1.9 KiB
Go
71 lines
1.9 KiB
Go
package crypto
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"io"
|
|
|
|
"golang.org/x/crypto/scrypt"
|
|
)
|
|
|
|
// NOTE: has to go with what is considered to be a simplistic in that it omits any
|
|
// authentication of the encrypted data.
|
|
// Person with better knowledge is welcomed to improve it.
|
|
// sourced from https://golang.org/src/crypto/cipher/example_test.go
|
|
|
|
var emptySalt []byte = make([]byte, 0, 0)
|
|
|
|
// AesEncrypt reads from input, encrypts with AES-256 and writes to the output.
|
|
// passphrase is used to generate an encryption key.
|
|
func AesEncrypt(input io.Reader, output io.Writer, passphrase []byte) error {
|
|
// making a 32 bytes key that would correspond to AES-256
|
|
// don't necessarily need a salt, so just kept in empty
|
|
key, err := scrypt.Key(passphrase, emptySalt, 32768, 8, 1, 32)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// If the key is unique for each ciphertext, then it's ok to use a zero
|
|
// IV.
|
|
var iv [aes.BlockSize]byte
|
|
stream := cipher.NewOFB(block, iv[:])
|
|
|
|
writer := &cipher.StreamWriter{S: stream, W: output}
|
|
// Copy the input to the output, encrypting as we go.
|
|
if _, err := io.Copy(writer, input); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AesDecrypt reads from input, decrypts with AES-256 and returns the reader to a read decrypted content from.
|
|
// passphrase is used to generate an encryption key.
|
|
func AesDecrypt(input io.Reader, passphrase []byte) (io.Reader, error) {
|
|
// making a 32 bytes key that would correspond to AES-256
|
|
// don't necessarily need a salt, so just kept in empty
|
|
key, err := scrypt.Key(passphrase, emptySalt, 32768, 8, 1, 32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// If the key is unique for each ciphertext, then it's ok to use a zero
|
|
// IV.
|
|
var iv [aes.BlockSize]byte
|
|
stream := cipher.NewOFB(block, iv[:])
|
|
|
|
reader := &cipher.StreamReader{S: stream, R: input}
|
|
|
|
return reader, nil
|
|
}
|