Skip to content
This repository has been archived by the owner on Apr 17, 2024. It is now read-only.

Storing keyset on disk encrypted with password #347

Closed
Stekeblad opened this issue Apr 10, 2020 · 6 comments
Closed

Storing keyset on disk encrypted with password #347

Stekeblad opened this issue Apr 10, 2020 · 6 comments

Comments

@Stekeblad
Copy link

From "Tink for Java HOW-TO":

Storing cleartext keysets on disk is not recommended. Tink supports encrypting keysets with master keys stored in remote key management systems.

Is there a way to not save a key in cleartext that does not depend on a on a remote keyserver or another key (that needs to be saved in cleartext or depend on a remote keyserver)?

With GnuPG you can set a password on the private key when its generated and you need to enter it every time you need to use it, can something similar be done with Tink? I do not want to write the private key to disk in cleartext and I do not want to configure and depend on a keyserver somewhere.

I have looked at Tink for Java HOW-TO and the Tinkey documentation but I can only see cleartext and remote keyserver examples.

@thaidn
Copy link
Contributor

thaidn commented Apr 14, 2020

Hi there,

If you use Android, you can store the keys wrapped with a master key in Android. The master key is just an alias, doesn't actually contain any key material.

If you want something equivalent to GnuPG, I guess you'd have to develop it yourself atm. You take the password, scrypt/argon2 it, and use it as a key for AesGcm which in turn is use to encrypt the keyset using KeysetHandle.write().

@thaidn
Copy link
Contributor

thaidn commented Apr 14, 2020

Please reopen this if you want to discuss more. Thanks!

@thaidn thaidn closed this as completed Apr 14, 2020
@Stekeblad
Copy link
Author

Hi and thank you for your pointers on where to start, now I had some time to think over and experiment with this.

I am not targeting Android with my project. I have been experimenting but I can not see how to go from the password to some secret hash or code that can be used to write the private key and then read it back. Below is one of my attempts:

// create new keys
Argon2 argon2 = Argon2Factory.create();
String argonHash = argon2.hash(15, 65536, 1, askForPassword().toCharArray());
AesGcmJce aesKey = new AesGcmJce(argonHash);
KeysetHandle privateKeyset = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256);
File privateKeyFile = new File(Paths.get("key-" + args[1]).toUri()); // name/location of the new key
privateKeyset.write(JsonKeysetWriter.withFile(privateKeyFile), aesKey);

First the argon hash is over 700 bits and AesGcmJce expects 128 or 256 bits. I could just take the last 256 bits of the digest value but argon2 adds a salt so one password gives new hash values every time. Salt is something good so its the wrong solution to try to work around it.

That means I must save the hash and then use argon-verify to check the password. If I save the hash I can not use anything in the hash to access the key because then someone can just check the code and use the right section of the saved hash without needing the password.

If I pass the password directly to AesGcmJce then it needs to be 16 or 32 characters long (128/256 bits), but then argon does not do anything required. I could also do the old SHA256 on the password so it does not need to have a specific length and plain SHA256 does not add a salt so I can run it again to get the same result and read the key back, but the entire purpose of argon is a more secure hash and not use SHA...

The AesGcm documentation that @thaidn linked shows encrypt/decrypt methods that can take an additional data argument of any length but I have the same problem there, what to input ...And then that key needs to be saved somewhere (or regenerated?) first before using it to encrypt/decrypt anything.

@thaidn
Copy link
Contributor

thaidn commented May 20, 2020

First the argon hash is over 700 bits and AesGcmJce expects 128 or 256 bits. I could just take the last 256 bits of the digest value but argon2 adds a salt so one password gives new hash values every time. Salt is something good so its the wrong solution to try to work around it.

I guess you'd have to use an Argon2 library that allows you to pick the salt yourself. You then store the salt and can recompute the hash from the password.

The AesGcm documentation that @thaidn linked shows encrypt/decrypt methods that can take an additional data argument of any length but I have the same problem there, what to input ...And then that key needs to be saved somewhere (or regenerated?) first before using it to encrypt/decrypt anything.

KeysetHandle.write(keysetWriter, aead) currently doesn't use this associated data field.

@Stekeblad
Copy link
Author

I guess you'd have to use an Argon2 library that allows you to pick the salt yourself.

Saving the salt... An easy answer, yet I could not figure it out my self! That should be the secure way to do it. The library I found do allow me to set the salt manually.

KeysetHandle.write(keysetWriter, aead) currently doesn't use this associated data field.

One of my thoughts, then trying to find a solution, was around calling aeadKey.encrypt(signingKey, someAssosiatedData); instead of the reverse, passing the aead-key to a keysetWriter for the signingKey.

A first version that allows creating password-protected keys and using them to create/verify signatures is now up on my GitHub https:/Stekeblad/Password-based-TinkTool.

Thank you thaidn for your help!

@thaidn thaidn reopened this May 27, 2020
@thaidn thaidn closed this as completed May 27, 2020
@thaidn
Copy link
Contributor

thaidn commented May 27, 2020

Glad that it works for you. I briefly skimmed https:/Stekeblad/Password-based-TinkTool and it looks good to me.

Note that users usually pick very weak passwords. Argon helps, but doesn't completely stop determined adversary from cracking most passwords. I suggest adding a warning or something about that.

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

No branches or pull requests

2 participants