Skip to content

Commit

Permalink
Merge pull request WebOfTrust#836 from SmithSamuelM/main
Browse files Browse the repository at this point in the history
Updated Encrypter, Decrypter, and Cipher to support all Cipher types including variable length with unit tests.
  • Loading branch information
SmithSamuelM committed Aug 6, 2024
2 parents 3909bd8 + f23c39e commit 2a2f8ce
Show file tree
Hide file tree
Showing 12 changed files with 772 additions and 195 deletions.
4 changes: 2 additions & 2 deletions src/keri/app/cli/commands/decrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ def decrypt(tymth, tock=0.0, **opts):
else:
data = data

m = coring.Matter(qb64=data)
d = coring.Matter(qb64=hab.decrypt(m.raw))
m = coring.Matter(qb64=data) # should refactor this to use Cipher
d = coring.Matter(qb64=hab.decrypt(ser=m.raw))
print(d.raw)

except kering.ConfigurationError:
Expand Down
4 changes: 2 additions & 2 deletions src/keri/app/cli/commands/witness/authenticate.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ def authDo(self, tymth, tock=0.0):
data = json.loads(rep.body)

totp = data["totp"]
m = coring.Matter(qb64=totp)
d = coring.Matter(qb64=self.hab.decrypt(m.raw))
m = coring.Matter(qb64=totp) # refactor this to use cipher
d = coring.Matter(qb64=self.hab.decrypt(ser=m.raw))
otpurl = f"otpauth://totp/KERIpy:{self.witness}?secret={d.raw.decode('utf-8')}&issuer=KERIpy"

if not self.urlOnly:
Expand Down
15 changes: 9 additions & 6 deletions src/keri/app/habbing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1320,24 +1320,27 @@ def sign(self, ser, verfers=None, indexed=True, indices=None, ondices=None, **kw
indices=indices,
ondices=ondices)


