Browse Source

added encryption and encoding

bmallred 10 years ago
parent
commit
7167b5c7cc
5 changed files with 135 additions and 43 deletions
  1. BIN
      084e0343a0486ff05530df6c705c8bb4
  2. 11 0
      file.go
  3. 45 38
      handlers.go
  4. 1 1
      main.go
  5. 78 4
      security.go

BIN
084e0343a0486ff05530df6c705c8bb4


+ 11 - 0
file.go

@ -24,6 +24,10 @@ func save(file, passphrase string, sites []Site) error {
24 24
	if err != nil {
25 25
		return err
26 26
	}
27
	b, err = encrypt(encodeBase64(b), passphrase)
28
	if err != nil {
29
		return err
30
	}
27 31
28 32
	// Compress the contents
29 33
	var buffer bytes.Buffer
@ -69,6 +73,13 @@ func read(file, passphrase string) ([]Site, error) {
69 73
	decompressed, err := ioutil.ReadAll(gzip)
70 74
	gzip.Close()
71 75
76
	// Decrypt the contents
77
	decompressed, err = decrypt(decompressed, passphrase)
78
	if err != nil {
79
		return nil, err
80
	}
81
	decompressed = decodeBase64(decompressed)
82
72 83
	// Unmarshal the JSON information
73 84
	var sites []Site
74 85
	err = json.Unmarshal(decompressed, &sites)

+ 45 - 38
handlers.go

@ -7,6 +7,7 @@ import (
7 7
	"os"
8 8
	"strconv"
9 9
	"text/template"
10
	"time"
10 11
)
11 12
12 13
type Page struct {
@ -31,6 +32,8 @@ func GenerateHandler(w http.ResponseWriter, r *http.Request) {
31 32
		return
32 33
	}
33 34
35
	passphrase = string(decodeBase64([]byte(passphrase)))
36
34 37
	u, err := url.Parse(host)
35 38
	if err != nil {
36 39
		http.Error(w, err.Error(), http.StatusInternalServerError)
@ -81,9 +84,15 @@ func ProfileHandler(w http.ResponseWriter, r *http.Request) {
81 84
		return
82 85
	}
83 86
84
	book := getBookname(profile)
87
	passphrase = string(decodeBase64([]byte(passphrase)))
85 88
86
	if cmd == "delete" {
89
	switch cmd {
90
	default:
91
		// This should never happen, but just in case send them back
92
		http.Redirect(w, r, "/book", http.StatusSeeOther)
93
		return
94
	case "delete":
95
		book := getBookname(profile)
87 96
		err := os.Remove(book)
88 97
		if err != nil {
89 98
			// Return an error
@ -92,12 +101,14 @@ func ProfileHandler(w http.ResponseWriter, r *http.Request) {
92 101
		}
93 102
94 103
		http.Redirect(w, r, "/", http.StatusSeeOther)
95
	} else if cmd == "update" {
104
		break
105
	case "update":
96 106
		if newPassphrase == "" || confirmPassphrase == "" || newPassphrase != confirmPassphrase {
97 107
			http.Error(w, "Invalid passphrase provided", http.StatusInternalServerError)
98 108
			return
99 109
		}
100 110
111
		book := getBookname(profile)
101 112
		sites, err := read(book, passphrase)
102 113
		if err != nil {
103 114
			http.Error(w, err.Error(), http.StatusInternalServerError)
@ -109,10 +120,13 @@ func ProfileHandler(w http.ResponseWriter, r *http.Request) {
109 120
			return
110 121
		}
111 122
112
		http.Redirect(w, r, "/book", http.StatusSeeOther)
113
	} else {
114
		// This should never happen, but just in case send them back
115
		http.Redirect(w, r, "/book", http.StatusSeeOther)
123
		cookiePassphrase := &http.Cookie{
124
			Name:   "passphrase",
125
			MaxAge: -1,
126
		}
127
		http.SetCookie(w, cookiePassphrase)
128
		http.Redirect(w, r, "/", http.StatusSeeOther)
129
		break
116 130
	}
117 131
}
118 132
@ -126,6 +140,8 @@ func RefreshHandler(w http.ResponseWriter, r *http.Request) {
126 140
		return
127 141
	}
128 142
143
	passphrase = string(decodeBase64([]byte(passphrase)))
144
129 145
	// Update the revision number and generate a new password
130 146
	book := getBookname(profile)
131 147
	sites, err := read(book, passphrase)
@ -158,6 +174,8 @@ func RemoveHandler(w http.ResponseWriter, r *http.Request) {
158 174
		return
159 175
	}
160 176
177
	passphrase = string(decodeBase64([]byte(passphrase)))
178
161 179
	// Remove the site from our book and save it
162 180
	book := getBookname(profile)
163 181
	sites, err := read(book, passphrase)
@ -180,7 +198,7 @@ func RemoveHandler(w http.ResponseWriter, r *http.Request) {
180 198
	http.Redirect(w, r, "/book", http.StatusSeeOther)
181 199
}
182 200
183
func SignOffHandler(w http.ResponseWriter, r *http.Request) {
201
func SignOutHandler(w http.ResponseWriter, r *http.Request) {
184 202
	cookieProfile := &http.Cookie{
185 203
		Name:   "profile",
186 204
		MaxAge: -1,
@ -207,8 +225,23 @@ func BookHandler(w http.ResponseWriter, r *http.Request) {
207 225
208 226
		c, err = r.Cookie("passphrase")
209 227
		if err == nil {
210
			passphrase = c.Value
228
			passphrase = string(decodeBase64([]byte(c.Value)))
211 229
		}
230
	} else {
231
		// Set cookies
232
		expire := time.Now().AddDate(0, 0, 1)
233
		cookieProfile := &http.Cookie{
234
			Name:    "profile",
235
			Value:   profile,
236
			Expires: expire,
237
		}
238
		cookiePassphrase := &http.Cookie{
239
			Name:    "passphrase",
240
			Value:   encodeBase64([]byte(passphrase)),
241
			Expires: expire,
242
		}
243
		http.SetCookie(w, cookieProfile)
244
		http.SetCookie(w, cookiePassphrase)
212 245
	}
213 246
214 247
	if profile == "" || passphrase == "" {
@ -216,37 +249,11 @@ func BookHandler(w http.ResponseWriter, r *http.Request) {
216 249
		return
217 250
	}
218 251
219
	// Set cookies
220
	//expire := time.Now().AddDate(0, 0, 1)
221
	cookieProfile := &http.Cookie{
222
		Name:  "profile",
223
		Value: profile,
224
		//Path:       "/",
225
		//Domain:     "localhost",
226
		//Expires:    expire,
227
		//RawExpires: expire.Format(time.UnixDate),
228
		//MaxAge:     0,
229
		//Secure:     false,
230
		//HttpOnly:   true,
231
	}
232
	http.SetCookie(w, cookieProfile)
233
	cookiePassphrase := &http.Cookie{
234
		Name:  "passphrase",
235
		Value: passphrase,
236
		//Path:       "/",
237
		//Domain:     "localhost",
238
		//Expires:    expire,
239
		//RawExpires: expire.Format(time.UnixDate),
240
		//MaxAge:     0,
241
		//Secure:     false,
242
		//HttpOnly:   true,
243
	}
244
	http.SetCookie(w, cookiePassphrase)
245 252
	book := getBookname(profile)
246
247 253
	sites, err := read(book, passphrase)
248 254
	if err != nil {
249
		http.Error(w, err.Error(), http.StatusInternalServerError)
255
		//http.Error(w, "Invalid credentials", http.StatusUnauthorized)
256
		http.Redirect(w, r, "/", http.StatusSeeOther)
250 257
		return
251 258
	}
252 259
	for i, s := range sites {
@ -256,7 +263,7 @@ func BookHandler(w http.ResponseWriter, r *http.Request) {
256 263
257 264
	page := Page{
258 265
		Profile:    profile,
259
		Passphrase: passphrase,
266
		Passphrase: encodeBase64([]byte(passphrase)),
260 267
		Sites:      sites,
261 268
	}
262 269

+ 1 - 1
main.go

@ -10,7 +10,7 @@ func main() {
10 10
	http.HandleFunc("/api/update", ProfileHandler)
11 11
	http.HandleFunc("/api/refresh", RefreshHandler)
12 12
	http.HandleFunc("/api/remove", RemoveHandler)
13
	http.HandleFunc("/signout", SignOffHandler)
13
	http.HandleFunc("/signout", SignOutHandler)
14 14
	http.HandleFunc("/book", BookHandler)
15 15
	http.HandleFunc("/", DefaultHandler)
16 16

+ 78 - 4
security.go

@ -1,11 +1,85 @@
1 1
package main
2 2
3
import (
4
	"crypto/aes"
5
	"crypto/cipher"
6
	"crypto/rand"
7
	"encoding/base64"
8
	"errors"
9
	"io"
10
	"os"
11
)
12
13
func encodeBase64(data []byte) string {
14
	return base64.StdEncoding.EncodeToString(data)
15
}
16
17
func decodeBase64(data []byte) []byte {
18
	b, _ := base64.StdEncoding.DecodeString(string(data))
19
	return b
20
}
21
22
func getLocalKey() string {
23
	env := os.Getenv("ENIGMA_KEY")
24
	if env == "" {
25
		env = "thebrownfoxjumpedoverthefence"
26
	}
27
28
	return env
29
}
30
31
func getSizedKey(key string) string {
32
	// Get the correct key length
33
	l := len(key)
34
	if l < 16 {
35
		for i := 0; i < 16-l; i++ {
36
			key += "."
37
		}
38
	} else if l < 24 {
39
		for i := 0; i < 24-l; i++ {
40
			key += "."
41
		}
42
	} else if l < 32 {
43
		for i := 0; i < 32-l; i++ {
44
			key += "."
45
		}
46
	} else {
47
		key = key[:32]
48
	}
49
50
	return key
51
}
52
3 53
// Encrypt the password book
4
func encrypt(clearText, profile, passphrase string) ([]byte, error) {
5
	return nil, nil
54
func encrypt(text, passphrase string) ([]byte, error) {
55
	key := []byte(getSizedKey(passphrase))
56
	block, err := aes.NewCipher(key)
57
	if err != nil {
58
		return nil, err
59
	}
60
	cipherText := make([]byte, aes.BlockSize+len(text))
61
	iv := cipherText[:aes.BlockSize]
62
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
63
		return nil, err
64
	}
65
	encrypter := cipher.NewCFBEncrypter(block, iv)
66
	encrypter.XORKeyStream(cipherText[aes.BlockSize:], []byte(text))
67
	return cipherText, nil
6 68
}
7 69
8 70
// Decrypt the password book
9
func decrypt(encryptedText, profile, passphrase string) ([]byte, error) {
10
	return nil, nil
71
func decrypt(text []byte, passphrase string) ([]byte, error) {
72
	key := []byte(getSizedKey(passphrase))
73
	block, err := aes.NewCipher(key)
74
	if err != nil {
75
		return nil, err
76
	}
77
	if len(text) < aes.BlockSize {
78
		return nil, errors.New("Cipher text too short")
79
	}
80
	iv := text[:aes.BlockSize]
81
	data := text[aes.BlockSize:]
82
	decrypter := cipher.NewCFBDecrypter(block, iv)
83
	decrypter.XORKeyStream(data, data)
84
	return data, nil
11 85
}