174b5f9048
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
125 lines
3.2 KiB
Go
125 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"git.tswf.io/infra/go-synapse-backupper/pkg/adapters/crypto/composite"
|
|
"git.tswf.io/infra/go-synapse-backupper/pkg/adapters/crypto/keymanager"
|
|
"git.tswf.io/infra/go-synapse-backupper/pkg/adapters/crypto/mlkem768"
|
|
"git.tswf.io/infra/go-synapse-backupper/pkg/adapters/crypto/x25519"
|
|
"git.tswf.io/infra/go-synapse-backupper/pkg/domain/crypto"
|
|
)
|
|
|
|
var (
|
|
newRestoreKeyManager = keymanager.NewKeyManager
|
|
newRestoreDecryptor = func(registry crypto.Registry) crypto.Decryptor {
|
|
return composite.NewDecryptor(registry)
|
|
}
|
|
restoreOutput io.Writer = os.Stdout
|
|
restoreOsOpen = os.Open
|
|
)
|
|
|
|
var restoreCmd = &cobra.Command{
|
|
Use: "restore",
|
|
Short: "Restore a backup from a .pqenc file",
|
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
|
privkeyPq, _ := cmd.Flags().GetString("privkey-pq")
|
|
privkeyClassical, _ := cmd.Flags().GetString("privkey-classical")
|
|
|
|
var pqMissing bool
|
|
if _, err := os.Stat(privkeyPq); err != nil {
|
|
pqMissing = true
|
|
}
|
|
|
|
var classicalMissing bool
|
|
if _, err := os.Stat(privkeyClassical); err != nil {
|
|
classicalMissing = true
|
|
}
|
|
|
|
if pqMissing || classicalMissing {
|
|
return fmt.Errorf(
|
|
"--privkey-pq and --privkey-classical are both required (AND model)",
|
|
)
|
|
}
|
|
return nil
|
|
},
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
inPath, _ := cmd.Flags().GetString("in")
|
|
outPath, _ := cmd.Flags().GetString("out")
|
|
privkeyPq, _ := cmd.Flags().GetString("privkey-pq")
|
|
privkeyClassical, _ := cmd.Flags().GetString("privkey-classical")
|
|
|
|
inFile, err := restoreOsOpen(inPath)
|
|
if err != nil {
|
|
return fmt.Errorf("open input file: %w", err)
|
|
}
|
|
defer inFile.Close()
|
|
|
|
registry := crypto.NewRegistry()
|
|
_ = registry.Register(
|
|
0x0006,
|
|
func() crypto.KEM { return mlkem768.New() },
|
|
)
|
|
_ = registry.Register(
|
|
0x0007,
|
|
func() crypto.KEM { return x25519.New() },
|
|
)
|
|
|
|
keyManager := newRestoreKeyManager(registry)
|
|
|
|
pqPriv, err := keyManager.LoadPriv(privkeyPq, 0x0006)
|
|
if err != nil {
|
|
return fmt.Errorf("load PQ private key: %w", err)
|
|
}
|
|
|
|
classicalPriv, err := keyManager.LoadPriv(privkeyClassical, 0x0007)
|
|
if err != nil {
|
|
return fmt.Errorf("load classical private key: %w", err)
|
|
}
|
|
|
|
var out io.Writer
|
|
if outPath != "" {
|
|
outFile, err := os.Create(outPath)
|
|
if err != nil {
|
|
return fmt.Errorf("create output file: %w", err)
|
|
}
|
|
defer outFile.Close()
|
|
out = outFile
|
|
} else {
|
|
out = restoreOutput
|
|
}
|
|
|
|
decryptor := newRestoreDecryptor(registry)
|
|
privateKeys := make([]crypto.RecipientPriv, 0, 2)
|
|
privateKeys = append(privateKeys, pqPriv, classicalPriv)
|
|
if err := decryptor.Decrypt(
|
|
inFile,
|
|
privateKeys,
|
|
out,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
restoreCmd.Flags().String("in", "", "Input .pqenc file path")
|
|
restoreCmd.Flags().String("privkey-pq", "", "Path to PQ private key PEM")
|
|
restoreCmd.Flags().String(
|
|
"privkey-classical",
|
|
"",
|
|
"Path to classical private key PEM",
|
|
)
|
|
restoreCmd.Flags().String("out", "", "Output file path (empty = stdout)")
|
|
|
|
_ = restoreCmd.MarkFlagRequired("in")
|
|
_ = restoreCmd.MarkFlagRequired("privkey-pq")
|
|
_ = restoreCmd.MarkFlagRequired("privkey-classical")
|
|
}
|