Update Picocrypt.go

This commit is contained in:
Evan Su 2021-04-25 22:44:46 -04:00 committed by GitHub
parent 3ab5c42e52
commit ccb473703c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 303 additions and 38 deletions

View File

@ -12,18 +12,23 @@ https://github.com/HACKERALERT/Picocrypt
*/
import (
"fmt"
"os"
"fmt"
"math"
"time"
"strings"
"path/filepath"
"strconv"
"image/color"
g "github.com/AllenDang/giu"
ig "github.com/AllenDang/imgui-go"
di "github.com/sqweek/dialog"
"crypto/rand"
"path/filepath"
"golang.org/x/crypto/sha3"
"golang.org/x/crypto/argon2"
"golang.org/x/crypto/blake2b"
g "github.com/AllenDang/giu"
di "github.com/sqweek/dialog"
ig "github.com/AllenDang/imgui-go"
"github.com/klauspost/reedsolomon"
_ "golang.org/x/crypto/argon2"
_ "github.com/HACKERALERT/Monocypher-Go/monocypher"
"golang.org/x/crypto/chacha20poly1305"
)
// Global variables
@ -41,7 +46,9 @@ var inputLabel = "Drag and drop file(s) and folder(s) into this window."
var outputEntry string
var outputWidth float32 = 376
var orLabel = "or"
var progress float32 = 0
var progressInfo = ""
var status = "Ready."
// User input variables
var password string
@ -52,9 +59,12 @@ var erase bool
var reedsolo bool
// Reed-Solomon encoders
var rs5_128,_ = reedsolomon.New(5,128)
var rs10_128,_ = reedsolomon.New(10,128)
var rs16_128,_ = reedsolomon.New(16,128)
var rs24_128,_ = reedsolomon.New(24,128)
var rs32_128,_ = reedsolomon.New(32,128)
var rs64_128,_ = reedsolomon.New(64,128)
// Create the user interface
func startUI(){
@ -128,11 +138,11 @@ func startUI(){
),
// Progress bar
g.ProgressBar(0).Size(-1,0).Overlay(progressInfo),
g.ProgressBar(progress).Size(-1,0).Overlay(progressInfo),
// Status label
g.Dummy(10,0),
g.Label("Ready."),
g.Label(status),
// Credits and version
g.Line(
@ -162,6 +172,9 @@ func onDrop(names []string){
onlyFolders = nil
allFiles = nil
files,folders := 0,0
// Reset UI
resetUI()
// Hide the ".pcv" label
orLabel = "or"
@ -190,6 +203,22 @@ func onDrop(names []string){
mode = "decrypt"
inputLabel = name+" (will decrypt)"
outputEntry = names[0][:len(names[0])-4]
// Open input file in read-only mode
fin,_ := os.Open(names[0])
defer fin.Close()
// Read metadata and insert into box
fin.Read(make([]byte,133))
tmp := make([]byte,138)
fin.Read(tmp)
tmp = rsDecode(tmp,rs10_128,10)
metadataLength,_ := strconv.Atoi(string(tmp))
//fmt.Println(metadataLength)
tmp = make([]byte,metadataLength)
fin.Read(tmp)
metadata = string(tmp)
}else{
mode = "encrypt"
inputLabel = name+" (will encrypt)"
@ -205,6 +234,8 @@ func onDrop(names []string){
// Set the file as 'outputEntry'
outputEntry = names[0]
inputFile = names[0]
}
}else{
// There are multiple dropped items, check each one
@ -267,6 +298,16 @@ func work(){
//headerBroken := false
//reedsoloFixed := 0
//reedsoloErrors := 0
// Declare salt and nonce
var salt []byte
var nonce []byte
var keyHash []byte
var crcHash []byte
var nonces []byte
stat,_ := os.Stat(inputFile)
total := stat.Size()
// Set the output file based on mode
if mode=="encrypt"{
@ -274,62 +315,262 @@ func work(){
}else{
outputFile = outputEntry
}
// Open input file in read-only mode
fin,_ := os.Open(inputFile)
defer fin.Close()
var fout *os.File
// If encrypting, generate values. If decrypting, read values from file
if mode=="encrypt"{
fout,_ := os.OpenFile(
status = "Generating values..."
g.Update()
fout,_ = os.OpenFile(
outputFile,
os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
0666,
os.O_RDWR|os.O_CREATE|os.O_TRUNC,
0755,
)
defer fout.Close()
// Argon2 salt and XChaCha20 nonce
salt := make([]byte,16)
nonce := make([]byte,24)
salt = make([]byte,16)
nonce = make([]byte,24)
// Write version to file
fout.Write(rsEncode([]byte("v1.13"),rs5_128,133))
// Encode the length of the metadata with Reed-Solomon
metadataLength := []byte(fmt.Sprintf("%010d",len(metadata)))
/*shards,_ := rs10_128.Split(metadataLength)
rs10_128.Encode(shards)
tmp := make([]byte,138)
for i,shard := range(shards){
tmp[i] = shard[0]
}
fout.Write(tmp)*/
metadataLength = rsEncode(metadataLength,rs10_128,138)
// Write the length of the metadata to file
fout.Write(metadataLength)
// Write the actual metadata
fout.Write([]byte(metadata))
// Fill salt and nonce with Go's CSPRNG
rand.Read(salt)
rand.Read(nonce)
//fmt.Println("Encrypting salt: ",salt)
//fmt.Println("Encrypting nonce: ",nonce)
// Encode salt with Reed-Solomon and write to file
/*shards,_ = rs16_128.Split(salt)
rs16_128.Encode(shards)
tmp = make([]byte,144)
for i,shard := range(shards){
tmp[i] = shard[0]
}
fout.Write(tmp)*/
salt = rsEncode(salt,rs16_128,144)
fout.Write(salt)
// Encode nonce with Reed-Solomon and write to file
/*shards,_ = rs24_128.Split(nonce)
rs24_128.Encode(shards)
tmp = make([]byte,152)
for i,shard := range(shards){
tmp[i] = shard[0]
}
fout.Write(tmp)*/
nonce = rsEncode(nonce,rs24_128,152)
fout.Write(nonce)
tmp := rsEncode(nonce,rs24_128,152)
fout.Write(tmp)
// Write placeholder for hash of key
fout.Write(make([]byte,192))
// Write placeholder for Blake2 CRC
fout.Write(make([]byte,160))
pairs := int(math.Ceil(float64(total)/1048576))
offset := 152*pairs+144
// Write placeholder for nonce/Poly1305 pairs
fout.Write(make([]byte,offset))
}else{
g.Update()
status = "Reading values..."
version := make([]byte,133)
fin.Read(version)
version = rsDecode(version,rs5_128,5)
tmp := make([]byte,138)
fin.Read(tmp)
tmp = rsDecode(tmp,rs10_128,10)
metadataLength,_ := strconv.Atoi(string(tmp))
fin.Read(make([]byte,metadataLength))
salt = make([]byte,144)
fin.Read(salt)
salt = rsDecode(salt,rs16_128,16)
nonce = make([]byte,152)
fin.Read(nonce)
nonce = rsDecode(nonce,rs24_128,24)
//fmt.Println("Decrypting salt: ",salt)
//fmt.Println("Decrypting nonce: ",nonce)
keyHash = make([]byte,192)
fin.Read(keyHash)
keyHash = rsDecode(keyHash,rs64_128,64)
crcHash = make([]byte,160)
fin.Read(crcHash)
crcHash = rsDecode(crcHash,rs32_128,32)
_tmp := math.Ceil(float64(total-int64(metadataLength+919))/float64(1048744))
nonces = make([]byte,int(_tmp*152)+144)
fin.Read(nonces)
//fmt.Println("Nonces: ",nonces)
}
g.Update()
status = "Deriving key..."
// Derive encryption/decryption key
key := argon2.IDKey(
[]byte(password),
salt,
4,
1048576/2,
4,
32,
)[:]
key = make([]byte,32)
sha3_512 := sha3.New512()
sha3_512.Write(key)
keyHash = sha3_512.Sum(nil)
//fmt.Println("keyHash: ",keyHash)
// Check is password is correct
if mode=="decrypt"{
fout,_ = os.OpenFile(
outputFile,
os.O_RDWR|os.O_CREATE|os.O_TRUNC,
0755,
)
defer fout.Close()
}
crc,_ := blake2b.New256(nil)
done := 0
counter := 0
startTime := time.Now()
cipher,_ := chacha20poly1305.NewX(key)
if mode=="decrypt"{
_mac := nonces[len(nonces)-144:]
_mac = rsDecode(_mac,rs16_128,16)
//fmt.Println("_mac len: ",len(_mac))
nonces = nonces[:len(nonces)-144]
var tmp []byte
var chunk []byte
for i,j := range(nonces){
chunk = append(chunk,j)
if (i+1)%152==0{
chunk = rsDecode(chunk,rs24_128,24)
for _,k := range(chunk){
tmp = append(tmp,k)
}
chunk = nil
}
}
for _,j := range(_mac){
tmp = append(tmp,j)
}
//fmt.Println("ENCRYPTED NONCES: ",tmp)
// XXXXXXXXXXXXXXXXFSFSDFFFSFF
nonces,_ = cipher.Open(nil,nonce,tmp,nil)
//fmt.Println("UNENCRYPTED NONCES: ",nonces)
}
for{
//fmt.Println("Encrypt/decrypt loop")
var _data []byte
var data []byte
var _nonce []byte
if mode=="encrypt"{
_data = make([]byte,1048576)
}else{
_data = make([]byte,1048592)
}
size,err := fin.Read(_data)
if err!=nil{
break
}
data = _data[:size]
if mode=="encrypt"{
_nonce = make([]byte,24)
rand.Read(_nonce)
for _,i := range(_nonce){
nonces = append(nonces,i)
}
}else{
_nonce = nonces[counter*24:counter*24+24]
}
//fmt.Println("Data nonce: ",_nonce)
//fmt.Println("Data: ",data)
if mode=="encrypt"{
data = cipher.Seal(nil,_nonce,data,nil)
crc.Write(data)
fout.Write(data)
}else{
//fmt.Println("DECODE LOOP")
crc.Write(data)
data,_ := cipher.Open(nil,_nonce,data,nil)
fout.Write(data)
//fmt.Println(authentic)
//fmt.Println("DECRYPTED DATA: ",data)
}
done += 1048576
counter++
progress = float32(done)/float32(total)
elapsed:= float64(int64(time.Now().Sub(startTime)))/float64(1000000000)
speed := (float64(done)/elapsed)/1000000
eta := float64(total-int64(done))/(speed*1000000)
progressInfo = fmt.Sprintf("%.2f%%",progress*100)
status = fmt.Sprintf("Working at %.2f MB/s (ETA: %.1fs)",speed,eta)
g.Update()
data = nil
}
if mode=="encrypt"{
//fmt.Println("'nonces' before RS: ",nonces)
fout.Seek(int64(567+len(metadata)),0)
fout.Write(rsEncode(keyHash,rs64_128,192))
fout.Write(rsEncode(crc.Sum(nil),rs32_128,160))
//fmt.Println("UNENCRYPTED NONCES: ",nonces)
tmp := cipher.Seal(nil,nonce,nonces,nil)
//fmt.Println("ENCRYPTED NONCES: ",tmp)
_mac := tmp[len(tmp)-16:]
//fmt.Println("_mac len: ",len(_mac))
tmp = tmp[:len(tmp)-16]
var chunk []byte
//fmt.Println("<Nonces>")
for i,j := range(tmp){
chunk = append(chunk,j)
if (i+1)%24==0{
fout.Write(rsEncode(chunk,rs24_128,152))
//fmt.Println(rsEncode(chunk,rs24_128,152))
chunk = nil
}
}
fout.Write(rsEncode(_mac,rs16_128,144))
//fmt.Println("</Nonces>")
}else{
fmt.Println("crcHash: ",crcHash)
fmt.Println("crc.Sum: ",crc.Sum(nil))
}
fmt.Println("==============================")
resetUI()
status = "Completed."
}
// Reset the UI to a clean state with no nothing selected
@ -338,6 +579,14 @@ func resetUI(){
outputEntry = ""
orLabel = "or"
outputWidth = 376
password = ""
cPassword = ""
metadata = ""
keep = false
erase = false
reedsolo = false
progress = 0
progressInfo = ""
g.Update()
}
@ -351,6 +600,22 @@ func rsEncode(data []byte,encoder reedsolomon.Encoder,size int) []byte{
return tmp
}
func rsDecode(data []byte,encoder reedsolomon.Encoder,size int) []byte{
res := make([][]byte,len(data))
for i,_ := range(data){
tmp := make([]byte,1)
tmp[0] = data[i]
res[i] = tmp
}
_ = encoder.Reconstruct(res)
res = res[:size]
tmp := make([]byte,size)
for i,shard := range(res){
tmp[i] = shard[0]
}
return tmp
}
// Create the master window, set callbacks, and start the UI
func main(){
window := g.NewMasterWindow("Picocrypt",480,470,g.MasterWindowFlagsNotResizable,nil)