]> git.apps.os.sepia.ceph.com Git - fscrypt.git/commitdiff
crypto: Move from libargon2 -> x/crypto/argon2
authorJoseph Richey <joerichey94@gmail.com>
Thu, 8 Feb 2018 10:37:42 +0000 (02:37 -0800)
committerJoseph Richey <joerichey94@gmail.com>
Fri, 9 Feb 2018 11:36:11 +0000 (03:36 -0800)
Use the golang library for the hashing function instead of the reference
C implementation. This removes the dependancy on libargon2. As we are no
longer doing our own error checking, we also eliminate those tests.

crypto/crypto.go
crypto/crypto_test.go

index a85d34598f567d62d5cef87cc2e293e69015ef25..7327bd54ac03c4bcfd182e2b62bc6c0e135be6cd 100644 (file)
 //             - descriptor computation (double SHA512)
 package crypto
 
-/*
-#cgo LDFLAGS: -largon2
-#include <stdlib.h> // malloc(), free()
-#include <argon2.h>
-*/
-import "C"
-
 import (
        "crypto/aes"
        "crypto/cipher"
@@ -45,9 +38,9 @@ import (
        "crypto/sha256"
        "crypto/sha512"
        "encoding/hex"
-       "unsafe"
 
        "github.com/pkg/errors"
+       "golang.org/x/crypto/argon2"
        "golang.org/x/crypto/hkdf"
 
        "github.com/google/fscrypt/metadata"
@@ -182,42 +175,6 @@ func Unwrap(wrappingKey *Key, data *metadata.WrappedKeyData) (*Key, error) {
        return secretKey, nil
 }
 
-// newArgon2Context creates an argon2_context C struct given the hash and
-// passphrase keys, salt and costs. The structure must be freed by the caller.
-func newArgon2Context(hash, passphrase *Key,
-       salt []byte, costs *metadata.HashingCosts) *C.argon2_context {
-
-       ctx := (*C.argon2_context)(C.malloc(C.sizeof_argon2_context))
-
-       ctx.out = (*C.uint8_t)(util.Ptr(hash.data))
-       ctx.outlen = C.uint32_t(hash.Len())
-
-       ctx.pwd = (*C.uint8_t)(util.Ptr(passphrase.data))
-       ctx.pwdlen = C.uint32_t(passphrase.Len())
-
-       ctx.salt = (*C.uint8_t)(util.Ptr(salt))
-       ctx.saltlen = C.uint32_t(len(salt))
-
-       ctx.secret = nil // We don't use the secret field.
-       ctx.secretlen = 0
-       ctx.ad = nil // We don't use the associated data field.
-       ctx.adlen = 0
-
-       ctx.t_cost = C.uint32_t(costs.Time)
-       ctx.m_cost = C.uint32_t(costs.Memory)
-       ctx.lanes = C.uint32_t(costs.Parallelism)
-
-       ctx.threads = ctx.lanes
-       ctx.version = C.ARGON2_VERSION_13
-
-       // We use the built in malloc/free for memory.
-       ctx.allocate_cbk = nil
-       ctx.free_cbk = nil
-       ctx.flags = C.ARGON2_FLAG_CLEAR_PASSWORD
-
-       return ctx
-}
-
 // 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.
@@ -228,43 +185,20 @@ func ComputeDescriptor(key *Key) string {
        return hex.EncodeToString(h2[:length])
 }
 
-/*
-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. On success, passphrase will no longer have valid data.
-However, the caller should still call passphrase.Wipe().
-
-Argon2 is the winning algorithm of the Password Hashing Competition
-(see: https://password-hashing.net). It is designed to be "memory hard"
-in that a large amount of memory is required to compute the hash value.
-This makes it hard to use specialized hardware like GPUs and ASICs. We
-use it in "id" mode to provide extra protection against side-channel
-attacks. For more info see: https://github.com/P-H-C/phc-winner-argon2
-*/
+// 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
+// https://godoc.org/golang.org/x/crypto/argon2.
 func PassphraseHash(passphrase *Key, salt []byte, costs *metadata.HashingCosts) (*Key, error) {
-       if err := util.CheckValidLength(metadata.SaltLen, len(salt)); err != nil {
-               return nil, errors.Wrap(err, "passphrase hashing salt")
-       }
-       if err := costs.CheckValidity(); err != nil {
-               return nil, errors.Wrap(err, "passphrase hashing costs")
-       }
+       t := uint32(costs.Time)
+       m := uint32(costs.Memory)
+       p := uint8(costs.Parallelism)
+       key := argon2.IDKey(passphrase.data, salt, t, m, p, metadata.InternalKeyLen)
 
-       // This key will hold the hashing output
        hash, err := newBlankKey(metadata.InternalKeyLen)
        if err != nil {
                return nil, err
        }
-
-       ctx := newArgon2Context(hash, passphrase, salt, costs)
-       defer C.free(unsafe.Pointer(ctx))
-
-       // Run the hashing function (translating the error if there is one)
-       returnCode := C.argon2id_ctx(ctx)
-       if returnCode != C.ARGON2_OK {
-               hash.Wipe()
-               errorString := C.GoString(C.argon2_error_message(returnCode))
-               return nil, util.SystemError("argon2: " + errorString)
-       }
-
+       copy(hash.data, key)
        return hash, nil
 }
index 444f8475584c76928ae2c6bfe865d12341459e3d..2946a59608e0b9475ea3edfe5a4f81ba0308e4b7 100644 (file)
@@ -533,65 +533,6 @@ func TestPassphraseHashing(t *testing.T) {
        }
 }
 
-func TestBadTime(t *testing.T) {
-       pk, err := fakePassphraseKey()
-       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)
-       }
-}
-
-func TestBadMemory(t *testing.T) {
-       pk, err := fakePassphraseKey()
-       if err != nil {
-               t.Fatal(err)
-       }
-       defer pk.Wipe()
-
-       costs := *hashTestCases[0].costs
-       costs.Memory = 7
-       _, err = PassphraseHash(pk, fakeSalt, &costs)
-       if err == nil {
-               t.Errorf("memory cost of %d should be invalid", costs.Memory)
-       }
-}
-
-func TestBadParallelism(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)
-       }
-}
-
-func TestBadSalt(t *testing.T) {
-       pk, err := fakePassphraseKey()
-       if err != nil {
-               t.Fatal(err)
-       }
-       defer pk.Wipe()
-
-       _, err = PassphraseHash(pk, []byte{1, 2, 3, 4}, hashTestCases[0].costs)
-       if err == nil {
-               t.Error("too short of salt should be invalid")
-       }
-}
-
 func BenchmarkWrap(b *testing.B) {
        for n := 0; n < b.N; n++ {
                Wrap(fakeWrappingKey, fakeValidPolicyKey)