MFATools 10.0.2
dotnet add package MFATools --version 10.0.2
NuGet\Install-Package MFATools -Version 10.0.2
<PackageReference Include="MFATools" Version="10.0.2" />
<PackageVersion Include="MFATools" Version="10.0.2" />
<PackageReference Include="MFATools" />
paket add MFATools --version 10.0.2
#r "nuget: MFATools, 10.0.2"
#:package MFATools@10.0.2
#addin nuget:?package=MFATools&version=10.0.2
#tool nuget:?package=MFATools&version=10.0.2
MFATools
MFATools es una librería completa en .NET para implementar autenticación de dos factores (2FA/MFA) basada en TOTP (Time-based One-Time Password), junto con utilidades adicionales para hashing de contraseñas y generación de contraseñas seguras. Facilita la generación y verificación de códigos TOTP, la creación de códigos QR para enrolamiento de usuarios, y proporciona proveedores configurables e intercambiables para QR, RNG y tiempo.
📑 Tabla de Contenidos
- Características
- Instalación
- Inicio Rápido
- Configuración
- Funcionalidades
- Proveedores
- API Reference
- Ejemplos de Uso
- Arquitectura
- Seguridad
- Testing
- Contribución
- Licencia
✨ Características
🔐 Autenticación de Dos Factores (2FA/TOTP)
- ✅ Generación de secretos en Base32 con RNG criptográficamente seguro
- ✅ Generación de códigos TOTP de 6-8 dígitos con múltiples algoritmos (SHA1, SHA256, SHA512, MD5)
- ✅ Verificación de códigos con soporte para discrepancia de tiempo
- ✅ Generación de URIs otpauth:// compatibles con Google Authenticator y similares
- ✅ Generación de códigos QR para enrolamiento fácil
- ✅ Validación de tiempo del servidor contra proveedores NTP/HTTP
🔒 Seguridad de Contraseñas
- ✅ Hashing con BCrypt (factor de trabajo 12)
- ✅ Verificación segura contra timing attacks
- ✅ Generación de contraseñas aleatorias con configuración flexible
🧩 Arquitectura Extensible
- ✅ Proveedores intercambiables para QR, RNG y Tiempo
- ✅ Integración con Dependency Injection de ASP.NET Core
- ✅ Sin dependencias externas para funcionalidad principal (excepto BCrypt y QRCoder)
📦 Instalación
Desde NuGet
dotnet add package MFATools
Desde el código fuente
git clone https://github.com/master-tech-team/MFATools.git
cd MFATools/MFATools
dotnet restore
dotnet build
🚀 Inicio Rápido
1. Registrar servicios en Program.cs o Startup.cs
using MFATools;
var builder = WebApplication.CreateBuilder(args);
// Registrar todos los servicios de MFATools
builder.Services.AddMFAServices(builder.Configuration);
var app = builder.Build();
2. Inyectar y usar en un controlador
using MFATools.Interfaces;
public class AuthController : ControllerBase
{
private readonly IMFAService _mfaService;
private readonly IPasswordHasherService _passwordHasher;
public AuthController(IMFAService mfaService, IPasswordHasherService passwordHasher)
{
_mfaService = mfaService;
_passwordHasher = passwordHasher;
}
[HttpPost("enroll")]
public IActionResult EnrollUser(string username)
{
// 1. Generar secreto
var secret = _mfaService.CreateSecret();
// 2. Generar URI otpauth
var uri = _mfaService.GetQrText(username, secret);
// 3. Generar QR como data URI
var qrDataUri = _mfaService.GetQrCodeImageAsDataUri(username, secret);
// 4. Guardar el secreto asociado al usuario (cifrado)
// ...
return Ok(new { secret, uri, qrDataUri });
}
[HttpPost("verify")]
public IActionResult VerifyCode(string username, string code)
{
// 1. Obtener secreto del usuario desde BD
var secret = GetUserSecret(username);
// 2. Verificar código
var isValid = _mfaService.VerifyCode(secret, code);
return isValid ? Ok() : Unauthorized();
}
}
⚙️ Configuración
appsettings.json
{
"MFA": {
"Issuer": "MiAplicacion"
}
}
Registro manual de proveedores
Si deseas personalizar los proveedores:
using MFATools.Providers;
using MFATools.Models;
services.AddSingleton<IQrCodeProvider, QRCoderQRCodeProvider>(); // O ImageChartsQrCodeProvider
services.AddSingleton<IRngProvider, DefaultRngProvider>(); // Criptográficamente seguro
services.AddSingleton<ITimeProvider, NTPTimeProvider>(); // O HttpTimeProvider / LocalMachineTimeProvider
services.AddSingleton<IPasswordHasherService, PasswordHasherService>();
services.AddSingleton<TwoFactorAuth>(sp =>
{
var issuer = Configuration["MFA:Issuer"];
var qr = sp.GetRequiredService<IQrCodeProvider>();
var rng = sp.GetRequiredService<IRngProvider>();
var time = sp.GetRequiredService<ITimeProvider>();
return new TwoFactorAuth(
issuer: issuer,
qrcodeprovider: qr,
rngprovider: rng,
timeprovider: time
);
});
services.AddScoped<IMFAService, MFAService>();
🎯 Funcionalidades
1. Autenticación de Dos Factores (2FA/TOTP)
Generar secreto
// Generar secreto con 80 bits (predeterminado)
var secret = _mfaService.CreateSecret();
// Generar secreto con bits personalizados
var secret128 = _mfaService.CreateSecret(128);
// Generar secreto permitiendo RNG no seguro (no recomendado)
var secretInsecure = _mfaService.CreateSecret(80, CryptoSecureRequirement.AllowInsecure);
Generar código TOTP
// Generar código para el momento actual
var code = _mfaService.GetCode(secret);
// Generar código para una fecha específica
var codeForDate = _mfaService.GetCode(secret, DateTime.UtcNow.AddMinutes(-1));
// Generar código para un timestamp específico
var codeForTimestamp = _mfaService.GetCode(secret, 1234567890);
Verificar código TOTP
// Verificar con discrepancia predeterminada (±1 período = ±30 segundos)
bool isValid = _mfaService.VerifyCode(secret, userCode);
// Verificar con discrepancia personalizada (±2 períodos = ±60 segundos)
bool isValid = _mfaService.VerifyCode(secret, userCode, discrepancy: 2);
// Verificar y obtener el timeslice que coincidió
bool isValid = _mfaService.VerifyCode(secret, userCode, out long timeSlice);
// Verificar para fecha/timestamp específico
bool isValid = _mfaService.VerifyCode(secret, userCode, discrepancy: 1, dateTime: specificDate);
Generar QR para enrolamiento
// Generar URI otpauth
var otpAuthUri = _mfaService.GetQrText("user@example.com", secret);
// Resultado: otpauth://totp/user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=MiApp&period=30&algorithm=SHA1&digits=6
// Generar QR como Data URI (tamaño predeterminado: 200px)
var qrDataUri = _mfaService.GetQrCodeImageAsDataUri("user@example.com", secret);
// Resultado: data:image/png;base64,iVBORw0KGgoAAAANSUhEU...
// Generar QR con tamaño personalizado
var qrDataUri300 = _mfaService.GetQrCodeImageAsDataUri("user@example.com", secret, size: 300);
Validar hora del servidor
// Validar hora contra proveedores NTP/HTTP predeterminados (leniency = 5 segundos)
try
{
_mfaService.EnsureCorrectTime();
// La hora del servidor es correcta
}
catch (TimeProviderException ex)
{
// La hora del servidor está desincronizada
Console.WriteLine(ex.Message);
}
// Validar con leniency personalizada
_mfaService.EnsureCorrectTime(leniency: 10);
// Validar contra proveedores específicos
var timeProviders = new List<ITimeProvider>
{
new NTPTimeProvider(),
new HttpTimeProvider()
};
_mfaService.EnsureCorrectTime(timeProviders, leniency: 5);
2. Hashing de Contraseñas
Usando IPasswordHasherService
// Hash de contraseña
string hashedPassword = _passwordHasher.HashPassword("MiContraseña123!");
// Verificar contraseña
bool isCorrect = _passwordHasher.VerifyPassword("MiContraseña123!", hashedPassword);
Usando el helper estático
using MFATools.Helpers;
// Hash de contraseña
string hashedPassword = PasswordHasher.HashPassword("MiContraseña123!");
// Verificar con extensión
bool isCorrect = "MiContraseña123!".VerifyPassword(hashedPassword);
Características:
- Usa BCrypt con factor de trabajo 12
- Resistente a rainbow tables y fuerza bruta
- Salting automático
3. Generación de Contraseñas Aleatorias
using MFATools.Helpers;
// Contraseña con configuración predeterminada (16 caracteres, mayúsculas, minúsculas, números, especiales)
var randomPwd = new RandomPassword();
string password = randomPwd.Next();
// Contraseña de longitud específica
var randomPwd20 = new RandomPassword(passwordLength: 20);
string password20 = randomPwd20.Next();
// Contraseña personalizada con builder pattern
var customPwd = new RandomPassword()
.IncludeLowercase()
.IncludeUppercase()
.IncludeNumeric()
.IncludeSpecial("!@#$%^&*()")
.LengthRequired(24)
.Next();
// Generar grupo de contraseñas
var passwords = new RandomPassword(16).NextGroup(10); // 10 contraseñas
Configuración avanzada:
var settings = new PasswordSettings(
includeLowercase: true,
includeUppercase: true,
includeNumeric: true,
includeSpecial: true,
passwordLength: 16,
maximumAttempts: 10000,
usingDefaults: false
);
var randomPwd = new RandomPassword(settings);
string password = randomPwd.Next();
Características:
- Evita más de 2 caracteres idénticos consecutivos
- Usa
RandomNumberGeneratorcriptográficamente seguro - Validación de requisitos (longitud, conjuntos de caracteres)
🔌 Proveedores
QR Code Providers
| Provider | Descripción | Ubicación |
|---|---|---|
| QRCoderQRCodeProvider | Generación local con QRCoder (predeterminado en DI) | Models/QRCoderQRCodeProvider.cs |
| QrServerQrCodeProvider | API externa api.qrserver.com |
Providers/Qr/QrServerQrCodeProvider.cs |
| ImageChartsQrCodeProvider | API externa image-charts.com |
Providers/Qr/ImageChartsQrCodeProvider.cs |
| QRicketQrCodeProvider | API externa qrickit.com |
Providers/Qr/QRicketQrCodeProvider.cs |
Interfaz:
public interface IQrCodeProvider
{
byte[] GetQrCodeImage(string text, int size);
string GetMimeType();
}
Uso personalizado:
services.AddSingleton<IQrCodeProvider, ImageChartsQrCodeProvider>();
RNG Providers
| Provider | Descripción | Criptográficamente Seguro |
|---|---|---|
| DefaultRngProvider | Usa RandomNumberGenerator de .NET (predeterminado) |
✅ Sí |
| HashRngProvider | Basado en hash SHA256 | ❌ No |
| PrngProvider | Generador pseudo-aleatorio | ❌ No |
Interfaz:
public interface IRngProvider
{
bool IsCryptographicallySecure { get; }
byte[] GetRandomBytes(int bytes);
}
Recomendación: Usar siempre DefaultRngProvider en producción.
Time Providers
| Provider | Descripción | Uso Recomendado |
|---|---|---|
| LocalMachineTimeProvider | Hora del sistema (predeterminado en DI) | Desarrollo/testing |
| NTPTimeProvider | Consulta servidor NTP pool.ntp.org |
Producción (servidores sin sincronización confiable) |
| HttpTimeProvider | Consulta API worldtimeapi.org |
Alternativa a NTP |
Interfaz:
public interface ITimeProvider
{
Task<DateTime> GetTimeAsync();
}
Uso múltiple para validación:
var timeProviders = new[]
{
new NTPTimeProvider(),
new HttpTimeProvider()
};
// Validar que la hora local no difiera más de 5 segundos de los proveedores externos
_twoFactorAuth.EnsureCorrectTime(timeProviders, leniency: 5);
📚 API Reference
IMFAService
Servicio principal para autenticación 2FA/TOTP.
Métodos
Generación de secretos:
string CreateSecret()
string CreateSecret(int bits)
string CreateSecret(int bits, CryptoSecureRequirement cryptoSecureRequirement)
Generación de códigos:
string GetCode(string secret)
string GetCode(string secret, DateTime dateTime)
string GetCode(string secret, long timestamp)
Verificación de códigos:
bool VerifyCode(string secret, string code)
bool VerifyCode(string secret, string code, int discrepancy)
bool VerifyCode(string secret, string code, int discrepancy, DateTime dateTime)
bool VerifyCode(string secret, string code, int discrepancy, DateTime dateTime, out long timeSlice)
bool VerifyCode(string secret, string code, int discrepancy, long timestamp)
bool VerifyCode(string secret, string code, int discrepancy, long timestamp, out long timeSlice)
bool VerifyCode(string secret, string code, int discrepancy, out long timeSlice)
bool VerifyCode(string secret, string code, out long timeSlice)
Generación de QR:
string GetQrText(string label, string secret)
string GetQrCodeImageAsDataUri(string label, string secret)
string GetQrCodeImageAsDataUri(string label, string secret, int size)
Validación de tiempo:
void EnsureCorrectTime(int leniency = 5)
void EnsureCorrectTime(IEnumerable<ITimeProvider> timeproviders)
void EnsureCorrectTime(IEnumerable<ITimeProvider> timeproviders, int leniency)
IPasswordHasherService
Servicio para hashing seguro de contraseñas.
public interface IPasswordHasherService
{
string HashPassword(string plainPassword);
bool VerifyPassword(string submittedPassword, string hashedPassword);
}
TwoFactorAuth
Clase principal que implementa la lógica TOTP. Se puede usar directamente o a través de IMFAService.
Propiedades
string Issuer- Emisor del token TOTPint Digits- Número de dígitos (predeterminado: 6)int Period- Período de validez en segundos (predeterminado: 30)Algorithm Algorithm- Algoritmo hash (predeterminado: SHA1)IQrCodeProvider QrCodeProvider- Proveedor de QRIRngProvider RngProvider- Proveedor de RNGITimeProvider TimeProvider- Proveedor de tiempo
Constantes
DEFAULTDIGITS = 6DEFAULTPERIOD = 30DEFAULTLENIENCY = 5DEFAULTALGORITHM = Algorithm.SHA1DEFAULTDISCREPANCY = 1DEFAULTSECRETBITS = 80DEFAULTQRCODESIZE = 200
Constructor
public TwoFactorAuth(
string issuer = null,
int digits = DEFAULTDIGITS,
int period = DEFAULTPERIOD,
Algorithm algorithm = Algorithm.SHA1,
IQrCodeProvider qrcodeprovider = null,
IRngProvider rngprovider = null,
ITimeProvider timeprovider = null
)
Enums
Algorithm
public enum Algorithm
{
SHA1,
SHA256,
SHA512,
MD5
}
CryptoSecureRequirement
public enum CryptoSecureRequirement
{
RequireSecure, // Requiere RNG criptográficamente seguro
AllowInsecure // Permite RNG no seguro
}
ErrorCorrectionLevel
public enum ErrorCorrectionLevel
{
Low = 'L', // 7% restaurable
Medium = 'M', // 15% restaurable
Quartile = 'Q', // 25% restaurable
High = 'H' // 30% restaurable
}
💡 Ejemplos de Uso
Ejemplo completo: Enrolamiento y verificación
public class MFAController : ControllerBase
{
private readonly IMFAService _mfaService;
private readonly IUserRepository _userRepo;
public MFAController(IMFAService mfaService, IUserRepository userRepo)
{
_mfaService = mfaService;
_userRepo = userRepo;
}
// Paso 1: Usuario solicita enrolamiento 2FA
[HttpPost("api/mfa/enroll")]
public async Task<IActionResult> EnrollMFA()
{
var userId = GetCurrentUserId();
// Generar secreto
var secret = _mfaService.CreateSecret();
// Guardar secreto cifrado en BD
await _userRepo.SaveEncryptedSecret(userId, secret);
// Generar QR
var email = await _userRepo.GetUserEmail(userId);
var qrDataUri = _mfaService.GetQrCodeImageAsDataUri(email, secret, size: 300);
return Ok(new
{
qrCode = qrDataUri,
manualEntryKey = secret
});
}
// Paso 2: Usuario verifica escaneó correctamente enviando primer código
[HttpPost("api/mfa/verify-enrollment")]
public async Task<IActionResult> VerifyEnrollment([FromBody] string code)
{
var userId = GetCurrentUserId();
var secret = await _userRepo.GetEncryptedSecret(userId);
if (_mfaService.VerifyCode(secret, code))
{
await _userRepo.EnableMFA(userId);
return Ok(new { message = "2FA activado exitosamente" });
}
return BadRequest(new { error = "Código inválido" });
}
// Paso 3: Login con 2FA
[HttpPost("api/auth/login-mfa")]
public async Task<IActionResult> LoginWithMFA([FromBody] LoginMFARequest request)
{
// Validar usuario y contraseña primero
var user = await _userRepo.ValidateCredentials(request.Email, request.Password);
if (user == null)
return Unauthorized();
// Si tiene 2FA habilitado, verificar código
if (user.MFAEnabled)
{
var secret = await _userRepo.GetEncryptedSecret(user.Id);
if (!_mfaService.VerifyCode(secret, request.MFACode))
return Unauthorized(new { error = "Código 2FA inválido" });
}
// Generar JWT o sesión
var token = GenerateAuthToken(user);
return Ok(new { token });
}
}
Ejemplo: Validación de hora del servidor en startup
// En Program.cs o Startup.cs
public void Configure(IApplicationBuilder app, IMFAService mfaService)
{
// Validar hora del servidor al iniciar la aplicación
try
{
mfaService.EnsureCorrectTime(leniency: 10);
Console.WriteLine("✅ Hora del servidor sincronizada correctamente");
}
catch (TimeProviderException ex)
{
Console.WriteLine($"⚠️ ADVERTENCIA: {ex.Message}");
Console.WriteLine("Los códigos TOTP pueden no funcionar correctamente");
}
// Resto de configuración...
}
🏗️ Arquitectura
Diagrama de componentes
MFATools
├── Models
│ ├── TwoFactorAuth.cs # Lógica principal TOTP
│ ├── DefaultProviders.cs # Proveedores predeterminados
│ └── QRCoderQRCodeProvider.cs # Implementación QR local
├── Services
│ ├── MFAService.cs # Fachada para DI
│ └── PasswordHasherService.cs # Servicio de hashing
├── Interfaces
│ ├── IMFAService.cs
│ ├── IPasswordHasherService.cs
│ ├── IQrCodeProvider.cs
│ ├── IRngProvider.cs
│ └── ITimeProvider.cs
├── Providers
│ ├── Qr/ # Implementaciones QR
│ ├── Rng/ # Implementaciones RNG
│ └── Time/ # Implementaciones Time
├── Helpers
│ ├── PasswordHasher.cs # Helper estático BCrypt
│ └── RandomPassword.cs # Generador de contraseñas
├── Enums
│ ├── Algorithm.cs
│ ├── CryptoSecureRequirement.cs
│ └── ErrorCorrectionLevel.cs
├── Exceptions
│ └── TimeProviderException.cs
└── DependencyInjection.cs # Extensiones para IServiceCollection
Flujo de ejecución típico
- Registro DI:
AddMFAServices()registra todos los servicios y proveedores - Inyección: Controladores/servicios reciben
IMFAServiceyIPasswordHasherService - Delegación:
MFAServicedelega aTwoFactorAuth - Proveedores:
TwoFactorAuthusa proveedores inyectados (IQrCodeProvider,IRngProvider,ITimeProvider)
Lifetime recomendados
| Servicio/Proveedor | Lifetime | Razón |
|---|---|---|
IQrCodeProvider |
Singleton | Sin estado |
IRngProvider |
Singleton | Sin estado |
ITimeProvider |
Singleton | Sin estado |
TwoFactorAuth |
Singleton | Sin estado por usuario |
IMFAService |
Scoped | Apropiado para web (request-scoped) |
IPasswordHasherService |
Singleton | Sin estado |
🔒 Seguridad
Mejores prácticas
Almacenamiento de secretos:
- ❌ NO guardar secretos en texto plano
- ✅ Cifrar secretos antes de almacenar en BD
- ✅ Usar Azure Key Vault, AWS Secrets Manager, o similar
RNG:
- ✅ Usar siempre
DefaultRngProvider(criptográficamente seguro) - ❌ Nunca usar
PrngProvideroHashRngProvideren producción
- ✅ Usar siempre
Sincronización de tiempo:
- ✅ Sincronizar servidores con NTP
- ✅ Validar hora del servidor en startup con
EnsureCorrectTime() - ✅ Usar
NTPTimeProvidersi la hora local no es confiable
Discrepancia de tiempo:
- ✅ Usar discrepancia de 1-2 períodos (30-60 segundos)
- ❌ No usar discrepancias muy grandes (reduce seguridad)
Códigos de recuperación:
- ✅ Generar códigos de recuperación para usuarios que pierden acceso
- ✅ Guardar códigos hasheados con BCrypt
Hashing de contraseñas:
- ✅ BCrypt con factor de trabajo 12 (predeterminado)
- ✅ Ajustar factor de trabajo según capacidad del servidor
Ejemplo: Cifrado de secretos
using System.Security.Cryptography;
using System.Text;
public class SecretEncryption
{
private readonly byte[] _encryptionKey;
public SecretEncryption(IConfiguration config)
{
// Cargar clave de cifrado desde Key Vault o configuración segura
_encryptionKey = Convert.FromBase64String(config["Encryption:Key"]);
}
public string Encrypt(string plainSecret)
{
using var aes = Aes.Create();
aes.Key = _encryptionKey;
aes.GenerateIV();
using var encryptor = aes.CreateEncryptor();
var plainBytes = Encoding.UTF8.GetBytes(plainSecret);
var encryptedBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
// Combinar IV + datos cifrados
var result = new byte[aes.IV.Length + encryptedBytes.Length];
Buffer.BlockCopy(aes.IV, 0, result, 0, aes.IV.Length);
Buffer.BlockCopy(encryptedBytes, 0, result, aes.IV.Length, encryptedBytes.Length);
return Convert.ToBase64String(result);
}
public string Decrypt(string encryptedSecret)
{
var fullData = Convert.FromBase64String(encryptedSecret);
using var aes = Aes.Create();
aes.Key = _encryptionKey;
// Extraer IV y datos
var iv = new byte[aes.IV.Length];
var encryptedBytes = new byte[fullData.Length - iv.Length];
Buffer.BlockCopy(fullData, 0, iv, 0, iv.Length);
Buffer.BlockCopy(fullData, iv.Length, encryptedBytes, 0, encryptedBytes.Length);
aes.IV = iv;
using var decryptor = aes.CreateDecryptor();
var decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(decryptedBytes);
}
}
🧪 Testing
Testing unitario con proveedores falsos
public class FakeTimeProvider : ITimeProvider
{
private readonly DateTime _fixedTime;
public FakeTimeProvider(DateTime fixedTime)
{
_fixedTime = fixedTime;
}
public Task<DateTime> GetTimeAsync() => Task.FromResult(_fixedTime);
}
public class FakeRngProvider : IRngProvider
{
public bool IsCryptographicallySecure => false;
public byte[] GetRandomBytes(int bytes)
{
// Retornar bytes predecibles para testing
return Enumerable.Repeat((byte)0x42, bytes).ToArray();
}
}
[Test]
public void VerifyCode_WithFixedTime_ReturnsTrue()
{
// Arrange
var fixedTime = new DateTime(2025, 1, 1, 12, 0, 0, DateTimeKind.Utc);
var fakeTimeProvider = new FakeTimeProvider(fixedTime);
var tfa = new TwoFactorAuth(
issuer: "Test",
timeprovider: fakeTimeProvider
);
var secret = tfa.CreateSecret();
var code = tfa.GetCode(secret, fixedTime);
// Act
var isValid = tfa.VerifyCode(secret, code);
// Assert
Assert.IsTrue(isValid);
}
Testing de integración
[TestClass]
public class MFAServiceIntegrationTests
{
private ServiceProvider _serviceProvider;
private IMFAService _mfaService;
[TestInitialize]
public void Setup()
{
var services = new ServiceCollection();
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["MFA:Issuer"] = "TestApp"
})
.Build();
services.AddMFAServices(config);
_serviceProvider = services.BuildServiceProvider();
_mfaService = _serviceProvider.GetRequiredService<IMFAService>();
}
[TestMethod]
public void EndToEnd_CreateSecretAndVerifyCode_Success()
{
// Arrange
var secret = _mfaService.CreateSecret();
// Act
var code = _mfaService.GetCode(secret);
var isValid = _mfaService.VerifyCode(secret, code);
// Assert
Assert.IsTrue(isValid);
}
[TestCleanup]
public void Cleanup()
{
_serviceProvider?.Dispose();
}
}
🤝 Contribución
¡Las contribuciones son bienvenidas! Para contribuir:
- Fork el repositorio
- Crea una rama para tu feature (
git checkout -b feature/AmazingFeature) - Commit tus cambios (
git commit -m 'Add some AmazingFeature') - Push a la rama (
git push origin feature/AmazingFeature) - Abre un Pull Request
Lineamientos
- Seguir convenciones de código C# y .NET
- Agregar tests unitarios para nuevas funcionalidades
- Documentar APIs públicas con XML comments
- Actualizar README si se agregan features importantes
📄 Licencia
Este proyecto está licenciado bajo la Licencia MIT. Ver el archivo LICENSE para más detalles.
📞 Contacto y Soporte
- Repositorio: https://github.com/master-tech-team/MFATools
- Issues: https://github.com/master-tech-team/MFATools/issues
- Equipo: Master Tech Team
🙏 Agradecimientos
- QRCoder - Generación local de códigos QR
- BCrypt.Net-Next - Hashing seguro de contraseñas
- Inspirado en implementaciones TOTP estándar (RFC 6238)
📝 Changelog
v10.0.1 (Actual)
- Primera versión pública
- Generación y verificación de códigos TOTP
- Creación de secretos y URIs otpauth
- Generación de códigos QR para enrolamiento
- Proveedores configurables para QR, RNG y tiempo
- Integración con Dependency Injection
- Hashing de contraseñas con BCrypt
- Generación de contraseñas aleatorias
- Documentación completa y ejemplos
¡Gracias por usar MFATools! 🚀🔐
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- BCrypt.Net-Next (>= 4.0.3)
- Microsoft.Extensions.Configuration (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.0)
- QRCoder (>= 1.7.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v10.0.0:
- Primera versión pública
- Generación y verificación de códigos TOTP
- Creación de secretos y URIs otpauth
- Generación de códigos QR para enrolamiento
- Proveedores configurables para QR, RNG y tiempo
- Integración con Dependency Injection
- Ejemplo de uso y documentación básica