refactor: Restructure crypt service and decouple from storage
This commit restructures the `crypt` service to be more modular and decoupled from storage concerns. - The standard cryptographic implementations (`lthn`, `chachapoly`, `rsa`) have been moved to the `pkg/crypt/std` directory. - The `rootfs` components have been removed to decouple the library from storage. - Import paths have been updated to reflect the new structure.
This commit is contained in:
parent
e21c910f91
commit
2ff894327b
14 changed files with 85 additions and 216 deletions
12
Taskfile.yml
Normal file
12
Taskfile.yml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
version: '3'
|
||||
|
||||
tasks:
|
||||
test:
|
||||
desc: "Run all tests"
|
||||
cmds:
|
||||
- go test -v ./...
|
||||
|
||||
build:
|
||||
desc: "Build the project"
|
||||
cmds:
|
||||
- go build -v ./...
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
package crypt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
payload := "hello"
|
||||
hash := Hash(LTHN, payload)
|
||||
assert.NotEmpty(t, hash)
|
||||
}
|
||||
|
||||
func TestLuhn(t *testing.T) {
|
||||
assert.True(t, Luhn("79927398713"))
|
||||
assert.False(t, Luhn("79927398714"))
|
||||
}
|
||||
|
||||
func TestFletcher16(t *testing.T) {
|
||||
assert.Equal(t, uint16(0xC8F0), Fletcher16("abcde"))
|
||||
assert.Equal(t, uint16(0x2057), Fletcher16("abcdef"))
|
||||
assert.Equal(t, uint16(0x0627), Fletcher16("abcdefgh"))
|
||||
}
|
||||
|
||||
func TestFletcher32(t *testing.T) {
|
||||
expected := uint32(0xF04FC729)
|
||||
actual := Fletcher32("abcde")
|
||||
fmt.Printf("Fletcher32('abcde'): expected: %x, actual: %x\n", expected, actual)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
expected = uint32(0x56502D2A)
|
||||
actual = Fletcher32("abcdef")
|
||||
fmt.Printf("Fletcher32('abcdef'): expected: %x, actual: %x\n", expected, actual)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
expected = uint32(0xEBE19591)
|
||||
actual = Fletcher32("abcdefgh")
|
||||
fmt.Printf("Fletcher32('abcdefgh'): expected: %x, actual: %x\n", expected, actual)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestFletcher64(t *testing.T) {
|
||||
assert.Equal(t, uint64(0xc8c6c527646362c6), Fletcher64("abcde"))
|
||||
assert.Equal(t, uint64(0xc8c72b276463c8c6), Fletcher64("abcdef"))
|
||||
assert.Equal(t, uint64(0x312e2b28cccac8c6), Fletcher64("abcdefgh"))
|
||||
}
|
||||
|
||||
func TestRootFS(t *testing.T) {
|
||||
tempDir, err := os.MkdirTemp("", "enchantrix-crypt-test")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
key := make([]byte, 32)
|
||||
for i := range key {
|
||||
key[i] = 1
|
||||
}
|
||||
|
||||
fs := NewRootFS(tempDir, key)
|
||||
err = fs.Write("test.txt", []byte("hello"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
data, err := fs.Read("test.txt")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte("hello"), data)
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/Snider/Enchantrix/chachapoly"
|
||||
"github.com/Snider/Enchantrix/pkg/crypt/std/chachapoly"
|
||||
"github.com/Snider/Enchantrix/trix"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,17 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Snider/Enchantrix/lthn"
|
||||
"github.com/Snider/Enchantrix/pkg/crypt/std/lthn"
|
||||
)
|
||||
|
||||
// Service is the main struct for the crypt service.
|
||||
type Service struct{}
|
||||
|
||||
// NewService creates a new crypt service.
|
||||
func NewService() *Service {
|
||||
return &Service{}
|
||||
}
|
||||
|
||||
// HashType defines the supported hashing algorithms.
|
||||
type HashType string
|
||||
|
||||
|
|
@ -27,7 +35,7 @@ const (
|
|||
// --- Hashing ---
|
||||
|
||||
// Hash computes a hash of the payload using the specified algorithm.
|
||||
func Hash(lib HashType, payload string) string {
|
||||
func (s *Service) Hash(lib HashType, payload string) string {
|
||||
switch lib {
|
||||
case LTHN:
|
||||
return lthn.Hash(payload)
|
||||
|
|
@ -51,7 +59,7 @@ func Hash(lib HashType, payload string) string {
|
|||
// --- Checksums ---
|
||||
|
||||
// Luhn validates a number using the Luhn algorithm.
|
||||
func Luhn(payload string) bool {
|
||||
func (s *Service) Luhn(payload string) bool {
|
||||
payload = strings.ReplaceAll(payload, " ", "")
|
||||
sum := 0
|
||||
isSecond := false
|
||||
|
|
@ -75,7 +83,7 @@ func Luhn(payload string) bool {
|
|||
}
|
||||
|
||||
// Fletcher16 computes the Fletcher-16 checksum.
|
||||
func Fletcher16(payload string) uint16 {
|
||||
func (s *Service) Fletcher16(payload string) uint16 {
|
||||
data := []byte(payload)
|
||||
var sum1, sum2 uint16
|
||||
for _, b := range data {
|
||||
|
|
@ -86,7 +94,7 @@ func Fletcher16(payload string) uint16 {
|
|||
}
|
||||
|
||||
// Fletcher32 computes the Fletcher-32 checksum.
|
||||
func Fletcher32(payload string) uint32 {
|
||||
func (s *Service) Fletcher32(payload string) uint32 {
|
||||
data := []byte(payload)
|
||||
if len(data)%2 != 0 {
|
||||
data = append(data, 0)
|
||||
|
|
@ -102,7 +110,7 @@ func Fletcher32(payload string) uint32 {
|
|||
}
|
||||
|
||||
// Fletcher64 computes the Fletcher-64 checksum.
|
||||
func Fletcher64(payload string) uint64 {
|
||||
func (s *Service) Fletcher64(payload string) uint64 {
|
||||
data := []byte(payload)
|
||||
if len(data)%4 != 0 {
|
||||
padding := 4 - (len(data) % 4)
|
||||
|
|
@ -127,7 +135,7 @@ func Fletcher64(payload string) uint64 {
|
|||
// import "github.com/Snider/Enchantrix/openpgp"
|
||||
//
|
||||
// // EncryptPGP encrypts data for a recipient, optionally signing it.
|
||||
// func EncryptPGP(writer io.Writer, recipientPath, data string, signerPath, signerPassphrase *string) error {
|
||||
// func (s *Service) EncryptPGP(writer io.Writer, recipientPath, data string, signerPath, signerPassphrase *string) error {
|
||||
// var buf bytes.Buffer
|
||||
// err := openpgp.EncryptPGP(&buf, recipientPath, data, signerPath, signerPassphrase)
|
||||
// if err != nil {
|
||||
|
|
@ -143,6 +151,6 @@ func Fletcher64(payload string) uint64 {
|
|||
// }
|
||||
//
|
||||
// // DecryptPGP decrypts a PGP message, optionally verifying the signature.
|
||||
// func DecryptPGP(recipientPath, message, passphrase string, signerPath *string) (string, error) {
|
||||
// func (s *Service) DecryptPGP(recipientPath, message, passphrase string, signerPath *string) (string, error) {
|
||||
// return openpgp.DecryptPGP(recipientPath, message, passphrase, signerPath)
|
||||
// }
|
||||
53
pkg/crypt/crypt_test.go
Normal file
53
pkg/crypt/crypt_test.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package crypt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
service := NewService()
|
||||
payload := "hello"
|
||||
hash := service.Hash(LTHN, payload)
|
||||
assert.NotEmpty(t, hash)
|
||||
}
|
||||
|
||||
func TestLuhn(t *testing.T) {
|
||||
service := NewService()
|
||||
assert.True(t, service.Luhn("79927398713"))
|
||||
assert.False(t, service.Luhn("79927398714"))
|
||||
}
|
||||
|
||||
func TestFletcher16(t *testing.T) {
|
||||
service := NewService()
|
||||
assert.Equal(t, uint16(0xC8F0), service.Fletcher16("abcde"))
|
||||
assert.Equal(t, uint16(0x2057), service.Fletcher16("abcdef"))
|
||||
assert.Equal(t, uint16(0x0627), service.Fletcher16("abcdefgh"))
|
||||
}
|
||||
|
||||
func TestFletcher32(t *testing.T) {
|
||||
service := NewService()
|
||||
expected := uint32(0xF04FC729)
|
||||
actual := service.Fletcher32("abcde")
|
||||
fmt.Printf("Fletcher32('abcde'): expected: %x, actual: %x\n", expected, actual)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
expected = uint32(0x56502D2A)
|
||||
actual = service.Fletcher32("abcdef")
|
||||
fmt.Printf("Fletcher32('abcdef'): expected: %x, actual: %x\n", expected, actual)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
expected = uint32(0xEBE19591)
|
||||
actual = service.Fletcher32("abcdefgh")
|
||||
fmt.Printf("Fletcher32('abcdefgh'): expected: %x, actual: %x\n", expected, actual)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestFletcher64(t *testing.T) {
|
||||
service := NewService()
|
||||
assert.Equal(t, uint64(0xc8c6c527646362c6), service.Fletcher64("abcde"))
|
||||
assert.Equal(t, uint64(0xc8c72b276463c8c6), service.Fletcher64("abcdef"))
|
||||
assert.Equal(t, uint64(0x312e2b28cccac8c6), service.Fletcher64("abcdefgh"))
|
||||
}
|
||||
3
pkg/crypt/std/rsa/rsa.go
Normal file
3
pkg/crypt/std/rsa/rsa.go
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
package rsa
|
||||
|
||||
// This file is a placeholder for RSA key handling functionality.
|
||||
11
rootfs.go
11
rootfs.go
|
|
@ -1,11 +0,0 @@
|
|||
package crypt
|
||||
|
||||
import "github.com/Snider/Enchantrix/rootfs"
|
||||
|
||||
// Storage is an alias for the rootfs.Storage interface.
|
||||
type Storage = rootfs.Storage
|
||||
|
||||
// NewRootFS creates a new encrypted passthrough storage system.
|
||||
func NewRootFS(root string, key []byte) Storage {
|
||||
return rootfs.NewLocalStorage(root, key)
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
package rootfs
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Snider/Enchantrix/chachapoly"
|
||||
)
|
||||
|
||||
// LocalStorage provides a passthrough storage system that encrypts data at rest.
|
||||
type LocalStorage struct {
|
||||
root string
|
||||
key []byte
|
||||
filePerm fs.FileMode
|
||||
dirPerm fs.FileMode
|
||||
}
|
||||
|
||||
// NewLocalStorage creates a new LocalStorage.
|
||||
func NewLocalStorage(root string, key []byte) *LocalStorage {
|
||||
return &LocalStorage{
|
||||
root: root,
|
||||
key: key,
|
||||
filePerm: 0644,
|
||||
dirPerm: 0755,
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads and decrypts the data for the given key.
|
||||
func (s *LocalStorage) Read(key string) ([]byte, error) {
|
||||
path := filepath.Join(s.root, key)
|
||||
ciphertext, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return chachapoly.Decrypt(ciphertext, s.key)
|
||||
}
|
||||
|
||||
// Write encrypts and writes the data for the given key.
|
||||
func (s *LocalStorage) Write(key string, data []byte) error {
|
||||
ciphertext, err := chachapoly.Encrypt(data, s.key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := filepath.Join(s.root, key)
|
||||
if err := os.MkdirAll(filepath.Dir(path), s.dirPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, ciphertext, s.filePerm)
|
||||
}
|
||||
|
||||
// Delete deletes the data for the given key.
|
||||
func (s *LocalStorage) Delete(key string) error {
|
||||
path := filepath.Join(s.root, key)
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// List lists the keys in the storage.
|
||||
func (s *LocalStorage) List(prefix string) ([]fs.FileInfo, error) {
|
||||
var files []fs.FileInfo
|
||||
err := filepath.Walk(filepath.Join(s.root, prefix), func(path string, info fs.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
files = append(files, info)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return files, err
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package rootfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLocalStorage(t *testing.T) {
|
||||
// Create a temporary directory for testing.
|
||||
tempDir, err := os.MkdirTemp("", "enchantrix-test")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Create a new LocalStorage instance.
|
||||
key := make([]byte, 32)
|
||||
for i := range key {
|
||||
key[i] = 1
|
||||
}
|
||||
storage := NewLocalStorage(tempDir, key)
|
||||
|
||||
// Test Write and Read.
|
||||
err = storage.Write("test.txt", []byte("hello"))
|
||||
assert.NoError(t, err)
|
||||
data, err := storage.Read("test.txt")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte("hello"), data)
|
||||
|
||||
// Test List.
|
||||
files, err := storage.List("")
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, files, 1)
|
||||
assert.Equal(t, "test.txt", files[0].Name())
|
||||
|
||||
// Test Delete.
|
||||
err = storage.Delete("test.txt")
|
||||
assert.NoError(t, err)
|
||||
_, err = os.Stat(filepath.Join(tempDir, "test.txt"))
|
||||
assert.True(t, os.IsNotExist(err))
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package rootfs
|
||||
|
||||
import "io/fs"
|
||||
|
||||
// Storage defines the interface for a passthrough storage system.
|
||||
type Storage interface {
|
||||
// Read reads the data for the given key.
|
||||
Read(key string) ([]byte, error)
|
||||
// Write writes the data for the given key.
|
||||
Write(key string, data []byte) error
|
||||
// Delete deletes the data for the given key.
|
||||
Delete(key string) error
|
||||
// List lists the keys in the storage.
|
||||
List(prefix string) ([]fs.FileInfo, error)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue