npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

poly-crypto

v2.1.4

Published

High-level cryptographic functions that are interoperable between NodeJS and PHP 7.1+.

Downloads

366

Readme

poly-crypto

Polyglot Cryptography. High-level cryptographic functions that are interoperable between NodeJS and PHP 7.1+.

NPM Link Packagist Link Language Build Status Code Coverage Gzipped Size Dependency details Tree shakeable ISC License

Project Goals

  1. APIs that work exactly the same on NodeJS and PHP 7.1+
  2. Package for Node that can be used on serverless functions without external C bindings
  3. Two-way symmetric encryption with a key or with password and salt
  4. Password hashing
  5. Support ESM with tree shaking; support CommonJS; Typescript

Installation

# NodeJS
npm install poly-crypto

# PHP
composer require poly-crypto/poly-crypto

Cheatsheet

| Section | NodeJS | PHP | | ----------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------ | | Encrypt with key | PolyAES.withKey(key).encrypt(data) | PolyAES::withKey($key)->encrypt($data) | | Decrypt with key | PolyAES.withKey(key).decrypt(encrypted) | PolyAES::withKey($key)->decrypt($encrypted) | | Encrypt with password | PolyAES.withPassword(password, salt).encrypt(data) | PolyAES::withPassword($password, $salt)->encrypt($data) | | Decrypt with password | PolyAES.withPassword(password, salt).decrypt(encrypted) | PolyAES::withPassword($password, $salt)->decrypt($encrypted) | | Bcrypt hash | PolyBcrypt.hash(password) | PolyBcrypt::hash($password) | | Bcrypt verify | PolyBcrypt.verify(password, hash) | PolyBcrypt::verify($password, $hash) | | Digest functions | PolyDigest.sha256(data) | PolyDigest::sha256($data) | | Random functions | PolyRand.slug(length) | PolyRand::slug($length) |

Table of Contents

  1. Technology choices
    1. AES-255 GCM
    2. Bcrypt
    3. Randomness
  2. Use Cases
  3. Misuse
  4. AES encryption
    1. Encrypt and decrypt with key
    2. Encrypt and decrypt with password
  5. Password hashing
  6. Digest functions
  7. Random functions
  8. Performance
  9. Command line utilities
  10. Browser usage
  11. JavaScript direct import
  12. Unit tests
  13. Open Source ISC Licence
  14. Changelog

Technology choices

AES-256 GCM

As of December 2022, AES-256 Encryption with GCM block mode is a reputable and secure method that is available across PHP and NodeJS without any extensions. With the right arguments and options, these 2 languages can decrypt one another's encrypted strings using PHP's openssl_* functions and npm's node-forge.

Bcrypt

As of December 2022, Bcrypt password hashing is reputable and secure. These 2 languages can hash and verify one another's hashes: npm's bcrypt-js and PHP's password_hash function.

Randomness

Cryptographic randomness is tricky. These 2 languages can provide secure randomness: PHP's random_bytes() and Node's crypto.randomBytes() functions.

Use cases

poly-crypto's basic use cases:

| | Case | Input | Output | NodeJS | | --- | -------------------------------------------------------- | ------------------------------------ | ------------------------------- | -------------------------------------------------- | | 1. | Encrypt data that you can to decrypt later | Encryption key string | base-64 encoded string | PolyAES.withKey(hexKey).encrypt(data) | | 2. | Encrypt data for a user that he or she can decrypt later | User-supplied password & system salt | base-64 encoded string | PolyAES.withPassword(password, salt).encrypt(data) | | 3. | Hash passwords with bcrypt | Password string | bcrypt hash | PolyBcrypt.hash(password) | | 4. | Check if a password matches the given bcrypt hash | Password string & bcrypt hash | True if password matches | PolyBcrypt.verify(password, hash) | | 5. | Calculate digests (e.g. sha256) | String data | digest string | PolyDigest.sha256(data) | | 6. | Generate random slugs | number of characters | a string with random characters | PolyRand.slug(numCharacters) |

Misuse

  1. File encryption. poly-crypto modules are not meant to be used to encrypt entire files. You'll want to use a C-based library that is designed to encrypt large amounts of data quickly. For example, consider the following:
    1. poly-crypto is not fast for large files.
    2. AES-256 GCM encryption can be parallelized in languages that support threading for faster processing
  2. Streaming data. PolyAES is not designed to encrypt streaming data.
  3. Secure key storage. If you store encryption keys or user passwords in plain text, encryption will not provide protection. You'll want to store keys in secure parameter store.
  4. Digests for passwords. Do not use md5 or any sha digest for hashing passwords, even if you use salt. PolyBcrypt is the only poly-crypto module designed for hashing passwords.

AES Encryption

Encrypt and decrypt with key

Note: key should be a 64-character hex-encoded string stored in a secure param store. To generate a cryptographically secure random key, use PolyAES.generateKey(64).

NodeJS:

import { PolyAES } from 'poly-crypto';

const hexKey = '64-char hex encoded string from secure param store';
const encrypted = PolyAES.withKey(hexKey).encrypt(data);
const decrypted = PolyAES.withKey(hexKey).decrypt(encrypted);

PHP:

<?php

require_once('vendor/autoload.php');
use PolyCrypto\PolyAES;

$hexKey = '64-char hex encoded string from secure param store';
$encrypted = PolyAES::withKey($hexKey)->encrypt($data);
$decrypted = PolyAES::withKey($hexKey)->decrypt($encrypted);

Note: You can re-use the "cipher" object. For example:

NodeJS:

import { PolyAES } from 'poly-crypto';

const hexKey = '64-char hex encoded string from secure param store';
const cipher = PolyAES.withKey(hexKey);
const encrypted = cipher.encrypt(data);
const decrypted = cipher.decrypt(encrypted);

