public PreLoginResponse PreLgoin() { this.header.FunctionName = "preLogin"; this.request = new PreLoginRequest(); this.header.Request = request; PreLoginResponse value = this.Request <PreLoginResponse>(); return(value); }
/// <summary> /// Generate authentication informations and store them in a serializable object to allow persistence /// </summary> /// <param name="email">email</param> /// <param name="password">password</param> /// <returns><see cref="AuthInfos" /> object containing encrypted data</returns> /// <exception cref="ArgumentNullException">email or password is null</exception> public AuthInfos GenerateAuthInfos(string email, string password) { if (string.IsNullOrEmpty(email)) { throw new ArgumentNullException("email"); } if (string.IsNullOrEmpty(password)) { throw new ArgumentNullException("password"); } // Prelogin to retrieve account version PreLoginRequest preLoginRequest = new PreLoginRequest(email); PreLoginResponse preLoginResponse = this.Request <PreLoginResponse>(preLoginRequest); if (preLoginResponse.Version == 2 && !string.IsNullOrEmpty(preLoginResponse.Salt)) { // Mega uses a new way to hash password based on a salt sent by Mega during prelogin var saltBytes = preLoginResponse.Salt.FromBase64(); var passwordBytes = password.ToBytesPassword(); const int Iterations = 100000; var derivedKeyBytes = new byte[32]; using (var hmac = new HMACSHA512()) { var pbkdf2 = new Pbkdf2(hmac, passwordBytes, saltBytes, Iterations); derivedKeyBytes = pbkdf2.GetBytes(derivedKeyBytes.Length); } // Derived key contains master key (0-16) and password hash (16-32) return(new AuthInfos( email, derivedKeyBytes.Skip(16).ToArray().ToBase64(), derivedKeyBytes.Take(16).ToArray())); } else if (preLoginResponse.Version == 1) { // Retrieve password as UTF8 byte array byte[] passwordBytes = password.ToBytesPassword(); // Encrypt password to use password as key for the hash byte[] passwordAesKey = PrepareKey(passwordBytes); // Hash email and password to decrypt master key on Mega servers string hash = GenerateHash(email.ToLowerInvariant(), passwordAesKey); return(new AuthInfos(email, hash, passwordAesKey)); } else { throw new NotSupportedException("Version of account not supported"); } }
// Token: 0x06000932 RID: 2354 RVA: 0x0004B428 File Offset: 0x00049628 public MegaApiClient.AuthInfos GenerateAuthInfos(string email, string password, string mfaKey = null) { if (string.IsNullOrEmpty(email)) { throw new ArgumentNullException("email"); } if (string.IsNullOrEmpty(password)) { throw new ArgumentNullException("password"); } PreLoginRequest request = new PreLoginRequest(email); PreLoginResponse preLoginResponse = this.Request <PreLoginResponse>(request, null); if (preLoginResponse.Version == 2 && !string.IsNullOrEmpty(preLoginResponse.Salt)) { byte[] salt = preLoginResponse.Salt.FromBase64(); byte[] password2 = password.ToBytesPassword(); byte[] array = new byte[32]; using (HMACSHA512 hmacsha = new HMACSHA512()) { array = new Pbkdf2(hmacsha, password2, salt, 100000).GetBytes(array.Length); } if (!string.IsNullOrEmpty(mfaKey)) { return(new MegaApiClient.AuthInfos(email, array.Skip(16).ToArray <byte>().ToBase64(), array.Take(16).ToArray <byte>(), mfaKey)); } return(new MegaApiClient.AuthInfos(email, array.Skip(16).ToArray <byte>().ToBase64(), array.Take(16).ToArray <byte>(), null)); } else { if (preLoginResponse.Version != 1) { throw new NotSupportedException("Version of account not supported"); } byte[] passwordAesKey = MegaApiClient.PrepareKey(password.ToBytesPassword()); string hash = MegaApiClient.GenerateHash(email.ToLowerInvariant(), passwordAesKey); if (!string.IsNullOrEmpty(mfaKey)) { return(new MegaApiClient.AuthInfos(email, hash, passwordAesKey, mfaKey)); } return(new MegaApiClient.AuthInfos(email, hash, passwordAesKey, null)); } }
public async Task Login(IUserConfiguration user = null) { var configuration = Api.Storage.Get(); user = await ResolveUserConfiguration(user, configuration); var username = user?.Username; var password = user?.Password; if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) { return; } var token = user.TwoFactorToken; var tokenType = "device_token"; string authHash = null; PreLoginResponse preLogin = null; while (true) { if (preLogin == null) { preLogin = await Api.GetPreLogin(username); authHash = null; } var authParams = preLogin.Salt[0]; int iterations = authParams.Iterations; byte[] salt = authParams.Salt_.ToByteArray(); if (authHash == null) { authHash = CryptoUtils.DeriveV1KeyHash(password, salt, iterations).Base64UrlEncode(); } var command = new LoginCommand(); command.username = username; command.authResponse = authHash; command.include = new[] { "keys", "settings", "enforcements", "is_enterprise_admin" }; command.twoFactorToken = token; command.twoFactorType = !string.IsNullOrEmpty(token) ? tokenType : null; command.deviceTokenExpiresInDays = !string.IsNullOrEmpty(token) && tokenType != "device_token" ? 9999 : (int?)null; var loginRs = await Api.ExecuteV2Command <LoginCommand, LoginResponse>(command); if (!loginRs.IsSuccess && loginRs.resultCode == "auth_failed") // invalid password { throw new Exception("Invalid user name or password"); } else { if (!string.IsNullOrEmpty(loginRs.deviceToken)) { token = loginRs.deviceToken; tokenType = "device_token"; } SessionToken = loginRs.sessionToken; Username = username; accountSettings = loginRs.accountSettings; if (loginRs.keys != null) { if (loginRs.keys.encryptedDataKey != null) { var key = CryptoUtils.DeriveKeyV2("data_key", password, salt, iterations); DataKey = CryptoUtils.DecryptAesV2(loginRs.keys.encryptedDataKey.Base64UrlDecode(), key); } else if (loginRs.keys.encryptionParams != null) { DataKey = CryptoUtils.DecryptEncryptionParams(password, loginRs.keys.encryptionParams.Base64UrlDecode()); } else { throw new Exception("Missing data key"); } if (loginRs.keys.encryptedPrivateKey != null) { privateKeyData = CryptoUtils.DecryptAesV1(loginRs.keys.encryptedPrivateKey.Base64UrlDecode(), DataKey); privateKey = null; } } if (loginRs.IsSuccess) { EncryptedPassword = CryptoUtils.EncryptAesV2(Encoding.UTF8.GetBytes(password), DataKey); TwoFactorToken = token; authResponse = authHash; IsEnterpriseAdmin = loginRs.isEnterpriseAdmin ?? false; enforcements = loginRs.enforcements; StoreConfigurationIfChanged(configuration); break; } switch (loginRs.resultCode) { case "need_totp": case "invalid_device_token": case "invalid_totp": token = await Ui.GetTwoFactorCode(); if (!string.IsNullOrEmpty(token)) { tokenType = "one_time"; continue; } break; case "auth_expired": await Ui.DisplayDialog(DialogType.Information, loginRs.message); password = await this.ChangeMasterPassword(iterations); if (!string.IsNullOrEmpty(password)) { preLogin = null; continue; } break; case "auth_expired_transfer": var shareAccountTo = loginRs.accountSettings.shareAccountTo; if (await Ui.DisplayDialog(DialogType.Confirmation, "Do you accept Account Transfer policy?")) { await this.ShareAccount(); continue; } break; } throw new KeeperApiException(loginRs.resultCode, loginRs.message); } } }