E2EE между клиентом и сервером с помощью Nodejs и Webcrypto API браузера через ECDH P-256

End2End encryption IOException: ошибка синтаксического анализа algid, а не последовательность

Я создал проект и написал эти коды на Backend-стороне:

      export function generateDHKeys(foreignPublicKeyB64) {
  try {
    const ecdh = crypto.createECDH('prime256v1');
    ecdh.generateKeys();

    const publicKeyB64 = ecdh.getPublicKey('base64');
    const privateKeyB64 = ecdh.getPrivateKey('base64');
    const webcryptoRawB64 = Buffer.from(foreignPublicKeyB64, 'base64')
      .slice(-65)
      .toString('base64'); // the last 65 bytes

    const sharedSecretB64 = ecdh.computeSecret(
      foreignPublicKeyB64,
      'base64',
      'base64'
    );
    const sharedSecretHashB64 = crypto
      .createHash('sha256')
      .update(sharedSecretB64, 'base64')
      .digest('base64');

    return {
      publicKeyB64,
      privateKeyB64,
      sharedSecretB64,
      sharedSecretHashB64,
    };
  } catch (e) {
    throw {
      error: { code: e.code, message: e.message },
    };
  }
}

И я шифрую все сообщения, как показано ниже:

      export function encrypt(privateKey: string, message: string) {
  const cipher = crypto.createCipheriv(
    'aes-256-gcm',
    Buffer.from(privateKey, 'base64'),
    getRandomIV()
  );

  let encrypted = cipher.update(message, 'utf8', 'base64');
  encrypted += cipher.final('base64');

  return Buffer.from(encrypted, 'base64').toString('base64');
}

export function getRandomIV() {
  return crypto.randomBytes(12);
}

Пример шифрования:

      // I have `sharedSecretHashB64` by the User's deviceId when they received a publicKey from the Server by their `publicKey` before.
const { sharedSecretHashB64 } = JSON.parse(this.db.get(deviceId));
return encrypt(sharedSecretHashB64, JSON.stringify([name: "Test Name", family: "Test Family"]));

На стороне клиента: 1.

      export const generateKeyPair = async (): Promise<CryptoKeyPair> => {
    return window.crypto.subtle.generateKey(
        {
            name: "ECDH",
            namedCurve: "P-256",
        },
        true,
        ["deriveKey", "deriveBits"],
    );
};
      export const convertKeyToAsn1 = async (key: CryptoKey): Promise<string> => {
    const DER = await window.crypto.subtle.exportKey("spki", key);

    return arrayBufferToBase64(DER);
};

Использование:

      const keyPair: CryptoKeyPair = await generateKeyPair();
const clientPublicKey: string = await convertKeyToAsn1(keyPair.publicKey!);

Отправьте publicKey серверу, что клиентский PublicKey выглядит примерно так:

      MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZQeF2h28zD5Zdo226gJmDbchD9fa6hNUAvhwcO9ogyAKbsCMcWXGX26+wWE+f5oNoY5LGhkBeC/1SzQLRId0Tw==

И publicKey сервера в ответ:

      BGDiM1k24nlz7FuEfOXpQoD6bAdFi52C6chxDxN6C5GG8Puo9becrNq/hICnu1JY7tj3uLUIr5Gr+TpFAx7hNNI=

Теперь я создаю свой собственный ключ AES:

      export async function importServerPublicKey(publicKey: string) {
  const publicKeyInUint8Array = new Uint8Array(base64ToArrayBuffer(publicKey));

  return window.crypto.subtle.importKey(
    'raw',
    publicKeyInUint8Array,
    {
      name: 'ECDH',
      namedCurve,
    },
    true,
    []
  );
}

export async function ECDHDeriveKey(
  serverPublicKey: CryptoKey,
  privateKey: CryptoKey
) {
  const sharedSecret = await window.crypto.subtle.deriveBits(
    {
      name: 'ECDH',
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      namedCurve,
      public: serverPublicKey,
    },
    privateKey,
    256
  );

  const aesSecret = await window.crypto.subtle.digest('SHA-256', sharedSecret);
  return window.crypto.subtle.importKey('raw', aesSecret, 'AES-GCM', true, [
    'encrypt',
    'decrypt',
  ]);
}

export async function getAESKey(
  serverPublicKey: string,
  privateKey: CryptoKey
) {
  const convertServerPublicKeyToCryptoKey = await importServerPublicKey(
    serverPublicKey
  );

  return ECDHDeriveKey(convertServerPublicKeyToCryptoKey, privateKey);
}

Моя первая расшифровка:

      const aesKey = await getAESKey(
   serverResponse.data.publicKey,
   keyPair.privateKey!
);

const decrypted = await decrypt(aesKey, serverResponse);

Я получил DOMException ошибка здесь, и я не знаю почему?

Заранее спасибо за помощь, я очень это ценю.

0 ответов

Другие вопросы по тегам