NAME

Vigil::Crypt

SYNOPSIS

Encryption/Decryption

    use Vigil::Crypt;

    my $crypt = Vigil::Crypt->new( ENCRYPTION_KEY );

    my $encrypted = $crypt->encrypt($plaintext_to_encrypt, $secret1, $secret2);

    my $decrypted = $crypt->decrypt($encrypted, $secret1, $secret2);

Hashing

    use Vigil::Crypt;

    my $crypt = Vigil::Crypt->new( ENCRYPTION_KEY );

    my $stored_hash = $crypt->hash($password, $PEPPER);

    if( $crypt->verify_password($entered_password, $stored_hash, $PEPPER) ) {
            ... passwords match ...
    } else {
            ... passwords did not match. Do not pass go, do not collect $200 ...
    }

DESCRIPTION

Encryption/Decryption

The encrypt_data and decrypt_data methods handle sensitive information - like emails or personal IDs - in a way that makes it extremely difficult for anyone without the right keys to access. They use ChaCha20-Poly1305, a modern authenticated encryption algorithm trusted in security-critical applications worldwide. Not only does this algorithm scramble your data (encryption), it also includes a tag to ensure the data hasn't been tampered with (authentication). The system also derives an additional authenticated data (AAD) from user-specific information, which means even if someone guesses part of the input, they still cannot decrypt the data without the full context. For a newcomer, think of it as a strong lock on your secrets that refuses to open if anything looks suspicious - all handled automatically for you.

ChaCha20-Poly1305 is used for encryption/decryption because:

* Provides authenticated encryption, ensuring data confidentiality and integrity.

* Resistant to tampering: modifying the ciphertext or tag causes decryption to fail completely.

* Fast and efficient in software, especially on CPUs without dedicated AES hardware.

* Uses a 256-bit key, providing strong security against brute-force attacks.

* Includes a nonce to ensure the same plaintext encrypts differently each time.

* Supports Additional Authenticated Data (AAD), allowing context-specific data to be protected without including it in the ciphertext.

* Widely standardized and recommended for modern secure communications.

* Constantly reviewed and trusted by the cryptography community.

Hashing Passwords/Markers

Hashing is used for one-way protection, typically for passwords, but also for any verification markers or tokens that need to be validated without storing the original value. With hash and verify_password, sensitive data is never stored directly - only the hashed version. The module uses Argon2id, a state-of-the-art password hashing function designed to resist brute-force attacks while being memory- and CPU-intensive enough to slow down attackers. We also pre-hash the input with a pepper to add an extra layer of security. verify_password (or verify_hash) lets you safely check credentials or other verification markers: it confirms the input matches the stored hash without ever exposing the original value. In short, it's like a magic fingerprint - you can confirm it, but nobody can reverse-engineer it.

Argon2 is used for password hashing because:

* It requires a large amount of RAM to compute.

* GPU/ASIC attackers can't easily parallelize attacks because they run out of memory bandwidth.

* This makes brute-force attacks extremely expensive on specialized hardware.

* Resistant to Time-Memory Trade-Off (TMTO) attacks: attackers can't just reduce memory drastically without paying a huge time penalty.

* Built with side-channel resistance in mind.

* Future-proof against most foreseeable optimizations in hardware cracking.

* Included in RFC 9106 as the recommended password hashing scheme.

* Supported in libraries across most languages.

* Constantly reviewed by cryptography experts.

CLASS METHODS

OBJECT METHODS

Encryption/Decryption

Hashing

ENCRYPTION LENGTHS

Knowing how long the final encryption will be is important when designing your database tables. The formula to calculate the length of encrypted values is:

    my $Base64_length = 4 * ceil(($plaintext_bytes + 28) / 3);

Since Perl does not have a ceil() function, we would actually calculate it this way:

    my $Base64_length = 4 * int((($plaintext_bytes + 28) + 2) / 3);

Here are some prepresentative values to get you going:

    Plaintext   Encrypted Base64
     (bytes)      (Characters)
    16          4 * ceil((16 + 28)/3)   = 60
    32          4 * ceil((32 + 28)/3)   = 80
    64          4 * ceil((64 + 28)/3)   = 123
    100         4 * ceil((100 + 28)/3)  = 172
    256         4 * ceil((256 + 28)/3)  = 372
    512         4 * ceil((512 + 28)/3)  = 688
    1000        4 * ceil((1000 + 28)/3) = 1376
    2500        4 * ceil((2500 + 28)/3) = 3352
    5000        4 * ceil((5000 + 28)/3) = 6712

Local Installation

If your host does not allow you to install from CPAN, then you can install this module locally two ways:

AUTHOR

Jim Melanson (jmelanson1965@gmail.com).

Created: October, 2018.

Last Update: August 2025.

License: Use it as you will, and don't pretend you wrote it - be a mensch.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.