-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
258 lines (216 loc) · 5.92 KB
/
main.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"image"
_ "image/gif"
_ "image/jpeg"
"image/png"
_ "image/png"
"io"
"log"
"strconv"
"strings"
"syscall/js"
"github.com/auyer/steganography"
)
var debuging bool = true
func compressLZW(testStr string) []int {
code := 256
dictionary := make(map[string]int)
for i := 0; i < 256; i++ {
dictionary[string(rune(i))] = i
}
currChar := ""
result := make([]int, 0)
for _, c := range []byte(testStr) {
phrase := currChar + string(c)
if _, isTrue := dictionary[phrase]; isTrue {
currChar = phrase
} else {
result = append(result, dictionary[currChar])
dictionary[phrase] = code
code++
currChar = string(c)
}
}
if currChar != "" {
result = append(result, dictionary[currChar])
}
return result
}
func decompressLZW(compressed []int) string {
code := 256
dictionary := make(map[int]string)
for i := 0; i < 256; i++ {
dictionary[i] = string(i)
}
currChar := string(compressed[0])
result := currChar
for _, element := range compressed[1:] {
var word string
if x, ok := dictionary[element]; ok {
word = x
} else if element == code {
word = currChar + currChar[:1]
} else {
panic(fmt.Sprintf("Bad compressed element: %d", element))
}
result += word
dictionary[code] = currChar + word[:1]
code++
currChar = word
}
return result
}
func Encrypt(plaintext []byte, key []byte) (ciphertext []byte, err error) {
k := sha256.Sum256(key)
block, err := aes.NewCipher(k[:])
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
_, err = io.ReadFull(rand.Reader, nonce)
if err != nil {
return nil, err
}
return gcm.Seal(nonce, nonce, plaintext, nil), nil
}
// Decrypt decrypts data using 256-bit AES-GCM. This both hides the content of
// the data and provides a check that it hasn't been altered. Expects input
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Decrypt(ciphertext []byte, key []byte) (plaintext []byte, err error) {
k := sha256.Sum256(key)
block, err := aes.NewCipher(k[:])
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(ciphertext) < gcm.NonceSize() {
return nil, errors.New("malformed ciphertext")
}
return gcm.Open(nil,
ciphertext[:gcm.NonceSize()],
ciphertext[gcm.NonceSize():],
nil,
)
}
func imgArrToGoImage(imgArr js.Value) (image.Image, error) {
imgBuff := make([]uint8, imgArr.Get("byteLength").Int()) // creating a uint buffer to store js image array
js.CopyBytesToGo(imgBuff, imgArr) // copies bytes from src(imgArr) to dst(imgBuff)
img, _, err := image.Decode(bytes.NewReader(imgBuff))
if err != nil {
return nil, err
}
return img, nil
}
func imageEncode(this js.Value, i []js.Value) interface{} {
imgArr := i[0] // image arr from frontend
img, _ := imgArrToGoImage(imgArr)
w := new(bytes.Buffer) // buffer that will recieve the results from stegno
mssg := (i[1].String()) // user message from front end
if debuging {
fmt.Println("mssg = ")
fmt.Println(mssg)
}
// compressing the data using LZW o/p is int[]
compressedData := compressLZW(mssg)
if debuging == true {
fmt.Println("compressed data")
fmt.Println(compressedData)
}
// cnverting int[] to string to encrypt
stringData := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(compressedData)), ","), "[]")
key := []byte(i[2].String()) //coverting password to byte[]
ct, err := Encrypt([]byte(stringData), key) // encrypting the message with the providede password
if err != nil {
panic(err)
}
if debuging {
fmt.Println("EncryptText :")
fmt.Println(base64.StdEncoding.EncodeToString(ct))
}
errImg := steganography.Encode(w, img, []byte(ct))
if errImg != nil {
log.Printf("Error Encoding file %v", err)
return ""
}
oi, _ := png.Decode(w)
var buff bytes.Buffer
png.Encode(&buff, oi)
encodeString := base64.StdEncoding.EncodeToString(buff.Bytes())
return js.ValueOf(encodeString)
}
func imageDecode(this js.Value, i []js.Value) interface{} {
imgArr := i[0] // image arr from frontend
img, _ := imgArrToGoImage(imgArr)
// img, _ = png.Decode(imgBuff)
password := i[1].String() // password from frontend and converting it into string so go can understand
// gets the size of the message from the first four bytes encoded in the image
sizeOfMessage := steganography.GetMessageSizeFromImage(img)
if debuging {
fmt.Print("sizeOfMessage = ")
fmt.Println(sizeOfMessage)
}
msg := steganography.Decode(sizeOfMessage, img) // decoding the message from the file
if debuging {
fmt.Println("extracted encrypted msg from image")
fmt.Println(base64.StdEncoding.EncodeToString(msg))
}
pt, err := Decrypt(msg, []byte(password))
if err != nil {
panic(err)
}
if debuging {
fmt.Println("DecryptedText : ")
fmt.Println(base64.StdEncoding.DecodeString(string(msg)))
}
// after decryption we get compressed data in one stringseparated by ','
// converting string to string arr[] on ","
strArryData := strings.Split(string(pt), ",")
var LZWIntData = []int{}
if debuging {
fmt.Println("strArryData")
fmt.Println(strArryData)
}
// string num array to int[]
for _, i := range strArryData {
j, err := strconv.Atoi(i)
if err != nil {
panic(err)
}
LZWIntData = append(LZWIntData, j)
}
decompressedData := decompressLZW(LZWIntData)
fmt.Println("decompressedData")
fmt.Println(decompressedData)
fmt.Println(password)
return js.ValueOf(string(decompressedData))
}
// exposing to JS
func registerCallbacks() {
js.Global().Set("imageEncode", js.FuncOf(imageEncode))
js.Global().Set("imageDecode", js.FuncOf(imageDecode))
}
func main() {
c := make(chan struct{}, 0)
println("WASM Go Initialized")
// register functions
registerCallbacks()
// to stop go from closing
<-c
}
// GOARCH=wasm GOOS=js go build -o lib.wasm main.go