diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/workflows/prebuild.yml b/.github/workflows/prebuild.yml index 8877a15..3c4a203 100644 --- a/.github/workflows/prebuild.yml +++ b/.github/workflows/prebuild.yml @@ -6,82 +6,82 @@ jobs: strategy: matrix: include: - - os: ubuntu-22.04 - platform: linux - arch: x64 - - os: ubuntu-22.04-arm64 - platform: linux - arch: arm64 - - os: ubuntu-22.04 - platform: android - arch: x64 - flags: -D ANDROID_STL=c++_shared - - os: ubuntu-22.04 - platform: android - arch: ia32 - flags: -D ANDROID_STL=c++_shared - - os: ubuntu-22.04 - platform: android - arch: arm64 - flags: -D ANDROID_STL=c++_shared - - os: ubuntu-22.04 - platform: android - arch: arm - flags: -D ANDROID_STL=c++_shared - - os: macos-14 - platform: darwin - arch: x64 - - os: macos-14 - platform: darwin - arch: arm64 - - os: macos-14 - platform: ios - arch: arm64 - - os: macos-14 - platform: ios - arch: arm64 - tags: -simulator - flags: --simulator - - os: macos-14 - platform: ios - arch: x64 - tags: -simulator - flags: --simulator - - os: windows-2022 - platform: win32 - arch: x64 - - os: windows-2022 - platform: win32 - arch: arm64 + - os: ubuntu-22.04 + platform: linux + arch: x64 + - os: ubuntu-22.04-arm64 + platform: linux + arch: arm64 + - os: ubuntu-22.04 + platform: android + arch: x64 + flags: -D ANDROID_STL=c++_shared + - os: ubuntu-22.04 + platform: android + arch: ia32 + flags: -D ANDROID_STL=c++_shared + - os: ubuntu-22.04 + platform: android + arch: arm64 + flags: -D ANDROID_STL=c++_shared + - os: ubuntu-22.04 + platform: android + arch: arm + flags: -D ANDROID_STL=c++_shared + - os: macos-14 + platform: darwin + arch: x64 + - os: macos-14 + platform: darwin + arch: arm64 + - os: macos-14 + platform: ios + arch: arm64 + - os: macos-14 + platform: ios + arch: arm64 + tags: -simulator + flags: --simulator + - os: macos-14 + platform: ios + arch: x64 + tags: -simulator + flags: --simulator + - os: windows-2022 + platform: win32 + arch: x64 + - os: windows-2022 + platform: win32 + arch: arm64 runs-on: ${{ matrix.os }} name: ${{ matrix.platform }}-${{ matrix.arch }}${{ matrix.tags }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - cache: false - go-version: stable - - uses: actions/setup-node@v4 - with: - node-version: lts/* - - run: npm install -g bare-runtime bare-make - - run: npm install - - run: bare-make generate --platform ${{ matrix.platform }} --arch ${{ matrix.arch }} ${{ matrix.flags }} - - run: bare-make build - - run: bare-make install - - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.platform }}-${{ matrix.arch }}${{ matrix.tags }} - path: prebuilds/* + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + cache: false + go-version: stable + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - run: npm install -g bare-runtime bare-make + - run: npm install + - run: bare-make generate --platform ${{ matrix.platform }} --arch ${{ matrix.arch }} ${{ matrix.flags }} + - run: bare-make build + - run: bare-make install + - uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.platform }}-${{ matrix.arch }}${{ matrix.tags }} + path: prebuilds/* merge: runs-on: ubuntu-latest needs: prebuild steps: - - uses: actions/download-artifact@v4 - with: - path: prebuilds - merge-multiple: true - - uses: actions/upload-artifact@v4 - with: - name: prebuilds - path: prebuilds + - uses: actions/download-artifact@v4 + with: + path: prebuilds + merge-multiple: true + - uses: actions/upload-artifact@v4 + with: + name: prebuilds + path: prebuilds diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f29a0a..2d24f6d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,29 +11,29 @@ jobs: strategy: matrix: include: - - os: ubuntu-latest - platform: linux - arch: x64 - - os: macos-latest - platform: darwin - arch: arm64 - - os: windows-latest - platform: win32 - arch: x64 + - os: ubuntu-latest + platform: linux + arch: x64 + - os: macos-latest + platform: darwin + arch: arm64 + - os: windows-latest + platform: win32 + arch: x64 runs-on: ${{ matrix.os }} name: ${{ matrix.platform }}-${{ matrix.arch }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - cache: false - go-version: stable - - uses: actions/setup-node@v4 - with: - node-version: lts/* - - run: npm install -g bare-runtime bare-make - - run: npm install - - run: bare-make generate --platform ${{ matrix.platform }} --arch ${{ matrix.arch }} --debug - - run: bare-make build - - run: bare-make install - - run: npm test + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + cache: false + go-version: stable + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - run: npm install -g bare-runtime bare-make + - run: npm install + - run: bare-make generate --platform ${{ matrix.platform }} --arch ${{ matrix.arch }} --debug + - run: bare-make build + - run: bare-make install + - run: npm test diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..c18a05d --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +"prettier-config-standard" diff --git a/README.md b/README.md index 3afd00a..419629f 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,13 @@ Fill a buffer with cryptographically secure random bytes, asynchronously providi The supported hash algorithms. -Constant | Description ---- | --- -`MD5` | A widely-used 128-bit hash function, now considered insecure due to vulnerabilities to collision attacks. Still fast but not recommended for security-sensitive purposes. -`SHA1` | A 160-bit hash function, stronger than MD5 but also broken by collision attacks. Deprecated for most cryptographic uses due to security vulnerabilities. -`SHA256` | Part of the SHA-2 family, this 256-bit hash function is widely used and considered secure for most applications. Slower than MD5 and SHA1 but much more secure. -`SHA512` | Another member of the SHA-2 family, this 512-bit hash function offers greater security than SHA256 but is slower and produces larger hashes. Suitable for high-security environments. -`BLAKE2B256` | A fast, secure alternative to SHA-2 designed for efficiency, producing a 256-bit hash. It is optimized for performance while maintaining strong cryptographic security. +| Constant | Description | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `MD5` | A widely-used 128-bit hash function, now considered insecure due to vulnerabilities to collision attacks. Still fast but not recommended for security-sensitive purposes. | +| `SHA1` | A 160-bit hash function, stronger than MD5 but also broken by collision attacks. Deprecated for most cryptographic uses due to security vulnerabilities. | +| `SHA256` | Part of the SHA-2 family, this 256-bit hash function is widely used and considered secure for most applications. Slower than MD5 and SHA1 but much more secure. | +| `SHA512` | Another member of the SHA-2 family, this 512-bit hash function offers greater security than SHA256 but is slower and produces larger hashes. Suitable for high-security environments. | +| `BLAKE2B256` | A fast, secure alternative to SHA-2 designed for efficiency, producing a 256-bit hash. It is optimized for performance while maintaining strong cryptographic security. | ## License diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..27e127a --- /dev/null +++ b/index.d.ts @@ -0,0 +1,67 @@ +import { Transform, TransformOptions } from 'bare-stream' +import Buffer, { BufferEncoding } from 'bare-buffer' + +type Algorithm = 'MD5' | 'SHA1' | 'SHA256' | 'SHA512' | 'BLAKE2B256' + +export const constants: { hash: Record } + +declare class CryptoError extends Error { + static UNSUPPORTED_DIGEST_METHOD(msg: string): CryptoError +} + +export class Hash extends Transform { + constructor( + algorithm: Algorithm | Lowercase | number, + opts?: TransformOptions + ) + + update(data: string, encoding?: BufferEncoding): this + update(data: Buffer): this + + digest(encoding: BufferEncoding): string + digest(): Buffer +} + +export function createHash( + algorithm: Algorithm | Lowercase | number, + opts?: TransformOptions +): Hash + +export function randomBytes(size: number): Buffer + +export function randomBytes( + size: number, + callback: (err: Error | null, buffer: Buffer) => void +): void + +export function randomFill( + buffer: B, + offset?: number, + size?: number +): B + +export function randomFill( + buffer: B, + callback: (err: Error | null, buffer: B) => void +): void + +export function randomFill( + buffer: B, + offset: number, + callback: (err: Error | null, buffer: B) => void +): void + +export function randomFill( + buffer: B, + offset: number, + size: number, + callback: (err: Error | null, buffer: B) => void +): void + +export function randomFillSync( + buffer: B, + offset?: number, + size?: number +): B + +export { CryptoError as errors } diff --git a/index.js b/index.js index 754cd8f..8cfd24f 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,10 @@ const { Transform } = require('bare-stream') const binding = require('./binding') -const constants = exports.constants = require('./lib/constants') -const errors = exports.errors = require('./lib/errors') +const constants = (exports.constants = require('./lib/constants')) +const errors = (exports.errors = require('./lib/errors')) -const Hash = exports.Hash = class CryptoHash extends Transform { - constructor (algorithm, opts = {}) { +exports.Hash = class CryptoHash extends Transform { + constructor(algorithm, opts = {}) { super(opts) if (typeof algorithm === 'string') { @@ -14,7 +14,9 @@ const Hash = exports.Hash = class CryptoHash extends Transform { if (algorithm in constants.hash) algorithm = constants.hash[algorithm] else { - throw errors.UNSUPPORTED_DIGEST_METHOD(`Unsupported digest method '${algorithm}'`) + throw errors.UNSUPPORTED_DIGEST_METHOD( + `Unsupported digest method '${algorithm}'` + ) } } } @@ -22,7 +24,7 @@ const Hash = exports.Hash = class CryptoHash extends Transform { this._handle = binding.hashInit(algorithm) } - update (data, encoding = 'utf8') { + update(data, encoding = 'utf8') { if (typeof data === 'string') data = Buffer.from(data, encoding) binding.hashUpdate(this._handle, data) @@ -30,37 +32,37 @@ const Hash = exports.Hash = class CryptoHash extends Transform { return this } - digest (encoding) { + digest(encoding) { const digest = Buffer.from(binding.hashFinal(this._handle)) return encoding ? digest.toString(encoding) : digest } - _transform (data, encoding, cb) { + _transform(data, encoding, cb) { this.update(data) cb(null) } - _flush (cb) { + _flush(cb) { this.push(this.digest()) cb(null) } } -exports.createHash = function createHash (algorithm, opts) { - return new Hash(algorithm, opts) +exports.createHash = function createHash(algorithm, opts) { + return new exports.Hash(algorithm, opts) } -exports.randomBytes = function randomBytes (size, cb) { +exports.randomBytes = function randomBytes(size, cb) { const buffer = Buffer.allocUnsafe(size) - randomFill(buffer) + exports.randomFill(buffer) if (cb) queueMicrotask(() => cb(null, buffer)) else return buffer } -const randomFill = exports.randomFill = function randomFill (buffer, offset, size, cb) { +exports.randomFill = function randomFill(buffer, offset, size, cb) { if (typeof offset === 'function') { cb = offset offset = undefined @@ -77,9 +79,12 @@ const randomFill = exports.randomFill = function randomFill (buffer, offset, siz if (size === undefined) size = buffer.byteLength - offset else size *= elementSize - if (offset < 0 || offset > buffer.byteLength) throw new RangeError('offset is out of range') - if (size < 0 || size > buffer.byteLength) throw new RangeError('size is out of range') - if (offset + size > buffer.byteLength) throw new RangeError('offset + size is out of range') + if (offset < 0 || offset > buffer.byteLength) + throw new RangeError('offset is out of range') + if (size < 0 || size > buffer.byteLength) + throw new RangeError('size is out of range') + if (offset + size > buffer.byteLength) + throw new RangeError('offset + size is out of range') if (ArrayBuffer.isView(buffer)) { offset += buffer.byteOffset @@ -93,6 +98,6 @@ const randomFill = exports.randomFill = function randomFill (buffer, offset, siz } // For Node.js compatibility -exports.randomFillSync = function randomFillSync (buffer, offset, size) { - return randomFill(buffer, offset, size) +exports.randomFillSync = function randomFillSync(buffer, offset, size) { + return exports.randomFill(buffer, offset, size) } diff --git a/lib/errors.js b/lib/errors.js index b734239..6b763b6 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -1,5 +1,5 @@ module.exports = class CryptoError extends Error { - constructor (msg, code, fn = CryptoError) { + constructor(msg, code, fn = CryptoError) { super(`${code}: ${msg}`) this.code = code @@ -8,11 +8,15 @@ module.exports = class CryptoError extends Error { } } - get name () { + get name() { return 'CryptoError' } - static UNSUPPORTED_DIGEST_METHOD (msg) { - return new CryptoError(msg, 'UNSUPPORTED_DIGEST_METHOD', CryptoError.UNSUPPORTED_DIGEST_METHOD) + static UNSUPPORTED_DIGEST_METHOD(msg) { + return new CryptoError( + msg, + 'UNSUPPORTED_DIGEST_METHOD', + CryptoError.UNSUPPORTED_DIGEST_METHOD + ) } } diff --git a/package.json b/package.json index 0599844..0b2c41f 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,17 @@ "version": "1.3.1", "description": "Cryptographic primitives for JavaScript", "exports": { - ".": "./index.js", + ".": { + "types": "./index.d.ts", + "default": "./index.js" + }, "./package": "./package.json", "./constants": "./lib/constants.js", "./errors": "./lib/errors.js" }, "files": [ "index.js", + "index.d.ts", "binding.c", "binding.js", "CMakeLists.txt", @@ -18,7 +22,7 @@ ], "addon": true, "scripts": { - "test": "standard && bare test.js" + "test": "prettier . --check && bare test.js" }, "repository": { "type": "git", @@ -31,12 +35,22 @@ }, "homepage": "https://github.com/holepunchto/bare-crypto#readme", "dependencies": { - "bare-stream": "^2.0.0" + "bare-stream": "^2.6.3" }, "devDependencies": { + "bare-buffer": "^3.0.1", "brittle": "^3.5.0", "cmake-bare": "^1.1.6", "cmake-fetch": "^1.0.0", - "standard": "^17.0.0" + "prettier": "^3.4.2", + "prettier-config-standard": "^7.0.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } } } diff --git a/test.js b/test.js index 0e873b0..54d7262 100644 --- a/test.js +++ b/test.js @@ -3,9 +3,7 @@ const crypto = require('.') test('hash sha1', (t) => { t.is( - crypto.createHash('sha1') - .update('foo bar') - .digest('hex'), + crypto.createHash('sha1').update('foo bar').digest('hex'), '3773dea65156909838fa6c22825cafe090ff8030' ) })