summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/internal/crypto/cipher.ts
diff options
context:
space:
mode:
authorYoshiya Hinosawa <stibium121@gmail.com>2023-03-18 21:51:28 +0900
committerGitHub <noreply@github.com>2023-03-18 21:51:28 +0900
commit5223f3d9b68921179db8cd6b00babd711d4f06ff (patch)
treebd0167da2bb488e31f79ee51dbcd0e67bcb527a7 /ext/node/polyfills/internal/crypto/cipher.ts
parent44553aa09ec2de5a59db17433fd601a9dc7bd624 (diff)
fix(ext/node): add createDecipheriv (#18245)
Diffstat (limited to 'ext/node/polyfills/internal/crypto/cipher.ts')
-rw-r--r--ext/node/polyfills/internal/crypto/cipher.ts93
1 files changed, 70 insertions, 23 deletions
diff --git a/ext/node/polyfills/internal/crypto/cipher.ts b/ext/node/polyfills/internal/crypto/cipher.ts
index b2d24947a..d40978cf6 100644
--- a/ext/node/polyfills/internal/crypto/cipher.ts
+++ b/ext/node/polyfills/internal/crypto/cipher.ts
@@ -130,7 +130,7 @@ export class Cipheriv extends Transform implements Cipher {
options?: TransformOptions,
) {
super(options);
- this.#cache = new BlockModeCache();
+ this.#cache = new BlockModeCache(false);
this.#context = ops.op_node_create_cipheriv(cipher, key, iv);
}
@@ -161,14 +161,23 @@ export class Cipheriv extends Transform implements Cipher {
update(
data: string | Buffer | ArrayBufferView,
- // TODO(kt3k): Handle inputEncoding
- _inputEncoding?: Encoding,
+ inputEncoding?: Encoding,
outputEncoding: Encoding = getDefaultEncoding(),
): Buffer | string {
- this.#cache.add(data);
+ // TODO(kt3k): throw ERR_INVALID_ARG_TYPE if data is not string, Buffer, or ArrayBufferView
+ if (typeof data === "string" && typeof inputEncoding === "string") {
+ this.#cache.add(Buffer.from(data, inputEncoding));
+ } else {
+ this.#cache.add(data);
+ }
const input = this.#cache.get();
- const output = new Buffer(input.length);
- ops.op_node_cipheriv_encrypt(this.#context, input, output);
+ let output;
+ if (input === null) {
+ output = Buffer.alloc(0);
+ } else {
+ output = Buffer.allocUnsafe(input.length);
+ ops.op_node_cipheriv_encrypt(this.#context, input, output);
+ }
return outputEncoding === "buffer"
? output
: output.toString(outputEncoding);
@@ -178,8 +187,13 @@ export class Cipheriv extends Transform implements Cipher {
/** Caches data and output the chunk of multiple of 16.
* Used by CBC, ECB modes of block ciphers */
class BlockModeCache {
- constructor() {
+ cache: Uint8Array;
+ // The last chunk can be padded when decrypting.
+ #lastChunkIsNonZero: boolean;
+
+ constructor(lastChunkIsNotZero = false) {
this.cache = new Uint8Array(0);
+ this.#lastChunkIsNonZero = lastChunkIsNotZero;
}
add(data: Uint8Array) {
@@ -189,11 +203,19 @@ class BlockModeCache {
this.cache.set(data, cache.length);
}
- get(): Uint8Array {
- if (this.cache.length < 16) {
+ /** Gets the chunk of the length of largest multiple of 16.
+ * Used for preparing data for encryption/decryption */
+ get(): Uint8Array | null {
+ let len = this.cache.length;
+ if (this.#lastChunkIsNonZero) {
+ // Reduces the available chunk length by 1 to keep the last chunk
+ len -= 1;
+ }
+ if (len < 16) {
return null;
}
- const len = Math.floor(this.cache.length / 16) * 16;
+
+ len = Math.floor(len / 16) * 16;
const out = this.cache.subarray(0, len);
this.cache = this.cache.subarray(len);
return out;
@@ -201,19 +223,28 @@ class BlockModeCache {
}
export class Decipheriv extends Transform implements Cipher {
+ /** DecipherContext resource id */
+ #context: number;
+
+ /** ciphertext data cache */
+ #cache: BlockModeCache;
+
constructor(
- _cipher: string,
- _key: CipherKey,
- _iv: BinaryLike | null,
- _options?: TransformOptions,
+ cipher: string,
+ key: CipherKey,
+ iv: BinaryLike | null,
+ options?: TransformOptions,
) {
- super();
-
- notImplemented("crypto.Decipheriv");
+ super(options);
+ this.#cache = new BlockModeCache(true);
+ this.#context = ops.op_node_create_decipheriv(cipher, key, iv);
}
- final(_outputEncoding?: string): Buffer | string {
- notImplemented("crypto.Decipheriv.prototype.final");
+ final(encoding: string = getDefaultEncoding()): Buffer | string {
+ let buf = new Buffer(16);
+ ops.op_node_decipheriv_final(this.#context, this.#cache.cache, buf);
+ buf = buf.subarray(0, 16 - buf.at(-1)); // Padded in Pkcs7 mode
+ return encoding === "buffer" ? buf : buf.toString(encoding);
}
setAAD(
@@ -234,11 +265,27 @@ export class Decipheriv extends Transform implements Cipher {
}
update(
- _data: string | BinaryLike | ArrayBufferView,
- _inputEncoding?: Encoding,
- _outputEncoding?: Encoding,
+ data: string | Buffer | ArrayBufferView,
+ inputEncoding?: Encoding,
+ outputEncoding: Encoding = getDefaultEncoding(),
): Buffer | string {
- notImplemented("crypto.Decipheriv.prototype.update");
+ // TODO(kt3k): throw ERR_INVALID_ARG_TYPE if data is not string, Buffer, or ArrayBufferView
+ if (typeof data === "string" && typeof inputEncoding === "string") {
+ this.#cache.add(Buffer.from(data, inputEncoding));
+ } else {
+ this.#cache.add(data);
+ }
+ const input = this.#cache.get();
+ let output;
+ if (input === null) {
+ output = Buffer.alloc(0);
+ } else {
+ output = new Buffer(input.length);
+ ops.op_node_decipheriv_decrypt(this.#context, input, output);
+ }
+ return outputEncoding === "buffer"
+ ? output
+ : output.toString(outputEncoding);
}
}