Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ecdsa better read me #19

Open
wants to merge 50 commits into
base: ecdsa-examples
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
6671459
Added and refined Doxygen: Documentation-Autogenerate System
damnkunze May 3, 2022
74d3727
Small improvements in Readme and examples-Readme
damnkunze May 3, 2022
81acee1
Optimized docstrings for Doxygen
damnkunze May 3, 2022
d449493
Reorganized Documentation files and moved most examples into /tools/
damnkunze May 11, 2022
e3fd025
Short Quickstart and Step by step examples implemented and documented…
damnkunze May 17, 2022
acde632
Repo cleanup: files present twice, test-web-of-trust.py doesnt work a…
damnkunze May 17, 2022
6bdccea
Update QuickstartExample.py
damnkunze May 17, 2022
48c0da3
Update StepByStepExample.py
damnkunze May 17, 2022
0752891
Structure change: Documentation .md files should be in the repository…
damnkunze May 19, 2022
d41778f
help got merge conflicts
damnkunze May 19, 2022
56f8ce3
docs rename
damnkunze May 19, 2022
cbcdac9
README.md is the same as index.md + Quickstart.md
damnkunze May 19, 2022
cde6a83
Set theme jekyll-theme-minimal
damnkunze May 19, 2022
8ed618f
Readme imporved
damnkunze May 19, 2022
2fba4e1
Merge branch 'ecdsa-betterReadMe' of https://github.com/ubirch/ubirch…
damnkunze May 19, 2022
d15955e
Use the same theme as the main page
damnkunze May 19, 2022
3dd172b
moved img folder
damnkunze May 19, 2022
66dea8b
testing html comparability
damnkunze May 30, 2022
4656e8f
Update index.md
damnkunze May 30, 2022
a9f7128
Added other doc links to README
damnkunze May 30, 2022
f372217
Added other doc links to gh pages index.md
damnkunze May 30, 2022
2c32301
Added other doc links to gh pages index.md 2
damnkunze May 30, 2022
d86c629
Implement Github Action to push doxygen-func-doc to other repo. Done …
damnkunze May 31, 2022
f092c92
Completed seperation of function-documentation and Textual Documentat…
damnkunze May 31, 2022
3fbacfa
Missing Titles & improved linking
damnkunze May 31, 2022
453e4e9
Updated Headlines
damnkunze Jun 1, 2022
ad8e2af
Updated Headlines
damnkunze Jun 1, 2022
de9aadc
Jekyll now can be run locally and produce the same results as Github …
damnkunze Jun 2, 2022
a625f00
config file has to be in root (/docs) for GH Pages to find it
damnkunze Jun 2, 2022
1dce3cf
Extended docstring-documentation in ubirch-library files + Last adapt…
damnkunze Jun 7, 2022
b5f785d
Tweaking of Jekyll Configuration and guides
damnkunze Jun 7, 2022
f0ad05b
Better README!
damnkunze Jun 8, 2022
1fe44a0
updated gitignore
damnkunze Jun 8, 2022
dae35c5
minors
damnkunze Jun 9, 2022
2493026
Untested (demo broken): Step by Step guide made detailed
damnkunze Jun 16, 2022
587403e
Step by Step is working. Now on prod stage.
damnkunze Jun 22, 2022
39faef6
Minors to clean up for PR to ecdsa-examples
damnkunze Jun 22, 2022
30fb769
ignore Gemfile.lock
damnkunze Jun 22, 2022
e1175a2
Changes suggested in the review from @UBOK19 -- PR #19
damnkunze Jun 24, 2022
eb987c7
Second fix for PR #19
damnkunze Jun 27, 2022
b352b8f
Improvement of examples through thorough testing
damnkunze Jun 28, 2022
4121f06
Improved dostrings in Ubirch package. Removed unneccesary tools. Cont…
damnkunze Jul 6, 2022
ede1a7b
partially fix tests
UBOK19 Jul 6, 2022
b5eb407
check uuid filtering
UBOK19 Jul 6, 2022
8debb34
remove old not implemented exception
UBOK19 Jul 6, 2022
82282db
Add note to Readme about "Personal access tokens"
damnkunze Jul 7, 2022
4e642f4
Bumped version of ubirch-protocol to 2.2.0
damnkunze Jul 7, 2022
d22a9eb
typo
damnkunze Jul 7, 2022
c61c384
Set version on ubirch-prtocol packagee to 3.1.0
damnkunze Jul 7, 2022
3ef05c7
added hashing in _sign() and _verify() for ecdsa, now the tests are w…
Jul 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/run_doxygen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Generate Doc
on: [push]
jobs:
deploys:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: ''

