Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use AES-WRAP in Electron apps #40

Open
gnarea opened this issue Nov 17, 2021 · 12 comments
Open

Can't use AES-WRAP in Electron apps #40

gnarea opened this issue Nov 17, 2021 · 12 comments
Assignees

Comments

@gnarea
Copy link

gnarea commented Nov 17, 2021

You'd get an error like this:

          Error: Unknown cipher
              at Cipheriv.createCipherBase (node:internal/crypto/cipher:116:19)
              at Cipheriv.createCipherWithIV (node:internal/crypto/cipher:135:3)
              at new Cipheriv (node:internal/crypto/cipher:243:3)
              at Object.createCipheriv (node:crypto:138:10)
              at Function.encryptAesKW (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/@peculiar/webcrypto/build/webcrypto.js:260:51)
              at Function.encrypt (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/@peculiar/webcrypto/build/webcrypto.js:182:29)
              at AesKwProvider.onEncrypt (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/@peculiar/webcrypto/build/webcrypto.js:506:26)
              at AesKwProvider.encrypt (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/webcrypto-core/build/webcrypto-core.js:184:31)
              at SubtleCrypto.wrapKey (/home/gus/repos/awala-gateway-desktop/packages/ui/app/node_modules/daemon/node_modules/webcrypto-core/build/webcrypto-core.js:1393:25)
              at async Promise.all (index 0)

This is due to electron/electron#31874

This means that you can't use PKI.js with EnvelopedData and DH, for example.

I don't think there's anything to change in this repo, but I wanted to create this issue to save some time to anyone that comes across this issue. Feel free to close it.

@gnarea
Copy link
Author

gnarea commented Nov 18, 2021

I'm not having much luck with the Electron or BoringSSL teams. If I can't convince them to add/enable AES-KW, would you guys be open to a PR that uses a pure JS implementation of AES-KW when crypto.getCiphers() doesn't include this AES mode?

This would require adding a dependency on @stablelib/aes-kw or aes-kw, or forking one of them to embed the implementation in @peculiar/webcrypto.

@microshine
Copy link
Collaborator

@gnarea I think the simplest way is creating and registering the new AES-KW provider with extra dependency for Electron.

I don't think it's a good solution to import such dependencies to the package if they are required for Electron runtime only

import { Crypto } from "@peculiar/webcrypto";
import * as core from "webcrypto-core";

class AesKwProvider extends core.AesKwProvider {

  async onGenerateKey(algorithm, extractable, keyUsages) {
    throw new Error("AES-KW: generateKey: Method not implemented");
  }

  async onExportKey(format, key) {
    throw new Error("Method not implemented");
  }

  async onImportKey(format, keyData, algorithm, extractable, keyUsages) {
    throw new Error("Method not implemented");
  }

  async onEncrypt(algorithm, key, data) {
    throw new Error("Method not implemented");
  }

  async onDecrypt(algorithm, key, data) {
    throw new Error("Method not implemented");
  }
}

// Register the new AES-KW provider
const crypto = new Crypto();
crypto.subtle.providers.set(new AesKwProvider())

await crypto.subtle.generateKey({ name: "AES-KW", length: 128 }, false, ["wrapKey", "unwrapKey"]);

// Error: AES-KW: generateKey: Method not implemented

But SubtleCrypto.providers is protected field and TypeScript doesn't show it. Looks like we need to make it public.

@gnarea
Copy link
Author

gnarea commented Nov 18, 2021

@microshine, thanks, that'd work for me. We could even just extend the AesKwProvider class from this project and only override onEncrypt()/onDecrypt(), right?

I can put a PR together to make SubtleCrypto.providers public if you're happy with that.

@microshine
Copy link
Collaborator

We could even just extend the AesKwProvider class from this project and only override onEncrypt()/onDecrypt(), right?

It's impossible. @peculiar/webcrypto doesn't export any providers.

I can put a PR together to make SubtleCrypto.providers public if you're happy with that

it would be nice

@gnarea
Copy link
Author

gnarea commented Nov 18, 2021

It's impossible. @peculiar/webcrypto doesn't export any providers.

True, I didn't realise that class wasn't exported. Would you consider exporting it? Otherwise, I'd have to duplicate most of the code in mechs/aes/aes_kw.ts plus other files like mechs/aes/crypto.ts, etc.

@microshine
Copy link
Collaborator

@peculiar/webcrypto uses internal getCryptoKey/setCryptoKey functions which allow to protect private key blobs of NodeJS keys. Without those blobs, you can't export NodeJS keys to the extra crypto module. This is why I think provider exporting is useless

@gnarea
Copy link
Author

gnarea commented Nov 18, 2021

Sorry, I don't understand why getCryptoKey/setCryptoKey would be problematic with this approach or in Electron. From my testing on Electron, the current AesKwProvider from @peculiar/webcrypto can generate, import and export keys without issues. I also just looked at the code and can't think of a reason why getCryptoKey/setCryptoKey wouldn't work on Electron.

@gnarea
Copy link
Author

gnarea commented Nov 18, 2021

Actually, I don't think I'd need AesKwProvider to be exported anyway because I could get the original implementation with something like SubtleCrypto.providers.get('aes-kw').

Then I could just proxy onGenerateKey()/onExportKey()/onImportKey() from my own AesKwProvider, so I'd just override onEncrypt() and onDecrypt().

@microshine
Copy link
Collaborator

Here are two representations of the one key.

CryptoKey doesn't keep a private blob of NodeJS secret key.
image

getCryptoKey function allows getting AesCryptoKey with the private NodeJS secret key blob which you can use in AesCrypto class. See AesCryptoKey.data field

image

Does it make sense?

@microshine
Copy link
Collaborator

Here is the package structure
image

@gnarea
Copy link
Author

gnarea commented Nov 18, 2021

I see. Thanks @microshine! That's really helpful. I'll get back to this tomorrow or Monday, and I'll make the PR then.

@gnarea
Copy link
Author

gnarea commented Nov 22, 2021

I don't think it's a good solution to import such dependencies to the package if they are required for Electron runtime only

Coming back to this, what about a PR that only used the pure JS implementation of AES-KW if Node.js doesn't support this cipher?

This is what I did in my project:

export class AwalaCrypto extends Crypto {
  constructor() {
    super();

    const doesNodejsSupportAesKw = getCiphers().includes('id-aes128-wrap');
    if (!doesNodejsSupportAesKw) {
      // This must be running on Electron, so let's use a pure JavaScript implementation of AES-KW:
      // https://github.com/relaycorp/relaynet-core-js/issues/367
      const providers = (this.subtle as SubtleCrypto).providers;
      const nodejsAesKwProvider = providers.get('AES-KW') as AesKwProvider;
      providers.set(new AwalaAesKwProvider(nodejsAesKwProvider));
    }
  }
}

And here's AwalaAesKwProvider.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants