Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev: Optimize encryption and decryption module #305

Merged
merged 4 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,21 @@ jobs:

steps:
- name: Set up Go ${{ matrix.goVer }}
uses: actions/setup-go@v1
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.goVer }}
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@v2

- name: Set Git to handle line endings consistently
run: git config --global core.autocrlf false
uses: actions/checkout@v4

- name: Format Check
if: matrix.os != 'windows-latest'
run: |
diff -u <(echo -n) <(gofmt -d .)

- name: Get dependencies
run: |
go get -v -t -d ./...
go get gopkg.in/check.v1
run: go get -v ./...

- name: Build
run: go build -v ./...
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version: "1.21.x"
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Check spelling with custom config file
uses: crate-ci/typos@master
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:

steps:
- name: Checkout source
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Use Golang
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version: "1.21.x"

Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/unittest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
- main
workflow_dispatch:

name: unit tests
name: Tests
jobs:
test:
strategy:
Expand All @@ -16,11 +16,11 @@ jobs:
steps:
- name: Install Go
if: success()
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Run tests
run: go test -v ./... -covermode=count

Expand All @@ -29,11 +29,11 @@ jobs:
steps:
- name: Install Go
if: success()
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version: "1.21.x"
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Calc coverage
run: |
go test -v ./... -covermode=count -coverprofile=coverage.out
Expand Down
2 changes: 2 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
Readed = "Readed"
Sie = "Sie"
OT = "OT"
Encrypter = "Encrypter"
Decrypter = "Decrypter"
[files]
extend-exclude = ["go.mod", "go.sum"]
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Please adhere to the existing coding style for consistency.

## Questions

If you have any questions or need further guidance, please feel free to ask in the issue or PR, or [reach out to the maintainers](mailto:[email protected]).
If you have any questions or need further guidance, please feel free to ask in the issue or PR, or [reach out to the maintainers](mailto:[email protected]). We will reply to you as soon as possible.

Thank you for your contribution!

2 changes: 1 addition & 1 deletion browser/chromium/chromium_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (c *Chromium) GetMasterKey() ([]byte, error) {
if err != nil {
return nil, errDecodeMasterKeyFailed
}
c.masterKey, err = crypto.DPAPI(key[5:])
c.masterKey, err = crypto.DecryptWithDPAPI(key[5:])
if err != nil {
slog.Error("decrypt master key failed", "err", err)
return nil, err
Expand Down
85 changes: 84 additions & 1 deletion browser/firefox/firefox.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package firefox

import (
"bytes"
"database/sql"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"

_ "modernc.org/sqlite" // sqlite3 driver TODO: replace with chooseable driver

"github.com/moond4rk/hackbrowserdata/browsingdata"
"github.com/moond4rk/hackbrowserdata/crypto"
"github.com/moond4rk/hackbrowserdata/item"
"github.com/moond4rk/hackbrowserdata/utils/fileutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
Expand Down Expand Up @@ -68,8 +74,85 @@ func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]
}
}

// GetMasterKey returns master key of Firefox. from key4.db
func (f *Firefox) GetMasterKey() ([]byte, error) {
return f.masterKey, nil
tempFilename := item.FirefoxKey4.TempFilename()

// Open and defer close of the database.
keyDB, err := sql.Open("sqlite", tempFilename)
if err != nil {
return nil, fmt.Errorf("open key4.db error: %w", err)
}
defer os.Remove(tempFilename)
defer keyDB.Close()

metaItem1, metaItem2, err := queryMetaData(keyDB)
if err != nil {
return nil, fmt.Errorf("query metadata error: %w", err)
}

nssA11, nssA102, err := queryNssPrivate(keyDB)
if err != nil {
return nil, fmt.Errorf("query NSS private error: %w", err)
}

return processMasterKey(metaItem1, metaItem2, nssA11, nssA102)
}

func queryMetaData(db *sql.DB) ([]byte, []byte, error) {
const query = `SELECT item1, item2 FROM metaData WHERE id = 'password'`
var metaItem1, metaItem2 []byte
if err := db.QueryRow(query).Scan(&metaItem1, &metaItem2); err != nil {
return nil, nil, err
}
return metaItem1, metaItem2, nil
}

func queryNssPrivate(db *sql.DB) ([]byte, []byte, error) {
const query = `SELECT a11, a102 from nssPrivate`
var nssA11, nssA102 []byte
if err := db.QueryRow(query).Scan(&nssA11, &nssA102); err != nil {
return nil, nil, err
}
return nssA11, nssA102, nil
}

// processMasterKey process master key of Firefox.
// Process the metaBytes and nssA11 with the corresponding cryptographic operations.
func processMasterKey(metaItem1, metaItem2, nssA11, nssA102 []byte) ([]byte, error) {
metaPBE, err := crypto.NewASN1PBE(metaItem2)
if err != nil {
return nil, fmt.Errorf("error creating ASN1PBE from metaItem2: %w", err)
}

flag, err := metaPBE.Decrypt(metaItem1)
if err != nil {
return nil, fmt.Errorf("error decrypting master key: %w", err)
}
const passwordCheck = "password-check"

if !bytes.Contains(flag, []byte(passwordCheck)) {
return nil, errors.New("flag verification failed: password-check not found")
}

var keyLin = []byte{248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
if !bytes.Equal(nssA102, keyLin) {
return nil, errors.New("master key verification failed: nssA102 not equal to expected value")
}

nssA11PBE, err := crypto.NewASN1PBE(nssA11)
if err != nil {
return nil, fmt.Errorf("error creating ASN1PBE from nssA11: %w", err)
}

finallyKey, err := nssA11PBE.Decrypt(metaItem1)
if err != nil {
return nil, fmt.Errorf("error decrypting final key: %w", err)
}
if len(finallyKey) < 24 {
return nil, errors.New("length of final key is less than 24 bytes")
}
return finallyKey[:24], nil
}

func (f *Firefox) Name() string {
Expand Down
38 changes: 38 additions & 0 deletions browser/firefox/firefox_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package firefox

import (
"testing"

"github.com/DATA-DOG/go-sqlmock"
"github.com/stretchr/testify/assert"
)

func TestQueryMetaData(t *testing.T) {
db, mock, err := sqlmock.New()
assert.NoError(t, err)
defer db.Close()

rows := sqlmock.NewRows([]string{"item1", "item2"}).
AddRow([]byte("globalSalt"), []byte("metaBytes"))
mock.ExpectQuery("SELECT item1, item2 FROM metaData WHERE id = 'password'").WillReturnRows(rows)

globalSalt, metaBytes, err := queryMetaData(db)
assert.NoError(t, err)
assert.Equal(t, []byte("globalSalt"), globalSalt)
assert.Equal(t, []byte("metaBytes"), metaBytes)
}

func TestQueryNssPrivate(t *testing.T) {
db, mock, err := sqlmock.New()
assert.NoError(t, err)
defer db.Close()

rows := sqlmock.NewRows([]string{"a11", "a102"}).
AddRow([]byte("nssA11"), []byte("nssA102"))
mock.ExpectQuery("SELECT a11, a102 from nssPrivate").WillReturnRows(rows)

nssA11, nssA102, err := queryNssPrivate(db)
assert.NoError(t, err)
assert.Equal(t, []byte("nssA11"), nssA11)
assert.Equal(t, []byte("nssA102"), nssA102)
}
4 changes: 2 additions & 2 deletions browsingdata/cookie/cookie.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ func (c *ChromiumCookie) Parse(masterKey []byte) error {
}
if len(encryptValue) > 0 {
if len(masterKey) == 0 {
value, err = crypto.DPAPI(encryptValue)
value, err = crypto.DecryptWithDPAPI(encryptValue)
} else {
value, err = crypto.DecryptPass(masterKey, encryptValue)
value, err = crypto.DecryptWithChromium(masterKey, encryptValue)
}
if err != nil {
slog.Error("decrypt chromium cookie error", "err", err)
Expand Down
8 changes: 4 additions & 4 deletions browsingdata/creditcard/creditcard.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ func (c *ChromiumCreditCard) Parse(masterKey []byte) error {
}
if len(encryptValue) > 0 {
if len(masterKey) == 0 {
value, err = crypto.DPAPI(encryptValue)
value, err = crypto.DecryptWithDPAPI(encryptValue)
} else {
value, err = crypto.DecryptPass(masterKey, encryptValue)
value, err = crypto.DecryptWithChromium(masterKey, encryptValue)
}
if err != nil {
slog.Error("decrypt chromium credit card error", "err", err)
Expand Down Expand Up @@ -114,9 +114,9 @@ func (c *YandexCreditCard) Parse(masterKey []byte) error {
}
if len(encryptValue) > 0 {
if len(masterKey) == 0 {
value, err = crypto.DPAPI(encryptValue)
value, err = crypto.DecryptWithDPAPI(encryptValue)
} else {
value, err = crypto.DecryptPass(masterKey, encryptValue)
value, err = crypto.DecryptWithChromium(masterKey, encryptValue)
}
if err != nil {
slog.Error("decrypt chromium credit card error", "err", err)
Expand Down
Loading
Loading