[mob] Lower Mem & increase ops limit for key derivation (#4771)

## Description

## Tests
This commit is contained in:
Neeraj
2025-01-20 16:40:09 +05:30
committed by GitHub
4 changed files with 45 additions and 18 deletions

View File

@@ -8,7 +8,6 @@ import 'package:logging/logging.dart';
import "package:photos/core/errors.dart";
import 'package:photos/models/derived_key_result.dart';
import 'package:photos/models/encryption_result.dart';
import "package:photos/utils/device_info.dart";
const int encryptionChunkSize = 4 * 1024 * 1024;
final int decryptionChunkSize =
@@ -392,24 +391,27 @@ class CryptoUtil {
Uint8List salt,
) async {
final logger = Logger("pwhash");
int memLimit = Sodium.cryptoPwhashMemlimitSensitive;
int opsLimit = Sodium.cryptoPwhashOpslimitSensitive;
if (await isLowSpecDevice()) {
logger.info("low spec device detected");
// When sensitive memLimit (1 GB) is used, on low spec device the OS might
// kill the app with OOM. To avoid that, start with 256 MB and
// corresponding ops limit (16).
// This ensures that the product of these two variables
// (the area under the graph that determines the amount of work required)
// stays the same
// SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE: 1073741824
// SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE: 268435456
// SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE: 4
memLimit = Sodium.cryptoPwhashMemlimitModerate;
final factor = Sodium.cryptoPwhashMemlimitSensitive ~/
Sodium.cryptoPwhashMemlimitModerate; // = 4
opsLimit = opsLimit * factor; // = 16
final int desiredStrength = Sodium.cryptoPwhashMemlimitSensitive *
Sodium.cryptoPwhashOpslimitSensitive;
// When sensitive memLimit (1 GB) is used, on low spec device the OS might
// kill the app with OOM. To avoid that, start with 256 MB and
// corresponding ops limit (16).
// This ensures that the product of these two variables
// (the area under the graph that determines the amount of work required)
// stays the same
// SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE: 1073741824
// SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE: 268435456
// SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE: 4
int memLimit = Sodium.cryptoPwhashMemlimitModerate;
final factor = Sodium.cryptoPwhashMemlimitSensitive ~/
Sodium.cryptoPwhashMemlimitModerate; // = 4
int opsLimit = Sodium.cryptoPwhashOpslimitSensitive * factor; // = 16
if (memLimit * opsLimit != desiredStrength) {
throw UnsupportedError(
"unexpcted values for memLimit $memLimit and opsLimit: $opsLimit",
);
}
Uint8List key;
while (memLimit >= Sodium.cryptoPwhashMemlimitMin &&
opsLimit <= Sodium.cryptoPwhashOpslimitMax) {

View File

@@ -10,6 +10,8 @@ const (
ChangeEmailOTTPurpose = "change"
SignUpOTTPurpose = "signup"
LoginOTTPurpose = "login"
ExpectedKDFStrength = 1073741824 * 4
)
// User represents a user in the system
@@ -88,6 +90,14 @@ type SetUserAttributesRequest struct {
KeyAttributes KeyAttributes `json:"keyAttributes" binding:"required"`
}
func (sk *SetUserAttributesRequest) Validate() error {
strength := sk.KeyAttributes.MemLimit * sk.KeyAttributes.OpsLimit
if strength != ExpectedKDFStrength {
return NewBadRequestWithMessage("Unexpected KDF strength")
}
return nil
}
// UpdateEmailMFA ..
type UpdateEmailMFA struct {
IsEnabled *bool `json:"isEnabled" binding:"required"`
@@ -102,6 +112,14 @@ type UpdateKeysRequest struct {
OpsLimit int `json:"opsLimit" binding:"required"`
}
func (u *UpdateKeysRequest) Validate() error {
strength := u.MemLimit * u.OpsLimit
if strength != ExpectedKDFStrength {
return NewBadRequestWithMessage("Unexpected KDF strength")
}
return nil
}
type SetRecoveryKeyRequest struct {
MasterKeyEncryptedWithRecoveryKey string `json:"masterKeyEncryptedWithRecoveryKey"`
MasterKeyDecryptionNonce string `json:"masterKeyDecryptionNonce"`

View File

@@ -82,6 +82,10 @@ func (h *UserHandler) SetAttributes(c *gin.Context) {
handler.Error(c, stacktrace.Propagate(err, ""))
return
}
if err := request.Validate(); err != nil {
handler.Error(c, stacktrace.Propagate(err, ""))
return
}
err := h.UserController.SetAttributes(userID, request)
if err != nil {
handler.Error(c, stacktrace.Propagate(err, ""))

View File

@@ -135,6 +135,9 @@ func (repo *UserAuthRepository) InsertOrUpdateSRPAuthAndKeyAttr(ctx context.Cont
return stacktrace.Propagate(err, "")
}
updateKeyAttr := *req.UpdateAttributes
if validErr := updateKeyAttr.Validate(); validErr != nil {
return stacktrace.Propagate(validErr, "")
}
_, err = tx.ExecContext(ctx, `UPDATE key_attributes SET kek_salt = $1, encrypted_key = $2, key_decryption_nonce = $3, mem_limit = $4, ops_limit = $5 WHERE user_id = $6`,
updateKeyAttr.KEKSalt, updateKeyAttr.EncryptedKey, updateKeyAttr.KeyDecryptionNonce, updateKeyAttr.MemLimit, updateKeyAttr.OpsLimit, userID)
if err != nil {