-
Notifications
You must be signed in to change notification settings - Fork 52
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
PBKDF2 and BIP39 Support #109
Conversation
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Hey Jim, really fantastic work, thank you! 🚀 On first review the code and interface look great, and code/comment style is excellent! Did you consider turning Since your ultimate goal with this is to add BIP39 support, if you're willing, I'd love to see that in this PR too! That would let us confirm that the interface is exactly what we need + improve test coverage. |
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
U = hmacFunction(password, U); | ||
|
||
for (let k = 0; k < hmacByteLength; k++) { | ||
// @ts-expect-error-next-line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bitjson No idea how to get rid of this one.
Algo is almost verbatim https://github.com/browserify/pbkdf2/blob/master/lib/sync-browser.js with a few minor changes (e.g. Buffer to Uint8Array).
I'm wondering if Typescript is doing something funky because we're doing a bitwise op. If you have any ideas, please let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, looks like the error is just that U[k]
is possibly 'undefined'.
as k
isn't guaranteed to be in the range of Uint8Array U
. We're sure in this case, so you can make that line:
T[k] ^= U[k]!; // eslint-disable-line @typescript-eslint/no-non-null-assertion
(Breaking rules is fine in sensible places, the linting just forces us to be explicit and deliberate about it. 👍)
/* eslint-disable functional/no-let, functional/no-loop-statement, functional/no-expression-statement, no-bitwise, no-plusplus */ | ||
const { password, salt, iterations, derivedKeyLength } = parameters; | ||
|
||
if (!Number.isInteger(iterations) || iterations <= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bitjson If we include these checks, we break a linter "complexity" rule (max is 5, we end up on 10).
I'm not sure if these are maybe overkill? Or maybe should be split out into a separate verifyPbkdf2Parameters
function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: If we keep these in, will try to add fail test cases for completeness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These checks are great! They make sense here, and I don't really see a reason to break them out into a separate function (it would be quite the stretch to use just this validation in some other context). So this is a good place to break our complexity rule (right above the relevant function):
// eslint-disable-next-line complexity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have placed this one in.
@bitjson probably ready for another look now. Note the long list of ignored linter rules and which ones we should try to fix up. Original algo is taken from https://github.com/browserify/pbkdf2/blob/master/lib/sync-browser.js |
Looking great so far! For the BIP39 implementation, maybe a reasonable strategy is including a |
Just pushed my initial recommendation, but feel free to experiment with other options 👍 |
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
d670d17
to
5ad6520
Compare
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
Signed-off-by: James Zuccon <[email protected]>
I think this is finally ready for review (sorry about how long this took!) A few notes:
|
Wow, fantastic work @jimtendo! Thanks for the attention to detail, this looks great. I'm going to dedicate some more time to reviewing it, and I'll pull it in with the next release. 🚀 |
Signed-off-by: James Zuccon <[email protected]>
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #109 +/- ##
===========================================
+ Coverage 0 84.26% +84.26%
===========================================
Files 0 144 +144
Lines 0 51448 +51448
Branches 0 2136 +2136
===========================================
+ Hits 0 43355 +43355
- Misses 0 8076 +8076
- Partials 0 17 +17 ☔ View full report in Codecov by Sentry. |
Thanks again for all your work here @jimtendo! Merged manually in 8e032c2. I added a few more functions, expanded the docs, and added a few more tests (including fuzzing/property-based testing) in 4709c17. Now released in |
This is a PBKDF2 pure JS implementation to progress towards supporting BIP39 mnemonics (I'll branch mnemonics off of this - want to try to keep reviews small and make sure I'm on the right track code-style-wise).
It's based on this implementation https://github.com/browserify/pbkdf2/blob/master/lib/sync-browser.js with a change to support derivedKeyLength that is less than the hmacLength (both NodeJS's PBKDF2 implementation and Python's support this - the test vectors I've found also have this).
The interface is a it clunky - I've tried to keep to the "under three params" lint rule and, unfortunately, we need to know the HMAC length in advance (we could determine this at run-time by "trying it", but I'm not sure that feels proper or efficient?j). Currently, the
Pbkdf2PHmac
interface breaks thefunctional/no-mixed-type
linter rule too - but I'm not too sure what's a good approach for this (maybe I remove this interface and just pass those params direct into function? Let me know if you have any suggestions).The implementation itself breaks many linter rules. At the moment, I've set a lot of these to be ignored as there's some precedent for this in the CashAddress implementation and rewriting around them may be less efficient considering we're dealing with an algo that iterates into the thousands in practice. Let me know what's preferred here and I can try to rewrite.
Overall, if you could take a look and just let me know which parts you'd like refactored and whether the general direction (e.g. the tests) look appropriate, that'd be great. I'm still digesting and learning the styles from elsewhere in Libauth.