aboutsummaryrefslogtreecommitdiff
path: root/crypto/crypto_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/crypto_test.go')
-rw-r--r--crypto/crypto_test.go207
1 files changed, 87 insertions, 120 deletions
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
index 444f847..1fa5a0c 100644
--- a/crypto/crypto_test.go
+++ b/crypto/crypto_test.go
@@ -30,11 +30,7 @@ import (
"os"
"testing"
- "golang.org/x/sys/unix"
-
"github.com/google/fscrypt/metadata"
- "github.com/google/fscrypt/security"
- "github.com/google/fscrypt/util"
)
// Reader that always returns the same byte
@@ -53,19 +49,14 @@ func makeKey(b byte, n int) (*Key, error) {
}
var (
- fakeValidDescriptor = "0123456789abcdef"
- fakeSalt = bytes.Repeat([]byte{'a'}, metadata.SaltLen)
- fakePassword = []byte("password")
- defaultService = unix.FS_KEY_DESC_PREFIX
-
- fakeValidPolicyKey, _ = makeKey(42, metadata.PolicyKeyLen)
- fakeInvalidPolicyKey, _ = makeKey(42, metadata.PolicyKeyLen-1)
- fakeWrappingKey, _ = makeKey(17, metadata.InternalKeyLen)
+ fakeSalt = bytes.Repeat([]byte{'a'}, metadata.SaltLen)
+ fakePassword = []byte("password")
- testUser, _ = util.EffectiveUser()
+ fakeValidPolicyKey, _ = makeKey(42, metadata.PolicyKeyLen)
+ fakeWrappingKey, _ = makeKey(17, metadata.InternalKeyLen)
)
-// As the passpharase hashing function clears the passphrase, we need to make
+// As the passphrase hashing function clears the passphrase, we need to make
// a new passphrase key for each test
func fakePassphraseKey() (*Key, error) {
return NewFixedLengthKeyFromReader(bytes.NewReader(fakePassword), len(fakePassword))
@@ -73,7 +64,9 @@ func fakePassphraseKey() (*Key, error) {
// Values for test cases pulled from argon2 command line tool.
// To generate run:
-// echo "password" | argon2 "aaaaaaaaaaaaaaaa" -id -t <t> -m <m> -p <p> -l 32
+//
+// echo "password" | argon2 "aaaaaaaaaaaaaaaa" -id -t <t> -m <m> -p <p> -l 32
+//
// where costs.Time = <t>, costs.Memory = 2^<m>, and costs.Parallelism = <p>.
type hashTestCase struct {
costs *metadata.HashingCosts
@@ -85,6 +78,12 @@ var hashTestCases = []hashTestCase{
costs: &metadata.HashingCosts{Time: 1, Memory: 1 << 10, Parallelism: 1},
hexHash: "a66f5398e33761bf161fdf1273e99b148f07d88d12d85b7673fddd723f95ec34",
},
+ // Make sure we maintain our backwards compatible behavior, where
+ // Parallelism is truncated to 8-bits unless TruncationFixed is true.
+ {
+ costs: &metadata.HashingCosts{Time: 1, Memory: 1 << 10, Parallelism: 257},
+ hexHash: "a66f5398e33761bf161fdf1273e99b148f07d88d12d85b7673fddd723f95ec34",
+ },
{
costs: &metadata.HashingCosts{Time: 10, Memory: 1 << 10, Parallelism: 1},
hexHash: "5fa2cb89db1f7413ba1776258b7c8ee8c377d122078d28fe1fd645c353787f50",
@@ -97,6 +96,15 @@ var hashTestCases = []hashTestCase{
costs: &metadata.HashingCosts{Time: 1, Memory: 1 << 10, Parallelism: 10},
hexHash: "b7c3d7a0be222680b5ea3af3fb1a0b7b02b92cbd7007821dc8b84800c86c7783",
},
+ {
+ costs: &metadata.HashingCosts{Time: 1, Memory: 1 << 11, Parallelism: 255},
+ hexHash: "d51af3775bbdd0cba31d96fd6d921d9de27f521ceffe667618cd7624f6643071",
+ },
+ // Adding TruncationFixed shouldn't matter if Parallelism < 256.
+ {
+ costs: &metadata.HashingCosts{Time: 1, Memory: 1 << 11, Parallelism: 255, TruncationFixed: true},
+ hexHash: "d51af3775bbdd0cba31d96fd6d921d9de27f521ceffe667618cd7624f6643071",
+ },
}
// Checks that len(array) == expected
@@ -158,7 +166,7 @@ func TestZeroLength(t *testing.T) {
}
defer key1.Wipe()
if key1.data != nil {
- t.Error("FIxed length key from reader contained data")
+ t.Error("Fixed length key from reader contained data")
}
key2, err := NewKeyFromReader(bytes.NewReader(nil))
@@ -171,7 +179,7 @@ func TestZeroLength(t *testing.T) {
}
}
-// Test that enabling the disabling memory locking succeeds even if a key is
+// Test that enabling then disabling memory locking succeeds even if a key is
// active when the variable changes.
func TestEnableDisableMemoryLocking(t *testing.T) {
// Mlock on for creation, off for wiping
@@ -242,47 +250,10 @@ func TestKeyLargeResize(t *testing.T) {
}
}
-// Adds and removes a key with various services.
-func TestAddRemoveKeys(t *testing.T) {
- for _, service := range []string{defaultService, "ext4:", "f2fs:"} {
- validDescription := service + fakeValidDescriptor
- if err := InsertPolicyKey(fakeValidPolicyKey, validDescription, testUser); err != nil {
- t.Error(err)
- }
- if err := security.RemoveKey(validDescription, testUser); err != nil {
- t.Error(err)
- }
- }
-}
-
-// Adds a key twice (both should succeed)
-func TestAddTwice(t *testing.T) {
- validDescription := defaultService + fakeValidDescriptor
- InsertPolicyKey(fakeValidPolicyKey, validDescription, testUser)
- if InsertPolicyKey(fakeValidPolicyKey, validDescription, testUser) != nil {
- t.Error("InsertPolicyKey should not fail if key already exists")
- }
- security.RemoveKey(validDescription, testUser)
-}
-
-// Makes sure a key fails with bad policy or service
-func TestBadAddKeys(t *testing.T) {
- validDescription := defaultService + fakeValidDescriptor
- if InsertPolicyKey(fakeInvalidPolicyKey, validDescription, testUser) == nil {
- security.RemoveKey(validDescription, testUser)
- t.Error("InsertPolicyKey should fail with bad policy key")
- }
- invalidDescription := "ext4" + fakeValidDescriptor
- if InsertPolicyKey(fakeValidPolicyKey, invalidDescription, testUser) == nil {
- security.RemoveKey(invalidDescription, testUser)
- t.Error("InsertPolicyKey should fail with bad service")
- }
-}
-
// Check that we can create random keys. All this test does to test the
// "randomness" is generate a page of random bytes and attempts compression.
// If the data can be compressed it is probably not very random. This isn't
-// indented to be a sufficient test for randomness (which is impossible), but a
+// intended to be a sufficient test for randomness (which is impossible), but a
// way to catch simple regressions (key is all zeros or contains a repeating
// pattern).
func TestRandomKeyGen(t *testing.T) {
@@ -303,7 +274,7 @@ func TestBigKeyGen(t *testing.T) {
case nil:
key.Wipe()
return
- case ErrKeyLock:
+ case ErrMlockUlimit:
// Don't fail just because "ulimit -l" is too low.
return
default:
@@ -456,7 +427,7 @@ func TestWrongUnwrappingKeyLength(t *testing.T) {
}
}
-// Wraping twice with the same keys should give different components
+// Wrapping twice with the same keys should give different components
func TestWrapTwiceDistinct(t *testing.T) {
data1, err := Wrap(fakeWrappingKey, fakeValidPolicyKey)
if err != nil {
@@ -472,14 +443,14 @@ func TestWrapTwiceDistinct(t *testing.T) {
}
}
-// Attempts to Unwrap data with key after altering tweek, should fail
-func testFailWithTweek(key *Key, data *metadata.WrappedKeyData, tweek []byte) error {
- tweek[0]++
+// Attempts to Unwrap data with key after altering tweak, should fail
+func testFailWithTweak(key *Key, data *metadata.WrappedKeyData, tweak []byte) error {
+ tweak[0]++
key, err := Unwrap(key, data)
if err == nil {
key.Wipe()
}
- tweek[0]--
+ tweak[0]--
return err
}
@@ -489,7 +460,7 @@ func TestUnwrapWrongKey(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if testFailWithTweek(fakeWrappingKey, data, fakeWrappingKey.data) == nil {
+ if testFailWithTweak(fakeWrappingKey, data, fakeWrappingKey.data) == nil {
t.Error("using a different wrapping key should make unwrap fail")
}
}
@@ -499,96 +470,92 @@ func TestUnwrapWrongData(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if testFailWithTweek(fakeWrappingKey, data, data.EncryptedKey) == nil {
+ if testFailWithTweak(fakeWrappingKey, data, data.EncryptedKey) == nil {
t.Error("changing encryption key should make unwrap fail")
}
- if testFailWithTweek(fakeWrappingKey, data, data.IV) == nil {
+ if testFailWithTweak(fakeWrappingKey, data, data.IV) == nil {
t.Error("changing IV should make unwrap fail")
}
- if testFailWithTweek(fakeWrappingKey, data, data.Hmac) == nil {
+ if testFailWithTweak(fakeWrappingKey, data, data.Hmac) == nil {
t.Error("changing HMAC should make unwrap fail")
}
}
-// Run our test cases for passphrase hashing
-func TestPassphraseHashing(t *testing.T) {
- for i, testCase := range hashTestCases {
- pk, err := fakePassphraseKey()
- if err != nil {
- t.Fatal(err)
- }
- defer pk.Wipe()
-
- hash, err := PassphraseHash(pk, fakeSalt, testCase.costs)
- if err != nil {
- t.Fatal(err)
- }
- defer hash.Wipe()
-
- actual := hex.EncodeToString(hash.data)
- if actual != testCase.hexHash {
- t.Errorf("Hash test %d: for costs=%+v expected hash of %q got %q",
- i, testCase.costs, testCase.hexHash, actual)
- }
- }
-}
-
-func TestBadTime(t *testing.T) {
- pk, err := fakePassphraseKey()
+func TestComputeKeyDescriptorV1(t *testing.T) {
+ descriptor, err := ComputeKeyDescriptor(fakeValidPolicyKey, 1)
if err != nil {
t.Fatal(err)
}
- defer pk.Wipe()
-
- costs := *hashTestCases[0].costs
- costs.Time = 0
- _, err = PassphraseHash(pk, fakeSalt, &costs)
- if err == nil {
- t.Errorf("time cost of %d should be invalid", costs.Time)
+ if descriptor != "8290608a029c5aae" {
+ t.Errorf("wrong v1 descriptor: %s", descriptor)
}
}
-func TestBadMemory(t *testing.T) {
- pk, err := fakePassphraseKey()
+func TestComputeKeyDescriptorV2(t *testing.T) {
+ descriptor, err := ComputeKeyDescriptor(fakeValidPolicyKey, 2)
if err != nil {
t.Fatal(err)
}
- defer pk.Wipe()
+ if descriptor != "2139f52bf8386ee99845818ac7e91c4a" {
+ t.Errorf("wrong v2 descriptor: %s", descriptor)
+ }
+}
- costs := *hashTestCases[0].costs
- costs.Memory = 7
- _, err = PassphraseHash(pk, fakeSalt, &costs)
+func TestComputeKeyDescriptorBadVersion(t *testing.T) {
+ _, err := ComputeKeyDescriptor(fakeValidPolicyKey, 0)
if err == nil {
- t.Errorf("memory cost of %d should be invalid", costs.Memory)
+ t.Error("computing key descriptor with bad version should fail")
}
}
-func TestBadParallelism(t *testing.T) {
+// Run our test cases for passphrase hashing
+func TestPassphraseHashing(t *testing.T) {
pk, err := fakePassphraseKey()
if err != nil {
t.Fatal(err)
}
defer pk.Wipe()
- costs := *hashTestCases[0].costs
- costs.Parallelism = 1 << 24
- costs.Memory = 1 << 27 // Running n threads requires at least 8*n memory
- _, err = PassphraseHash(pk, fakeSalt, &costs)
- if err == nil {
- t.Errorf("parallelism cost of %d should be invalid", costs.Parallelism)
+ for i, testCase := range hashTestCases {
+ if err := testCase.costs.CheckValidity(); err != nil {
+ t.Errorf("Hash test %d: for costs=%+v hashing failed: %v", i, testCase.costs, err)
+ continue
+ }
+ hash, err := PassphraseHash(pk, fakeSalt, testCase.costs)
+ if err != nil {
+ t.Errorf("Hash test %d: for costs=%+v hashing failed: %v", i, testCase.costs, err)
+ continue
+ }
+ defer hash.Wipe()
+
+ actual := hex.EncodeToString(hash.data)
+ if actual != testCase.hexHash {
+ t.Errorf("Hash test %d: for costs=%+v expected hash of %q got %q",
+ i, testCase.costs, testCase.hexHash, actual)
+ }
}
}
-func TestBadSalt(t *testing.T) {
- pk, err := fakePassphraseKey()
- if err != nil {
- t.Fatal(err)
- }
- defer pk.Wipe()
+var badCosts = []*metadata.HashingCosts{
+ // Bad Time costs
+ {Time: 0, Memory: 1 << 11, Parallelism: 1},
+ {Time: 1 << 33, Memory: 1 << 11, Parallelism: 1},
+ // Bad Memory costs
+ {Time: 1, Memory: 5, Parallelism: 1},
+ {Time: 1, Memory: 1 << 33, Parallelism: 1},
+ // Bad Parallelism costs
+ {Time: 1, Memory: 1 << 11, Parallelism: 0, TruncationFixed: false},
+ {Time: 1, Memory: 1 << 11, Parallelism: 0, TruncationFixed: true},
+ {Time: 1, Memory: 1 << 11, Parallelism: 256, TruncationFixed: false},
+ {Time: 1, Memory: 1 << 11, Parallelism: 256, TruncationFixed: true},
+ {Time: 1, Memory: 1 << 11, Parallelism: 257, TruncationFixed: true},
+}
- _, err = PassphraseHash(pk, []byte{1, 2, 3, 4}, hashTestCases[0].costs)
- if err == nil {
- t.Error("too short of salt should be invalid")
+func TestBadParameters(t *testing.T) {
+ for i, costs := range badCosts {
+ if costs.CheckValidity() == nil {
+ t.Errorf("Hash test %d: expected error for costs=%+v", i, costs)
+ }
}
}