OpenCrypto
OpenCrypto is a lightweight, high performance, standard-compliant JavaScript library built on top of Web Cryptography API. This library makes it easier to implement cryptography in a browser with less code. It can convert and encode ASN.1, PEM and CryptoKey. OpenCrypto is created and maintained by SafeBash.
Instructions
Load OpenCrypto into your web application
<script type="text/javascript" src="OpenCrypto.min.js"></script>
or
import OpenCrypto from 'opencrypto'
Examples
// Initialize new OpenCrypto instance
const crypt = new OpenCrypto()
// Conversion of CryptoKey and PEM
// Convert CryptoKey of type private to PEM
/*
* privateKey: CryptoKey | default: undefined
*/
crypt.cryptoPrivateToPem(privateKey).then(function (privatePem) {
console.log(privatePem)
})
// Convert PEM private key to CryptoKey
/*
* pem: PEM Private Key (String) | default: undefined
* options:
* for ECDH: { name: 'ECDH', usages: ['deriveKey', 'deriveBits'], isExtractable: true }
* for ECDSA: { name: 'ECDSA', usages: ['sign'], isExtractable: true }
* for RSA-OAEP: { name: 'RSA-OAEP', hash: { name: 'SHA-512' }, usages: ['decrypt', 'unwrapKey'], isExtractable: true }
* for RSA-PSS: { name: 'RSA-PSS', hash: { name: 'SHA-512' }, usages: ['sign'], isExtractable: true }
*/
crypt.pemPrivateToCrypto(pem, options).then(function (cryptoPrivate) {
console.log(cryptoPrivate)
})
// Convert CryptoKey of type public to PEM
/*
* publicKey: CryptoKey | default: undefined
*/
crypt.cryptoPublicToPem(publicKey).then(function (publicPem) {
console.log(publicPem)
})
// Convert PEM public key to CryptoKey
/*
* pem: PEM Public Key (String) | default: undefined
* options:
* for ECDH: { name: 'ECDH', usages: [], isExtractable: true }
* for ECDSA: { name: 'ECDSA', usages: ['verify'], isExtractable: true }
* for RSA-OAEP: { name: 'RSA-OAEP', hash: { name: 'SHA-512' }, usages: ['encrypt', 'wrapKey'], isExtractable: true }
* for RSA-PSS: { name: 'RSA-PSS', hash: { name: 'SHA-512' }, usages: ['verify'], isExtractable: true }
*/
crypt.pemPublicToCrypto(pem, options).then(function (cryptoPublic) {
console.log(cryptoPublic)
})
// Data encoding and decoding
// Encode ArrayBuffer to Hexadecimal String
/*
* ab: ArrayBuffer | default: undefined
*/
const hexString = crypt.arrayBufferToHexString(ab)
// Decode Hexadecimal String to ArrayBuffer
/*
* hexString: Hexadecimal encoded String | default: undefined
*/
const ab = crypt.hexStringToArrayBuffer(hexString)
// Encode ArrayBuffer to Base64
/*
* ab: ArrayBuffer | default: undefined
*/
const base64 = crypt.arrayBufferToBase64(ab)
// Decode Base64 to ArrayBuffer
/*
* base64: Base64 encoded String | default: undefined
*/
const ab = crypt.base64ToArrayBuffer(base64)
// Encode ArrayBuffer to String
/*
* ab: ArrayBuffer | default: undefined
*/
const str = crypt.arrayBufferToString(ab)
// Decode String to ArrayBuffer
/*
* str: String | default: undefined
*/
const ab = crypt.stringToArrayBuffer(str)
// Asymmetric Encryption (RSA)
// Generate RSA key pair
/*
* modulusLength: 1024 or 2048 or 4096 | default: 2048
* hash: 'SHA1' or 'SHA-256' or 'SHA-384' or 'SHA-512' | default: 'SHA-512'
* paddingScheme: 'RSA-OAEP' or 'RSA-PSS' | default: 'RSA-OAEP'
* usages:
* for RSA-OAEP = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey']
* for RSA-PSS = ['sign', 'verify']
* default: ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey']
* isExtractable: true or false | default: true
*/
crypt.getRSAKeyPair(modulusLength, hash, paddingScheme, usages, isExtractable).then(function (keyPair) {
console.log(keyPair.publicKey)
console.log(keyPair.privateKey)
})
// Encrypt data using public key
/*
* publicKey: CryptoKey | default: undefined
* data: ArrayBuffer | default: undefined
*/
crypt.rsaEncrypt(publicKey, data).then(function (encryptedDataAsymmetric) {
console.log(encryptedDataAsymmetric)
})
// Decrypt data using private key
/*
* privateKey: CryptoKey | default: undefined
* encryptedData: base64 String | default: undefined
*/
crypt.rsaDecrypt(privateKey, encryptedData).then(function (decryptedDataAsymmetric) {
console.log(decryptedDataAsymmetric)
})
// Generate EC key pair
/*
* curve: P-256 or P-384 or P-521 | default: P-256
* type: 'ECDH' or 'ECDSA' | default: 'ECDH'
* usages: default: ['deriveKey', 'deriveBits']
* isExtractable: true or false | default: true
*/
crypt.getECKeyPair(curve, type, usages, isExtractable).then(function (keyPair) {
console.log(keyPair.privateKey)
console.log(keyPair.publicKey)
})
// Encrypt CryptoKey of type private into PEM Encrypted Private Key
/*
* privateKey: CryptoKey | default: undefined
* passphrase: String | default: undefined
* iterations: Integer | default: 64000
* hash: 'SHA-1' or 'SHA-256' or 'SHA-384' or 'SHA-512' | default: 'SHA-512'
* cipher: 'AES-CBC' or 'AES-GCM' or 'AES-CFB' | default: 'AES-CBC'
* keyLength: default: 256
*/
crypt.encryptPrivateKey(privateKey, passphrase, iterations, hash, cipher, keyLength).then(function (encryptedPrivateKey) {
// This PEM Encrypted Private Key is fully compatiable with OpenSSL
console.log(encryptedPrivateKey)
})
// Decrypt PEM Encrypted Private Key
/*
* encryptedPrivateKey: PEM PKCS #8 | default: undefined
* passphrase: String | default: undefined
* options:
* for ECDH: { name: 'ECDH', namedCurve: 'P-256', keyUsages: ['deriveKey', 'deriveBits'], isExtractable: true }
* for ECDSA: { name: 'ECDSA', namedCurve: 'P-256', keyUsages: ['sign'], isExtractable: true }
* for RSA-OAEP: { name: 'RSA-OAEP', hash: { name: 'SHA-512' }, keyUsages: ['decrypt', 'unwrapKey'], isExtractable: true }
* for RSA-PSS: { name: 'RSA-PSS', hash: { name: 'SHA-512' }, keyUsages: ['sign'], isExtractable: true }
* default: { name: 'ECDH', namedCurve: 'P-256', keyUsages: ['deriveKey', 'deriveBits'], isExtractable: true }
*/
crypt.decryptPrivateKey(encryptedPrivateKey, passphrase, options).then(function (decryptedPrivateKey) {
console.log(decryptedPrivateKey)
})
// ECDH Key Agreement
/*
* privateKey CryptoKey | default: undefined
* publicKey CryptoKey | default: undefined
* options: { bitLength: 256, hkdfHash: 'SHA-512', hkdfSalt: "new UInt8Array()", hkdfInfo: "new UInt8Array()", keyCipher: 'AES-GCM', keyLength: 256, keyUsages: ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'], isExtractable: true }
*/
crypt.keyAgreement(privateKey, publicKey).then(function (symmetricKey) {
console.log(symmetricKey)
})
// Encrypt shared key
/*
* Supports AES and RSA-OAEP
* wrappingKey: CryptoKey | default: undefined
* sharedKey: CryptoKey | default: undefined
*/
crypt.encryptKey(wrappingKey, sharedKey).then(function (encryptedSharedKey) {
console.log(encryptedSharedKey)
})
// Decrypt shared key
/*
* Supports AES and RSA-OAEP
* unwrappingKey: CryptoKey | default: undefined
* encryptedSharedKey: CryptoKey | default: undefined
* options:
* for AES-GCM: { keyCipher: 'AES-GCM', keyLength: 256, keyUsages: ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'], isExtractable: true }
* for RSA-OAEP: { keyCipher: 'AES-GCM', keyLength: 256, keyUsages: ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'], isExtractable: true }
*/
crypt.decryptKey(privateKey, encryptedSharedKey, options).then(function (decryptedSharedKey) {
console.log(decryptedSharedKey)
})
// Sign data
/*
* privateKey: CryptoKey | default: undefined
* data: ArrayBuffer | default: undefined
* options:
* for ECDSA: { hash: 'SHA-512' }
* for RSA-PSS: { saltLength: 128 }
*/
crypt.sign(privateKey, data, options).then(function (signature) {
console.log(signature)
})
// Verify signature
/*
* publicKey: CryptoKey | default: undefined
* data: ArrayBuffer | default: undefined
* signature: base64 String | default: undefined
* options:
* for ECDSA: { hash: 'SHA-512' }
* for RSA-PSS: { saltLength: 128 }
*/
crypt.verify(publicKey, data, signature, options).then(function (isValid) {
console.log(isValid)
})
// Symmetric Encryption (AES)
// Generate new symmetric key
/*
* keyLength: 128, 192 or 256 | default: 256
* options: { keyCipher: 'AES-GCM', keyUsages: ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'], isExtractable: true }
*/
crypt.getSharedKey(keyLength, options).then(function (sharedKey) {
console.log(sharedKey)
})
// Encrypt data using shared key
/*
* sharedKey: CryptoKey | default: undefined
* data: ArrayBuffer | default: undefined
*/
crypt.encrypt(sharedKey, data).then(function (encryptedData) {
console.log(encryptedData)
})
// Decrypt data using shared key
/*
* sharedKey: CryptoKey | default: undefined
* encryptedData: base64 String | default: undefined
*/
crypt.decrypt(sharedKey, encryptedData).then(function (decryptedData) {
console.log(decryptedData)
})
// Other Crypto Features
// Derive hash from passphrase
/*
* passphrase: String | default: undefined
* salt: ArrayBuffer | default: undefined
* iterations: Integer | default: 64000
* hash: 'SHA-1' or 'SHA-256' or 'SHA-384' or 'SHA-512' | default: 'SHA-512'
* length: default: 256
*/
crypt.hashPassphrase(passphrase, salt, iterations, hash, length).then(function (derivedKey) {
console.log(derivedKey)
})
// Get key fingerprint
/*
* key: CryptoKey | default: undefined
* options: Object | default: { hash: 'SHA-512', isBuffer: false }
*/
crypt.getFingerprint(key, options).then(function (fingerprint) {
console.log(fingerprint)
})
// Generate random data
/*
* size: Integer | default: 16
*/
crypt.getRandomBytes(size).then(function (data) {
console.log(data)
})
Standards Compliance
RFC 5280
RFC 6090
RFC 5208
RFC 5480
RFC 5915
RFC 8018
RFC 3394
NIST SP 800-38A
NIST SP 800-38B
NIST SP 800-38D
NIST SP 800-56A
NIST SP 800-56C
NIST FIPS 180-4
Contributors
Peter Bielak
Andrew Kozlik, Ph.D.
License
MIT