Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
Encrypt and decrypt data with AES-256 GCM; interoperable with Node and PHP 7.1+
License
kensnyder/poly-crypto
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Polyglot Cryptography. High-level cryptographic functions that are interoperable between NodeJS and PHP 7.1+.
- APIs that work exactly the same on NodeJS and PHP 7.1+
- Package for Node that can be used on serverless functions without external C bindings
- Two-way symmetric encryption with a key or with password and salt
- Password hashing
- Support ESM with tree shaking; support CommonJS; Typescript
# NodeJS npm install --save poly-crypto # PHP composer require poly-crypto/poly-crypto
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) |
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.
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.
Cryptographic randomness is tricky. These 2 languages can provide secure randomness: PHP’s random_bytes() and Node’s crypto.randomBytes() functions.
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) |
- 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:
- poly-crypto is not fast for large files.
- AES-256 GCM encryption can be parallelized in languages that support threading for faster processing
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) .
const PolyAES > = require('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);
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:
const PolyAES > = require('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);
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
const PolyAES > = require('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);
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.
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.
const PolyBcrypt > = require('poly-crypto'); const password = 'Password from a user'; const hash = PolyBcrypt.hash(password); const isCorrect = PolyBcrypt.verify(password, hash);
require_once('vendor/autoload.php'); use PolyCrypto\PolyBcrypt; $password = 'Password from a user'; $hash = PolyBcrypt::hash($password); $isCorrect = PolyBcrypt::verify($password, $hash);
Standard one-way digest functions.
const PolyDigest > = require('poly-crypto'); PolyDigest.sha512(data); PolyDigest.sha256(data); PolyDigest.sha1(data); PolyDigest.md5(data);
require_once('vendor/autoload.php'); use PolyCrypto\PolyDigest; PolyDigest::sha512($data); PolyDigest::sha256($data); PolyDigest::sha1($data); PolyDigest::md5($data);
Simple functions to generate random values synchronously.
const PolyRand > = require('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();
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();
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 .
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.
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';
# test both languages npm run test:all # PHP ./vendor/bin/kahlan --spec=php/tests # NodeJS npm test
Contributions welcome! See CONTRIBUTING.md .