142 lines
2.8 KiB
Go
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
|
|
}
|
|
}
|