mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-21 00:38:37 +00:00
Extend warnings for --cryptkey and lack of it
@Abrynos
This commit is contained in:
@@ -27,12 +27,14 @@ namespace ArchiSteamFarm.Tests {
|
|||||||
[TestClass]
|
[TestClass]
|
||||||
#pragma warning disable CA1724
|
#pragma warning disable CA1724
|
||||||
public sealed class Utilities {
|
public sealed class Utilities {
|
||||||
#pragma warning restore CA1724
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void LongPassphraseIsNotWeak() => Assert.IsFalse(TestPasswordStrength("10chars<!>asdf").IsWeak);
|
public void AdditionallyForbiddenWordsWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("10chars<!>asdf", new HashSet<string> { "chars<!>" }).IsWeak);
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ShortPassphraseIsWeak() => Assert.IsTrue(TestPasswordStrength("four").IsWeak);
|
public void ContextSpecificWordsWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("archisteamfarmpassword").IsWeak);
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LongPassphraseIsNotWeak() => Assert.IsFalse(TestPasswordStrength("10chars<!>asdf").IsWeak);
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void RepetitiveCharactersWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("testaaaatest").IsWeak);
|
public void RepetitiveCharactersWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("testaaaatest").IsWeak);
|
||||||
@@ -44,9 +46,7 @@ namespace ArchiSteamFarm.Tests {
|
|||||||
public void SequentialDescendingCharactersWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("testdcbatest").IsWeak);
|
public void SequentialDescendingCharactersWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("testdcbatest").IsWeak);
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ContextSpecificWordsWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("archisteamfarmpassword").IsWeak);
|
public void ShortPassphraseIsWeak() => Assert.IsTrue(TestPasswordStrength("four").IsWeak);
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void AdditionallyForbiddenWordsWeakenPassphrases() => Assert.IsTrue(TestPasswordStrength("10chars<!>asdf", new HashSet<string> { "chars<!>" }).IsWeak);
|
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CA1724
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -19,10 +19,12 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#if NETFRAMEWORK
|
||||||
|
using JustArchiNET.Madness;
|
||||||
|
#endif
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@@ -31,16 +33,12 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using AngleSharp.XPath;
|
using AngleSharp.XPath;
|
||||||
using ArchiSteamFarm.Localization;
|
|
||||||
using ArchiSteamFarm.Storage;
|
using ArchiSteamFarm.Storage;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using Humanizer.Localisation;
|
using Humanizer.Localisation;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using SteamKit2;
|
using SteamKit2;
|
||||||
using Zxcvbn;
|
using Zxcvbn;
|
||||||
#if NETFRAMEWORK
|
|
||||||
using JustArchiNET.Madness;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ArchiSteamFarm.Core {
|
namespace ArchiSteamFarm.Core {
|
||||||
public static class Utilities {
|
public static class Utilities {
|
||||||
@@ -329,6 +327,20 @@ namespace ArchiSteamFarm.Core {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool RelativeDirectoryStartsWith(string directory, params string[] prefixes) {
|
||||||
|
if (string.IsNullOrEmpty(directory)) {
|
||||||
|
throw new ArgumentNullException(nameof(directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CA1508 // False positive, params could be null when explicitly set
|
||||||
|
if ((prefixes == null) || (prefixes.Length == 0)) {
|
||||||
|
#pragma warning restore CA1508 // False positive, params could be null when explicitly set
|
||||||
|
throw new ArgumentNullException(nameof(prefixes));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (from prefix in prefixes where directory.Length > prefix.Length let pathSeparator = directory[prefix.Length] where (pathSeparator == Path.DirectorySeparatorChar) || (pathSeparator == Path.AltDirectorySeparatorChar) select prefix).Any(prefix => directory.StartsWith(prefix, StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
internal static (bool IsWeak, string? Reason) TestPasswordStrength(string password, ISet<string>? additionallyForbiddenPhrases = null) {
|
internal static (bool IsWeak, string? Reason) TestPasswordStrength(string password, ISet<string>? additionallyForbiddenPhrases = null) {
|
||||||
if (string.IsNullOrEmpty(password)) {
|
if (string.IsNullOrEmpty(password)) {
|
||||||
throw new ArgumentNullException(nameof(password));
|
throw new ArgumentNullException(nameof(password));
|
||||||
@@ -345,19 +357,5 @@ namespace ArchiSteamFarm.Core {
|
|||||||
|
|
||||||
return (result.Score < 4, string.IsNullOrEmpty(feedback.Warning) ? feedback.Suggestions.FirstOrDefault() : feedback.Warning);
|
return (result.Score < 4, string.IsNullOrEmpty(feedback.Warning) ? feedback.Suggestions.FirstOrDefault() : feedback.Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool RelativeDirectoryStartsWith(string directory, params string[] prefixes) {
|
|
||||||
if (string.IsNullOrEmpty(directory)) {
|
|
||||||
throw new ArgumentNullException(nameof(directory));
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CA1508 // False positive, params could be null when explicitly set
|
|
||||||
if ((prefixes == null) || (prefixes.Length == 0)) {
|
|
||||||
#pragma warning restore CA1508 // False positive, params could be null when explicitly set
|
|
||||||
throw new ArgumentNullException(nameof(prefixes));
|
|
||||||
}
|
|
||||||
|
|
||||||
return (from prefix in prefixes where directory.Length > prefix.Length let pathSeparator = directory[prefix.Length] where (pathSeparator == Path.DirectorySeparatorChar) || (pathSeparator == Path.AltDirectorySeparatorChar) select prefix).Any(prefix => directory.StartsWith(prefix, StringComparison.Ordinal));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,21 +24,29 @@ using OperatingSystem = JustArchiNET.Madness.OperatingSystemMadness.OperatingSys
|
|||||||
#endif
|
#endif
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using ArchiSteamFarm.Core;
|
using ArchiSteamFarm.Core;
|
||||||
|
using ArchiSteamFarm.Localization;
|
||||||
using CryptSharp.Utility;
|
using CryptSharp.Utility;
|
||||||
using SteamKit2;
|
using SteamKit2;
|
||||||
|
|
||||||
namespace ArchiSteamFarm.Helpers {
|
namespace ArchiSteamFarm.Helpers {
|
||||||
public static class ArchiCryptoHelper {
|
public static class ArchiCryptoHelper {
|
||||||
private const byte DefaultHashLength = 32;
|
private const byte DefaultHashLength = 32;
|
||||||
|
private const byte MinimumRecommendedCryptKeyBytes = 32;
|
||||||
private const ushort SteamParentalPbkdf2Iterations = 10000;
|
private const ushort SteamParentalPbkdf2Iterations = 10000;
|
||||||
private const byte SteamParentalSCryptBlocksCount = 8;
|
private const byte SteamParentalSCryptBlocksCount = 8;
|
||||||
private const ushort SteamParentalSCryptIterations = 8192;
|
private const ushort SteamParentalSCryptIterations = 8192;
|
||||||
|
|
||||||
|
internal static bool HasDefaultCryptKey { get; private set; } = true;
|
||||||
|
|
||||||
|
private static readonly ImmutableHashSet<string> ForbiddenCryptKeyPhrases = ImmutableHashSet.Create(StringComparer.InvariantCultureIgnoreCase, "crypt", "key", "cryptkey");
|
||||||
|
|
||||||
private static IEnumerable<byte> SteamParentalCharacters => Enumerable.Range('0', 10).Select(static character => (byte) character);
|
private static IEnumerable<byte> SteamParentalCharacters => Enumerable.Range('0', 10).Select(static character => (byte) character);
|
||||||
|
|
||||||
private static IEnumerable<byte[]> SteamParentalCodes {
|
private static IEnumerable<byte[]> SteamParentalCodes {
|
||||||
@@ -158,7 +166,22 @@ namespace ArchiSteamFarm.Helpers {
|
|||||||
throw new ArgumentNullException(nameof(key));
|
throw new ArgumentNullException(nameof(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utilities.InBackground(
|
||||||
|
() => {
|
||||||
|
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(key, ForbiddenCryptKeyPhrases);
|
||||||
|
|
||||||
|
if (isWeak) {
|
||||||
|
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningWeakCryptKey, reason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
EncryptionKey = Encoding.UTF8.GetBytes(key);
|
EncryptionKey = Encoding.UTF8.GetBytes(key);
|
||||||
|
HasDefaultCryptKey = false;
|
||||||
|
|
||||||
|
if (EncryptionKey.Length < MinimumRecommendedCryptKeyBytes) {
|
||||||
|
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningTooShortCryptKey, MinimumRecommendedCryptKeyBytes));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? DecryptAES(string encryptedString) {
|
private static string? DecryptAES(string encryptedString) {
|
||||||
|
|||||||
2477
ArchiSteamFarm/Localization/Strings.Designer.cs
generated
2477
ArchiSteamFarm/Localization/Strings.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -711,4 +711,16 @@ Process uptime: {1}</value>
|
|||||||
<value>Your encryption key seems to be weak. Consider choosing a stronger one for increased security. Reason: {0}</value>
|
<value>Your encryption key seems to be weak. Consider choosing a stronger one for increased security. Reason: {0}</value>
|
||||||
<comment>{0} will be replaced by the reason for the encryption key being considered weak</comment>
|
<comment>{0} will be replaced by the reason for the encryption key being considered weak</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="WarningTooShortCryptKey" xml:space="preserve">
|
||||||
|
<value>Your encryption key is too short. We recommend to use one that is at least {0} bytes (characters) long.</value>
|
||||||
|
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
|
||||||
|
</data>
|
||||||
|
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
|
||||||
|
<value>You're using {0} setting of {1} property, but you didn't provide a custom --cryptkey. You should provide a custom --cryptkey for increased security.</value>
|
||||||
|
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
|
||||||
|
</data>
|
||||||
|
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
|
||||||
|
<value>You're using {0} setting of {1} property, but you didn't provide a custom --cryptkey. This entirely defeats the protection, as ASF is forced to use its own (known) key. You should provide a custom --cryptkey for making use of the security benefit offered by this setting.</value>
|
||||||
|
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -47,8 +46,6 @@ using SteamKit2;
|
|||||||
|
|
||||||
namespace ArchiSteamFarm {
|
namespace ArchiSteamFarm {
|
||||||
internal static class Program {
|
internal static class Program {
|
||||||
private static readonly ImmutableHashSet<string> ForbiddenCryptKeyPhrases = ImmutableHashSet.Create(StringComparer.InvariantCultureIgnoreCase, "crypt", "key", "cryptkey");
|
|
||||||
|
|
||||||
internal static bool ConfigMigrate { get; private set; } = true;
|
internal static bool ConfigMigrate { get; private set; } = true;
|
||||||
internal static bool ConfigWatch { get; private set; } = true;
|
internal static bool ConfigWatch { get; private set; } = true;
|
||||||
internal static string? NetworkGroup { get; private set; }
|
internal static string? NetworkGroup { get; private set; }
|
||||||
@@ -102,16 +99,6 @@ namespace ArchiSteamFarm {
|
|||||||
throw new ArgumentNullException(nameof(cryptKey));
|
throw new ArgumentNullException(nameof(cryptKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
Utilities.InBackground(
|
|
||||||
() => {
|
|
||||||
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(cryptKey, ForbiddenCryptKeyPhrases);
|
|
||||||
|
|
||||||
if (isWeak) {
|
|
||||||
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningWeakCryptKey, reason));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
ArchiCryptoHelper.SetEncryptionKey(cryptKey);
|
ArchiCryptoHelper.SetEncryptionKey(cryptKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -598,6 +598,17 @@ namespace ArchiSteamFarm.Steam.Storage {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (botConfig.PasswordFormat) {
|
||||||
|
case ArchiCryptoHelper.ECryptoMethod.AES when ArchiCryptoHelper.HasDefaultCryptKey:
|
||||||
|
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningDefaultCryptKeyUsedForEncryption, botConfig.PasswordFormat, nameof(SteamPassword)));
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ArchiCryptoHelper.ECryptoMethod.ProtectedDataForCurrentUser when ArchiCryptoHelper.HasDefaultCryptKey:
|
||||||
|
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningDefaultCryptKeyUsedForHashing, botConfig.PasswordFormat, nameof(SteamPassword)));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Program.ConfigMigrate) {
|
if (!Program.ConfigMigrate) {
|
||||||
return (botConfig, null);
|
return (botConfig, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ using SteamKit2;
|
|||||||
namespace ArchiSteamFarm.Storage {
|
namespace ArchiSteamFarm.Storage {
|
||||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||||
public sealed class GlobalConfig {
|
public sealed class GlobalConfig {
|
||||||
private static readonly ImmutableHashSet<string> ForbiddenIPCPasswordPhrases = ImmutableHashSet.Create(StringComparer.InvariantCultureIgnoreCase, "ipc", "api", "gui", "asf-ui", "asf-gui");
|
|
||||||
|
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public const bool DefaultAutoRestart = true;
|
public const bool DefaultAutoRestart = true;
|
||||||
|
|
||||||
@@ -134,6 +132,8 @@ namespace ArchiSteamFarm.Storage {
|
|||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public static readonly ImmutableHashSet<uint> DefaultBlacklist = ImmutableHashSet<uint>.Empty;
|
public static readonly ImmutableHashSet<uint> DefaultBlacklist = ImmutableHashSet<uint>.Empty;
|
||||||
|
|
||||||
|
private static readonly ImmutableHashSet<string> ForbiddenIPCPasswordPhrases = ImmutableHashSet.Create(StringComparer.InvariantCultureIgnoreCase, "ipc", "api", "gui", "asf-ui", "asf-gui");
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public WebProxy? WebProxy {
|
public WebProxy? WebProxy {
|
||||||
@@ -506,7 +506,8 @@ namespace ArchiSteamFarm.Storage {
|
|||||||
return (null, null);
|
return (null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalConfig.IPCPasswordFormat == ArchiCryptoHelper.EHashingMethod.PlainText && !string.IsNullOrEmpty(globalConfig.IPCPassword)) {
|
switch (globalConfig.IPCPasswordFormat) {
|
||||||
|
case ArchiCryptoHelper.EHashingMethod.PlainText when !string.IsNullOrEmpty(globalConfig.IPCPassword):
|
||||||
Utilities.InBackground(
|
Utilities.InBackground(
|
||||||
() => {
|
() => {
|
||||||
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(globalConfig.IPCPassword!, ForbiddenIPCPasswordPhrases);
|
(bool isWeak, string? reason) = Utilities.TestPasswordStrength(globalConfig.IPCPassword!, ForbiddenIPCPasswordPhrases);
|
||||||
@@ -516,6 +517,13 @@ namespace ArchiSteamFarm.Storage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ArchiCryptoHelper.EHashingMethod.Pbkdf2 when ArchiCryptoHelper.HasDefaultCryptKey:
|
||||||
|
case ArchiCryptoHelper.EHashingMethod.SCrypt when ArchiCryptoHelper.HasDefaultCryptKey:
|
||||||
|
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningDefaultCryptKeyUsedForHashing, globalConfig.IPCPasswordFormat, nameof(IPCPassword)));
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Program.ConfigMigrate) {
|
if (!Program.ConfigMigrate) {
|
||||||
|
|||||||
Reference in New Issue
Block a user