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