Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
ca59a49
build(deps): bump six from 1.16.0 to 1.17.0
dependabot[bot] Dec 9, 2024
68d7476
Merge pull request #26 from smswithoutborders/dependabot/pip/six-1.17.0
PromiseFru Dec 10, 2024
3ab3334
chore: bump version from 0.1.1 to 0.1.2
PromiseFru Dec 10, 2024
f157326
build(deps): bump ecdsa from 0.19.0 to 0.19.1
dependabot[bot] Mar 17, 2025
4e71ceb
Merge pull request #30 from smswithoutborders/dependabot/pip/ecdsa-0.…
PromiseFru Mar 26, 2025
8109920
build(deps): bump pycryptodome from 3.21.0 to 3.22.0
dependabot[bot] Mar 26, 2025
4b12a99
Merge pull request #29 from smswithoutborders/dependabot/pip/pycrypto…
PromiseFru Mar 26, 2025
e11d064
build(deps): bump cryptography from 44.0.0 to 44.0.2
dependabot[bot] Mar 26, 2025
ad394a3
Merge pull request #28 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru Mar 26, 2025
aefd4c7
build(deps): bump version from 0.1.2 to 0.1.3.
PromiseFru Mar 26, 2025
78c6520
build(deps): bump cryptography from 44.0.2 to 44.0.3
dependabot[bot] May 5, 2025
cc0e25e
Merge pull request #31 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru May 6, 2025
9bf68f5
build(deps): bump version from 0.1.3 to 0.1.4.
PromiseFru May 6, 2025
02e673a
build(deps): bump cryptography from 44.0.3 to 45.0.3
dependabot[bot] May 26, 2025
3711760
Merge pull request #34 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru May 27, 2025
7080945
build(deps): bump pycryptodome from 3.22.0 to 3.23.0
dependabot[bot] May 27, 2025
0cb6872
Merge pull request #32 from smswithoutborders/dependabot/pip/pycrypto…
PromiseFru May 27, 2025
b8f0680
build(deps): bump version from 0.1.4 to 0.1.5
PromiseFru May 27, 2025
100be0d
build(deps): bump cryptography from 45.0.3 to 45.0.5
dependabot[bot] Jul 7, 2025
a513354
Merge pull request #36 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru Jul 15, 2025
2fe3209
build(deps): bump version from 0.1.5 to 0.1.6
PromiseFru Jul 15, 2025
819dfbe
build(deps): bump cryptography from 45.0.5 to 45.0.6
dependabot[bot] Aug 11, 2025
f46e0e9
Merge pull request #37 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru Aug 12, 2025
2c028c8
build(deps): bump version from 0.1.6 to 0.1.7
PromiseFru Aug 12, 2025
03706de
build(deps): bump cffi from 1.17.1 to 2.0.0
dependabot[bot] Sep 15, 2025
52f80e0
Merge pull request #40 from smswithoutborders/dependabot/pip/cffi-2.0.0
PromiseFru Sep 16, 2025
1188eba
build(deps): bump pycparser from 2.22 to 2.23
dependabot[bot] Sep 16, 2025
d03b056
Merge pull request #39 from smswithoutborders/dependabot/pip/pycparse…
PromiseFru Sep 16, 2025
51615fe
build(deps): bump cryptography from 45.0.6 to 45.0.7
dependabot[bot] Sep 16, 2025
a1983b5
Merge pull request #38 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru Sep 16, 2025
6e7b33e
build(deps): bump version from 0.1.7 to 0.1.8
PromiseFru Sep 16, 2025
1f3d4b1
build(deps): bump cryptography from 45.0.7 to 46.0.1
dependabot[bot] Sep 22, 2025
fc9f151
Merge pull request #41 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru Sep 23, 2025
ecfa907
build(deps): bump version from 0.1.8 to 0.1.9
PromiseFru Sep 23, 2025
37e2f77
build(deps): bump cryptography from 46.0.1 to 46.0.2
dependabot[bot] Oct 6, 2025
941844d
Merge pull request #42 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru Oct 7, 2025
61d8ba2
build(deps): bump version from 0.1.9 to 0.1.10
PromiseFru Oct 7, 2025
ea2fbeb
build(deps): bump cryptography from 46.0.2 to 46.0.3
dependabot[bot] Oct 20, 2025
c9f4a1e
Merge pull request #43 from smswithoutborders/dependabot/pip/cryptogr…
PromiseFru Oct 21, 2025
3782539
build(deps): bump version from 0.1.10 to 0.1.11
PromiseFru Oct 21, 2025
8e07cbd
refactor(keypairs): Use constant-time comparison for secret keys in e…
PromiseFru Nov 13, 2025
83d4d7c
refactor(protocols): improve formatting and readability
PromiseFru Nov 13, 2025
03df5fe
fix(protocols): use constant-time compare for secrets
PromiseFru Nov 13, 2025
a8e2811
test(protocols): add comprehensive protocol tests
PromiseFru Nov 13, 2025
86da234
feat(protocols): add JSON serialization for States
PromiseFru Dec 3, 2025
7daae75
refactor: remove ecdsa dependency and ECDH keypair class
PromiseFru Dec 3, 2025
be4ec8a
Bump version from 0.1.11 to 0.2.0
PromiseFru Dec 11, 2025
896860d
refactor(protocols): remove __eq__ methods from core classes
PromiseFru Dec 15, 2025
0208bad
build(deps): bump sqlcipher3 from 0.5.4 to 0.6.0
dependabot[bot] Jan 5, 2026
57d8c88
Merge pull request #45 from smswithoutborders/dependabot/pip/sqlciphe…
PromiseFru Jan 6, 2026
e9d4f42
merge staging into main
PromiseFru Jan 6, 2026
d28908f
chore: remove .DS_Store and add to .gitignore
PromiseFru Jan 6, 2026
965c76c
Merge branch 'staging'
PromiseFru Jan 6, 2026
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
Binary file removed .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,4 @@ sample.py
vault.py
parser.py
*.pem
.DS_Store
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.1
0.2.0
13 changes: 6 additions & 7 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
cffi==1.17.1
cryptography==44.0.0
ecdsa==0.19.0
pycparser==2.22
pycryptodome==3.21.0
six==1.16.0
sqlcipher3==0.5.4
cffi==2.0.0
cryptography==46.0.3
pycparser==2.23
pycryptodome==3.23.0
six==1.17.0
sqlcipher3==0.6.0
104 changes: 43 additions & 61 deletions smswithoutborders_libsig/keypairs.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
#!/usr/bin/env python3