PHP:

<?php

require_once('vendor/autoload.php');
use PolyCrypto\PolyAES;

$hexKey = '64-char hex encoded string from secure param store';
$cipher = PolyAES::withKey($hexKey);
$encrypted = $cipher->encrypt($data);
$decrypted = $cipher->decrypt($encrypted);

Encrypt and decrypt with password

NodeJS:

import { PolyAES } from 'poly-crypto';

const password = 'String from user';
const salt = 'String from secure param store';
const encrypted = PolyAES.withPassword(password, salt).encrypt(data);
const decrypted = PolyAES.withPassword(password, salt).decrypt(encrypted);

PHP:

<?php

require_once('vendor/autoload.php');
use PolyCrypto\PolyAES;

$password = 'String from user';
$salt = 'String from secure param store';
$encrypted = PolyAES::withPassword($password, $salt)->encrypt($data);
$decrypted = PolyAES::withPassword($password, $salt)->decrypt($encrypted);

Note: You can re-use the "cipher" as an object.

Password hashing

Bcrypt hashes are designed to store user passwords with a max length of 72 bytes. If a longer string is passed, an exception will be thrown. Keep in mind that Unicode characters require multiple bytes.

Bcrypt conveniently stores salt along with the password. That ensures that identical passwords will get different hashes. As such, you cannot compare two hashes, you must use the PolyBcrypt.verify() function to see if the given password matches the hash you have on record.

NodeJS:

import { PolyBcrypt } from 'poly-crypto';

const password = 'Password from a user';
const hash = PolyBcrypt.hash(password);
const isCorrect = PolyBcrypt.verify(password, hash);

PHP:

<?php

require_once('vendor/autoload.php');
use PolyCrypto\PolyBcrypt;

$password = 'Password from a user';
$hash = PolyBcrypt::hash($password);
$isCorrect = PolyBcrypt::verify($password, $hash);

Digest functions

Standard one-way digest functions.

NodeJS:

import { PolyDigest } from 'poly-crypto';

PolyDigest.sha512(data);
PolyDigest.sha256(data);
PolyDigest.sha1(data);
PolyDigest.md5(data);

PHP:

<?php

require_once('vendor/autoload.php');
use PolyCrypto\PolyDigest;

PolyDigest::sha512($data);
PolyDigest::sha256($data);
PolyDigest::sha1($data);
PolyDigest::md5($data);

Random functions

Simple functions to generate random values synchronously.

NodeJS:

import { PolyRand } from 'poly-crypto';

// generate a string containing numbers and letters minus vowels
// suitable for resources such as URLs with random strings
PolyRand.slug(length);

// generate a string containing hexadecimal characters
PolyRand.hex(length);

// generate a string containing numbers and lowercase letters
// that are unambiguous when written down
PolyRand.fax(length);

// generate a string containing lowercase letters minus vowels
const symbolList = 'bcdfghjklmnpqrstvwxyz'.split('');
PolyRand.string(length, symbolList);

// generate random bytes in binary form
PolyRand.bytes(length);

// generate a uuid v4
PolyRand.uuidv4();

PHP:

<?php

require_once('vendor/autoload.php');
use PolyCrypto\PolyRand;

// generate a string containing numbers and letters minus vowels
// suitable for resources such as URLs with random strings
PolyRand::slug($length);

// generate a string containing hexadecimal characters
PolyRand::hex($length);

// generate a string containing numbers and lowercase letters
// that are unambiguous when written down
PolyRand::fax($length);

// generate a string containing lowercase letters minus vowels
$symbolList = explode('', 'bcdfghjklmnpqrstvwxyz');
PolyRand::string($length, $symbolList);

// generate random bytes in binary form
PolyRand::bytes($length);

// generate a uuid v4
PolyRand::uuidv4();

Command line utilities

poly-crypto functions can be used from the command line if Node JS is installed.

Global install of poly-crypto

You'll have the following commands as symlinks:

# Global install command and arguments        # JavaScript equivalent
# ------------------------------------------- # ---------------------
npx key-encrypt $hexKey $plaintext            # PolyAES.withKey(hexKey).encrypt(plaintext)
npx key-decrypt $hexKey $ciphertext           # PolyAES.withKey(hexKey).decript(ciphertext)
npx pass-encrypt $password $salt $plaintext   # PolyAES.withPassword(password, salt).encrypt(plaintext)
npx pass-decrypt $password $salt $ciphertext  # PolyAES.withPassword(password, salt).decrypt(plaintext)
npx bcrypt-hash $password                     # PolyBcrypt.hash(password)
npx bcrypt-verify $password $againstHash      # PolyBcrypt.verify(password, againstHash)
npx poly-digest $algo $string                 # PolyDigest[algo](data) where algo is one of: sha1, sha256, sha512, md5
npx poly-rand $type $length                   # PolyRand[type](length) where type is one of: slug, hex, fax, bytes, uuidv4
npx poly-rand-string $length $symbolString    # PolyRand.string(length, symbolList) where symbolList is a string containing allowed characters

Local install of poly-crypto

Prefix each of the commands above with npm exec.

Browser usage

All poly-crypto modules do indeed function in the browser. There are only a few use cases where encrypting in the browser is a good idea. If you have a good reason to use poly-crypto in the browser, see the following section for instructions on directly importing a Poly* module.

JavaScript direct import

If you are using ESM or a bundler such as vite or esbuild you will benefit from tree shaking by using an import statement.

import { PolyBcrypt } from 'poly-crypto';

Unit tests

# test both languages
npm run test:all

# PHP
./vendor/bin/kahlan --spec=php/tests

# NodeJS
npm test

Contributing

Contributions welcome! See CONTRIBUTING.md .

License

Open Source, under the ISC License.