-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Refactor crypto decryption functions for consistency and error …
…handling (#302) * feat: Refactor crypto decryption functions for consistency and error handling - Close #301 - Refactored and renamed decryption functions across multiple files for consistency - Updated cookie sorting method to sort in descending order - Added new encryption functions for AES in CBC and GCM modes and DES in CBC mode - Added error handling to decryption functions and created new error variables for invalid ciphertext length and decode failures - Test cases added for encryption and decryption functions - Removed unused code and imports. * chore: Add new words to .typos.toml dictionary - Add new terms to `.typos.toml` dictionary - Improve code formatting and readability - Refactor functions for better performance - Update comments and documentation - Resolve minor bugs and errors * refactor: Refactor crypto package for better structure and readability - Refactored and cleaned up crypto package code for better readability - Renamed `ToByteArray` method to `bytes` for consistency - Modified `DecryptWithDPAPI` method to use `outBlob.bytes()` for efficiency - Added comments and removed unused methods in `loginPBE` - Refactored `nssPBE` and `metaPBE` Decrypt methods to use `deriveKeyAndIV` helper method - Improved overall maintainability and organization of codebase * refactor: Refactor firefox password encryption and decryption. - Implement ASN1PBE interface with various PBE struct types and encryption/decryption methods - Fix naming and remove unused variables in browsingdata and crypto files - Add tests for ASN1PBE implementation using external assertion package - Refactor and improve error handling in firefox file functions related to master key retrieval - Add input validation and AES-GCM encryption function to crypto file
- Loading branch information
Showing
13 changed files
with
750 additions
and
278 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
package crypto | ||
|
||
import ( | ||
"crypto/hmac" | ||
"crypto/sha1" | ||
"crypto/sha256" | ||
"encoding/asn1" | ||
"errors" | ||
|
||
"golang.org/x/crypto/pbkdf2" | ||
) | ||
|
||
type ASN1PBE interface { | ||
Decrypt(globalSalt []byte) ([]byte, error) | ||
|
||
Encrypt(globalSalt, plaintext []byte) ([]byte, error) | ||
} | ||
|
||
func NewASN1PBE(b []byte) (pbe ASN1PBE, err error) { | ||
var ( | ||
nss nssPBE | ||
meta metaPBE | ||
login loginPBE | ||
) | ||
if _, err := asn1.Unmarshal(b, &nss); err == nil { | ||
return nss, nil | ||
} | ||
if _, err := asn1.Unmarshal(b, &meta); err == nil { | ||
return meta, nil | ||
} | ||
if _, err := asn1.Unmarshal(b, &login); err == nil { | ||
return login, nil | ||
} | ||
return nil, ErrDecodeASN1Failed | ||
} | ||
|
||
var ErrDecodeASN1Failed = errors.New("decode ASN1 data failed") | ||
|
||
// nssPBE Struct | ||
// | ||
// SEQUENCE (2 elem) | ||
// OBJECT IDENTIFIER | ||
// SEQUENCE (2 elem) | ||
// OCTET STRING (20 byte) | ||
// INTEGER 1 | ||
// OCTET STRING (16 byte) | ||
type nssPBE struct { | ||
AlgoAttr struct { | ||
asn1.ObjectIdentifier | ||
SaltAttr struct { | ||
EntrySalt []byte | ||
Len int | ||
} | ||
} | ||
Encrypted []byte | ||
} | ||
|
||
// Decrypt decrypts the encrypted password with the global salt. | ||
func (n nssPBE) Decrypt(globalSalt []byte) ([]byte, error) { | ||
key, iv := n.deriveKeyAndIV(globalSalt) | ||
|
||
return DES3Decrypt(key, iv, n.Encrypted) | ||
} | ||
|
||
func (n nssPBE) Encrypt(globalSalt []byte, plaintext []byte) ([]byte, error) { | ||
key, iv := n.deriveKeyAndIV(globalSalt) | ||
|
||
return DES3Encrypt(key, iv, plaintext) | ||
} | ||
|
||
// deriveKeyAndIV derives the key and initialization vector (IV) | ||
// from the global salt and entry salt. | ||
func (n nssPBE) deriveKeyAndIV(globalSalt []byte) ([]byte, []byte) { | ||
salt := n.AlgoAttr.SaltAttr.EntrySalt | ||
hashPrefix := sha1.Sum(globalSalt) | ||
compositeHash := sha1.Sum(append(hashPrefix[:], salt...)) | ||
paddedEntrySalt := paddingZero(salt, 20) | ||
|
||
hmacProcessor := hmac.New(sha1.New, compositeHash[:]) | ||
hmacProcessor.Write(paddedEntrySalt) | ||
|
||
paddedEntrySalt = append(paddedEntrySalt, salt...) | ||
keyComponent1 := hmac.New(sha1.New, compositeHash[:]) | ||
keyComponent1.Write(paddedEntrySalt) | ||
|
||
hmacWithSalt := append(hmacProcessor.Sum(nil), salt...) | ||
keyComponent2 := hmac.New(sha1.New, compositeHash[:]) | ||
keyComponent2.Write(hmacWithSalt) | ||
|
||
key := append(keyComponent1.Sum(nil), keyComponent2.Sum(nil)...) | ||
iv := key[len(key)-8:] | ||
return key[:24], iv | ||
} | ||
|
||
// MetaPBE Struct | ||
// | ||
// SEQUENCE (2 elem) | ||
// OBJECT IDENTIFIER | ||
// SEQUENCE (2 elem) | ||
// SEQUENCE (2 elem) | ||
// OBJECT IDENTIFIER | ||
// SEQUENCE (4 elem) | ||
// OCTET STRING (32 byte) | ||
// INTEGER 1 | ||
// INTEGER 32 | ||
// SEQUENCE (1 elem) | ||
// OBJECT IDENTIFIER | ||
// SEQUENCE (2 elem) | ||
// OBJECT IDENTIFIER | ||
// OCTET STRING (14 byte) | ||
// OCTET STRING (16 byte) | ||
type metaPBE struct { | ||
AlgoAttr algoAttr | ||
Encrypted []byte | ||
} | ||
|
||
type algoAttr struct { | ||
asn1.ObjectIdentifier | ||
Data struct { | ||
Data struct { | ||
asn1.ObjectIdentifier | ||
SlatAttr slatAttr | ||
} | ||
IVData ivAttr | ||
} | ||
} | ||
|
||
type ivAttr struct { | ||
asn1.ObjectIdentifier | ||
IV []byte | ||
} | ||
|
||
type slatAttr struct { | ||
EntrySalt []byte | ||
IterationCount int | ||
KeySize int | ||
Algorithm struct { | ||
asn1.ObjectIdentifier | ||
} | ||
} | ||
|
||
func (m metaPBE) Decrypt(globalSalt []byte) ([]byte, error) { | ||
key, iv := m.deriveKeyAndIV(globalSalt) | ||
|
||
return AES128CBCDecrypt(key, iv, m.Encrypted) | ||
} | ||
|
||
func (m metaPBE) Encrypt(globalSalt, plaintext []byte) ([]byte, error) { | ||
key, iv := m.deriveKeyAndIV(globalSalt) | ||
|
||
return AES128CBCEncrypt(key, iv, plaintext) | ||
} | ||
|
||
func (m metaPBE) deriveKeyAndIV(globalSalt []byte) ([]byte, []byte) { | ||
password := sha1.Sum(globalSalt) | ||
|
||
salt := m.AlgoAttr.Data.Data.SlatAttr.EntrySalt | ||
iter := m.AlgoAttr.Data.Data.SlatAttr.IterationCount | ||
keyLen := m.AlgoAttr.Data.Data.SlatAttr.KeySize | ||
|
||
key := pbkdf2.Key(password[:], salt, iter, keyLen, sha256.New) | ||
iv := append([]byte{4, 14}, m.AlgoAttr.Data.IVData.IV...) | ||
return key, iv | ||
} | ||
|
||
// loginPBE Struct | ||
// | ||
// OCTET STRING (16 byte) | ||
// SEQUENCE (2 elem) | ||
// OBJECT IDENTIFIER | ||
// OCTET STRING (8 byte) | ||
// OCTET STRING (16 byte) | ||
type loginPBE struct { | ||
CipherText []byte | ||
Data struct { | ||
asn1.ObjectIdentifier | ||
IV []byte | ||
} | ||
Encrypted []byte | ||
} | ||
|
||
func (l loginPBE) Decrypt(globalSalt []byte) ([]byte, error) { | ||
key, iv := l.deriveKeyAndIV(globalSalt) | ||
return DES3Decrypt(key, iv, l.Encrypted) | ||
} | ||
|
||
func (l loginPBE) Encrypt(globalSalt, plaintext []byte) ([]byte, error) { | ||
key, iv := l.deriveKeyAndIV(globalSalt) | ||
return DES3Encrypt(key, iv, plaintext) | ||
} | ||
|
||
func (l loginPBE) deriveKeyAndIV(globalSalt []byte) ([]byte, []byte) { | ||
return globalSalt, l.Data.IV | ||
} |
Oops, something went wrong.