dumbtv
dumbtv가 ADB로 Fire TV에서 광고·추적·업데이트 알림을 제거, 루트·앱 변경 없이, 무료 오픈소스
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Secure end-to-end encryption for .NET — modern cryptographic protocols, production-ready
🔒 End-to-End Encrypted • 🔑 X3DH + Double Ratchet • 📱 Multi-Device • 🏢 Enterprise-Ready
A comprehensive, production-ready end-to-end encryption library for .NET applications implementing modern cryptographic protocols with a focus on security, privacy, and usability. Now with advanced features including post-quantum cryptography preparation, WebRTC transport, message batching, and enterprise-grade monitoring capabilities.README 전문 보기 ↗Secure end-to-end encryption for .NET — modern cryptographic protocols, production-ready
🔒 End-to-End Encrypted • 🔑 X3DH + Double Ratchet • 📱 Multi-Device • 🏢 Enterprise-Ready
Quick Start • Features • Documentation • License
A comprehensive, production-ready end-to-end encryption library for .NET applications implementing modern cryptographic protocols with a focus on security, privacy, and usability. Now with advanced features including post-quantum cryptography preparation, WebRTC transport, message batching, and enterprise-grade monitoring capabilities.
// Install via NuGet
// dotnet add package LibEmiddle --version 2.7.0
using LibEmiddle.API;
using LibEmiddle.Domain.Enums;
// Configure the client
var options = new LibEmiddleClientOptions
{
TransportType = TransportType.Http,
ServerEndpoint = "https://your-server.com",
EnableMultiDevice = true,
EnableMessageHistory = true
};
// Create and initialize the client
using var client = new LibEmiddleClient(options);
await client.InitializeAsync();
// Start a secure conversation
var chatSession = await client.CreateChatSessionAsync(recipientPublicKey, "user123");
var encryptedMessage = await chatSession.EncryptAsync("Hello, secure world!");
PN header field lets messages that arrive across a ratchet step still decrypt (v2.7)LibEmiddleClient for all operations (IAsyncDisposable support)LibEmiddleException with typed LibEmiddleErrorCode for precise error handlingResilienceManagerNote: connection pooling, session backup, advanced key-rotation scheduling, WebRTC transport, and post-quantum crypto are present as API stubs only — they satisfy their interfaces but perform no real work. See Feature Maturity before depending on them.
// First contact: supply the recipient's full X3DHPublicBundle as UTF-8 JSON bytes.
// The library caches the bundle for future lookups by identity key.
byte[] bundleBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(recipientBundle));
var chatSession = await client.CreateChatSessionAsync(
bundleBytes,
recipientUserId: "[email protected]",
options: new ChatSessionOptions
{
RotationStrategy = KeyRotationStrategy.Aggressive,
EnableMessageHistory = true
});
// Subsequent contacts: a bare 32-byte identity key is sufficient
// (the bundle is looked up from the local cache).
var chatSession = await client.CreateChatSessionAsync(
recipientPublicKey, // 32-byte Ed25519 identity key
recipientUserId: "[email protected]",
options: new ChatSessionOptions { RotationStrategy = KeyRotationStrategy.Standard });
// Send encrypted messages
var encryptedMessage = await chatSession.EncryptAsync("Hello Alice!");
// Receive and decrypt messages
var decryptedMessage = await chatSession.DecryptAsync(incomingEncryptedMessage);
Console.WriteLine($"Received: {decryptedMessage}");
// Send message directly by recipient key (creates session if needed)
var directMessage = await client.SendChatMessageAsync(
recipientPublicKey,
"Direct message without explicit session creation");
// Handle incoming messages with events
chatSession.MessageReceived += (sender, args) =>
{
Console.WriteLine($"New message: {args.DecryptedContent}");
};
// Enable multi-device support in client options
var options = new LibEmiddleClientOptions
{
EnableMultiDevice = true,
MaxLinkedDevices = 5
};
using var client = new LibEmiddleClient(options);
await client.InitializeAsync();
// Link a new device
var linkMessage = client.CreateDeviceLinkMessage(newDevicePublicKey);
// Process device link on the new device
var success = await client.ProcessDeviceLinkMessageAsync(linkMessage);
// Synchronize data across devices
var syncData = Encoding.UTF8.GetBytes("Session data to sync");
var syncMessages = client.CreateSyncMessages(syncData);
// Send sync messages to all linked devices
foreach (var (deviceId, message) in syncMessages)
{
await client.SendToDeviceAsync(deviceId, message);
}
// Revoke a compromised device
await client.RevokeDeviceAsync(compromisedDevicePublicKey, "Device lost");
// Create a new group
var groupSession = await client.CreateGroupAsync(
groupId: "team-secure-chat",
groupName: "Development Team",
options: new GroupSessionOptions
{
RotationStrategy = KeyRotationStrategy.Standard,
MaxMembers = 50
});
// Add members to the group
await groupSession.AddMemberAsync(member1PublicKey, MemberRole.Admin);
await groupSession.AddMemberAsync(member2PublicKey, MemberRole.Member);
// Send encrypted group messages
var encryptedGroupMessage = await client.SendGroupMessageAsync(
"team-secure-chat",
"Confidential team discussion");
// Join an existing group using distribution message
var joinedGroup = await client.JoinGroupAsync(distributionMessage);
// Handle group events
groupSession.MemberAdded += (sender, args) =>
{
Console.WriteLine($"Member {args.MemberPublicKey} joined the group");
};
groupSession.MessageReceived += (sender, args) =>
{
Console.WriteLine($"Group message: {args.DecryptedContent}");
};
// Rotate group keys (admin only)
await groupSession.RotateKeysAsync();
// Leave the group
await client.LeaveGroupAsync("team-secure-chat");
LibEmiddle uses a flexible mailbox transport system for asynchronous encrypted message delivery. The transport layer handles message routing while encryption is managed by the Double Ratchet protocol.
// Perfect for testing and local development
var options = new LibEmiddleClientOptions
{
TransportType = TransportType.InMemory
};
using var client = new LibEmiddleClient(options);
await client.InitializeAsync();
// Production-ready HTTP REST API transport
var options = new LibEmiddleClientOptions
{
TransportType = TransportType.Http,
ServerEndpoint = "https://messaging-server.example.com/api",
NetworkTimeoutMs = 30000,
EnableStrictCertificateValidation = true,
CustomHeaders = new Dictionary<string, string>
{
["Authorization"] = "Bearer your-jwt-token"
}
};
using var client = new LibEmiddleClient(options);
await client.InitializeAsync();
// Listen for incoming messages
client.MessageReceived += async (sender, args) =>
{
Console.WriteLine($"From: {Convert.ToBase64String(args.Message.SenderKey)[..8]}...");
Console.WriteLine($"Message: {args.DecryptedContent}");
// Optionally mark as read
await client.MarkMessageAsReadAsync(args.Message.Id);
};
// Start listening (default 5 second polling interval)
await client.StartListeningAsync();
// For low-latency applications, use shorter polling
await client.StartListeningAsync(pollingInterval: 1000); // 1 second
// Stop listening when done
await client.StopListeningAsync();
// Send a message (automatically encrypted with Double Ratchet)
await client.SendChatMessageAsync(recipientPublicKey, "Hello!");
// Or use ChatSession for more control (requires bundle cached or pass bundleBytes on first use)
var session = await client.CreateChatSessionAsync(recipientPublicKey, "[email protected]");
await client.SendChatMessageAsync(recipientPublicKey, "Secure message");
Application → LibEmiddleClient → ChatSession → MailboxManager (encrypts)
→ IMailboxTransport → HttpMailboxTransport → Server
Key Point: Only MailboxManager handles encryption/decryption. Transport layers work with already-encrypted messages.
For a complete guide, see Mailbox Transport Guide and Message Flow Diagram.
// Comprehensive client configuration
var options = new LibEmiddleClientOptions
{
// Storage configuration
IdentityKeyPath = "keys/identity.key",
SessionStoragePath = "data/sessions",
KeyStoragePath = "data/keys",
// Transport settings
TransportType = TransportType.Http,
ServerEndpoint = "https://api.example.com",
NetworkTimeoutMs = 30000,
// Security policies
SecurityPolicy = new SecurityPolicyOptions
{
RequirePerfectForwardSecrecy = true,
RequireMessageAuthentication = true,
MinimumProtocolVersion = "2.0",
AllowInsecureConnections = false
},
// Key management
DefaultRotationStrategy = KeyRotationStrategy.Aggressive,
MaxOneTimePreKeys = 100,
MaxSkippedMessageKeys = 1000,
EnableAutomaticKeyRotation = true,
// Multi-device support
EnableMultiDevice = true,
MaxLinkedDevices = 10,
// Performance and reliability
EnableMessageHistory = true,
MaxMessageHistoryPerSession = 1000,
EnableSecureMemory = true,
EnableSessionPersistence = true,
// Retry configuration
RetryOptions = new RetryOptions
{
MaxRetries = 3,
BaseDelayMs = 1000,
MaxDelayMs = 30000,
BackoffMultiplier = 2.0
}
};
using var client = new LibEmiddleClient(options);
// Get all active sessions
var activeSessions = await client.GetActiveSessionsAsync();
// Get specific session by ID
var session = await client.GetSessionAsync(sessionId);
// Get chat sessions with a specific user
var userSessions = await client.GetChatSessionsAsync(userPublicKey);
// Session lifecycle management
await session.ActivateAsync();
await session.SuspendAsync("Temporary suspension");
await session.ResumeAsync();
await session.TerminateAsync();
// Session persistence and recovery
await client.SaveSessionAsync(session);
var recoveredSession = await client.LoadSessionAsync(sessionId);
// Session metadata and history
session.Metadata["custom_field"] = "value";
var messageHistory = session.GetMessageHistory();
// Session events
session.StateChanged += (sender, args) =>
{
Console.WriteLine($"Session {args.SessionId} state changed to {args.NewState}");
};
// Enable message batching for improved throughput
var options = new LibEmiddleClientOptions
{
FeatureFlags = new FeatureFlags
{
EnableMessageBatching = true
},
BatchingOptions = new BatchingOptions
{
MaxBatchSize = 50,
BatchTimeoutMs = 1000,
CompressionLevel = CompressionLevel.Balanced
}
};
// Messages are automatically batched and compressed
await client.SendChatMessageAsync(recipientKey, "Message 1");
await client.SendChatMessageAsync(recipientKey, "Message 2");
await client.SendChatMessageAsync(recipientKey, "Message 3");
// All three messages sent in a single compressed batch
// Configure post-quantum crypto algorithms (preparation for future)
var options = new LibEmiddleClientOptions
{
PostQuantumOptions = new PostQuantumOptions
{
Algorithm = PostQuantumAlgorithm.Kyber1024,
EnableHybridMode = true, // Classical + Post-quantum
KeyExchangeMode = KeyExchangeMode.Hybrid
}
};
// The system will use hybrid classical+PQ when available
using var client = new LibEmiddleClient(options);
// Enable comprehensive monitoring and diagnostics
var options = new LibEmiddleClientOptions
{
FeatureFlags = new FeatureFlags
{
EnableDiagnostics = true,
EnableResilienceManager = true
},
ResilienceOptions = new ResilienceOptions
{
RetryPolicy = RetryPolicy.ExponentialBackoff,
HealthCheckIntervalMs = 30000,
EnableFailover = true
}
};
using var client = new LibEmiddleClient(options);
// Access diagnostics information
var diagnostics = client.GetDiagnostics();
Console.WriteLine($"Active Sessions: {diagnostics.ActiveSessions}");
Console.WriteLine($"Messages Sent: {diagnostics.MessagesSent}");
Console.WriteLine($"Network Quality: {diagnostics.NetworkQuality}");
// Monitor resilience events
client.ResilienceManager.ConnectionRestored += (sender, args) =>
{
Console.WriteLine($"Connection restored after {args.DowntimeMs}ms");
};
// Configure connection pooling for high-throughput scenarios
var options = new LibEmiddleClientOptions
{
ConnectionPoolOptions = new ConnectionPoolOptions
{
MinPoolSize = 5,
MaxPoolSize = 20,
ConnectionTimeoutMs = 30000,
IdleTimeoutMs = 300000,
EnableLoadBalancing = true
}
};
// Connections are automatically managed and reused
using var client = new LibEmiddleClient(options);
// Configure sophisticated key rotation policies
var rotationPolicy = new KeyRotationPolicy
{
Strategy = KeyRotationStrategy.Adaptive,
TimeBasedRotationIntervalHours = 24,
MessageCountThreshold = 10000,
RiskBasedRotation = true,
BackupKeyCount = 3
};
await client.SetAdvancedKeyRotationPolicyAsync(sessionId, rotationPolicy);
// Monitor key rotation events
client.KeyRotated += (sender, args) =>
{
Console.WriteLine($"Keys rotated for session {args.SessionId}: {args.RotationReason}");
};
On
KeyRotationStrategy.Standard(changed in v2.7): the DH ratchet advances only in response to a peer's new ratchet key, per the Signal specification. Earlier versions also rotated the sender's ratchet key every 20 messages; because a DH ratchet step is only valid once the peer holds the new public key, that could diverge both sides' DH inputs and permanently break a session where both parties were actively sending. Forward secrecy within a chain comes from the symmetric ratchet and is unaffected.KeyRotationStrategy.AfterEveryMessageis unchanged.
sodium_memzero, including superseded root keys, chain keys, retired ratchet private keys, and evicted skipped-message keysNot every type in the public surface is backed by a real implementation. This table is the authoritative list — treat anything marked Stub as unavailable.
| Area | Status | Notes |
|---|---|---|
| X3DH + Double Ratchet | ✅ Production | Signal-compliant key agreement and ratcheting |
| AES-256-GCM / Ed25519 / X25519 | ✅ Production | All via libsodium |
| Chat & group sessions | ✅ Production | Replay protection, forward secrecy, member management |
| Multi-device linking & sync | ✅ Production | Encrypted persistent device list |
| Session persistence | ✅ Production | Argon2id-derived keys, atomic writes |
| HTTP / InMemory transport | ✅ Production | |
| Resilience (retry, circuit breaker, timeout) | ✅ Production | ResilienceManager |
| Post-quantum crypto | ⚠️ Stub | PostQuantumCryptoStub returns random bytes for all Kyber/Dilithium/Falcon operations and its VerifyAsync returns true for any correctly-sized signature. Do not use for any security decision. |
| WebRTC transport | ⚠️ Stub | Echoes sent bytes back as received |
| Session backup manager | ⚠️ Stub | Returns hardcoded checksums; writes nothing to disk |
| Connection pool | ⚠️ Stub | Returns a connection that echoes sends as receives |
| Advanced key rotation scheduling | ⚠️ Stub | Task.Delay then a synthetic result; no keys are rotated |
All stubs are targeted for real implementations in v3.0.
Breaking — password-protected key storage. StoreKeyAsync() / RetrieveKeyAsync() now derive
their encryption key with a fresh random Argon2id salt per stored key instead of a fixed
application-wide salt. The stored blob layout changed from nonce‖ciphertext to
salt‖nonce‖ciphertext, so password-protected keys written by 2.6.x and earlier cannot be read by
2.7.0. Re-store any affected keys before upgrading, or keep a 2.6.x reader available to migrate
them. Keys stored without a password are unaffected, as are session files and device lists.
Behavioral — KeyRotationStrategy.Standard. No longer performs a send-count-based DH ratchet
rotation; see Forward Secrecy & Post-Compromise Security.
No API change and no action required.
Wire format — additive and backward compatible. EncryptedMessage gained
PreviousChainLength (the Signal PN header field). It defaults to 0 when absent, so 2.7.0 reads
messages from older peers. Older peers ignore the field. Out-of-order delivery across a ratchet step
only recovers when both sides run 2.7.0+.
dotnet add package LibEmiddle --version 2.7.0
Install-Package LibEmiddle -Version 2.7.0
Direct peer-to-peer encrypted communication using WebRTC data channels:
Status: API stub only — WebRTCTransportStub echoes sent bytes back as received bytes. Not functional.
Target: v3.0 release
// Future API (not yet functional)
var webRtcOptions = new LibEmiddleClientOptions
{
TransportType = TransportType.WebRTC,
WebRTCOptions = new WebRTCOptions
{
ICEServers = new[] { "stun:stun.l.google.com:19302" },
EnableAdaptiveBitrate = true
}
};
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
⚠️ Important: If you modify this software and provide it as a service over a network (e.g., SaaS), you must make the complete source code of your modified version available to all users.
See LICENSE file for details or visit https://www.gnu.org/licenses/agpl-3.0.html
We welcome contributions! Please see our contributing guidelines and:
The Documentation/ folder contains comprehensive technical documentation including:
Built by Russell Benzing. Reach out at [email protected].
If LibEmiddle is useful to you, you can support the work: