aboutsummaryrefslogtreecommitdiff
path: root/crypto/crypto.go
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/crypto.go')
-rw-r--r--crypto/crypto.go39
1 files changed, 33 insertions, 6 deletions
diff --git a/crypto/crypto.go b/crypto/crypto.go
index ec961b6..9a138d0 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -28,7 +28,7 @@
// - key stretching (SHA256-based HKDF)
// - key wrapping/unwrapping (Encrypt then MAC)
// - passphrase-based key derivation (Argon2id)
-// - descriptor computation (double SHA512)
+// - key descriptor computation (double SHA512, or HKDF-SHA512)
package crypto
import (
@@ -38,6 +38,7 @@ import (
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
+ "io"
"github.com/pkg/errors"
"golang.org/x/crypto/argon2"
@@ -176,16 +177,42 @@ func Unwrap(wrappingKey *Key, data *metadata.WrappedKeyData) (*Key, error) {
return secretKey, nil
}
-// ComputeDescriptor computes the descriptor for a given cryptographic key. In
-// keeping with the process used in e4crypt, this uses the initial bytes
-// (formatted as hexadecimal) of the double application of SHA512 on the key.
-func ComputeDescriptor(key *Key) string {
+func computeKeyDescriptorV1(key *Key) string {
h1 := sha512.Sum512(key.data)
h2 := sha512.Sum512(h1[:])
- length := hex.DecodedLen(metadata.DescriptorLen)
+ length := hex.DecodedLen(metadata.PolicyDescriptorLenV1)
return hex.EncodeToString(h2[:length])
}
+func computeKeyDescriptorV2(key *Key) (string, error) {
+ // This algorithm is specified by the kernel. It uses unsalted
+ // HKDF-SHA512, where the application-information string is the prefix
+ // "fscrypt\0" followed by the HKDF_CONTEXT_KEY_IDENTIFIER byte.
+ hkdf := hkdf.New(sha512.New, key.data, nil, []byte("fscrypt\x00\x01"))
+ h := make([]byte, hex.DecodedLen(metadata.PolicyDescriptorLenV2))
+ if _, err := io.ReadFull(hkdf, h); err != nil {
+ return "", err
+ }
+ return hex.EncodeToString(h), nil
+}
+
+// ComputeKeyDescriptor computes the descriptor for a given cryptographic key.
+// If policyVersion=1, it uses the first 8 bytes of the double application of
+// SHA512 on the key. Use this for protectors and v1 policy keys.
+// If policyVersion=2, it uses HKDF-SHA512 to compute a key identifier that's
+// compatible with the kernel's key identifiers for v2 policy keys.
+// In both cases, the resulting bytes are formatted as hex.
+func ComputeKeyDescriptor(key *Key, policyVersion int64) (string, error) {
+ switch policyVersion {
+ case 1:
+ return computeKeyDescriptorV1(key), nil
+ case 2:
+ return computeKeyDescriptorV2(key)
+ default:
+ return "", errors.Errorf("policy version of %d is invalid", policyVersion)
+ }
+}
+
// PassphraseHash uses Argon2id to produce a Key given the passphrase, salt, and
// hashing costs. This method is designed to take a long time and consume
// considerable memory. For more information, see the documentation at