Files
stfs/internal/encryption/decrypt.go
2021-12-07 21:12:23 +01:00

142 lines
2.8 KiB
Go

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/pax"
"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.ErrEmbeddedHeaderMissing
}
encryptedEmbeddedHeader, ok := hdr.PAXRecords[pax.STFSRecordEmbeddedHeader]
if !ok {
return config.ErrEmbeddedHeaderMissing
}
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
}
}