[mob] Lower Mem & increase ops limit for key derivation (#4771)
## Description ## Tests
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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, ""))
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user