Merge pull request #14 from Snider/feat-refactor-crypt-service
feat: Implement Pre-Encryption Sigil Packing for Enhanced Security
This commit is contained in:
commit
3268e4a6e7
3 changed files with 80 additions and 71 deletions
|
|
@ -11,84 +11,78 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
// 1. Original plaintext
|
||||
// 1. Original plaintext and encryption key
|
||||
plaintext := []byte("This is a super secret message!")
|
||||
key := make([]byte, 32) // In a real application, use a secure key
|
||||
for i := range key {
|
||||
key[i] = 1
|
||||
}
|
||||
|
||||
// 2. Encrypt the data using the chachapoly package
|
||||
// The ciphertext from chachapoly includes the nonce.
|
||||
ciphertext, err := chachapoly.Encrypt(plaintext, key)
|
||||
// 2. Create a Trix container with the plaintext and attach sigils
|
||||
trixContainer := &trix.Trix{
|
||||
Header: map[string]interface{}{},
|
||||
Payload: plaintext,
|
||||
Sigils: []trix.Sigil{&trix.ReverseSigil{}},
|
||||
}
|
||||
|
||||
// 3. Pack the Trix container to apply the sigil transformations
|
||||
if err := trixContainer.Pack(); err != nil {
|
||||
log.Fatalf("Failed to pack trix container: %v", err)
|
||||
}
|
||||
fmt.Printf("Packed (obfuscated) payload: %x\n", trixContainer.Payload)
|
||||
|
||||
|
||||
// 4. Encrypt the packed payload
|
||||
ciphertext, err := chachapoly.Encrypt(trixContainer.Payload, key)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to encrypt: %v", err)
|
||||
}
|
||||
trixContainer.Payload = ciphertext // Update the payload with the ciphertext
|
||||
|
||||
// For the .trix header, we need to separate the nonce from the ciphertext.
|
||||
// chacha20poly1305.NewX nonce size is 24 bytes.
|
||||
// 5. Add encryption metadata to the header
|
||||
nonce := ciphertext[:24]
|
||||
actualCiphertext := ciphertext[24:]
|
||||
|
||||
// 3. Create a .trix container for the encrypted data
|
||||
header := map[string]interface{}{
|
||||
trixContainer.Header = map[string]interface{}{
|
||||
"content_type": "application/octet-stream",
|
||||
"encryption_algorithm": "chacha20poly1305",
|
||||
"nonce": base64.StdEncoding.EncodeToString(nonce),
|
||||
"created_at": time.Now().UTC().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
trixContainer := &trix.Trix{
|
||||
Header: header,
|
||||
Payload: actualCiphertext,
|
||||
Sigils: []trix.Sigil{&trix.ReverseSigil{}},
|
||||
}
|
||||
|
||||
// 4. Encode the .trix container into its binary format
|
||||
magicNumber := "MyT1" // My Trix 1
|
||||
// 6. Encode the .trix container into its binary format
|
||||
magicNumber := "MyT1"
|
||||
encodedTrix, err := trix.Encode(trixContainer, magicNumber)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to encode .trix container: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully created .trix container.")
|
||||
|
||||
// 5. Decode the .trix container to retrieve the encrypted data
|
||||
// --- DECODING ---
|
||||
|
||||
// 7. Decode the .trix container
|
||||
decodedTrix, err := trix.Decode(encodedTrix, magicNumber)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to decode .trix container: %v", err)
|
||||
}
|
||||
|
||||
// Manually apply the Out method of the sigil to restore the original payload.
|
||||
restoredPayload, err := trixContainer.Sigils[0].Out(decodedTrix.Payload)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to apply sigil: %v", err)
|
||||
}
|
||||
decodedTrix.Payload = restoredPayload
|
||||
|
||||
// 6. Reassemble the ciphertext (nonce + payload) and decrypt
|
||||
retrievedNonceStr, ok := decodedTrix.Header["nonce"].(string)
|
||||
if !ok {
|
||||
log.Fatalf("Nonce not found or not a string in header")
|
||||
}
|
||||
retrievedNonce, err := base64.StdEncoding.DecodeString(retrievedNonceStr)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to decode nonce: %v", err)
|
||||
}
|
||||
retrievedCiphertext := append(retrievedNonce, decodedTrix.Payload...)
|
||||
|
||||
decrypted, err := chachapoly.Decrypt(retrievedCiphertext, key)
|
||||
// 8. Decrypt the payload
|
||||
decryptedPayload, err := chachapoly.Decrypt(decodedTrix.Payload, key)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to decrypt: %v", err)
|
||||
}
|
||||
decodedTrix.Payload = decryptedPayload
|
||||
|
||||
// 7. Verify the result
|
||||
fmt.Printf("Original plaintext: %s\n", plaintext)
|
||||
fmt.Printf("Decrypted plaintext: %s\n", decrypted)
|
||||
// 9. Unpack the Trix container to reverse the sigil transformations
|
||||
decodedTrix.Sigils = trixContainer.Sigils // Re-attach sigils
|
||||
if err := decodedTrix.Unpack(); err != nil {
|
||||
log.Fatalf("Failed to unpack trix container: %v", err)
|
||||
}
|
||||
fmt.Printf("Unpacked (original) payload: %s\n", decodedTrix.Payload)
|
||||
|
||||
if string(plaintext) == string(decrypted) {
|
||||
fmt.Println("\nSuccess! The message was decrypted correctly.")
|
||||
// 10. Verify the result
|
||||
if string(plaintext) == string(decodedTrix.Payload) {
|
||||
fmt.Println("\nSuccess! The message was decrypted and unpacked correctly.")
|
||||
} else {
|
||||
fmt.Println("\nFailure! The decrypted message does not match the original.")
|
||||
fmt.Println("\nFailure! The final payload does not match the original.")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,19 +39,6 @@ func Encode(trix *Trix, magicNumber string) ([]byte, error) {
|
|||
return nil, ErrMagicNumberLength
|
||||
}
|
||||
|
||||
// Apply sigils to the payload before encoding
|
||||
payload := trix.Payload
|
||||
for _, sigil := range trix.Sigils {
|
||||
if sigil == nil {
|
||||
return nil, ErrNilSigil
|
||||
}
|
||||
var err error
|
||||
payload, err = sigil.In(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
headerBytes, err := json.Marshal(trix.Header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -81,7 +68,7 @@ func Encode(trix *Trix, magicNumber string) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Write Payload
|
||||
if _, err := buf.Write(payload); err != nil {
|
||||
if _, err := buf.Write(trix.Payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -143,6 +130,37 @@ func Decode(data []byte, magicNumber string) (*Trix, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Pack applies the In method of all attached sigils to the payload.
|
||||
func (t *Trix) Pack() error {
|
||||
for _, sigil := range t.Sigils {
|
||||
if sigil == nil {
|
||||
return ErrNilSigil
|
||||
}
|
||||
var err error
|
||||
t.Payload, err = sigil.In(t.Payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unpack applies the Out method of all sigils in reverse order.
|
||||
func (t *Trix) Unpack() error {
|
||||
for i := len(t.Sigils) - 1; i >= 0; i-- {
|
||||
sigil := t.Sigils[i]
|
||||
if sigil == nil {
|
||||
return ErrNilSigil
|
||||
}
|
||||
var err error
|
||||
t.Payload, err = sigil.Out(t.Payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReverseSigil is an example Sigil that reverses the bytes of the payload.
|
||||
type ReverseSigil struct{}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,27 +127,24 @@ func (s *FailingSigil) Out(data []byte) ([]byte, error) {
|
|||
return nil, s.err
|
||||
}
|
||||
|
||||
func TestSigilPipeline_Good(t *testing.T) {
|
||||
func TestPackUnpack_Good(t *testing.T) {
|
||||
originalPayload := []byte("hello world")
|
||||
trix := &Trix{
|
||||
Header: map[string]interface{}{},
|
||||
Payload: originalPayload,
|
||||
Sigils: []Sigil{&ReverseSigil{}},
|
||||
Sigils: []Sigil{&ReverseSigil{}, &ReverseSigil{}}, // Double reverse should be original
|
||||
}
|
||||
|
||||
encoded, err := Encode(trix, "SIGL")
|
||||
err := trix.Pack()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, originalPayload, trix.Payload) // Should be back to the original
|
||||
|
||||
decoded, err := Decode(encoded, "SIGL")
|
||||
err = trix.Unpack()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Manually apply the Out method to restore the original payload.
|
||||
restoredPayload, err := trix.Sigils[0].Out(decoded.Payload)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, originalPayload, restoredPayload)
|
||||
assert.Equal(t, originalPayload, trix.Payload) // Should be back to the original again
|
||||
}
|
||||
|
||||
func TestSigilPipeline_Bad(t *testing.T) {
|
||||
func TestPackUnpack_Bad(t *testing.T) {
|
||||
expectedErr := errors.New("sigil failed")
|
||||
trix := &Trix{
|
||||
Header: map[string]interface{}{},
|
||||
|
|
@ -155,12 +152,12 @@ func TestSigilPipeline_Bad(t *testing.T) {
|
|||
Sigils: []Sigil{&ReverseSigil{}, &FailingSigil{err: expectedErr}},
|
||||
}
|
||||
|
||||
_, err := Encode(trix, "FAIL")
|
||||
err := trix.Pack()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, expectedErr, err)
|
||||
}
|
||||
|
||||
func TestSigilPipeline_Ugly(t *testing.T) {
|
||||
func TestPackUnpack_Ugly(t *testing.T) {
|
||||
t.Run("NilSigil", func(t *testing.T) {
|
||||
trix := &Trix{
|
||||
Header: map[string]interface{}{},
|
||||
|
|
@ -168,7 +165,7 @@ func TestSigilPipeline_Ugly(t *testing.T) {
|
|||
Sigils: []Sigil{nil},
|
||||
}
|
||||
|
||||
_, err := Encode(trix, "UGLY")
|
||||
err := trix.Pack()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, ErrNilSigil, err)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue