Skip to content

Commit 8a43c22

Browse files
authored
meta: support sm for format encryption (#6419)
Signed-off-by: jiefenghuang <[email protected]>
1 parent 0d18267 commit 8a43c22

File tree

2 files changed

+64
-30
lines changed

2 files changed

+64
-30
lines changed

pkg/meta/config.go

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ import (
2727
"io"
2828
"time"
2929

30+
"github.com/emmansun/gmsm/sm3"
31+
"github.com/emmansun/gmsm/sm4"
32+
"github.com/juicedata/juicefs/pkg/object"
3033
"github.com/juicedata/juicefs/pkg/version"
3134
"github.com/pkg/errors"
3235
)
@@ -187,31 +190,52 @@ func (f *Format) CheckCliVersion(ver *version.Semver) error {
187190
return nil
188191
}
189192

193+
func newCipher(algo string, key string) (cipher.AEAD, error) {
194+
switch algo {
195+
case object.SM4GCM:
196+
block, err := sm4.NewCipher(sm3.Kdf([]byte(key), 16))
197+
if err != nil {
198+
return nil, fmt.Errorf("new sm4 cipher: %s", err)
199+
}
200+
aead, err := cipher.NewGCM(block)
201+
if err != nil {
202+
return nil, fmt.Errorf("new sm4 GCM: %s", err)
203+
}
204+
return aead, nil
205+
default:
206+
hashKey := md5.Sum([]byte(key))
207+
block, err := aes.NewCipher(hashKey[:])
208+
if err != nil {
209+
return nil, fmt.Errorf("new cipher: %s", err)
210+
}
211+
aead, err := cipher.NewGCM(block)
212+
if err != nil {
213+
return nil, fmt.Errorf("new GCM: %s", err)
214+
}
215+
return aead, nil
216+
}
217+
}
218+
190219
func (f *Format) Encrypt() error {
191220
if f.KeyEncrypted || f.SecretKey == "" && f.EncryptKey == "" && f.SessionToken == "" {
192221
return nil
193222
}
194-
key := md5.Sum([]byte(f.UUID))
195-
block, err := aes.NewCipher(key[:])
196-
if err != nil {
197-
return fmt.Errorf("new cipher: %s", err)
198-
}
199-
aesgcm, err := cipher.NewGCM(block)
223+
ci, err := newCipher(f.EncryptAlgo, f.UUID)
200224
if err != nil {
201-
return fmt.Errorf("new GCM: %s", err)
225+
return err
202226
}
203227
encrypt := func(k *string) {
204228
if *k == "" {
205229
return
206230
}
207-
nonce := make([]byte, 12)
231+
nonce := make([]byte, ci.NonceSize())
208232
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
209233
logger.Fatalf("generate nonce for secret key: %s", err)
210234
}
211-
ciphertext := aesgcm.Seal(nil, nonce, []byte(*k), nil)
212-
buf := make([]byte, 12+len(ciphertext))
235+
ciphertext := ci.Seal(nil, nonce, []byte(*k), nil)
236+
buf := make([]byte, ci.NonceSize()+len(ciphertext))
213237
copy(buf, nonce)
214-
copy(buf[12:], ciphertext)
238+
copy(buf[ci.NonceSize():], ciphertext)
215239
*k = base64.StdEncoding.EncodeToString(buf)
216240
}
217241

@@ -226,14 +250,10 @@ func (f *Format) Decrypt() error {
226250
if !f.KeyEncrypted {
227251
return nil
228252
}
229-
key := md5.Sum([]byte(f.UUID))
230-
block, err := aes.NewCipher(key[:])
231-
if err != nil {
232-
return fmt.Errorf("new cipher: %s", err)
233-
}
234-
aesgcm, err := cipher.NewGCM(block)
253+
254+
ci, err := newCipher(f.EncryptAlgo, f.UUID)
235255
if err != nil {
236-
return fmt.Errorf("new GCM: %s", err)
256+
return err
237257
}
238258
decrypt := func(k *string) {
239259
if *k == "" {
@@ -248,7 +268,7 @@ func (f *Format) Decrypt() error {
248268
err = fmt.Errorf("decode key: %s", e)
249269
return
250270
}
251-
plaintext, e := aesgcm.Open(nil, buf[:12], buf[12:], nil)
271+
plaintext, e := ci.Open(nil, buf[:ci.NonceSize()], buf[ci.NonceSize():], nil)
252272
if e != nil {
253273
err = fmt.Errorf("open cipher: %s", e)
254274
return

pkg/meta/config_test.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package meta
1919
import (
2020
"strings"
2121
"testing"
22+
23+
"github.com/juicedata/juicefs/pkg/object"
2224
)
2325

2426
func TestRemoveSecret(t *testing.T) {
@@ -38,17 +40,29 @@ func TestRemoveSecret(t *testing.T) {
3840
}
3941

4042
func TestEncrypt(t *testing.T) {
41-
format := Format{Name: "test", SecretKey: "testSecret", SessionToken: "token", EncryptKey: "testEncrypt"}
42-
if err := format.Encrypt(); err != nil {
43-
t.Fatalf("Format encrypt: %s", err)
44-
}
45-
if format.SecretKey == "testSecret" || format.SessionToken == "token" || format.EncryptKey == "testEncrypt" {
46-
t.Fatalf("invalid format: %+v", format)
47-
}
48-
if err := format.Decrypt(); err != nil {
49-
t.Fatalf("Format decrypt: %s", err)
43+
cases := []struct {
44+
algo string
45+
}{
46+
{object.AES256GCM_RSA},
47+
{object.CHACHA20_RSA},
48+
{object.SM4GCM},
5049
}
51-
if format.SecretKey != "testSecret" || format.SessionToken != "token" || format.EncryptKey != "testEncrypt" {
52-
t.Fatalf("invalid format: %+v", format)
50+
format := Format{Name: "test", SecretKey: "testSecret", SessionToken: "token", EncryptKey: "testEncrypt"}
51+
for _, c := range cases {
52+
format.EncryptAlgo = c.algo
53+
t.Run(c.algo, func(t *testing.T) {
54+
if err := format.Encrypt(); err != nil {
55+
t.Fatalf("Format encrypt: %s", err)
56+
}
57+
if format.SecretKey == "testSecret" || format.SessionToken == "token" || format.EncryptKey == "testEncrypt" {
58+
t.Fatalf("invalid format: %+v", format)
59+
}
60+
if err := format.Decrypt(); err != nil {
61+
t.Fatalf("Format decrypt: %s", err)
62+
}
63+
if format.SecretKey != "testSecret" || format.SessionToken != "token" || format.EncryptKey != "testEncrypt" {
64+
t.Fatalf("invalid format: %+v", format)
65+
}
66+
})
5367
}
5468
}

0 commit comments

Comments
 (0)