-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunctions.go
213 lines (170 loc) · 6.59 KB
/
functions.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
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/gotk3/gotk3/gtk"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
// Check for errors.
func check(e error) {
if e != nil {
log.Fatal(e)
panic(e)
}
}
// Handle updating status label.
func updatestatus(statustext string, statuslabel *gtk.Label) {
statuslabel.SetText(statustext)
for gtk.EventsPending() {
gtk.MainIteration()
}
}
// Handle encrypting files.
func encryptfile(filename string, s string, progressbar *gtk.ProgressBar, statuslabel *gtk.Label, hintlabel *gtk.Label, image *gtk.Image) {
// Check if user pressed cancel button.
if filename == "" {
return
}
// Update progress bar.
progressbar.SetFraction(0.0)
image.SetFromFile("./Assets/working2.gif")
// Get basename and remove extension.
basename := filepath.Base(filename)
name := strings.TrimSuffix(basename, filepath.Ext(basename))
// Make a temporary zip file.
updatestatus("Status: Compressing...", statuslabel)
fi, err := os.Stat(filename)
var cmd *exec.Cmd
check(err)
switch mode := fi.Mode(); {
case mode.IsDir():
cmd = exec.Command("zip", "-j", "-r", "nekotemp.zip", filename)
case mode.IsRegular():
cmd = exec.Command("zip", "-j", "nekotemp.zip", filename)
}
cmd.Run()
// Update progress bar.
progressbar.SetFraction(0.4)
// Read temporary zip file bytes.
dat, _ := ioutil.ReadFile("nekotemp.zip")
// Create key hash from password.
updatestatus("Status: Generating key hash...", statuslabel)
h := sha256.New()
h.Write([]byte(s))
// Update progress bar.
progressbar.SetFraction(0.5)
// Convert key to string.
key := hex.EncodeToString(h.Sum(nil))
// Encrypt data.
updatestatus("Status: Encrypting...", statuslabel)
encrypted := encrypt(dat, key)
// Write output data to file.
updatestatus("Status: Writing output to file...", statuslabel)
f, err := os.OpenFile(filepath.Dir(filename)+"/"+name+".neko", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
check(err)
defer f.Close()
f.WriteString(encrypted)
// Delete temporary zip file.
updatestatus("Status: Cleaning up...", statuslabel)
os.Remove("nekotemp.zip")
// Update progress bar.
progressbar.SetFraction(1.0)
updatestatus("Status: Done", statuslabel)
hintlabel.SetText("The file/folder was successfully encrypted.")
image.SetFromFile("./Assets/success.gif")
}
// Handle decrypting files.
func decryptfile(filename string, s string, progressbar *gtk.ProgressBar, statuslabel *gtk.Label, hintlabel *gtk.Label, image *gtk.Image) {
// Check if user pressed cancel button.
if filename == "" {
return
}
// Update progress bar.
progressbar.SetFraction(0.0)
image.SetFromFile("./Assets/working2.gif")
// Read input file bytes.
updatestatus("Status: Reading file to decrypt...", statuslabel)
dat, _ := ioutil.ReadFile(filename)
// Update progress bar.
progressbar.SetFraction(0.1)
// Create key hash from password.
updatestatus("Status: Generating key hash...", statuslabel)
h := sha256.New()
h.Write([]byte(s))
// Update progress bar.
progressbar.SetFraction(0.4)
// Convert key to string.
key := hex.EncodeToString(h.Sum(nil))
// Decrypt data.
updatestatus("Status: Decrypting...", statuslabel)
decrypted := decrypt(dat, key)
// Write data to temporary zip file.
updatestatus("Status: Writing output to temporary file...", statuslabel)
f, err := os.OpenFile("nekotemp.zip", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
check(err)
defer f.Close()
f.WriteString(decrypted)
// Update progress bar.
progressbar.SetFraction(0.5)
// Unzip temporary zip file into directory of input file.
updatestatus("Status: Decompressing...", statuslabel)
cmd := exec.Command("unzip", "nekotemp.zip", "-d", filepath.Dir(filename))
cmd.Run()
// Delete temporary zip file.
updatestatus("Status: Cleaning up...", statuslabel)
os.Remove("nekotemp.zip")
// Update progress bar.
progressbar.SetFraction(1.0)
updatestatus("Status: Done", statuslabel)
hintlabel.SetText("The file/folder was successfully decrypted.")
image.SetFromFile("./Assets/success.gif")
}
// Handle encrypting data.
func encrypt(plaintext []byte, keyString string) (encryptedString string) {
//Since the key is in string, we need to convert decode it to bytes
key, _ := hex.DecodeString(keyString)
//Create a new Cipher Block from the key
block, err := aes.NewCipher(key)
check(err)
//Create a new GCM - https://en.wikipedia.org/wiki/Galois/Counter_Mode
//https://golang.org/pkg/crypto/cipher/#NewGCM
aesGCM, err := cipher.NewGCM(block)
check(err)
//Create a nonce. Nonce should be from GCM
nonce := make([]byte, aesGCM.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
//Encrypt the data using aesGCM.Seal
//Since we don't want to save the nonce somewhere else in this case, we add it as a prefix to the encrypted data. The first nonce argument in Seal is the prefix.
ciphertext := aesGCM.Seal(nonce, nonce, plaintext, nil)
return fmt.Sprintf("%s", ciphertext)
}
// Handle decrypting data.
func decrypt(enc []byte, keyString string) (decryptedString string) {
key, _ := hex.DecodeString(keyString)
//Create a new Cipher Block from the key
block, err := aes.NewCipher(key)
check(err)
//Create a new GCM
aesGCM, err := cipher.NewGCM(block)
check(err)
//Get the nonce size
nonceSize := aesGCM.NonceSize()
//Extract the nonce from the encrypted data
nonce, ciphertext := enc[:nonceSize], enc[nonceSize:]
//Decrypt the data
plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil)
check(err)
return fmt.Sprintf("%s", plaintext)
}