summaryrefslogtreecommitdiffstats
path: root/internal/cryptoutil
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2025-09-26 09:12:27 -0700
committerRose Hogenson <rosehogenson@posteo.net>2025-09-26 09:12:27 -0700
commit768d3629b938196d132b80864204d7b6a9683a9e (patch)
treea147fbd27c911b6a1ec38c6492c02fd5f7b93456 /internal/cryptoutil
parent6cb1031bcbea0c13fb49f9ae445641aed53d2e8e (diff)
downloadroseh.moe-768d3629b938196d132b80864204d7b6a9683a9e.tar.zst
Turn up all the parameters
Hopefully this makes it secure 😳
Diffstat (limited to 'internal/cryptoutil')
-rw-r--r--internal/cryptoutil/cryptoutil.go54
1 files changed, 29 insertions, 25 deletions
diff --git a/internal/cryptoutil/cryptoutil.go b/internal/cryptoutil/cryptoutil.go
index b58282b..4ed600d 100644
--- a/internal/cryptoutil/cryptoutil.go
+++ b/internal/cryptoutil/cryptoutil.go
@@ -9,24 +9,27 @@ import (
"crypto/hmac"
"crypto/pbkdf2"
"crypto/rand"
- "crypto/sha256"
+ "crypto/sha512"
"crypto/subtle"
"encoding/hex"
"errors"
)
const (
- defaultIterations = 3749890 // from cmd/finditers
+ defaultIterations = 4718580 // from cmd/finditers
- saltSize = 2 * sha256.Size
- hashSize = 32
- certSize = sha256.Size
- aesKeySize = 32
- nonceSize = aes.BlockSize
+ oneSaltSize = 64
+ hashSize = 64
+ certSize = sha512.Size
+ aesKeySize = 32
+ nonceSize = aes.BlockSize
)
+// SaltSize is the expected salt length for HashIter.
+const SaltSize = 2 * oneSaltSize
+
// A PasswordHash must be PasswordHashSize bytes.
-const PasswordHashSize = saltSize + hashSize
+const PasswordHashSize = SaltSize + hashSize
// A PasswordHash is derived from the user's password and can be passed to
// CheckPassword to verify if two passwords match. A PasswordHash must be
@@ -42,14 +45,14 @@ type RawKey struct {
}
// An HMACKey must be HMACKeySize bytes.
-const HMACKeySize = sha256.Size
+const HMACKeySize = sha512.BlockSize
// An HMAC key can be used to symmetrically sign and verify messages
-// using HMAC-SHA256. An HMACKey must be HMACKeyLen bytes.
+// using HMAC-SHA512. An HMACKey must be HMACKeyLen bytes.
type HMACKey []byte
// A SignedMessage is a message that has been cryptographically signed
-// with HMAC-SHA256.
+// with HMAC-SHA512.
type SignedMessage []byte
// An EncryptionKey must be EncryptionKeySize bytes.
@@ -59,33 +62,34 @@ const EncryptionKeySize = aesKeySize + HMACKeySize
// must be EncryptionKeySize bytes.
type EncryptionKey []byte
-// An EncryptedMessage is encrypted with AES-256-CTR-HMAC-SHA256.
+// An EncryptedMessage is encrypted with AES-256-CTR-HMAC-SHA512.
type EncryptedMessage []byte
-// HashIter runs PBKDF2-SHA256 for iter iterations. Useful for benchmarking.
+// HashIter runs PBKDF2-SHA512 for iter iterations. Useful for benchmarking. The
+// salt must be SaltSize bytes.
func HashIter(password string, salt []byte, iter int) ([]byte, error) {
- return pbkdf2.Key(sha256.New, password, salt, iter, sha256.Size)
+ return pbkdf2.Key(sha512.New, password, salt, iter, sha512.Size)
}
func hashWithSalt(password string, salt []byte) (RawKey, []byte, error) {
- hash, err := HashIter(password, salt[:sha256.Size], defaultIterations)
+ hash, err := HashIter(password, salt[:oneSaltSize], defaultIterations)
if err != nil {
return RawKey{}, nil, err
}
- key, err := hkdf.Extract(sha256.New, hash, salt[sha256.Size:])
+ key, err := hkdf.Extract(sha512.New, hash, salt[oneSaltSize:])
if err != nil {
return RawKey{}, nil, err
}
- pwHash, err := hkdf.Expand(sha256.New, key, "pwhash", hashSize)
+ pwHash, err := hkdf.Expand(sha512.New, key, "pwhash", hashSize)
if err != nil {
return RawKey{}, nil, err
}
return RawKey{key}, pwHash, nil
}
-// Hash hashes a user password using PBKDF2-SHA256.
+// Hash hashes a user password using PBKDF2-SHA512.
func Hash(password string) (PasswordHash, error) {
- salt := make([]byte, saltSize, saltSize+hashSize)
+ salt := make([]byte, SaltSize, SaltSize+hashSize)
rand.Read(salt)
_, pwHash, err := hashWithSalt(password, salt)
if err != nil {
@@ -97,7 +101,7 @@ func Hash(password string) (PasswordHash, error) {
// CheckPassword verifies password against a PasswordHash and returns an
// EncryptionKey derived from the password if successful.
func (h PasswordHash) CheckPassword(password string) (RawKey, error) {
- salt, expectedHash := h[:saltSize], h[saltSize:]
+ salt, expectedHash := h[:SaltSize], h[SaltSize:]
key, pwHash, err := hashWithSalt(password, salt)
if err != nil {
return RawKey{}, err
@@ -108,9 +112,9 @@ func (h PasswordHash) CheckPassword(password string) (RawKey, error) {
return key, nil
}
-// Sign generates an HMAC-SHA256 signature and appends it to msg.
+// Sign generates an HMAC-SHA512 signature and appends it to msg.
func (k HMACKey) Sign(msg []byte) SignedMessage {
- mac := hmac.New(sha256.New, k)
+ mac := hmac.New(sha512.New, k)
mac.Write(msg)
return mac.Sum(msg)
}
@@ -122,7 +126,7 @@ func (k HMACKey) Verify(msg SignedMessage) ([]byte, bool) {
return nil, false
}
msg, sig := msg[:len(msg)-certSize], msg[len(msg)-certSize:]
- mac := hmac.New(sha256.New, k)
+ mac := hmac.New(sha512.New, k)
mac.Write(msg)
if !hmac.Equal(sig, mac.Sum(nil)) {
return nil, false
@@ -132,10 +136,10 @@ func (k HMACKey) Verify(msg SignedMessage) ([]byte, bool) {
// EncryptionKey derives an EncryptionKey.
func (k RawKey) EncryptionKey() (EncryptionKey, error) {
- return hkdf.Expand(sha256.New, k.key, "encrypt", EncryptionKeySize)
+ return hkdf.Expand(sha512.New, k.key, "encrypt", EncryptionKeySize)
}
-// Encrypt encrypts a message with AES-256-CTR-HMAC-SHA256.
+// Encrypt encrypts a message with AES-256-CTR-HMAC-SHA512.
func (k EncryptionKey) Encrypt(msg []byte) (EncryptedMessage, error) {
aesKey, hmacKey := k[:aesKeySize], HMACKey(k[aesKeySize:])
block, err := aes.NewCipher(aesKey)