Skip to content

Commit e02654a

Browse files
committed
Add localization, optimization, better error handling
1 parent a4778c2 commit e02654a

19 files changed

+649
-208
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
bin/
22
obj/
3-
.idea
3+
.idea
4+
.DS_Store
5+
*.DotSettings.user

YandexKeyExtractor/Decryptor.cs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,28 @@
55

66
namespace YandexKeyExtractor;
77

8-
public static class Decryptor
8+
internal static class Decryptor
99
{
10+
private const int maxStackallocSize = 4096;
11+
1012
public static string? Decrypt(string encryptedText, string password)
1113
{
1214
var base64Text = NormalizeBase64(encryptedText);
1315

14-
ReadOnlySpan<byte> textBytes = Convert.FromBase64String(base64Text).AsSpan();
16+
var textBytes = Convert.FromBase64String(base64Text);
1517

1618
const byte SaltLength = 16;
17-
var textData = textBytes[..^SaltLength];
18-
var textSalt = textBytes[^SaltLength..];
19+
var textData = textBytes.AsSpan()[..^SaltLength];
20+
var salt = textBytes[^SaltLength..];
1921

2022
var generatedPassword = SCrypt.ComputeDerivedKey(
21-
Encoding.UTF8.GetBytes(password), textSalt.ToArray(), 32768, 20, 1, null, 32
23+
Encoding.UTF8.GetBytes(password),
24+
salt,
25+
cost: 32768,
26+
blockSize: 20,
27+
parallel: 1,
28+
maxThreads: null,
29+
derivedKeyLength: 32
2230
);
2331

2432
using XSalsa20Poly1305 secureBox = new(generatedPassword);
@@ -27,8 +35,9 @@ public static class Decryptor
2735
var nonce = textData[..NonceLength];
2836
var dataWithMac = textData[NonceLength..];
2937

30-
31-
var message = dataWithMac.Length <= 4096 ? stackalloc byte[dataWithMac.Length] : new byte[dataWithMac.Length];
38+
var message = dataWithMac.Length <= maxStackallocSize
39+
? stackalloc byte[dataWithMac.Length]
40+
: new byte[dataWithMac.Length];
3241

3342
const byte MacLength = 16;
3443
var data = dataWithMac[MacLength..];
@@ -41,11 +50,27 @@ public static class Decryptor
4150

4251
private static string NormalizeBase64(string encryptedText)
4352
{
44-
return encryptedText.Replace('-', '+').Replace('_', '/') + (encryptedText.Length % 4) switch
53+
var suffixLength = (encryptedText.Length % 4) switch
4554
{
46-
2 => "==",
47-
3 => "=",
48-
_ => ""
55+
2 => 2,
56+
3 => 1,
57+
_ => 0
4958
};
59+
60+
var newLength = encryptedText.Length + suffixLength;
61+
var normalized = newLength <= maxStackallocSize / sizeof(char)
62+
? stackalloc char[newLength]
63+
: new char[newLength];
64+
65+
encryptedText.CopyTo(normalized);
66+
normalized.Replace('-', '+');
67+
normalized.Replace('_', '/');
68+
69+
if (suffixLength > 0)
70+
{
71+
normalized[^suffixLength..].Fill('=');
72+
}
73+
74+
return new string(normalized);
5075
}
5176
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace YandexKeyExtractor.Exceptions;
4+
5+
public class InvalidTrackIdException : Exception
6+
{
7+
public InvalidTrackIdException() : base("Invalid track ID.")
8+
{
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace YandexKeyExtractor.Exceptions;
4+
5+
public class NoValidBackupException : Exception
6+
{
7+
public NoValidBackupException() : base(Localization.NoValidBackup)
8+
{
9+
}
10+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace YandexKeyExtractor.Exceptions;
5+
6+
public class ResponseFailedException : Exception
7+
{
8+
public string ResponseName { get; }
9+
public string? Status { get; }
10+
public IReadOnlyCollection<string>? Errors { get; }
11+
12+
public ResponseFailedException(string responseName) : base($"{responseName} failed.")
13+
{
14+
ResponseName = responseName;
15+
}
16+
17+
public ResponseFailedException(string responseName, string? status, IReadOnlyCollection<string>? errors) : this(responseName)
18+
{
19+
Status = status;
20+
Errors = errors;
21+
}
22+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace YandexKeyExtractor.Models;
4+
5+
public class BackupInfo
6+
{
7+
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
8+
[JsonPropertyName("updated")]
9+
public uint Updated { get; set; }
10+
}

YandexKeyExtractor/Models/BackupInfoResponse.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,4 @@ public class BackupInfoResponse : StatusResponse
66
{
77
[JsonPropertyName("backup_info")]
88
public BackupInfo? Info { get; set; }
9-
10-
public class BackupInfo
11-
{
12-
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
13-
[JsonPropertyName("updated")]
14-
public uint Updated { get; set; }
15-
}
169
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
using System.Collections.Generic;
12
using System.Text.Json.Serialization;
23

34
namespace YandexKeyExtractor.Models;
45

56
public class CountryResponse : StatusResponse
67
{
78
[JsonPropertyName("country")]
8-
public string[]? Country { get; set; }
9+
public IReadOnlyCollection<string>? Country { get; set; }
910
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace YandexKeyExtractor.Models;
4+
5+
public class PhoneNumberInfo
6+
{
7+
[JsonPropertyName("e164")]
8+
public string? StandardizedNumber { get; set; }
9+
}

YandexKeyExtractor/Models/PhoneNumberResponse.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,4 @@ public class PhoneNumberResponse : StatusResponse
66
{
77
[JsonPropertyName("number")]
88
public PhoneNumberInfo? PhoneNumber { get; set; }
9-
10-
public class PhoneNumberInfo
11-
{
12-
[JsonPropertyName("e164")]
13-
public string? StandardizedNumber { get; set; }
14-
}
159
}

0 commit comments

Comments
 (0)