<commit_before>package pwsafe

import (
	"crypto/cipher"
	"crypto/sha256"
	"errors"
	"io"

	"golang.org/x/crypto/twofish"
)

//Decrypt Decrypts the data in the reader using the given password and populates the information into the db
func (db *V3) Decrypt(reader io.Reader, passwd string) (int, error) {
	var bytesRead int
	// The TAG is 4 ascii characters, should be "PWS3"
	tag := make([]byte, 4)
	_, err := reader.Read(tag)
	if err != nil || string(tag) != "PWS3" {
		return bytesRead, errors.New("File is not a valid Password Safe v3 file")
	}
	bytesRead += 4

	// Read the Salt
	salt := make([]byte, 32)
	readSize, err := reader.Read(salt)
	if err != nil || readSize != 32 {
		return bytesRead, errors.New("Error reading File, salt is invalid")
	}
	bytesRead += 32
	db.Salt = salt

	// Read iter
	iter := make([]byte, 4)
	readSize, err = reader.Read(iter)
	if err != nil || readSize != 4 {
		return bytesRead, errors.New("Error reading File, invalid iterations")
	}
	bytesRead += 4
	db.Iter = uint32(uint32(iter[0]) | uint32(iter[1])<<8 | uint32(iter[2])<<16 | uint32(iter[3])<<24)

	// Verify the password
	db.calculateStretchKey(passwd)
	readHash := make([]byte, sha256.Size)
	var keyHash [sha256.Size]byte
	readSize, err = reader.Read(readHash)
	copy(keyHash[:], readHash)
	if err != nil || readSize != sha256.Size || keyHash != sha256.Sum256(db.stretchedKey[:]) {
		return bytesRead, errors.New("Invalid Password")
	}

	//extract the encryption and hmac keys
	keyData := make([]byte, 64)
	readSize, err = reader.Read(keyData)
	if err != nil || readSize != 64 {
		return bytesRead, errors.New("Error reading encryption/HMAC keys")
	}
	bytesRead += 64
	db.extractKeys(keyData)

	cbciv := make([]byte, 16)
	readSize, err = reader.Read(cbciv)
	if err != nil || readSize != 16 {
		return bytesRead, errors.New("Error reading Initial CBC value")
	}
	bytesRead += 16
	db.CBCIV = cbciv

	// All following fields are encrypted with twofish in CBC mode until the EOF, find the EOF
	var encryptedDB []byte
	var encryptedSize int
	for {
		blockBytes := make([]byte, twofish.BlockSize)
		readSize, err = reader.Read(blockBytes)
		if err != nil || readSize != twofish.BlockSize {
			return bytesRead, errors.New("Error reading Encrypted Data, possibly no EOF found")
		}

		if string(blockBytes) == "PWS3-EOFPWS3-EOF" {
			bytesRead += twofish.BlockSize
			break
		} else {
			encryptedSize += readSize
			encryptedDB = append(encryptedDB, blockBytes...)
		}
	}
	bytesRead += encryptedSize

	if len(encryptedDB)%twofish.BlockSize != 0 {
		return bytesRead, errors.New("Error, encrypted data size is not a multiple of the block size")
	}

	// HMAC 32bytes keyed-hash MAC with SHA-256 as the hash function. Calculated over all unencryped db data
	hmac := make([]byte, 32)
	readSize, err = reader.Read(hmac)
	if err != nil || readSize != 32 {
		return bytesRead, errors.New("Error reading HMAC")
	}
	bytesRead += 32
	db.HMAC = hmac

	block, err := twofish.NewCipher(db.encryptionKey)
	decrypter := cipher.NewCBCDecrypter(block, db.CBCIV)<commit_msg>Read the entire db file in when decrypting, this makes the code cleaner<commit_after>package pwsafe

import (
	"crypto/cipher"
	"crypto/sha256"
	"errors"
	"io"

	"golang.org/x/crypto/twofish"
)

//Decrypt Decrypts the data in the reader using the given password and populates the information into the db
func (db *V3) Decrypt(reader io.Reader, passwd string) (int, error) {
	// read the entire encrypted db into memory
	var rawDB []byte
	var bytesRead int
	for {
		block := make([]byte, 256)
		readLoop, err := reader.Read(block)
		bytesRead += readLoop
		if err != nil {
			return bytesRead, err
		}
		rawDB = append(rawDB, block[:readLoop]...)
		if readLoop != 256 {
			break
		}
	}

	if bytesRead < 200 {
		return bytesRead, errors.New("DB file is smaller than minimum size")
	}

	// The TAG is 4 ascii characters, should be "PWS3"
	if string(rawDB[:4]) != "PWS3" {
		return bytesRead, errors.New("File is not a valid Password Safe v3 file")
	}
	pos := 4 // used to track the current position in the byte array representing the db.

	// Read the Salt
	db.Salt = rawDB[pos : pos+32]
	pos += 32

	// Read iter
	iter := rawDB[pos : pos+4]
	db.Iter = uint32(uint32(iter[0]) | uint32(iter[1])<<8 | uint32(iter[2])<<16 | uint32(iter[3])<<24)
	pos += 4

	// Verify the password
	db.calculateStretchKey(passwd)
	var keyHash [sha256.Size]byte
	copy(keyHash[:], rawDB[pos:pos+sha256.Size])
	pos += sha256.Size
	if keyHash != sha256.Sum256(db.stretchedKey[:]) {
		return bytesRead, errors.New("Invalid Password")
	}

	//extract the encryption and hmac keys
	db.extractKeys(rawDB[pos : pos+64])
	pos += 64

	db.CBCIV = rawDB[pos : pos+16]
	pos += 16

	// All following fields are encrypted with twofish in CBC mode until the EOF, find the EOF
	var encryptedDB []byte
	var encryptedSize int
	for {
		if pos+twofish.BlockSize > bytesRead {
			return bytesRead, errors.New("Invalid DB, no EOF found")
		}
		blockBytes := rawDB[pos : pos+twofish.BlockSize]
		pos += twofish.BlockSize

		if string(blockBytes) == "PWS3-EOFPWS3-EOF" {
			break
		} else {
			encryptedSize += twofish.BlockSize
			encryptedDB = append(encryptedDB, blockBytes...)
		}
	}

	// HMAC 32bytes keyed-hash MAC with SHA-256 as the hash function. Calculated over all unencryped db data
	db.HMAC = rawDB[pos : pos+32]
	pos += 32

	block, err := twofish.NewCipher(db.encryptionKey)
	decrypter := cipher.NewCBCDecrypter(block, db.CBCIV)
{'fraction_non_alphanumeric': 0.12978645066273933, 'fraction_numerical': 0.02890279823269514, 'mean_word_length': 3.9167420814479637, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3171277', 'n_tokens_mistral': 2102, 'n_tokens_neox': 1883, 'n_words': 573}