from abc import ABC, abstractmethod

# X25519
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
from cryptography.hazmat.primitives import serialization
import binascii
import base64
import binascii
import secrets
import struct
import uuid
from typing import Self

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric.x25519 import (
X25519PrivateKey,
X25519PublicKey,
)
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

from smswithoutborders_libsig.keystore import Keystore

import base64
import secrets
import uuid
import struct
from typing import Self # Available in Python 3.11+

class x25519:
def __init__(self, keystore_path=None, pnt_keystore=None, secret_key=None):
Expand All @@ -40,56 +39,56 @@ def init(self):
if not self.keystore_path:
self.keystore_path = f"db_keys/{self.pnt_keystore}.db"

self.secret_key = self.store(pk, _pk, self.keystore_path,
self.pnt_keystore, secret_key=self.secret_key)
self.secret_key = self.store(
pk, _pk, self.keystore_path, self.pnt_keystore, secret_key=self.secret_key
)
return pk

def serialize(self) -> bytes:
"""
"""
if not hasattr(self, 'pnt_keystore') or self.pnt_keystore == None or \
not hasattr(self, 'keystore_path') or self.keystore_path == None or \
not hasattr(self, 'secret_key') or self.secret_key == None:
""" """
if (
not hasattr(self, "pnt_keystore")
or self.pnt_keystore == None
or not hasattr(self, "keystore_path")
or self.keystore_path == None
or not hasattr(self, "secret_key")
or self.secret_key == None
):
raise Exception("keypair not initialized -- init()")

