Giter Site home page Giter Site logo

dmazzella / ucrypto Goto Github PK

View Code? Open in Web Editor NEW
29.0 29.0 11.0 389 KB

Micropython package for doing fast rsa and elliptic curve cryptography, specifically digital signatures

Makefile 0.03% C 91.60% Python 8.30% CMake 0.07%
cryptography elliptic-curves micropython rsa

ucrypto's Introduction

life is short, use python! 🐍

Tip

If you find my projects useful, consider ⭐ and why not ... Buy me a coffee πŸ˜„

ucrypto's People

Contributors

dmazzella avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ucrypto's Issues

Secp256k1

Hi!
Can I use calculations with the secp256k1 curve if I change the source data in the file "ucrypto_ecc_p256.py"?

Bad ECDSA signature/crash on RPi Pico W

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!

RSA worked for me on Pico W fairly quickly with bits=512 and using the default example

I copied https://github.com/dmazzella/ucrypto/tree/master/modules/ufastrsa and https://github.com/dmazzella/ucrypto/blob/master/modules/functools.py into lib and ran a slightly modified version of the example from the README:

from ufastrsa.rsa import RSA, genrsa


def main():

    bits = 512
    print("RSA bits", bits)
    r = RSA(*genrsa(bits, e=65537))
    if r:
        print("RSA OK")
        data = b"a message to sign and encrypt via RSA"
        print("random data len:", len(data), data)
        assert r.pkcs_verify(r.pkcs_sign(data)) == data
        print("pkcs_verify OK")
        assert r.pkcs_decrypt(r.pkcs_encrypt(data)) == data
        print("pkcs_decrypt OK")


if __name__ == "__main__":
    main()

Thank you for the straightforward solution! xref https://github.com/orgs/micropython/discussions/10048#discussioncomment-4202935

TFM fp_exptmod producing unexpected result

I've been playing around with various RSA libraries and found an oddity in the pow3_ function which uses TFM fp_exptmod. I'm not sure if what I'm seeing is an error, but it isn't what I'm expecting. Here is the test I'm running on an ESP32-S3:

from _crypto import NUMBER as tfm
from adafruit_rsa.core import fast_pow as adf_pow
from time import ticks_diff, ticks_ms

import random
import sys

tfm_pow = tfm.exptmod

def main():
    l = []
    for i in range(0, 10):
        a = random.randint(0, sys.maxsize)
        b = random.randint(0, sys.maxsize)
        # b = 65537  # 65537 is standard for reasons
        c = random.randint(0, sys.maxsize)
        # c = 2048  # 2048 bit max to prevent overflow per TFM_CHECK comment

        l.append((a, b, c))

    # Test tfm
    tfm_results = []
    start = ticks_ms()
    for a, b, c in l:
        tfm_results.append(tfm_pow(a, b, c))

    stop = ticks_ms()
    print('tfm_pow: ', ticks_diff(stop, start))

    # Test adf
    adf_results = []
    start = ticks_ms()
    for a, b, c in l:
        adf_results.append(adf_pow(a, b, c))

    stop = ticks_ms()
    print('adf_pow: ', ticks_diff(stop, start))

    # Verify both functions had the same output
    print('Results are identical: ', tfm_results == adf_results)

    if tfm_results != adf_results:
        print('Test inputs:')
        print(l)
        print()
        print('TFM results:')
        print(tfm_results)
        print()
        print('ADF results:')
        print(adf_results)

if __name__ == "__main__":
    main()

And here is the adafruit fast_pow function. The output of the function below always matches the output of CPython's pow function as well:

def fast_pow(x: int, e: int, m: int) -> int:
    """
    Performs fast modular exponentiation, saves RAM on small CPUs/micros.

    :param int x: Base
    :param int e: Exponent
    :param int m: Modulo
    """

    X = x
    E = e
    Y = 1
    while E > 0:
        if E % 2 == 0:
            X = (X * X) % m
            E = E // 2
        else:
            Y = (X * Y) % m
            E = E - 1
    return Y

And here are the results:


MicroPython v1.19.1-709-g0219c40e2-dirty on 2022-12-16; ESP32S3 module with ESP32S3
Type "help()" for more information.
>>> import pow
>>> pow.main()
tfm_pow:  9
adf_pow:  112
Results are identical:  False
Test inputs:
[(1965509468, 1387443297, 1605567237), (1871294224, 1902723300, 752900670), (1233710178, 1838389496, 1357457465), (1632487816, 1367755825, 1923817713), (442177334, 385651918, 144762972), (488834613, 74276846, 1063867451), (1029344430, 2060678614, 294479980), (1412723309, 1652848341, 2144438478), (457083566, 747582368, 583126214), (580365312, 1089030014, 32)]

TFM results:
[1132155764, 0, 81381301, 488747596, 0, 681878736, 0, 0, 0, 0]

ADF results:
[1132155764, 278440606, 81381301, 488747596, 28485700, 681878736, 227706460, 238573763, 62767214, 0]

It is unclear to me why the fp_exptmod output isn't matching other pow implementations. I have tried disabling TFM_CHECK and TFM_TIMING_RESISTANT, but disabling the former doesn't appear to make any difference, and disabling the latter results in a stackoverflow.

