Нормализовать переводы строк в LF
Решение по TD-STYLE-ANALYZERS: LF — инструменты проекта (Python/Node) пишут LF, CRLF-.sh не работают на Linux CI (sh scripts/ci.sh), большинство файлов уже были LF. Добавлен .gitattributes (* text=auto eol=lf, бинарные исключения), .editorconfig переведён на lf, 1029 файлов конвертированы, git add --renormalize. Из индекса убраны закравшиеся archive/**/__pycache__/*.pyc.
This commit is contained in:
@@ -1,101 +1,101 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Deal.Telegram.Sessions;
|
||||
|
||||
/// <summary>
|
||||
/// AES-256-GCM-обёртка файла сессии тенанта.
|
||||
/// </summary>
|
||||
public sealed class SessionFileCipher
|
||||
{
|
||||
/// <summary>
|
||||
/// Префикс зашифрованного значения
|
||||
/// </summary>
|
||||
public const string EncryptedPrefix = "enc:";
|
||||
|
||||
// Размер nonce AES-GCM (рекомендованный NIST — 96 бит).
|
||||
private const int NonceSizeBytes = 12;
|
||||
|
||||
// Размер тега аутентичности.
|
||||
private const int TagSizeBytes = 16;
|
||||
|
||||
private readonly byte[] _key;
|
||||
|
||||
/// <summary>
|
||||
/// Создаёт шифр с ключом из опций
|
||||
/// </summary>
|
||||
/// <param name="options">Опции хранения сессий.</param>
|
||||
public SessionFileCipher(TgOptions options)
|
||||
{
|
||||
_key = options.SessionKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Шифрует содержимое файла сессии
|
||||
/// </summary>
|
||||
/// <param name="plainBytes">Открытое содержимое сессии (расшифрованная копия в памяти процесса).</param>
|
||||
/// <returns>Зашифрованное значение для записи в файл.</returns>
|
||||
public string EncryptBytes(byte[] plainBytes)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(plainBytes);
|
||||
|
||||
byte[] nonce = RandomNumberGenerator.GetBytes(NonceSizeBytes);
|
||||
byte[] cipherBytes = new byte[plainBytes.Length];
|
||||
byte[] tag = new byte[TagSizeBytes];
|
||||
|
||||
using (AesGcm aesGcm = new AesGcm(_key, TagSizeBytes))
|
||||
{
|
||||
aesGcm.Encrypt(nonce, plainBytes, cipherBytes, tag);
|
||||
}
|
||||
|
||||
byte[] payload = new byte[nonce.Length + cipherBytes.Length + tag.Length];
|
||||
nonce.CopyTo(payload, 0);
|
||||
cipherBytes.CopyTo(payload, nonce.Length);
|
||||
tag.CopyTo(payload, nonce.Length + cipherBytes.Length);
|
||||
|
||||
return EncryptedPrefix + Convert.ToBase64String(payload);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Расшифровывает значение файла сессии.
|
||||
/// </summary>
|
||||
/// <param name="encryptedValue">Содержимое файла сессии (enc: + base64).</param>
|
||||
/// <returns>Открытые байты сессии либо null (не наш формат).</returns>
|
||||
/// <exception cref="CryptographicException">Тег аутентичности не совпал (битый файл/чужой ключ).</exception>
|
||||
public byte[]? DecryptBytes(string encryptedValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(encryptedValue) || !encryptedValue.StartsWith(EncryptedPrefix, StringComparison.Ordinal))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] payload;
|
||||
try
|
||||
{
|
||||
payload = Convert.FromBase64String(encryptedValue[EncryptedPrefix.Length..]);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (payload.Length < NonceSizeBytes + TagSizeBytes)
|
||||
{
|
||||
// Слишком короткий payload: nonce и tag в нём не помещаются.
|
||||
return null;
|
||||
}
|
||||
|
||||
int cipherTextLength = payload.Length - NonceSizeBytes - TagSizeBytes;
|
||||
byte[] plainBytes = new byte[cipherTextLength];
|
||||
|
||||
using (AesGcm aesGcm = new AesGcm(_key, TagSizeBytes))
|
||||
{
|
||||
aesGcm.Decrypt(
|
||||
new ReadOnlySpan<byte>(payload, 0, NonceSizeBytes),
|
||||
new ReadOnlySpan<byte>(payload, NonceSizeBytes, cipherTextLength),
|
||||
new ReadOnlySpan<byte>(payload, NonceSizeBytes + cipherTextLength, TagSizeBytes),
|
||||
plainBytes);
|
||||
}
|
||||
|
||||
return plainBytes;
|
||||
}
|
||||
}
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Deal.Telegram.Sessions;
|
||||
|
||||
/// <summary>
|
||||
/// AES-256-GCM-обёртка файла сессии тенанта.
|
||||
/// </summary>
|
||||
public sealed class SessionFileCipher
|
||||
{
|
||||
/// <summary>
|
||||
/// Префикс зашифрованного значения
|
||||
/// </summary>
|
||||
public const string EncryptedPrefix = "enc:";
|
||||
|
||||
// Размер nonce AES-GCM (рекомендованный NIST — 96 бит).
|
||||
private const int NonceSizeBytes = 12;
|
||||
|
||||
// Размер тега аутентичности.
|
||||
private const int TagSizeBytes = 16;
|
||||
|
||||
private readonly byte[] _key;
|
||||
|
||||
/// <summary>
|
||||
/// Создаёт шифр с ключом из опций
|
||||
/// </summary>
|
||||
/// <param name="options">Опции хранения сессий.</param>
|
||||
public SessionFileCipher(TgOptions options)
|
||||
{
|
||||
_key = options.SessionKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Шифрует содержимое файла сессии
|
||||
/// </summary>
|
||||
/// <param name="plainBytes">Открытое содержимое сессии (расшифрованная копия в памяти процесса).</param>
|
||||
/// <returns>Зашифрованное значение для записи в файл.</returns>
|
||||
public string EncryptBytes(byte[] plainBytes)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(plainBytes);
|
||||
|
||||
byte[] nonce = RandomNumberGenerator.GetBytes(NonceSizeBytes);
|
||||
byte[] cipherBytes = new byte[plainBytes.Length];
|
||||
byte[] tag = new byte[TagSizeBytes];
|
||||
|
||||
using (AesGcm aesGcm = new AesGcm(_key, TagSizeBytes))
|
||||
{
|
||||
aesGcm.Encrypt(nonce, plainBytes, cipherBytes, tag);
|
||||
}
|
||||
|
||||
byte[] payload = new byte[nonce.Length + cipherBytes.Length + tag.Length];
|
||||
nonce.CopyTo(payload, 0);
|
||||
cipherBytes.CopyTo(payload, nonce.Length);
|
||||
tag.CopyTo(payload, nonce.Length + cipherBytes.Length);
|
||||
|
||||
return EncryptedPrefix + Convert.ToBase64String(payload);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Расшифровывает значение файла сессии.
|
||||
/// </summary>
|
||||
/// <param name="encryptedValue">Содержимое файла сессии (enc: + base64).</param>
|
||||
/// <returns>Открытые байты сессии либо null (не наш формат).</returns>
|
||||
/// <exception cref="CryptographicException">Тег аутентичности не совпал (битый файл/чужой ключ).</exception>
|
||||
public byte[]? DecryptBytes(string encryptedValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(encryptedValue) || !encryptedValue.StartsWith(EncryptedPrefix, StringComparison.Ordinal))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] payload;
|
||||
try
|
||||
{
|
||||
payload = Convert.FromBase64String(encryptedValue[EncryptedPrefix.Length..]);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (payload.Length < NonceSizeBytes + TagSizeBytes)
|
||||
{
|
||||
// Слишком короткий payload: nonce и tag в нём не помещаются.
|
||||
return null;
|
||||
}
|
||||
|
||||
int cipherTextLength = payload.Length - NonceSizeBytes - TagSizeBytes;
|
||||
byte[] plainBytes = new byte[cipherTextLength];
|
||||
|
||||
using (AesGcm aesGcm = new AesGcm(_key, TagSizeBytes))
|
||||
{
|
||||
aesGcm.Decrypt(
|
||||
new ReadOnlySpan<byte>(payload, 0, NonceSizeBytes),
|
||||
new ReadOnlySpan<byte>(payload, NonceSizeBytes, cipherTextLength),
|
||||
new ReadOnlySpan<byte>(payload, NonceSizeBytes + cipherTextLength, TagSizeBytes),
|
||||
plainBytes);
|
||||
}
|
||||
|
||||
return plainBytes;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user