fix(s070): draw gateway pairing codes from the cryptographically secure generator - #69
Merged
Merged
Conversation
…re generator A pairing code is a credential: it is the whole of the proof that whoever holds an outside channel is the person sitting at this machine. It was generated with Enum.random/1, which draws from :rand. That generator is not cryptographically secure and its output is predictable from observed output, so an attacker who saw a few codes could anticipate the next one and pair an identity the operator never approved. The code was compared in constant time, which made the weakness easier to miss: the comparison was careful and the generation was not. Codes now come from :crypto.strong_rand_bytes/1. The alphabet is 32 characters and a byte has 256 values, so mapping with rem/2 is uniform - 256 is exactly eight whole cycles of the alphabet and no character is favoured. Two tests hold it. One asserts codes are the right shape, distinct across 200 draws and spread across the alphabet. The other is a census over lib/trinity/gateways: no file may call Enum.random or :rand, reading code with comments and docs stripped, so a moduledoc explaining why the weak generator is not used does not trip the check that forbids calling it. Found by auditing the tree against the OpenSSF Best Practices criterion crypto_random while preparing the badge self-certification. Signed-off-by: Ayla Croft <aylacroft@proton.me>
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.
A pairing code is a credential: it is the whole of the proof that whoever holds an outside channel is the person sitting at this machine.
It was generated with
Enum.random/1, which draws from:rand. That generator is not cryptographically secure and its output is predictable from observed output, so someone who saw a few codes could anticipate the next one and pair an identity the operator never approved. The code was compared in constant time, which made the weakness easier to miss: the comparison was careful and the generation was not.Codes now come from
:crypto.strong_rand_bytes/1. The alphabet is 32 characters and a byte has 256 values, so mapping withrem/2is uniform: 256 is exactly eight whole cycles of the alphabet and no character is favoured.Two tests hold it. One asserts codes are the right shape, distinct across 200 draws, and spread across the alphabet. The other is a census over
lib/trinity/gateways: no file may callEnum.randomor:rand. The census reads code with comments and docs stripped, so a moduledoc explaining why the weak generator is not used does not trip the check that forbids calling it.How it was found: auditing the tree against the OpenSSF Best Practices criterion
crypto_random("all cryptographic keys and nonces MUST be generated using a cryptographically secure random number generator") while preparing the badge self-certification. The audit was the point of the exercise and it earned its keep on the first pass.Gate green: 566 tests.