HashGenerator
Documentație pentru serviciul HashGenerator
1. Descriere Generală
HashGenerator
este un serviciu server-side care oferă funcționalități de generare hash criptografic pentru aplicațiile FOD. În prezent, serviciul suportă generarea de hash-uri SHA-1 pentru diverse scopuri de securitate și integritate a datelor.
Caracteristici principale: - Generare hash SHA-1 - Implementare asincronă - Suport UTF-8 pentru caractere speciale - Returnare rezultat ca array de bytes - Utilizare în verificarea integrității datelor
Notă importantă: SHA-1 nu mai este considerat sigur pentru aplicații criptografice critice. Pentru aplicații noi, considerați SHA-256 sau SHA-512.
2. Configurare și Înregistrare
// Program.cs sau Startup.cs (server-side)
builder.Services.AddScoped<IHashGenerator, HashGenerator>();
// În modulul Server.ServicesSetup
public static IServiceCollection AddServerServices(this IServiceCollection services)
{
services.AddScoped<IHashGenerator, HashGenerator>();
return services;
}
3. Interfață
public interface IHashGenerator
{
Task<byte[]> GetSha1(string value);
}
4. Metodă Disponibilă
GetSha1
Generează un hash SHA-1 pentru valoarea string furnizată.
Parametri:
- value
(string) - Șirul de caractere pentru care se generează hash-ul
Returnează:
- Task<byte[]>
- Hash-ul SHA-1 ca array de bytes (20 bytes)
Note: - Folosește encoding UTF-8 pentru conversia string-ului - SHA-1 produce întotdeauna un hash de 160 biți (20 bytes) - Metoda este deterministă - același input produce același hash
5. Exemple de Utilizare
Generare hash simplu
public class DocumentService
{
private readonly IHashGenerator _hashGenerator;
public DocumentService(IHashGenerator hashGenerator)
{
_hashGenerator = hashGenerator;
}
public async Task<string> GenerateDocumentHash(string documentContent)
{
// Generare hash
byte[] hashBytes = await _hashGenerator.GetSha1(documentContent);
// Conversie la string hexadecimal
string hashString = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
return hashString;
}
}
Verificare integritate fișier
public class FileIntegrityService
{
private readonly IHashGenerator _hashGenerator;
private readonly IFileRepository _fileRepository;
public async Task<FileIntegrityResult> VerifyFileIntegrity(
int fileId,
string expectedHash)
{
var file = await _fileRepository.GetById(fileId);
if (file == null)
{
return new FileIntegrityResult
{
IsValid = false,
Message = "Fișierul nu a fost găsit"
};
}
// Calculează hash-ul actual
var currentHashBytes = await _hashGenerator.GetSha1(file.Content);
var currentHash = Convert.ToBase64String(currentHashBytes);
// Compară cu hash-ul așteptat
var isValid = currentHash == expectedHash;
return new FileIntegrityResult
{
IsValid = isValid,
CurrentHash = currentHash,
ExpectedHash = expectedHash,
Message = isValid
? "Integritatea fișierului este validă"
: "Fișierul a fost modificat"
};
}
}
Generare token unic
public class TokenService
{
private readonly IHashGenerator _hashGenerator;
public async Task<string> GenerateUniqueToken(string userId, DateTime timestamp)
{
// Combină mai multe elemente pentru unicitate
var tokenData = $"{userId}|{timestamp:O}|{Guid.NewGuid()}";
// Generează hash
var hashBytes = await _hashGenerator.GetSha1(tokenData);
// Conversie la Base64 pentru URL-safe token
var token = Convert.ToBase64String(hashBytes)
.Replace("+", "-")
.Replace("/", "_")
.TrimEnd('=');
return token;
}
}
6. Verificare parolă (exemplu educativ)
public class PasswordVerificationService
{
private readonly IHashGenerator _hashGenerator;
// NOTĂ: Acesta este doar un exemplu. Pentru producție, folosiți
// algoritmi specializați pentru parole (bcrypt, scrypt, Argon2)
public async Task<bool> VerifyPassword(
string inputPassword,
string salt,
string storedHash)
{
// Combină parola cu salt
var saltedPassword = $"{inputPassword}{salt}";
// Generează hash
var hashBytes = await _hashGenerator.GetSha1(saltedPassword);
var inputHash = Convert.ToBase64String(hashBytes);
// Compară hash-urile
return inputHash == storedHash;
}
public async Task<(string hash, string salt)> HashPassword(string password)
{
// Generează salt aleatoriu
var salt = Guid.NewGuid().ToString("N");
// Hash cu salt
var saltedPassword = $"{password}{salt}";
var hashBytes = await _hashGenerator.GetSha1(saltedPassword);
var hash = Convert.ToBase64String(hashBytes);
return (hash, salt);
}
}
7. Checksum pentru date
public class DataChecksumService
{
private readonly IHashGenerator _hashGenerator;
public async Task<ChecksumResult> GenerateChecksum<T>(T data)
{
// Serializare date
var json = JsonSerializer.Serialize(data);
// Generare checksum
var hashBytes = await _hashGenerator.GetSha1(json);
return new ChecksumResult
{
Data = data,
Checksum = Convert.ToBase64String(hashBytes),
Algorithm = "SHA-1",
GeneratedAt = DateTime.UtcNow
};
}
public async Task<bool> ValidateChecksum<T>(T data, string expectedChecksum)
{
var result = await GenerateChecksum(data);
return result.Checksum == expectedChecksum;
}
}
8. Cache key generation
public class CacheKeyService
{
private readonly IHashGenerator _hashGenerator;
private readonly IMemoryCache _cache;
public async Task<string> GenerateCacheKey(params object[] keyComponents)
{
// Combină componentele cheii
var keyData = string.Join("|", keyComponents.Select(c => c?.ToString() ?? "null"));
// Generează hash pentru cheie scurtă și unică
var hashBytes = await _hashGenerator.GetSha1(keyData);
var shortHash = Convert.ToBase64String(hashBytes).Substring(0, 8);
return $"cache_{shortHash}";
}
public async Task<T> GetOrCreateAsync<T>(
string prefix,
object[] keyComponents,
Func<Task<T>> factory,
TimeSpan expiration)
{
var cacheKey = await GenerateCacheKey(keyComponents);
var fullKey = $"{prefix}_{cacheKey}";
return await _cache.GetOrCreateAsync(fullKey, async entry =>
{
entry.AbsoluteExpirationRelativeToNow = expiration;
return await factory();
});
}
}
9. Deduplicare date
public class DataDeduplicationService
{
private readonly IHashGenerator _hashGenerator;
private readonly IDataRepository _repository;
public async Task<DeduplicationResult> CheckDuplicate(string content)
{
// Generează hash pentru conținut
var hashBytes = await _hashGenerator.GetSha1(content);
var contentHash = Convert.ToBase64String(hashBytes);
// Caută duplicate în baza de date
var existingRecord = await _repository.FindByHash(contentHash);
if (existingRecord != null)
{
return new DeduplicationResult
{
IsDuplicate = true,
ExistingRecordId = existingRecord.Id,
Hash = contentHash,
Message = "Conținut duplicat detectat"
};
}
return new DeduplicationResult
{
IsDuplicate = false,
Hash = contentHash,
Message = "Conținut unic"
};
}
public async Task<int> RemoveDuplicates(IEnumerable<DataRecord> records)
{
var uniqueRecords = new Dictionary<string, DataRecord>();
var duplicatesRemoved = 0;
foreach (var record in records)
{
var hashBytes = await _hashGenerator.GetSha1(record.Content);
var hash = Convert.ToBase64String(hashBytes);
if (!uniqueRecords.ContainsKey(hash))
{
uniqueRecords[hash] = record;
}
else
{
duplicatesRemoved++;
}
}
return duplicatesRemoved;
}
}
10. Implementare extinsă cu mai mulți algoritmi
public interface IExtendedHashGenerator : IHashGenerator
{
Task<byte[]> GetSha256(string value);
Task<byte[]> GetSha512(string value);
Task<byte[]> GetMd5(string value); // Doar pentru compatibilitate legacy
}
public class ExtendedHashGenerator : IExtendedHashGenerator
{
public async Task<byte[]> GetSha1(string value)
{
return await Task.FromResult(
SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(value))
);
}
public async Task<byte[]> GetSha256(string value)
{
return await Task.FromResult(
SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(value))
);
}
public async Task<byte[]> GetSha512(string value)
{
return await Task.FromResult(
SHA512.Create().ComputeHash(Encoding.UTF8.GetBytes(value))
);
}
public async Task<byte[]> GetMd5(string value)
{
return await Task.FromResult(
MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(value))
);
}
}
11. Testing
[TestClass]
public class HashGeneratorTests
{
private IHashGenerator _hashGenerator;
[TestInitialize]
public void Setup()
{
_hashGenerator = new HashGenerator();
}
[TestMethod]
public async Task GetSha1_SameInput_ReturnsSameHash()
{
// Arrange
var input = "test string";
// Act
var hash1 = await _hashGenerator.GetSha1(input);
var hash2 = await _hashGenerator.GetSha1(input);
// Assert
CollectionAssert.AreEqual(hash1, hash2);
}
[TestMethod]
public async Task GetSha1_DifferentInput_ReturnsDifferentHash()
{
// Arrange
var input1 = "test string 1";
var input2 = "test string 2";
// Act
var hash1 = await _hashGenerator.GetSha1(input1);
var hash2 = await _hashGenerator.GetSha1(input2);
// Assert
CollectionAssert.AreNotEqual(hash1, hash2);
}
[TestMethod]
public async Task GetSha1_ReturnsCorrectLength()
{
// Arrange
var input = "test";
// Act
var hash = await _hashGenerator.GetSha1(input);
// Assert
Assert.AreEqual(20, hash.Length); // SHA-1 = 160 bits = 20 bytes
}
[TestMethod]
public async Task GetSha1_KnownValue_ReturnsExpectedHash()
{
// Arrange
var input = "hello world";
var expectedHex = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed";
// Act
var hash = await _hashGenerator.GetSha1(input);
var actualHex = BitConverter.ToString(hash).Replace("-", "").ToLower();
// Assert
Assert.AreEqual(expectedHex, actualHex);
}
}
12. Best Practices
- Securitate: SHA-1 nu mai este recomandat pentru aplicații criptografice. Folosiți SHA-256 sau SHA-512
- Salt pentru parole: Întotdeauna folosiți salt pentru hash-uri de parole
- Algoritmi specializați: Pentru parole, folosiți bcrypt, scrypt sau Argon2
- Comparare sigură: Folosiți comparare constantă în timp pentru hash-uri
- Encoding consistent: Folosiți întotdeauna același encoding (UTF-8)
- Stocare: Stocați hash-urile ca Base64 sau hexadecimal pentru eficiență
13. Migrare la algoritmi mai siguri
public class HashMigrationService
{
private readonly IHashGenerator _oldHashGenerator;
private readonly IExtendedHashGenerator _newHashGenerator;
public async Task<MigrationResult> MigrateHash(
string value,
string oldSha1Hash)
{
// Verifică hash-ul vechi
var oldHashBytes = await _oldHashGenerator.GetSha1(value);
var oldHash = Convert.ToBase64String(oldHashBytes);
if (oldHash != oldSha1Hash)
{
return new MigrationResult
{
Success = false,
Error = "Hash vechi invalid"
};
}
// Generează hash nou
var newHashBytes = await _newHashGenerator.GetSha256(value);
var newHash = Convert.ToBase64String(newHashBytes);
return new MigrationResult
{
Success = true,
OldHash = oldHash,
NewHash = newHash,
Algorithm = "SHA-256"
};
}
}
14. Concluzie
HashGenerator
oferă funcționalitate de bază pentru generarea hash-urilor SHA-1 în aplicațiile FOD. Deși simplu și eficient pentru verificarea integrității datelor non-critice, serviciul ar trebui extins cu algoritmi mai moderni pentru aplicații care necesită securitate sporită. Pentru aplicații noi, considerați implementarea SHA-256 sau SHA-512.