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

otpus

v1.1.0

Published

General purpose cipher for Node & browser

Downloads

30

Readme

OTPUS

Cipher and tools for Node and Browser.
( 범용 암호 구현 및 환경)

Features

  • Ready to development using Web Crypto API.
    • Isomorphic Web Crypto Name Reference(Node and Browser)
    • You can use isomorphic reference name of 'webCrypto' from otpus.
    • Node.js and Browser use different namespace.
  • WebCrypto API based general purpose async style encryption functions
    • algorithm: AES-GCM, PBKDF2.
    • encrypt() : support any type of data and key.
    • random data size
    • secret buffer pack ( meta buffer pack )
    • decrypt() : return origin data type.( thanks to the special feature of MBP)
  • pure otpus implements
    • xotp()
      • cipher function. based XOR and Pseudo OTP.
    • encryptMessage()
      • simple but strong enough text message encryption.( Use stong passphrase)
      • recersive hash sum with salt.(like PBKDF2)
      • random data size.(hide real message size.)
      • HMAC support. (detect corrupted message.)
      • output: base64 string.(simple handy universal data format)
    • decryptMessage()
      • receive base64 encoded message.
      • return plain text.
      • return undefined. ( for corrupted message)
  • include essential tools:
    • otpus.sha256 : fast-sha256 : sync type hash, hmac.
    • otpus.base64js : base64js : transcoder( buffer <-> UTF8 string )
    • otpus.MBP : meta buffer pack : buffer packer
    • otpus.Buffer : buffer : Node.js Buffer for browser.

Table of Contents

Support

You can use modern ESM style or Legacy CJS, IIFE style both.

  • NodeJS:
    • ESM: src/index.js , dist/otpus.mjs (bundled version.)
    • CommonJS: dist/otpus.cjs
  • Browser:
    • ESM: dist/otpus.esm.js
    • IIFE: dist/otpus.min.js

Usage

Installing

npm i otpus

Browser

  • IIFE: Use script tag in html
  • the otpus.min.js file is inside dist folder.
<script src="../dist/otpus.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/otpus@1/dist/otpus.min.js"></script>
  • ES Module.

// don't forget the fullpath and file extension.
import {encryptMessage, decryptMessage, xotp } from "../path/otpus.esm.js"

Node.js


// Node ESM
import {encryptMessage, decryptMessage, xotp } from "otpus"

// Node CJS
// tip. if your pacakage.json using "module" type, you should use *.cjs file extension.
const {encryptMessage, decryptMessage, xotp } = require("otpus")

Sync functions

encryptMessage()

encryptMessage( data: String , key: String , nPower: Number = 15 ) : String

General purpose text message encryption.

  • data: Any UTF8 string.
  • key: Any UTF8 string.
    • please use long passPhrase.
  • nPower:
    • factor for recursive hash sum counter
    • counter = 2 ** nPower
    • counter is the result of exponentiation with number two as the base and integer nPower as the exponent.
    • default value is 15. ( 2 ** 15 => 32768 times)
    • You can use high number for strong encryption( but it takes more cpu time. )
    • example( on my device)
      • mobile: 15 => spent about one second.
      • desktop: 17 => spent about one second.
  • output: encrytped and encoded base64 string.

decryptMessage()

decryptMessage( data: String, key: String ) : String
  • data: base64 ecoded string data
  • key: same with encryptMessage()
  • output: plain text

Encoded data

  • encryptMessage() return base64 string data.
  • If you need buffer data. use Buffer.from( base64Msg, 'base64' ) method.
  • or reverse command: buffer.toString('base64')

import {  encryptMessage, decryptMessage , Buffer } from 'otpus'
   
const plainText = 'this is sercret message'
const keyStr =  'this is secret key'

let encPack = encryptMessage( plainText, keyStr  )

// now encPack is encrypted & base64 encoded string.
/*  random size.
sX7SStdL/pF7umBBEJ7EKXuv7QYLflCe3vy9F+XEayQVfAVa3PoZ1UasXl
... SxbIm5Qb3dlciIsIjgiLDE0OF1dAE8=
*/

// if you need buffer data.
const encBuffer = Buffer.from( encPack , 'base64' )
// or reverse transformation ( from buffer to base64) also avaiable. 
const base64Pack = encBuffer.toString('base64')

let decMsg = decryptMessage(encPack ,keyStr )

if( decMsg  ){ // success
    // decMsg === 'this is sercret message'
}else{ 
    // decMsg === undefined  when fail. 
}

decryptMessage()

corruption check

  • When encryption process is fail for any reason. it will return undefined.
  • The encryption data store HMAC ( hash of message and key) info inside.
  • If calculated hmac is dismatched with stored hmac then return undefined.
  • Try this example. See the result when modify one byte of encryption data.

import {  encryptMessage, decryptMessage } from 'otpus'
   
const plainText = 'this is sercret message'
const keyStr =  'this is secret key'

let encPack = encryptMessage( plainText, keyStr  )

encPack = messageModification( encPack) //try make corrupted message.

let decMsg = decryptMessage(encPack ,keyStr )

if( decMsg  ){ // success
    console.log( 'decMsg:', decMsg )
}else{ // return undefined  when fail. 
    console.log('wrong data')
}

function messageModification( dataOrg ){
    const data = Buffer.from(dataOrg, 'base64')
    data[10] ^= 0x01; // modify one byte
    return data.toString('base64')
}

xotp()

This function is base cipher algorithm for otpus.( using XOR and Pseudo OTP.) You can make other encryption function( like encyptMessage) using this function.


xotp( data: Uint8Array, otpKey32Bytes: Uint8Array, otpSartIndex: Number = 0, shareDataBuffer: boolean = false ) : Uint8Array
  • Using encryption and decryption both.
  • data: Uint8Array only.
  • key: 32bytes Uint8Array only.
  • otpStartIndex: Number( 0 ~ 2**32-1.) default. 0
  • shareDataBuff: important
    • false: return new buffer. default.
      • recommended for small size data.
    • true: modify input data buffer.
      • recommended for the large data.

import { MBP, sha256, xotp  } from 'otpus'
   
const msgStr = 'aaaaaaaaaaaa'   
const pwStr = 'passphrase'    
  
let otpKey = sha256.hash( pwStr)  
// return 32bytes Uint8Array from string data.
let data = MBP.U8( msgStr )  
// MBP.U8(): parse any type of data into Uint8Array 

// use case 1. shareDataBuffer is false. 
let enc = xotp( data ,otpKey, 0 )  // false default.
let dec = xotp( enc , otpKey, 0 ) 

// use case 2. shareDataBuffer is true.
let encShare = xotp( data ,otpKey, 0 , true)  
// encShare & data is reference of same arrayBuffer.

// when shareOption is true.
// no return value needed. ( same below.)

// data before encryption.
xotp( data , otpKey, 0, true)
// now input data is changed.  
xotp( data , otpKey, 0 , true)
// now data is decrypted.

Async functions using WebCrypto API

Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers. MDN SubtleCrypto
Node.js: The Web Cryptography API implementation has landed as an experimental feature in Node.js 15.0.0.( current status: Stability: 1 - Experimental.) Implementing the Web Cryptography API for Node.js Core

encrypt()

otpus's general purpose encryption implement using Web Crypto API.

features:

  • any type of data.
  • any type of key( passPhrase). string passphrase or buffer
  • result of decryption data will be same data type of origin data.
  • randomize data size. (to hide real message size)
  • Using WebCrypto API
    • encryption algorithm: AES-GCM of Webcrypto API.
      • support message authentication
    • key generation: PBKDF2 of WebCrypto API.
    • salt, iv: from getRandomValues
  • data packaging: MBP(meta-buffer-pack)
  encrypt( data: any , passPhrase: any ,iterations : Number = 32768 ) bufferPack: Promise
  • async version of otpus.encrytMessage()
    • available: promise chaining, async await.
  • input
    • data {Stinrg | Uint8Array | Number | Object }
    • passPhrase {Stinrg | Uint8Array | Number | Object }
    • iterations {Number} iterations for PBKDF2 ( default 32768.)
  • returns
    • Promise ( will return bufferPack when fulfilled )

    • bufferPack is Node.js Buffer( subclass of Uint8Array)

