refactor away from pycryptopp "helper" classes
This commit is contained in:
parent
78a13aad43
commit
df4671f90e
|
@ -12,7 +12,7 @@ from twisted.python.failure import Failure
|
||||||
|
|
||||||
import allmydata
|
import allmydata
|
||||||
from allmydata.crypto.ed25519 import SigningKey
|
from allmydata.crypto.ed25519 import SigningKey
|
||||||
from allmydata.crypto.rsa import PrivateKey
|
from allmydata.crypto import rsa
|
||||||
from allmydata.storage.server import StorageServer
|
from allmydata.storage.server import StorageServer
|
||||||
from allmydata import storage_client
|
from allmydata import storage_client
|
||||||
from allmydata.immutable.upload import Uploader
|
from allmydata.immutable.upload import Uploader
|
||||||
|
@ -156,8 +156,7 @@ class KeyGenerator(object):
|
||||||
keysize = keysize or self.default_keysize
|
keysize = keysize or self.default_keysize
|
||||||
# RSA key generation for a 2048 bit key takes between 0.8 and 3.2
|
# RSA key generation for a 2048 bit key takes between 0.8 and 3.2
|
||||||
# secs
|
# secs
|
||||||
signer = PrivateKey.generate(keysize)
|
signer, verifier = rsa.create_signing_keypair(keysize)
|
||||||
verifier = signer.public_key()
|
|
||||||
return defer.succeed( (verifier, signer) )
|
return defer.succeed( (verifier, signer) )
|
||||||
|
|
||||||
class Terminator(service.Service):
|
class Terminator(service.Service):
|
||||||
|
|
|
@ -8,110 +8,153 @@ from cryptography.hazmat.primitives.serialization import load_der_private_key, l
|
||||||
from allmydata.crypto import BadSignature
|
from allmydata.crypto import BadSignature
|
||||||
|
|
||||||
|
|
||||||
class RsaMixin(object):
|
"""
|
||||||
|
|
||||||
'''
|
|
||||||
This is the value that was used by `pycryptopp`, and we must continue to use it for
|
This is the value that was used by `pycryptopp`, and we must continue to use it for
|
||||||
both backwards compatibility and interoperability.
|
both backwards compatibility and interoperability.
|
||||||
|
|
||||||
The docs for `cryptography` suggest to use the constant defined at
|
The docs for `cryptography` suggest to use the constant defined at
|
||||||
`cryptography.hazmat.primitives.asymmetric.padding.PSS.MAX_LENGTH`, but this causes old
|
`cryptography.hazmat.primitives.asymmetric.padding.PSS.MAX_LENGTH`, but this causes old
|
||||||
signatures to fail to validate.
|
signatures to fail to validate.
|
||||||
'''
|
"""
|
||||||
RSA_PSS_SALT_LENGTH = 32
|
RSA_PSS_SALT_LENGTH = 32
|
||||||
|
|
||||||
|
|
||||||
class PrivateKey(RsaMixin):
|
def create_verifying_key_from_string(public_key_der):
|
||||||
|
"""
|
||||||
|
Create an RSA verifying key from a previously serialized public key.
|
||||||
|
|
||||||
def __init__(self, priv_key):
|
:returns: public key
|
||||||
self._priv_key = priv_key
|
"""
|
||||||
|
pub_key = load_der_public_key(
|
||||||
|
public_key_der,
|
||||||
|
backend=default_backend(),
|
||||||
|
)
|
||||||
|
return pub_key
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def generate(cls, key_size):
|
def create_signing_keypair(key_size):
|
||||||
|
"""
|
||||||
|
Create a new RSA signing keypair from scratch. Can be used with
|
||||||
|
`sign_data` function.
|
||||||
|
|
||||||
|
:param int key_size: length of key in bits
|
||||||
|
|
||||||
|
:returns: 2-tuple of (private_key, public_key)
|
||||||
|
"""
|
||||||
priv_key = rsa.generate_private_key(
|
priv_key = rsa.generate_private_key(
|
||||||
public_exponent=65537, # serisously don't change this value
|
public_exponent=65537, # serisously don't change this value
|
||||||
key_size=key_size,
|
key_size=key_size,
|
||||||
backend=default_backend()
|
backend=default_backend()
|
||||||
)
|
)
|
||||||
return cls(priv_key)
|
return priv_key, priv_key.public_key()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def parse_string(cls, priv_key_str):
|
def create_signing_keypair_from_string(private_key_der):
|
||||||
|
"""
|
||||||
|
Create an RSA signing key from a previously serialized private key.
|
||||||
|
|
||||||
|
:returns: 2-tuple of (private_key, public_key)
|
||||||
|
"""
|
||||||
priv_key = load_der_private_key(
|
priv_key = load_der_private_key(
|
||||||
priv_key_str,
|
private_key_der,
|
||||||
password=None,
|
password=None,
|
||||||
backend=default_backend(),
|
backend=default_backend(),
|
||||||
)
|
)
|
||||||
return cls(priv_key)
|
return priv_key, priv_key.public_key()
|
||||||
|
|
||||||
def public_key(self):
|
|
||||||
return PublicKey(self._priv_key.public_key())
|
|
||||||
|
|
||||||
def serialize(self):
|
def der_string_from_signing_key(private_key):
|
||||||
return self._priv_key.private_bytes(
|
"""
|
||||||
|
Serializes a given RSA private key to a DER string
|
||||||
|
"""
|
||||||
|
_validate_private_key(private_key)
|
||||||
|
return private_key.private_bytes(
|
||||||
encoding=Encoding.DER,
|
encoding=Encoding.DER,
|
||||||
format=PrivateFormat.PKCS8,
|
format=PrivateFormat.PKCS8,
|
||||||
encryption_algorithm=NoEncryption(),
|
encryption_algorithm=NoEncryption(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def sign(self, data):
|
|
||||||
return self._priv_key.sign(
|
|
||||||
data,
|
|
||||||
padding.PSS(
|
|
||||||
mgf=padding.MGF1(hashes.SHA256()),
|
|
||||||
salt_length=self.RSA_PSS_SALT_LENGTH,
|
|
||||||
),
|
|
||||||
hashes.SHA256(),
|
|
||||||
)
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def der_string_from_verifying_key(public_key):
|
||||||
if isinstance(other, type(self)):
|
"""
|
||||||
return self.serialize() == other.serialize()
|
Serializes a given RSA private key to a DER string
|
||||||
else:
|
"""
|
||||||
return False
|
_validate_public_key(public_key)
|
||||||
|
return public_key.public_bytes(
|
||||||
def __ne__(self, other):
|
|
||||||
return not self.__eq__(other)
|
|
||||||
|
|
||||||
|
|
||||||
class PublicKey(RsaMixin):
|
|
||||||
|
|
||||||
def __init__(self, pub_key):
|
|
||||||
self._pub_key = pub_key
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def parse_string(cls, pub_key_str):
|
|
||||||
pub_key = load_der_public_key(
|
|
||||||
pub_key_str,
|
|
||||||
backend=default_backend(),
|
|
||||||
)
|
|
||||||
return cls(pub_key)
|
|
||||||
|
|
||||||
def serialize(self):
|
|
||||||
return self._pub_key.public_bytes(
|
|
||||||
encoding=Encoding.DER,
|
encoding=Encoding.DER,
|
||||||
format=PublicFormat.SubjectPublicKeyInfo,
|
format=PublicFormat.SubjectPublicKeyInfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
def verify(self, signature, data):
|
|
||||||
try:
|
def create_verifying_key_from_string(public_key_der):
|
||||||
self._pub_key.verify(
|
"""
|
||||||
signature,
|
Create an RSA signing key from a previously serialized public key
|
||||||
|
"""
|
||||||
|
pub_key = load_der_public_key(
|
||||||
|
public_key_der,
|
||||||
|
backend=default_backend(),
|
||||||
|
)
|
||||||
|
return pub_key
|
||||||
|
|
||||||
|
|
||||||
|
def sign_data(private_key, data):
|
||||||
|
"""
|
||||||
|
:param private_key: the private part of a keypair returned from
|
||||||
|
`create_signing_keypair_from_string` or `create_signing_keypair`
|
||||||
|
|
||||||
|
:param bytes data: the bytes to sign
|
||||||
|
|
||||||
|
:returns: bytes which are a signature of the bytes given as `data`.
|
||||||
|
"""
|
||||||
|
_validate_private_key(private_key)
|
||||||
|
return private_key.sign(
|
||||||
data,
|
data,
|
||||||
padding.PSS(
|
padding.PSS(
|
||||||
mgf=padding.MGF1(hashes.SHA256()),
|
mgf=padding.MGF1(hashes.SHA256()),
|
||||||
salt_length=self.RSA_PSS_SALT_LENGTH,
|
salt_length=RSA_PSS_SALT_LENGTH,
|
||||||
|
),
|
||||||
|
hashes.SHA256(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def verify_signature(public_key, alleged_signature, data):
|
||||||
|
"""
|
||||||
|
:param public_key: a verifying key, returned from `create_verifying_key_from_string` or `create_verifying_key_from_private_key`
|
||||||
|
|
||||||
|
:param bytes alleged_signature: the bytes of the alleged signature
|
||||||
|
|
||||||
|
:param bytes data: the data which was allegedly signed
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
public_key.verify(
|
||||||
|
alleged_signature,
|
||||||
|
data,
|
||||||
|
padding.PSS(
|
||||||
|
mgf=padding.MGF1(hashes.SHA256()),
|
||||||
|
salt_length=RSA_PSS_SALT_LENGTH,
|
||||||
),
|
),
|
||||||
hashes.SHA256(),
|
hashes.SHA256(),
|
||||||
)
|
)
|
||||||
except InvalidSignature:
|
except InvalidSignature:
|
||||||
raise BadSignature
|
raise BadSignature
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
if isinstance(other, type(self)):
|
|
||||||
return self.serialize() == other.serialize()
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
def _validate_public_key(public_key):
|
||||||
return not self.__eq__(other)
|
"""
|
||||||
|
Internal helper. Checks that `public_key` is a valid cryptography
|
||||||
|
object
|
||||||
|
"""
|
||||||
|
if not isinstance(public_key, rsa.RSAPublicKey):
|
||||||
|
raise ValueError(
|
||||||
|
"public_key not an RSAPublicKey"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_private_key(private_key):
|
||||||
|
"""
|
||||||
|
Internal helper. Checks that `public_key` is a valid cryptography
|
||||||
|
object
|
||||||
|
"""
|
||||||
|
if not isinstance(private_key, rsa.RSAPrivateKey):
|
||||||
|
raise ValueError(
|
||||||
|
"private_key not an RSAPrivateKey"
|
||||||
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ from twisted.internet import defer, reactor
|
||||||
from foolscap.api import eventually
|
from foolscap.api import eventually
|
||||||
|
|
||||||
from allmydata.crypto.aes import AES
|
from allmydata.crypto.aes import AES
|
||||||
|
from allmydata.crypto import rsa
|
||||||
from allmydata.interfaces import IMutableFileNode, ICheckable, ICheckResults, \
|
from allmydata.interfaces import IMutableFileNode, ICheckable, ICheckResults, \
|
||||||
NotEnoughSharesError, MDMF_VERSION, SDMF_VERSION, IMutableUploadable, \
|
NotEnoughSharesError, MDMF_VERSION, SDMF_VERSION, IMutableUploadable, \
|
||||||
IMutableFileVersion, IWriteable
|
IMutableFileVersion, IWriteable
|
||||||
|
@ -128,8 +129,8 @@ class MutableFileNode(object):
|
||||||
"""
|
"""
|
||||||
(pubkey, privkey) = keypair
|
(pubkey, privkey) = keypair
|
||||||
self._pubkey, self._privkey = pubkey, privkey
|
self._pubkey, self._privkey = pubkey, privkey
|
||||||
pubkey_s = self._pubkey.serialize()
|
pubkey_s = rsa.der_string_from_verifying_key(self._pubkey)
|
||||||
privkey_s = self._privkey.serialize()
|
privkey_s = rsa.der_string_from_signing_key(self._privkey)
|
||||||
self._writekey = hashutil.ssk_writekey_hash(privkey_s)
|
self._writekey = hashutil.ssk_writekey_hash(privkey_s)
|
||||||
self._encprivkey = self._encrypt_privkey(self._writekey, privkey_s)
|
self._encprivkey = self._encrypt_privkey(self._writekey, privkey_s)
|
||||||
self._fingerprint = hashutil.ssk_pubkey_fingerprint_hash(pubkey_s)
|
self._fingerprint = hashutil.ssk_pubkey_fingerprint_hash(pubkey_s)
|
||||||
|
|
|
@ -6,6 +6,7 @@ from twisted.internet import defer
|
||||||
from twisted.python import failure
|
from twisted.python import failure
|
||||||
|
|
||||||
from allmydata.crypto.aes import AES
|
from allmydata.crypto.aes import AES
|
||||||
|
from allmydata.crypto import rsa
|
||||||
from allmydata.interfaces import IPublishStatus, SDMF_VERSION, MDMF_VERSION, \
|
from allmydata.interfaces import IPublishStatus, SDMF_VERSION, MDMF_VERSION, \
|
||||||
IMutableUploadable
|
IMutableUploadable
|
||||||
from allmydata.util import base32, hashutil, mathutil, log
|
from allmydata.util import base32, hashutil, mathutil, log
|
||||||
|
@ -849,7 +850,7 @@ class Publish(object):
|
||||||
started = time.time()
|
started = time.time()
|
||||||
self._status.set_status("Signing prefix")
|
self._status.set_status("Signing prefix")
|
||||||
signable = self._get_some_writer().get_signable()
|
signable = self._get_some_writer().get_signable()
|
||||||
self.signature = self._privkey.sign(signable)
|
self.signature = rsa.sign_data(self._privkey, signable)
|
||||||
|
|
||||||
for (shnum, writers) in self.writers.iteritems():
|
for (shnum, writers) in self.writers.iteritems():
|
||||||
for writer in writers:
|
for writer in writers:
|
||||||
|
@ -864,7 +865,7 @@ class Publish(object):
|
||||||
self._status.set_status("Pushing shares")
|
self._status.set_status("Pushing shares")
|
||||||
self._started_pushing = started
|
self._started_pushing = started
|
||||||
ds = []
|
ds = []
|
||||||
verification_key = self._pubkey.serialize()
|
verification_key = rsa.der_string_from_verifying_key(self._pubkey)
|
||||||
|
|
||||||
for (shnum, writers) in self.writers.copy().iteritems():
|
for (shnum, writers) in self.writers.copy().iteritems():
|
||||||
for writer in writers:
|
for writer in writers:
|
||||||
|
|
|
@ -9,7 +9,7 @@ from foolscap.api import eventually, fireEventually, DeadReferenceError, \
|
||||||
RemoteException
|
RemoteException
|
||||||
|
|
||||||
from allmydata.crypto.aes import AES
|
from allmydata.crypto.aes import AES
|
||||||
from allmydata.crypto.rsa import PrivateKey
|
from allmydata.crypto import rsa
|
||||||
from allmydata.interfaces import IRetrieveStatus, NotEnoughSharesError, \
|
from allmydata.interfaces import IRetrieveStatus, NotEnoughSharesError, \
|
||||||
DownloadStopped, MDMF_VERSION, SDMF_VERSION
|
DownloadStopped, MDMF_VERSION, SDMF_VERSION
|
||||||
from allmydata.util.assertutil import _assert, precondition
|
from allmydata.util.assertutil import _assert, precondition
|
||||||
|
@ -935,7 +935,7 @@ class Retrieve(object):
|
||||||
# it's good
|
# it's good
|
||||||
self.log("got valid privkey from shnum %d on reader %s" %
|
self.log("got valid privkey from shnum %d on reader %s" %
|
||||||
(reader.shnum, reader))
|
(reader.shnum, reader))
|
||||||
privkey = PrivateKey.parse_string(alleged_privkey_s)
|
privkey, _ = rsa.create_signing_keypair_from_string(alleged_privkey_s)
|
||||||
self._node._populate_encprivkey(enc_privkey)
|
self._node._populate_encprivkey(enc_privkey)
|
||||||
self._node._populate_privkey(privkey)
|
self._node._populate_privkey(privkey)
|
||||||
self._need_privkey = False
|
self._need_privkey = False
|
||||||
|
|
|
@ -9,7 +9,7 @@ from twisted.python import failure
|
||||||
from foolscap.api import DeadReferenceError, RemoteException, eventually, \
|
from foolscap.api import DeadReferenceError, RemoteException, eventually, \
|
||||||
fireEventually
|
fireEventually
|
||||||
from allmydata.crypto import BadSignature
|
from allmydata.crypto import BadSignature
|
||||||
from allmydata.crypto.rsa import PublicKey, PrivateKey
|
from allmydata.crypto import rsa
|
||||||
from allmydata.util import base32, hashutil, log, deferredutil
|
from allmydata.util import base32, hashutil, log, deferredutil
|
||||||
from allmydata.util.dictutil import DictOfSets
|
from allmydata.util.dictutil import DictOfSets
|
||||||
from allmydata.storage.server import si_b2a
|
from allmydata.storage.server import si_b2a
|
||||||
|
@ -845,7 +845,7 @@ class ServermapUpdater(object):
|
||||||
# against the public key before keeping track of it.
|
# against the public key before keeping track of it.
|
||||||
assert self._node.get_pubkey()
|
assert self._node.get_pubkey()
|
||||||
try:
|
try:
|
||||||
self._node.get_pubkey().verify(signature[1], prefix)
|
rsa.verify_signature(self._node.get_pubkey(), signature[1], prefix)
|
||||||
except BadSignature:
|
except BadSignature:
|
||||||
raise CorruptShareError(server, shnum,
|
raise CorruptShareError(server, shnum,
|
||||||
"signature is invalid")
|
"signature is invalid")
|
||||||
|
@ -916,7 +916,7 @@ class ServermapUpdater(object):
|
||||||
update_data)
|
update_data)
|
||||||
|
|
||||||
def _deserialize_pubkey(self, pubkey_s):
|
def _deserialize_pubkey(self, pubkey_s):
|
||||||
verifier = PublicKey.parse_string(pubkey_s)
|
verifier = rsa.create_verifying_key_from_string(pubkey_s)
|
||||||
return verifier
|
return verifier
|
||||||
|
|
||||||
def _try_to_validate_privkey(self, enc_privkey, server, shnum, lp):
|
def _try_to_validate_privkey(self, enc_privkey, server, shnum, lp):
|
||||||
|
@ -937,7 +937,7 @@ class ServermapUpdater(object):
|
||||||
self.log("got valid privkey from shnum %d on serverid %s" %
|
self.log("got valid privkey from shnum %d on serverid %s" %
|
||||||
(shnum, server.get_name()),
|
(shnum, server.get_name()),
|
||||||
parent=lp)
|
parent=lp)
|
||||||
privkey = PrivateKey.parse_string(alleged_privkey_s)
|
privkey, _ = rsa.create_signing_keypair_from_string(alleged_privkey_s)
|
||||||
self._node._populate_encprivkey(enc_privkey)
|
self._node._populate_encprivkey(enc_privkey)
|
||||||
self._node._populate_privkey(privkey)
|
self._node._populate_privkey(privkey)
|
||||||
self._need_privkey = False
|
self._need_privkey = False
|
||||||
|
|
|
@ -5,6 +5,7 @@ from twisted.trial import unittest
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from foolscap.logging import log
|
from foolscap.logging import log
|
||||||
from allmydata import uri
|
from allmydata import uri
|
||||||
|
from allmydata.crypto import rsa
|
||||||
from allmydata.interfaces import NotEnoughSharesError, SDMF_VERSION, MDMF_VERSION
|
from allmydata.interfaces import NotEnoughSharesError, SDMF_VERSION, MDMF_VERSION
|
||||||
from allmydata.util import fileutil
|
from allmydata.util import fileutil
|
||||||
from allmydata.util.hashutil import ssk_writekey_hash, ssk_pubkey_fingerprint_hash
|
from allmydata.util.hashutil import ssk_writekey_hash, ssk_pubkey_fingerprint_hash
|
||||||
|
@ -211,8 +212,8 @@ class Problems(GridTestMixin, unittest.TestCase, testutil.ShouldFailMixin):
|
||||||
def _got_key(keypair):
|
def _got_key(keypair):
|
||||||
(pubkey, privkey) = keypair
|
(pubkey, privkey) = keypair
|
||||||
nm.key_generator = SameKeyGenerator(pubkey, privkey)
|
nm.key_generator = SameKeyGenerator(pubkey, privkey)
|
||||||
pubkey_s = pubkey.serialize()
|
pubkey_s = rsa.der_string_from_verifying_key(pubkey)
|
||||||
privkey_s = privkey.serialize()
|
privkey_s = rsa.der_string_from_signing_key(privkey)
|
||||||
u = uri.WriteableSSKFileURI(ssk_writekey_hash(privkey_s),
|
u = uri.WriteableSSKFileURI(ssk_writekey_hash(privkey_s),
|
||||||
ssk_pubkey_fingerprint_hash(pubkey_s))
|
ssk_pubkey_fingerprint_hash(pubkey_s))
|
||||||
self._storage_index = u.get_storage_index()
|
self._storage_index = u.get_storage_index()
|
||||||
|
|
|
@ -209,13 +209,8 @@ class TestRegression(unittest.TestCase):
|
||||||
This simply checks that keys and signatures generated using the old code are still valid
|
This simply checks that keys and signatures generated using the old code are still valid
|
||||||
using the new code.
|
using the new code.
|
||||||
'''
|
'''
|
||||||
priv_key = rsa.PrivateKey.parse_string(self.RSA_2048_PRIV_KEY)
|
priv_key, pub_key = rsa.create_signing_keypair_from_string(self.RSA_2048_PRIV_KEY)
|
||||||
pub_key = priv_key.public_key()
|
rsa.verify_signature(pub_key, self.RSA_2048_SIG, b'test')
|
||||||
|
|
||||||
parsed_pub_key = rsa.PublicKey.parse_string(self.RSA_2048_PUB_KEY)
|
|
||||||
self.failUnlessEqual(pub_key, parsed_pub_key)
|
|
||||||
|
|
||||||
pub_key.verify(self.RSA_2048_SIG, b'test')
|
|
||||||
|
|
||||||
|
|
||||||
class TestEd25519(unittest.TestCase):
|
class TestEd25519(unittest.TestCase):
|
||||||
|
@ -249,24 +244,26 @@ class TestEd25519(unittest.TestCase):
|
||||||
class TestRsa(unittest.TestCase):
|
class TestRsa(unittest.TestCase):
|
||||||
|
|
||||||
def test_keys(self):
|
def test_keys(self):
|
||||||
priv_key = rsa.PrivateKey.generate(2048)
|
priv_key, pub_key = rsa.create_signing_keypair(2048)
|
||||||
priv_key_str = priv_key.serialize()
|
priv_key_str = rsa.der_string_from_signing_key(priv_key)
|
||||||
|
|
||||||
self.assertIsInstance(priv_key_str, six.string_types)
|
self.assertIsInstance(priv_key_str, six.string_types)
|
||||||
|
|
||||||
priv_key2 = rsa.PrivateKey.parse_string(priv_key_str)
|
priv_key2, pub_key2 = rsa.create_signing_keypair_from_string(priv_key_str)
|
||||||
|
|
||||||
self.failUnlessEqual(priv_key, priv_key2)
|
# instead of asking "are these two keys equal", we can instead
|
||||||
|
# test their function: can the second key verify a signature
|
||||||
|
# produced by the first (and FAIL a signature with different
|
||||||
|
# data)
|
||||||
|
|
||||||
pub_key = priv_key.public_key()
|
data_to_sign = b"test data"
|
||||||
pub_key2 = priv_key2.public_key()
|
sig0 = rsa.sign_data(priv_key, data_to_sign)
|
||||||
|
rsa.verify_signature(pub_key2, sig0, data_to_sign)
|
||||||
|
|
||||||
self.failUnlessEqual(pub_key, pub_key2)
|
# ..and the other way
|
||||||
|
sig1 = rsa.sign_data(priv_key2, data_to_sign)
|
||||||
|
rsa.verify_signature(pub_key, sig1, data_to_sign)
|
||||||
|
|
||||||
pub_key_str = pub_key.serialize()
|
# ..and a failed way
|
||||||
|
with self.assertRaises(rsa.BadSignature):
|
||||||
self.assertIsInstance(pub_key_str, six.string_types)
|
rsa.verify_signature(pub_key, sig1, data_to_sign + b"more")
|
||||||
|
|
||||||
pub_key2 = rsa.PublicKey.parse_string(pub_key_str)
|
|
||||||
|
|
||||||
self.failUnlessEqual(pub_key, pub_key2)
|
|
||||||
|
|
Loading…
Reference in New Issue