aboutsummaryrefslogtreecommitdiff
path: root/crypto/key.go
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/key.go')
-rw-r--r--crypto/key.go82
1 files changed, 39 insertions, 43 deletions
diff --git a/crypto/key.go b/crypto/key.go
index 9bf9098..2e57443 100644
--- a/crypto/key.go
+++ b/crypto/key.go
@@ -33,7 +33,6 @@ import (
"io"
"log"
"os"
- "os/user"
"runtime"
"unsafe"
@@ -41,7 +40,6 @@ import (
"golang.org/x/sys/unix"
"github.com/google/fscrypt/metadata"
- "github.com/google/fscrypt/security"
"github.com/google/fscrypt/util"
)
@@ -94,13 +92,13 @@ type Key struct {
data []byte
}
-// newBlankKey constructs a blank key of a specified length and returns an error
+// NewBlankKey constructs a blank key of a specified length and returns an error
// if we are unable to allocate or lock the necessary memory.
-func newBlankKey(length int) (*Key, error) {
+func NewBlankKey(length int) (*Key, error) {
if length == 0 {
return &Key{data: nil}, nil
} else if length < 0 {
- return nil, errors.Wrapf(ErrNegitiveLength, "length of %d requested", length)
+ return nil, errors.Errorf("requested key length %d is negative", length)
}
flags := keyMmapFlags
@@ -111,11 +109,11 @@ func newBlankKey(length int) (*Key, error) {
// See MAP_ANONYMOUS in http://man7.org/linux/man-pages/man2/mmap.2.html
data, err := unix.Mmap(-1, 0, length, keyProtection, flags)
if err == unix.EAGAIN {
- return nil, ErrKeyLock
+ return nil, ErrMlockUlimit
}
if err != nil {
- log.Printf("unix.Mmap() with length=%d failed: %v", length, err)
- return nil, ErrKeyAlloc
+ return nil, errors.Wrapf(err,
+ "failed to allocate (mmap) key buffer of length %d", length)
}
key := &Key{data: data}
@@ -141,7 +139,7 @@ func (key *Key) Wipe() error {
if err := unix.Munmap(data); err != nil {
log.Printf("unix.Munmap() failed: %v", err)
- return ErrKeyFree
+ return errors.Wrapf(err, "failed to free (munmap) key buffer")
}
}
return nil
@@ -167,7 +165,7 @@ func (key *Key) resize(requestedSize int) (*Key, error) {
}
defer key.Wipe()
- resizedKey, err := newBlankKey(requestedSize)
+ resizedKey, err := NewBlankKey(requestedSize)
if err != nil {
return nil, err
}
@@ -175,6 +173,18 @@ func (key *Key) resize(requestedSize int) (*Key, error) {
return resizedKey, nil
}
+// Data returns a slice of the key's underlying data. Note that this may become
+// outdated if the key is resized.
+func (key *Key) Data() []byte {
+ return key.data
+}
+
+// UnsafePtr returns an unsafe pointer to the key's underlying data. Note that
+// this will only be valid as long as the key is not resized.
+func (key *Key) UnsafePtr() unsafe.Pointer {
+ return util.Ptr(key.data)
+}
+
// UnsafeToCString makes a copy of the string's data into a null-terminated C
// string allocated by C. Note that this method is unsafe as this C copy has no
// locking or wiping functionality. The key shouldn't contain any `\0` bytes.
@@ -185,12 +195,22 @@ func (key *Key) UnsafeToCString() unsafe.Pointer {
return data
}
+// Clone creates a key as a copy of another one.
+func (key *Key) Clone() (*Key, error) {
+ newKey, err := NewBlankKey(key.Len())
+ if err != nil {
+ return nil, err
+ }
+ copy(newKey.data, key.data)
+ return newKey, nil
+}
+
// NewKeyFromCString creates of a copy of some C string's data in a key. Note
// that the original C string is not modified at all, so steps must be taken to
// ensure that this original copy is secured.
func NewKeyFromCString(str unsafe.Pointer) (*Key, error) {
size := C.strlen((*C.char)(str))
- key, err := newBlankKey(int(size))
+ key, err := NewBlankKey(int(size))
if err != nil {
return nil, err
}
@@ -198,12 +218,12 @@ func NewKeyFromCString(str unsafe.Pointer) (*Key, error) {
return key, nil
}
-// NewKeyFromReader constructs a key of abritary length by reading from reader
+// NewKeyFromReader constructs a key of arbitrary length by reading from reader
// until hitting EOF.
func NewKeyFromReader(reader io.Reader) (*Key, error) {
// Use an initial key size of a page. As Mmap allocates a page anyway,
// there isn't much additional overhead from starting with a whole page.
- key, err := newBlankKey(os.Getpagesize())
+ key, err := NewBlankKey(os.Getpagesize())
if err != nil {
return nil, err
}
@@ -235,7 +255,7 @@ func NewKeyFromReader(reader io.Reader) (*Key, error) {
// NewFixedLengthKeyFromReader constructs a key with a specified length by
// reading exactly length bytes from reader.
func NewFixedLengthKeyFromReader(reader io.Reader, length int) (*Key, error) {
- key, err := newBlankKey(length)
+ key, err := NewBlankKey(length)
if err != nil {
return nil, err
}
@@ -246,30 +266,6 @@ func NewFixedLengthKeyFromReader(reader io.Reader, length int) (*Key, error) {
return key, nil
}
-// InsertPolicyKey puts the provided policy key into the kernel keyring with the
-// provided description, and type logon. The key must be a policy key.
-func InsertPolicyKey(key *Key, description string, target *user.User) error {
- if err := util.CheckValidLength(metadata.PolicyKeyLen, key.Len()); err != nil {
- return errors.Wrap(err, "policy key")
- }
-
- // Create our payload (containing an FscryptKey)
- payload, err := newBlankKey(int(unsafe.Sizeof(unix.FscryptKey{})))
- if err != nil {
- return err
- }
- defer payload.Wipe()
-
- // Cast the payload to an FscryptKey so we can initialize the fields.
- fscryptKey := (*unix.FscryptKey)(util.Ptr(payload.data))
- // Mode is ignored by the kernel
- fscryptKey.Mode = 0
- fscryptKey.Size = metadata.PolicyKeyLen
- copy(fscryptKey.Raw[:], key.data)
-
- return security.InsertKey(payload.data, description, target)
-}
-
var (
// The recovery code is base32 with a dash between each block of 8 characters.
encoding = base32.StdEncoding
@@ -290,7 +286,7 @@ func WriteRecoveryCode(key *Key, writer io.Writer) error {
}
// We store the base32 encoded data (without separators) in a temp key
- encodedKey, err := newBlankKey(encodedLength)
+ encodedKey, err := NewBlankKey(encodedLength)
if err != nil {
return err
}
@@ -312,13 +308,13 @@ func WriteRecoveryCode(key *Key, writer io.Writer) error {
return w.Err()
}
-// ReadRecoveryCode gets the recovery code from the provided writer and returns
+// ReadRecoveryCode gets the recovery code from the provided reader and returns
// the corresponding cryptographic key.
// WARNING: This recovery key is enough to derive the original key, so it must
// be given the same level of protection as a raw cryptographic key.
func ReadRecoveryCode(reader io.Reader) (*Key, error) {
// We store the base32 encoded data (without separators) in a temp key
- encodedKey, err := newBlankKey(encodedLength)
+ encodedKey, err := NewBlankKey(encodedLength)
if err != nil {
return nil, err
}
@@ -333,7 +329,7 @@ func ReadRecoveryCode(reader io.Reader) (*Key, error) {
for blockStart := blockSize; blockStart < encodedLength; blockStart += blockSize {
r.Read(inputSeparator)
if r.Err() == nil && !bytes.Equal(separator, inputSeparator) {
- err := errors.Wrapf(ErrRecoveryCode, "invalid separator %q", inputSeparator)
+ err = errors.Wrapf(ErrRecoveryCode, "invalid separator %q", inputSeparator)
return nil, err
}
@@ -347,7 +343,7 @@ func ReadRecoveryCode(reader io.Reader) (*Key, error) {
}
// Now we decode the key, resizing if necessary
- decodedKey, err := newBlankKey(decodedLength)
+ decodedKey, err := NewBlankKey(decodedLength)
if err != nil {
return nil, err
}