react-native-quick-crypto
Version:
A fast implementation of Node's `crypto` module written in C/C++ JSI
108 lines (96 loc) • 3.1 kB
text/typescript
import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
import type { InternalHmac } from './NativeQuickCrypto/hmac';
import {
type Encoding,
toArrayBuffer,
type BinaryLike,
binaryLikeToArrayBuffer,
} from './Utils';
import Stream from 'readable-stream';
import { Buffer } from '@craftzdog/react-native-buffer';
const createInternalHmac = NativeQuickCrypto.createHmac;
export function createHmac(
algorithm: string,
key: BinaryLike,
options?: Stream.TransformOptions,
) {
return new Hmac(algorithm, key, options);
}
class Hmac extends Stream.Transform {
private internalHmac: InternalHmac;
private isFinalized: boolean = false;
constructor(
algorithm: string,
key: BinaryLike,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_options?: Stream.TransformOptions,
) {
super();
const keyAsString = binaryLikeToArrayBuffer(key);
if (keyAsString === undefined) {
throw 'Wrong key type';
}
this.internalHmac = createInternalHmac(
algorithm,
keyAsString as ArrayBuffer,
);
}
/**
* Updates the `Hmac` content with the given `data`, the encoding of which
* is given in `inputEncoding`.
* If `encoding` is not provided, and the `data` is a string, an
* encoding of `'utf8'` is enforced. If `data` is a `Buffer`, `TypedArray`, or`DataView`, then `inputEncoding` is ignored.
*
* This can be called many times with new data as it is streamed.
* @since v0.1.94
* @param inputEncoding The `encoding` of the `data` string.
*/
update(data: string | BinaryLike, inputEncoding?: Encoding): Hmac {
if (data instanceof ArrayBuffer) {
this.internalHmac.update(data);
return this;
}
if (typeof data === 'string') {
const buffer = Buffer.from(data, inputEncoding);
this.internalHmac.update(toArrayBuffer(buffer));
return this;
}
this.internalHmac.update(binaryLikeToArrayBuffer(data));
return this;
}
_transform(
chunk: string | BinaryLike,
encoding: Encoding,
callback: () => void,
) {
this.update(chunk, encoding);
callback();
}
_flush(callback: () => void) {
this.push(this.digest());
callback();
}
/**
* Calculates the HMAC digest of all of the data passed using `hmac.update()`.
* If `encoding` is
* provided a string is returned; otherwise a `Buffer` is returned;
*
* The `Hmac` object can not be used again after `hmac.digest()` has been
* called. Multiple calls to `hmac.digest()` will result in an error being thrown.
* @since v0.1.94
* @param encoding The `encoding` of the return value.
*/
digest(): Buffer;
digest(encoding: 'buffer'): Buffer;
digest(encoding: Encoding): string;
digest(encoding?: Encoding | 'buffer'): string | Buffer {
const result: ArrayBuffer = this.isFinalized
? new ArrayBuffer(0)
: this.internalHmac.digest();
this.isFinalized = true;
if (encoding && encoding !== 'buffer') {
return Buffer.from(result).toString(encoding);
}
return Buffer.from(result);
}
}