- name: Generate doc with Doxygen
uses: mattnotmitt/[email protected]
with:
working-directory: 'docs/doxygen'
doxyfile-path: './Doxyfile'

- name: Deploy to func-doc repo
uses: peaceiris/actions-gh-pages@v3
with:
publish_dir: docs/doxygen/html
external_repository: ubirch/function_documentation
personal_token: ${{ secrets.PERSONAL_TOKEN }}
publish_branch: master
destination_dir: ${{ github.event.repository.name }}
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_STORE
*.keys
*.cfg
.idea
Expand All @@ -9,4 +10,7 @@
*.egg-info
build
dist
/venv*
/venv*
Gemfile.lock
docs/_site/
docs/doxygen/html/
268 changes: 87 additions & 181 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,230 +1,136 @@
# ubirch-protocol for python
[**Documentation and examples**](https://developer.ubirch.com/ubirch-protocol-python/)
damnkunze marked this conversation as resolved.
Show resolved Hide resolved

This is an implementation of the [ubirch-protocol](https://github.com/ubirch/ubirch-protocol)
for [Python 3](https://www.python.org/). Please see [ubirch-protocol](https://github.com/ubirch/ubirch-protocol)
for details.
[**Function Documentation**](https://developer.ubirch.com/function_documentation/ubirch-protocol-python/)

The library consists of three parts which can be used individually:
---

* `ubirch.API` - a python layer covering the ubirch backend REST API
* `ubirch.Protocol` - the protocol compiler which packages messages and handles signing and verification
* `ubirch.KeyStore` - a simple key store based on [pyjks](https://pypi.org/project/pyjks/) to store keys and certificates
<!-- IMPORTANT
The Getting Started and the README have the same content.
But for Github to render it as the repo description and Github Pages (Jekyll) to be able to find it, there need to be two.
The links are different in some places, so please don't just copy paste everything while doing changes.
-->

> the [ubirch](https://ubirch.com) protocol uses the [Ed25519](https://ed25519.cr.yp.to/) signature scheme by default.

## Usage
<p align="center">
<a href="#installation">Installation</a> •
<a href="#setup">Setup</a> •
<a href="#a-minimal-application">A minimal application</a>
</p>

Install the library: `pip install ubirch-protocol`

### Creating keypair and messages

```python
import ubirch
from uuid import UUID
import binascii
This repository contains a library providing an implementation of the [Ubirch-protocol](https://github.com/ubirch/ubirch-protocol) in **Python 3**.

# create a keystore for the device keypair
keystore = ubirch.KeyStore("demo-device.jks", "keystore")
That, along with the helper classes `KeyStore` and `API`. These can be used to handle cryptografic keys und to communicate with the Ubirch backend.

# create a UUID that identifies the device and load or create a keypair
uuid = UUID(hex="575A5601FD744F8EB6AEEF592CDEE12C")
if not keystore.exists_signing_key(uuid):
keystore.create_ed25519_keypair(uuid)
Additionally, the raw documentation files rendered to the [documentation pages](https://developer.ubirch.com/ubirch-protocol-python/).

# implement the _sign method of the ubirch.Protocol to use the just created keys to sign the message
class ProtocolImpl(ubirch.Protocol):
def _sign(self, uuid: UUID, message: bytes) -> bytes:
return keystore.find_signing_key(uuid).sign(message)

# create an instance of the ubirch protocol
proto = ProtocolImpl()

# create ubirch protocol messages
print(binascii.hexlify(proto.message_chained(uuid, 0x00, [1, 2, 3])))
print(binascii.hexlify(proto.message_chained(uuid, 0x00, [4, 5, 6])))
```

### Sending messages using the ubirch API

Please see [test-protocol.py](examples/test-protocol.py) for a comprehensive example, how to create a device and
send data. Below is a snipped that will send two chained messages, using a generic key/value payload.

You will need a password for the ubirch backend. Go to https://console.demo.ubirch.com to register your UUID
under `Things`. Then click on your device and copy the password from the `apiConfig`-field.

```python
import ubirch
from uuid import UUID
import binascii
from datetime import datetime
## Installation
Optionally create environment to install to:

# create a keystore for the device key pair
keystore = ubirch.KeyStore("demo-device.jks", "keystore")
`$ python -m venv venv`

# create a UUID that identifies the device and load or create a key pair
uuid = UUID(hex="575A5601FD744F8EB6AEEF592CDEE12C")
if not keystore.exists_signing_key(uuid):
keystore.create_ed25519_keypair(uuid)
`$ . venv/bin/activate`

Install the requirements and Ubirch library using pip:

# implement the _sign method of the ubirch.Protocol
class ProtocolImpl(ubirch.Protocol):
def _sign(self, _uuid: UUID, message: bytes) -> bytes:
return keystore.find_signing_key(uuid).sign(message)
`$ pip install -r requirements.txt`

`$ pip install ubirch-protocol`
damnkunze marked this conversation as resolved.
Show resolved Hide resolved

# create an instance of the ubirch protocol
proto = ProtocolImpl()
> Currently the version of the `ubirch-protocol` package installable with pip is not the same as the package provided in this repository

# create an instance of the ubirch API and set the password
api = ubirch.API()
api.set_authentication(uuid, "<< password for the ubirch backend >>") # register your UUID at https://console.demo.ubirch.com and retrieve your password
If you want to install from another source than pip, follow along [here](docs/NotPip.md).

# message 1
msg = proto.message_chained(uuid, 0x53, {'ts': int(datetime.utcnow().timestamp()), 'v': 99})
print(binascii.hexlify(msg))
# send message to ubirch backend
r = api.send(uuid, msg)
print("{}: {}".format(r.status_code, r.content))
## Setup
Before anything, you will need to do/get a couple of things:
- Open up the [uBirch Console](https://console.demo.ubirch.com) (`'demo'` stage)
- For guidance, check out the [uBirch console documentation](https://developer.ubirch.com/console.html)
- First register to get an account
- Then Create a "Thing":
- Using a UUID generated with a [UUID-Generator](https://www.uuidgenerator.net/)
- You will be using the shown UUID (ID) and the generated Auth-Token (password) from now on
- Come up or [generate](https://www.random.org/passwords/) a password for the KeyStore, which is where public and private Keys will be stored locally

# message 2 (chained to message 1)
msg = proto.message_chained(uuid, 0x53, {"ts": int(datetime.utcnow().timestamp()), "v": 100})
print(binascii.hexlify(msg))
# send message to ubirch backend
r = api.send(uuid, msg)
print("{}: {}".format(r.status_code, r.content))
```
> Open up the [Getting started](https://developer.ubirch.com/ubirch-protocol-python/GettingStarted.html) on the [Documentation and Examples](https://developer.ubirch.com/ubirch-protocol-python/) pages or continue below.

### Verification of received message
### Now you should have the following at hand:

Our [Ubirch API](http://developer.ubirch.com/function_documentation/ubirch-protocol-python/)
authentication with an uuid and a password:
```python
import ubirch
from ed25519 import VerifyingKey, BadSignatureError
from uuid import UUID

remote_uuid = UUID(hex="9d3c78ff22f34441a5d185c636d486ff")
remote_vk = VerifyingKey("a2403b92bc9add365b3cd12ff120d020647f84ea6983f98bc4c87e0f4be8cd66", encoding='hex')

# create a keystore and insert the verifying key
keystore = ubirch.KeyStore("demo-device.jks", "keystore")
keystore.insert_ed25519_verifying_key(remote_uuid, remote_vk)

# implement the _verify method of the ubirch.Protocol
class ProtocolImpl(ubirch.Protocol):
def _verify(self, uuid: UUID, message: bytes, signature: bytes) -> dict:
return keystore.find_verifying_key(uuid).verify(signature, message)

# create an instance of the ubirch protocol
proto = ProtocolImpl()

message = bytes.fromhex(
"9623c4109d3c78ff22f34441a5d185c636d486ffc440a5b371acdfc8495790ee86802399585da50401b0d3c87f60946719338eb0283d36c0bac9b8a6a75a5385342e62932335da988b97c0ec211556db082e9f8478070081a76d657373616765bf796f7572207265717565737420686173206265656e207375626d6974746564c440c8529623a4c2335f7a8ae1eeea655768d2e9a0df141f481ced557c9dac7216e8f64ca9f6970fc6c1096ed49bcc6f7fa77d8f85d05bff5e1301588597edc9770e")

# verify the message (throws an exception if the message could not be verified)
try:
print(proto.message_verify(message))
print("verification successful!")
except BadSignatureError as e:
print("ERROR: verification failed!")
uuid = UUID(hex = "f5ded8a3-d462-41c4-a8dc-af3fd072a217")
auth = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
```

### Existing keys

In case you create a key pair from our demo website, use the following code to insert it into the key store:

And credentials for a [KeyStore](http://developer.ubirch.com/function_documentation/ubirch-protocol-python/)
to store your public and private key:
```python
import ubirch
import ed25519
import uuid

hwDeviceId = uuid.uuid4()
keystore = ubirch.KeyStore("demo-device.jks", "keystore")
key_encoded = input("paste the encoded private key here:")
sk = ed25519.SigningKey(key_encoded, encoding='hex')
vk = sk.get_verifying_key()

keystore.insert_ed25519_keypair(hwDeviceId, vk, sk)
```

### Running the example

```bash
python3 -m venv venv3
. venv3/bin/activate
pip install -r requirements.txt
pip install ubirch-protocol
PYTHONPATH=. python3 examples/test-protocol.py
keystore_name = "devices.jks"
keystore_password = "XXXXXXXXXXX"
```

At the first launch the script generates a random UUID for your device and you will be asked
about the authentication token and the device group. You can safely ignore the device group, just press Enter.
The script creates a file `demo-device.ini` which is loaded upon running the script again. If
you need to change anything edit that file.
## A minimal application
The smallest uBirch application looks something like this.

The script goes through a number of steps:
*The code can be found in [`GettingStarted.py`](examples/GettingStarted.py) as well.*

1. checks the existence of the device and deletes the device if it exists
2. registers the device with the backend
3. generates a new identity for that device and stores it in the key store
4. registers the new identity with the backend
5. sends two consecutive chained messages to the backend

### Example: Web-of-Trust

#### Before First Execution

```bash
python3 -m venv venv3
pip install -r requirements.txt
```
Lets say we have got some weather-sensor data like:

#### Running The Example

```bash
. venv3/bin/activate
PYTHONPATH=. python3 examples/test-web-of-trust.py
```python
import time

data = {
"timestamp": int(time.time()),
"temperature": 11.2,
"humidity": 35.8,
"status": "OK"
}
```

During first launch the script generates key pairs for two users. Each user has one device and key pairs are created for
these, too. All key pairs are stored in `test-web-of-trust.jks` while the association of users, their device and the
respective key pair is stored in `demo-web-of-trust.ini`. In consecutive runs no new key pairs are generated and instead
the ones referenced in `demo-web-of-trust.ini` are used.
To send a hash of the data to the Ubirch backend run these few lines inside of `examples/`:
```python
import ubirch
from UbirchWrapper import UbirchWrapper

The script always uploads all public keys, followed by creating and uploading a web-of-trust and searching all public
keys trusted by `deviceA`. This search is repeated with different parameters. The results are then printed onto the
terminal.
client = UbirchClient(uuid, auth, keystore_name=keystore_name, keystore_password=keystore_password)
client.checkRegisterPubkey()

The web-of-trust created looks as follows (trust knows a direction; always bidirectional in this example):
currentUPP = client.createUPP(data)

```
deviceA <--trustLevel=100--> user1 <--trustLevel=50--> user2 <--trustLevel=100--> deviceB
```
response = client.api.send(uuid, currentUPP)
client.handleMessageResponse(response)

The first search for all trusted keys is for a minimum trust of 50 and a depth of 3 resulting in the the following keys
being found:
client.verifyResponseSender(response)

* user1
* user2
* deviceB
previousSignatureInUPP = client.extractPreviousSignature(response)
client.assertSignatureCorrect(previousSignatureInUPP)

The second search increases the minimum trust to 60 resulting in:
print("Successfully sent the UPP and verified the response!")

* user1
client.protocol.persist(uuid)
```

And the third search is with a minimum trust of 50 again while the depth is now 2 resulting in:
1. Initialize an UbirchClient instance and pass the credentials for a `KeyStore`
2. Check if the public key is registered at the Ubirch key service and register it if necessary
3. Create a chained Ubirch protocol packet (UPP) that contains a hash of the data
4. Send the UPP to the Ubirch backend using the `API`
5. Handle the response
6. Verify that the response came from the backend
7. Unpack the received UPP to get its previous signature
8. Make sure it is the same as the UPP signature sent
9. Persist signature: Save last signatures to a `.sig` file

* user1
* user2
*This example uses the example [UbirchWrapper](examples/UbirchWrapper.py) that helps to implement general repetitive tasks.*

> **Next:** Take a look at the Step-by-step-example on the [Documentation Pages](https://developer.ubirch.com/ubirch-protocol-python/)
damnkunze marked this conversation as resolved.
Show resolved Hide resolved

### Testing

Unit tests are added to test the functionality of all objects provided in this library.
## Testing
Unit tests are added to test the functionality of objects provided in this library.

```bash
pip install -r requirements.test.txt
python3 -m pytest tests
```
# License

python -m pytest tests
```

Loading