2023-07-17 04:23:26 +03:00
|
|
|
package crypto
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/sha256"
|
|
|
|
"fmt"
|
|
|
|
"runtime/debug"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/awnumar/memguard"
|
|
|
|
"golang.org/x/crypto/argon2"
|
|
|
|
"golang.org/x/crypto/pbkdf2"
|
|
|
|
)
|
|
|
|
|
|
|
|
type KDFType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
PBKDF2 KDFType = 0
|
|
|
|
Argon2ID KDFType = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
type KDFConfig struct {
|
|
|
|
Type KDFType
|
|
|
|
Iterations uint32
|
|
|
|
Memory uint32
|
|
|
|
Parallelism uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type MasterKey struct {
|
|
|
|
encKey *memguard.Enclave
|
|
|
|
}
|
|
|
|
|
|
|
|
func (masterKey MasterKey) GetBytes() []byte {
|
|
|
|
defer debug.FreeOSMemory()
|
|
|
|
|
|
|
|
buffer, err := masterKey.encKey.Open()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
defer buffer.Destroy()
|
|
|
|
|
|
|
|
return bytes.Clone(buffer.Bytes())
|
|
|
|
}
|
|
|
|
|
2023-12-22 14:01:21 +03:00
|
|
|
func DeriveMasterKey(password []byte, email string, kdfConfig KDFConfig) (MasterKey, error) {
|
2023-07-17 04:23:26 +03:00
|
|
|
defer debug.FreeOSMemory()
|
|
|
|
|
|
|
|
var key []byte
|
|
|
|
switch kdfConfig.Type {
|
|
|
|
case PBKDF2:
|
2023-12-22 14:01:21 +03:00
|
|
|
key = pbkdf2.Key(password, []byte(strings.ToLower(email)), int(kdfConfig.Iterations), 32, sha256.New)
|
2023-07-17 04:23:26 +03:00
|
|
|
case Argon2ID:
|
|
|
|
var salt [32]byte = sha256.Sum256([]byte(strings.ToLower(email)))
|
2023-12-22 14:01:21 +03:00
|
|
|
key = argon2.IDKey(password, salt[:], kdfConfig.Iterations, kdfConfig.Memory*1024, uint8(kdfConfig.Parallelism), 32)
|
2023-07-17 04:23:26 +03:00
|
|
|
default:
|
|
|
|
return MasterKey{}, fmt.Errorf("unsupported KDF type %d", kdfConfig.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
return MasterKey{memguard.NewEnclave(key)}, nil
|
|
|
|
}
|
2023-08-21 14:52:06 +03:00
|
|
|
|
|
|
|
func MasterKeyFromBytes(key []byte) MasterKey {
|
|
|
|
return MasterKey{memguard.NewEnclave(key)}
|
|
|
|
}
|