interface-spec icon indicating copy to clipboard operation
interface-spec copied to clipboard

System API for threshold key derivation (vetKD)

Open fspreiss opened this issue 1 year ago • 18 comments

Proposes two new system APIs for the prospective threshold key derivation (vetKD) feature in the management canister.

Notes

  • The API is designed so that it allows for implementing the scheme referred to as An aggregatable vetBLS scheme (2) in the related talk at the Real World Crypto Symposium (RWC) 2023.
  • The APIs are designed to be similar to the ones for threshold ECDSA.
  • Information regarding usage of vetKD keys is not included in the interface spec on purpose. The idea is that the relevant information will later be provided in the Internet Computer Developer Docs.

Alternatives considered

We considered the following alternative API, where one would have two sets of API pairs: one pair for threshold key derivation, and a second one for threshold BLS signatures.

  // Threshold key derivation
  vetkd_public_key : (record {
    canister_id : opt canister_id;
    key_id : record { curve : vetkd_curve; name : text };
  }) -> (record { public_key : blob; });
  vetkd_encrypted_key : (record {
    derivation_id : blob;
    key_id : record { curve : vetkd_curve; name : text };
    encryption_public_key : blob;
  }) -> (record { encrypted_key : blob; });
  // Threshold BLS signature
  bls_public_key : (record {
    canister_id : opt canister_id;
    derivation_path : vec blob;
    key_id : record { curve : vetkd_curve; name : text };
  }) -> (record { public_key : blob; });
  sign_with_bls : (record {
    message : blob;
    derivation_path : vec blob;
    key_id : record { curve : vetkd_curve; name : text };
  }) -> (record { signature : blob; });

This alternative was discarded, however, because there is a concern that not all possible future use cases can be covered with this split API approach.

TODOs

  • Determine if we should specify further constraints on input data (e.g., max size of derivation_id, etc.)

fspreiss avatar Apr 20 '23 12:04 fspreiss

Deploy Preview for ic-interface-spec ready!

Name Link
Latest commit c3dc62d729b8228f118dc8b8c57d9c5a935f98d8
Latest deploy log https://app.netlify.com/sites/ic-interface-spec/deploys/64c18914ad1a1e000819da11
Deploy Preview https://deploy-preview-158--ic-interface-spec.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

netlify[bot] avatar Apr 20 '23 12:04 netlify[bot]

🤖 Here's your preview: https://jfhyp-gaaaa-aaaak-qck6q-cai.icp0.io/docs

github-actions[bot] avatar Sep 04 '23 05:09 github-actions[bot]

@fspreiss I don't know where to ask this question, so I will ask it here. Does the vetkd_encrypted_key method lack an authentication feature for vetKD? Is a calling canister responsible for authentication? (Meaning, by a calling canister receiving the 'caller', it is considered authenticated.)

Can someone else forge the derivation_id for vetkd_encrypted_key and then invoke it?

tokuryoo avatar Sep 13 '23 07:09 tokuryoo

@tokuryoo, a canister can only get vetKeys for itself form the system API, that is, vetKeys are domain-separated by the canister that calls the system API. This means that derivation_ids cannot be forged so that one canister gets to the vetKeys of another canister.

In any case, it is important that a canister does authentication regarding the vetKeys it forwards to users, that is, a canister must only give users their own keys. This can be achieved, for example, by using the calling user as derivation_id. You can see an example of this here, where ic_cdk::caller() is provided by the system, so it cannot be forged either.

fspreiss avatar Sep 13 '23 08:09 fspreiss

@fspreiss Thank you for your reply. My understanding has improved. I believe that a malicious canister B could get the encrypted_ibe_decryption_key of canister A. Am I mistaken? CanisterA https://github.com/dfinity/examples/blob/master/motoko/vetkd/src/app_backend/Main.mo