Errors compiling for ESP32_GENERIC_C3

I'm trying to build a Micropython firmware with this library included. I have an environment set up for building Micropython and can get a firmware.bin file out by running

make -C ports/esp32 BOARD=ESP32_GENERIC_C3

However when I clone down ucrypto and include it in the USER_C_MODULES argument as instructed, I get quite a lot of errors and the firmware fails to build.

make -j8 -C ports/esp32 V=1 BOARD=ESP32_GENERIC_C3 USER_C_MODULES="$(realpath ../ucrypto/micropython.cmake)"

Here is the last chunk of output, but there are quite a few errors, all seemingly coming from ucrypto/moducrypto.c

/home/jonah/micropython/ucrypto/moducrypto.c:2225:7: error: expected ';' before 'const'
 2225 | STATIC MP_DEFINE_CONST_DICT(mp_module_ucrypto_globals, mp_module_ucrypto_globals_table);
      |       ^
      |       ;
/home/jonah/micropython/ucrypto/moducrypto.c:302:12: warning: 'fp_pow3' defined but not used [-Wunused-function]
  302 | static int fp_pow3(fp_int *X, fp_int *E, fp_int *M, fp_int *Y)
      |            ^~~~~~~
cc1: some warnings being treated as errors
[96/97] Generating binary image from built executable
esptool.py v4.7.0
Creating esp32c3 image...
Merged 2 ELF sections
Successfully created esp32c3 image.
Generated /home/jonah/micropython/micropython/ports/esp32/build-ESP32_GENERIC_C3/bootloader/bootloader.bin
[97/97] cd /home/jonah/micropython/micropython/ports/esp32...rts/esp32/build-ESP32_GENERIC_C3/bootloader/bootloader.bin
Bootloader binary size 0x4330 bytes. 0x3cd0 bytes (48%) free.
ninja: build stopped: subcommand failed.
ninja failed with exit code 1, output of the command is in the /home/jonah/micropython/micropython/ports/esp32/build-ESP32_GENERIC_C3/log/idf_py_stderr_output_39396 and /home/jonah/micropython/micropython/ports/esp32/build-ESP32_GENERIC_C3/log/idf_py_stdout_output_39396
See https://github.com/micropython/micropython/wiki/Build-Troubleshooting
make: *** [Makefile:66: all] Error 1
make: Leaving directory '/home/jonah/micropython/micropython/ports/esp32'

Here's the full output:
https://paste.sr.ht/~jonahbron/c48f525093b76f9481d9340163c03c66fb289442

Is this a known issue, does ESP32C3 not work? Or am I doing something wrong with my compilation?

make on Pi Pico RP2040 board

Hi, friend!)
What is the right command to make firmware on Pi Pico 2040 board? When i used this -> make -j8 -C mpy-cross && make -j8 -C ports/stm32/ BOARD="PYBD_SF6" USER_C_MODULES="$(pwd)/ports/stm32/boards/PYBD_SF6/cmodules" firmware.elf is not supported. And when i convert this firmware with ./elf2uf2 firmware.elf firmware.uf2 I get an error "ERROR: HARD-FLOAT not supported"

Please help me to understand this

Install steps on Beetle ESP32

Hi!,

Dear Author this is really good project!, I am interested how I can use it on my boad could you please provide the steps how to install it?

USER_C_MODULES seems should be pointing to a root cmake file

Followed README.md, the build fails with latest MicroPython source:

make -j8 -C mpy-cross && make -j8 -C ports/stm32/ BOARD="PYBD_SF6" USER_C_MODULES="$(pwd)/ports/stm32/boards/PYBD_SF6/cmodules"

Turns out I have to go with :
make -j8 -C mpy-cross && make -j8 -C ports/stm32/ BOARD="PYBD_SF6" USER_C_MODULES="$(pwd)/ports/stm32/boards/PYBD_SF6/cmodules/micropython.cmake"

[ESP32] Compiling for Micropython

Hi,

Do you have to change the make file to a cmake file in order for this to compile?

-- Adding linker script /Users/thomasgiles/esp-VS/micropython-3/esp-idf/components/soc/esp32s3/ld/esp32s3.peripherals.ld
Including User C Module(s) from /Users/thomasgiles/esp-VS/micropython-3/ports/esp32/boards/GENERIC_S3_SPIRAM/ucrypto
CMake Error at /Users/thomasgiles/esp-VS/micropython-3/py/usermod.cmake:42 (include):
include requested file is a directory:

/Users/thomasgiles/esp-VS/micropython-3/ports/esp32/boards/GENERIC_S3_SPIRAM/ucrypto

Call Stack (most recent call first):
main/CMakeLists.txt:10 (include)

Many thanks,

Thomas

Build fails on PICO_W

With latest sources, both micropython and ucrypto. Trying to make a build for pico w board, but it always fails in the last steps :

The building keeps failing with Error
selected processor does not support ***** in Thumb mode
instruction not supported -- '*******'

To the best of my knowledge these kind of asm issues should be automatically solved by compiler, but it seems currently not.

What else can be done to make things work or it's just a unsolvable platform supporting issue?

overflow ecdsa

image

Hello I have this problem in esp32 , do you know how to solve ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.