[PATCH] arm64: random: implement arch_get_random_int/_long based on RNDR

Ard Biesheuvel ardb at kernel.org
Thu Jan 13 05:49:15 PST 2022


On Thu, 13 Jan 2022 at 14:41, Jason A. Donenfeld <Jason at zx2c4.com> wrote:
>
> Hi Ard,
>
> Wow, didn't expect for this to come so fast. Excellent.
>
> On Thu, Jan 13, 2022 at 02:12:39PM +0100, Ard Biesheuvel wrote:
> > - map arch_get_random_int/_long() onto RNDR, which returns the output of
> >   a DRBG that is reseeded at an implemented defined rate;
>
> implemented -> implementation?
>

Ack

> >  static inline bool __must_check arch_get_random_long(unsigned long *v)
> >  {
> > +     /*
> > +      * Only support the generic interface after we have detected
> > +      * the system wide capability, avoiding complexity with the
> > +      * cpufeature code and with potential scheduling between CPUs
> > +      * with and without the feature.
> > +      */
> > +     if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v))
> > +             return true;
> >       return false;
> >  }
>
> Can't this just become:
>
>   return cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v);
>

Sure, but I just retained the original style.

> >
> >  static inline bool __must_check arch_get_random_int(unsigned int *v)
> >  {
> > +     if (cpus_have_const_cap(ARM64_HAS_RNG)) {
> > +             unsigned long val;
> > +
> > +             if (__arm64_rndr(&val)) {
> > +                     *v = val;
> > +                     return true;
> > +             }
> > +     }
> >       return false;
> >  }
>
> Why not implement arch_get_random_int with the same type of flow as
> arch_get_random_long?
>
> static inline bool __must_check arch_get_random_int(unsigned int *v)
> {
>         unsigned long val;
>         if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(&val))) {
>                 *v = val;
>                 return true;
>         }
>         return false;
> }
>
> Or, even better, just define arch_get_random_int in terms of
> arch_get_random_long:
>
> static inline bool __must_check arch_get_random_int(unsigned int *v)
> {
>         unsigned long val;
>         if (arch_get_random_long(&val)) {
>                 *v = val;
>                 return true;
>         }
>         return false;
> }
>
>

If I was interested in rewriting this header file, I might consider
all these options. For now, I am just trying to focus the change on
the parts that actually matter.

> > @@ -71,12 +105,11 @@ static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
> >       }
> >
> >       /*
> > -      * Only support the generic interface after we have detected
> > -      * the system wide capability, avoiding complexity with the
> > -      * cpufeature code and with potential scheduling between CPUs
> > -      * with and without the feature.
> > +      * RNDRRS is not backed by an entropy source but by a DRBG that is
> > +      * reseeded after each invocation. This is not a 100% fit but good
> > +      * enough to implement this API if no other entropy source exists.
>
> The docs are actually a bit more optimistic than that:
>
> https://developer.arm.com/documentation/ddi0595/2021-03/AArch64-Registers/RNDRRS--Reseeded-Random-Number
>
>  ~ Reseeded Random Number. Returns a 64-bit random number which is reseeded
>  ~ from the True Random Number source immediately before the read of the
>  ~ random number.
>
> If I'm reading that correctly, it looks like the reseeding happens
> *before* the read, and it looks like it comes from a TRNG. In
> other words, it sounds to me like it's just doing something like
> HASH(READ_TRNG()). That would be pretty darn good.
>

No it does not. RNDR and RNDRRS both return the output of a DRBG, the
only difference is the reseed interval.

Specifically, this means that, even though the ARM ARM references NIST
SP800-90B directly, the RNDRRS construction is a black box containing
a entropy source + DRBG, and so we shouldn't pretend that RNDRRS
itself can be treated as a source of true entropy. This is especially
relevant when it comes to seeding a DRBG of a certain security
strength N >= the security strength of the hidden DRBG, as
concatenating multiple RNDRRS results does not satisfy the
requirements for seeding a DRBG of security strength N.

> >        */
> > -     if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v))
> > +     if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndrrs(v))
> >               return true;
> >
> >       return false;
> > @@ -96,7 +129,7 @@ static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
> >       }
> >
> >       if (cpus_have_const_cap(ARM64_HAS_RNG)) {
> > -             if (__arm64_rndr(&val)) {
> > +             if (__arm64_rndrrs(&val)) {
> >                       *v = val;
> >                       return true;
> >               }
>
> I suppose the same control flow simplification stuff mentioned above
> could be done here too, if you feel like what I mentioned earlier is
> worthwhile.
>
> From a randomness perspective:
>
> Acked-by: Jason A. Donenfeld <Jason at zx2c4.com>
>

Thanks,



More information about the linux-arm-kernel mailing list