diff options
author | Yoshiya Hinosawa <stibium121@gmail.com> | 2023-03-18 21:51:28 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-18 21:51:28 +0900 |
commit | 5223f3d9b68921179db8cd6b00babd711d4f06ff (patch) | |
tree | bd0167da2bb488e31f79ee51dbcd0e67bcb527a7 /ext/node/polyfills/internal/crypto/cipher.ts | |
parent | 44553aa09ec2de5a59db17433fd601a9dc7bd624 (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.ts | 93 |
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); } } |