feat: expose and validate the scrypt recipient work factor#548
Merged
msfjarvis merged 2 commits intoJun 22, 2026
Merged
Conversation
Promote the default scrypt work factor to a public const so callers can reference the value kage applies by default (e.g. to display it or derive a relative factor) instead of hard-coding 18. The salt/stanza/label constants stay internal.
ScryptRecipient.wrap computes `1 shl workFactor`, an Int shift whose count is masked to its low 5 bits, so a work factor >= 31 silently wraps (e.g. 33 -> N=2) and would emit a uselessly weak file with no error. Bound the constructor argument to 1..30 in an init block, the same range ScryptIdentity already enforces on decryption and the range the reference age implementation accepts. Also rename ScryptIdentity's private DEFAULT_WORK_FACTOR to DEFAULT_MAX_WORK_FACTOR: it is the default ceiling on the work factor accepted when decrypting, not an applied cost, and the old name collided with ScryptRecipient.DEFAULT_WORK_FACTOR. Internal only; no API change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two small changes to
ScryptRecipient, both from building on kage.The default scrypt work factor was hardcoded as
18insidewrap(). This pulls it out into a publicScryptRecipient.DEFAULT_WORK_FACTORso callers can read or display the value kage uses instead of repeating the literal.The recipient also never checked the work factor it was handed.
wrap()does1 shl workFactor, and anIntshift on the JVM masks the count to 5 bits, soworkFactor = 33quietly becomes1 shl 1, which is2, and31or32give a negative or zeroN. You end up with a file encrypted at near-zero scrypt cost and no error. I addedrequire(workFactor in 1..30)in aninitblock, the same rangeScryptIdentityalready enforces on the decrypt side. I also renamed the private decrypt-side constant fromDEFAULT_WORK_FACTORtoDEFAULT_MAX_WORK_FACTOR, since it's the ceiling accepted when decrypting and read confusingly next to the new encrypt-side default.The test checks that
Int.MIN_VALUE, -1, 0, 31, 32, 33, Int.MAX_VALUEare rejected and that1and30still construct.Notes for review:
DEFAULT_WORK_FACTORconstant is in thekage.apidiff. The rename is private and doesn't touch the surface../gradlew test checkKotlinAbi animalsnifferMain spotlessCheck; pitest left to CI.