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

System API for threshold key derivation (vetKD) #158

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

fspreiss
Copy link
Member

@fspreiss fspreiss commented Apr 20, 2023

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.)

@netlify
Copy link

netlify bot commented Apr 20, 2023

Deploy Preview for ic-interface-spec ready!

Name Link
🔨 Latest commit c3dc62d
🔍 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.

@github-actions
Copy link

github-actions bot commented Sep 4, 2023

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

@tokuryoo
Copy link

@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?

@fspreiss
Copy link
Member Author

@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.

@tokuryoo
Copy link

tokuryoo commented Sep 14, 2023

@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
Copy link

tokuryoo commented Sep 14, 2023

@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

@fspreiss
Copy link
Member Author

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.

@tokuryoo
Copy link

@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)

@fspreiss
Copy link
Member Author

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.

@tokuryoo
Copy link

@fspreiss
I see! Thank you very much.

@devvspaces
Copy link

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

@tokuryoo
Copy link

@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.

@fspreiss
Copy link
Member Author

@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.

@tokuryoo
Copy link

@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
Copy link

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

@vporton
Copy link

vporton commented May 13, 2024

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
Copy link

vporton commented May 13, 2024

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
Copy link

vporton commented May 13, 2024

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.

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

Successfully merging this pull request may close these issues.

5 participants