2017-10-07 02:29:07 +00:00
|
|
|
import pytest
|
|
|
|
|
|
|
|
from nkms.characters import Alice, Ursula, Character
|
2017-10-11 02:18:24 +00:00
|
|
|
from nkms.crypto import api
|
2017-10-11 05:39:25 +00:00
|
|
|
from nkms.crypto.constants import NOT_SIGNED
|
|
|
|
from nkms.crypto.powers import CryptoPower, SigningKeypair, NoSigningPower, NoEncryptingPower, \
|
|
|
|
EncryptingKeypair
|
|
|
|
|
|
|
|
"""
|
|
|
|
SIGNING
|
|
|
|
"""
|
2017-10-07 02:29:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_actor_without_signing_power_cannot_sign():
|
|
|
|
"""
|
|
|
|
We can create a Character with no real CryptoPower to speak of.
|
|
|
|
This Character can't even sign a message.
|
|
|
|
"""
|
|
|
|
cannot_sign = CryptoPower(power_ups=[])
|
|
|
|
non_signer = Character(crypto_power=cannot_sign)
|
|
|
|
|
2017-10-07 02:46:51 +00:00
|
|
|
# The non-signer's seal doesn't work for signing...
|
2017-10-07 02:29:07 +00:00
|
|
|
with pytest.raises(NoSigningPower) as e_info:
|
|
|
|
non_signer.seal("something")
|
|
|
|
|
2017-10-07 02:46:51 +00:00
|
|
|
# ...or as a way to show the public key.
|
2017-10-07 02:29:07 +00:00
|
|
|
with pytest.raises(NoSigningPower) as e_info:
|
|
|
|
non_signer.seal.as_bytes()
|
2017-10-07 02:46:51 +00:00
|
|
|
with pytest.raises(NoSigningPower) as e_info:
|
|
|
|
non_signer.seal.as_tuple()
|
2017-10-07 02:29:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_actor_with_signing_power_can_sign():
|
|
|
|
"""
|
|
|
|
However, simply giving that character a PowerUp bestows the power to sign.
|
|
|
|
|
|
|
|
Instead of having a Character verify the signature, we'll use the lower level API.
|
|
|
|
"""
|
|
|
|
message = b"Llamas."
|
|
|
|
|
|
|
|
signer = Character(crypto_power_ups=[SigningKeypair])
|
|
|
|
seal_of_the_signer = signer.seal
|
|
|
|
|
|
|
|
# We can use the signer's seal to sign a message...
|
|
|
|
signature = seal_of_the_signer(message)
|
|
|
|
|
|
|
|
# ...or to get the signer's public key for verification purposes.
|
2017-10-11 02:18:24 +00:00
|
|
|
sig = api.ecdsa_load_sig(signature)
|
|
|
|
verification = api.ecdsa_verify(*sig, api.keccak_digest(message), seal_of_the_signer.as_tuple())
|
2017-10-07 02:29:07 +00:00
|
|
|
|
2017-10-07 02:46:51 +00:00
|
|
|
assert verification is True
|
2017-10-07 02:29:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_anybody_can_verify():
|
|
|
|
"""
|
|
|
|
In the last example, we used the lower-level Crypto API to verify the signature.
|
|
|
|
|
|
|
|
Here, we show that anybody can do it without needing to directly access Crypto.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Alice can sign by default, by dint of her _default_crypto_powerups.
|
|
|
|
alice = Alice()
|
|
|
|
|
|
|
|
# So, our story is fairly simple: an everyman meets Alice.
|
|
|
|
somebody = Character()
|
|
|
|
somebody.learn_about_actor(alice)
|
|
|
|
|
|
|
|
# Alice signs a message.
|
|
|
|
message = b"A message for all my friends who can only verify and not sign."
|
|
|
|
signature = alice.seal(message)
|
|
|
|
|
|
|
|
# Our everyman can verify it.
|
|
|
|
verification = somebody.verify_from(alice, signature, message)
|
2017-10-07 02:46:51 +00:00
|
|
|
assert verification is True
|
2017-10-07 02:29:07 +00:00
|
|
|
|
|
|
|
|
2017-10-11 05:39:25 +00:00
|
|
|
"""
|
|
|
|
ENCRYPTION
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
2017-10-07 02:29:07 +00:00
|
|
|
def test_signing_only_power_cannot_encrypt():
|
2017-10-07 02:46:51 +00:00
|
|
|
"""
|
|
|
|
Similar to the above with signing, here we show that a Character without the EncryptingKeypair
|
|
|
|
PowerUp can't encrypt.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Here's somebody who can sign but not encrypt.
|
|
|
|
can_sign_but_not_encrypt = Character(crypto_power_ups=[SigningKeypair])
|
|
|
|
|
|
|
|
# ..and here's Ursula, for whom our Character above wants to encrypt.
|
2017-10-07 02:29:07 +00:00
|
|
|
ursula = Ursula()
|
|
|
|
|
2017-10-07 02:46:51 +00:00
|
|
|
# They meet.
|
|
|
|
can_sign_but_not_encrypt.learn_about_actor(ursula)
|
|
|
|
|
|
|
|
# The Character has the message ready...
|
2017-10-07 02:29:07 +00:00
|
|
|
cleartext = "This is Officer Rod Farva. Come in, Ursula! Come in Ursula!"
|
|
|
|
|
2017-10-07 02:46:51 +00:00
|
|
|
# But without the proper PowerUp, no encryption happens.
|
2017-10-07 02:29:07 +00:00
|
|
|
with pytest.raises(NoEncryptingPower) as e_info:
|
2017-10-07 02:46:51 +00:00
|
|
|
can_sign_but_not_encrypt.encrypt_for(ursula, cleartext)
|
2017-10-11 05:39:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_character_with_encrypting_power_can_encrypt():
|
|
|
|
"""
|
|
|
|
Now, a Character *with* EncryptingKeyPair can encrypt.
|
|
|
|
"""
|
|
|
|
can_sign_and_encrypt = Character(crypto_power_ups=[SigningKeypair, EncryptingKeypair])
|
|
|
|
ursula = Ursula()
|
|
|
|
can_sign_and_encrypt.learn_about_actor(ursula)
|
|
|
|
|
|
|
|
cleartext = b"This is Officer Rod Farva. Come in, Ursula! Come in Ursula!"
|
|
|
|
|
|
|
|
# TODO: Make encrypt_for actually encrypt.
|
|
|
|
ciphertext, signature = can_sign_and_encrypt.encrypt_for(ursula, cleartext, sign=False)
|
|
|
|
assert signature == NOT_SIGNED
|
|
|
|
|
|
|
|
assert ciphertext is not None # annnd fail.
|