Browse Source

Initial commit for file encryption tool

master
Tovi Jaeschke-Rogers 4 years ago
commit
f1b1368afd
7 changed files with 436 additions and 0 deletions
  1. +28
    -0
      Encryption/CreateCipherBlock.go
  2. +101
    -0
      Encryption/Decrypt.go
  3. +95
    -0
      Encryption/Edit.go
  4. +71
    -0
      Encryption/Encrypt.go
  5. +34
    -0
      Encryption/SecureDelete.go
  6. BIN
      fenc
  7. +107
    -0
      main.go

+ 28
- 0
Encryption/CreateCipherBlock.go View File

@ -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
}

+ 101
- 0
Encryption/Decrypt.go View File

@ -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
}

+ 95
- 0
Encryption/Edit.go View File

@ -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
}

+ 71
- 0
Encryption/Encrypt.go View File

@ -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
}

+ 34
- 0
Encryption/SecureDelete.go View File

@ -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
}

BIN
fenc View File


+ 107
- 0
main.go View File

@ -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)
}
}
}

Loading…
Cancel
Save