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

Auth Slates proposal #90

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

marekyggdrasil
Copy link

Initial draft of the auth-slates proposal

Initial draft of the auth-slates proposal
included a reference to the PR
@Anynomouss
Copy link

Anynomouss commented Jul 9, 2022

I like the concept of using the wallets keys for something more such as a digital identity.
key = H(seed || username || url) is a neat trick to not reveal the slatepack address.

I am not yet 100% convinced though about whether we need to use slatepacks here to interact with an exchange, but I can think of some advantages. For example, I am not sure if you planned to make the slatepacks encrypted for a specific service, but if you do encrypt them to the public-key/slate-pack address of the server/service. It would have the advantage of being armored, no user information or service information is leaked if intercepted.
Secondly, if you would start using this 'Digital Identity', you can also send encrypted messages or signed memo's to that server/service.

Maybe we should think here also about unifying signing for memo's, to signing with you digital ID's to messages, contracts etc.
Only drawback I could find is that the user needs to remember the user name, you could mention it in the drawback section. Not leaking the slate-pack address comes with a cost, a small cost, worth paying IMO. In general, I think you could consider expanding on this concept and elevating/expanding it to a digital identity, of which the 'Auth Slates' is the first step.

@marekyggdrasil
Copy link
Author

I like the concept of using the wallets keys for something more such as a digital identity. key = H(seed || username || url) is a neat trick to not reveal the slatepack address.

I am having some second thoughts about it. I am not sure if this won't make it possible to find wallet seed using preimage attacks. Commonly solution would be to add some cryptographic pepper as

key = H(seed || username || url || pepper)

where pepper has to be sufficiently random. But then to regain access to your account after database loss you also need to find same pepper so it complicates the recovery. Maybe an alternative would be double hashing

key = H(H(seed || username || url) || username || url)

but I am no cryptographer, not sure if that makes it sufficiently resistant to preimage attack. Perhaps someone more experience could comment / propose something.

I am not yet 100% convinced though about whether we need to use slatepacks here to interact with an exchange, but I can think of some advantages. For example, I am not sure if you planned to make the slatepacks encrypted for a specific service, but if you do encrypt them to the public-key/slate-pack address of the server/service. It would have the advantage of being armored, no user information or service information is leaked if intercepted. Secondly, if you would start using this 'Digital Identity', you can also send encrypted messages or signed memo's to that server/service.

Maybe we should think here also about unifying signing for memo's, to signing with you digital ID's to messages, contracts etc. Only drawback I could find is that the user needs to remember the user name, you could mention it in the drawback section. Not leaking the slate-pack address comes with a cost, a small cost, worth paying IMO. In general, I think you could consider expanding on this concept and elevating/expanding it to a digital identity, of which the 'Auth Slates' is the first step.

Very good suggestion. I think it is possible to achieve it while still having just one slatepack for login. The current login slatepack looks as follows

{
    "version_info": {
        "version": 1
    },
    "authentication": "login",
    "data": {
        "username": "picked-username",
        "url": "url-of-the-service",
        "timestamp": 1657270059,
        "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
    }
}

we could do it as follows

{
    "version_info": {
        "version": 1
    },
    "authentication": "login",
    "data": {
        "login-data": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "timestamp": 1657270059,
        "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
    }
}

In short, we replace two entries username and url with single entry named login-data. The login-data is encrypted string username+url padded to fixed length, the symmetric key to decrypt it is signing key + username. A potential man in the middle is capable to derive the signing key from the signature but does not know the username, the service however is supposed to have username associated to the signing key in their database.

I will implement changes shortly.

@marekyggdrasil
Copy link
Author

@Anynomouss I made some changes. I developed a way to have login slatepack shielded, but I did not do it for the registration slatepack. Reason for that is during the registration there is no shared secret in common, establishing one would require Diffie-Hellman key exchange which imposes an additional step in the protocol. I am not yet sure if it is worth it.

I think we should discuss if it is worth it to shield authentication slatepacks as the exposed data is public anyway. Unlike the transaction building, which can be performed via third party, authentication could be assumed to be always performed directly between the two parties. Any thoughts?

