UNPKG

@voken/base32

Version:

VOKEN Flavored Base32 Encoding and Decoding, with the checksum by default.

138 lines (106 loc) 2.94 kB
const crypto = require('crypto') const ALPHABET = '0123456789abcdefghjkmnpqrstuvwxy' // encode const encode = function (input, checksum = true) { const encoded = _encode(input) if (!checksum) { return encoded } const encodedArray = encoded.split('') const hash32 = crypto.createHash('sha256').update(encoded).digest() let output = '' encodedArray.forEach(function (c, i) { if (hash32[i % 32] > 127) { output = output + c.toUpperCase() } else { output = output + c } }) return output } // decode const decode = function (input, checksum = true) { const decoded = _decode(input) if (!checksum) { return decoded } const encodedChecksum = encode(decoded) if (input !== encodedChecksum) { throw new InvalidChecksumError('Invalid checksum') } return decoded } const isChecksum = function (input) { const decoded = _decode(input) const encodedChecksum = encode(decoded) return input === encodedChecksum } // encode without checksum const _encode = function (input) { if (Array.isArray(input) || input instanceof Uint8Array) { input = Buffer.from(input) } if (!Buffer.isBuffer(input)) { throw new TypeError('Expected Buffer') } let bits = 0 let value = 0 let output = '' for (let i = 0; i < input.byteLength; i++) { value = (value << 8) | input[i] bits += 8 while (bits >= 5) { output += ALPHABET[(value >>> (bits - 5)) & 31] bits -= 5 } } if (bits > 0) { output += ALPHABET[(value << (5 - bits)) & 31] } // while ((output.length % 8) !== 0) { // output += '=' // } return output } // decode without checksum const _decode = function (input) { input = input.replace(/=+$/, '').toLowerCase() const output = new Uint8Array((input.length * 5 / 8) | 0) let bits = 0 let value = 0 let index = 0 for (let i = 0; i < input.length; i++) { value = (value << 5) | _readChar(input[i]) bits += 5 if (bits >= 8) { output[index++] = (value >>> (bits - 8)) & 255 bits -= 8 } } return Buffer.from(output) } // readChar const _readChar = function (char) { const idx = ALPHABET.indexOf(char) if (idx === -1) { throw new InvalidCharacterError('Invalid character found: ' + char) } return idx } class InvalidCharacterError extends Error { constructor(message) { super(message); this.name = "InvalidCharacterError"; this.code = 'INVALID_CHARACTER' } } class InvalidChecksumError extends Error { constructor(message) { super(message); this.name = "InvalidChecksumError"; this.code = 'INVALID_CHECKSUM' } } module.exports = { encode: encode, decode: decode, isChecksum: isChecksum, InvalidCharacterError: InvalidCharacterError, InvalidChecksumError: InvalidChecksumError }