dolutech / cryptnote-php
A PHP library for creating encrypted, self-destructing messages with view limits and optional password protection
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/dolutech/cryptnote-php
Requires
- php: >=8.0
- ext-openssl: *
- ext-pdo: *
- ext-pdo_sqlite: *
Requires (Dev)
- phpunit/phpunit: ^10.0
Suggests
- ext-pdo_mysql: For MySQL database support
- ext-pdo_pgsql: For PostgreSQL database support
This package is auto-updated.
Last update: 2026-01-11 17:36:22 UTC
README
A standalone PHP library for creating encrypted, self-destructing messages with view limits and optional password protection. Based on the CryptNote.pro encryption system.
Features
- ๐ AES-256-GCM (default) with AEAD โ authenticated encryption by default; legacy v1 CBC+HMAC remains for compatibility
- ๐ Optional Password Protection โ PBKDF2 + versioned encryption; configurable min length and validator
- ๐๏ธ View Limits โ Messages self-destruct after a specified number of views
- โฐ Time Expiration โ Set messages to expire after a certain time
- ๐ Markdown/HTML Support โ Store and retrieve formatted content
- ๐๏ธ SQLite Storage โ Zero-configuration database included
- ๐งน Auto Cleanup โ Automatic removal of old, unviewed messages
- ๐ Secure Deletion โ Optional SQLite secure_delete/DELETE journal for stronger erasure
- ๐ก๏ธ Privacy Mode โ Obfuscate status for missing/expired notes
- ๐๏ธ Key Wrapping โ Optional wrapping key to protect stored per-note keys
Requirements
- PHP 8.0 or higher
- OpenSSL extension
- PDO extension with SQLite driver
Installation
Via Composer
composer require dolutech/cryptnote-php
Manual Installation
- Download or clone this repository
- Include the autoloader or require the files directly:
require_once 'path/to/library-open/src/CryptNote.php'; require_once 'path/to/library-open/src/CryptNoteStandalone.php';
Quick Start
Basic Usage (with built-in storage)
<?php use CryptNote\CryptNote; // Initialize with default settings (v2 AES-256-GCM) $cryptnote = new CryptNote([ 'encryption_method' => 'AES-256-GCM', 'encryption_version' => 'v2', ]); // Create an encrypted note $result = $cryptnote->create('This is a secret message!', [ 'max_views' => 1, // Self-destruct after 1 view ]); echo "Token: " . $result['token']; // Token: a1b2c3d4e5f6... // View the note (this will decrement the view count) $note = $cryptnote->view($result['token']); echo $note['content']; // Output: This is a secret message! // The note is now destroyed (max_views reached)
With Password Protection
<?php use CryptNote\CryptNote; $cryptnote = new CryptNote(); // Create a password-protected note $result = $cryptnote->create('Top secret information', [ 'password' => 'mySecretPassword123', 'max_views' => 3, ]); // View requires the password $note = $cryptnote->view($result['token'], 'mySecretPassword123'); echo $note['content'];
With Time Expiration
<?php use CryptNote\CryptNote; $cryptnote = new CryptNote(); // Create a note that expires in 60 minutes $result = $cryptnote->create('Time-sensitive information', [ 'max_views' => 10, 'expire_minutes' => 60, // Expires in 1 hour ]); echo "Expires at: " . $result['expires_at'];
Check Note Status
<?php use CryptNote\CryptNote; $cryptnote = new CryptNote(); $status = $cryptnote->status($token); if ($status['status'] === 'active') { echo "Note is active"; echo "Remaining views: " . $status['remaining_views']; echo "Requires password: " . ($status['requires_password'] ? 'Yes' : 'No'); } elseif ($status['status'] === 'expired') { echo "Note has expired"; } else { echo "Note not found"; }
Standalone Encryption (No Database)
If you want to handle storage yourself, use the CryptNoteStandalone class:
<?php use CryptNote\CryptNoteStandalone; $crypto = new CryptNoteStandalone(); // Generate a key $key = $crypto->generateKey(); // Encrypt $encrypted = $crypto->encrypt('My secret data', $key); // Decrypt $decrypted = $crypto->decrypt($encrypted, $key); // With password $encrypted = $crypto->encryptWithPassword('My secret', $key, 'password123'); $decrypted = $crypto->decryptWithPassword($encrypted, $key, 'password123');
Configuration Options
CryptNote (Full Library)
$cryptnote = new CryptNote([ // Database path (default: ./data/cryptnote.db) 'db_path' => '/path/to/your/database.db', // Encryption (default: AES-256-GCM with AEAD) 'encryption_method' => 'AES-256-GCM', 'encryption_version' => 'v2', // use 'v1' only for legacy CBC payloads // Token length in bytes (default: 32, produces 64 hex chars) 'token_length' => 32, // Maximum content length (default: 50000) 'max_content_length' => 50000, // Password policy 'password_min_length' => 12, 'password_validator' => null, // optional callable 'require_password' => false, // force all notes to have a password // PBKDF2 iterations for password derivation (default: 100000) 'pbkdf2_iterations' => 100000, // Key handling 'enable_key_wrapping' => false, 'wrapping_key' => null, // provide a wrapping key when enabled // Privacy and deletion controls 'privacy_mode' => false, // hide status details for missing/expired/invalid 'secure_delete' => false, // enable SQLite secure_delete + delete journal // Enable automatic cleanup (default: true) 'auto_cleanup' => true, // Days after which unviewed notes are cleaned (default: 15) 'cleanup_days' => 15, // Base URL for generating share links (optional) 'base_url' => 'https://yoursite.com/view', ]);
CryptNoteStandalone
$crypto = new CryptNoteStandalone([ 'encryption_method' => 'AES-256-GCM', 'encryption_version' => 'v2', 'pbkdf2_iterations' => 100000, ]);
API Reference
CryptNote Class
create(string $content, array $options = []): array
Create an encrypted note.
Options:
password(string|null): Optional password for additional protectionmax_views(int): Maximum views before destruction (1-100, default: 1)expire_minutes(int|null): Minutes until expiration (max: 10080 = 7 days)is_markdown(bool): Whether content is Markdown (default: false)is_html(bool): Whether content is HTML (default: false)
Returns:
[
'success' => true,
'token' => 'abc123...',
'has_password' => false,
'max_views' => 1,
'is_markdown' => false,
'is_html' => false,
'expires_at' => '2026-01-15 12:00:00',
'created_at' => '2026-01-15 11:00:00',
'share_url' => 'https://yoursite.com/view?token=abc123...', // if base_url configured
]
view(string $token, ?string $password = null): array
View and decrypt a note.
Returns:
[
'success' => true,
'content' => 'The decrypted message',
'is_markdown' => false,
'is_html' => false,
'remaining_views' => 0,
'max_views' => 1,
'expires_at' => null,
'destroyed' => true,
]
status(string $token): array
Check note status without viewing.
Returns:
[
'success' => true,
'status' => 'active', // 'active', 'expired', 'not_found', 'invalid_token'
'requires_password' => false,
'is_markdown' => false,
'is_html' => false,
'max_views' => 3,
'remaining_views' => 2,
'expires_at' => null,
'created_at' => '2026-01-15 11:00:00',
]
delete(string $token): bool
Manually delete a note.
getStats(): array
Get database statistics.
CryptNoteStandalone Class
generateToken(int $length = 32): string
Generate a secure random token.
generateKey(): string
Generate a random encryption key.
encrypt(string $content, string $key): string
Encrypt content.
decrypt(string $encryptedData, string $key): string
Decrypt content.
encryptWithPassword(string $content, string $key, string $password): string
Encrypt with password protection.
decryptWithPassword(string $encryptedData, string $key, string $password): string
Decrypt with password.
validateToken(string $token, int $expectedLength = 64): bool
Validate token format.
generatePassword(int $length = 16, bool $includeSpecial = true): string
Generate a secure random password.
Security Considerations
- Database Security: Ensure your SQLite database file is not publicly accessible. Store it outside the web root.
- HTTPS: Always use HTTPS when transmitting tokens or passwords
- Password Strength: Minimum 12 characters required by default; enforce stronger policies with
password_validatororrequire_passwordas needed. - Key Storage: Never log or expose encryption keys; consider enabling
enable_key_wrappingwith an application wrapping key. - Secure Deletion: Enable
secure_deletefor SQLite secure deletion (DELETE journal + secure_delete pragma); pair with disk-level encryption for additional assurance. - PBKDF2: Uses 100,000 iterations by default. For high-security applications, consider increasing or using Argon2id.
- Rate Limiting: Implement rate limiting in your application to prevent brute-force attacks on password-protected notes.
- Privacy Mode: Enable
privacy_modeto avoid leaking existence/expiration of notes viastatus()responses.
Building a Web Interface
Here's a simple example of building a web interface:
<?php // create.php use CryptNote\CryptNote; $cryptnote = new CryptNote([ 'base_url' => 'https://yoursite.com/view.php', ]); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $result = $cryptnote->create($_POST['content'], [ 'password' => $_POST['password'] ?: null, 'max_views' => (int)$_POST['max_views'], 'expire_minutes' => $_POST['expire_minutes'] ?: null, ]); echo "Share this link: " . $result['share_url']; }
<?php // view.php use CryptNote\CryptNote; $cryptnote = new CryptNote(); $token = $_GET['token'] ?? ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { $note = $cryptnote->view($token, $_POST['password'] ?? null); echo htmlspecialchars($note['content']); } catch (Exception $e) { echo "Error: " . $e->getMessage(); } }
License
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Links
- Packagist: packagist.org/packages/dolutech/cryptnote-php
- GitHub: github.com/dolutech/cryptnote-php
- CryptNote.pro: cryptnote.pro
Credits
Developed by Dolutech - Based on CryptNote.pro encryption system.