Files
live-stego-experiments/stego-client/decode.go
2025-05-22 17:22:27 +02:00

130 lines
2.6 KiB
Go

package main
import (
"bufio"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
"image"
"log"
"os"
"github.com/auyer/steganography"
"github.com/chai2010/webp"
"gopkg.in/yaml.v3"
)
type DecodeConfig struct {
Security struct {
AESKey string `yaml:"aes_key"` // Base64 encoded 32-byte key
} `yaml:"security"`
}
var (
aesKey []byte
cfg DecodeConfig
)
func loadDecodeConfig(filename string) error {
data, err := os.ReadFile(filename)
if err != nil {
return fmt.Errorf("config file read error: %w", err)
}
if err := yaml.Unmarshal(data, &cfg); err != nil {
return fmt.Errorf("config parse error: %w", err)
}
return nil
}
func decryptData(ciphertext []byte) ([]byte, error) {
block, err := aes.NewCipher(aesKey)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, fmt.Errorf("ciphertext too short")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
return gcm.Open(nil, nonce, ciphertext, nil)
}
func decodeImage(file *os.File) (image.Image, error) {
reader := bufio.NewReader(file)
// Try to decode with image.Decode first
img, _, err := image.Decode(reader)
if err == nil {
return img, nil
}
// Try fallback: WebP
// Reset file offset to 0
_, _ = file.Seek(0, 0)
img, err = webp.Decode(file)
if err != nil {
return nil, fmt.Errorf("unsupported image format or decode failure: %w", err)
}
return img, nil
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run decode.go <encoded_image>")
return
}
if err := loadDecodeConfig("config.yaml"); err != nil {
log.Fatalf("Failed to load config: %v", err)
}
filePath := os.Args[1]
inFile, err := os.Open(filePath)
if err != nil {
fmt.Printf("Failed to open file: %v\n", err)
return
}
defer inFile.Close()
// Initialize AES key
if cfg.Security.AESKey != "" {
aesKey, err = base64.StdEncoding.DecodeString(cfg.Security.AESKey)
if err != nil {
log.Fatalf("Invalid AES key in config: %v", err)
}
} else {
log.Fatal("AES key not provided in config.")
}
img, err := decodeImage(inFile)
if err != nil {
fmt.Printf("Failed to decode image: %v\n", err)
return
}
size := steganography.GetMessageSizeFromImage(img)
message := steganography.Decode(size, img)
if message == nil {
fmt.Println("No message found in the image.")
return
}
decryptedMessage, err := decryptData(message)
if err != nil {
fmt.Printf("Failed to decrypt message: %v\n", err)
return
}
fmt.Printf("Decrypted message: %s\n", decryptedMessage)
}