decrypt()

  decrypt(data:Uint8Array , passPhrase: any  ) decodeData: Promise 
  • input
    • bufferPack(MBP pack) {Uint8Array}
    • passPhrase {String | Uint8Array | any }
  • returns
    • Promise ( will return decodedData when fulfilled )
import { encrypt, decrypt ,Buffer } from "otpus"

// async await style
const plainText = 'this is a secret message.'
const encPack = await encrypt(plainText, 'passPhrase', 10000)
const decodeMessage = await decrypt(encPack, 'passPhrase')

console.log('decrypted:', decodeMessage)

const plainData = Buffer.alloc(100 * 2 ** 20)
const encData = await encrypt(plainData, 'passPhrase', 10000)
const decData = await decrypt(encData, 'passPhrase')

const some = decData.slice(0, 16)
console.log('decrypted: some:', some)
console.log('decrypted: byteLength:', decData.byteLength)

const key = 'key'
const strData = 'hello world'


// promise chaining

// string data will return string data. 
encrypt(strData, key)
  .then(secretPack => {
    console.log('secretPack', secretPack.byteLength)
    return decrypt(secretPack, key)
  })
  .then(data => {
    console.log( 'typeof data:', typeof data)  // string 
    console.log('decoded string message: ', data)
  })


// Uint8Array data will return Uint8Array data.
const binaryData = Uint8Array.from([1, 2, 3, 4])
encrypt(binaryData, key)
  .then(secretPack => {
    console.log('secretPack', secretPack.byteLength)
    return decrypt(secretPack, key)
  })
  .then(data => {
    console.log('instanceof Uint8Array:', data instanceof Uint8Array )  //true
    console.log('decoded binary data: ', data)
  })

Error catch

For many reason encryption process could be fail. You should use try, catch statements.

//  await style
try{
    const secretPack = await encrypt('plain text','key')
    const decoded = await decrypt( secretPack,'key')
    console.log('decoded:', decoded)
}catch(error){
    console.log(error)
}

// Promise style
encrypt('plain text','key')
    .then( secretPack => decrypt(secretPack, 'key' ) )
    .then( decoded => console.log( decoded ))
    .catch( error=>{
        console.log(error)
    })

Handling buffer

encrypt() function generate a buffer( meta-buffer-pack). You can transform data format.


import{ encrypt, decrypt, MBP } from 'otpus'

const secretPack = await encrypt('data','key')

// secretPack is Buffer ( subclass of Uint8Array)
console.log( secretPack instanceof Uint8Array ) //  true 

// case. If you need base64 string data. 
const base64Pack = secretPack.toString('base64')
console.log( 'base64 data:', base64Pack ) 

/*
base64 data: F59Pyfq8EOSVSprdvbI2U+46JGtpcQ0sa3W2YtGRBxdJTdT41GY6a+FfBIvT4byChSu1KTGP1PJXewTidfeN1dgQh2IAe+eB2f/Df64kBXdr7HcvMFbawu2tOuUzUsonluKK25J5ilUtpuF2qszf9DEwMDAwW1siZW5jRGF0YSIsIkIiLDAsODRdLFsiaXYiLCJCIiw4NCwxMl0sWyJzYWx0IiwiQiIsOTYsMTZdLFsiaXRlcmF0aW9ucyIsIk4iLDExMiw1XV0AUw==
*/

// secretPack is meta-buffer-pack of MBP.
// You can use  MBP.unpack() to check public information like iv , salt.
cosnt secretObject = MBP.unpack( secretPack )
console.log( 'salt:', sercretObject.salt ) // 16 bytes. random values.

// salt: <Buffer 96 e2 8a db 92 79 8a 55 2d a6 e1 76 aa cc df f4>

Examples

  • NodeJs: please check test, testing directory.
  • Browser: example directory.

Online demo

license

MIT