diff --git a/mobile/lib/utils/crypto_util.dart b/mobile/lib/utils/crypto_util.dart index 2005e7882f..52ed85f857 100644 --- a/mobile/lib/utils/crypto_util.dart +++ b/mobile/lib/utils/crypto_util.dart @@ -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) { diff --git a/server/ente/user.go b/server/ente/user.go index 9ab12f31a4..8b207712d9 100644 --- a/server/ente/user.go +++ b/server/ente/user.go @@ -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"` diff --git a/server/pkg/api/user.go b/server/pkg/api/user.go index bfdd36ab7b..c62613ccb7 100644 --- a/server/pkg/api/user.go +++ b/server/pkg/api/user.go @@ -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, "")) diff --git a/server/pkg/repo/srp.go b/server/pkg/repo/srp.go index 9a8480e6ac..efb7c3bea2 100644 --- a/server/pkg/repo/srp.go +++ b/server/pkg/repo/srp.go @@ -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 {