Update Picocrypt.go

This commit is contained in:
Evan Su 2021-05-23 12:38:28 -04:00 committed by GitHub
parent a850a96fe9
commit 10c5d82169
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 159 additions and 89 deletions

View File

@ -12,6 +12,7 @@ https://github.com/HACKERALERT/Picocrypt
*/ */
import ( import (
"io"
"os" "os"
"fmt" "fmt"
"math" "math"
@ -20,6 +21,7 @@ import (
"strconv" "strconv"
"image/color" "image/color"
"crypto/md5" "crypto/md5"
"archive/zip"
"crypto/rand" "crypto/rand"
"crypto/sha1" "crypto/sha1"
"encoding/hex" "encoding/hex"
@ -40,6 +42,8 @@ import (
"github.com/HACKERALERT/Picocypher/monocypher" "github.com/HACKERALERT/Picocypher/monocypher"
) )
var version = "v1.13"
// Global variables // Global variables
var dpi float32 var dpi float32
var mode string var mode string
@ -57,10 +61,13 @@ var outputEntry string
var outputWidth float32 = 376 var outputWidth float32 = 376
var orLabel = "or" var orLabel = "or"
var passwordState = g.InputTextFlags_Password var passwordState = g.InputTextFlags_Password
var passwordToggleString = "Show" var showPassword = false
var keyfile = false
var progress float32 = 0 var progress float32 = 0
var progressInfo = "" var progressInfo = ""
var status = "Ready." var status = "Ready."
var _status = "adfs"
var _status_color = color.RGBA{0xff,0xff,0xff,255}
var items = []string{ var items = []string{
"Fast", "Fast",
"Normal", "Normal",
@ -149,10 +156,11 @@ func startUI(){
}), }),
// Label listing the input files and a button to clear input files // Label listing the input files and a button to clear input files
g.Dummy(30,0), g.Dummy(10,0),
g.Row( g.Row(
g.Label(inputLabel), g.Label(inputLabel),
g.Button("Clear").OnClick(resetUI), g.Dummy(-55,0),
g.Button("Clear").Size(46,0).OnClick(resetUI),
), ),
// Allow user to choose a custom output path and name // Allow user to choose a custom output path and name
@ -179,19 +187,23 @@ func startUI(){
// Prompt for password // Prompt for password
g.Dummy(10,0), g.Dummy(10,0),
g.Label("Password:"), g.Row(
g.Label("Password:"),
g.Dummy(-200,0),
g.Label("Password:"),
),
g.Row( g.Row(
g.InputText("##password",&password).Size(200/dpi).Flags(passwordState), g.InputText("##password",&password).Size(200/dpi).Flags(passwordState),
g.Button(passwordToggleString).OnClick(func(){ g.Checkbox("##showPassword",&showPassword).OnChange(func(){
if passwordState==g.InputTextFlags_Password{ if passwordState==g.InputTextFlags_Password{
passwordState = g.InputTextFlags_None passwordState = g.InputTextFlags_None
passwordToggleString = "Hide"
}else{ }else{
passwordState = g.InputTextFlags_Password passwordState = g.InputTextFlags_Password
passwordToggleString = "Show"
} }
g.Update() g.Update()
}), }),
g.Dummy(-200,0),
g.Checkbox("Use a keyfile",&keyfile),
), ),
// Prompt to confirm password // Prompt to confirm password
@ -202,7 +214,7 @@ func startUI(){
// Optional metadata // Optional metadata
g.Dummy(10,0), g.Dummy(10,0),
g.Label("Metadata (optional):"), g.Label("Metadata (optional):"),
g.InputTextMultiline("##metadata",&metadata).Size(200,80), g.InputTextMultiline("##metadata",&metadata).Size(226,100),
// Advanced options can be enabled with checkboxes // Advanced options can be enabled with checkboxes
g.Dummy(10,0), g.Dummy(10,0),
@ -227,18 +239,9 @@ func startUI(){
go work() go work()
}), }),
/*// Progress bar
g.ProgressBar(progress).Size(-1,0).Overlay(progressInfo),
// Status label
g.Dummy(10,0), g.Dummy(10,0),
g.Label(status),*/ g.Style().SetColor(ig.StyleColor,_status_color).To(
g.Label(_status),
// Credits and version
g.Row(
g.Label("Created by Evan Su. See the About tab for more info."),
g.Dummy(46,0),
g.Label("v1.13"),
), ),
), ),
@ -259,7 +262,7 @@ func startUI(){
), ),
// File checksum generator tab // File checksum generator tab
g.TabItem("Checksum generator").Layout( g.TabItem("Checksum").Layout(
// Update 'tab' to indicate active tab // Update 'tab' to indicate active tab
g.Custom(func(){ g.Custom(func(){
if g.IsItemActive(){ if g.IsItemActive(){
@ -274,12 +277,11 @@ func startUI(){
g.Dummy(10,0), g.Dummy(10,0),
g.Row( g.Row(
g.Checkbox("MD5:",&md5_selected), g.Checkbox("MD5:",&md5_selected),
g.Dummy(360,0), g.Dummy(-45,0),
g.Button("Copy##md5").OnClick(func(){ g.Button("Copy##md5").Size(36,0).OnClick(func(){
clipboard.WriteAll(cs_md5) clipboard.WriteAll(cs_md5)
}), }),
), ), g.Style().SetColor(ig.StyleColorBorder,md5_color).To(
g.Style().SetColor(ig.StyleColorBorder,md5_color).To(
g.InputText("##cs_md5",&cs_md5).Size(-1).Flags(g.InputTextFlags_ReadOnly), g.InputText("##cs_md5",&cs_md5).Size(-1).Flags(g.InputTextFlags_ReadOnly),
), ),
@ -287,8 +289,8 @@ func startUI(){
g.Dummy(10,0), g.Dummy(10,0),
g.Row( g.Row(
g.Checkbox("SHA1:",&sha1_selected), g.Checkbox("SHA1:",&sha1_selected),
g.Dummy(353,0), g.Dummy(-45,0),
g.Button("Copy##sha1").OnClick(func(){ g.Button("Copy##sha1").Size(36,0).OnClick(func(){
clipboard.WriteAll(cs_sha1) clipboard.WriteAll(cs_sha1)
}), }),
), ),
@ -300,8 +302,8 @@ func startUI(){
g.Dummy(10,0), g.Dummy(10,0),
g.Row( g.Row(
g.Checkbox("SHA256:",&sha256_selected), g.Checkbox("SHA256:",&sha256_selected),
g.Dummy(339,0), g.Dummy(-45,0),
g.Button("Copy##sha256").OnClick(func(){ g.Button("Copy##sha256").Size(36,0).OnClick(func(){
clipboard.WriteAll(cs_sha256) clipboard.WriteAll(cs_sha256)
}), }),
), ),
@ -313,8 +315,8 @@ func startUI(){
g.Dummy(10,0), g.Dummy(10,0),
g.Row( g.Row(
g.Checkbox("SHA3-256:",&sha3_256_selected), g.Checkbox("SHA3-256:",&sha3_256_selected),
g.Dummy(325,0), g.Dummy(-45,0),
g.Button("Copy##sha3_256").OnClick(func(){ g.Button("Copy##sha3_256").Size(36,0).OnClick(func(){
clipboard.WriteAll(cs_sha3_256) clipboard.WriteAll(cs_sha3_256)
}), }),
), ),
@ -326,8 +328,8 @@ func startUI(){
g.Dummy(10,0), g.Dummy(10,0),
g.Row( g.Row(
g.Checkbox("BLAKE2b:",&blake2b_selected), g.Checkbox("BLAKE2b:",&blake2b_selected),
g.Dummy(332,0), g.Dummy(-45,0),
g.Button("Copy##blake2b").OnClick(func(){ g.Button("Copy##blake2b").Size(36,0).OnClick(func(){
clipboard.WriteAll(cs_blake2b) clipboard.WriteAll(cs_blake2b)
}), }),
), ),
@ -339,8 +341,8 @@ func startUI(){
g.Dummy(10,0), g.Dummy(10,0),
g.Row( g.Row(
g.Checkbox("BLAKE2s:",&blake2s_selected), g.Checkbox("BLAKE2s:",&blake2s_selected),
g.Dummy(332,0), g.Dummy(-45,0),
g.Button("Copy##blake2s").OnClick(func(){ g.Button("Copy##blake2s").Size(36,0).OnClick(func(){
clipboard.WriteAll(cs_blake2s) clipboard.WriteAll(cs_blake2s)
}), }),
), ),
@ -352,8 +354,8 @@ func startUI(){
g.Dummy(10,0), g.Dummy(10,0),
g.Row( g.Row(
g.Checkbox("BLAKE3:",&blake3_selected), g.Checkbox("BLAKE3:",&blake3_selected),
g.Dummy(339,0), g.Dummy(-45,0),
g.Button("Copy##blake3").OnClick(func(){ g.Button("Copy##blake3").Size(36,0).OnClick(func(){
clipboard.WriteAll(cs_blake3) clipboard.WriteAll(cs_blake3)
}), }),
), ),
@ -406,7 +408,7 @@ func startUI(){
} }
}), }),
g.Dummy(30,0), g.Dummy(30,0),
g.Label("Picocrypt v1.13, created by Evan Su (https://evansu.cc)"), g.Label("Picocrypt "+version+", created by Evan Su (https://evansu.cc)"),
), ),
), ),
), ),
@ -417,17 +419,23 @@ func startUI(){
g.Label("Tips:"), g.Label("Tips:"),
g.Label(" - Choose a strong password with more than 16 characters."), g.Label(" - Choose a strong password with more than 16 characters."),
g.Label(" - Use a unique password that isn't used anywhere else."), g.Label(" - Use a unique password that isn't used anywhere else."),
g.Label(" - Trust no one but yourself and never give out your key."),
g.Label(" - For highly sensitive files, encrypt them while offline."),
g.Label(" - An antivirus can be beneficial to prevent keyloggers."),
g.Label(" - Encrypt your root filesystem for maximal security."),
g.Dummy(0,-50),
// Progress bar // Progress bar
g.ProgressBar(progress).Size(-1,0).Overlay(progressInfo), g.Row(
g.ProgressBar(progress).Size(-54,0).Overlay(progressInfo),
// Status label g.Dummy(-59,0),
g.Button("Cancel").Size(50,0).OnClick(func(){
working = false
}),
),
g.Dummy(10,0), g.Dummy(10,0),
g.Label(status), g.Label(status),
g.Button("Cancel").Size(95,20).OnClick(func(){
working = false
}),
) )
} }
} }
@ -462,6 +470,8 @@ func onDrop(names []string){
// Set 'outputEntry' to 'Encrypted.zip' in the same directory // Set 'outputEntry' to 'Encrypted.zip' in the same directory
outputEntry = filepath.Join(filepath.Dir(names[0]),"Encrypted.zip") outputEntry = filepath.Join(filepath.Dir(names[0]),"Encrypted.zip")
mode = "encrypt"
}else{ }else{
files++ files++
name := filepath.Base(names[0]) name := filepath.Base(names[0])
@ -503,6 +513,7 @@ func onDrop(names []string){
inputFile = names[0] inputFile = names[0]
} }
}else{ }else{
mode = "encrypt"
// There are multiple dropped items, check each one // There are multiple dropped items, check each one
for _,name := range names{ for _,name := range names{
stat,_ := os.Stat(name) stat,_ := os.Stat(name)
@ -568,31 +579,62 @@ func work(){
//headerBroken := false //headerBroken := false
//reedsoloFixed := 0 //reedsoloFixed := 0
//reedsoloErrors := 0 //reedsoloErrors := 0
// Declare salt and nonce
var salt []byte var salt []byte
var nonce []byte var nonce []byte
var keyHash []byte var keyHash []byte
var _keyHash []byte
var crcHash []byte var crcHash []byte
var nonces []byte var nonces []byte
stat,_ := os.Stat(inputFile)
total := stat.Size()
fmt.Println(mode)
// Set the output file based on mode // Set the output file based on mode
if mode=="encrypt"{ if mode=="encrypt"{
outputFile = outputEntry+".pcv" outputFile = outputEntry+".pcv"
// Compress files into a zip archive
if len(allFiles)>1{
rootDir := filepath.Dir(outputEntry)
inputFile = outputEntry
fmt.Println(inputFile)
file,_ := os.Create(inputFile)
defer file.Close()
w := zip.NewWriter(file)
for _,path := range(allFiles){
fmt.Printf("Crawling: %#v\n",path)
if path==inputFile{
continue
}
stat,_ := os.Stat(path)
header,_ := zip.FileInfoHeader(stat)
header.Name = strings.Replace(path,rootDir,"",1)
header.Method = zip.Deflate
writer,_ := w.CreateHeader(header)
file,_ := os.Open(path)
defer file.Close()
io.Copy(writer,file)
}
w.Flush()
w.Close()
}
}else{ }else{
outputFile = outputEntry outputFile = outputEntry
} }
fmt.Println(inputFile)
stat,_ := os.Stat(inputFile)
total := stat.Size()
fmt.Println(total)
// Open input file in read-only mode // Open input file in read-only mode
fin,_ := os.Open(inputFile) fin,_ := os.Open(inputFile)
defer fin.Close() defer fin.Close()
var fout *os.File var fout *os.File
// If encrypting, generate values. If decrypting, read values from file // If encrypting, generate values; If decrypting, read values from file
if mode=="encrypt"{ if mode=="encrypt"{
status = "Generating values..." status = "Generating values..."
g.Update() g.Update()
@ -608,11 +650,13 @@ func work(){
nonce = make([]byte,24) nonce = make([]byte,24)
// Write version to file // Write version to file
fout.Write(rsEncode([]byte("v1.13"),rs5_128,133)) fout.Write(rsEncode([]byte(version),rs5_128,133))
// Encode the length of the metadata with Reed-Solomon // Encode the length of the metadata with Reed-Solomon
metadataLength := []byte(fmt.Sprintf("%010d",len(metadata))) metadataLength := []byte(fmt.Sprintf("%010d",len(metadata)))
//fmt.Println("metadataLength:",metadataLength)
metadataLength = rsEncode(metadataLength,rs10_128,138) metadataLength = rsEncode(metadataLength,rs10_128,138)
// Write the length of the metadata to file // Write the length of the metadata to file
fout.Write(metadataLength) fout.Write(metadataLength)
@ -620,10 +664,10 @@ func work(){
fout.Write([]byte(metadata)) fout.Write([]byte(metadata))
flags := make([]byte,5) flags := make([]byte,5)
fmt.Println(flags)
if fast{ if fast{
flags[0] = 1 flags[0] = 1
} }
//fmt.Println("flags:",flags)
flags = rsEncode(flags,rs5_128,133) flags = rsEncode(flags,rs5_128,133)
fout.Write(flags) fout.Write(flags)
@ -631,8 +675,8 @@ func work(){
rand.Read(salt) rand.Read(salt)
rand.Read(nonce) rand.Read(nonce)
//fmt.Println("Encrypting salt: ",salt) fmt.Println("salt: ",salt)
//fmt.Println("Encrypting nonce: ",nonce) fmt.Println("nonce: ",nonce)
// Encode salt with Reed-Solomon and write to file // Encode salt with Reed-Solomon and write to file
_salt := rsEncode(salt,rs16_128,144) _salt := rsEncode(salt,rs16_128,144)
@ -656,8 +700,8 @@ func work(){
// Write placeholder for nonce/Poly1305 pairs // Write placeholder for nonce/Poly1305 pairs
fout.Write(make([]byte,offset)) fout.Write(make([]byte,offset))
}else{ }else{
g.Update()
status = "Reading values..." status = "Reading values..."
g.Update()
version := make([]byte,133) version := make([]byte,133)
fin.Read(version) fin.Read(version)
version = rsDecode(version,rs5_128,5) version = rsDecode(version,rs5_128,5)
@ -666,13 +710,14 @@ func work(){
fin.Read(tmp) fin.Read(tmp)
tmp = rsDecode(tmp,rs10_128,10) tmp = rsDecode(tmp,rs10_128,10)
metadataLength,_ := strconv.Atoi(string(tmp)) metadataLength,_ := strconv.Atoi(string(tmp))
//fmt.Println("metadataLength",metadataLength)
fin.Read(make([]byte,metadataLength)) fin.Read(make([]byte,metadataLength))
flags := make([]byte,5) flags := make([]byte,133)
fin.Read(flags) fin.Read(flags)
flags = rsDecode(flags,rs5_128,5) flags = rsDecode(flags,rs5_128,5)
fmt.Println(flags) //fmt.Println("flags",flags)
fast = flags[0]==1 fast = flags[0]==1
salt = make([]byte,144) salt = make([]byte,144)
@ -683,50 +728,64 @@ func work(){
fin.Read(nonce) fin.Read(nonce)
nonce = rsDecode(nonce,rs24_128,24) nonce = rsDecode(nonce,rs24_128,24)
//fmt.Println("Decrypting salt: ",salt) fmt.Println("salt: ",salt)
//fmt.Println("Decrypting nonce: ",nonce) fmt.Println("nonce: ",nonce)
keyHash = make([]byte,192) _keyHash = make([]byte,192)
fin.Read(keyHash) fin.Read(_keyHash)
keyHash = rsDecode(keyHash,rs64_128,64) _keyHash = rsDecode(_keyHash,rs64_128,64)
//fmt.Println("keyHash",keyHash)
crcHash = make([]byte,160) crcHash = make([]byte,160)
fin.Read(crcHash) fin.Read(crcHash)
crcHash = rsDecode(crcHash,rs32_128,32) crcHash = rsDecode(crcHash,rs32_128,32)
//fmt.Println("crcHash",crcHash)
_tmp := math.Ceil(float64(total-int64(metadataLength+1063))/float64(1048744)) _tmp := math.Ceil(float64(total-int64(metadataLength+1196))/float64(1048728))
nonces = make([]byte,int(_tmp*152)+144) nonces = make([]byte,int(_tmp*152)+144)
fin.Read(nonces) fin.Read(nonces)
//fmt.Println("Nonces: ",nonces) //fmt.Println("Nonces: ",nonces)
} }
g.Update() g.Update()
status = "Deriving key..." status = "Deriving key..."
fmt.Println("password",[]byte(password))
fmt.Println("salt",salt)
// Derive encryption/decryption key // Derive encryption/decryption key
var mem uint32 = 1048576;
if fast{
mem /= 2
}
key := argon2.IDKey( key := argon2.IDKey(
[]byte(password), []byte(password),
salt, salt,
4, 8,
1048576/2, mem,
4, 8,
32, 32,
)[:] )[:]
fmt.Println("key",key) //fmt.Println("key",key)
//key = make([]byte,32) //key = make([]byte,32)
sha3_512 := sha3.New512() sha3_512 := sha3.New512()
sha3_512.Write(key) sha3_512.Write(key)
keyHash = sha3_512.Sum(nil) keyHash = sha3_512.Sum(nil)
fmt.Println("keyHash: ",keyHash) //fmt.Println("keyHash: ",keyHash)
// Check is password is correct // Check is password is correct
if mode=="decrypt"{ if mode=="decrypt"{
keyCorrect := true
for i,j := range(_keyHash){
if keyHash[i]!=j{
keyCorrect = false
break
}
}
if !keyCorrect{
working = false
_status = "Incorrect password."
return
}
fout,_ = os.OpenFile( fout,_ = os.OpenFile(
outputFile, outputFile,
os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.O_RDWR|os.O_CREATE|os.O_TRUNC,
@ -746,7 +805,7 @@ func work(){
if mode=="decrypt"{ if mode=="decrypt"{
_mac := nonces[len(nonces)-144:] _mac := nonces[len(nonces)-144:]
_mac = rsDecode(_mac,rs16_128,16) _mac = rsDecode(_mac,rs16_128,16)
//fmt.Println("_mac len: ",len(_mac)) //fmt.Println("_mac ",_mac)
nonces = nonces[:len(nonces)-144] nonces = nonces[:len(nonces)-144]
var tmp []byte var tmp []byte
var chunk []byte var chunk []byte
@ -760,16 +819,19 @@ func work(){
chunk = nil chunk = nil
} }
} }
for _,j := range(_mac){ /*for _,j := range(_mac){
tmp = append(tmp,j) tmp = append(tmp,j)
} }*/
//fmt.Println("ENCRYPTED NONCES: ",tmp) //fmt.Println("ENCRYPTED NONCES: ",tmp)
// XXXXXXXXXXXXXXXXFSFSDFFFSFF // XXXXXXXXXXXXXXXXFSFSDFFFSFF
nonces,_ = cipher.Open(nil,nonce,tmp,nil) //nonces,_ = cipher.Open(nil,nonce,tmp,nil)
nonces,_ = monocypher.Unlock(nonces,nonce,key,_mac)
//fmt.Println("UNENCRYPTED NONCES: ",nonces) //fmt.Println("UNENCRYPTED NONCES: ",nonces)
} }
for{ for{
if !working{ if !working{
fout.Close()
os.Remove(outputFile)
return return
} }
//fmt.Println("Encrypt/decrypt loop") //fmt.Println("Encrypt/decrypt loop")
@ -805,19 +867,23 @@ func work(){
if fast{ if fast{
data = cipher.Seal(nil,_nonce,data,nil) data = cipher.Seal(nil,_nonce,data,nil)
fout.Write(data) fout.Write(data)
//crc.Write(data)
}else{ }else{
mac,data := monocypher.Lock(data,_nonce,key) mac,data := monocypher.Lock(data,_nonce,key)
fout.Write(data) fout.Write(data)
fout.Write(mac) fout.Write(mac)
crc.Write(data)
crc.Write(mac)
} }
crc.Write(data)
//fout.Write(data) //fout.Write(data)
}else{ }else{
//fmt.Println("DECODE LOOP") //fmt.Println("DECODE LOOP")
crc.Write(data) //crc.Write(data)
if fast{ if fast{
data,_ = cipher.Open(nil,_nonce,data,nil) data,_ = cipher.Open(nil,_nonce,data,nil)
}else{ }else{
crc.Write(data)
mac := data[len(data)-16:] mac := data[len(data)-16:]
data = data[:len(data)-16] data = data[:len(data)-16]
data,_ = monocypher.Unlock(data,_nonce,key,mac) data,_ = monocypher.Unlock(data,_nonce,key,mac)
@ -846,15 +912,16 @@ func work(){
if mode=="encrypt"{ if mode=="encrypt"{
//fmt.Println("'nonces' before RS: ",nonces) //fmt.Println("'nonces' before RS: ",nonces)
fout.Seek(int64(567+len(metadata)),0) fout.Seek(int64(700+len(metadata)),0)
fout.Write(rsEncode(keyHash,rs64_128,192)) fout.Write(rsEncode(keyHash,rs64_128,192))
fout.Write(rsEncode(crc.Sum(nil),rs32_128,160)) fout.Write(rsEncode(crc.Sum(nil),rs32_128,160))
//fmt.Println("UNENCRYPTED NONCES: ",nonces)
tmp := cipher.Seal(nil,nonce,nonces,nil) _mac,tmp := monocypher.Lock(nonces,nonce,key)
//tmp := cipher.Seal(nil,nonce,nonces,nil)
//fmt.Println("ENCRYPTED NONCES: ",tmp) //fmt.Println("ENCRYPTED NONCES: ",tmp)
_mac := tmp[len(tmp)-16:] //_mac := tmp[len(tmp)-16:]
//fmt.Println("_mac len: ",len(_mac))
tmp = tmp[:len(tmp)-16] //tmp = tmp[:len(tmp)-16]
var chunk []byte var chunk []byte
//fmt.Println("<Nonces>") //fmt.Println("<Nonces>")
for i,j := range(tmp){ for i,j := range(tmp){
@ -868,8 +935,13 @@ func work(){
fout.Write(rsEncode(_mac,rs16_128,144)) fout.Write(rsEncode(_mac,rs16_128,144))
//fmt.Println("</Nonces>") //fmt.Println("</Nonces>")
}else{ }else{
fmt.Println("crcHash: ",crcHash) //fmt.Println("crcHash: ",crcHash)
fmt.Println("crc.Sum: ",crc.Sum(nil)) //fmt.Println("crc.Sum: ",crc.Sum(nil))
}
// Delete the temporary zip file
if len(allFiles)>1{
os.Remove(outputEntry)
} }
fmt.Println("==============================") fmt.Println("==============================")
resetUI() resetUI()
@ -1029,9 +1101,7 @@ func rsDecode(data []byte,encoder reedsolomon.Encoder,size int) []byte{
// Create the master window, set callbacks, and start the UI // Create the master window, set callbacks, and start the UI
func main(){ func main(){
var width int = 480 window := g.NewMasterWindow("Picocrypt",480,496,g.MasterWindowFlagsNotResizable,nil)
var height int = 500
window := g.NewMasterWindow("Picocrypt",width,height,g.MasterWindowFlagsNotResizable)
window.SetDropCallback(onDrop) window.SetDropCallback(onDrop)
dpi = g.Context.GetPlatform().GetContentScale() dpi = g.Context.GetPlatform().GetContentScale()
window.Run(startUI) window.Run(startUI)