shift7-ch / katta-server

Zero-config storage management and zero-knowledge key management for teams and organizations.
GNU Affero General Public License v3.0
0 stars 0 forks source link

client-side user key generation fails in hub #27

Open chenkins opened 1 year ago

chenkins commented 1 year ago

Summary

client-side user key generation fails when user keys decrypted in hub.

Reproducibility

With historic key pair, not with newly generated key pairs any more.

Relevant Log Output

private key generated with P384KeyPair.generate() in Java causes

Unexpected Error: Data provided to an operation does not meet requirements

in UserKeys.recover in hub in line

 const privateKey = await crypto.subtle.importKey('pkcs8', decodedPrivateKey, UserKeys.KEY_DESIGNATION, false, UserKeys.KEY_USAGES);
overheadhunter commented 1 year ago

Interesting. I noticed that the private keys exported by JavaScript are longer than the ones exported by Java.

When decoding the ASN.1, there is additional information, maybe this is required...

I will have a closer look at this tomorrow, so we can be sure keys can be used cross-boundaries.

overheadhunter commented 1 year ago

I just tried this in jshell (Temurin 20):

import java.security.*;
import import java.security.spec.*;
var keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(new ECGenParameterSpec("secps384r1"));
var keyPair = keyGen.generateKeyPair();
Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded())

and this in my browser's console (Brave 1.52.130 Chromium: 114.0.5735.198):

let pemEncoded = atob('ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDCC6lPePPdsnq2gMH6A+kHb2P9OBgoIrNm2wRLXHmTHJWBeg/EPoeBIWCpOgwFU9Hc=')
let keyData = new Uint8Array(pemEncoded.length)
for (let i=0; i<keyData.length; i++) keyData[i] = pemEncoded.charCodeAt(i)
let privateKey = await crypto.subtle.importKey('pkcs8', keyData, {name: 'ECDH', namedCurve: 'P-384'}, true, ['deriveBits'])
await crypto.subtle.exportKey('jwk', privateKey)

And it does work. Nevertheless I'll add a regression test to the .ts project where we import both a pkcs8-encoded private key as well as an spki-encoded public key. But for now I must assume something else is broken.

Can you share the base64-encoded keys that you used for testing?

chenkins commented 1 year ago

@overheadhunter

Update 1: I cannot reproduce currently: when I now generate new user keys P384KeyPair.generate(); in Java, it works (i.e. I can go the hub and add the browser as device with the setup code), and this used to fail consistently (around mid-June).

Update 2: The strange thing is that this always worked in crypto.spec.ts but not in the browser (I tried both with Firefox and Safari), so I expected the following test to fail, but it did not:

  describe('UserKeys recover', () => {
    it('x = decrypt(encrypt(x, pass), pass)', async () => {
             const encodedPublicKey = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEmAkfc+lCMuKBkq3pq/eDuhZZb1z2aS/98EM2DLfMBis0QLoXCG0EE9mgnIRYh0yn+oII0vK7FnJGjDdhhfVlfCXgLkg7P52zRt+X6eVWa8UayFkT3qMLlRYNWDAkyaxJ"
             const encryptedPrivateKey= "eyJwMnMiOiJicVhoMGJNeS1QS3FmTFBoYW5DNmZ3IiwicDJjIjoxMDAwMDAwLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUEJFUzItSFM1MTIrQTI1NktXIn0.voAnfslMyy4Kydt8yozQLNSNbHCvuzsOLOwx-RFnLaZB1Ft6RFI3Rw.T0HWPxw9ZOyS8UzE.8YdWEf5buapJle9Ji1wYxGDVSxlVl-i6LKEYaRY2HmZPwj9JfaVrFAXrZd_apD_MUTtcfbjjrKcqJmn7ua01ptWCLko3Vy90QUu2xMgzyhS9_aJKAXn23A9VxKPVqTRP3lqzFJn1AYRqc2XiwzJ2pqNg61QSnQ.mfwMD4dsSdQ81BOkHMs9xw"
             const setupCode= "blabla"

            const userKeys = await UserKeys.recover(encodedPublicKey,encryptedPrivateKey,setupCode)
            console.log(await userKeys.encodedPublicKey())
    });

Update-3: I can reproduce the error in the hub/browser with the above key pair:

import static ch.iterate.hub.model.UserKeyJWE.*;

...
            userKeys = userKeysRecover(
                    "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEmAkfc+lCMuKBkq3pq/eDuhZZb1z2aS/98EM2DLfMBis0QLoXCG0EE9mgnIRYh0yn+oII0vK7FnJGjDdhhfVlfCXgLkg7P52zRt+X6eVWa8UayFkT3qMLlRYNWDAkyaxJ",
                    "eyJwMnMiOiJicVhoMGJNeS1QS3FmTFBoYW5DNmZ3IiwicDJjIjoxMDAwMDAwLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUEJFUzItSFM1MTIrQTI1NktXIn0.voAnfslMyy4Kydt8yozQLNSNbHCvuzsOLOwx-RFnLaZB1Ft6RFI3Rw.T0HWPxw9ZOyS8UzE.8YdWEf5buapJle9Ji1wYxGDVSxlVl-i6LKEYaRY2HmZPwj9JfaVrFAXrZd_apD_MUTtcfbjjrKcqJmn7ua01ptWCLko3Vy90QUu2xMgzyhS9_aJKAXn23A9VxKPVqTRP3lqzFJn1AYRqc2XiwzJ2pqNg61QSnQ.mfwMD4dsSdQ81BOkHMs9xw",
                    "blabla");

or base-64 only:

2023-07-21 15:51:20,154 [main] INFO  ch.iterate.hub.workflows.FirstLoginDeviceSetup - pub=MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEmAkfc+lCMuKBkq3pq/eDuhZZb1z2aS/98EM2DLfMBis0QLoXCG0EE9mgnIRYh0yn+oII0vK7FnJGjDdhhfVlfCXgLkg7P52zRt+X6eVWa8UayFkT3qMLlRYNWDAkyaxJ
2023-07-21 15:51:20,154 [main] INFO  ch.iterate.hub.workflows.FirstLoginDeviceSetup - priv=MFcCAQAwEAYHKoZIzj0CAQYFK4EEACIEQDA+AgEBBDAxcuEdOGYwpL/8e8cNY0Fm6VyykwyD+tnQnHY7jyGsuclKSwWNAlwsggkczz6LJtegBwYFK4EEACI=

When I then go to the hub, user key recovery fails in the browser:

image image
Recovering user key failed. DOMException: Data provided to an operation does not meet requirements
    recover crypto.ts:340
    recoverUserKey SetupUserKey.vue:249
    _sfc_render/_cache[8]< SetupUserKey.vue:101
    node_modules chunk-CMJ6ZCLF.js:8122
    callWithErrorHandling runtime-core.esm-bundler.js:173
    callWithAsyncErrorHandling runtime-core.esm-bundler.js:182
    invoker runtime-dom.esm-bundler.js:345