Skip to content

Commit 667484a

Browse files
committed
migrate to Age encryption
1 parent 1baf7a5 commit 667484a

5 files changed

Lines changed: 66 additions & 64 deletions

File tree

cmd/ubackup/encryption.go

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,14 @@
11
package main
22

33
import (
4-
"crypto/rand"
5-
"crypto/rsa"
6-
"crypto/x509"
74
"io"
85
"os"
96

10-
"github.com/function61/gokit/crypto/cryptoutil"
117
"github.com/function61/gokit/os/osutil"
128
"github.com/function61/ubackup/pkg/backupfile"
139
"github.com/spf13/cobra"
1410
)
1511

16-
func decryptionKeyGenerate(out io.Writer) error {
17-
// using 4096 to be super safe, though 2048 seems to be what's currently used
18-
privKey, err := rsa.GenerateKey(rand.Reader, 4096)
19-
if err != nil {
20-
return err
21-
}
22-
23-
privKeyBytes := cryptoutil.MarshalPemBytes(
24-
x509.MarshalPKCS1PrivateKey(privKey),
25-
cryptoutil.PemTypeRsaPrivateKey)
26-
27-
if _, err := out.Write(privKeyBytes); err != nil {
28-
return err
29-
}
30-
31-
return nil
32-
}
33-
34-
func decryptionKeyToEncryptionKey(privKeyPemReader io.Reader, pubKeyOut io.Writer) error {
35-
privKeyPem, err := ioutil.ReadAll(privKeyPemReader)
36-
if err != nil {
37-
return err
38-
}
39-
40-
privKey, err := cryptoutil.ParsePemPkcs1EncodedRsaPrivateKey(privKeyPem)
41-
if err != nil {
42-
return err
43-
}
44-
45-
if _, err := pubKeyOut.Write(cryptoutil.MarshalPemBytes(
46-
x509.MarshalPKCS1PublicKey(&privKey.PublicKey),
47-
cryptoutil.PemTypeRsaPublicKey),
48-
); err != nil {
49-
return err
50-
}
51-
52-
return nil
53-
}
54-
5512
func decryptEntry() *cobra.Command {
5613
decryptAndDecompress := func(pathToPrivateKey string, input io.Reader, output io.Writer) error {
5714
privateKeyFile, err := os.ReadFile(pathToPrivateKey)
@@ -67,7 +24,6 @@ func decryptEntry() *cobra.Command {
6724
}
6825

6926
_, err = io.Copy(output, plaintextDecompressed)
70-
7127
return err
7228
}
7329

@@ -84,10 +40,10 @@ func decryptEntry() *cobra.Command {
8440
func decryptionKeyGenerateEntry() *cobra.Command {
8541
return &cobra.Command{
8642
Use: "decryption-key-generate",
87-
Short: "Generate RSA private key for backup decryption",
43+
Short: "Generate private key for backup decryption",
8844
Args: cobra.NoArgs,
8945
Run: func(cmd *cobra.Command, args []string) {
90-
osutil.ExitIfError(decryptionKeyGenerate(os.Stdout))
46+
osutil.ExitIfError(backupfile.DecryptionKeyGenerate(os.Stdout))
9147
},
9248
}
9349
}
@@ -98,7 +54,7 @@ func decryptionKeyToEncryptionKeyEntry() *cobra.Command {
9854
Short: "Prints encryption key (= public key) of decryption key (= private key)",
9955
Args: cobra.NoArgs,
10056
Run: func(cmd *cobra.Command, args []string) {
101-
osutil.ExitIfError(decryptionKeyToEncryptionKey(os.Stdin, os.Stdout))
57+
osutil.ExitIfError(backupfile.DecryptionKeyToEncryptionKey(os.Stdin, os.Stdout))
10258
},
10359
}
10460
}

go.mod

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111

1212
require (
1313
cloud.google.com/go v0.26.0 // indirect
14+
filippo.io/age v1.2.1
1415
github.com/BurntSushi/toml v0.3.1 // indirect
1516
github.com/OneOfOne/xxhash v1.2.2 // indirect
1617
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
@@ -49,7 +50,7 @@ require (
4950
github.com/golang/mock v1.1.1 // indirect
5051
github.com/golang/protobuf v1.3.2 // indirect
5152
github.com/google/btree v1.0.0 // indirect
52-
github.com/google/go-cmp v0.4.0 // indirect
53+
github.com/google/go-cmp v0.6.0 // indirect
5354
github.com/google/gofuzz v1.0.0 // indirect
5455
github.com/gorilla/websocket v1.4.0 // indirect
5556
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect
@@ -116,15 +117,15 @@ require (
116117
go.uber.org/atomic v1.4.0 // indirect
117118
go.uber.org/multierr v1.1.0 // indirect
118119
go.uber.org/zap v1.10.0 // indirect
119-
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 // indirect
120+
golang.org/x/crypto v0.24.0 // indirect
120121
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 // indirect
121-
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect
122+
golang.org/x/net v0.26.0 // indirect
122123
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be // indirect
123-
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
124-
golang.org/x/sys v0.6.0 // indirect
125-
golang.org/x/text v0.3.2 // indirect
124+
golang.org/x/sync v0.7.0 // indirect
125+
golang.org/x/sys v0.21.0 // indirect
126+
golang.org/x/text v0.16.0 // indirect
126127
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
127-
golang.org/x/tools v0.0.0-20190311212946-11955173bddd // indirect
128+
golang.org/x/tools v0.22.0 // indirect
128129
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
129130
google.golang.org/appengine v1.1.0 // indirect
130131
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 // indirect

go.sum

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2+
filippo.io/age v1.2.1 h1:X0TZjehAZylOIj4DubWYU1vWQxv9bJpo+Uu2/LGhi1o=
3+
filippo.io/age v1.2.1/go.mod h1:JL9ew2lTN+Pyft4RiNGguFfOpewKwSHm5ayKD/A4004=
24
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
35
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
46
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -80,6 +82,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
8082
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
8183
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
8284
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
85+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
8386
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
8487
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
8588
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@@ -208,6 +211,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90Pveol
208211
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
209212
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
210213
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
214+
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
215+
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
211216
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
212217
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
213218
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -220,11 +225,13 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowK
220225
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
221226
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
222227
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
228+
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
223229
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
224230
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
225231
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
226232
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
227233
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
234+
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
228235
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
229236
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
230237
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -241,14 +248,18 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7w
241248
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
242249
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
243250
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
251+
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
252+
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
244253
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
245254
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
246255
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
256+
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
247257
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
248258
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
249259
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
250260
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
251261
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
262+
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
252263
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
253264
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
254265
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=

pkg/backupfile/encryptiondecryption.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
// File format for ubackup. Basically just: pkencryptedstream(gzip(plaintext))
2-
// pkencryptedstream is aesKeyEnvelope(rsaOaep(aesKey, pubKey)) + iv + aesCtr(plaintextGzipped)
1+
// File format for ubackup. Basically just: `ageEncrypt(gzip(plaintext))`
32
package backupfile
43

54
import (
65
"compress/gzip"
76
"io"
7+
"strings"
88

9-
"github.com/function61/gokit/crypto/cryptoutil"
10-
"github.com/function61/gokit/crypto/pkencryptedstream"
9+
"filippo.io/age"
1110
)
1211

1312
type encryptorAndCompressor struct {
@@ -31,27 +30,27 @@ func (f *encryptorAndCompressor) Close() error {
3130

3231
// you need to call .Close() on the returned WriteCloser for the gzip header and encryption
3332
// process to finish gracefully
34-
func CreateEncryptorAndCompressor(rsaPublicKeyPemPkcs1 string, sink io.Writer) (io.WriteCloser, error) {
35-
publicKey, err := cryptoutil.ParsePemPkcs1EncodedRsaPublicKey([]byte(rsaPublicKeyPemPkcs1))
33+
func CreateEncryptorAndCompressor(ageRecipients string, sink io.Writer) (io.WriteCloser, error) {
34+
recipients, err := age.ParseRecipients(strings.NewReader(ageRecipients))
3635
if err != nil {
3736
return nil, err
3837
}
3938

40-
encryptedWriter, err := pkencryptedstream.Writer(sink, publicKey)
39+
encryptedWriter, err := age.Encrypt(sink, recipients...)
4140
if err != nil {
4241
return nil, err
4342
}
4443

4544
return &encryptorAndCompressor{encryptedWriter, gzip.NewWriter(encryptedWriter)}, nil
4645
}
4746

48-
func CreateDecryptorAndDecompressor(rsaPrivateKeyPemPkcs1 string, ciphertextAndCompressedInput io.Reader) (io.Reader, error) {
49-
privateKey, err := cryptoutil.ParsePemPkcs1EncodedRsaPrivateKey([]byte(rsaPrivateKeyPemPkcs1))
47+
func CreateDecryptorAndDecompressor(ageIdentities string, ciphertextAndCompressedInput io.Reader) (io.Reader, error) {
48+
identities, err := age.ParseIdentities(strings.NewReader(ageIdentities))
5049
if err != nil {
5150
return nil, err
5251
}
5352

54-
compressedPlaintextReader, err := pkencryptedstream.Reader(ciphertextAndCompressedInput, privateKey)
53+
compressedPlaintextReader, err := age.Decrypt(ciphertextAndCompressedInput, identities...)
5554
if err != nil {
5655
return nil, err
5756
}

pkg/backupfile/key-management.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package backupfile
2+
3+
import (
4+
"io"
5+
6+
"filippo.io/age"
7+
)
8+
9+
func DecryptionKeyGenerate(out io.Writer) error {
10+
identity, err := age.GenerateX25519Identity()
11+
if err != nil {
12+
return err
13+
}
14+
15+
if _, err := out.Write([]byte(identity.String())); err != nil {
16+
return err
17+
}
18+
19+
return nil
20+
}
21+
22+
func DecryptionKeyToEncryptionKey(privKeyReader io.Reader, pubKeyOut io.Writer) error {
23+
identities, err := age.ParseIdentities(privKeyReader)
24+
if err != nil {
25+
return err
26+
}
27+
28+
for _, identity := range identities {
29+
if _, err := pubKeyOut.Write([]byte(identity.(*age.X25519Identity).Recipient().String())); err != nil {
30+
return err
31+
}
32+
}
33+
34+
return nil
35+
}

0 commit comments

Comments
 (0)