You've already forked rsa-file-encryption
inital working commit
This commit is contained in:
165
crypt/file.go
Normal file
165
crypt/file.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package crypt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type EncryptedFile struct {
|
||||
ciphertext []byte
|
||||
plainText []byte
|
||||
nonce []byte
|
||||
privatePem []byte
|
||||
PublicPem []byte
|
||||
privateKey *rsa.PrivateKey
|
||||
PublicKey *rsa.PublicKey
|
||||
symmetricKey []byte
|
||||
symmetricKeyEnc []byte
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) packFile() []byte {
|
||||
file := append(f.nonce, f.ciphertext...)
|
||||
return append(file, f.symmetricKeyEnc...)
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) EncryptFile() error {
|
||||
c, err := aes.NewCipher(f.symmetricKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.nonce = make([]byte, aes.BlockSize)
|
||||
_, err = rand.Read(f.nonce)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cbc := cipher.NewCBCEncrypter(c, f.nonce)
|
||||
ciphertext := make([]byte, len(f.plainText))
|
||||
ciphertext = pad(ciphertext, aes.BlockSize)
|
||||
plaintextP := pad(f.plainText, aes.BlockSize)
|
||||
|
||||
cbc.CryptBlocks(ciphertext, plaintextP)
|
||||
f.ciphertext = ciphertext
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) OsReadPlainTextFile(path string) error {
|
||||
plaintext, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.plainText = plaintext
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) WriteEncryptFileToDisk(filePath string) error {
|
||||
packed := f.packFile()
|
||||
|
||||
err := os.WriteFile(filePath+".enc", packed, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) WriteDecryptedFileToDisk(filePath string) error {
|
||||
err := os.WriteFile(filePath, f.plainText, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) unpackFileAndDecrypt(packedFile []byte) error {
|
||||
keyLen := f.privateKey.Size()
|
||||
|
||||
lenWithoutKey := len(packedFile) - keyLen
|
||||
|
||||
packedFile, f.symmetricKeyEnc = packedFile[0:lenWithoutKey], packedFile[lenWithoutKey:]
|
||||
|
||||
err := f.decryptSymmetricKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, err := aes.NewCipher(f.symmetricKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.nonce, f.ciphertext = packedFile[0:aes.BlockSize], packedFile[aes.BlockSize:]
|
||||
|
||||
cbc := cipher.NewCBCDecrypter(a, f.nonce)
|
||||
|
||||
plainText := make([]byte, len(f.ciphertext))
|
||||
|
||||
cbc.CryptBlocks(plainText, f.ciphertext)
|
||||
|
||||
f.plainText, err = unPad(plainText)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) OsReadCipherTextFile(path string) error {
|
||||
packedFile, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = f.unpackFileAndDecrypt(packedFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func pad(buf []byte, size int) []byte {
|
||||
if size < 1 || size > 255 {
|
||||
panic(fmt.Sprintf("pkcs7pad: inappropriate block size %d", size))
|
||||
}
|
||||
i := size - (len(buf) % size)
|
||||
return append(buf, bytes.Repeat([]byte{byte(i)}, i)...)
|
||||
}
|
||||
|
||||
func unPad(buf []byte) ([]byte, error) {
|
||||
if len(buf) == 0 {
|
||||
return nil, fmt.Errorf("pkcs7pad: bad padding")
|
||||
}
|
||||
|
||||
padLen := buf[len(buf)-1]
|
||||
toCheck := 255
|
||||
good := 1
|
||||
if toCheck > len(buf) {
|
||||
toCheck = len(buf)
|
||||
}
|
||||
for i := 0; i < toCheck; i++ {
|
||||
b := buf[len(buf)-1-i]
|
||||
|
||||
outOfRange := subtle.ConstantTimeLessOrEq(int(padLen), i)
|
||||
equal := subtle.ConstantTimeByteEq(padLen, b)
|
||||
good &= subtle.ConstantTimeSelect(outOfRange, 1, equal)
|
||||
}
|
||||
|
||||
good &= subtle.ConstantTimeLessOrEq(1, int(padLen))
|
||||
good &= subtle.ConstantTimeLessOrEq(int(padLen), len(buf))
|
||||
|
||||
if good != 1 {
|
||||
return nil, fmt.Errorf("pkcs7pad: bad padding")
|
||||
}
|
||||
|
||||
return buf[:len(buf)-int(padLen)], nil
|
||||
}
|
||||
130
crypt/keys.go
Normal file
130
crypt/keys.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package crypt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"os"
|
||||
)
|
||||
|
||||
func (f *EncryptedFile) encryptSymmetricKey() error {
|
||||
hash := sha512.New()
|
||||
ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, f.PublicKey, f.symmetricKey, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.symmetricKeyEnc = ciphertext
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) decryptSymmetricKey() error {
|
||||
hash := sha512.New()
|
||||
plaintext, err := rsa.DecryptOAEP(hash, rand.Reader, f.privateKey, f.symmetricKeyEnc, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.symmetricKey = plaintext
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) OsReadPublicKey(path string) error {
|
||||
pemKey, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.PublicPem = pemKey
|
||||
err = f.ParsePublicPem()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) OsReadPrivateKey(path string) error {
|
||||
pemKey, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.privatePem = pemKey
|
||||
|
||||
err = f.ParsePrivatePem()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) GenerateSymmetricKey() error {
|
||||
symKey := make([]byte, 32)
|
||||
_, err := rand.Read(symKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.symmetricKey = symKey
|
||||
|
||||
err = f.encryptSymmetricKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) ParsePublicPem() error {
|
||||
pemKeyBin, _ := pem.Decode(f.PublicPem)
|
||||
|
||||
if bytes.Contains(f.PublicPem, []byte("-----BEGIN PUBLIC KEY-----")) {
|
||||
key, err := x509.ParsePKIXPublicKey(pemKeyBin.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.PublicKey = key.(*rsa.PublicKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
pubKey, err := x509.ParsePKCS1PublicKey(pemKeyBin.Bytes)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.PublicKey = pubKey
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EncryptedFile) ParsePrivatePem() error {
|
||||
pemKeyBin, _ := pem.Decode(f.privatePem)
|
||||
|
||||
if bytes.Contains(f.privatePem, []byte("-----BEGIN PRIVATE KEY-----")) {
|
||||
key, err := x509.ParsePKCS8PrivateKey(pemKeyBin.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.privateKey = key.(*rsa.PrivateKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
privKey, err := x509.ParsePKCS1PrivateKey(pemKeyBin.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.privateKey = privKey
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user