keystore_path_len = len(self.keystore_path)
pnt_keystore_len = len(self.pnt_keystore)
return struct.pack("<ii", keystore_path_len, pnt_keystore_len) + \
self.keystore_path.encode() + \
self.pnt_keystore.encode() + self.secret_key.encode()
return (
struct.pack("<ii", keystore_path_len, pnt_keystore_len)
+ self.keystore_path.encode()
+ self.pnt_keystore.encode()
+ self.secret_key.encode()
)

def deserialize(self, data) -> Self:
"""
"""
""" """
x = x25519()

keystore_path_len, pnt_keystore_len = struct.unpack("<ii", data[0:8])
x.keystore_path = data[8 : (8 + keystore_path_len)].decode()
x.pnt_keystore = data[(8 + keystore_path_len) : (8 + keystore_path_len + pnt_keystore_len)].decode()
x.secret_key = data[(8 + keystore_path_len + pnt_keystore_len):].decode()
x.pnt_keystore = data[
(8 + keystore_path_len) : (8 + keystore_path_len + pnt_keystore_len)
].decode()
x.secret_key = data[(8 + keystore_path_len + pnt_keystore_len) :].decode()
return x

def __eq__(self, other):
if not isinstance(other, self):
return NotImplemented

return (other.keystore_path == self.keystore_path and
other.pnt_keystore == self.pnt_keystore and
other.secret_key == self.secret_key)

def load_keystore(self, pnt_keystore: str, secret_key: bytes):
if not self.keystore_path:
self.keystore_path = f"db_keys/{pnt_keystore}.db"
ppk = self.fetch(pnt_keystore, secret_key, self.keystore_path )
ppk = self.fetch(pnt_keystore, secret_key, self.keystore_path)
if ppk:
self.pnt_keystore = pnt_keystore
self.secret_key = secret_key

return X25519PrivateKey.from_private_bytes(ppk[1])


def get_public_key(self):
ppk = self.fetch(self.pnt_keystore, self.secret_key, self.keystore_path )
ppk = self.fetch(self.pnt_keystore, self.secret_key, self.keystore_path)
if ppk:
return ppk[0]

Expand All @@ -100,7 +99,7 @@ def agree(self, public_key, info=b"x25591_key_exchange", salt=None) -> bytes:

def store(self, pk, _pk, keystore_path, pnt_keystore, secret_key=None) -> bytes:
if not secret_key:
secret_key = secrets.token_bytes(self.size) # store this
secret_key = secrets.token_bytes(self.size) # store this

keystore = Keystore(keystore_path, secret_key)
keystore.store(keypair=(pk, _pk), pnt=pnt_keystore)
Expand All @@ -110,32 +109,15 @@ def store(self, pk, _pk, keystore_path, pnt_keystore, secret_key=None) -> bytes:
def fetch(self, pnt_keystore, secret_key, keystore_path=None):
keystore = Keystore(keystore_path, secret_key)
return keystore.fetch(pnt_keystore)


def __agree__(self, secret_key, info=b"x25591_key_exchange", salt=None):
return HKDF(algorithm=hashes.SHA256(),
length=self.size, salt=salt, info=info,).derive(secret_key)
return HKDF(
algorithm=hashes.SHA256(),
length=self.size,
salt=salt,
info=info,
).derive(secret_key)

def migrate(self, old_key: str) -> str:
dec_key = base64.b64decode(old_key)
return binascii.hexlify(dec_key).decode("ascii")


if __name__ == "__main__":
client1 = x25519()
client1_public_key = client1.init()

client2 = x25519()
client2_public_key = client2.init()

dk = client1.agree(client2_public_key)
dk1 = client2.agree(client1_public_key)

assert(dk != None)
assert(dk1 != None)
assert(dk == dk1)

s_c1 = client1.serialize()
d_c1 = client1.deserialize(s_c1)

assert(d_c1 == client1)
Loading