summaryrefslogtreecommitdiff
path: root/internal/nametransform/xattr.go
blob: 721c4e4401a4ce10a63c2228c6ec26620f52c76e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package nametransform

import (
	"fmt"
	"strings"
	"syscall"

	"github.com/rfjakob/gocryptfs/v2/internal/tlog"
)

// xattr names are encrypted like file names, but with a fixed IV.
// Padded with "_xx" for length 16.
var xattrNameIV = []byte("xattr_name_iv_xx")

func isValidXattrName(name string) error {
	if name == "" {
		return fmt.Errorf("empty input")
	}
	if strings.Contains(name, "\000") {
		return fmt.Errorf("contains forbidden null byte")
	}
	return nil
}

// EncryptXattrName encrypts an extended attribute (xattr) name.
// xattr names are encrypted like file names, but with a fixed IV, and fewer
// naming restriction.
func (n *NameTransform) EncryptXattrName(plainName string) (cipherName64 string, err error) {
	if err := isValidXattrName(plainName); err != nil {
		tlog.Warn.Printf("EncryptXattrName %q: invalid plainName: %v", plainName, err)
		return "", syscall.EBADMSG
	}
	return n.encryptName(plainName, xattrNameIV), nil
}

// DecryptXattrName calls decryptName to try and decrypt a base64-encoded encrypted
// filename "cipherName", and failing that checks if it can be bypassed
func (n *NameTransform) DecryptXattrName(cipherName string) (plainName string, err error) {
	if plainName, err = n.decryptName(cipherName, xattrNameIV); err != nil {
		return "", err
	}
	if err := isValidXattrName(plainName); err != nil {
		tlog.Warn.Printf("DecryptXattrName %q: invalid name after decryption: %v", cipherName, err)
		return "", syscall.EBADMSG
	}
	return plainName, err
}