diff --git a/pyseeder/crypto.py b/pyseeder/crypto.py index 0bca55a..9f64d67 100644 --- a/pyseeder/crypto.py +++ b/pyseeder/crypto.py @@ -61,16 +61,30 @@ def keygen(pub_key, priv_key, user_id, priv_key_password=None): f.write(cert.public_bytes(serialization.Encoding.PEM)) -def append_signature(target_file, priv_key, priv_key_password=None): - """Append signature to the end of file""" - with open(target_file, "rb") as f: - contents = f.read() +def get_signature(contents, priv_key, priv_key_password=None): + """Calculate signature for prepared reseed file""" + """Singing with NoneWithRSA algorithm: https://stackoverflow.com/a/68301530""" + import rsa as pyrsa with open(priv_key, "rb") as kf: - private_key = serialization.load_pem_private_key( - kf.read(), password=priv_key_password, backend=default_backend()) + pk = pyrsa.PrivateKey.load_pkcs1( + serialization.load_pem_private_key( + kf.read(), password=priv_key_password, backend=default_backend() + ).private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.NoEncryption() + ) + ) - signature = private_key.sign(contents, padding.PKCS1v15(), hashes.SHA512()) + digest = hashes.Hash(hashes.SHA512()) + digest.update(contents) + h = digest.finalize() - with open(target_file, "ab") as f: - f.write(signature) + keylength = pyrsa.pkcs1.common.byte_size(pk.n) + padded = pyrsa.pkcs1._pad_for_signing(h, keylength) + payload = pyrsa.pkcs1.transform.bytes2int(padded) + encrypted = pk.blinded_encrypt(payload) + sig = pyrsa.pkcs1.transform.int2bytes(encrypted, keylength) + + return sig diff --git a/pyseeder/su3file.py b/pyseeder/su3file.py index 2f45c5d..cfa0e23 100644 --- a/pyseeder/su3file.py +++ b/pyseeder/su3file.py @@ -24,31 +24,43 @@ class SU3File: self.CONTENT_LENGTH = None self.VERSION = str(int(time.time())).encode("utf-8") #self.keytype = "RSA_SHA512_4096" + self.OUTPUT = None def write(self, filename, priv_key, priv_key_password=None): """Write file to disc""" nullbyte = bytes([0]) + + self.OUTPUT = "I2Psu3".encode("utf-8") + self.OUTPUT += bytes([0,0]) + self.OUTPUT += self.SIGNATURE_TYPE.to_bytes(2, "big") + self.OUTPUT += self.SIGNATURE_LENGTH.to_bytes(2, "big") + self.OUTPUT += nullbyte + self.OUTPUT += bytes([self.VERSION_LENGTH]) + self.OUTPUT += nullbyte + self.OUTPUT += bytes([self.SIGNER_ID_LENGTH]) + self.OUTPUT += self.CONTENT_LENGTH.to_bytes(8, "big") + self.OUTPUT += nullbyte + self.OUTPUT += bytes([self.FILE_TYPE]) + self.OUTPUT += nullbyte + self.OUTPUT += bytes([self.CONTENT_TYPE]) + self.OUTPUT += bytes([0 for _ in range(12)]) + self.OUTPUT += self.VERSION + bytes( + [0 for _ in range(16 - len(self.VERSION))]) + self.OUTPUT += self.SIGNER_ID.encode("utf-8") + self.OUTPUT += self.CONTENT + + with open(filename + "-data", "wb") as f: + f.write(self.OUTPUT) + + signature = pyseeder.crypto.get_signature(self.OUTPUT, priv_key, priv_key_password) + + with open(filename + "-sig", "wb") as f: + f.write(signature) + + self.OUTPUT += signature + with open(filename, "wb") as f: - f.write("I2Psu3".encode("utf-8")) - f.write(bytes([0,0])) - f.write(self.SIGNATURE_TYPE.to_bytes(2, "big")) - f.write(self.SIGNATURE_LENGTH.to_bytes(2, "big")) - f.write(nullbyte) - f.write(bytes([self.VERSION_LENGTH])) - f.write(nullbyte) - f.write(bytes([self.SIGNER_ID_LENGTH])) - f.write(self.CONTENT_LENGTH.to_bytes(8, "big")) - f.write(nullbyte) - f.write(bytes([self.FILE_TYPE])) - f.write(nullbyte) - f.write(bytes([self.CONTENT_TYPE])) - f.write(bytes([0 for _ in range(12)])) - f.write(self.VERSION + bytes( - [0 for _ in range(16 - len(self.VERSION))])) - f.write(self.SIGNER_ID.encode("utf-8")) - f.write(self.CONTENT) - - pyseeder.crypto.append_signature(filename, priv_key, priv_key_password) + f.write(self.OUTPUT) def reseed(self, netdb, yggseeds): """Compress netdb entries and set content""" diff --git a/pyseeder/transports/github.py b/pyseeder/transports/github.py index 7377816..ae998e3 100644 --- a/pyseeder/transports/github.py +++ b/pyseeder/transports/github.py @@ -21,22 +21,28 @@ def run(filename, config): # get release info try: - resp = requests.get(release_info_url, auth=creds) + release = requests.get(release_info_url, auth=creds) except: raise TransportException("Failed to connect to GitHub API") - if resp.status_code is not 200: + if release.status_code is not 200: raise TransportException("Check your GitHub API auth settings") + # fetch release assets + try: + assets = requests.get(release.json()["assets_url"], auth=creds) + except: + raise TransportException("Unable get release assets") + # delete old asset - for x in resp.json()["assets"]: + for x in assets.json(): if x["name"] == asset_name: r = requests.delete(x["url"], auth=creds) if r.status_code is not 204: raise TransportException("Failed to delete asset from GitHub") # upload new asset - upload_url = resp.json()["upload_url"].split("{")[0] # wat + upload_url = release.json()["upload_url"].split("{")[0] # wat headers = {'Content-Type': content_type} params = {'name': asset_name} @@ -45,5 +51,5 @@ def run(filename, config): data=data) if r.status_code is not 201: - raise TransportException("Failed to upload asset to GitHub API") + raise TransportException("Failed to upload asset to GitHub API : code %d" % (r.status_code)) diff --git a/requirements.txt b/requirements.txt index 9be67a1..681d92b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ cryptography>=1.4 +rsa requests