package main import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/md5" "crypto/rand" "fmt" "io" "io/ioutil" "os" "regexp" "strings" "syscall" "github.com/h2non/filetype" "golang.org/x/crypto/ssh/terminal" ) var debug bool = true var FileName string var HDNFhead []byte = []byte("HDNF") var hdnfType = filetype.NewType("hdn","application/hns") func checkErr(err error) { if err != nil { if debug { panic(err.Error()) } else { os.Exit(1) } } } func keyMkr(passwd string) []byte { key := md5.New() key.Write([]byte(passwd)) return key.Sum(nil) } func encrypt(data []byte, key []byte) []byte { block, err := aes.NewCipher(key) checkErr(err) gcm, err := cipher.NewGCM(block) checkErr(err) nonce := make([]byte, gcm.NonceSize()) _ , err= io.ReadFull(rand.Reader, nonce) checkErr(err) sealed := gcm.Seal(nonce, nonce, data, nil) return sealed } func decrypt(sealed []byte, key []byte) []byte { block, err := aes.NewCipher(key) checkErr(err) gcm, err := cipher.NewGCM(block) nonceSize := gcm.NonceSize() nonce, ctxt := sealed[:nonceSize], sealed[nonceSize:] data, err := gcm.Open(nil, nonce, ctxt, nil) checkErr(err) return data } func file2data(filename string) []byte { data, err := ioutil.ReadFile(filename) checkErr(err) return data } func data2file(filename string, data []byte) { f, err := os.Create(filename) checkErr(err) defer f.Close() f.Write(data) } func getMode() string { var mode string match, _ := regexp.Match(`.*\.hdn$`,[]byte(FileName)) if match { return "s" } fmt.Print("mode: ") fmt.Fscan(os.Stdin, &mode) if mode == "q" {os.Exit(1)} if mode != "h" && mode != "s" { fmt.Println("not a mode") fmt.Println("type 'h' for hide, 's' for show or 'q' to quit") mode = getMode() } return mode } func readFn() string { var filename string arg := os.Args[1:] if len(arg) != 1 { fmt.Println("hns only takes file name as arg") os.Exit(1) } fn := arg[0] if _, err := os.Stat(fn); err == nil { filename = fn } else { fmt.Println("No such file") os.Exit(1) } return filename } func readPass() string { pw, err := terminal.ReadPassword(int(syscall.Stdin)) checkErr(err) return string(pw) } func checkPass() string { var pw string fmt.Print("password: ") pw1 := readPass() fmt.Print("\nagain: ") pw2 := readPass() fmt.Print("\n") if pw1 == pw2 { pw = pw1 } else { fmt.Println("passwords don't match") checkPass() } return pw } func headerAdd(data []byte) []byte { return bytes.Join([][]byte{HDNFhead,data},nil) } func headerRemove(data []byte) []byte { return bytes.TrimPrefix(data,HDNFhead) } func hdnfMatcher(buf []byte) bool { return len(buf) > 1 && buf[0] == 0x48 && buf[1] == 0x44 && buf[2] == 0x4e && buf[3] == 0x46 } func main() { FileName = readFn() filetype.AddMatcher(hdnfType, hdnfMatcher) fn := FileName fmt.Println(fn) buf := file2data(FileName) if filetype.IsType(buf,hdnfType) { fmt.Println("this is an hidden file") fmt.Print("password: ") pw := readPass() fmt.Print("\n") key := keyMkr(pw) secret := headerRemove(buf) datafn := strings.TrimRight(fn,".hdn") data := decrypt(secret, key) data2file(datafn, data) } else { fmt.Println("not hidden") pw := checkPass() key := keyMkr(pw) secret := headerAdd(encrypt(buf,key)) secretfn := fn + ".hdn" clearfn := fn + ".origin" err := os.Rename(fn,clearfn) checkErr(err) data2file(secretfn,secret) fmt.Printf("think about shredding %s\n", clearfn) } }