@Anynomouss
Copy link

Anynomouss commented Jul 10, 2022

I

am having some second thoughts about it. I am not sure if this won't make it possible to find wallet seed using preimage attacks. Commonly solution would be to add some cryptographic pepper as

This should not be an issue if you use hardened derivation to derive the key for a specific service.

I think we should discuss if it is worth it to shield authentication slatepacks as the exposed data is public anyway. Unlike the transaction building, which can be performed via third party, authentication could be assumed to be always performed directly between the two parties. Any thoughts?

I am also not sure if it is needed. If the service has a public key/slate pack-address, you can encrypt using the public key of the the service provider so only they can read. Since you provide in that initial slatepack message your own specific used hardened public key, the service provider can use this to encrypt his response to the user so only he can decrypt it. In the end it is the same as how encrypting a slatepack to a slate-pack-address/public key works, with only difference that you derived one with this specific.
key = H(H(seed || username || url) || username || url)

I am not exactly sure how to integrate that with hardened derivation, but I am sure it is possible. Probably by hashing the parent parent key opposed to using the parent key directly. I think that is what HMAC is fore. See here more information on hardened versus non hardened derivation.
https://ethereum.stackexchange.com/questions/41898/how-to-use-hardened-key-derivation-properly

@Anynomouss
Copy link

Anynomouss commented Jul 10, 2022

Now I think about it, hashing should just solve all problems. Just HMAC-SHA512(seed2|username| url), note that HMAC_SHA512 is by default used in most crypto wallets for hardened key derivation and uses double hashing, so you can never derive a parent key. So you do not need to call HMAC_SHA512 twice, since it already double hashes by default.

The upside of using HMAC-SHA512 is that the security and privacy it offers since you can never derive the same parent.
One downside of using the hardening is that it becomes impossible to proof that a child belongs to a parent public key. So you cannot prove that for example your account belongs to a certain slate-pack-address. Not a big issue, but worth noting.

@marekyggdrasil
Copy link
Author

@Anynomouss. currently I'm working on the extended key derivation for https://github.com/grinventions/mimblewimble-py and I think this can help improve this RFC a lot. Perhaps there is a way to derive the auth key using currently used and secure derivation path mechanisms. Thank you for your feedback and pls be patient I will respond as soon as I implement and understand the currently used mechanism.

@marekyggdrasil
Copy link
Author

marekyggdrasil commented Aug 24, 2022

Hey @Anynomouss, I am sorry for taking so long to respond. In the meantime I did implement the Mimblewimble slatepack address derivation and now I understand it pretty well so I can return to this RFC.

I like your suggestion to use HMAC-SHA512. How about a following protocol

  1. Derive the ED25519 seed that is used for the slatepack address
  2. Use that seed for HMAC-SHA512 as the key and for the message take username | url. Digest that and that is the ED25519 auth_slate_seed.
  3. From the auth_slate_seed get the public_key and signing_key.
  4. Produce another message m, either "I wish to be register to {url} as {username}" either "On {timestamp} I wish to login to {url} as {username}", depending if it is registration or login.
  5. Sign m using signing_key derived from the auth_slate_seed.

During both registration and verification the service will extract public_key from the signature.
I made an example implementation here https://github.com/marekyggdrasil/mimblewimble-py/blob/31ed970cb7ef936fe3a90f6bca999bb52586ecdc/mimblewimble/wallet.py#L132-L191

@Anynomouss
Copy link

Anynomouss commented Aug 31, 2022

Looks good to me. Also learned something new, I did not yet know ou could recover the public_key from a signature with ECDSA. Quite amazing when you think of it what you can achieve with simple wallet derivation and an extension of it like you suggested. Basically it is all you need to manage digital ID's in a secure and private manner.

I only looked briefly at the code, is the self.nonce = os.urandom(12) used for a random nonce when signing? Not so much into crypto right now, mostly deep into changing diapers right now. I am asking just to make sure that each time when a user signs a message there is a random nonce since otherwise a user signs the same message two times would allow an attacker to deduce the privatekey for their account.

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.

2 participants