mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-08 23:50:48 +02:00
- Added new routes and handlers for managing storage providers, including creation, editing, and deletion. - Introduced a new StorageProvider form component for user input. - Enhanced the database schema to support storage provider references in transfer configurations. - Implemented encryption for sensitive fields in storage provider data. - Added tests for storage provider API endpoints and integration with the database. - Updated frontend components to support storage provider selection and testing.
275 lines
8.1 KiB
Go
275 lines
8.1 KiB
Go
package encryption
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"os"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func setupTestKeyManager(t *testing.T) KeyManager {
|
|
// Setup test environment
|
|
testEnvVar := "TEST_ENCRYPTION_KEY"
|
|
validKey := make([]byte, AES256KeySize)
|
|
for i := range validKey {
|
|
validKey[i] = byte(i % 256)
|
|
}
|
|
validKeyBase64 := base64.StdEncoding.EncodeToString(validKey)
|
|
|
|
// Set a valid key in environment
|
|
os.Setenv(testEnvVar, validKeyBase64)
|
|
t.Cleanup(func() {
|
|
os.Unsetenv(testEnvVar)
|
|
})
|
|
|
|
km := NewKeyManager(testEnvVar)
|
|
err := km.(KeyManager).Initialize()
|
|
require.NoError(t, err)
|
|
|
|
return km
|
|
}
|
|
|
|
func setupEncryptionService(t *testing.T) *EncryptionService {
|
|
km := setupTestKeyManager(t)
|
|
service, err := NewEncryptionService(km)
|
|
require.NoError(t, err)
|
|
return service
|
|
}
|
|
|
|
func TestNewEncryptionService(t *testing.T) {
|
|
t.Run("Valid key manager", func(t *testing.T) {
|
|
km := setupTestKeyManager(t)
|
|
service, err := NewEncryptionService(km)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, service)
|
|
})
|
|
|
|
t.Run("Nil key manager", func(t *testing.T) {
|
|
service, err := NewEncryptionService(nil)
|
|
require.Error(t, err)
|
|
assert.Nil(t, service)
|
|
})
|
|
}
|
|
|
|
func TestEncryptionService_Encrypt(t *testing.T) {
|
|
service := setupEncryptionService(t)
|
|
|
|
t.Run("Encrypt valid data", func(t *testing.T) {
|
|
plaintext := []byte("This is a test message that needs to be encrypted")
|
|
encrypted, err := service.Encrypt(plaintext)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, encrypted)
|
|
|
|
// Encrypted data should be base64 encoded
|
|
_, err = base64.StdEncoding.DecodeString(encrypted)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("Encrypt empty data", func(t *testing.T) {
|
|
encrypted, err := service.Encrypt([]byte{})
|
|
require.Error(t, err)
|
|
assert.Equal(t, ErrEmptyPlaintext, err)
|
|
assert.Empty(t, encrypted)
|
|
})
|
|
|
|
t.Run("Same plaintext produces different ciphertexts", func(t *testing.T) {
|
|
plaintext := []byte("This should encrypt to different ciphertexts each time")
|
|
encrypted1, err := service.Encrypt(plaintext)
|
|
require.NoError(t, err)
|
|
|
|
encrypted2, err := service.Encrypt(plaintext)
|
|
require.NoError(t, err)
|
|
|
|
assert.NotEqual(t, encrypted1, encrypted2, "Same plaintext should encrypt to different ciphertexts due to random IV")
|
|
})
|
|
}
|
|
|
|
func TestEncryptionService_Decrypt(t *testing.T) {
|
|
service := setupEncryptionService(t)
|
|
|
|
t.Run("Decrypt valid data", func(t *testing.T) {
|
|
plaintext := []byte("This is a test message that needs to be encrypted and decrypted")
|
|
encrypted, err := service.Encrypt(plaintext)
|
|
require.NoError(t, err)
|
|
|
|
decrypted, err := service.Decrypt(encrypted)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, plaintext, decrypted)
|
|
})
|
|
|
|
t.Run("Decrypt empty data", func(t *testing.T) {
|
|
decrypted, err := service.Decrypt("")
|
|
require.Error(t, err)
|
|
assert.Equal(t, ErrEmptyCiphertext, err)
|
|
assert.Nil(t, decrypted)
|
|
})
|
|
|
|
t.Run("Decrypt invalid base64", func(t *testing.T) {
|
|
decrypted, err := service.Decrypt("this-is-not-valid-base64!@#$%^")
|
|
require.Error(t, err)
|
|
assert.Nil(t, decrypted)
|
|
})
|
|
|
|
t.Run("Decrypt corrupted data - last byte modified", func(t *testing.T) {
|
|
plaintext := []byte("This is a test message with proper length for padding")
|
|
encrypted, err := service.Encrypt(plaintext)
|
|
require.NoError(t, err)
|
|
|
|
// Modify the last byte to corrupt the padding
|
|
decoded, err := base64.StdEncoding.DecodeString(encrypted)
|
|
require.NoError(t, err)
|
|
decoded[len(decoded)-1] ^= 0x01 // Flip one bit in the last byte
|
|
corrupted := base64.StdEncoding.EncodeToString(decoded)
|
|
|
|
decrypted, err := service.Decrypt(corrupted)
|
|
require.Error(t, err, "Decryption should fail with corrupted data")
|
|
assert.Nil(t, decrypted)
|
|
})
|
|
|
|
t.Run("Decrypt with short data", func(t *testing.T) {
|
|
// Create a short invalid encrypted string (not enough bytes for IV)
|
|
shortData := base64.StdEncoding.EncodeToString([]byte("tooshort"))
|
|
decrypted, err := service.Decrypt(shortData)
|
|
require.Error(t, err)
|
|
assert.Nil(t, decrypted)
|
|
})
|
|
}
|
|
|
|
func TestEncryptionService_EncryptString(t *testing.T) {
|
|
service := setupEncryptionService(t)
|
|
|
|
t.Run("Encrypt valid string", func(t *testing.T) {
|
|
plaintext := "This is a test string that needs to be encrypted"
|
|
encrypted, err := service.EncryptString(plaintext)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, encrypted)
|
|
|
|
// Encrypted data should be base64 encoded
|
|
_, err = base64.StdEncoding.DecodeString(encrypted)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("Encrypt empty string", func(t *testing.T) {
|
|
encrypted, err := service.EncryptString("")
|
|
require.Error(t, err)
|
|
assert.Equal(t, ErrEmptyPlaintext, err)
|
|
assert.Empty(t, encrypted)
|
|
})
|
|
}
|
|
|
|
func TestEncryptionService_DecryptString(t *testing.T) {
|
|
service := setupEncryptionService(t)
|
|
|
|
t.Run("Decrypt valid string", func(t *testing.T) {
|
|
plaintext := "This is a test string that needs to be encrypted and decrypted"
|
|
encrypted, err := service.EncryptString(plaintext)
|
|
require.NoError(t, err)
|
|
|
|
decrypted, err := service.DecryptString(encrypted)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, plaintext, decrypted)
|
|
})
|
|
|
|
t.Run("Decrypt empty string", func(t *testing.T) {
|
|
decrypted, err := service.DecryptString("")
|
|
require.Error(t, err)
|
|
assert.Equal(t, ErrEmptyCiphertext, err)
|
|
assert.Empty(t, decrypted)
|
|
})
|
|
}
|
|
|
|
func TestPkcs7Padding(t *testing.T) {
|
|
blockSize := 16
|
|
|
|
t.Run("Pad and unpad", func(t *testing.T) {
|
|
testCases := []struct {
|
|
input []byte
|
|
expected int // expected padding size
|
|
}{
|
|
{[]byte("testing"), 9}, // 7 bytes + 9 padding = 16 bytes (multiple of blockSize)
|
|
{[]byte("16 bytes exactly"), 16}, // 16 bytes + 16 padding = 32 bytes (multiple of blockSize)
|
|
{[]byte("this is a longer test string"), 4}, // 28 bytes + 4 padding = 32 bytes (multiple of blockSize)
|
|
{[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 2}, // 14 bytes + 2 padding = 16 bytes (multiple of blockSize)
|
|
{[]byte{}, 16}, // 0 bytes + 16 padding = 16 bytes (multiple of blockSize)
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
padded := pkcs7Pad(tc.input, blockSize)
|
|
// Check padding size
|
|
assert.Equal(t, len(tc.input)+tc.expected, len(padded))
|
|
// Check padding value
|
|
for i := len(tc.input); i < len(padded); i++ {
|
|
assert.Equal(t, byte(tc.expected), padded[i])
|
|
}
|
|
|
|
// Unpad and check
|
|
unpadded, err := pkcs7Unpad(padded, blockSize)
|
|
require.NoError(t, err)
|
|
assert.True(t, bytes.Equal(tc.input, unpadded))
|
|
}
|
|
})
|
|
|
|
t.Run("Invalid padding", func(t *testing.T) {
|
|
// Invalid padding value
|
|
invalid := []byte("test data with invalid padding")
|
|
paddedInvalid := pkcs7Pad(invalid, blockSize)
|
|
paddedInvalid[len(paddedInvalid)-1] = 99 // Invalid padding value
|
|
_, err := pkcs7Unpad(paddedInvalid, blockSize)
|
|
require.Error(t, err)
|
|
|
|
// Inconsistent padding
|
|
inconsistent := []byte("test data with inconsistent padding")
|
|
paddedInconsistent := pkcs7Pad(inconsistent, blockSize)
|
|
paddedInconsistent[len(paddedInconsistent)-2] = 99 // Make padding inconsistent
|
|
_, err = pkcs7Unpad(paddedInconsistent, blockSize)
|
|
require.Error(t, err)
|
|
|
|
// Empty data
|
|
_, err = pkcs7Unpad([]byte{}, blockSize)
|
|
require.Error(t, err)
|
|
|
|
// Invalid block size
|
|
invalidSize := []byte("invalid size")
|
|
_, err = pkcs7Unpad(invalidSize, blockSize)
|
|
require.Error(t, err)
|
|
})
|
|
}
|
|
|
|
func TestGetGlobalEncryptionService(t *testing.T) {
|
|
// Reset global key manager before test
|
|
globalKeyManager = nil
|
|
globalKeyManagerOnce = sync.Once{}
|
|
|
|
// Setup test environment
|
|
testEnvVar := DefaultKeyEnvVar
|
|
validKey := make([]byte, AES256KeySize)
|
|
for i := range validKey {
|
|
validKey[i] = byte(i % 256)
|
|
}
|
|
validKeyBase64 := base64.StdEncoding.EncodeToString(validKey)
|
|
|
|
// Set a valid key in environment
|
|
os.Setenv(testEnvVar, validKeyBase64)
|
|
t.Cleanup(func() {
|
|
os.Unsetenv(testEnvVar)
|
|
})
|
|
|
|
// Get global encryption service
|
|
service, err := GetGlobalEncryptionService()
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, service)
|
|
|
|
// Test with actual encryption/decryption
|
|
plaintext := "Test with global encryption service"
|
|
encrypted, err := service.EncryptString(plaintext)
|
|
require.NoError(t, err)
|
|
|
|
decrypted, err := service.DecryptString(encrypted)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, plaintext, decrypted)
|
|
}
|