adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.07k stars 1.2k forks source link

os.urandom() throws confusing exception for lengths above 64 #2447

Closed kevinjwalters closed 4 years ago

kevinjwalters commented 4 years ago

I was playing around in CircuitPython to work out the possible and best ways to detect if os.urandom is present. It turns out it's always present so I then started looking at the exceptions that it throws on platforms with no hardware, e.g. SAMD21 (M0) like the CPX. I noticed during that experimentation that even on a CPB where there is hardware support this fails for values above 64. Either that's a bug or it's a confusing use of the NotImplementedError exception?

Adafruit CircuitPython 5.0.0-beta.2 on 2019-12-20; Adafruit Circuit Playground Bluefruit with nRF52840
>>>
>>>
>>> import os
>>> os.urandom(100)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NotImplementedError: No hardware random available
>>> os.urandom(65)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NotImplementedError: No hardware random available
>>> os.urandom(64)
b'\x02B\xa9\xb8\xde\xcavG\xfb4e\x08\x11\x1f\x9c\x88\x91\x89p\xf6\xe8u\x87\xa8\x9a\x1c\xf7B\x03A\x87\x0b\x03\x05\x95a\xe3Y\x0b\xa2&\xd2 \xa1{\xe4\xd4\x04\x9cI\xf7\x1d\xf0\xb8-r\xa9/\xfb\xca\xce\x8b\x1a^'
>>> os.urandom(4)
b'\x86`{\x08'

For comparison of the exception, CPX output:

Adafruit CircuitPython 4.1.0 on 2019-08-02; Adafruit CircuitPlayground Express with samd21g18
>>>
>>> import os
>>> os.urandom(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NotImplementedError: No hardware random available
kevinjwalters commented 4 years ago

I have no need for lengths above 64 btw!

tannewt commented 4 years ago

The soft device must only support up to 64 bytes here: https://github.com/adafruit/circuitpython/blob/master/ports/nrf/common-hal/os/__init__.c#L70

We should split it up as needed.

kevinjwalters commented 4 years ago

Based on previous mention of the SAMD51 having this hardware feature too I thought I'd try a nearby Feather M4 Express. I put 4.1.2 on that and I've noticed that works ok with numbers larger than 64.

It does blow up with -1 and 30000. I hunted around the upper magic value and it doesn't look like a fixed value but perhaps one related to memory. It goes into hard fault handler and says The CircuitPython stack was corrupted because the heap was too small. I doubt many people are going to need large amounts of random data in one go but this could cause confusing crashes for bugs where the wrong number of bytes are sometimes requested from urandom().

Perhaps more worringly after a second os.urandom() crash on that board on my trusty Win8.1 desktop the usb starts misbehaving and the serial port (driver is Adafruit Industries LLC / 13/01/2019 / 10.2.4.0) and CIRCUITPY drive no longer work. Any other Adafruit boards then don't work and that together with a ponderous reboot to Win 8.1 suggests there's a driver issue here. I had a quick try on a Win 10 laptop and can't reproduce usb issue there.

dhalbert commented 4 years ago

Fixed by #2461.