Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions pkg/crypt/crypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import (
)

// Service is the main struct for the crypt service.
// It provides methods for hashing, checksums, and encryption.
type Service struct {
rsa *rsa.Service
pgp *pgp.Service
}

// NewService creates a new crypt Service and initialises its embedded services.
// It returns a new Service.
func NewService() *Service {
return &Service{
rsa: rsa.NewService(),
Expand All @@ -34,11 +36,16 @@ func NewService() *Service {
type HashType string

const (
LTHN HashType = "lthn"
// LTHN is a custom quasi-salted hashing algorithm.
LTHN HashType = "lthn"
// SHA512 is the SHA-512 hashing algorithm.
SHA512 HashType = "sha512"
// SHA256 is the SHA-256 hashing algorithm.
SHA256 HashType = "sha256"
SHA1 HashType = "sha1"
MD5 HashType = "md5"
// SHA1 is the SHA-1 hashing algorithm.
SHA1 HashType = "sha1"
// MD5 is the MD5 hashing algorithm.
MD5 HashType = "md5"
)

// --- Hashing ---
Expand All @@ -54,6 +61,7 @@ func (s *Service) IsHashAlgo(algo string) bool {
}

// Hash computes a hash of the payload using the specified algorithm.
// It returns the hash as a hex-encoded string.
func (s *Service) Hash(lib HashType, payload string) string {
switch lib {
case LTHN:
Expand All @@ -78,6 +86,7 @@ func (s *Service) Hash(lib HashType, payload string) string {
// --- Checksums ---

// Luhn validates a number using the Luhn algorithm.
// It is typically used to validate credit card numbers.
func (s *Service) Luhn(payload string) bool {
payload = strings.ReplaceAll(payload, " ", "")
if len(payload) <= 1 {
Expand Down Expand Up @@ -106,6 +115,7 @@ func (s *Service) Luhn(payload string) bool {
}

// Fletcher16 computes the Fletcher-16 checksum.
// It is a fast checksum algorithm that is more reliable than a simple sum.
func (s *Service) Fletcher16(payload string) uint16 {
data := []byte(payload)
var sum1, sum2 uint16
Expand All @@ -117,6 +127,7 @@ func (s *Service) Fletcher16(payload string) uint16 {
}

// Fletcher32 computes the Fletcher-32 checksum.
// It provides better error detection than Fletcher-16.
func (s *Service) Fletcher32(payload string) uint32 {
data := []byte(payload)
if len(data)%2 != 0 {
Expand All @@ -133,6 +144,7 @@ func (s *Service) Fletcher32(payload string) uint32 {
}

// Fletcher64 computes the Fletcher-64 checksum.
// It provides the best error detection of the Fletcher algorithms.
func (s *Service) Fletcher64(payload string) uint64 {
data := []byte(payload)
if len(data)%4 != 0 {
Expand Down Expand Up @@ -186,36 +198,42 @@ func (s *Service) ensurePGP() {
}

// GeneratePGPKeyPair creates a new PGP key pair.
// It returns the public and private keys in PEM format.
func (s *Service) GeneratePGPKeyPair(name, email, comment string) (publicKey, privateKey []byte, err error) {
s.ensurePGP()
return s.pgp.GenerateKeyPair(name, email, comment)
}

// EncryptPGP encrypts data with a public key.
// It returns the encrypted data.
func (s *Service) EncryptPGP(publicKey, data []byte) ([]byte, error) {
s.ensurePGP()
return s.pgp.Encrypt(publicKey, data)
}

// DecryptPGP decrypts data with a private key.
// It returns the decrypted data.
func (s *Service) DecryptPGP(privateKey, ciphertext []byte) ([]byte, error) {
s.ensurePGP()
return s.pgp.Decrypt(privateKey, ciphertext)
}

// SignPGP creates a detached signature for a message.
// It returns the signature.
func (s *Service) SignPGP(privateKey, data []byte) ([]byte, error) {
s.ensurePGP()
return s.pgp.Sign(privateKey, data)
}

// VerifyPGP verifies a detached signature for a message.
// It returns an error if the signature is invalid.
func (s *Service) VerifyPGP(publicKey, data, signature []byte) error {
s.ensurePGP()
return s.pgp.Verify(publicKey, data, signature)
}

// SymmetricallyEncryptPGP encrypts data with a passphrase.
// It returns the encrypted data.
func (s *Service) SymmetricallyEncryptPGP(passphrase, data []byte) ([]byte, error) {
s.ensurePGP()
if len(passphrase) == 0 {
Expand Down
170 changes: 170 additions & 0 deletions pkg/crypt/examples_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package crypt_test

import (
"fmt"
"log"

"github.com/Snider/Enchantrix/pkg/crypt"
)

func ExampleService_Hash() {
cryptService := crypt.NewService()
payload := "Enchantrix"

hashTypes := []crypt.HashType{
crypt.LTHN,
crypt.MD5,
crypt.SHA1,
crypt.SHA256,
crypt.SHA512,
}

fmt.Printf("Payload to hash: \"%s\"\n", payload)
for _, hashType := range hashTypes {
hash := cryptService.Hash(hashType, payload)
fmt.Printf(" - %-6s: %s\n", hashType, hash)
}
// Output:
// Payload to hash: "Enchantrix"
// - lthn : 331f24f86375846ac8d0d06cfb80cb2877e8900548a88d4ac8d39177cd854dab
// - md5 : 7c54903a10f058a93fd1f21ea802cb27
// - sha1 : 399f776c4b97e558a2c4f319b223dd481c6d43f1
// - sha256: 2ae653f74554abfdb2343013925f5184a0f05e4c2e0c3881448fc80caeb667c2
// - sha512: 9638018a9720b5d83fba7f3899e4ba5ab78018781f9c600f0c0738ff8ccf1ea54e1c783ee8778542b70aa26283d87ce88784b2df5697322546d3b8029c4b6797
}

func ExampleService_Luhn() {
cryptService := crypt.NewService()
luhnPayloadGood := "49927398716"
luhnPayloadBad := "49927398717"
fmt.Printf("Luhn Checksum:\n")
fmt.Printf(" - Payload '%s' is valid: %v\n", luhnPayloadGood, cryptService.Luhn(luhnPayloadGood))
fmt.Printf(" - Payload '%s' is valid: %v\n", luhnPayloadBad, cryptService.Luhn(luhnPayloadBad))
// Output:
// Luhn Checksum:
// - Payload '49927398716' is valid: true
// - Payload '49927398717' is valid: false
}

func ExampleService_Fletcher16() {
cryptService := crypt.NewService()
fletcherPayload := "abcde"
fmt.Printf("Fletcher16 Checksum (Payload: \"%s\"): %d\n", fletcherPayload, cryptService.Fletcher16(fletcherPayload))
// Output:
// Fletcher16 Checksum (Payload: "abcde"): 51440
}

func ExampleService_Fletcher32() {
cryptService := crypt.NewService()
fletcherPayload := "abcde"
fmt.Printf("Fletcher32 Checksum (Payload: \"%s\"): %d\n", fletcherPayload, cryptService.Fletcher32(fletcherPayload))
// Output:
// Fletcher32 Checksum (Payload: "abcde"): 4031760169
}

func ExampleService_Fletcher64() {
cryptService := crypt.NewService()
fletcherPayload := "abcde"
fmt.Printf("Fletcher64 Checksum (Payload: \"%s\"): %d\n", fletcherPayload, cryptService.Fletcher64(fletcherPayload))
// Output:
// Fletcher64 Checksum (Payload: "abcde"): 14467467625952928454
}

func ExampleService_GeneratePGPKeyPair() {
cryptService := crypt.NewService()
publicKey, privateKey, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key")
if err != nil {
log.Fatalf("Failed to generate PGP key pair: %v", err)
}
fmt.Printf("PGP public key is not empty: %v\n", len(publicKey) > 0)
fmt.Printf("PGP private key is not empty: %v\n", len(privateKey) > 0)
// Output:
// PGP public key is not empty: true
// PGP private key is not empty: true
}

func ExampleService_EncryptPGP() {
cryptService := crypt.NewService()
publicKey, _, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key")
if err != nil {
log.Fatalf("Failed to generate PGP key pair: %v", err)
}
message := []byte("This is a secret message for PGP.")
ciphertext, err := cryptService.EncryptPGP(publicKey, message)
if err != nil {
log.Fatalf("Failed to encrypt with PGP: %v", err)
}
fmt.Printf("PGP ciphertext is not empty: %v\n", len(ciphertext) > 0)
// Output:
// PGP ciphertext is not empty: true
}

func ExampleService_DecryptPGP() {
cryptService := crypt.NewService()
publicKey, privateKey, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key")
if err != nil {
log.Fatalf("Failed to generate PGP key pair: %v", err)
}
message := []byte("This is a secret message for PGP.")
ciphertext, err := cryptService.EncryptPGP(publicKey, message)
if err != nil {
log.Fatalf("Failed to encrypt with PGP: %v", err)
}
decrypted, err := cryptService.DecryptPGP(privateKey, ciphertext)
if err != nil {
log.Fatalf("Failed to decrypt with PGP: %v", err)
}
fmt.Printf("Decrypted message: %s\n", decrypted)
// Output:
// Decrypted message: This is a secret message for PGP.
}

func ExampleService_SignPGP() {
cryptService := crypt.NewService()
_, privateKey, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key")
if err != nil {
log.Fatalf("Failed to generate PGP key pair: %v", err)
}
message := []byte("This is a message to be signed.")
signature, err := cryptService.SignPGP(privateKey, message)
if err != nil {
log.Fatalf("Failed to sign with PGP: %v", err)
}
fmt.Printf("PGP signature is not empty: %v\n", len(signature) > 0)
// Output:
// PGP signature is not empty: true
}

func ExampleService_VerifyPGP() {
cryptService := crypt.NewService()
publicKey, privateKey, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key")
if err != nil {
log.Fatalf("Failed to generate PGP key pair: %v", err)
}
message := []byte("This is a message to be signed.")
signature, err := cryptService.SignPGP(privateKey, message)
if err != nil {
log.Fatalf("Failed to sign with PGP: %v", err)
}
err = cryptService.VerifyPGP(publicKey, message, signature)
if err != nil {
fmt.Println("PGP signature verification failed.")
} else {
fmt.Println("PGP signature verified successfully.")
}
// Output:
// PGP signature verified successfully.
}

func ExampleService_SymmetricallyEncryptPGP() {
cryptService := crypt.NewService()
passphrase := []byte("my secret passphrase")
message := []byte("This is a symmetric secret.")
ciphertext, err := cryptService.SymmetricallyEncryptPGP(passphrase, message)
if err != nil {
log.Fatalf("Failed to symmetrically encrypt with PGP: %v", err)
}
fmt.Printf("Symmetric PGP ciphertext is not empty: %v\n", len(ciphertext) > 0)
// Output:
// Symmetric PGP ciphertext is not empty: true
}
3 changes: 3 additions & 0 deletions pkg/enchantrix/enchantrix.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package enchantrix

// Sigil defines the interface for a data transformer.
// A Sigil is a reversible or irreversible transformation of a byte slice.
type Sigil interface {
// In transforms the data.
In(data []byte) ([]byte, error)
// Out reverses the transformation.
Out(data []byte) ([]byte, error)
}

Expand Down
44 changes: 44 additions & 0 deletions pkg/enchantrix/examples_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package enchantrix_test

import (
"fmt"
"log"

"github.com/Snider/Enchantrix/pkg/enchantrix"
)

func ExampleTransmute() {
data := []byte("Hello, World!")
sigils := []enchantrix.Sigil{
&enchantrix.ReverseSigil{},
&enchantrix.HexSigil{},
}
transformed, err := enchantrix.Transmute(data, sigils)
if err != nil {
log.Fatalf("Transmute failed: %v", err)
}
fmt.Printf("Transformed data: %s\n", transformed)
// Output:
// Transformed data: 21646c726f57202c6f6c6c6548
}

func ExampleNewSigil() {
sigil, err := enchantrix.NewSigil("base64")
if err != nil {
log.Fatalf("Failed to create sigil: %v", err)
}
data := []byte("Hello, World!")
encoded, err := sigil.In(data)
if err != nil {
log.Fatalf("Sigil In failed: %v", err)
}
fmt.Printf("Encoded data: %s\n", encoded)
decoded, err := sigil.Out(encoded)
if err != nil {
log.Fatalf("Sigil Out failed: %v", err)
}
fmt.Printf("Decoded data: %s\n", decoded)
// Output:
// Encoded data: SGVsbG8sIFdvcmxkIQ==
// Decoded data: Hello, World!
}
Loading