From 52823fc651d56e9ac35e164680b70e40a434f68d Mon Sep 17 00:00:00 2001 From: microshine Date: Mon, 15 Jul 2024 14:29:13 +0200 Subject: [PATCH 1/2] fix: support char codes greater than 255 in password transformation --- .../NodeEngineNodeSpecific.ts | 23 +++++++++++-------- src/CryptoEngine/CryptoEngine.ts | 20 +++++++++++----- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/examples/NodePKCS12Example/NodeEngineNodeSpecific.ts b/examples/NodePKCS12Example/NodeEngineNodeSpecific.ts index 5f2f8a766..1b3335a88 100644 --- a/examples/NodePKCS12Example/NodeEngineNodeSpecific.ts +++ b/examples/NodePKCS12Example/NodeEngineNodeSpecific.ts @@ -141,18 +141,21 @@ function makePKCS12B2Key( //#region Main algorithm making key //#region Transform password to UTF-8 like string - const passwordViewInitial = new Uint8Array(password); - - const passwordTransformed = new ArrayBuffer((password.byteLength * 2) + 2); - const passwordTransformedView = new Uint8Array(passwordTransformed); - - for (let i = 0; i < passwordViewInitial.length; i++) { - passwordTransformedView[i * 2] = 0x00; - passwordTransformedView[i * 2 + 1] = passwordViewInitial[i]; + const originalPassword = new Uint8Array(password); + let decodedPassword = new TextDecoder().decode(password); + const encodedPassword = new TextEncoder().encode(decodedPassword); + if (encodedPassword.some((byte, i) => byte !== originalPassword[i])) { + decodedPassword = String.fromCharCode(...originalPassword); } - passwordTransformedView[passwordTransformedView.length - 2] = 0x00; - passwordTransformedView[passwordTransformedView.length - 1] = 0x00; + // Transform the password into a byte array + const passwordTransformed = new Uint8Array(decodedPassword.length * 2 + 2); + const passwordDataView = new DataView(passwordTransformed.buffer); + for (let i = 0; i < decodedPassword.length; i++) { + passwordDataView.setUint16(i * 2, decodedPassword.charCodeAt(i), false); + } + // Add null-terminator + passwordDataView.setUint16(decodedPassword.length * 2, 0, false); password = passwordTransformed.slice(0); //#endregion diff --git a/src/CryptoEngine/CryptoEngine.ts b/src/CryptoEngine/CryptoEngine.ts index 53c8be812..d264bda05 100644 --- a/src/CryptoEngine/CryptoEngine.ts +++ b/src/CryptoEngine/CryptoEngine.ts @@ -52,14 +52,22 @@ async function makePKCS12B2Key(hashAlgorithm: string, keyLength: number, passwor throw new Error("Unsupported hashing algorithm"); } - // Transform the password into a null-terminated UCS-2 encoded string - const passwordViewInitial = new Uint8Array(password); - const passwordTransformed = new Uint8Array((password.byteLength * 2) + 2); - for (let i = 0; i < passwordViewInitial.length; i++) { - passwordTransformed[i * 2] = 0x00; - passwordTransformed[i * 2 + 1] = passwordViewInitial[i]; + const originalPassword = new Uint8Array(password); + let decodedPassword = new TextDecoder().decode(password); + const encodedPassword = new TextEncoder().encode(decodedPassword); + if (encodedPassword.some((byte, i) => byte !== originalPassword[i])) { + decodedPassword = String.fromCharCode(...originalPassword); } + // Transform the password into a byte array + const passwordTransformed = new Uint8Array(decodedPassword.length * 2 + 2); + const passwordView = new DataView(passwordTransformed.buffer); + for (let i = 0; i < decodedPassword.length; i++) { + passwordView.setUint16(i * 2, decodedPassword.charCodeAt(i), false); + } + // Add null-terminator + passwordView.setUint16(decodedPassword.length * 2, 0, false); + // Create a filled array D with the value 3 (ID for MACing) const D = new Uint8Array(v).fill(3); From 2dcf442de70f5e29a96bc68d3949f2508a4b3d7a Mon Sep 17 00:00:00 2001 From: microshine Date: Mon, 15 Jul 2024 14:29:52 +0200 Subject: [PATCH 2/2] test: improve testing for PKCS12 --- test/pkcs12SimpleExample.spec.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/pkcs12SimpleExample.spec.ts b/test/pkcs12SimpleExample.spec.ts index 941da0ffc..1af4b02f7 100644 --- a/test/pkcs12SimpleExample.spec.ts +++ b/test/pkcs12SimpleExample.spec.ts @@ -46,9 +46,23 @@ context("PKCS#12 Simple Example", () => { await example.certificatePrivacy(password); }); - it("Making OpenSSL-like PKCS#12 Data", async () => { - const pfx = await example.openSSLLike(password); - await example.parsePKCS12(pfx, password); + context("Making OpenSSL-like PKCS#12 Data", () => { + it("ASCII", async () => { + const pfx = await example.openSSLLike(password); + await example.parsePKCS12(pfx, password); + }); + + it("UTF-8", async () => { + const password = "пароль"; + const pfx = await example.openSSLLike(password); + await example.parsePKCS12(pfx, password); + }); + + it("Binary", async () => { + const password = "\x04\xff\x20\x21"; // decode/encode -> [ 4, 239, 191, 189, 32, 33 ] + const pfx = await example.openSSLLike(password); + await example.parsePKCS12(pfx, password); + }); }); it("Speed test for stampDataWithPassword", async () => {