forked from wal-g/wal-g
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement libsodium Crypter (wal-g#512)
* Implement libsodium Crypter * Environment variable for possible build without libsodium * Add explanation comment Co-authored-by: IrinaSedova <[email protected]>
- Loading branch information
Showing
17 changed files
with
480 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// +build !libsodium | ||
|
||
package internal | ||
|
||
// This file contains functions that should return `nil`, | ||
// in order to be able to build wal-g without specific implementations of the crypter. | ||
// And the configure_crypter_<crypter>.go files must have a real implementation of the function. | ||
// | ||
// Thus, if the tag is missing, the condition: | ||
// if crypter := configure<crypter>Crypter(); crypter != nil { | ||
// return crypter | ||
// } | ||
// will never be met. | ||
// If there is a tag, we can configure the correct implementation of crypter. | ||
|
||
import ( | ||
"github.com/wal-g/wal-g/internal/crypto" | ||
) | ||
|
||
func configureLibsodiumCrypter() crypto.Crypter { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// +build libsodium | ||
|
||
package internal | ||
|
||
import ( | ||
"github.com/spf13/viper" | ||
"github.com/wal-g/wal-g/internal/crypto" | ||
"github.com/wal-g/wal-g/internal/crypto/libsodium" | ||
) | ||
|
||
func configureLibsodiumCrypter() crypto.Crypter { | ||
if viper.IsSet(LibsodiumKeySetting) { | ||
return libsodium.CrypterFromKey(viper.GetString(LibsodiumKeySetting)) | ||
} | ||
|
||
if viper.IsSet(LibsodiumKeyPathSetting) { | ||
return libsodium.CrypterFromKeyPath(viper.GetString(LibsodiumKeyPathSetting)) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package libsodium | ||
|
||
// #cgo CFLAGS: -I../../../tmp/libsodium/include | ||
// #cgo LDFLAGS: -L../../../tmp/libsodium/lib -lsodium | ||
// #include <sodium.h> | ||
import "C" | ||
|
||
import ( | ||
"io" | ||
"io/ioutil" | ||
"strings" | ||
"sync" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/wal-g/wal-g/internal/crypto" | ||
) | ||
|
||
const ( | ||
chunkSize = 8192 | ||
) | ||
|
||
// libsodium should always be initialised | ||
func init() { | ||
C.sodium_init() | ||
} | ||
|
||
// Crypter is libsodium Crypter implementation | ||
type Crypter struct { | ||
Key string | ||
KeyPath string | ||
|
||
mutex sync.RWMutex | ||
} | ||
|
||
// CrypterFromKey creates Crypter from key | ||
func CrypterFromKey(key string) crypto.Crypter { | ||
return &Crypter{Key: key} | ||
} | ||
|
||
// CrypterFromKeyPath creates Crypter from key path | ||
func CrypterFromKeyPath(path string) crypto.Crypter { | ||
return &Crypter{KeyPath: path} | ||
} | ||
|
||
func (crypter *Crypter) setup() (err error) { | ||
crypter.mutex.RLock() | ||
|
||
if crypter.Key == "" && crypter.KeyPath == "" { | ||
return errors.New("libsodium Crypter must have a key or key path") | ||
} | ||
|
||
if crypter.Key != "" { | ||
crypter.mutex.RUnlock() | ||
|
||
return | ||
} | ||
|
||
crypter.mutex.RUnlock() | ||
|
||
crypter.mutex.Lock() | ||
defer crypter.mutex.Unlock() | ||
|
||
if crypter.Key != "" { | ||
return | ||
} | ||
|
||
key, err := ioutil.ReadFile(crypter.KeyPath) | ||
|
||
if err != nil { | ||
return | ||
} | ||
|
||
crypter.Key = strings.TrimSpace(string(key)) | ||
|
||
return nil | ||
} | ||
|
||
// Encrypt creates encryption writer from ordinary writer | ||
func (crypter *Crypter) Encrypt(writer io.Writer) (io.WriteCloser, error) { | ||
if err := crypter.setup(); err != nil { | ||
return nil, err | ||
} | ||
|
||
return NewWriter(writer, []byte(crypter.Key)) | ||
} | ||
|
||
// Decrypt creates decrypted reader from ordinary reader | ||
func (crypter *Crypter) Decrypt(reader io.Reader) (io.Reader, error) { | ||
if err := crypter.setup(); err != nil { | ||
return nil, err | ||
} | ||
|
||
return NewReader(reader, []byte(crypter.Key)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// +build libsodium | ||
|
||
package libsodium | ||
|
||
import ( | ||
"bytes" | ||
"io/ioutil" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/wal-g/wal-g/internal/crypto" | ||
) | ||
|
||
const ( | ||
keyPath = "./testdata/testKey" | ||
testKey = "TEST_LIBSODIUM_KEY" | ||
) | ||
|
||
func MockCrypterFromKey() *Crypter { | ||
return CrypterFromKey(testKey).(*Crypter) | ||
} | ||
|
||
func MockCrypterFromKeyPath() *Crypter { | ||
return CrypterFromKeyPath(keyPath).(*Crypter) | ||
} | ||
|
||
func TestMockCrypterFromKey(t *testing.T) { | ||
assert.NoError(t, MockCrypterFromKey().setup(), "setup Crypter from key error") | ||
} | ||
|
||
func TestMockCrypterFromKeyPath(t *testing.T) { | ||
assert.NoError(t, MockCrypterFromKeyPath().setup(), "setup Crypter from key path error") | ||
} | ||
|
||
func TestMockCrypterFromKey_ShouldReturnErrorOnEmptyKey(t *testing.T) { | ||
assert.Error(t, CrypterFromKey("").(*Crypter).setup(), "no error on empty key") | ||
} | ||
|
||
func TestMockCrypterFromKeyPath_ShouldReturnErrorOnNonExistentFile(t *testing.T) { | ||
assert.Error(t, CrypterFromKeyPath("").(*Crypter).setup(), "no error on non-existent key path") | ||
} | ||
|
||
func EncryptionCycle(t *testing.T, crypter crypto.Crypter) { | ||
secret := strings.Repeat(" so very secret thing ", 1000) | ||
|
||
buffer := new(bytes.Buffer) | ||
encrypt, err := crypter.Encrypt(buffer) | ||
assert.NoErrorf(t, err, "encryption error: %v", err) | ||
|
||
encrypt.Write([]byte(secret)) | ||
encrypt.Close() | ||
|
||
decrypt, err := crypter.Decrypt(buffer) | ||
assert.NoErrorf(t, err, "decryption error: %v", err) | ||
|
||
decrypted, err := ioutil.ReadAll(decrypt) | ||
assert.NoErrorf(t, err, "decryption read error: %v", err) | ||
|
||
assert.Equal(t, secret, string(decrypted), "decrypted text not equals to open text") | ||
} | ||
|
||
func TestEncryptionCycleFromKey(t *testing.T) { | ||
EncryptionCycle(t, MockCrypterFromKey()) | ||
} | ||
|
||
func TestEncryptionCycleFromKeyPath(t *testing.T) { | ||
EncryptionCycle(t, MockCrypterFromKeyPath()) | ||
} |
Oops, something went wrong.