Skip to content

Commit

Permalink
Merge pull request #412 from PeculiarVentures/fix-pfx-pass-utf8
Browse files Browse the repository at this point in the history
Fix password transformation for characters with char codes greater than 255
  • Loading branch information
microshine authored Jul 15, 2024
2 parents 0e6e280 + 2dcf442 commit 6d49deb
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 19 deletions.
23 changes: 13 additions & 10 deletions examples/NodePKCS12Example/NodeEngineNodeSpecific.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 14 additions & 6 deletions src/CryptoEngine/CryptoEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
20 changes: 17 additions & 3 deletions test/pkcs12SimpleExample.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down

0 comments on commit 6d49deb

Please sign in to comment.