mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-20 17:52:50 +00:00
replaced pytcryptopp rsa with our own wrapper
This commit is contained in:
parent
9e31bfe2f4
commit
8063d93c6d
@ -9,10 +9,10 @@ from twisted.application import service
|
||||
from twisted.application.internet import TimerService
|
||||
from twisted.python.filepath import FilePath
|
||||
from twisted.python.failure import Failure
|
||||
from pycryptopp.publickey import rsa
|
||||
|
||||
import allmydata
|
||||
from allmydata.crypto.ed25519 import SigningKey
|
||||
from allmydata.crypto.rsa import PrivateKey
|
||||
from allmydata.storage.server import StorageServer
|
||||
from allmydata import storage_client
|
||||
from allmydata.immutable.upload import Uploader
|
||||
@ -156,8 +156,8 @@ class KeyGenerator(object):
|
||||
keysize = keysize or self.default_keysize
|
||||
# RSA key generation for a 2048 bit key takes between 0.8 and 3.2
|
||||
# secs
|
||||
signer = rsa.generate(keysize)
|
||||
verifier = signer.get_verifying_key()
|
||||
signer = PrivateKey.generate(keysize)
|
||||
verifier = signer.public_key()
|
||||
return defer.succeed( (verifier, signer) )
|
||||
|
||||
class Terminator(service.Service):
|
||||
|
@ -1,3 +1,7 @@
|
||||
class BadSignature(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BadPrefixError(Exception):
|
||||
pass
|
||||
|
||||
|
@ -17,18 +17,12 @@ base32.
|
||||
|
||||
import six
|
||||
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
|
||||
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption, \
|
||||
PublicFormat
|
||||
|
||||
# When we were still using `pycryptopp`, BadSignatureError was the name of the exception, and now
|
||||
# that we've switched to `cryptography`, we are importing and "re-exporting" this to keep the name
|
||||
# the same (for now).
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
BadSignatureError = InvalidSignature
|
||||
del InvalidSignature
|
||||
|
||||
from allmydata.crypto import remove_prefix
|
||||
from allmydata.crypto import remove_prefix, BadSignature
|
||||
from allmydata.util.base32 import a2b, b2a
|
||||
|
||||
_PRIV_PREFIX = 'priv-v0-'
|
||||
@ -109,7 +103,10 @@ class VerifyingKey:
|
||||
if not isinstance(data, six.binary_type):
|
||||
raise ValueError('data must be bytes')
|
||||
|
||||
self._pub_key.verify(signature, data)
|
||||
try:
|
||||
self._pub_key.verify(signature, data)
|
||||
except InvalidSignature:
|
||||
raise BadSignature
|
||||
|
||||
@classmethod
|
||||
def parse_encoded_key(cls, pub_str):
|
||||
|
117
src/allmydata/crypto/rsa.py
Normal file
117
src/allmydata/crypto/rsa.py
Normal file
@ -0,0 +1,117 @@
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa, padding
|
||||
from cryptography.hazmat.primitives.serialization import load_der_private_key, load_der_public_key, \
|
||||
Encoding, PrivateFormat, PublicFormat, NoEncryption
|
||||
|
||||
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
|
||||
both backwards compatibility and interoperability.
|
||||
|
||||
The docs for `cryptography` suggest to use the constant defined at
|
||||
`cryptography.hazmat.primitives.asymmetric.padding.PSS.MAX_LENGTH`, but this causes old
|
||||
signatures to fail to validate.
|
||||
'''
|
||||
RSA_PSS_SALT_LENGTH = 32
|
||||
|
||||
|
||||
class PrivateKey(RsaMixin):
|
||||
|
||||
def __init__(self, priv_key):
|
||||
self._priv_key = priv_key
|
||||
|
||||
@classmethod
|
||||
def generate(cls, key_size):
|
||||
priv_key = rsa.generate_private_key(
|
||||
public_exponent=65537, # serisously don't change this value
|
||||
key_size=key_size,
|
||||
backend=default_backend()
|
||||
)
|
||||
return cls(priv_key)
|
||||
|
||||
@classmethod
|
||||
def parse_string(cls, priv_key_str):
|
||||
priv_key = load_der_private_key(
|
||||
priv_key_str,
|
||||
password=None,
|
||||
backend=default_backend(),
|
||||
)
|
||||
return cls(priv_key)
|
||||
|
||||
def public_key(self):
|
||||
return PublicKey(self._priv_key.public_key())
|
||||
|
||||
def serialize(self):
|
||||
return self._priv_key.private_bytes(
|
||||
encoding=Encoding.DER,
|
||||
format=PrivateFormat.PKCS8,
|
||||
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):
|
||||
if isinstance(other, type(self)):
|
||||
return self.serialize() == other.serialize()
|
||||
else:
|
||||
return False
|
||||
|
||||
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,
|
||||
format=PublicFormat.SubjectPublicKeyInfo,
|
||||
)
|
||||
|
||||
def verify(self, signature, data):
|
||||
try:
|
||||
self._pub_key.verify(
|
||||
signature,
|
||||
data,
|
||||
padding.PSS(
|
||||
mgf=padding.MGF1(hashes.SHA256()),
|
||||
salt_length=self.RSA_PSS_SALT_LENGTH,
|
||||
),
|
||||
hashes.SHA256(),
|
||||
)
|
||||
except InvalidSignature:
|
||||
raise BadSignature
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, type(self)):
|
||||
return self.serialize() == other.serialize()
|
||||
else:
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
@ -9,7 +9,7 @@ from allmydata.introducer.common import sign_to_foolscap, unsign_from_foolscap,\
|
||||
get_tubid_string_from_ann
|
||||
from allmydata.util import log, yamlutil, connection_status
|
||||
from allmydata.util.rrefutil import add_version_to_remote_reference
|
||||
from allmydata.crypto.ed25519 import BadSignatureError
|
||||
from allmydata.crypto import BadSignature
|
||||
from allmydata.util.assertutil import precondition
|
||||
|
||||
class InvalidCacheError(Exception):
|
||||
@ -238,7 +238,7 @@ class IntroducerClient(service.Service, Referenceable):
|
||||
ann, key_s = unsign_from_foolscap(ann_t)
|
||||
# key is "v0-base32abc123"
|
||||
precondition(isinstance(key_s, str), key_s)
|
||||
except BadSignatureError:
|
||||
except BadSignature:
|
||||
self.log("bad signature on inbound announcement: %s" % (ann_t,),
|
||||
parent=lp, level=log.WEIRD, umid="ZAU15Q")
|
||||
# process other announcements that arrived with the bad one
|
||||
|
@ -229,7 +229,7 @@ class IntroducerService(service.MultiService, Referenceable):
|
||||
self._debug_counts["inbound_message"] += 1
|
||||
self.log("introducer: announcement published: %s" % (ann_t,),
|
||||
umid="wKHgCw")
|
||||
ann, key = unsign_from_foolscap(ann_t) # might raise BadSignatureError
|
||||
ann, key = unsign_from_foolscap(ann_t) # might raise BadSignature
|
||||
service_name = str(ann["service-name"])
|
||||
|
||||
index = (service_name, key)
|
||||
|
@ -9,6 +9,7 @@ from foolscap.api import eventually, fireEventually, DeadReferenceError, \
|
||||
RemoteException
|
||||
|
||||
from allmydata.crypto.aes import AES
|
||||
from allmydata.crypto.rsa import PrivateKey
|
||||
from allmydata.interfaces import IRetrieveStatus, NotEnoughSharesError, \
|
||||
DownloadStopped, MDMF_VERSION, SDMF_VERSION
|
||||
from allmydata.util.assertutil import _assert, precondition
|
||||
@ -17,8 +18,6 @@ from allmydata.util.dictutil import DictOfSets
|
||||
from allmydata import hashtree, codec
|
||||
from allmydata.storage.server import si_b2a
|
||||
|
||||
from pycryptopp.publickey import rsa
|
||||
|
||||
from allmydata.mutable.common import CorruptShareError, BadShareError, \
|
||||
UncoordinatedWriteError
|
||||
from allmydata.mutable.layout import MDMFSlotReadProxy
|
||||
@ -936,13 +935,11 @@ class Retrieve(object):
|
||||
# it's good
|
||||
self.log("got valid privkey from shnum %d on reader %s" %
|
||||
(reader.shnum, reader))
|
||||
privkey = rsa.create_signing_key_from_string(alleged_privkey_s)
|
||||
privkey = PrivateKey.parse_string(alleged_privkey_s)
|
||||
self._node._populate_encprivkey(enc_privkey)
|
||||
self._node._populate_privkey(privkey)
|
||||
self._need_privkey = False
|
||||
|
||||
|
||||
|
||||
def _done(self):
|
||||
"""
|
||||
I am called by _download_current_segment when the download process
|
||||
@ -973,7 +970,6 @@ class Retrieve(object):
|
||||
self._consumer.unregisterProducer()
|
||||
eventually(self._done_deferred.callback, ret)
|
||||
|
||||
|
||||
def _raise_notenoughshareserror(self):
|
||||
"""
|
||||
I am called when there are not enough active servers left to complete
|
||||
|
@ -8,11 +8,12 @@ from twisted.internet import defer
|
||||
from twisted.python import failure
|
||||
from foolscap.api import DeadReferenceError, RemoteException, eventually, \
|
||||
fireEventually
|
||||
from allmydata.crypto import BadSignature
|
||||
from allmydata.crypto.rsa import PublicKey, PrivateKey
|
||||
from allmydata.util import base32, hashutil, log, deferredutil
|
||||
from allmydata.util.dictutil import DictOfSets
|
||||
from allmydata.storage.server import si_b2a
|
||||
from allmydata.interfaces import IServermapUpdaterStatus
|
||||
from pycryptopp.publickey import rsa
|
||||
|
||||
from allmydata.mutable.common import MODE_CHECK, MODE_ANYTHING, MODE_WRITE, \
|
||||
MODE_READ, MODE_REPAIR, CorruptShareError
|
||||
@ -843,8 +844,9 @@ class ServermapUpdater(object):
|
||||
# This is a new version tuple, and we need to validate it
|
||||
# against the public key before keeping track of it.
|
||||
assert self._node.get_pubkey()
|
||||
valid = self._node.get_pubkey().verify(prefix, signature[1])
|
||||
if not valid:
|
||||
try:
|
||||
self._node.get_pubkey().verify(prefix, signature[1])
|
||||
except BadSignature:
|
||||
raise CorruptShareError(server, shnum,
|
||||
"signature is invalid")
|
||||
|
||||
@ -913,12 +915,10 @@ class ServermapUpdater(object):
|
||||
verinfo,
|
||||
update_data)
|
||||
|
||||
|
||||
def _deserialize_pubkey(self, pubkey_s):
|
||||
verifier = rsa.create_verifying_key_from_string(pubkey_s)
|
||||
verifier = PublicKey.parse_string(pubkey_s)
|
||||
return verifier
|
||||
|
||||
|
||||
def _try_to_validate_privkey(self, enc_privkey, server, shnum, lp):
|
||||
"""
|
||||
Given a writekey from a remote server, I validate it against the
|
||||
@ -937,7 +937,7 @@ class ServermapUpdater(object):
|
||||
self.log("got valid privkey from shnum %d on serverid %s" %
|
||||
(shnum, server.get_name()),
|
||||
parent=lp)
|
||||
privkey = rsa.create_signing_key_from_string(alleged_privkey_s)
|
||||
privkey = PrivateKey.parse_string(alleged_privkey_s)
|
||||
self._node._populate_encprivkey(enc_privkey)
|
||||
self._node._populate_privkey(privkey)
|
||||
self._need_privkey = False
|
||||
|
1
src/allmydata/test/data/pycryptopp-rsa-2048-priv.txt
Normal file
1
src/allmydata/test/data/pycryptopp-rsa-2048-priv.txt
Normal file
@ -0,0 +1 @@
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC0JwgBbVsI+XlOopqjvBatKkQbJPXuap7Psbe5i4EoMfiYI2PC2UB7GuYeTdE79TvDtmfjFD/RVWA3Y/RTQYQz/lKyCFS4w3wa/TPkZwF1r3OjIMSsCYe2J3W9NV3cK+PVw2A8D2y5DvUIAdO+Mi6aH26p2UV8FTnPqHWvJubrcLQt6979/BQnqKCFJ+SPx4se5XsMZ3vrbs6MCqM2qS9RnNEhexlNrJd1wXezILKsmQdf/QiZiY7LXjEdD6BNG8OYQ2iSbCa8aGEoSPQfdnZZxcTFE02QwKcScZKhU9fRv0Ttqr3i8xiliw9gn4UzptEZO6MVO2BrptS30SjJDXC7AgERAoIBADpI3PFnJPtfxV00m3E1UqFvjoFAqetAnMq5fzR/9RSIo0BHr1Wgo+uXwuuvw7GEC85gqSPR2GlfYuS+dLGGIz3/dRt7KngDAoEzzQYhU0u4w4eZqQp7jcn9tSagUxKGq5f7cfVQSNJ1x77TaibyHiLN7xjVWj67krQf6dbI0j0cYvnxu+4EZbzNdvFw93ddoOZB/dFjLu0kVKVl/mWyCX9GNr2nCSHe9wYipOz5b9WkdD0J2Oy0v8Wkn4y3yOOvo/EgrNYfo4IVslsDo9Yw3Yk32Eml0ZsdwSqu+wM4c+jRbTJ+sBGqci4etPpMhcsH0Vt9+97Lnuan2Jza9xjrL2ECgYEA8wj+/bfjTCXsu22f8V7Z40vJUyM7j4WvUoA9khAQ7qAlnFdqdzq5a7ArA9vRjeN6ya16j36IXCkpT+FGe6YWCsZCKd1ZVy7sZ1Uh7X2hRqf0vxJsSJvG/OmofFUfuwCgLFLKI4SDhHaB+pWAdkAIL4MkJQADg/qVlAdrWoPsfhECgYEAvcNHhSCW010SRudwmTRX5QtndHk/LM6VAgyR0ElarvmG6K5pbpL8MD5CpJ3AhUwKp96SlMsBEG3a9BR5zv6Jvhc/KHxT7W/EjLnV9PSD90+BgHHsTonjg6TayJ9XE6RpO3MqeifVG/2S5WhhFFGGd5KSFnvZwr9ni+LYRuDVpgsCgYEAgKpo4KylgqqqgVgnf8jNtJGIs4sfiDe3K61NxcxFMwl9UsTeAuLaomxTAgr2eEtBAVvXeSTex2EV3v7K9irAYA6bf5NNamQizUswFFGRneByg0X9F2GHdtYN53hcF7UJgOCJIdy+GPNx/SH4txLXKDZebfDyzWaLbHxmAr5QBoECgYBC+aDFkwgOXRWCb81jP6aNExV0Zwc8/Z4AuSRnoWtM0In3xRYnBrNcUjWjgvinhD//A0LLGnjYnz44BzoM0k67j7vwK+Fi3CdAug9HZVvAsqYtVWJ2EoyI0MWwODzZwY6Nc/Df0dK+lbtgBrjZ/qft937awkzbUp0EMfH65fENbQKBgQCSVWXy+WLQXeHtx/+nNv9HyjQnowalp3SwWRf0YoK/xa526xg+ixViVZvT6e2KTcJGdHFQ+cbCsc1Vx6E13n3Mu9y0N3a4WRQkZHPgnsNouPLaKn0SmVY7RX/I/Rz2r0hRE+gDM6+1/99zPuwP3FW5eLoTBX021Y35kBFHbZ4r+w==
|
1
src/allmydata/test/data/pycryptopp-rsa-2048-pub.txt
Normal file
1
src/allmydata/test/data/pycryptopp-rsa-2048-pub.txt
Normal file
@ -0,0 +1 @@
|
||||
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAtCcIAW1bCPl5TqKao7wWrSpEGyT17mqez7G3uYuBKDH4mCNjwtlAexrmHk3RO/U7w7Zn4xQ/0VVgN2P0U0GEM/5SsghUuMN8Gv0z5GcBda9zoyDErAmHtid1vTVd3Cvj1cNgPA9suQ71CAHTvjIumh9uqdlFfBU5z6h1rybm63C0Leve/fwUJ6ighSfkj8eLHuV7DGd7627OjAqjNqkvUZzRIXsZTayXdcF3syCyrJkHX/0ImYmOy14xHQ+gTRvDmENokmwmvGhhKEj0H3Z2WcXExRNNkMCnEnGSoVPX0b9E7aq94vMYpYsPYJ+FM6bRGTujFTtga6bUt9EoyQ1wuwIBEQ==
|
1
src/allmydata/test/data/pycryptopp-rsa-2048-sig.txt
Normal file
1
src/allmydata/test/data/pycryptopp-rsa-2048-sig.txt
Normal file
@ -0,0 +1 @@
|
||||
ItsyW1XTOIvet6WsS68AJ/ernMG62aoeJKzyBBZ9fdeB2mVzURCBmgX5P0hTPgxHa1sEI6oIbREv4lIQnWHcPgjvz5qBkDtbOp1YHkkFAFOh533dH4s2MiRECIzHh19sBsqTGe0w/pRTHhwV+nStFqZ0IMsdxv0Qsgk5IClIY/WgBSnHQZpVbxyfL7qwvm1JK2GRuygRRsrSsxLiSnA5RWlOsDkDikVu5nhZI31K+PWa9v1i6U7ZkV4uD9triJkHW2XBIRkCyqT6wgM4KBN6V4H9nqlxZhJSQoSn1U5Rh3pL+XG6yevaZq7+pwOnRUcFkEwiJ2wT/NIK0Bjng8Szmw==
|
@ -1,10 +1,14 @@
|
||||
import six
|
||||
import unittest
|
||||
|
||||
from base64 import b64decode
|
||||
from binascii import a2b_hex, b2a_hex
|
||||
from os import path
|
||||
|
||||
from allmydata.crypto.aes import AES
|
||||
from allmydata.crypto.ed25519 import SigningKey, VerifyingKey
|
||||
from allmydata.crypto import ed25519, rsa
|
||||
|
||||
RESOURCE_DIR = path.join(path.dirname(__file__), 'data')
|
||||
|
||||
|
||||
class TestRegression(unittest.TestCase):
|
||||
@ -14,9 +18,35 @@ class TestRegression(unittest.TestCase):
|
||||
keys.
|
||||
'''
|
||||
|
||||
KEY = b'My\x9c\xc0f\xd3\x03\x9a1\x8f\xbd\x17W_\x1f2'
|
||||
AES_KEY = b'My\x9c\xc0f\xd3\x03\x9a1\x8f\xbd\x17W_\x1f2'
|
||||
IV = b'\x96\x1c\xa0\xbcUj\x89\xc1\x85J\x1f\xeb=\x17\x04\xca'
|
||||
|
||||
with open(path.join(RESOURCE_DIR, 'pycryptopp-rsa-2048-priv.txt')) as f:
|
||||
'''
|
||||
Created using `pycryptopp`:
|
||||
|
||||
from base64 import b64encode
|
||||
from pycryptopp.publickey import rsa
|
||||
priv = rsa.generate(2048)
|
||||
priv_str = b64encode(priv.serialize())
|
||||
pub_str = b64encode(priv.get_verifying_key().serialize())
|
||||
'''
|
||||
RSA_2048_PRIV_KEY = six.b(b64decode(f.read().strip()))
|
||||
|
||||
with open(path.join(RESOURCE_DIR, 'pycryptopp-rsa-2048-sig.txt')) as f:
|
||||
'''
|
||||
Signature created using `RSA_2048_PRIV_KEY` via:
|
||||
|
||||
sig = priv.sign(b'test')
|
||||
'''
|
||||
RSA_2048_SIG = six.b(b64decode(f.read().strip()))
|
||||
|
||||
with open(path.join(RESOURCE_DIR, 'pycryptopp-rsa-2048-pub.txt')) as f:
|
||||
'''
|
||||
The public key corresponding to `RSA_2048_PRIV_KEY`.
|
||||
'''
|
||||
RSA_2048_PUB_KEY = six.b(b64decode(f.read().strip()))
|
||||
|
||||
def test_old_start_up_test(self):
|
||||
"""
|
||||
This was the old startup test run at import time in `pycryptopp.cipher.aes`.
|
||||
@ -74,7 +104,7 @@ class TestRegression(unittest.TestCase):
|
||||
plaintext = b'test'
|
||||
expected_ciphertext = b'\x7fEK\\'
|
||||
|
||||
aes = AES(self.KEY)
|
||||
aes = AES(self.AES_KEY)
|
||||
ciphertext = aes.process(plaintext)
|
||||
|
||||
self.failUnlessEqual(ciphertext, expected_ciphertext)
|
||||
@ -96,7 +126,7 @@ class TestRegression(unittest.TestCase):
|
||||
b'\x1f\xa1|\xd2$E\xb5\xe7\x9d\xae\xd1\x1f)\xe4\xc7\x83\xb8\xd5|dHhU\xc8\x9a\xb1\x10\xed'
|
||||
b'\xd1\xe7|\xd1')
|
||||
|
||||
aes = AES(self.KEY)
|
||||
aes = AES(self.AES_KEY)
|
||||
ciphertext = aes.process(plaintext)
|
||||
|
||||
self.failUnlessEqual(ciphertext, expected_ciphertext)
|
||||
@ -115,7 +145,7 @@ class TestRegression(unittest.TestCase):
|
||||
plaintext = b'test'
|
||||
expected_ciphertext = b'\x82\x0e\rt'
|
||||
|
||||
aes = AES(self.KEY, iv=self.IV)
|
||||
aes = AES(self.AES_KEY, iv=self.IV)
|
||||
ciphertext = aes.process(plaintext)
|
||||
|
||||
self.failUnlessEqual(ciphertext, expected_ciphertext)
|
||||
@ -137,8 +167,7 @@ class TestRegression(unittest.TestCase):
|
||||
b'\x97a\xdc\x100?\xf5L\x9f\xd9\xeeO\x98\xda\xf5g\x93\xa7q\xe1\xb1~\xf8\x1b\xe8[\\s'
|
||||
b'\x144$\x86\xeaC^f')
|
||||
|
||||
|
||||
aes = AES(self.KEY, iv=self.IV)
|
||||
aes = AES(self.AES_KEY, iv=self.IV)
|
||||
ciphertext = aes.process(plaintext)
|
||||
|
||||
self.failUnlessEqual(ciphertext, expected_ciphertext)
|
||||
@ -165,8 +194,8 @@ class TestRegression(unittest.TestCase):
|
||||
b'\x86 ier!\xe8\xe5#*\x9d\x8c\x0bI\x02\xd90\x0e7\xbeW\xbf\xa3\xfe\xc1\x1c\xf5+\xe9)'
|
||||
b'\xa3\xde\xc9\xc6s\xc9\x90\xf7x\x08')
|
||||
|
||||
priv_key = SigningKey.parse_encoded_key(priv_str)
|
||||
pub_key = VerifyingKey.parse_encoded_key(pub_str)
|
||||
priv_key = ed25519.SigningKey.parse_encoded_key(priv_str)
|
||||
pub_key = ed25519.VerifyingKey.parse_encoded_key(pub_str)
|
||||
|
||||
self.failUnlessEqual(priv_key.public_key(), pub_key)
|
||||
|
||||
@ -175,17 +204,30 @@ class TestRegression(unittest.TestCase):
|
||||
|
||||
pub_key.verify(new_sig, test_data)
|
||||
|
||||
def test_decode_rsa_keypair(self):
|
||||
'''
|
||||
This simply checks that keys and signatures generated using the old code are still valid
|
||||
using the new code.
|
||||
'''
|
||||
priv_key = rsa.PrivateKey.parse_string(self.RSA_2048_PRIV_KEY)
|
||||
pub_key = priv_key.public_key()
|
||||
|
||||
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):
|
||||
|
||||
def test_keys(self):
|
||||
priv_key = SigningKey.generate()
|
||||
priv_key = ed25519.SigningKey.generate()
|
||||
priv_key_str = priv_key.encoded_key()
|
||||
|
||||
self.assertIsInstance(priv_key_str, six.string_types)
|
||||
self.assertIsInstance(priv_key.private_bytes(), six.binary_type)
|
||||
|
||||
priv_key2 = SigningKey.parse_encoded_key(priv_key_str)
|
||||
priv_key2 = ed25519.SigningKey.parse_encoded_key(priv_key_str)
|
||||
|
||||
self.failUnlessEqual(priv_key, priv_key2)
|
||||
|
||||
@ -199,6 +241,32 @@ class TestEd25519(unittest.TestCase):
|
||||
self.assertIsInstance(pub_key_str, six.string_types)
|
||||
self.assertIsInstance(pub_key.public_bytes(), six.binary_type)
|
||||
|
||||
pub_key2 = VerifyingKey.parse_encoded_key(pub_key_str)
|
||||
pub_key2 = ed25519.VerifyingKey.parse_encoded_key(pub_key_str)
|
||||
|
||||
self.failUnlessEqual(pub_key, pub_key2)
|
||||
|
||||
|
||||
class TestRsa(unittest.TestCase):
|
||||
|
||||
def test_keys(self):
|
||||
priv_key = rsa.PrivateKey.generate(2048)
|
||||
priv_key_str = priv_key.serialize()
|
||||
|
||||
self.assertIsInstance(priv_key_str, six.string_types)
|
||||
|
||||
priv_key2 = rsa.PrivateKey.parse_string(priv_key_str)
|
||||
|
||||
self.failUnlessEqual(priv_key, priv_key2)
|
||||
|
||||
pub_key = priv_key.public_key()
|
||||
pub_key2 = priv_key2.public_key()
|
||||
|
||||
self.failUnlessEqual(pub_key, pub_key2)
|
||||
|
||||
pub_key_str = pub_key.serialize()
|
||||
|
||||
self.assertIsInstance(pub_key_str, six.string_types)
|
||||
|
||||
pub_key2 = rsa.PublicKey.parse_string(pub_key_str)
|
||||
|
||||
self.failUnlessEqual(pub_key, pub_key2)
|
||||
|
@ -1006,7 +1006,7 @@ class Signatures(SyncTestCase):
|
||||
# bad signature
|
||||
bad_ann = {"key1": "value2"}
|
||||
bad_msg = json.dumps(bad_ann).encode("utf-8")
|
||||
self.failUnlessRaises(ed25519.BadSignatureError,
|
||||
self.failUnlessRaises(crypto.BadSignature,
|
||||
unsign_from_foolscap, (bad_msg, sig, key))
|
||||
|
||||
# unrecognized signatures
|
||||
|
Loading…
x
Reference in New Issue
Block a user