dmazzella / ucrypto

Micropython package for doing fast rsa and elliptic curve cryptography, specifically digital signatures
31 stars 11 forks source link

Bad ECDSA signature/crash on RPi Pico W #18

Closed tomharadalni closed 5 months ago

tomharadalni commented 5 months ago

Hello,

On the Pico W, I've observed ecdsa.sign() consistently producing an incorrect signature or hanging the system under specific conditions. The issue only seems to happen when ecdsa.sign() is invoked in an asyncio task, and only when roughly 85k-100k of the available 180k heap space is allocated. The issue exists with the latest ucrypto and micropython.

Below is a demo program that triggers the behavior. Tweaking the heap usage changes whether a bad signature is produced or the program hangs.

from ufastecdsa import ecdsa, keys, curve
import asyncio
import gc

private_key = 22322313096608720262726022759208549999371313709767561346264284646350673024178
public_key = keys.get_public_key(private_key, curve.P256)

# Buffers to consume heap space. The issue manifests around 85-100 kB allocated.
buf_a = bytearray(55000)
buf_b = bytearray()

async def sign_task():
    sign()

def sign():
    for i in range(0, 100):
        print(f'Test {i}')
        gc.collect()
        print(f'{gc.mem_alloc()} allocated')

        # Sometimes ecdsa.sign() hangs forever and sometimes the verification fails instead
        msg = bytearray(500)
        r, s = ecdsa.sign(msg, private_key)
        print(f'{r=}, {s=}')
        v = ecdsa.verify((r, s), msg, public_key)
        if not v:
            print('Verification failed!')
            return

        # Increase heap usage in a predicable way
        buf_b.extend(bytearray(1000))

# Running the function directly does not appear to cause the issue
# sign()

# Running the function as a task causes the issue
asyncio.run(sign_task())

The output:

Test 0
86400 allocated
r=85138370589888148504419467028945835242182133906801408929085382665177392495649, s=36405879136828887984530789867378534397858885811006898673352558309076209890931
Test 1
88032 allocated
r=85138370589888148504419467028945835242182133906801408929085382665177392495649, s=36405879136828887984530789867378534397858885811006898673352558309076209890931
Test 2
89024 allocated
r=85138370589888148504419467028945835242182133906801408929085382665177392495649, s=36405879136828887984530789867378534397858885811006898673352558309076209890931
Test 3
90032 allocated
r=81005532657339936592853986520470807188817871510725802802965116630864593609458, s=59780292414690978660613437195734621900681328919802338312801725760749994467877
Verification failed!

Thanks!

dmazzella commented 5 months ago

Hi, if you need only ecdsa, you can try to reduce memory usage: #define FP_MAX_SIZE try to reduce it from ((2048 * 2) + (8 * DIGIT_BIT)) to ((512 * 2) + (8 * DIGIT_BIT))

Best regards, D.

tomharadalni commented 5 months ago

That does seem to prevent the errors, although I don't understand why. Some kind of potential buffer overflow caused by the larger FP_MAX_SIZE? In any case, thanks for the help and for the useful library.