Skip to content

Conversation

Ayrx
Copy link
Contributor

@Ayrx Ayrx commented Aug 27, 2016

Definitely not ready for reviews yet!

def derive_scrypt(self, key_material, salt, length, N, r, p):
for b in self._filtered_backends(ScryptBackend):
return b.derive_scrypt(key_material, salt, length, N, r, p)
Raise UnsupportedAlgorithm("This backend does not support scrypt.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've got yourself a SyntaxError here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. :)

@reaperhulk reaperhulk mentioned this pull request Aug 27, 2016
5 tasks
@alex alex added this to the Sixteenth Release milestone Aug 27, 2016
@alex
Copy link
Member

alex commented Aug 27, 2016

I think you can skip the scrypt_supported, and instead just conditionally register the interface.

@Ayrx
Copy link
Contributor Author

Ayrx commented Aug 27, 2016

@alex Hmm, fair idea. I'll give that a shot.

@Ayrx
Copy link
Contributor Author

Ayrx commented Aug 28, 2016

@reaperhulk, @alex I need some API advice on this.

So, EVP_PBE_scrypt has a parameter uint64_t maxmem which defines the maximum memory that the function can use. When this parameter is set to 0, which I have currently opted to do in this PR, it defaults to the value of SCRYPT_MAX_MEM. When this isn't configured at build time, it defaults to (1024 * 1024 * 32) (32MB). This value is too small to have one of the test vectors pass. (Here is the link to the part of the source code.)

What do you think we should pass in to maxmem to ensure the most consistent experience overall? I don't think this should be exposed as part of the user facing API as it isn't defined in the specification and it seems like a OpenSSL specific thing (libscrypt doesn't have it for example...).

@reaperhulk
Copy link
Member

It looks like if SCRYPT_MAX_MEM is set to zero during compile then it defines it to ((size_t)-1)/2. How about setting it to that by default (to be conservative we can use a 32-bit size_t)?

@Ayrx
Copy link
Contributor Author

Ayrx commented Aug 28, 2016

@reaperhulk What I don't like about that is that it breaks expectations if the user compiles OpenSSL with that particular option enabled.

After some hours of deliberation, my thoughts will be to handle that error gracefully (which we'd need to do anyway), and have our CI compile OpenSSL with SCRYPT_MAX_MEM = 0 which sets it to ((size_t)-1). Thoughts?


# If the backend has support for Scrypt, dynamically register the backend and
# implement the interface.
def _derive_scrypt(self, key_material, salt, length, n, r, p):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should just be on the class normally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this break if the user uses the OpenSSL backend directly instead of going through default_backend()?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because https://github.com/pyca/cryptography/pull/3117/files#diff-2b076058f22fe576413155fbf8ebafbdR19 will catch it if ScryptBackend is not registered so even though the method is present it won't be called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

D'oh. Right. :)

@reaperhulk
Copy link
Member

Users are going to use whatever the default of their distro is in 99.9% of cases. If that number is low enough to cause failures when setting scrypt variables that's problematic...and 32MB is not a particularly huge number.

We definitely should handle the error gracefully, but I'm 👎 on anything that requires a custom compile flag to make our tests pass.

@Ayrx
Copy link
Contributor Author

Ayrx commented Aug 28, 2016

On the contrary I'd say that in practice almost no one is going to be using such high memory settings in production because that is 32MB every time you derive a key with Scrypt and very little systems can support that with any kind of practical load.

@reaperhulk
Copy link
Member

On a system with 64GB of RAM that's 1/2000th of available memory, and 64GB is not hard to come by. That said, maybe you can convince me that "large enough to pass the test vectors" is a good starting point and then we can change it in the future if users complain.

@alex
Copy link
Member

alex commented Aug 28, 2016

Ultimately ram usage is controlled by the 3 parameters scrypt takes, so if people want it to use less RAM they should change those. I have no problem setting max memory to sys.maxsize

# implement the interface.
def _derive_scrypt(self, key_material, salt, length, n, r, p):
buf = self._ffi.new("unsigned char[]", length)
self._lib.EVP_PBE_scrypt(key_material, len(key_material), salt,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to check the return value here.

@alex
Copy link
Member

alex commented Aug 28, 2016

(Will also need docs and a changelog entry)

@reaperhulk
Copy link
Member

Looks like there's a small pep8 issue to clear up too :)

from tests.utils import load_nist_vectors, load_vectors_from_file

vectors = load_vectors_from_file(
"KDF/scrypt.txt", load_nist_vectors)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be os.path.join("KDF", "scrypt.txt")

@alex
Copy link
Member

alex commented Aug 29, 2016

register_interface_if merged

:param int r: Block size parameter.
:param int p: Parallelization parameter.
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.ScryptBackend`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't documented, that's why the tests are failing.

@Ayrx
Copy link
Contributor Author

Ayrx commented Aug 30, 2016

Working on a better description for N, r and p now. Will push it up when I'm done.

@Ayrx Ayrx changed the title [WIP] Scrypt Implementation Scrypt Implementation Aug 30, 2016
@Ayrx
Copy link
Contributor Author

Ayrx commented Aug 30, 2016

Alright, I hope that explanation makes sense to people as much as it does in my head. Suggestions welcomed. :)

@Ayrx
Copy link
Contributor Author

Ayrx commented Sep 1, 2016

@alex @reaperhulk ping

.. _`key stretching`: https://en.wikipedia.org/wiki/Key_stretching
.. _`HKDF`: https://en.wikipedia.org/wiki/HKDF
.. _`HKDF paper`: https://eprint.iacr.org/2010/264
.. _`RFC 7914`: https://tools.ietf.org/html/rfc7914
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link is not required now that you're using the :rfc: setup.

@reaperhulk
Copy link
Member

Time for one quick question in ignorance: We have an AlreadyFinalized for our other KDFs that prevents calling derive more than once. Should we do that here?

@Ayrx
Copy link
Contributor Author

Ayrx commented Sep 1, 2016

I think it should for consistency sake. Added.

@reaperhulk
Copy link
Member

Anybody remember why we added AlreadyFinalized as an exception?

@alex
Copy link
Member

alex commented Sep 1, 2016

Because salt is in the constructor and we don't want to make it easy to
reuse a salt.

On Thu, Sep 1, 2016 at 8:39 AM, Paul Kehrer notifications@github.com
wrote:

Anybody remember why we added AlreadyFinalized as an exception?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#3117 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAADBPHxGOaIYGMS9KENuvDn5GMHXgI9ks5qlsd-gaJpZM4JuswS
.

"I disapprove of what you say, but I will defend to the death your right to
say it." -- Evelyn Beatrice Hall (summarizing Voltaire)
"The people's good is the highest law." -- Cicero
GPG Key fingerprint: D1B3 ADC0 E023 8CA6

@reaperhulk reaperhulk merged commit d8a27df into pyca:master Sep 1, 2016
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 24, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants