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