def decrypt(self, ser, verfers=None, **kwa):
"""Sign given serialization ser using appropriate keys.
"""Decrypt given serialization ser using appropriate keys.
Use provided verfers or .kever.verfers to lookup keys to sign.
Parameters:
ser (bytes): serialization to sign
ser (str | bytes | bytearray | memoryview): serialization to decrypt
verfers (list[Verfer] | None): Verfer instances to get pub verifier
keys to lookup private siging keys.
keys to lookup and convert to private decryption keys.
verfers None means use .kever.verfers. Assumes that when group
and verfers is not None then provided verfers must be .kever.verfers
"""
if verfers is None:
verfers = self.kever.verfers # when group these provide group signing keys

return self.mgr.decrypt(ser=ser,
verfers=verfers,
)
# should not use mgr.decrypt since it assumes qb64. Just lucky its not
# yet a problem
return self.mgr.decrypt(qb64=ser, verfers=verfers)


def query(self, pre, src, query=None, **kwa):
""" Create, sign and return a `qry` message against the attester for the prefix
Expand Down
42 changes: 25 additions & 17 deletions src/keri/app/keeping.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,8 +804,8 @@ def updateAeid(self, aeid, seed):
# re-encrypt root salt secrets by prefix parameters .prms
for keys, data in self.ks.prms.getItemIter(): # keys is tuple of pre qb64
if data.salt:
salter = self.decrypter.decrypt(ser=data.salt)
data.salt = (self.encrypter.encrypt(matter=salter).qb64
salter = self.decrypter.decrypt(qb64=data.salt)
data.salt = (self.encrypter.encrypt(prim=salter).qb64
if self.encrypter else salter.qb64)
self.ks.prms.pin(keys, val=data)

Expand Down Expand Up @@ -889,7 +889,7 @@ def salt(self):
"""
salt = self.ks.gbls.get('salt')
if self.decrypter: # given .decrypt secret salt must be encrypted in db
return self.decrypter.decrypt(ser=salt).qb64
return self.decrypter.decrypt(qb64=salt).qb64
return salt


Expand All @@ -902,7 +902,7 @@ def salt(self, salt):
may be plain text or cipher text handled by updateAeid
"""
if self.encrypter:
salt = self.encrypter.encrypt(ser=salt).qb64
salt = self.encrypter.encrypt(ser=salt, code=core.MtrDex.X25519_Cipher_Salt).qb64
self.ks.gbls.pin('salt', salt)


Expand Down Expand Up @@ -1020,7 +1020,8 @@ def incept(self, icodes=None, icount=1, icode=coring.MtrDex.Ed25519_Seed,

if creator.salt:
pp.salt = (creator.salt if not self.encrypter
else self.encrypter.encrypt(ser=creator.salt).qb64)
else self.encrypter.encrypt(ser=creator.salt,
code=core.MtrDex.X25519_Cipher_Salt).qb64)

dt = helping.nowIso8601()
ps = PreSit(
Expand Down Expand Up @@ -1184,7 +1185,7 @@ def rotate(self, pre, ncodes=None, ncount=1,
if self.aeid:
if not self.decrypter:
raise kering.DecryptError("Unauthorized decryption. Aeid but no decrypter.")
salt = self.decrypter.decrypt(ser=salt).qb64
salt = self.decrypter.decrypt(qb64=salt).qb64
else:
salt = core.Salter(qb64=salt).qb64 # ensures salt was unencrypted

Expand Down Expand Up @@ -1394,21 +1395,23 @@ def sign(self, ser, pubs=None, verfers=None, indexed=True,
cigars.append(signer.sign(ser)) # assigns .verfer to cigar
return cigars

def decrypt(self, ser, pubs=None, verfers=None):

def decrypt(self, qb64, pubs=None, verfers=None):
"""
Returns list of signatures of ser if indexed as Sigers else as Cigars with
.verfer assigned.
Returns decrypted plaintext of encrypted qb64 ciphertext serialization.
Parameters:
ser (bytes): serialization to sign
qb64 (str | bytes | bytearray | memoryview): fully qualified base64
ciphertext serialization to decrypt
pubs (list[str] | None): of qb64 public keys to lookup private keys
one of pubs or verfers is required. If both then verfers is ignored.
verfers (list[Verfer] | None): Verfer instances of public keys
one of pubs or verfers is required. If both then verfers is ignored.
If not pubs then gets public key from verfer.qb64
If not pubs then gets public key from verfer.qb64 used to lookup
private keys
Returns:
bytes: decrypted data
plain (bytes): decrypted plaintext
"""
signers = []
Expand All @@ -1433,18 +1436,22 @@ def decrypt(self, ser, pubs=None, verfers=None):
raise ValueError("Missing prikey in db for pubkey={}".format(verfer.qb64))
signers.append(signer)

plain = ser
if hasattr(qb64, "encode"):
qb64 = qb64.encode() # convert str to bytes
qb64 = bytes(qb64) # convert bytearray or memoryview to bytes

for signer in signers:
sigkey = signer.raw + signer.verfer.raw # sigkey is raw seed + raw verkey
prikey = pysodium.crypto_sign_sk_to_box_sk(sigkey) # raw private encrypt key
pubkey = pysodium.crypto_scalarmult_curve25519_base(prikey)
plain = pysodium.crypto_box_seal_open(plain, pubkey, prikey) # qb64b
plain = pysodium.crypto_box_seal_open(qb64, pubkey, prikey) # qb64b

if plain == ser:
raise ValueError("unable to decrypt data")
if plain == qb64:
raise ValueError(f"Unable to decrypt.")

return plain


def ingest(self, secrecies, iridx=0, ncount=1, ncode=coring.MtrDex.Ed25519_Seed,
dcode=coring.MtrDex.Blake3_256,
algo=Algos.salty, salt=None, stem=None, tier=None,
Expand Down Expand Up @@ -1542,7 +1549,8 @@ def ingest(self, secrecies, iridx=0, ncount=1, ncode=coring.MtrDex.Ed25519_Seed,
pp = PrePrm(pidx=pidx,
algo=algo,
salt=(creator.salt if not self.encrypter
else self.encrypter.encrypt(ser=creator.salt).qb64),
else self.encrypter.encrypt(ser=creator.salt,
code=core.MtrDex.X25519_Cipher_Salt).qb64),
stem=creator.stem,
tier=creator.tier)
pre = csigners[0].verfer.qb64b
Expand Down
1 change: 1 addition & 0 deletions src/keri/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
from .indexing import Indexer, Siger, IdrDex, IdxSigDex
from .signing import Signer, Salter, Cipher, CiXDex, Encrypter, Decrypter
from .counting import Counter, Codens, CtrDex_2_0
from .streaming import Streamer
22 changes: 13 additions & 9 deletions src/keri/core/coring.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,12 +350,12 @@ class MatterCodex:
Bytes_Big_L0: str = '7AAB' # Byte String big lead size 0
Bytes_Big_L1: str = '8AAB' # Byte String big lead size 1
Bytes_Big_L2: str = '9AAB' # Byte String big lead size 2
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_L0: str = '4C' # X25519 sealed box cipher bytes of sniffable stream plaintext lead size 0
X25519_Cipher_L1: str = '5C' # X25519 sealed box cipher bytes of sniffable stream plaintext lead size 1
X25519_Cipher_L2: str = '6C' # X25519 sealed box cipher bytes of sniffable stream plaintext lead size 2
X25519_Cipher_Big_L0: str = '7AAC' # X25519 sealed box cipher bytes of sniffable stream plaintext big lead size 0
X25519_Cipher_Big_L1: str = '8AAC' # X25519 sealed box cipher bytes of sniffable stream plaintext big lead size 1
X25519_Cipher_Big_L2: str = '9AAC' # X25519 sealed box cipher bytes of sniffable stream 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
Expand Down Expand Up @@ -795,9 +795,13 @@ def __init__(self, raw=None, code=MtrDex.Ed25519N, soft='', rize=None,
rize (int | None): raw size in bytes when variable sized material not
including lead bytes if any
Otherwise None
qb64b (bytes | None): fully qualified crypto material Base64
qb64 (str | bytes | None): fully qualified crypto material Base64
qb2 (bytes | None): fully qualified crypto material Base2
qb64b (str | bytes | bytearray | memoryview | None): fully qualified
crypto material Base64. When str, encodes as utf-8. Strips when
bytearray and strip is True.
qb64 (str | bytes | bytearray | memoryview | None): fully qualified
crypto material Base64. When str, encodes as utf-8. Ignores strip
qb2 (bytes | bytearray | memoryview | None): fully qualified crypto
material Base2. Strips when bytearray and strip is True.
strip (bool): True means strip (delete) matter from input stream
bytearray after parsing qb64b or qb2. False means do not strip
Expand Down
Loading

0 comments on commit 2a2f8ce

Please sign in to comment.