From 77010bd02a7d6849db246d75ba1081ca3e7b996e Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Mon, 29 Jul 2024 10:09:26 -0600 Subject: [PATCH 1/7] move Cipher related Codices to core.signing.py so same place as Cipher --- src/keri/core/coring.py | 109 ------------------------------------ src/keri/core/signing.py | 112 +++++++++++++++++++++++++++++++++++++ tests/core/test_signing.py | 57 +++++++++---------- 3 files changed, 141 insertions(+), 137 deletions(-) diff --git a/src/keri/core/coring.py b/src/keri/core/coring.py index 2c47104e1..ebbab6309 100644 --- a/src/keri/core/coring.py +++ b/src/keri/core/coring.py @@ -465,115 +465,6 @@ def __iter__(self): TexDex = TextCodex() # Make instance -@dataclass(frozen=True) -class CipherX25519VarCodex: - """ - CipherX25519VarCodex is codex all variable sized cipher bytes derivation codes - for sealed box encryped ciphertext. Plaintext is B2. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_L0: str = '4D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 0 - X25519_Cipher_L1: str = '5D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 1 - X25519_Cipher_L2: str = '6D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 2 - X25519_Cipher_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 0 - X25519_Cipher_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 1 - X25519_Cipher_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 2 - - def __iter__(self): - return iter(astuple(self)) - - -CiXVarDex = CipherX25519VarCodex() # Make instance - - -@dataclass(frozen=True) -class CipherX25519FixQB64Codex: - """ - CipherX25519FixQB64Codex is codex all fixed sized cipher bytes derivation codes - for sealed box encryped ciphertext. Plaintext is B64. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed - X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt - - def __iter__(self): - return iter(astuple(self)) - - -CiXFixQB64Dex = CipherX25519FixQB64Codex() # Make instance - - -@dataclass(frozen=True) -class CipherX25519VarQB64Codex: - """ - CipherX25519VarQB64Codex is codex all variable sized cipher bytes derivation codes - for sealed box encryped ciphertext. Plaintext is QB64. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 - X25519_Cipher_QB64_L1: str = '5E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 - X25519_Cipher_QB64_L2: str = '6E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 - X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 - X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 - X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 - - def __iter__(self): - return iter(astuple(self)) - - -CiXVarQB64Dex = CipherX25519VarQB64Codex() # Make instance - - -@dataclass(frozen=True) -class CipherX25519AllQB64Codex: - """ - CipherX25519AllQB64Codex is codex all both fixed and variable sized cipher bytes - derivation codes for sealed box encryped ciphertext. Plaintext is B64. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed - X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt - X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 - X25519_Cipher_QB64_L1: str = '5E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 - X25519_Cipher_QB64_L2: str = '6E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 - X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 - X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 - X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 - - def __iter__(self): - return iter(astuple(self)) - - -CiXAllQB64Dex = CipherX25519AllQB64Codex() # Make instance - - -@dataclass(frozen=True) -class CipherX25519QB2VarCodex: - """ - CipherX25519QB2VarCodex is codex all variable sized cipher bytes derivation codes - for sealed box encryped ciphertext. Plaintext is B2. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_L0: str = '4E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 0 - X25519_Cipher_L1: str = '5E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 1 - X25519_Cipher_L2: str = '6E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 2 - X25519_Cipher_Big_L0: str = '7AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 0 - X25519_Cipher_Big_L1: str = '8AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 1 - X25519_Cipher_Big_L2: str = '9AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 2 - - def __iter__(self): - return iter(astuple(self)) - - -CiXVarQB2Dex = CipherX25519QB2VarCodex() # Make instance - - - @dataclass(frozen=True) class NonTransCodex: diff --git a/src/keri/core/signing.py b/src/keri/core/signing.py index 875ce179b..404c77062 100644 --- a/src/keri/core/signing.py +++ b/src/keri/core/signing.py @@ -4,6 +4,7 @@ Provides support Signer class """ +from dataclasses import dataclass, astuple, asdict import pysodium @@ -25,6 +26,117 @@ ECDSA_256k1_SEEDBYTES = 32 +@dataclass(frozen=True) +class CipherX25519VarCodex: + """ + CipherX25519VarCodex is codex all variable sized cipher bytes derivation codes + for sealed box encryped ciphertext. Plaintext is B2. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_L0: str = '4D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 0 + X25519_Cipher_L1: str = '5D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 1 + X25519_Cipher_L2: str = '6D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 2 + X25519_Cipher_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 0 + X25519_Cipher_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 1 + X25519_Cipher_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + + +CiXVarDex = CipherX25519VarCodex() # Make instance + + +@dataclass(frozen=True) +class CipherX25519FixQB64Codex: + """ + CipherX25519FixQB64Codex is codex all fixed sized cipher bytes derivation codes + for sealed box encryped ciphertext. Plaintext is B64. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed + X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt + + def __iter__(self): + return iter(astuple(self)) + + +CiXFixQB64Dex = CipherX25519FixQB64Codex() # Make instance + + +@dataclass(frozen=True) +class CipherX25519VarQB64Codex: + """ + CipherX25519VarQB64Codex is codex all variable sized cipher bytes derivation codes + for sealed box encryped ciphertext. Plaintext is QB64. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 + X25519_Cipher_QB64_L1: str = '5E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 + X25519_Cipher_QB64_L2: str = '6E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 + X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 + X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 + X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + + +CiXVarQB64Dex = CipherX25519VarQB64Codex() # Make instance + + +@dataclass(frozen=True) +class CipherX25519AllQB64Codex: + """ + CipherX25519AllQB64Codex is codex all both fixed and variable sized cipher bytes + derivation codes for sealed box encryped ciphertext. Plaintext is B64. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed + X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt + X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 + X25519_Cipher_QB64_L1: str = '5E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 + X25519_Cipher_QB64_L2: str = '6E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 + X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 + X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 + X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + + +CiXAllQB64Dex = CipherX25519AllQB64Codex() # Make instance + + +@dataclass(frozen=True) +class CipherX25519QB2VarCodex: + """ + CipherX25519QB2VarCodex is codex all variable sized cipher bytes derivation codes + for sealed box encryped ciphertext. Plaintext is B2. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_L0: str = '4E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 0 + X25519_Cipher_L1: str = '5E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 1 + X25519_Cipher_L2: str = '6E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 2 + X25519_Cipher_Big_L0: str = '7AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 0 + X25519_Cipher_Big_L1: str = '8AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 1 + X25519_Cipher_Big_L2: str = '9AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + + +CiXVarQB2Dex = CipherX25519QB2VarCodex() # Make instance + + + + + class Signer(Matter): """ Signer is Matter subclass with method to create signature of serialization diff --git a/tests/core/test_signing.py b/tests/core/test_signing.py index f0e519db2..b38477183 100644 --- a/tests/core/test_signing.py +++ b/tests/core/test_signing.py @@ -375,33 +375,6 @@ def test_signer(): """ Done Test """ -def test_generatesigners(): - """ - Test the support function genSigners - - """ - signers = Salter().signers(count=2, temp=True, transferable=False) - assert len(signers) == 2 - for signer in signers: - assert signer.verfer.code == MtrDex.Ed25519N - - # raw = pysodium.randombytes(pysodium.crypto_pwhash_SALTBYTES) # raw salt - raw = b'g\x15\x89\x1a@\xa4\xa47\x07\xb9Q\xb8\x18\xcdJW' - assert len(raw) == 16 - signers = Salter(raw=raw).signers(count=4) - assert len(signers) == 4 - for signer in signers: - assert signer.code == MtrDex.Ed25519_Seed - assert signer.verfer.code == MtrDex.Ed25519 - - sigkeys = [signer.qb64 for signer in signers] - assert sigkeys == ['AK8F6AAiYDpXlWdj2O5F5-6wNCCNJh2A4XOlqwR_HwwH', - 'AOs8-zNPPh0EhavdrCfCiTk9nGeO8e6VxUCzwdKXJAd0', - 'AHMBU5PsIJN2U9m7j0SGyvs8YD8fkym2noELzxIrzfdG', - 'AJZ7ZLd7unQ4IkMUwE69NXcvDO9rrmmRH_Xk3TPu9BpP'] - - """ End Test """ - def test_salter(): """ @@ -452,6 +425,34 @@ def test_salter(): """ Done Test """ +def test_gensignerswithsalter(): + """ + Test generating a set of signers using Salter + + """ + signers = Salter().signers(count=2, temp=True, transferable=False) + assert len(signers) == 2 + for signer in signers: + assert signer.verfer.code == MtrDex.Ed25519N + + # raw = pysodium.randombytes(pysodium.crypto_pwhash_SALTBYTES) # raw salt + raw = b'g\x15\x89\x1a@\xa4\xa47\x07\xb9Q\xb8\x18\xcdJW' + assert len(raw) == 16 + signers = Salter(raw=raw).signers(count=4) + assert len(signers) == 4 + for signer in signers: + assert signer.code == MtrDex.Ed25519_Seed + assert signer.verfer.code == MtrDex.Ed25519 + + sigkeys = [signer.qb64 for signer in signers] + assert sigkeys == ['AK8F6AAiYDpXlWdj2O5F5-6wNCCNJh2A4XOlqwR_HwwH', + 'AOs8-zNPPh0EhavdrCfCiTk9nGeO8e6VxUCzwdKXJAd0', + 'AHMBU5PsIJN2U9m7j0SGyvs8YD8fkym2noELzxIrzfdG', + 'AJZ7ZLd7unQ4IkMUwE69NXcvDO9rrmmRH_Xk3TPu9BpP'] + + """ End Test """ + + def test_cipher(): """ Test Cipher subclass of Matter @@ -702,8 +703,8 @@ def test_decrypter(): if __name__ == "__main__": test_signer() - test_generatesigners() test_salter() + test_gensignerswithsalter() test_cipher() test_encrypter() test_decrypter() From b8d56b842a8bb238e447296609a8f4dfbb1fed48 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Mon, 29 Jul 2024 11:56:27 -0600 Subject: [PATCH 2/7] Started adding support for variable sized ciphers to Cipher --- src/keri/core/__init__.py | 2 +- src/keri/core/signing.py | 307 +++++++++++++++++++++++-------------- tests/core/test_signing.py | 51 +++++- 3 files changed, 240 insertions(+), 120 deletions(-) diff --git a/src/keri/core/__init__.py b/src/keri/core/__init__.py index 734d8259c..1042deb62 100644 --- a/src/keri/core/__init__.py +++ b/src/keri/core/__init__.py @@ -14,5 +14,5 @@ from .coring import Tholder from .indexing import Indexer, Siger, IdrDex, IdxSigDex -from .signing import Signer, Salter, Cipher, Encrypter, Decrypter +from .signing import Signer, Salter, Cipher, CiXDex, Encrypter, Decrypter from .counting import Counter, Codens diff --git a/src/keri/core/signing.py b/src/keri/core/signing.py index 404c77062..298e5b78f 100644 --- a/src/keri/core/signing.py +++ b/src/keri/core/signing.py @@ -12,7 +12,7 @@ from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat from cryptography.hazmat.primitives.asymmetric import ec, utils -from ..kering import (EmptyMaterialError,) +from ..kering import (EmptyMaterialError, InvalidSizeError, InvalidVarRawSizeError) from ..help import helping @@ -26,115 +26,6 @@ ECDSA_256k1_SEEDBYTES = 32 -@dataclass(frozen=True) -class CipherX25519VarCodex: - """ - CipherX25519VarCodex is codex all variable sized cipher bytes derivation codes - for sealed box encryped ciphertext. Plaintext is B2. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_L0: str = '4D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 0 - X25519_Cipher_L1: str = '5D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 1 - X25519_Cipher_L2: str = '6D' # X25519 sealed box cipher bytes of sniffable plaintext lead size 2 - X25519_Cipher_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 0 - X25519_Cipher_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 1 - X25519_Cipher_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 2 - - def __iter__(self): - return iter(astuple(self)) - - -CiXVarDex = CipherX25519VarCodex() # Make instance - - -@dataclass(frozen=True) -class CipherX25519FixQB64Codex: - """ - CipherX25519FixQB64Codex is codex all fixed sized cipher bytes derivation codes - for sealed box encryped ciphertext. Plaintext is B64. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed - X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt - - def __iter__(self): - return iter(astuple(self)) - - -CiXFixQB64Dex = CipherX25519FixQB64Codex() # Make instance - - -@dataclass(frozen=True) -class CipherX25519VarQB64Codex: - """ - CipherX25519VarQB64Codex is codex all variable sized cipher bytes derivation codes - for sealed box encryped ciphertext. Plaintext is QB64. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 - X25519_Cipher_QB64_L1: str = '5E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 - X25519_Cipher_QB64_L2: str = '6E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 - X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 - X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 - X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 - - def __iter__(self): - return iter(astuple(self)) - - -CiXVarQB64Dex = CipherX25519VarQB64Codex() # Make instance - - -@dataclass(frozen=True) -class CipherX25519AllQB64Codex: - """ - CipherX25519AllQB64Codex is codex all both fixed and variable sized cipher bytes - derivation codes for sealed box encryped ciphertext. Plaintext is B64. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed - X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt - X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 - X25519_Cipher_QB64_L1: str = '5E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 - X25519_Cipher_QB64_L2: str = '6E' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 - X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 - X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 - X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 - - def __iter__(self): - return iter(astuple(self)) - - -CiXAllQB64Dex = CipherX25519AllQB64Codex() # Make instance - - -@dataclass(frozen=True) -class CipherX25519QB2VarCodex: - """ - CipherX25519QB2VarCodex is codex all variable sized cipher bytes derivation codes - for sealed box encryped ciphertext. Plaintext is B2. - Only provide defined codes. - Undefined are left out so that inclusion(exclusion) via 'in' operator works. - """ - X25519_Cipher_L0: str = '4E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 0 - X25519_Cipher_L1: str = '5E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 1 - X25519_Cipher_L2: str = '6E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 2 - X25519_Cipher_Big_L0: str = '7AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 0 - X25519_Cipher_Big_L1: str = '8AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 1 - X25519_Cipher_Big_L2: str = '9AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 2 - - def __iter__(self): - return iter(astuple(self)) - - -CiXVarQB2Dex = CipherX25519QB2VarCodex() # Make instance - - - class Signer(Matter): @@ -588,6 +479,153 @@ def signers(self, count=1, start=0, path="", **kwa): return [self.signer(path=f"{path}{i + start:x}", **kwa) for i in range(count)] + + +# Codes for for ciphers of variable sized sniffable QB2 or QB64 plain text +@dataclass(frozen=True) +class CipherX25519VarSnifCodex: + """ + CipherX25519VarCodex is codex all variable sized cipher bytes derivation codes + for sealed box encryped ciphertext. Plaintext is Sniffable QB2 or QB64. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_L0: str = '4C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 0 + X25519_Cipher_L1: str = '5C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 1 + X25519_Cipher_L2: str = '6C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 2 + X25519_Cipher_Big_L0: str = '7AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 0 + X25519_Cipher_Big_L1: str = '8AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 1 + X25519_Cipher_Big_L2: str = '9AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + +CiXVarSnifDex = CipherX25519VarSnifCodex() # Make instance + + +# Codes for for ciphers of variable sized QB64 plain text +@dataclass(frozen=True) +class CipherX25519VarQB64Codex: + """ + CipherX25519VarQB64Codex is codex all variable sized cipher bytes derivation codes + for sealed box encryped ciphertext. Plaintext is QB64. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 + X25519_Cipher_QB64_L1: str = '5D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 + X25519_Cipher_QB64_L2: str = '6D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 + X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 + X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 + X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + +CiXVarQB64Dex = CipherX25519VarQB64Codex() # Make instance + +# Codes for for ciphers of fixed sized QB64 plain text +@dataclass(frozen=True) +class CipherX25519FixQB64Codex: + """ + CipherX25519FixQB64Codex is codex all fixed sized cipher bytes derivation codes + for sealed box encryped ciphertext. Plaintext is B64. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed + X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt + + def __iter__(self): + return iter(astuple(self)) + +CiXFixQB64Dex = CipherX25519FixQB64Codex() # Make instance + +# Codes for for ciphers of all sizes fixed and variable of QB64 plain text +@dataclass(frozen=True) +class CipherX25519AllQB64Codex: + """ + CipherX25519AllQB64Codex is codex all both fixed and variable sized cipher bytes + derivation codes for sealed box encryped ciphertext. Plaintext is B64. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed + X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt + X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 + X25519_Cipher_QB64_L1: str = '5D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 + X25519_Cipher_QB64_L2: str = '6D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 + X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 + X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 + X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + +CiXAllQB64Dex = CipherX25519AllQB64Codex() # Make instance + + + +# Codes for for ciphers of variable sized QB2 plain text +@dataclass(frozen=True) +class CipherX25519QB2VarCodex: + """ + CipherX25519QB2VarCodex is codex all variable sized cipher bytes derivation codes + for sealed box encryped ciphertext. Plaintext is B2. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_QB2_L0: str = '4E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 0 + X25519_Cipher_QB2_L1: str = '5E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 1 + X25519_Cipher_QB2_L2: str = '6E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 2 + X25519_Cipher_QB2_Big_L0: str = '7AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 0 + X25519_Cipher_QB2_Big_L1: str = '8AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 1 + X25519_Cipher_QB2_Big_L2: str = '9AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + +CiXVarQB2Dex = CipherX25519QB2VarCodex() # Make instance + + +# Codes for for ciphers of all sizes and all types of plain text +@dataclass(frozen=True) +class CipherX25519AllCodex: + """ + CipherX25519AllCodex is codex all codes and types of cipher bytes + for sealed box encryped ciphertext. Plaintext maybe sniffable or qb64 or qb2. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_L0: str = '4C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 0 + X25519_Cipher_L1: str = '5C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 1 + X25519_Cipher_L2: str = '6C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 2 + X25519_Cipher_Big_L0: str = '7AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 0 + X25519_Cipher_Big_L1: str = '8AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 1 + X25519_Cipher_Big_L2: str = '9AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 2 + X25519_Cipher_Seed: str = 'P' # X25519 sealed box 124 char qb64 Cipher of 44 char qb64 Seed + X25519_Cipher_Salt: str = '1AAH' # X25519 sealed box 100 char qb64 Cipher of 24 char qb64 Salt + X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 + X25519_Cipher_QB64_L1: str = '5D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 + X25519_Cipher_QB64_L2: str = '6D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 + X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 + X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 + X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 + X25519_Cipher_QB2_L0: str = '4E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 0 + X25519_Cipher_QB2_L1: str = '5E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 1 + X25519_Cipher_QB2_L2: str = '6E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 2 + X25519_Cipher_QB2_Big_L0: str = '7AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 0 + X25519_Cipher_QB2_Big_L1: str = '8AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 1 + X25519_Cipher_QB2_Big_L2: str = '9AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + +CiXDex = CipherX25519AllCodex() # Make instance + + + + class Cipher(Matter): """ Cipher is Matter subclass holding a cipher text of a secret that may be @@ -605,18 +643,53 @@ class Cipher(Matter): See Matter for inherited attributes and properties """ + Codex = CiXDex + Codes = asdict(CiXDex) # map code name to code - def __init__(self, raw=None, code=None, **kwa): + def __init__(self, raw=None, code=None, fix=False, **kwa): """ Parmeters: - raw (Union[bytes, str]): cipher text + raw (bytes | str): cipher text code (str): cipher suite + """ - if raw is not None and code is None: - if len(raw) == Matter._rawSize(MtrDex.X25519_Cipher_Salt): - code = MtrDex.X25519_Cipher_Salt - elif len(raw) == Matter._rawSize(MtrDex.X25519_Cipher_Seed): - code = MtrDex.X25519_Cipher_Seed + if raw is not None: + if code is None or code in CiXFixQB64Dex: + if len(raw) == Matter._rawSize(MtrDex.X25519_Cipher_Salt): + code = MtrDex.X25519_Cipher_Salt + elif len(raw) == Matter._rawSize(MtrDex.X25519_Cipher_Seed): + code = MtrDex.X25519_Cipher_Seed + else: + raise InvalidSizeError(f"Unsupported fixed raw size" + f" {len(raw)} for {code=}.") + + #if code[0] in SmallVrzDex: # compute code with sizes + #if size <= (64 ** 2 - 1): # ss = 2 + #hs = 2 + #s = astuple(SmallVrzDex)[ls] + #code = f"{s}{code[1:hs]}" + #ss = 2 + #elif size <= (64 ** 4 - 1): # ss = 4 make big version of code + #hs = 4 + #s = astuple(LargeVrzDex)[ls] + #code = f"{s}{'A' * (hs - 2)}{code[1]}" + #soft = intToB64(size, 4) + #ss = 4 + #else: + #raise InvalidVarRawSizeError(f"Unsupported raw size for " + #f"{code=}.") + #elif code[0] in LargeVrzDex: # compute code with sizes + #if size <= (64 ** 4 - 1): # ss = 4 + #hs = 4 + #s = astuple(LargeVrzDex)[ls] + #code = f"{s}{code[1:hs]}" + #ss = 4 + #else: + #raise InvalidVarRawSizeError(f"Unsupported raw size for large " + #f"{code=}. {size} <= {64 ** 4 - 1}") + #else: + #raise InvalidVarRawSizeError(f"Unsupported variable raw size " + #f"{code=}.") if hasattr(raw, "encode"): raw = raw.encode("utf-8") # ensure bytes not str diff --git a/tests/core/test_signing.py b/tests/core/test_signing.py index b38477183..a9f4d98d4 100644 --- a/tests/core/test_signing.py +++ b/tests/core/test_signing.py @@ -11,8 +11,7 @@ from keri import kering from keri.core import (Indexer, IdrDex, ) from keri.core import (Matter, MtrDex, Cigar, Verfer, Prefixer) -from keri.core import (Signer, Salter, - Cipher, Encrypter, Decrypter, ) +from keri.core import (Signer, Salter, Cipher, CiXDex, Encrypter, Decrypter, ) from keri.core import (Tiers, ) @@ -452,6 +451,38 @@ def test_gensignerswithsalter(): """ End Test """ +def test_cipher_closs(): + """ + Test class attributes of Cipher + """ + assert Cipher.Codex == CiXDex + + assert Cipher.Codes == \ + { + 'X25519_Cipher_L0': '4C', + 'X25519_Cipher_L1': '5C', + 'X25519_Cipher_L2': '6C', + 'X25519_Cipher_Big_L0': '7AAC', + 'X25519_Cipher_Big_L1': '8AAC', + 'X25519_Cipher_Big_L2': '9AAC', + 'X25519_Cipher_Seed': 'P', + 'X25519_Cipher_Salt': '1AAH', + 'X25519_Cipher_QB64_L0': '4D', + 'X25519_Cipher_QB64_L1': '5D', + 'X25519_Cipher_QB64_L2': '6D', + 'X25519_Cipher_QB64_Big_L0': '7AAD', + 'X25519_Cipher_QB64_Big_L1': '8AAD', + 'X25519_Cipher_QB64_Big_L2': '9AAD', + 'X25519_Cipher_QB2_L0': '4E', + 'X25519_Cipher_QB2_L1': '5E', + 'X25519_Cipher_QB2_L2': '6E', + 'X25519_Cipher_QB2_Big_L0': '7AAE', + 'X25519_Cipher_QB2_Big_L1': '8AAE', + 'X25519_Cipher_QB2_Big_L2': '9AAE' + } + + """End Test""" + def test_cipher(): """ @@ -512,6 +543,21 @@ def test_cipher(): with pytest.raises(ValueError): # bad code cipher = Cipher(raw=raw, code=MtrDex.Ed25519N) + + # Test bad raw size + raw = pysodium.crypto_box_seal(seedqb64b, pubkey) # uses nonce so different everytime + with pytest.raises(kering.InvalidSizeError): + cipher = Cipher(raw=raw[:len(raw)-1]) # make raw too small + with pytest.raises(kering.InvalidSizeError): + cipher = Cipher(raw=raw + b'_') # make raw too big + + raw = pysodium.crypto_box_seal(saltqb64b, pubkey) # uses nonce so different everytime + with pytest.raises(kering.InvalidSizeError): + cipher = Cipher(raw=raw[:len(raw)-1]) # make raw too small + with pytest.raises(kering.InvalidSizeError): + cipher = Cipher(raw=raw + b'_') # make raw too big + + """ Done Test """ @@ -705,6 +751,7 @@ def test_decrypter(): test_signer() test_salter() test_gensignerswithsalter() + test_cipher_closs() test_cipher() test_encrypter() test_decrypter() From 486a5f33138242fcbc45d32df7a285080caec783 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Mon, 29 Jul 2024 12:32:09 -0600 Subject: [PATCH 3/7] some refactoring --- src/keri/core/signing.py | 81 +++++++++++++++++++++----------------- tests/core/test_signing.py | 2 +- 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/keri/core/signing.py b/src/keri/core/signing.py index 298e5b78f..716e796ad 100644 --- a/src/keri/core/signing.py +++ b/src/keri/core/signing.py @@ -12,12 +12,13 @@ from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat from cryptography.hazmat.primitives.asymmetric import ec, utils -from ..kering import (EmptyMaterialError, InvalidSizeError, InvalidVarRawSizeError) +from ..kering import (EmptyMaterialError, InvalidCodeError, InvalidSizeError, + InvalidVarRawSizeError) from ..help import helping from .coring import (Tiers, ) -from .coring import (Matter, MtrDex, Verfer, Cigar) +from .coring import (SmallVrzDex, LargeVrzDex, Matter, MtrDex, Verfer, Cigar) from .indexing import IdrDex, Siger @@ -587,6 +588,39 @@ def __iter__(self): CiXVarQB2Dex = CipherX25519QB2VarCodex() # Make instance +# Codes for for ciphers of all varibale sizes and all types of plain text +@dataclass(frozen=True) +class CipherX25519AllVarCodex: + """ + CipherX25519AllVarCodex is codex all variable size codes of cipher bytes + for sealed box encryped ciphertext. Plaintext maybe sniffable or qb64 or qb2. + Only provide defined codes. + Undefined are left out so that inclusion(exclusion) via 'in' operator works. + """ + X25519_Cipher_L0: str = '4C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 0 + X25519_Cipher_L1: str = '5C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 1 + X25519_Cipher_L2: str = '6C' # X25519 sealed box cipher bytes of sniffable plaintext lead size 2 + X25519_Cipher_Big_L0: str = '7AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 0 + X25519_Cipher_Big_L1: str = '8AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 1 + X25519_Cipher_Big_L2: str = '9AAC' # X25519 sealed box cipher bytes of sniffable plaintext big lead size 2 + X25519_Cipher_QB64_L0: str = '4D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 0 + X25519_Cipher_QB64_L1: str = '5D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 1 + X25519_Cipher_QB64_L2: str = '6D' # X25519 sealed box cipher bytes of QB64 plaintext lead size 2 + X25519_Cipher_QB64_Big_L0: str = '7AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 0 + X25519_Cipher_QB64_Big_L1: str = '8AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 1 + X25519_Cipher_QB64_Big_L2: str = '9AAD' # X25519 sealed box cipher bytes of QB64 plaintext big lead size 2 + X25519_Cipher_QB2_L0: str = '4E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 0 + X25519_Cipher_QB2_L1: str = '5E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 1 + X25519_Cipher_QB2_L2: str = '6E' # X25519 sealed box cipher bytes of QB2 plaintext lead size 2 + X25519_Cipher_QB2_Big_L0: str = '7AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 0 + X25519_Cipher_QB2_Big_L1: str = '8AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 1 + X25519_Cipher_QB2_Big_L2: str = '9AAE' # X25519 sealed box cipher bytes of QB2 plaintext big lead size 2 + + def __iter__(self): + return iter(astuple(self)) + +CiXVarDex = CipherX25519AllVarCodex() # Make instance + # Codes for for ciphers of all sizes and all types of plain text @dataclass(frozen=True) @@ -653,51 +687,26 @@ def __init__(self, raw=None, code=None, fix=False, **kwa): code (str): cipher suite """ - if raw is not None: - if code is None or code in CiXFixQB64Dex: + # default when raw is not None and code is None is to use fixed size + # code given by raw size. Otherwise provided code fixed or variable size + # is handled by Matter superclass. + if raw is not None and code is None: if len(raw) == Matter._rawSize(MtrDex.X25519_Cipher_Salt): code = MtrDex.X25519_Cipher_Salt elif len(raw) == Matter._rawSize(MtrDex.X25519_Cipher_Seed): code = MtrDex.X25519_Cipher_Seed else: raise InvalidSizeError(f"Unsupported fixed raw size" - f" {len(raw)} for {code=}.") - - #if code[0] in SmallVrzDex: # compute code with sizes - #if size <= (64 ** 2 - 1): # ss = 2 - #hs = 2 - #s = astuple(SmallVrzDex)[ls] - #code = f"{s}{code[1:hs]}" - #ss = 2 - #elif size <= (64 ** 4 - 1): # ss = 4 make big version of code - #hs = 4 - #s = astuple(LargeVrzDex)[ls] - #code = f"{s}{'A' * (hs - 2)}{code[1]}" - #soft = intToB64(size, 4) - #ss = 4 - #else: - #raise InvalidVarRawSizeError(f"Unsupported raw size for " - #f"{code=}.") - #elif code[0] in LargeVrzDex: # compute code with sizes - #if size <= (64 ** 4 - 1): # ss = 4 - #hs = 4 - #s = astuple(LargeVrzDex)[ls] - #code = f"{s}{code[1:hs]}" - #ss = 4 - #else: - #raise InvalidVarRawSizeError(f"Unsupported raw size for large " - #f"{code=}. {size} <= {64 ** 4 - 1}") - #else: - #raise InvalidVarRawSizeError(f"Unsupported variable raw size " - #f"{code=}.") + f" {len(raw)} for {code=}.") if hasattr(raw, "encode"): raw = raw.encode("utf-8") # ensure bytes not str super(Cipher, self).__init__(raw=raw, code=code, **kwa) - if self.code not in (MtrDex.X25519_Cipher_Salt, MtrDex.X25519_Cipher_Seed): - raise ValueError("Unsupported cipher code = {}.".format(self.code)) + if self.code not in CiXDex: + raise InvalidCodeError(f"Unsupported cipher code = {self.code}.") + def decrypt(self, prikey=None, seed=None): """ @@ -706,7 +715,7 @@ def decrypt(self, prikey=None, seed=None): qualified (qb64) so derivaton code of plain text preserved through encryption/decryption round trip. - Uses either decryption key given by prikey or derives prikey from + Decrypter uses either decryption key given by prikey or derives prikey from signing key derived from private seed. Parameters: diff --git a/tests/core/test_signing.py b/tests/core/test_signing.py index a9f4d98d4..1061c9a9f 100644 --- a/tests/core/test_signing.py +++ b/tests/core/test_signing.py @@ -541,7 +541,7 @@ def test_cipher(): cryptseedqb64 = Matter(raw=cryptseed, code=MtrDex.Ed25519_Seed).qb64b assert cipher.decrypt(seed=cryptseedqb64).qb64b == saltqb64b - with pytest.raises(ValueError): # bad code + with pytest.raises(kering.InvalidCodeError): # bad code cipher = Cipher(raw=raw, code=MtrDex.Ed25519N) # Test bad raw size From ad49eee6fcb27ea0ea4936a0f705808567b18c38 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Mon, 29 Jul 2024 12:37:17 -0600 Subject: [PATCH 4/7] updated Usage comment --- src/keri/help/helping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keri/help/helping.py b/src/keri/help/helping.py index 838f69bf4..5333887e5 100644 --- a/src/keri/help/helping.py +++ b/src/keri/help/helping.py @@ -266,7 +266,7 @@ def fromIso8601(dts): B64REX = rb'^[0-9A-Za-z_-]*\Z' # [A-Za-z0-9\-\_] Reb64 = re.compile(B64REX) # compile is faster -# to use if Reb64.match(bext): +# Usage: if Reb64.match(bext): or if not Reb64.match(bext): def intToB64(i, l=1): From e6274a7b4f5d8c346b2486c119093996fbbba52c Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Mon, 29 Jul 2024 12:51:14 -0600 Subject: [PATCH 5/7] some refactoring --- src/keri/core/signing.py | 8 ++++---- src/keri/kering.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/keri/core/signing.py b/src/keri/core/signing.py index 716e796ad..79e08e238 100644 --- a/src/keri/core/signing.py +++ b/src/keri/core/signing.py @@ -13,7 +13,7 @@ from cryptography.hazmat.primitives.asymmetric import ec, utils from ..kering import (EmptyMaterialError, InvalidCodeError, InvalidSizeError, - InvalidVarRawSizeError) + RawMaterialError) from ..help import helping @@ -670,7 +670,7 @@ class Cipher(Matter): private key for decryption. The default is to use X25519 sealed box encryption. The Cipher instances .raw is the raw binary encrypted cipher text and its - .code indicates what type of secret has been encrypted. The cipher suite used + .code indicates what type of plain text has been encrypted. The cipher suite used for the encryption/decryption is implied by the context where the cipher is used. @@ -680,10 +680,10 @@ class Cipher(Matter): Codex = CiXDex Codes = asdict(CiXDex) # map code name to code - def __init__(self, raw=None, code=None, fix=False, **kwa): + def __init__(self, raw=None, code=None, **kwa): """ Parmeters: - raw (bytes | str): cipher text + raw (bytes | str): cipher text (not plain text) code (str): cipher suite """ diff --git a/src/keri/kering.py b/src/keri/kering.py index 725e3b961..2177b1be8 100644 --- a/src/keri/kering.py +++ b/src/keri/kering.py @@ -461,7 +461,7 @@ class MaterialError(KeriError): class RawMaterialError(MaterialError): """ - Not Enough bytes in buffer bytearray for raw material + Invalid raw material Usage: raise RawMaterialError("error message") """ @@ -469,7 +469,7 @@ class RawMaterialError(MaterialError): class SoftMaterialError(MaterialError): """ - Not Enough chars in soft for soft material + Invalid soft material Usage: raise SoftMaterialError("error message") """ From c7c547f306eb5d1ee6c555a9ad05abb2cc46976b Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Mon, 29 Jul 2024 12:51:56 -0600 Subject: [PATCH 6/7] removed unused import --- src/keri/core/signing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/keri/core/signing.py b/src/keri/core/signing.py index 79e08e238..dcfaec05a 100644 --- a/src/keri/core/signing.py +++ b/src/keri/core/signing.py @@ -12,8 +12,7 @@ from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat from cryptography.hazmat.primitives.asymmetric import ec, utils -from ..kering import (EmptyMaterialError, InvalidCodeError, InvalidSizeError, - RawMaterialError) +from ..kering import (EmptyMaterialError, InvalidCodeError, InvalidSizeError) from ..help import helping From 4678826605cec4de46fa042514ccab23752fe663 Mon Sep 17 00:00:00 2001 From: Samuel M Smith Date: Mon, 29 Jul 2024 15:41:16 -0600 Subject: [PATCH 7/7] Finished support in Cipher for variable sized raw of all the types Sniffable, QB64, and QB2 with unit tests. --- src/keri/core/__init__.py | 2 +- src/keri/core/coring.py | 2 +- tests/core/test_signing.py | 185 ++++++++++++++++++++++++++++++++++++- 3 files changed, 185 insertions(+), 4 deletions(-) diff --git a/src/keri/core/__init__.py b/src/keri/core/__init__.py index 1042deb62..ec83d8bbb 100644 --- a/src/keri/core/__init__.py +++ b/src/keri/core/__init__.py @@ -15,4 +15,4 @@ from .coring import Tholder from .indexing import Indexer, Siger, IdrDex, IdxSigDex from .signing import Signer, Salter, Cipher, CiXDex, Encrypter, Decrypter -from .counting import Counter, Codens +from .counting import Counter, Codens, CtrDex_2_0 diff --git a/src/keri/core/coring.py b/src/keri/core/coring.py index ebbab6309..5896ffe09 100644 --- a/src/keri/core/coring.py +++ b/src/keri/core/coring.py @@ -622,7 +622,7 @@ class Matter: Names (dict): maps code to code name Pad (str): B64 pad char for xtra size pre-padded soft values - Calss Methods: + Class Methods: Attributes: diff --git a/tests/core/test_signing.py b/tests/core/test_signing.py index 1061c9a9f..9b8ec4d16 100644 --- a/tests/core/test_signing.py +++ b/tests/core/test_signing.py @@ -3,12 +3,12 @@ tests.core.test_indexing module """ - +from base64 import urlsafe_b64decode as decodeB64 import pysodium import pytest -from keri import kering +from keri import kering, core from keri.core import (Indexer, IdrDex, ) from keri.core import (Matter, MtrDex, Cigar, Verfer, Prefixer) from keri.core import (Signer, Salter, Cipher, CiXDex, Encrypter, Decrypter, ) @@ -521,6 +521,11 @@ def test_cipher(): uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) assert uncb == seedqb64b + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_Seed) + assert cipher.code == MtrDex.X25519_Cipher_Seed + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == seedqb64b + # test .decrypt method needs qb64 prikeyqb64 = Matter(raw=prikey, code=MtrDex.X25519_Private).qb64b assert cipher.decrypt(prikey=prikeyqb64).qb64b == seedqb64b @@ -528,12 +533,27 @@ def test_cipher(): cryptseedqb64 = Matter(raw=cryptseed, code=MtrDex.Ed25519_Seed).qb64b assert cipher.decrypt(seed=cryptseedqb64).qb64b == seedqb64b + # wrong but shorter code so instance creation succeeds + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_Salt) + assert cipher.code == MtrDex.X25519_Cipher_Salt + with pytest.raises(ValueError): # but decryption fails + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + + raw = pysodium.crypto_box_seal(saltqb64b, pubkey) # uses nonce so different everytime cipher = Cipher(raw=raw) assert cipher.code == MtrDex.X25519_Cipher_Salt uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) assert uncb == saltqb64b + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_Salt) + assert cipher.code == MtrDex.X25519_Cipher_Salt + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == saltqb64b + + with pytest.raises(kering.RawMaterialError): # wrong code to big for raw bytes + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_Seed) + # test .decrypt method needs qb64 prikeyqb64 = Matter(raw=prikey, code=MtrDex.X25519_Private).qb64b assert cipher.decrypt(prikey=prikeyqb64).qb64b == saltqb64b @@ -557,6 +577,167 @@ def test_cipher(): with pytest.raises(kering.InvalidSizeError): cipher = Cipher(raw=raw + b'_') # make raw too big + # variable sized ciphers + # Always init with L0 code and let Matter auto correct the code for the + # actual lead size of raw + + # qb64 lead 0 + plain = "The quick brown fox jumps over the lazy " + texter = core.Texter(text=plain) + assert texter.text == plain + raw = pysodium.crypto_box_seal(texter.qb64b, pubkey) # uses nonce so different everytime + assert len(raw) == 108 + assert (3 - (len(raw) % 3)) % 3 == 0 + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_QB64_L0) + assert cipher.code == CiXDex.X25519_Cipher_QB64_L0 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == texter.qb64b + texter = core.Texter(qb64b=uncb) + assert texter.text == plain + + # qb64 lead 1 + plain = "The quick brown fox jumps over the lazy dogcats" + texter = core.Texter(text=plain) + assert texter.text == plain + raw = pysodium.crypto_box_seal(texter.qb64b, pubkey) # uses nonce so different everytime + assert len(raw) == 116 + assert (3 - (len(raw) % 3)) % 3 == 1 + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_QB64_L0) + assert cipher.code == CiXDex.X25519_Cipher_QB64_L1 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == texter.qb64b + texter = core.Texter(qb64b=uncb) + assert texter.text == plain + + # qb64 lead 2 + plain = "The quick brown fox jumps over the lazy dog" + texter = core.Texter(text=plain) + assert texter.text == plain + raw = pysodium.crypto_box_seal(texter.qb64b, pubkey) # uses nonce so different everytime + assert len(raw) == 112 + assert (3 - (len(raw) % 3)) % 3 == 2 + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_QB64_L0) + assert cipher.code == CiXDex.X25519_Cipher_QB64_L2 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == texter.qb64b + texter = core.Texter(qb64b=uncb) + assert texter.text == plain + + # qb2 lead 0 (always lead 0 when qb2 from texter) + plain = "The quick brown fox jumps over the lazy dog" + texter = core.Texter(text=plain) + assert texter.text == plain + raw = pysodium.crypto_box_seal(texter.qb2, pubkey) # uses nonce so different everytime + assert len(raw) == 96 + assert (3 - (len(raw) % 3)) % 3 == 0 + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_QB2_L0) + assert cipher.code == CiXDex.X25519_Cipher_QB2_L0 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == texter.qb2 + texter = core.Texter(qb2=uncb) + assert texter.text == plain + + # sniffable qb64 lead 0 + plain = "The quick brown fox jumps over the lazy" + texter = core.Texter(text=plain) + assert texter.text == plain + counter = core.Counter(core.Codens.GenericGroup, count=texter.size) + peb = counter.qb64b + texter.qb64b + raw = pysodium.crypto_box_seal(peb, pubkey) # uses nonce so different everytime + assert len(raw) == 108 + assert (3 - (len(raw) % 3)) % 3 == 0 + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_L0) + assert cipher.code == CiXDex.X25519_Cipher_L0 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == peb + peb = bytearray(peb) + counter = core.Counter(qb64b=peb, strip=True) + assert counter.code == core.CtrDex_2_0.GenericGroup + texter = core.Texter(qb64b=peb, strip=True) + assert texter.text == plain + + # sniffable qb64 lead 1 + plain = "The quick brown fox jumps over the lazy dog" + texter = core.Texter(text=plain) + assert texter.text == plain + counter = core.Counter(core.Codens.GenericGroup, count=texter.size) + peb = counter.qb64b + texter.qb64b + raw = pysodium.crypto_box_seal(peb, pubkey) # uses nonce so different everytime + assert len(raw) == 116 + assert (3 - (len(raw) % 3)) % 3 == 1 + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_L0) + assert cipher.code == CiXDex.X25519_Cipher_L1 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == peb + peb = bytearray(peb) + counter = core.Counter(qb64b=peb, strip=True) + assert counter.code == core.CtrDex_2_0.GenericGroup + texter = core.Texter(qb64b=peb, strip=True) + assert texter.text == plain + + # sniffable qb64 lead 2 + plain = "The quick brown fox jumps over the lazy " + texter = core.Texter(text=plain) + assert texter.text == plain + counter = core.Counter(core.Codens.GenericGroup, count=texter.size) + peb = counter.qb64b + texter.qb64b + raw = pysodium.crypto_box_seal(peb, pubkey) # uses nonce so different everytime + assert len(raw) == 112 + assert (3 - (len(raw) % 3)) % 3 == 2 + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_L0) + assert cipher.code == CiXDex.X25519_Cipher_L2 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == peb + peb = bytearray(peb) + counter = core.Counter(qb64b=peb, strip=True) + assert counter.code == core.CtrDex_2_0.GenericGroup + texter = core.Texter(qb64b=peb, strip=True) + assert texter.text == plain + + # sniffable qb2 lead 0 + plain = "The quick brown fox jumps over the lazy" + texter = core.Texter(text=plain) + assert texter.text == plain + counter = core.Counter(core.Codens.GenericGroup, count=texter.size) + assert counter.code == core.CtrDex_2_0.GenericGroup + peb = counter.qb64b + texter.qb64b + pebqb2 = decodeB64(peb) + raw = pysodium.crypto_box_seal(pebqb2, pubkey) # uses nonce so different everytime + assert len(raw) == 93 + assert (3 - (len(raw) % 3)) % 3 == 0 + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_L0) + assert cipher.code == CiXDex.X25519_Cipher_L0 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == pebqb2 + pebqb2 = bytearray(pebqb2) + counter = core.Counter(qb2=pebqb2, strip=True) + assert counter.code == core.CtrDex_2_0.GenericGroup + texter = core.Texter(qb2=pebqb2, strip=True) + assert texter.text == plain + + + # sniffable qb2 lead 0 Big + + plain = "The quick brown fox jumps over the lazy" * 324 + texter = core.Texter(text=plain) + assert texter.text == plain + counter = core.Counter(core.Codens.GenericGroup, count=texter.size) + assert counter.code == core.CtrDex_2_0.BigGenericGroup + peb = counter.qb64b + texter.qb64b + pebqb2 = decodeB64(peb) + raw = pysodium.crypto_box_seal(pebqb2, pubkey) # uses nonce so different everytime + assert len(raw) == 12696 + assert (3 - (len(raw) % 3)) % 3 == 0 + assert (len(raw) // 3 ) > (64 ** 2 - 1) # triplets + cipher = Cipher(raw=raw, code=CiXDex.X25519_Cipher_L0) + assert cipher.code == CiXDex.X25519_Cipher_Big_L0 + uncb = pysodium.crypto_box_seal_open(cipher.raw, pubkey, prikey) + assert uncb == pebqb2 + pebqb2 = bytearray(pebqb2) + counter = core.Counter(qb2=pebqb2, strip=True) + assert counter.code == core.CtrDex_2_0.BigGenericGroup + texter = core.Texter(qb2=pebqb2, strip=True) + assert texter.text == plain """ Done Test """