| @ -0,0 +1,28 @@ | |||
| package Encryption | |||
| import ( | |||
| "crypto/aes" | |||
| "crypto/cipher" | |||
| "crypto/hmac" | |||
| "crypto/sha256" | |||
| "hash" | |||
| ) | |||
| func CreateHash(key string) []byte { | |||
| var h hash.Hash | |||
| h = hmac.New(sha256.New, []byte(key)) | |||
| h.Write([]byte(key)) | |||
| return h.Sum(nil) | |||
| } | |||
| func CreateKey(hashedKey []byte) (cipher.Block, error) { | |||
| var ( | |||
| block cipher.Block | |||
| e error | |||
| ) | |||
| block, e = aes.NewCipher(hashedKey) | |||
| if e != nil { | |||
| return nil, e | |||
| } | |||
| return block, nil | |||
| } | |||
| @ -0,0 +1,101 @@ | |||
| package Encryption | |||
| import ( | |||
| "bytes" | |||
| "crypto/aes" | |||
| "crypto/cipher" | |||
| "errors" | |||
| "io" | |||
| "io/ioutil" | |||
| "os" | |||
| ) | |||
| func DecryptData(password string, ciphertext []byte) ([]byte, error) { | |||
| var ( | |||
| hashedKey []byte | |||
| iv []byte | |||
| encKey []byte | |||
| block cipher.Block | |||
| stream cipher.Stream | |||
| e error | |||
| ) | |||
| hashedKey = CreateHash(password) | |||
| if len(ciphertext) == 0 { | |||
| return []byte{}, errors.New("Invalid length") | |||
| } | |||
| iv = ciphertext[:aes.BlockSize] | |||
| encKey = ciphertext[:32+aes.BlockSize][aes.BlockSize:] | |||
| ciphertext = ciphertext[aes.BlockSize+32:] | |||
| block, e = CreateKey(hashedKey) | |||
| if e != nil { | |||
| return []byte{}, e | |||
| } | |||
| stream = cipher.NewCFBDecrypter(block, iv) | |||
| stream.XORKeyStream(encKey, encKey) | |||
| for i := range encKey { | |||
| if encKey[i] != hashedKey[i] { | |||
| return []byte{}, errors.New("Incorrect Password") | |||
| } | |||
| } | |||
| stream.XORKeyStream(ciphertext, ciphertext) | |||
| return ciphertext, nil | |||
| } | |||
| func DecryptFile(password string, FilePath string) error { | |||
| var ( | |||
| OldFilePath string | |||
| ciphertext []byte | |||
| plaintext []byte | |||
| plaintextFile *os.File | |||
| e error | |||
| ) | |||
| OldFilePath = FilePath[:(len(FilePath) - 4)] | |||
| ciphertext, e = ioutil.ReadFile(FilePath) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| if len(ciphertext) < aes.BlockSize { | |||
| return errors.New("ciphertext too short") | |||
| } | |||
| plaintext, e = DecryptData(password, ciphertext) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| plaintextFile, e = os.Create(OldFilePath) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| _, e = io.Copy(plaintextFile, bytes.NewReader(plaintext)) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| os.Remove(FilePath) | |||
| return nil | |||
| } | |||
| func DecryptAndReadFile(password string, FilePath string) (string, error) { | |||
| var ( | |||
| ciphertext []byte | |||
| plaintext []byte | |||
| e error | |||
| ) | |||
| ciphertext, e = ioutil.ReadFile(FilePath) | |||
| if e != nil { | |||
| return "", e | |||
| } | |||
| if len(ciphertext) < aes.BlockSize { | |||
| return "", errors.New("ciphertext too short") | |||
| } | |||
| plaintext, e = DecryptData(password, ciphertext) | |||
| if e != nil { | |||
| return "", e | |||
| } | |||
| return string(plaintext), nil | |||
| } | |||
| @ -0,0 +1,95 @@ | |||
| package Encryption | |||
| import ( | |||
| "fmt" | |||
| "bytes" | |||
| "crypto/aes" | |||
| "errors" | |||
| "os" | |||
| "os/exec" | |||
| "io/ioutil" | |||
| "io" | |||
| ) | |||
| func EditEncryptedFile(password string, FilePath string) (error) { | |||
| var ( | |||
| editor string | |||
| tmpFilePath string | |||
| ciphertext []byte | |||
| plaintext []byte | |||
| tmpFile *os.File | |||
| encryptedFile *os.File | |||
| cmd *exec.Cmd | |||
| e error | |||
| ) | |||
| editor = os.Getenv("EDITOR") | |||
| if editor == "" { | |||
| return errors.New("EDITOR variable cannot be blank") | |||
| } | |||
| tmpFilePath = "/tmp/klsadjhflk" | |||
| ciphertext, e = ioutil.ReadFile(FilePath) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| if len(ciphertext) < aes.BlockSize { | |||
| return errors.New("ciphertext too short") | |||
| } | |||
| plaintext, e = DecryptData(password, ciphertext) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| tmpFile, e = os.Create(tmpFilePath) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| _, e = io.Copy(tmpFile, bytes.NewReader(plaintext)) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| e = tmpFile.Close() | |||
| if e != nil { | |||
| return e | |||
| } | |||
| cmd = exec.Command(editor, tmpFilePath) | |||
| cmd.Stdout = os.Stdout | |||
| cmd.Stdin = os.Stdin | |||
| cmd.Stderr = os.Stderr | |||
| e = cmd.Run() | |||
| if (e != nil) { | |||
| return e | |||
| } | |||
| plaintext, e = ioutil.ReadFile(tmpFilePath) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| ciphertext, e = EncryptData(password, plaintext) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| // open output file | |||
| encryptedFile, e = os.OpenFile(FilePath, os.O_RDWR, 0666) | |||
| if e != nil { | |||
| fmt.Println(1) | |||
| return e | |||
| } | |||
| defer func() { | |||
| encryptedFile.Close() | |||
| SecureDelete(tmpFilePath) | |||
| }() | |||
| _, e = io.Copy(encryptedFile, bytes.NewReader(ciphertext)) | |||
| if e != nil { | |||
| fmt.Println(2) | |||
| return e | |||
| } | |||
| return nil | |||
| } | |||
| @ -0,0 +1,71 @@ | |||
| package Encryption | |||
| import ( | |||
| "bytes" | |||
| "crypto/aes" | |||
| "crypto/cipher" | |||
| "crypto/rand" | |||
| "io" | |||
| "io/ioutil" | |||
| "os" | |||
| ) | |||
| func EncryptData(password string, data []byte) ([]byte, error) { | |||
| var ( | |||
| hashedKey []byte | |||
| ciphertext []byte | |||
| iv []byte | |||
| block cipher.Block | |||
| stream cipher.Stream | |||
| e error | |||
| ) | |||
| hashedKey = CreateHash(password) | |||
| ciphertext = make([]byte, aes.BlockSize+len(hashedKey)+len(data)) | |||
| iv = ciphertext[:aes.BlockSize] | |||
| if _, e = io.ReadFull(rand.Reader, iv); e != nil { | |||
| return []byte{}, e | |||
| } | |||
| block, e = CreateKey(hashedKey) | |||
| if e != nil { | |||
| return []byte{}, e | |||
| } | |||
| stream = cipher.NewCFBEncrypter(block, iv) | |||
| stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(hashedKey)) | |||
| stream.XORKeyStream(ciphertext[aes.BlockSize+len([]byte(hashedKey)):], data) | |||
| return ciphertext, nil | |||
| } | |||
| func EncryptFile(password string, FilePath string) error { | |||
| var ( | |||
| plaintext []byte | |||
| ciphertext []byte | |||
| encryptedFile *os.File | |||
| e error | |||
| ) | |||
| plaintext, e = ioutil.ReadFile(FilePath) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| ciphertext, e = EncryptData(password, plaintext) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| // open output file | |||
| encryptedFile, e = os.Create(FilePath + ".enc") | |||
| if e != nil { | |||
| return e | |||
| } | |||
| defer func() { | |||
| encryptedFile.Close() | |||
| SecureDelete(FilePath) | |||
| }() | |||
| _, e = io.Copy(encryptedFile, bytes.NewReader(ciphertext)) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| return nil | |||
| } | |||
| @ -0,0 +1,34 @@ | |||
| package Encryption | |||
| import ( | |||
| "os" | |||
| ) | |||
| func SecureDelete(FilePath string) error { | |||
| var ( | |||
| file *os.File | |||
| fileInfo os.FileInfo | |||
| size int64 | |||
| zeroBytes []byte | |||
| e error | |||
| ) | |||
| file, _ = os.OpenFile(FilePath, os.O_RDWR, 0666) | |||
| defer file.Close() | |||
| // Find out how large is the target file | |||
| fileInfo, e = file.Stat() | |||
| if e != nil { | |||
| return e | |||
| } | |||
| size = fileInfo.Size() | |||
| // Create byte array filled with zero's | |||
| zeroBytes = make([]byte, size) | |||
| _, e = file.Write([]byte(zeroBytes)) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| e = os.Remove(FilePath) | |||
| if e != nil { | |||
| return e | |||
| } | |||
| return nil | |||
| } | |||
| @ -0,0 +1,107 @@ | |||
| package main | |||
| import ( | |||
| "flag" | |||
| "fmt" | |||
| "os" | |||
| "syscall" | |||
| "golang.org/x/crypto/ssh/terminal" | |||
| "gitlab.com/tovijaeschke/FileEncryption/Encryption" | |||
| ) | |||
| func getPassword() (string, error) { | |||
| var ( | |||
| bytePassword []byte | |||
| e error | |||
| ) | |||
| fmt.Print("Enter Password: ") | |||
| bytePassword, e = terminal.ReadPassword(int(syscall.Stdin)) | |||
| if e != nil { | |||
| return "", e | |||
| } | |||
| return string(bytePassword), nil | |||
| } | |||
| func main() { | |||
| var ( | |||
| files []string | |||
| decrypt *bool | |||
| read *bool | |||
| edit *bool | |||
| plaintext string | |||
| password string | |||
| e error | |||
| ) | |||
| flag.Usage = func() { | |||
| fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [OPTIONS]... [FILES]...\n", os.Args[0]) | |||
| fmt.Println("\t-d: Decrypt files") | |||
| fmt.Println("\t-r: Decrypt and read files to stdout") | |||
| fmt.Println("\t-e: Edit encrypted file") | |||
| } | |||
| decrypt = flag.Bool("d", false, "Decrypt the file(s)") | |||
| read = flag.Bool("r", false, "Read file to stdout") | |||
| edit = flag.Bool("e", false, "Edit encrypted file") | |||
| flag.Parse() | |||
| files = flag.Args() | |||
| if len(files) == 0 { | |||
| flag.Usage() | |||
| fmt.Println("Files cannot be null") | |||
| os.Exit(1) | |||
| } | |||
| password, e = getPassword() | |||
| if e != nil { | |||
| fmt.Println(e.Error()) | |||
| os.Exit(1) | |||
| } | |||
| if *decrypt { | |||
| for _, file := range files { | |||
| e = Encryption.DecryptFile(password, file) | |||
| if e != nil { | |||
| fmt.Println(e.Error()) | |||
| os.Exit(1) | |||
| } | |||
| } | |||
| os.Exit(0) | |||
| } | |||
| if *read { | |||
| for _, file := range files { | |||
| plaintext, e = Encryption.DecryptAndReadFile(password, file) | |||
| if e != nil { | |||
| fmt.Println(e.Error()) | |||
| os.Exit(1) | |||
| } | |||
| fmt.Println(file) | |||
| fmt.Println(plaintext) | |||
| } | |||
| os.Exit(0) | |||
| } | |||
| if *edit { | |||
| for _, file := range files { | |||
| e = Encryption.EditEncryptedFile(password, file) | |||
| if e != nil { | |||
| fmt.Println(e.Error()) | |||
| os.Exit(1) | |||
| } | |||
| } | |||
| os.Exit(0) | |||
| } | |||
| for _, file := range files { | |||
| e = Encryption.EncryptFile(password, file) | |||
| if e != nil { | |||
| fmt.Println(e.Error()) | |||
| os.Exit(1) | |||
| } | |||
| } | |||
| } | |||