-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstegage.go
134 lines (101 loc) · 3.06 KB
/
stegage.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) 2021 The stegage developers
// Package stegage implements file encryption according to the age-encryption.org/v1
// specification, and also steganography of the encrypted file.
package stegage
import (
"bufio"
"bytes"
"fmt"
imagePkg "image"
"io"
// Supported formats
_ "image/jpeg"
_ "image/png"
"filippo.io/age"
"github.com/auyer/steganography"
)
// age_header_first_14 contains the first 14 bytes of a valid encrypted age
// file
const age_header_first_14 = "age-encryption"
// Encode encrypts data to the age password recipient and after that encodes
// with LSB steganography the encrypted payload in a copy of image.
//
// The resulting image format is png.
func Encode(password, data, image io.Reader, out io.Writer) error {
passBuf := new(bytes.Buffer)
passBuf.ReadFrom(password)
pass := passBuf.String()
encOut := new(bytes.Buffer)
r, err := age.NewScryptRecipient(pass)
if err != nil {
return fmt.Errorf("age: could no initialize password: %v", err)
}
w, err := age.Encrypt(encOut, r)
if err != nil {
return fmt.Errorf("age: Could not encrypt file: %v", err)
}
if _, err := io.Copy(w, data); err != nil {
return fmt.Errorf("stegage: Could not copy file: %v", err)
}
if err := w.Close(); err != nil {
return fmt.Errorf("age: Could not close file: %v", err)
}
encrypted := encOut.Bytes()
// Double check
if !isPayloadAge(encrypted) {
return fmt.Errorf("stegage: No encrypted payload")
}
img, _, err := imagePkg.Decode(image)
if err != nil {
return fmt.Errorf("image: could no decode image: %v", err)
}
imageOut := new(bytes.Buffer)
err = steganography.Encode(imageOut, img, encrypted)
if err != nil {
return fmt.Errorf("steganography: could no encode image: %v", err)
}
bufFile := bufio.NewWriter(out)
if _, err := io.Copy(bufFile, imageOut); err != nil {
return fmt.Errorf("stegage: Could not copy file: %v", err)
}
bufFile.Flush()
return nil
}
// Decode extracts the encrypted payload of a png image and decrypts the payload
// with the given password.
func Decode(password, image io.Reader, out io.Writer) error {
r := bufio.NewReader(image)
img, _, err := imagePkg.Decode(r)
if err != nil {
return fmt.Errorf("image: could no decode image: %v", err)
}
sizeOfMessage := steganography.GetMessageSizeFromImage(img)
msg := steganography.Decode(sizeOfMessage, img)
if !isPayloadAge(msg) {
return fmt.Errorf("stegage: found no encrypted age file inside image")
}
b := bytes.NewBuffer(msg)
passBuf := new(bytes.Buffer)
passBuf.ReadFrom(password)
pass := passBuf.String()
i, err := age.NewScryptIdentity(pass)
if err != nil {
return fmt.Errorf("age: could no initialize password: %v", err)
}
decOut, err := age.Decrypt(b, i)
if err != nil {
return fmt.Errorf("age: could no decrypt data: %v", err)
}
outBuf := bufio.NewWriter(out)
if _, err := io.Copy(outBuf, decOut); err != nil {
return fmt.Errorf("stegage: Could not copy file: %v", err)
}
outBuf.Flush()
return nil
}
func isPayloadAge(payload []byte) bool {
if string(payload[:14]) != age_header_first_14 {
return false
}
return true
}