CanisterB

     public shared func encrypted_ibe_decryption_key_for_caller(principal : Principal) : async Text { 
         let { encrypted_key } = await vetkd_system_api.vetkd_encrypted_key({
             derivation_id = Principal.toBlob(principal); // not caller
             public_key_derivation_path = Array.make(Text.encodeUtf8("ibe_encryption"));
             key_id = { curve = #bls12_381; name = "test_key_1" };
             encryption_public_key;
         });
         Hex.encode(Blob.toArray(encrypted_key));
     };

tokuryoo avatar Sep 14 '23 02:09 tokuryoo

@fspreiss I understand that you've implemented IBE, but why did you also choose to implement AES-GCM-256? Also, do you plan to write guidelines on which should be used in which cases? https://github.com/dfinity/examples/tree/master/motoko/vetkd

tokuryoo avatar Sep 14 '23 02:09 tokuryoo

I believe that a malicious canister B could get the encrypted_ibe_decryption_key of canister A. Am I mistaken?

@tokuryoo, this is not possible. Even if canisters A and B use the exact same derivation_id (and public_key_derivation_path and key_id) when calling vetkd_system_api.vetkd_encrypted_key, they will actually get different results, so they cannot see or steal each others keys.

This is because the system API is not using the derivation path directly for calculating the vetKey, but a combination of the calling canister's identity (for example, A or B) and the derivation path. (You can see the insecure implementation of the system API canister do that here.) This combination is what I meant with "domain separation" in my message above. You can think if it as follows: each vetKey requested from the system API is tied to the domain (meaning zone or realm) of the canister.

I understand that you've implemented IBE, but why did you also choose to implement AES-GCM-256?

The two are used for different use cases. If your use case requires a key for symmetric encryption, you can use AES-GCM-256. If your use case requires a key for asymmetric encryption, you can use identity-based encryption (IBE). So it really depends on what you need. We aimed to make the vetKD system API flexible enough to support all of these.

Also, do you plan to write guidelines on which should be used in which cases?

We recently recorded a workshop video where the concepts of vetKD are explained and a walk-through of all the currently available demos is provided. You might find this helpful. You find a link to the latter here, and there are also several useful links in the video's description, such as developer docs, crypto background, Real-World Crypto conference talk, etc. I hope this helps.

fspreiss avatar Sep 14 '23 09:09 fspreiss

@fspreiss Thank you very much for your thoughtful response. I learned a lot. Let me ask one last question. In vetKD, is it possible for one ciphertext to be decrypted by more than one person? (For example, multiple people sharing a file)

tokuryoo avatar Sep 15 '23 04:09 tokuryoo

In vetKD, is it possible for one ciphertext to be decrypted by more than one person? (For example, multiple people sharing a file)

@tokuryoo, yes, that's definitely possible. Because it is the canister deciding who can (and cannot) get access to a particular vetKey, the canister can decide to give out some key to multiple people. The file sharing you mentioned is one example scenario. Another example scenario is group chat, where a canister gives out the key to the group's messages to all members of the group.

fspreiss avatar Sep 15 '23 15:09 fspreiss

@fspreiss I see! Thank you very much.

tokuryoo avatar Sep 19 '23 04:09 tokuryoo

@fspreiss just watching the walk-through video you did now, the talks here make me understand domain separation and derivation ids better, thanks.

devvspaces avatar Sep 25 '23 05:09 devvspaces

@fspreiss I read "vetKeys: How a blockchain can keep many secrets" and have a question about page 8. https://iacr.org/submit/files/slides/2023/rwc/rwc2023/82/slides.pdf On this page, "K_Bob ← KeyDer(msk, “Bob”)" is written. I am worried that a node administrator might steal K_Bob. Is threshold key derivation secure as it generates 'ek' without creating K_id? I would like to ensure that it is secure.

tokuryoo avatar Oct 10 '23 08:10 tokuryoo

@tokuryoo, the slide 8 you are referring to (and also slide 7) is merely explaining the concept of an identity-based encryption (IBE) scheme, which typically relies on a central authority to derive keys. However, with the proposed vetKD primitive, on the Internet Computer, this central authority would be replaced with a set of nodes, where each node only has a share of the master secret. The latter is depicted in slide 9 and the ones following. Keys can only be derived if sufficiently many nodes agree to perform the key derivation. This means that even if one or even several node administrators up to a certain threshold would be malicious, then they still would not be able to derive (or "steal") keys.

Regarding how ek is calculated, for a high-level view, please see slide 11: as you can see, this requires eks_i, which requires msk_i, which is the master secret key share of node i. For the exact cryptographic details, please see the paper vetKeys: How a Blockchain Can Keep Many Secrets.

If you have not done this already, I suggest to watch Gregory's Real-World Crypto conference talk: there everything is explained really well.

Maybe you know this already, but there is also an active forum thread on threshold key derivation on the Internet Computer on the DFINITY forum here. Feel free to also ask questions there.

fspreiss avatar Oct 10 '23 12:10 fspreiss

@fspreiss Thank you for your reply. It is difficult for me and It will take some time for me to understand.

Regarding how ek is calculated, for a high-level view, please see slide 11

eks_i ← EKDer(msk_i, id, tpk) ek ← Combine({eks_i}) In the above, a node does not compute K_id and might not even be able to compute K_id. Are you aware of this? Should I ask in the forum?

tokuryoo avatar Oct 11 '23 07:10 tokuryoo

I have resolved it. There's no need to worry about it.

tokuryoo avatar Oct 26 '23 06:10 tokuryoo

It seems that vetKeys API has a deficiency:

Retrieving a secret key for later signing allows to produce multiple signatures with that secret key, all of which would be verified true by a signature checker. This allows a canister with hacked hardware to secretly produce multiple signatures (and use it for example to authenticate multiple different calls to OpenAI API instead of one requested by a user, to steal OpenAI tokens).

I propose to introduce additional API:

  vetkd_sign : (record {
    public_key_derivation_path : vec blob;
    derivation_id : blob;
    key_id : record { curve : vetkd_curve; name : text };
    encryption_public_key : blob;
    message: blob;
  }) -> (record { signature : blob; });

vporton avatar May 13 '24 03:05 vporton

vetkd_sign : (record { public_key_derivation_path : vec blob; derivation_id : blob; key_id : record { curve : vetkd_curve; name : text }; encryption_public_key : blob; message: blob; }) -> (record { signature : blob; });

Can also this be implemented?

  vetkd_encrypt : (record {
    public_key_derivation_path : vec blob;
    derivation_id : blob;
    key_id : record { curve : vetkd_curve; name : text };
    encryption_public_key : blob;
    message: blob;
  }) -> (record { encrypted : blob; });

Moreover, the above could be rectified to support both symmetric and asymmetric encryption, possibly.

vporton avatar May 13 '24 03:05 vporton

Moreover, if secret key API retrieval API is not removed (being replaced by my API), then hacked canister hardware can without user's allowance use the retrieved key (multiple times), so authenticating to an external service without user allowance.

vporton avatar May 13 '24 04:05 vporton