refactor: Split keys and keyext packages, make compression, signature and encryption packages public

This commit is contained in:
Felicitas Pojtinger
2022-01-03 14:56:46 +01:00
parent b0a1b61297
commit 5d5b6ebb96
27 changed files with 65 additions and 55 deletions
+141
View File
@@ -0,0 +1,141 @@
package encryption
import (
"archive/tar"
"bytes"
"encoding/base64"
"encoding/json"
"io"
"filippo.io/age"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/pojntfx/stfs/internal/records"
"github.com/pojntfx/stfs/pkg/config"
)
func Decrypt(
src io.Reader,
encryptionFormat string,
identity interface{},
) (io.ReadCloser, error) {
switch encryptionFormat {
case config.EncryptionFormatAgeKey:
identity, ok := identity.(*age.X25519Identity)
if !ok {
return nil, config.ErrIdentityUnparsable
}
r, err := age.Decrypt(src, identity)
if err != nil {
return nil, err
}
return io.NopCloser(r), nil
case config.EncryptionFormatPGPKey:
identity, ok := identity.(openpgp.EntityList)
if !ok {
return nil, config.ErrIdentityUnparsable
}
r, err := openpgp.ReadMessage(src, identity, nil, nil)
if err != nil {
return nil, err
}
return io.NopCloser(r.UnverifiedBody), nil
case config.NoneKey:
return io.NopCloser(src), nil
default:
return nil, config.ErrEncryptionFormatUnsupported
}
}
func DecryptHeader(
hdr *tar.Header,
encryptionFormat string,
identity interface{},
) error {
if encryptionFormat == config.NoneKey {
return nil
}
if hdr.PAXRecords == nil {
return config.ErrTarHeaderEmbeddedMissing
}
encryptedEmbeddedHeader, ok := hdr.PAXRecords[records.STFSRecordEmbeddedHeader]
if !ok {
return config.ErrTarHeaderEmbeddedMissing
}
embeddedHeader, err := DecryptString(encryptedEmbeddedHeader, encryptionFormat, identity)
if err != nil {
return err
}
var newHdr tar.Header
if err := json.Unmarshal([]byte(embeddedHeader), &newHdr); err != nil {
return err
}
*hdr = newHdr
return nil
}
func DecryptString(
src string,
encryptionFormat string,
identity interface{},
) (string, error) {
switch encryptionFormat {
case config.EncryptionFormatAgeKey:
identity, ok := identity.(*age.X25519Identity)
if !ok {
return "", config.ErrIdentityUnparsable
}
decoded, err := base64.StdEncoding.DecodeString(src)
if err != nil {
return "", err
}
r, err := age.Decrypt(bytes.NewBufferString(string(decoded)), identity)
if err != nil {
return "", err
}
out := &bytes.Buffer{}
if _, err := io.Copy(out, r); err != nil {
return "", err
}
return out.String(), nil
case config.EncryptionFormatPGPKey:
identity, ok := identity.(openpgp.EntityList)
if !ok {
return "", config.ErrIdentityUnparsable
}
decoded, err := base64.StdEncoding.DecodeString(src)
if err != nil {
return "", err
}
r, err := openpgp.ReadMessage(bytes.NewBufferString(string(decoded)), identity, nil, nil)
if err != nil {
return "", err
}
out := &bytes.Buffer{}
if _, err := io.Copy(out, r.UnverifiedBody); err != nil {
return "", err
}
return out.String(), nil
case config.NoneKey:
return src, nil
default:
return "", config.ErrEncryptionFormatUnsupported
}
}
+127
View File
@@ -0,0 +1,127 @@
package encryption
import (
"archive/tar"
"bytes"
"encoding/base64"
"encoding/json"
"io"
"filippo.io/age"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/pojntfx/stfs/internal/ioext"
"github.com/pojntfx/stfs/internal/records"
"github.com/pojntfx/stfs/pkg/config"
)
func Encrypt(
dst io.Writer,
encryptionFormat string,
recipient interface{},
) (io.WriteCloser, error) {
switch encryptionFormat {
case config.EncryptionFormatAgeKey:
recipient, ok := recipient.(*age.X25519Recipient)
if !ok {
return nil, config.ErrRecipientUnparsable
}
return age.Encrypt(dst, recipient)
case config.EncryptionFormatPGPKey:
recipient, ok := recipient.(openpgp.EntityList)
if !ok {
return nil, config.ErrRecipientUnparsable
}
return openpgp.Encrypt(dst, recipient, nil, nil, nil)
case config.NoneKey:
return ioext.AddCloseNopToWriter(dst), nil
default:
return nil, config.ErrEncryptionFormatUnsupported
}
}
func EncryptHeader(
hdr *tar.Header,
encryptionFormat string,
recipient interface{},
) error {
if encryptionFormat == config.NoneKey {
return nil
}
newHdr := &tar.Header{
Format: tar.FormatPAX,
Size: hdr.Size,
PAXRecords: map[string]string{},
}
wrappedHeader, err := json.Marshal(hdr)
if err != nil {
return err
}
newHdr.PAXRecords[records.STFSRecordEmbeddedHeader], err = EncryptString(string(wrappedHeader), encryptionFormat, recipient)
if err != nil {
return err
}
*hdr = *newHdr
return nil
}
func EncryptString(
src string,
encryptionFormat string,
recipient interface{},
) (string, error) {
switch encryptionFormat {
case config.EncryptionFormatAgeKey:
recipient, ok := recipient.(*age.X25519Recipient)
if !ok {
return "", config.ErrRecipientUnparsable
}
out := &bytes.Buffer{}
w, err := age.Encrypt(out, recipient)
if err != nil {
return "", err
}
if _, err := io.WriteString(w, src); err != nil {
return "", err
}
if err := w.Close(); err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(out.Bytes()), nil
case config.EncryptionFormatPGPKey:
recipient, ok := recipient.(openpgp.EntityList)
if !ok {
return "", config.ErrRecipientUnparsable
}
out := &bytes.Buffer{}
w, err := openpgp.Encrypt(out, recipient, nil, nil, nil)
if err != nil {
return "", err
}
if _, err := io.WriteString(w, src); err != nil {
return "", err
}
if err := w.Close(); err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(out.Bytes()), nil
case config.NoneKey:
return src, nil
default:
return "", config.ErrEncryptionFormatUnsupported
}
}