Finalize v1.29

This commit is contained in:
Evan Su 2022-05-23 20:40:01 -04:00 committed by GitHub
parent b908bd7bd1
commit dcb6bf3839
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -437,10 +437,17 @@ func draw() {
} }
fout, _ := os.Create(file) fout, _ := os.Create(file)
data := make([]byte, MiB) data := make([]byte, KiB)
rand.Read(data) rand.Read(data)
fout.Write(data) _, err = fout.Write(data)
fout.Close() fout.Close()
if err != nil {
insufficientSpace(nil, nil)
os.Remove(file)
} else {
mainStatus = "Ready."
mainStatusColor = WHITE
}
}), }),
giu.Tooltip("Generate a cryptographically secure keyfile."), giu.Tooltip("Generate a cryptographically secure keyfile."),
), ),
@ -625,7 +632,7 @@ func onDrop(names []string) {
if showKeyfile { if showKeyfile {
keyfiles = append(keyfiles, names...) keyfiles = append(keyfiles, names...)
// Remove duplicate keyfiles and make sure they're accessible // Make sure keyfiles are accessible, remove duplicates
var tmp []string var tmp []string
for _, i := range keyfiles { for _, i := range keyfiles {
duplicate := false duplicate := false
@ -638,6 +645,12 @@ func onDrop(names []string) {
fin, err := os.Open(i) fin, err := os.Open(i)
if err == nil { if err == nil {
fin.Close() fin.Close()
} else {
showKeyfile = false
resetUI()
accessDenied("Keyfile read")
giu.Update()
return
} }
if !duplicate && !stat.IsDir() && err == nil { if !duplicate && !stat.IsDir() && err == nil {
tmp = append(tmp, i) tmp = append(tmp, i)
@ -705,8 +718,8 @@ func onDrop(names []string) {
outputFile = names[0][:ind] outputFile = names[0][:ind]
recombine = true recombine = true
totalFiles := 0
// Find out the number of splitted chunks // Find out the number of splitted chunks
totalFiles := 0
for { for {
stat, err := os.Stat(fmt.Sprintf("%s.%d", inputFile, totalFiles)) stat, err := os.Stat(fmt.Sprintf("%s.%d", inputFile, totalFiles))
if err != nil { if err != nil {
@ -918,11 +931,9 @@ func work() {
} }
compressDone = 0 compressDone = 0
// Add each file to the .zip
writer := zip.NewWriter(file) writer := zip.NewWriter(file)
compressStart = time.Now() compressStart = time.Now()
// Add each file to the .zip
for i, path := range files { for i, path := range files {
progressInfo = fmt.Sprintf("%d/%d", i+1, len(files)) progressInfo = fmt.Sprintf("%d/%d", i+1, len(files))
giu.Update() giu.Update()
@ -959,17 +970,15 @@ func work() {
fin.Close() fin.Close()
if err != nil { if err != nil {
insufficientSpace() insufficientSpace(nil, file)
writer.Close() writer.Close()
file.Close()
os.Remove(inputFile) os.Remove(inputFile)
return return
} }
if !working { if !working {
cancel() cancel(nil, file)
writer.Close() writer.Close()
file.Close()
os.Remove(inputFile) os.Remove(inputFile)
return return
} }
@ -1004,12 +1013,18 @@ func work() {
// Merge all chunks into one file // Merge all chunks into one file
startTime := time.Now() startTime := time.Now()
for i := 0; i < totalFiles; i++ { for i := 0; i < totalFiles; i++ {
fin, _ := os.Open(fmt.Sprintf("%s.%d", inputFile, i)) fin, err := os.Open(fmt.Sprintf("%s.%d", inputFile, i))
if err != nil {
fout.Close()
os.Remove(outputFile + ".pcv")
resetUI()
accessDenied("Read")
return
}
for { for {
if !working { if !working {
cancel() cancel(fin, fout)
fin.Close()
fout.Close()
os.Remove(outputFile + ".pcv") os.Remove(outputFile + ".pcv")
return return
} }
@ -1025,9 +1040,7 @@ func work() {
done += read done += read
if err != nil { if err != nil {
insufficientSpace() insufficientSpace(fin, fout)
fin.Close()
fout.Close()
os.Remove(outputFile + ".pcv") os.Remove(outputFile + ".pcv")
return return
} }
@ -1065,7 +1078,7 @@ func work() {
return return
} }
// Set up output file // Setup output file
var fout *os.File var fout *os.File
// If encrypting, generate values and write to file // If encrypting, generate values and write to file
@ -1073,6 +1086,9 @@ func work() {
popupStatus = "Generating values..." popupStatus = "Generating values..."
giu.Update() giu.Update()
// Stores any errors when writing to file
errs := make([]error, 11)
// Create the output file // Create the output file
var err error var err error
fout, err = os.Create(outputFile) fout, err = os.Create(outputFile)
@ -1089,15 +1105,18 @@ func work() {
nonce = make([]byte, 24) nonce = make([]byte, 24)
// Write the program version to file // Write the program version to file
fout.Write(rsEncode(rs5, []byte(version))) _, errs[0] = fout.Write(rsEncode(rs5, []byte(version)))
// Encode and write the comment length to file // Encode and write the comment length to file
commentsLength := []byte(fmt.Sprintf("%05d", len(comments))) commentsLength := []byte(fmt.Sprintf("%05d", len(comments)))
fout.Write(rsEncode(rs5, commentsLength)) _, errs[1] = fout.Write(rsEncode(rs5, commentsLength))
// Encode the comment and write to file // Encode the comment and write to file
for _, i := range []byte(comments) { for _, i := range []byte(comments) {
fout.Write(rsEncode(rs1, []byte{i})) _, err := fout.Write(rsEncode(rs1, []byte{i}))
if err != nil {
errs[2] = err
}
} }
// Configure flags and write to file // Configure flags and write to file
@ -1117,7 +1136,7 @@ func work() {
if total%int64(MiB) >= int64(MiB)-128 { // Reed-Solomon internals if total%int64(MiB) >= int64(MiB)-128 { // Reed-Solomon internals
flags[4] = 1 flags[4] = 1
} }
fout.Write(rsEncode(rs5, flags)) _, errs[3] = fout.Write(rsEncode(rs5, flags))
// Fill values with Go's CSPRNG // Fill values with Go's CSPRNG
rand.Read(salt) rand.Read(salt)
@ -1126,15 +1145,27 @@ func work() {
rand.Read(nonce) rand.Read(nonce)
// Encode values with Reed-Solomon and write to file // Encode values with Reed-Solomon and write to file
fout.Write(rsEncode(rs16, salt)) _, errs[4] = fout.Write(rsEncode(rs16, salt))
fout.Write(rsEncode(rs32, hkdfSalt)) _, errs[5] = fout.Write(rsEncode(rs32, hkdfSalt))
fout.Write(rsEncode(rs16, serpentSalt)) _, errs[6] = fout.Write(rsEncode(rs16, serpentSalt))
fout.Write(rsEncode(rs24, nonce)) _, errs[7] = fout.Write(rsEncode(rs24, nonce))
// Write placeholders for future use // Write placeholders for future use
fout.Write(make([]byte, 192)) // Hash of encryption key _, errs[8] = fout.Write(make([]byte, 192)) // Hash of encryption key
fout.Write(make([]byte, 96)) // Hash of keyfile key _, errs[9] = fout.Write(make([]byte, 96)) // Hash of keyfile key
fout.Write(make([]byte, 192)) // BLAKE2b/HMAC-SHA3 tag _, errs[10] = fout.Write(make([]byte, 192)) // BLAKE2b/HMAC-SHA3 tag
for _, err := range errs {
if err != nil {
insufficientSpace(fin, fout)
os.Remove(outputFile + ".pcv")
if len(allFiles) > 1 || len(onlyFolders) > 0 || compress {
os.Remove(inputFile)
}
return
}
}
} else { // Decrypting, read values from file and decode } else { // Decrypting, read values from file and decode
popupStatus = "Reading values..." popupStatus = "Reading values..."
giu.Update() giu.Update()
@ -1194,12 +1225,7 @@ func work() {
if keep { // If the user chooses to force decrypt if keep { // If the user chooses to force decrypt
kept = true kept = true
} else { } else {
mainStatus = "The volume header is damaged." broken(fin, nil, "The volume header is damaged.")
mainStatusColor = RED
fin.Close()
if recombine {
os.Remove(inputFile)
}
return return
} }
} }
@ -1238,16 +1264,19 @@ func work() {
if keyfileOrdered { // If order matters, hash progressively if keyfileOrdered { // If order matters, hash progressively
var tmp = sha3.New256() var tmp = sha3.New256()
// For each keyfile...
for _, path := range keyfiles { for _, path := range keyfiles {
fin, _ := os.Open(path) fin, _ := os.Open(path)
stat, _ := os.Stat(path) stat, _ := os.Stat(path)
data := make([]byte, stat.Size()) data := make([]byte, stat.Size())
fin.Read(data) fin.Read(data) // Read the keyfile
fin.Close() fin.Close()
tmp.Write(data) tmp.Write(data) // Hash the data
} }
keyfileKey = tmp.Sum(nil) keyfileKey = tmp.Sum(nil) // Get the SHA3-256
// Store a hash of 'keyfileKey' for comparison
tmp = sha3.New256() tmp = sha3.New256()
tmp.Write(keyfileKey) tmp.Write(keyfileKey)
keyfileHash = tmp.Sum(nil) keyfileHash = tmp.Sum(nil)
@ -1256,11 +1285,15 @@ func work() {
fin, _ := os.Open(path) fin, _ := os.Open(path)
stat, _ := os.Stat(path) stat, _ := os.Stat(path)
data := make([]byte, stat.Size()) data := make([]byte, stat.Size())
fin.Read(data) fin.Read(data) // Read the keyfile
fin.Close() fin.Close()
// Get the SHA3-256
tmp := sha3.New256() tmp := sha3.New256()
tmp.Write(data) tmp.Write(data)
sum := tmp.Sum(nil) sum := tmp.Sum(nil)
// XOR keyfile hash with 'keyfileKey'
if keyfileKey == nil { if keyfileKey == nil {
keyfileKey = sum keyfileKey = sum
} else { } else {
@ -1270,7 +1303,7 @@ func work() {
} }
} }
// Store a hash of the keyfile key for comparison // Store a hash of 'keyfileKey' for comparison
tmp := sha3.New256() tmp := sha3.New256()
tmp.Write(keyfileKey) tmp.Write(keyfileKey)
keyfileHash = tmp.Sum(nil) keyfileHash = tmp.Sum(nil)
@ -1308,11 +1341,7 @@ func work() {
mainStatus = "Incorrect keyfiles." mainStatus = "Incorrect keyfiles."
} }
} }
mainStatusColor = RED broken(fin, nil, mainStatus)
fin.Close()
if recombine {
os.Remove(inputFile)
}
return return
} }
} }
@ -1338,7 +1367,7 @@ func work() {
done, counter := 0, 0 done, counter := 0, 0
chacha, _ := chacha20.NewUnauthenticatedCipher(key, nonce) chacha, _ := chacha20.NewUnauthenticatedCipher(key, nonce)
// Use HKDF-SHA3 to generate a subkey // Use HKDF-SHA3 to generate a subkey for the MAC
var mac hash.Hash var mac hash.Hash
subkey := make([]byte, 32) subkey := make([]byte, 32)
hkdf := hkdf.New(sha3.New256, key, hkdfSalt, nil) hkdf := hkdf.New(sha3.New256, key, hkdfSalt, nil)
@ -1355,14 +1384,12 @@ func work() {
s, _ := serpent.NewCipher(serpentKey) s, _ := serpent.NewCipher(serpentKey)
serpent := cipher.NewCTR(s, serpentSalt) serpent := cipher.NewCTR(s, serpentSalt)
// Start the main encryption process
canCancel = true canCancel = true
startTime := time.Now() startTime := time.Now()
for { for {
// If the user cancels the process, stop and clean up
if !working { if !working {
cancel() cancel(fin, fout)
fin.Close()
fout.Close()
if recombine || len(allFiles) > 1 || len(onlyFolders) > 0 || compress { if recombine || len(allFiles) > 1 || len(onlyFolders) > 0 || compress {
os.Remove(inputFile) os.Remove(inputFile)
} }
@ -1490,11 +1517,10 @@ func work() {
} }
} }
// Write the data to output file
_, err = fout.Write(dst) _, err = fout.Write(dst)
if err != nil { if err != nil {
insufficientSpace() insufficientSpace(fin, fout)
fin.Close()
fout.Close()
if recombine || len(allFiles) > 1 || len(onlyFolders) > 0 || compress { if recombine || len(allFiles) > 1 || len(onlyFolders) > 0 || compress {
os.Remove(inputFile) os.Remove(inputFile)
} }
@ -1520,7 +1546,7 @@ func work() {
} }
giu.Update() giu.Update()
// Change counters after 60 GiB to prevent overflow // Change values after 60 GiB to prevent overflow
if counter >= 60*GiB { if counter >= 60*GiB {
// ChaCha20 // ChaCha20
nonce = make([]byte, 24) nonce = make([]byte, 24)
@ -1556,6 +1582,7 @@ func work() {
// Validate the authenticity of decrypted data // Validate the authenticity of decrypted data
if subtle.ConstantTimeCompare(mac.Sum(nil), authTag) == 0 { if subtle.ConstantTimeCompare(mac.Sum(nil), authTag) == 0 {
// Decrypt again but this time rebuilding the input data
if reedsolo && fastDecode { if reedsolo && fastDecode {
fastDecode = false fastDecode = false
fin.Close() fin.Close()
@ -1563,6 +1590,7 @@ func work() {
work() work()
return return
} }
if keep { if keep {
kept = true kept = true
} else { } else {
@ -1603,6 +1631,7 @@ func work() {
giu.Update() giu.Update()
fin, _ := os.Open(outputFile) fin, _ := os.Open(outputFile)
// Start the splitting process
startTime := time.Now() startTime := time.Now()
for i := 0; i < chunks; i++ { for i := 0; i < chunks; i++ {
// Make the chunk // Make the chunk
@ -1621,40 +1650,30 @@ func work() {
break break
} }
if !working { if !working {
cancel() cancel(fin, fout)
fin.Close()
fout.Close()
if len(allFiles) > 1 || len(onlyFolders) > 0 || compress { if len(allFiles) > 1 || len(onlyFolders) > 0 || compress {
os.Remove(inputFile) os.Remove(inputFile)
} }
os.Remove(outputFile) os.Remove(outputFile)
for _, j := range splitted { // Remove unfinished chunks
// If user cancels, remove the unfinished files
for _, j := range splitted {
os.Remove(j) os.Remove(j)
} }
os.Remove(fmt.Sprintf("%s.%d", outputFile, i)) os.Remove(fmt.Sprintf("%s.%d", outputFile, i))
return return
} }
data = data[:read] data = data[:read]
_, err = fout.Write(data) _, err = fout.Write(data)
if err != nil { if err != nil {
insufficientSpace() insufficientSpace(fin, fout)
fin.Close()
fout.Close()
if len(allFiles) > 1 || len(onlyFolders) > 0 || compress { if len(allFiles) > 1 || len(onlyFolders) > 0 || compress {
os.Remove(inputFile) os.Remove(inputFile)
} }
os.Remove(outputFile) os.Remove(outputFile)
for _, j := range splitted { // Remove unfinished chunks
// If user cancels, remove the unfinished files
for _, j := range splitted {
os.Remove(j) os.Remove(j)
} }
os.Remove(fmt.Sprintf("%s.%d", outputFile, i)) os.Remove(fmt.Sprintf("%s.%d", outputFile, i))
return return
} }
done += read done += read
@ -1694,7 +1713,7 @@ func work() {
os.Remove(inputFile) os.Remove(inputFile)
} }
// Delete the temporary .zip used to encrypt files // Delete the temporary .zip used to encrypt multiple files
if len(allFiles) > 1 || len(onlyFolders) > 0 || compress { if len(allFiles) > 1 || len(onlyFolders) > 0 || compress {
os.Remove(inputFile) os.Remove(inputFile)
} }
@ -1705,7 +1724,7 @@ func work() {
giu.Update() giu.Update()
if mode == "decrypt" { if mode == "decrypt" {
if recombine { // Remove each chunk if recombine { // Remove each chunk of volume
i := 0 i := 0
for { for {
_, err := os.Stat(fmt.Sprintf("%s.%d", inputFileOld, i)) _, err := os.Stat(fmt.Sprintf("%s.%d", inputFileOld, i))
@ -1750,7 +1769,9 @@ func accessDenied(s string) {
} }
// If there isn't enough disk space // If there isn't enough disk space
func insufficientSpace() { func insufficientSpace(fin *os.File, fout *os.File) {
fin.Close()
fout.Close()
mainStatus = "Insufficient disk space." mainStatus = "Insufficient disk space."
mainStatusColor = RED mainStatusColor = RED
} }
@ -1769,8 +1790,10 @@ func broken(fin *os.File, fout *os.File, message string) {
os.Remove(outputFile) os.Remove(outputFile)
} }
// Stop working // Stop working if user hits "Cancel"
func cancel() { func cancel(fin *os.File, fout *os.File) {
fin.Close()
fout.Close()
mainStatus = "Operation cancelled by user." mainStatus = "Operation cancelled by user."
mainStatusColor = WHITE mainStatusColor = WHITE
} }
@ -1860,6 +1883,8 @@ func rsDecode(rs *infectious.FEC, data []byte) ([]byte, error) {
} }
return data[:rs.Total()/3], err return data[:rs.Total()/3], err
} }
// No issues, return the decoded data
return res, nil return res, nil
} }