otpus
v1.1.0
Published
General purpose cipher for Node & browser
Downloads
30
Maintainers
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)
- simple but strong enough text message encryption.(
- decryptMessage()
- receive base64 encoded message.
- return plain text.
- return undefined. ( for corrupted message)
- xotp()
- 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
- otpus
- Features
- Table of Contents
- Support
- Usage
- Sync functions
- Async functions using WebCrypto API
- Examples
- Online demo
- License
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>
- You can use global CDN url. jsDeliver
<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.
- false: return new buffer. default.
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
- encryption algorithm: AES-GCM of Webcrypto API.
- 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.