A standalone PHP library for creating encrypted, self-destructing messages with view limits and optional password protection. Based on the CryptNote.pro encryption system.
- 🔐 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
- PHP 8.0 or higher
- OpenSSL extension
- PDO extension with SQLite driver
composer require dolutech/cryptnote-php- 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';<?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)<?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'];<?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'];<?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";
}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');$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',
]);$crypto = new CryptNoteStandalone([
'encryption_method' => 'AES-256-GCM',
'encryption_version' => 'v2',
'pbkdf2_iterations' => 100000,
]);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 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,
]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',
]Manually delete a note.
Get database statistics.
Generate a secure random token.
Generate a random encryption key.
Encrypt content.
Decrypt content.
Encrypt with password protection.
Decrypt with password.
Validate token format.
Generate a secure random password.
- 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.
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();
}
}MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Packagist: packagist.org/packages/dolutech/cryptnote-php
- GitHub: github.com/dolutech/cryptnote-php
- CryptNote.pro: cryptnote.pro
Developed by Dolutech - Based on CryptNote.pro encryption system.