class reqPGP(object): def __init__(self, path=None): self.gpg = GPG(gpgbinary=('../gpg.exe' if osName == 'nt' else 'gpg')) if not path: try: self.path = environ["HOME"] + '/' except KeyError: self.path = environ["HOMEPATH"] + '\\' else: if path[-1] != '\\' and osName == 'nt': path += '\\' elif path[-1] != '/' and osName == 'posix': path += '/' self.path = path def genKey(self, account, passphrase): input_data = self.gpg.gen_key_input( name_email=account, passphrase=passphrase) self.gpg.gen_key(input_data) def encryptFile(self, account, data): encryptedData = str(self.gpg.encrypt(data, account)) with open(self.path + '.' + account + '.req', 'w') as f: f.write(encryptedData) def decryptFile(self, account, passphrase): with open(self.path + '.' + account + '.req', 'rb') as f: decryptedData = str(self.gpg.decrypt_file(f, passphrase=passphrase)) return decryptedData def deleteKey(self, keyId): self.gpg.delete_keys(keyId, True) self.gpg.delete_keys(keyId)
def generate_keys(gpg: gnupg.GPG, company_name: str, targer_folder: str): company_path, public_file_name, secret_file_name = __get_absolut_filepath( company_name=company_name) configuration_kwargs = utils.get_configuratation( path=os.path.join(targer_folder, 'configuration')) os.makedirs(company_path, exist_ok=True) gpg_keys = gpg.gen_key_input(**configuration_kwargs.get('array')) key = gpg.gen_key(gpg_keys) ascii_armored_public_keys = gpg.export_keys(key.fingerprint) ascii_armored_private_keys = gpg.export_keys( key.fingerprint, secret=True, passphrase=configuration_kwargs.get('array')['passphrase'], ) with open(public_file_name, 'w') as file: file.write(ascii_armored_public_keys) logger.info(f'Generate file to export to customer done') with open(secret_file_name, 'w') as file: file.write(ascii_armored_public_keys) file.write(ascii_armored_private_keys) logger.info(f'Generate file to use done') _clean_directory(path=settings.PROJECT_NAME)
class reqPGP(object): def __init__(self, path=None): self.gpg = GPG(gpgbinary=('../gpg.exe' if osName == 'nt' else 'gpg')) if not path: try: self.path = environ["HOME"] + '/' except KeyError: self.path = environ["HOMEPATH"] + '\\' else: if path[-1] != '\\' and osName == 'nt': path += '\\' elif path[-1] != '/' and osName == 'posix': path += '/' self.path = path def genKey(self, account, passphrase): input_data = self.gpg.gen_key_input(name_email=account, passphrase=passphrase) self.gpg.gen_key(input_data) def encryptFile(self, account, data): encryptedData = str(self.gpg.encrypt(data, account)) with open(self.path + '.' + account + '.req', 'w') as f: f.write(encryptedData) def decryptFile(self, account, passphrase): with open(self.path + '.' + account + '.req', 'rb') as f: decryptedData = str(self.gpg.decrypt_file(f, passphrase=passphrase)) return decryptedData def deleteKey(self, keyId): self.gpg.delete_keys(keyId, True) self.gpg.delete_keys(keyId)
def _generate_key(username): gpg = GPG() key_input = gpg.gen_key_input(key_type="RSA", key_length=1024, name_email=username+"@node.org", name_real=username) entropy_thread = Process(target=generate_entropy) entropy_thread.start() key = gpg.gen_key(key_input) entropy_thread.terminate() keys = gpg.list_keys(True) for k in keys: if k.get("fingerprint") == key.fingerprint: return k['keyid']
class Test(unittest.TestCase): '''Unit test cases for signing envelopes from the Learning Registry''' def __init__(self, methodName="runTest"): self.gpgbin="/usr/local/bin/gpg" self.gnupgHome = os.path.expanduser(os.path.join("~", ".gnupg")) self.gpg = GPG(gpgbinary=self.gpgbin, gnupghome=self.gnupgHome) unittest.TestCase.__init__(self, methodName) self.testDataDir = None configFile = os.path.join("config.cfg") if os.path.exists(configFile): config = json.load(file(configFile)) if config.has_key("global"): if config["global"].has_key("testdata") and os.path.exists(config["global"]["testdata"]): self.testDataDir = config["global"]["testdata"] def setUp(self): now = time.localtime() now = calendar.timegm(now) self.goodEmail = "signTest-{0}@learningregistry.org".format(now) self.goodRealName = "Autogenerated Sign Test" self.goodpassphrase = "supersecret" input = self.gpg.gen_key_input(name_real=self.goodRealName, name_email=self.goodEmail, passphrase=self.goodpassphrase) self.goodPrivateKey = self.gpg.gen_key(input) privateKeyAvailable = False privateKeys = self.gpg.list_keys(secret=True) for skey in privateKeys: if skey["keyid"] == self.goodPrivateKey.fingerprint: privateKeyAvailable = True self.privateKeyInfo = skey break if skey["fingerprint"] == self.goodPrivateKey.fingerprint: privateKeyAvailable = True self.privateKeyInfo = skey break assert privateKeyAvailable == True, "Could not locate generated Private Key" self.goodkeyid = self.privateKeyInfo["keyid"] self.goodowner = self.privateKeyInfo["uids"][0] self.badkeyid = "XXXXXXXXXXXXXXXX" self.badpassphrase = "bad passphrase" self.sampleJSON = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data":"<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "keys":["United States--Description and travel.","eng"], "submitter_type":"agent", "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "submitter":"NSDL 2 LR Data Pump", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.10.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleJSON_strip = '''{"keys": ["United States--Description and travel.", "eng"], "TOS": {"submission_attribution": "unidentified", "submission_TOS": "http://example.com/tos/unknown"}, "payload_placement": "inline", "active": true, "resource_locator": "http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_type": "resource_data", "resource_data": "<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "submitter_type": "agent", "resource_data_type": "metadata", "payload_schema_locator": "http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_schema": ["oai_dc"], "doc_version": "0.10.0", "submitter": "NSDL 2 LR Data Pump"}''' self.sampleJSON_strip_normal = '''{"keys": ["United States--Description and travel.", "eng"], "TOS": {"submission_attribution": "unidentified", "submission_TOS": "http://example.com/tos/unknown"}, "payload_placement": "inline", "active": "true", "resource_locator": "http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_type": "resource_data", "resource_data": "<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "submitter_type": "agent", "resource_data_type": "metadata", "payload_schema_locator": "http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_schema": ["oai_dc"], "doc_version": "0.10.0", "submitter": "NSDL 2 LR Data Pump"}''' self.sampleJSON_strip_normal_bencode = '''d3:TOSd14:submission_TOS30:http://example.com/tos/unknown22:submission_attribution12:unidentifiede6:active4:true8:doc_type13:resource_data11:doc_version6:0.10.04:keysl38:United States--Description and travel.3:enge17:payload_placement6:inline14:payload_schemal6:oai_dce22:payload_schema_locator90:http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd13:resource_data968:<oai_dc:dc xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openarchives.org/OAI/2.0/" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">\n<dc:title>A chat about America. October and November, 1884.</dc:title>\n<dc:creator>J. P.</dc:creator>\n<dc:subject>United States--Description and travel.</dc:subject>\n<dc:description>"Printed for private circulation only."</dc:description>\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\n<dc:date>1885</dc:date>\n<dc:type>text</dc:type>\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\n<dc:language>eng</dc:language>\n<dc:coverage>United States</dc:coverage>\n</oai_dc:dc>\n 18:resource_data_type8:metadata16:resource_locator38:http://hdl.loc.gov/loc.gdc/lhbtn.122819:submitter19:NSDL 2 LR Data Pump14:submitter_type5:agente''' self.sampleJSON_sha256 = '''ef1b3b63adc663602c7a3c7595951b2761b34f5f6490ea1acee3df0fd97db03c''' self.sampleKeyLocations = [ "http://example.com/mykey", "http://example2.com/mykey" ] self.signatureTemplate = '{{"key_location": [{0}], "key_owner": "'+self.goodowner+'", "signing_method": "LR-PGP.1.0", "signature": "{1}"}}' def tearDown(self): self.gpg.delete_keys([self.goodPrivateKey.fingerprint, ], secret=True) self.gpg.delete_keys([self.goodPrivateKey.fingerprint, ], secret=False) pass def testMissingPrivateKey(self): def missingKey(): try: sign = Sign_0_21(self.badkeyid) except UnknownKeyException as e: assert e.keyid == self.badkeyid, "keyid in exception doesn't match key passed to sign." raise e self.assertRaises(UnknownKeyException, missingKey) def testPresentPrivateKey(self): sign = Sign_0_21(self.goodkeyid) assert sign.privateKeyID == self.goodkeyid def testStrip(self): origJson = json.loads(self.sampleJSON) benchmark = json.loads(self.sampleJSON_strip) signer = Sign_0_21(self.goodkeyid) stripJson = signer._stripEnvelope(origJson) assert benchmark == stripJson def testStripNormal(self): origJson = json.loads(self.sampleJSON) benchmark = json.loads(self.sampleJSON_strip_normal) signer = Sign_0_21(self.goodkeyid) stripJson = signer._stripEnvelope(origJson) normalJson = signer._bnormal(stripJson) assert benchmark == normalJson def testStripNormalBencode(self): origJson = json.loads(self.sampleJSON) benchmark = self.sampleJSON_strip_normal_bencode signer = Sign_0_21(self.goodkeyid) stripJson = signer._stripEnvelope(origJson) normalJson = signer._bnormal(stripJson) bencodeJson = signer._buildCanonicalString(normalJson) assert benchmark == bencodeJson def testStripNormalBencodeHash(self): origJson = json.loads(self.sampleJSON) benchmark = self.sampleJSON_sha256 signer = Sign_0_21(self.goodkeyid) stripJson = signer._stripEnvelope(origJson) normalJson = signer._bnormal(stripJson) bencodeJson = signer._buildCanonicalString(normalJson) hash = signer._hash(bencodeJson) assert benchmark == hash def testGetMessage(self): origJson = json.loads(self.sampleJSON) benchmark = self.sampleJSON_sha256 signer = Sign_0_21(self.goodkeyid) message = signer.get_message(origJson) assert benchmark == message def testPrivateKeyOwner(self): benchmark = self.goodowner signer = Sign_0_21(self.goodkeyid) assert benchmark == signer._get_privatekey_owner() def testSigBlock(self): origJson = json.loads(self.sampleJSON) arbitrarySigdata = "ABCDEF0123456789-abcdef" arbitraryKeyLoc = self.sampleKeyLocations keyloc = ",".join(map(lambda x: '"{0}"'.format(x), arbitraryKeyLoc)) benchmark = json.loads(self.signatureTemplate.format(keyloc, arbitrarySigdata)) signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc) assert benchmark == signer._get_sig_block(arbitrarySigdata) def testSign(self): origJson = json.loads(self.sampleJSON) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc) signed = signer.sign(origJson) assert signed.has_key("digital_signature") sig = signed["digital_signature"] assert sig.has_key("signature") assert sig["signature"] != None and len(sig["signature"]) > 0 def testSignUnicode(self): if self.testDataDir == None: log.info("Skipping test, test data directory not set.") return import codecs fileName = "2011-02-28Metadata1004.json" unsigned = json.load(codecs.open(os.path.join(self.testDataDir, fileName), "r", "utf-8-sig")) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc) signed = signer.sign(unsigned) assert signed.has_key("digital_signature") sig = signed["digital_signature"] assert sig.has_key("signature") assert sig["signature"] != None and len(sig["signature"]) > 0 def testSignLRTestData(self): if self.testDataDir == None: log.info("Skipping test, test data directory not set.") return import codecs allfiles = os.listdir(self.testDataDir) for fileName in allfiles: log.info("Trying to sign %s" % (fileName, )) unsigned = json.load(codecs.open(os.path.join(self.testDataDir, fileName), "r", "utf-8-sig")) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc) signed = signer.sign(unsigned) assert signed.has_key("digital_signature") sig = signed["digital_signature"] assert sig.has_key("signature") assert sig["signature"] != None and len(sig["signature"]) > 0
class Test(unittest.TestCase): '''Unit tests for validating signed envelopes from the Learning Registry''' def __init__(self, methodName="runTest"): self.sampleJSON = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data":"<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "keys":["United States--Description and travel.","eng"], "submitter_type":"agent", "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "submitter":"NSDL 2 LR Data Pump", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.10.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleKeyLocations = [ "http://example.com/mykey", "http://example2.com/mykey" ] self.gpgbin = "gpg" self.gnupgHome = os.path.expanduser( os.path.abspath(os.path.join("..", "gnupg_home"))) self.gpg = None self.testDataDir = None self.testDataUnicode = None configFile = os.path.join("config.cfg") if os.path.exists(configFile): config = json.load(file(configFile)) if "global" in config: if "testdata" in config["global"] and os.path.exists( config["global"]["testdata"]): self.testDataDir = config["global"]["testdata"] if "testdata_unicode" in config["global"] and os.path.exists( config["global"]["testdata_unicode"]): self.testDataUnicode = config["global"]["testdata_unicode"] unittest.TestCase.__init__(self, methodName) def setUp(self): now = time.localtime() now = calendar.timegm(now) try: for root, dirs, files in os.walk(self.gnupgHome): for filename in files: try: os.unlink(os.path.join(root, filename)) except: pass os.removedirs(root) except: pass os.makedirs(self.gnupgHome) self.gpg = GPG(gpgbinary=self.gpgbin, gnupghome=self.gnupgHome) self.privateEmail = "privateTest-{0}@learningregistry.org".format(now) self.privateEmail2 = "privateTest2-{0}@learningregistry.org".format( now) self.genericPassphrase = "supersecret" input = self.gpg.gen_key_input(name_email=self.privateEmail, passphrase=self.genericPassphrase) self.privateKey = self.gpg.gen_key(input) input = self.gpg.gen_key_input(name_email=self.privateEmail2, passphrase=self.genericPassphrase) self.privateKey2 = self.gpg.gen_key(input) self.privExport = self.gpg.export_keys( [self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=True) self.pubExport = self.gpg.export_keys( [self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=False) pass def tearDown(self): self.gpg.delete_keys( [self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=True) self.gpg.delete_keys( [self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=False) pass def testGetSignatureBlock(self): '''Check that signature block validation correctly returns a structurally valid response''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "envelope did not sign correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) sigInfo = verifytool._getSignatureInfo(signed) assert sigInfo != None, "signature extraction from envelope failed" assert "signing_method" in sigInfo and sigInfo[ "signing_method"] == verifytool.signatureMethod, "signing_method is missing from signature block" assert "signature" in sigInfo and sigInfo["signature"] != None and len( sigInfo["signature"] ) > 0, "signature field is missing, null or is empty" assert "key_location" in sigInfo and sigInfo[ "key_location"] == self.sampleKeyLocations, "key_location field is not correct" assert "key_owner" in sigInfo and sigInfo[ "key_owner"] == signtool._get_privatekey_owner( ), "key_owner field does not match signing key" def testBadSignatureBlockMissingLocation(self): '''Check that signature block validation correctly checks for missing key_location field''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=None) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_KEY_LOCATION, "Exception not formatted with correct message" def testBadSignatureBlockMissingSignatureMethod(self): '''Check signature block for missing signature_method detection''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly." del signed["digital_signature"]["signing_method"] verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.UnsupportedSignatureAlgorithm, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.alg == None, "Raised exception not formatted correctly" def testBadSignatureBlockBadSignatureMethod(self): '''Check signature block for detecting unsupported algorithm use''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None signed["digital_signature"][ "signing_method"] = signtool.signatureMethod + "+BAD_SIGNATURE_METHOD" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.UnsupportedSignatureAlgorithm, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.alg == signed["digital_signature"][ "signing_method"], "Exception not raised correctly." def testBadSignatureBlockBadKeyOwner(self): '''Check signature block for a bad key_owner field''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly" signed["digital_signature"]["key_owner"] = [ "John Q. Public <*****@*****.**>" ] verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.BAD_KEY_OWNER, "Wrong exception" def testBadSignatureBlockMissingNullEmptySignature(self): '''Check signature block validation with missing/null or empty signature''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope signing did not succeed correctly." verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) signed["digital_signature"]["signature"] = "" with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" signed["digital_signature"]["signature"] = None with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" del signed["digital_signature"]["signature"] with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" def testValidSignature(self): '''Check for valid signature''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope did not sign correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "Envelope signature verification did not succeed, even though it should" def testMissingPublicKey(self): '''Check for appropriate response when public key for signature is missing''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope did not sign correctly" self.gpg.delete_keys([self.privateKey.fingerprint], secret=True) self.gpg.delete_keys([self.privateKey.fingerprint], secret=False) verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.MissingPublicKey, msg="Expected exception not raised.") as caught: verified = verifytool.verify(signed) assert verified == False, "Envelope verified, despite missing public key." def testCorruptEnvelope(self): '''Modify a signed envelope and check for validity''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "envelope did not get signed correctly" signed["X_corrupted"] = "Corrupted Envelope" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == False, "corrupted envelope verified as good" def testWrongSignature(self): '''Test using a mis-matched signature, using a signature from a different valid envelope''' unsigned = json.loads(self.sampleJSON) altered = copy.deepcopy(unsigned) altered["X_corrupted"] = "Altered Envelope" signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signtool2 = Sign_0_21(privateKeyID=self.privateKey2.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) alt_signed = signtool2.sign(altered) assert signed != None, "original did not get signed" assert alt_signed != None, "modified copy did not get signed" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "signature did not verify, even though it should." verified = verifytool.verify(alt_signed) assert verified == True, "signature did not verify, even though it should." signed["digital_signature"] = alt_signed["digital_signature"] verified = verifytool.verify(signed) assert verified == False, "swapped signature block validated envelope as good." def testCorruptSignature(self): '''Test using a corrupted signature, replace the hash within a signature with a hash from a different envelope''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "baseline signing failed" # validate original with good signature verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "baseline validation failed" # manipulate the hash portion of a signature block altered = copy.deepcopy(unsigned) altered["X_corrupted"] = "Altered Envelope" altered_hash = signtool.get_message(altered) validHash = verifytool._extractHashFromSignature( signed["digital_signature"]["signature"]) alt_signed = copy.deepcopy(signed) alt_signed["digital_signature"]["signature"] = signed[ "digital_signature"]["signature"].replace(validHash, altered_hash) assert alt_signed["digital_signature"]["signature"] != signed[ "digital_signature"][ "signature"], "envelopes should not be equal after deliberate modificaton" verified = verifytool.verify(alt_signed) assert verified == False, "verification failed, corrupted signature block verified as good" def testSignLRTestData(self): '''Test using LR Test Data, if available''' if self.testDataDir == None: log.info("Skipping test, test data directory not set.") return import codecs signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) allfiles = os.listdir(self.testDataDir) for root, dirs, files in os.walk(self.testDataDir): for fileName in files: log.info("Trying to sign %s" % (fileName, )) unsigned = json.load( codecs.open(os.path.join(root, fileName), "r", "utf-8-sig")) signed = signtool.sign(unsigned) assert "digital_signature" in signed, "missing digital_signature" verified = verifytool.verify(signed) assert verified == True, "baseline validation failed"
def finish_login(message, bot, settings): user_root_folder = '/Seppass/Users_folder/user_' + str(message.chat.id) try: if not path.isdir(user_root_folder+'/main'): makedirs(user_root_folder+'/main') if not path.isdir(user_root_folder+'/user_data'): makedirs(user_root_folder+'/user_data') except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return try: gpg = GPG() input_data = gpg.gen_key_input( passphrase=message.text, name_real='user_'+str(message.chat.id) ) key = gpg.gen_key(input_data) key = key.fingerprint ascii_armored_private_keys = gpg.export_keys(key, True, passphrase=message.text) system('echo RELOADAGENT | gpg-connect-agent') with open(user_root_folder+'/user_data/gpg_private_key.asc', 'w') as f: f.write(ascii_armored_private_keys) with open(user_root_folder+'/main/gpg_private_key.asc', 'w') as f: f.write(ascii_armored_private_keys) except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return try: data = (('user_'+str(message.chat.id), key, str(settings))) conn = connect('DataBase.db', check_same_thread=False) c = conn.cursor() query = "INSERT INTO Users VALUES (?, ?, ?)" c.execute(query, data) conn.commit() conn.close() except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.add('Да') if settings["store_pass"] == "pass_server": try: with open(user_root_folder+'/user_data/Nothing.txt', 'w') as f: f.write(message.text) except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return msg_handler = bot.send_message(message.chat.id, 'Регистрация прошла успешно. Пароль храниться на сервере.\n\nВаш user id:\n'+str(message.chat.id)+'\n\nПароль:\n'+ message.text +'\n\nЭто ваш отпечаток ключа:\n'+ str(key)+'\n\nЗапомнили? Я сейчас это сообщение удалю, в целях сохранности ваших данных.', reply_markup = markup) bot.register_next_step_handler(msg_handler, lambda msg: complete_finish_login(msg, bot)) else: msg_handler = bot.send_message(message.chat.id, 'Регистрация прошла успешно. Запомните пароль, в случае его утери ваш акк не восстановить (пока).\n\nВаш user id:\n'+str(message.chat.id)+'\n\nПароль:\n'+ message.text +'\n\nЭто ваш отпечаток ключа:\n'+ str(key)+'\n\nЗапомнили? Я сейчас это сообщение удалю, в целях сохранности ваших данных.', reply_markup = markup) bot.register_next_step_handler(msg_handler, lambda msg: complete_finish_login(msg, bot))
class Test(unittest.TestCase): '''Unit test cases for signing envelopes from the Learning Registry''' def __init__(self, methodName="runTest"): self.gpgbin = "gpg" self.gnupgHome = os.path.expanduser( os.path.abspath(os.path.join("..", "gnupg_home"))) try: os.makedirs(self.gnupghome) except: pass self.gpg = None unittest.TestCase.__init__(self, methodName) self.testDataDir = None self.testDataUnicode = None configFile = os.path.join("config.cfg") if os.path.exists(configFile): config = json.load(file(configFile)) if "global" in config: if "testdata" in config["global"] and os.path.exists( config["global"]["testdata"]): self.testDataDir = config["global"]["testdata"] if "testdata_unicode" in config["global"] and os.path.exists( config["global"]["testdata_unicode"]): self.testDataUnicode = config["global"]["testdata_unicode"] def setUp(self): now = time.localtime() now = calendar.timegm(now) self.goodEmail = "signTest-{0}@learningregistry.org".format(now) self.goodRealName = "Autogenerated Sign Test" self.goodpassphrase = "supersecret" try: for root, dirs, files in os.walk(self.gnupgHome): for filename in files: try: os.unlink(os.path.join(root, filename)) except: pass os.removedirs(root) except: pass os.makedirs(self.gnupgHome) self.gpg = GPG(gpgbinary=self.gpgbin, gnupghome=self.gnupgHome) input = self.gpg.gen_key_input(name_real=self.goodRealName, name_email=self.goodEmail, passphrase=self.goodpassphrase) self.goodPrivateKey = self.gpg.gen_key(input) privateKeyAvailable = False privateKeys = self.gpg.list_keys(secret=True) for skey in privateKeys: if skey["keyid"] == self.goodPrivateKey.fingerprint: privateKeyAvailable = True self.privateKeyInfo = skey break if skey["fingerprint"] == self.goodPrivateKey.fingerprint: privateKeyAvailable = True self.privateKeyInfo = skey break assert privateKeyAvailable == True, "Could not locate generated Private Key" self.goodkeyid = self.privateKeyInfo["keyid"] self.goodowner = self.privateKeyInfo["uids"][0] self.badkeyid = "XXXXXXXXXXXXXXXX" self.badpassphrase = "bad passphrase" self.sampleJSON = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data":"<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "keys":["United States--Description and travel.","eng"], "submitter_type":"agent", "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "submitter":"NSDL 2 LR Data Pump", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.10.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleJSON__0_23_0 = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data":"<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "keys":["United States--Description and travel.","eng"], "identity":{ "submitter_type":"agent", "submitter":"NSDL 2 LR Data Pump" }, "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.23.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleJSON__0_51_0 = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2014-04-01 13:36:04.617999", "resource_data":"<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "keys":["United States--Description and travel.","eng"], "identity":{ "submitter_type":"agent", "submitter":"NSDL 2 LR Data Pump" }, "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "payload_schema":["oai_dc"], "node_timestamp":"2014-04-01 13:32:04.617999", "doc_version":"0.51.0", "create_timestamp":"2014-04-01 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleJSON_no_coercion = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data": { "name": "Test coersion", "nullable": null, "booleanT": true, "booleanF": false }, "keys":["United States--Description and travel.","eng"], "identity":{ "submitter_type":"agent", "submitter":"NSDL 2 LR Data Pump" }, "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.23.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleJSON_lossy_sha256 = [ ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data": { "name": "Test Lossy" "integer": 1 }, "keys":["United States--Description and travel.","eng"], "identity":{ "submitter_type":"agent", "submitter":"NSDL 2 LR Data Pump" }, "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.23.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''', ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data": { "name": "Test Lossy" "float": 1.1 }, "keys":["United States--Description and travel.","eng"], "identity":{ "submitter_type":"agent", "submitter":"NSDL 2 LR Data Pump" }, "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.23.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''', ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data": { "name": "Test Lossy" "max_int": 9007199254740990 }, "keys":["United States--Description and travel.","eng"], "identity":{ "submitter_type":"agent", "submitter":"NSDL 2 LR Data Pump" }, "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.23.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''', ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data": { "name": "Test Lossy" "min_int": -9007199254740990 }, "keys":["United States--Description and travel.","eng"], "identity":{ "submitter_type":"agent", "submitter":"NSDL 2 LR Data Pump" }, "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.23.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' ] self.sampleJSON_strip = '''{"keys": ["United States--Description and travel.", "eng"], "TOS": {"submission_attribution": "unidentified", "submission_TOS": "http://example.com/tos/unknown"}, "payload_placement": "inline", "active": true, "resource_locator": "http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_type": "resource_data", "resource_data": "<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "submitter_type": "agent", "resource_data_type": "metadata", "payload_schema_locator": "http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_schema": ["oai_dc"], "doc_version": "0.10.0", "submitter": "NSDL 2 LR Data Pump"}''' self.sampleJSON_strip_normal = '''{"keys": ["United States--Description and travel.", "eng"], "TOS": {"submission_attribution": "unidentified", "submission_TOS": "http://example.com/tos/unknown"}, "payload_placement": "inline", "active": "true", "resource_locator": "http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_type": "resource_data", "resource_data": "<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "submitter_type": "agent", "resource_data_type": "metadata", "payload_schema_locator": "http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_schema": ["oai_dc"], "doc_version": "0.10.0", "submitter": "NSDL 2 LR Data Pump"}''' self.sampleJSON_strip_normal_bencode = '''d3:TOSd14:submission_TOS30:http://example.com/tos/unknown22:submission_attribution12:unidentifiede6:active4:true8:doc_type13:resource_data11:doc_version6:0.10.04:keysl38:United States--Description and travel.3:enge17:payload_placement6:inline14:payload_schemal6:oai_dce22:payload_schema_locator90:http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd13:resource_data968:<oai_dc:dc xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openarchives.org/OAI/2.0/" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">\n<dc:title>A chat about America. October and November, 1884.</dc:title>\n<dc:creator>J. P.</dc:creator>\n<dc:subject>United States--Description and travel.</dc:subject>\n<dc:description>"Printed for private circulation only."</dc:description>\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\n<dc:date>1885</dc:date>\n<dc:type>text</dc:type>\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\n<dc:language>eng</dc:language>\n<dc:coverage>United States</dc:coverage>\n</oai_dc:dc>\n 18:resource_data_type8:metadata16:resource_locator38:http://hdl.loc.gov/loc.gdc/lhbtn.122819:submitter19:NSDL 2 LR Data Pump14:submitter_type5:agente''' self.sampleJSON_sha256 = '''ef1b3b63adc663602c7a3c7595951b2761b34f5f6490ea1acee3df0fd97db03c''' self.sampleKeyLocations = [ "http://example.com/mykey", "http://example2.com/mykey" ] self.signatureTemplate = '{{"key_location": [{0}], "key_owner": "' + self.goodowner + '", "signing_method": "LR-PGP.1.0", "signature": "{1}"}}' def tearDown(self): self.gpg.delete_keys([ self.goodPrivateKey.fingerprint, ], secret=True) self.gpg.delete_keys([ self.goodPrivateKey.fingerprint, ], secret=False) pass def testMissingPrivateKey(self): def missingKey(): try: sign = Sign_0_21(self.badkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) except UnknownKeyException as e: assert e.keyid == self.badkeyid, "keyid in exception doesn't match key passed to sign." raise e self.assertRaises(UnknownKeyException, missingKey) def testPresentPrivateKey(self): sign = Sign_0_21(self.goodkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) assert sign.privateKeyID == self.goodkeyid def testStrip(self): origJson = json.loads(self.sampleJSON) benchmark = json.loads(self.sampleJSON_strip) signer = Sign_0_21(self.goodkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) stripJson = signer._stripEnvelope(origJson) assert benchmark == stripJson def testStripNormal(self): origJson = json.loads(self.sampleJSON) benchmark = json.loads(self.sampleJSON_strip_normal) signer = Sign_0_21(self.goodkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) stripJson = signer._stripEnvelope(origJson) normalJson = signer._bnormal(stripJson) assert benchmark == normalJson def testStripNormalBencode(self): origJson = json.loads(self.sampleJSON) benchmark = self.sampleJSON_strip_normal_bencode signer = Sign_0_21(self.goodkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) stripJson = signer._stripEnvelope(origJson) normalJson = signer._bnormal(stripJson) bencodeJson = signer._buildCanonicalString(normalJson) assert benchmark == bencodeJson def testStripNormalBencodeHash(self): origJson = json.loads(self.sampleJSON) benchmark = self.sampleJSON_sha256 signer = Sign_0_21(self.goodkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) stripJson = signer._stripEnvelope(origJson) normalJson = signer._bnormal(stripJson) bencodeJson = signer._buildCanonicalString(normalJson) hashed = signer._hash(bencodeJson) assert benchmark == hashed def testKnownLossyHash(self): for idx, lossyJSON in enumerate(self.sampleJSON_lossy_sha256): origJson = json.loads(self.sampleJSON) signer = Sign_0_21(self.goodkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) stripJson = signer._stripEnvelope(origJson) normalJson = signer._bnormal(stripJson) bencodeJson = signer._buildCanonicalString(normalJson) hashed = signer._hash(bencodeJson) if idx > 0: assert prev_hashed == hashed, "Hashes should match - algorithm is lossy" assert prev_bencodeJson == bencodeJson, "Bencode strings should match - algorithm is lossy" prev_bencodeJson = bencodeJson prev_hashed = hashed def testGetMessage(self): origJson = json.loads(self.sampleJSON) benchmark = self.sampleJSON_sha256 signer = Sign_0_21(self.goodkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) message = signer.get_message(origJson) assert benchmark == message def testPrivateKeyOwner(self): benchmark = self.goodowner signer = Sign_0_21(self.goodkeyid, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) assert benchmark == signer._get_privatekey_owner() def testSigBlock(self): origJson = json.loads(self.sampleJSON) arbitrarySigdata = "ABCDEF0123456789-abcdef" arbitraryKeyLoc = self.sampleKeyLocations keyloc = ",".join(['"{0}"'.format(x) for x in arbitraryKeyLoc]) benchmark = json.loads( self.signatureTemplate.format(keyloc, arbitrarySigdata)) signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) assert benchmark == signer._get_sig_block(arbitrarySigdata) def testSignNoEnvelopeCoercion(self): origJson = json.loads(self.sampleJSON_no_coercion) arbitraryKeyLoc = self.sampleKeyLocations assert origJson["resource_data"]["nullable"] == None, "Expected null" assert origJson["resource_data"]["booleanT"] == True, "Expected true" assert origJson["resource_data"]["booleanF"] == False, "Expected false" signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) signed = signer.sign(origJson) assert "digital_signature" in signed assert origJson["resource_data"]["nullable"] == None, "Expected null" assert origJson["resource_data"]["booleanT"] == True, "Expected true" assert origJson["resource_data"]["booleanF"] == False, "Expected false" def testSign_0_10__no_passthru(self): origJson = json.loads(self.sampleJSON) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) signed = signer.sign(origJson) assert "digital_signature" in signed sig = signed["digital_signature"] assert "signature" in sig assert sig["signature"] != None and len(sig["signature"]) > 0 def test_Sign__0_10__passthru(self): origJson = json.loads(self.sampleJSON) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, sign_everything=False, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) signed = signer.sign(origJson) assert "digital_signature" not in signed # sig = signed["digital_signature"] # assert sig.has_key("signature") # assert sig["signature"] != None and len(sig["signature"]) > 0 def test_Sign__0_23__passthru(self): origJson = json.loads(self.sampleJSON__0_23_0) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_23(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, sign_everything=False, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) signed = signer.sign(origJson) assert "digital_signature" in signed sig = signed["digital_signature"] assert "signature" in sig assert sig["signature"] != None and len(sig["signature"]) > 0 def test_Sign__0_23__no_passthru(self): origJson = json.loads(self.sampleJSON__0_23_0) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_23(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, sign_everything=True, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) signed = signer.sign(origJson) assert "digital_signature" in signed sig = signed["digital_signature"] assert "signature" in sig assert sig["signature"] != None and len(sig["signature"]) > 0 def test_Sign__0_51__no_passthru(self): origJson = json.loads(self.sampleJSON__0_51_0) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_51(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, sign_everything=True, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) signed = signer.sign(origJson) assert "digital_signature" in signed sig = signed["digital_signature"] assert "signature" in sig assert sig["signature"] != None and len(sig["signature"]) > 0 def testSignUnicode(self): if self.testDataUnicode == None: log.info("Skipping test, unicode test data file not set.") return import codecs # fileName = "2011-02-28Metadata1004.json" # unsigned = json.load(codecs.open(os.path.join(self.testDataDir, fileName), "r", "utf-8-sig")) unsigned = json.load( codecs.open(self.testDataUnicode, "r", "utf-8-sig")) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) signed = signer.sign(unsigned) assert "digital_signature" in signed sig = signed["digital_signature"] assert "signature" in sig assert sig["signature"] != None and len(sig["signature"]) > 0 def testSignLRTestData(self): if self.testDataDir == None: log.info("Skipping test, test data directory not set.") return import codecs # allfiles = os.listdir(self.testDataDir) for root, dirs, files in os.walk(self.testDataDir): for fileName in files: log.info("Trying to sign %s" % (fileName, )) unsigned = json.load( codecs.open(os.path.join(root, fileName), "r", "utf-8-sig")) arbitraryKeyLoc = self.sampleKeyLocations signer = Sign_0_21(self.goodkeyid, passphrase=self.goodpassphrase, publicKeyLocations=arbitraryKeyLoc, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin) signed = signer.sign(unsigned) assert "digital_signature" in signed sig = signed["digital_signature"] assert "signature" in sig assert sig["signature"] != None and len(sig["signature"]) > 0
class Test(unittest.TestCase): '''Unit tests for validating signed envelopes from the Learning Registry''' def __init__(self, methodName="runTest"): self.sampleJSON = ''' { "_id":"00e3f67232e743b6bc2a079bd98ff55a", "_rev":"1-8163d32f6cc9996f2b7228d8b5db7962", "doc_type":"resource_data", "update_timestamp":"2011-03-14 13:36:04.617999", "resource_data":"<oai_dc:dc xmlns:oai_dc=\\"http://www.openarchives.org/OAI/2.0/oai_dc/\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xmlns=\\"http://www.openarchives.org/OAI/2.0/\\" xsi:schemaLocation=\\"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd\\">\\n<dc:title>A chat about America. October and November, 1884.</dc:title>\\n<dc:creator>J. P.</dc:creator>\\n<dc:subject>United States--Description and travel.</dc:subject>\\n<dc:description>\\"Printed for private circulation only.\\"</dc:description>\\n<dc:description>Electronic reproduction. Washington, D.C. : Library of Congress, [2002-2003]</dc:description>\\n<dc:publisher>Manchester, Palmer & Howe</dc:publisher>\\n<dc:date>1885</dc:date>\\n<dc:type>text</dc:type>\\n<dc:identifier>http://hdl.loc.gov/loc.gdc/lhbtn.12281</dc:identifier>\\n<dc:language>eng</dc:language>\\n<dc:coverage>United States</dc:coverage>\\n</oai_dc:dc>\\n ", "keys":["United States--Description and travel.","eng"], "submitter_type":"agent", "resource_data_type":"metadata", "payload_schema_locator":"http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd", "payload_placement":"inline", "submitter":"NSDL 2 LR Data Pump", "payload_schema":["oai_dc"], "node_timestamp":"2011-03-14 13:36:04.617999", "doc_version":"0.10.0", "create_timestamp":"2011-03-14 13:36:04.617999", "active":true, "publishing_node":"string", "resource_locator":"http://hdl.loc.gov/loc.gdc/lhbtn.12281", "doc_ID":"00e3f67232e743b6bc2a079bd98ff55a", "TOS": { "submission_TOS": "http://example.com/tos/unknown", "submission_attribution": "unidentified" } } ''' self.sampleKeyLocations = [ "http://example.com/mykey", "http://example2.com/mykey" ] self.gpgbin="/usr/local/bin/gpg" self.gnupgHome = os.path.expanduser(os.path.join("~", ".gnupg")) self.gpg = GPG(gpgbinary=self.gpgbin, gnupghome=self.gnupgHome) self.testDataDir = None configFile = os.path.join("config.cfg") if os.path.exists(configFile): config = json.load(file(configFile)) if config.has_key("global"): if config["global"].has_key("testdata") and os.path.exists(config["global"]["testdata"]): self.testDataDir = config["global"]["testdata"] unittest.TestCase.__init__(self, methodName) def setUp(self): now = time.localtime() now = calendar.timegm(now) self.privateEmail = "privateTest-{0}@learningregistry.org".format(now) self.privateEmail2 = "privateTest2-{0}@learningregistry.org".format(now) self.genericPassphrase = "supersecret" input = self.gpg.gen_key_input(name_email=self.privateEmail, passphrase=self.genericPassphrase) self.privateKey = self.gpg.gen_key(input) input = self.gpg.gen_key_input(name_email=self.privateEmail2, passphrase=self.genericPassphrase) self.privateKey2 = self.gpg.gen_key(input) self.privExport = self.gpg.export_keys([self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=True) self.pubExport = self.gpg.export_keys([self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=False) pass def tearDown(self): self.gpg.delete_keys([self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=True) self.gpg.delete_keys([self.privateKey.fingerprint, self.privateKey2.fingerprint], secret=False) pass def testGetSignatureBlock(self): '''Check that signature block validation correctly returns a structurally valid response''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "envelope did not sign correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) sigInfo = verifytool._getSignatureInfo(signed) assert sigInfo != None, "signature extraction from envelope failed" assert sigInfo.has_key("signing_method") and sigInfo["signing_method"] == verifytool.signatureMethod, "signing_method is missing from signature block" assert sigInfo.has_key("signature") and sigInfo["signature"] != None and len(sigInfo["signature"]) > 0, "signature field is missing, null or is empty" assert sigInfo.has_key("key_location") and sigInfo["key_location"] == self.sampleKeyLocations, "key_location field is not correct" assert sigInfo.has_key("key_owner") and sigInfo["key_owner"] == signtool._get_privatekey_owner(), "key_owner field does not match signing key" def testBadSignatureBlockMissingLocation(self): '''Check that signature block validation correctly checks for missing key_location field''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=None) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_KEY_LOCATION, "Exception not formatted with correct message" def testBadSignatureBlockMissingSignatureMethod(self): '''Check signature block for missing signature_method detection''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly." del signed["digital_signature"]["signing_method"] verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.UnsupportedSignatureAlgorithm, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.alg == None, "Raised exception not formatted correctly" def testBadSignatureBlockBadSignatureMethod(self): '''Check signature block for detecting unsupported algorithm use''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None signed["digital_signature"]["signing_method"] = signtool.signatureMethod+"+BAD_SIGNATURE_METHOD" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.UnsupportedSignatureAlgorithm, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.alg == signed["digital_signature"]["signing_method"], "Exception not raised correctly." def testBadSignatureBlockBadKeyOwner(self): '''Check signature block for a bad key_owner field''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope not signed correctly" signed["digital_signature"]["key_owner"] = ["John Q. Public <*****@*****.**>"] verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.BAD_KEY_OWNER, "Wrong exception" def testBadSignatureBlockMissingNullEmptySignature(self): '''Check signature block validation with missing/null or empty signature''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope signing did not succeed correctly." verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) signed["digital_signature"]["signature"] = "" with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" signed["digital_signature"]["signature"] = None with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" del signed["digital_signature"]["signature"] with self.assertRaises(errors.BadSignatureFormat, msg="Expected exception not raised.") as caught: sigInfo = verifytool._getSignatureInfo(signed) assert caught.exception.message == errors.MISSING_SIGNATURE, "Wrong exception raised" def testValidSignature(self): '''Check for valid signature''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope did not sign correctly" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "Envelope signature verification did not succeed, even though it should" def testMissingPublicKey(self): '''Check for appropriate response when public key for signature is missing''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "Envelope did not sign correctly" self.gpg.delete_keys([self.privateKey.fingerprint], secret=True) self.gpg.delete_keys([self.privateKey.fingerprint], secret=False) verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) with self.assertRaises(errors.MissingPublicKey, msg="Expected exception not raised.") as caught: verified = verifytool.verify(signed) assert verified == False, "Envelope verified, despite missing public key." def testCorruptEnvelope(self): '''Modify a signed envelope and check for validity''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "envelope did not get signed correctly" signed["X_corrupted"] = "Corrupted Envelope" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == False, "corrupted envelope verified as good" def testWrongSignature(self): '''Test using a mis-matched signature, using a signature from a different valid envelope''' unsigned = json.loads(self.sampleJSON) altered = copy.copy(unsigned) altered["X_corrupted"] = "Altered Envelope" signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signtool2 = Sign_0_21(privateKeyID=self.privateKey2.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) alt_signed = signtool2.sign(altered) assert signed != None, "original did not get signed" assert alt_signed != None, "modified copy did not get signed" verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "signature did not verify, even though it should." verified = verifytool.verify(alt_signed) assert verified == True, "signature did not verify, even though it should." signed["digital_signature"] = alt_signed["digital_signature"] verified = verifytool.verify(signed) assert verified == False, "swapped signature block validated envelope as good." def testCorruptSignature(self): '''Test using a corrupted signature, replace the hash within a signature with a hash from a different envelope''' unsigned = json.loads(self.sampleJSON) signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) signed = signtool.sign(unsigned) assert signed != None, "baseline signing failed" # validate original with good signature verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) verified = verifytool.verify(signed) assert verified == True, "baseline validation failed" # manipulate the hash portion of a signature block altered = copy.copy(unsigned) altered["X_corrupted"] = "Altered Envelope" altered_hash = signtool.get_message(altered) validHash = verifytool._extractHashFromSignature(signed["digital_signature"]["signature"]) alt_signed = copy.deepcopy(signed) alt_signed["digital_signature"]["signature"] = signed["digital_signature"]["signature"].replace(validHash, altered_hash) assert alt_signed["digital_signature"]["signature"] != signed["digital_signature"]["signature"], "envelopes should not be equal after deliberate modificaton" verified = verifytool.verify(alt_signed) assert verified == False, "verification failed, corrupted signature block verified as good" def testSignLRTestData(self): '''Test using LR Test Data, if available''' if self.testDataDir == None: log.info("Skipping test, test data directory not set.") return import codecs signtool = Sign_0_21(privateKeyID=self.privateKey.fingerprint, passphrase=self.genericPassphrase, gnupgHome=self.gnupgHome, gpgbin=self.gpgbin, publicKeyLocations=self.sampleKeyLocations) verifytool = Verify_0_21(gpgbin=self.gpgbin, gnupgHome=self.gnupgHome) allfiles = os.listdir(self.testDataDir) for fileName in allfiles: log.info("Trying to sign %s" % (fileName, )) unsigned = json.load(codecs.open(os.path.join(self.testDataDir, fileName), "r", "utf-8-sig")) signed = signtool.sign(unsigned) assert signed.has_key("digital_signature"), "missing digital_signature" verified = verifytool.verify(signed) assert verified == True, "baseline validation failed"
class OpenPgpFactory(GenericFactory): """Provides OpenPGP functionality based on GnuPG.""" implements(ICipherModule) gpg_binary = Option( 'crypto', 'gpg_binary', 'gpg', """GnuPG binary name, allows for full path too. Value 'gpg' is same default as in python-gnupg itself. For usual installations location of the gpg binary is auto-detected. """) gpg_home = Option( 'crypto', 'gpg_home', '.gpg', """Directory containing keyring files. In case of wrong configuration missing keyring files without content will be created in the configured location, provided necessary write permssion is granted for the corresponding parent directory. """) priv_key = Option( 'crypto', 'gpg_private_key', '', """Key ID of private key (last 8 chars or more). If unset, a private key will be selected from keyring automagicly. The password must be available i.e. provided by running gpg-agent (not yet available) or empty (security trade-off). No private key operation can happen before the key has been unlocked successfully. """) name = 'openpgp' _supported_keys = [ 'name_real', 'name_comment', 'name_email', 'key_type', 'key_length', 'subkey_type', 'subkey_length', 'expire_date', 'passphrase' ] def __init__(self): try: from gnupg import GPG except ImportError: raise TracError( _("""Unable to load the python-gnupg module. Please check and correct your installation.""")) try: # Initialize the GnuPG instance. path = os.path.join(os.path.abspath(self.env.path), self.gpg_home) self.env.log.debug('Using GnuPG home dir: ' + str(path)) self.gpg = GPG(gpgbinary=self.gpg_binary, gnupghome=path) except ValueError: raise TracError( _("""Missing the crypto binary. Please check and set full path with option 'gpg_binary'.""")) # IKeyVault methods def keys(self, private=False, id_only=False): """Returns the list of all available keys.""" # DEVEL: Cache this for performance. if not id_only: return self.gpg.list_keys(private) # same as gpg.list_keys(False) keys = [] for key in self.gpg.list_keys(private): keys.append(key['fingerprint']) return keys def create_key(self, **kwargs): """Generate a new OpenPGP key pair.""" # Sanitize input. for k in kwargs.keys(): if k not in self._supported_keys: kwargs.pop(k) input_data = self.gpg.gen_key_input(**kwargs) try: return self.gpg.gen_key(input_data) except ValueError, e: return False, e
class OpenPgpFactory(GenericFactory): """Provides OpenPGP functionality based on GnuPG.""" implements(ICipherModule) gpg_binary = Option('crypto', 'gpg_binary', 'gpg', """GnuPG binary name, allows for full path too. Value 'gpg' is same default as in python-gnupg itself. For usual installations location of the gpg binary is auto-detected. """) gpg_home = Option('crypto', 'gpg_home', '.gpg', """Directory containing keyring files. In case of wrong configuration missing keyring files without content will be created in the configured location, provided necessary write permssion is granted for the corresponding parent directory. """) priv_key = Option('crypto', 'gpg_private_key', '', """Key ID of private key (last 8 chars or more). If unset, a private key will be selected from keyring automagicly. The password must be available i.e. provided by running gpg-agent (not yet available) or empty (security trade-off). No private key operation can happen before the key has been unlocked successfully. """) name = 'openpgp' _supported_keys = ['name_real', 'name_comment', 'name_email', 'key_type', 'key_length', 'subkey_type', 'subkey_length', 'expire_date', 'passphrase'] def __init__(self): try: from gnupg import GPG except ImportError: raise TracError(_("""Unable to load the python-gnupg module. Please check and correct your installation.""")) try: # Initialize the GnuPG instance. path = os.path.join(os.path.abspath(self.env.path), self.gpg_home) self.env.log.debug('Using GnuPG home dir: ' + str(path)) self.gpg = GPG(gpgbinary=self.gpg_binary, gnupghome=path) except ValueError: raise TracError(_("""Missing the crypto binary. Please check and set full path with option 'gpg_binary'.""")) # IKeyVault methods def keys(self, private=False, id_only=False): """Returns the list of all available keys.""" # DEVEL: Cache this for performance. if not id_only: return self.gpg.list_keys(private) # same as gpg.list_keys(False) keys = [] for key in self.gpg.list_keys(private): keys.append(key['fingerprint']) return keys def create_key(self, **kwargs): """Generate a new OpenPGP key pair.""" # Sanitize input. for k in kwargs.keys(): if k not in self._supported_keys: kwargs.pop(k) input_data = self.gpg.gen_key_input(**kwargs) try: return self.gpg.gen_key(input_data) except ValueError, e: return False, e
def setUp(self): """ Construct environment. Here, we adopt the configuration used by the production or development installation and make the necessary changes before writing it to a new file in the etc directory. When we're finished, we'll remove it in the tearDown() function. """ if not os.path.exists(self.client_env['CONFDIR']): # Don't waste time and entropy on keys if we can't write configuration # files -- that's a very distressing experience. assert len(sys.argv) == 2 # Prepare two GPG keypairs; one for the agent, one for the client agent_gpg_dir = os.path.join(self.client_env['CONFDIR'], 'agent_gpg') agent_gpg = GPG(gnupghome=agent_gpg_dir) agent_key = agent_gpg.gen_key(agent_gpg.gen_key_input(**self.gpg_params)) client_gpg_dir = os.path.join(self.client_env['CONFDIR'], 'client_gpg') client_gpg = GPG(gnupghome=client_gpg_dir) client_key = client_gpg.gen_key(client_gpg.gen_key_input(**self.gpg_params)) # Export both public keys; import them into the opposing side agent_key_blob = agent_gpg.export_keys(agent_key.fingerprint) client_gpg.import_keys(agent_key_blob) client_gpg.sign_key(agent_key.fingerprint) client_key_blob = client_gpg.export_keys(client_key.fingerprint) agent_gpg.import_keys(client_key_blob) agent_gpg.sign_key(client_key.fingerprint) # Configure the agent to run in a development-safe configuration. # # Here, we load the base configuration we ship with the application # as the default. All other configuration will be ignored for the # purposes of the test run, since this is outside of our scope. with open(self.agent_env['CONFDIR'], 'w') as f: l = os.path.join(self.client_env['CONFDIR'], 'agent_%s.log') agent_cfg = ConfigurationFactory.get('hypernova.agent', root_dir=sys.argv[1]) agent_cfg.set('server', 'address', self.agent_addr[0]) agent_cfg.set('server', 'port', self.agent_addr[1]) agent_cfg.set('server', 'daemon', 'false') agent_cfg.set('gpg', 'key_store', agent_gpg_dir) agent_cfg.set('gpg', 'fingerprint', agent_key.fingerprint) agent_cfg.set('logging', 'main_log', l %('main')) agent_cfg.set('logging', 'request_log', l %('request')) agent_cfg.set('logging', 'error_log', l %('error')) agent_cfg.write(f) # The client has to use two different configuration files, both in # the same directory. client_cfg_dir = self.client_env['CONFDIR'] # Configure the client to use its temporary key. # # To communicate with the agent (which will be running in a limited # testing mode), we'll need to reconfigure the client with a keypair # we've imported into the agent. This keystore manipulation has # already taken place, so we know the fingerprint of our new private # key. client_cfg_file = os.path.join(client_cfg_dir, 'client.ini') with open(client_cfg_file, 'w') as f: client_cfg = configparser.SafeConfigParser() client_cfg.add_section('client') client_cfg.set('client', 'privkey', client_key.fingerprint) client_cfg.write(f) # Pair the client to the agent. # # We do this manually, since the importer requires that we write the # public key to a file before we import it. This would be a # pointless exercise and an unnecessary complication. client_srv_file = os.path.join(client_cfg_dir, 'servers.ini') with open(client_srv_file, 'w') as f: client_srv_cfg = configparser.SafeConfigParser() client_srv_cfg.add_section('local') client_srv_cfg.set('local', 'addr', ':'.join(self.agent_addr)) client_srv_cfg.set('local', 'pubkey', agent_key.fingerprint) client_srv_cfg.write(f) # TODO: instead of lazily and unreliably falling asleep on the job, # we should probably use a regular expression to check the output. # Time is of the essence, though! # No, we'll use pexpect instead, since it's now shipped as a py3k # dependency. agent_cmd = [ 'hn-agent', self.agent_env['CONFDIR'] ] self.agent_proc = subprocess.Popen(agent_cmd, env=self.agent_env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) time.sleep(self.agent_init_time)
def setUpClass(cls): super(TestGnuPGMessage, cls).setUpClass() gpg = GPG(gnupghome=settings.GNUPG_HOMEDIR) key_input = gpg.gen_key_input() gpg.gen_key(key_input)
class gpg(object): """ module to wrap the gnupg library and gpg binary """ def __init__(self, folder_path=None, binary_path=None): # ugly but working if binary_path is None: binary_path = join(project_base, "gpg", "gpg.exe") if not isfile(binary_path): binary_path = join(project_base, 'gpg') if not isfile(binary_path): binary_path = find_executable('gpg') if not isfile(binary_path): raise RuntimeError('gpg not found') self.gpg = GPG( binary_path, # gpgbinary folder_path, # gnupghome verbose=False, options=["--allow-non-selfsigned-uid"]) def get_key(self, fingerprint, private, passphrase): """ returns the key belonging to the fingerprint given. if 'private' is True, the private key is returned. If 'private' is False, the public key will be returned. """ key = self.gpg.export_keys(fingerprint, private, armor=False, passphrase=passphrase) return b64encode(key) def add_keypair(self, public_key, private_key, site, user, passphrase): """ add a keypair into the gpg key database """ try: result1 = self.gpg.import_keys(b64decode(public_key)) result2 = self.gpg.import_keys(b64decode(private_key)) except TypeError as error: getLogger(__name__).critical("add_keypair TypeError " + str(error)) # make sure this is a key _pair_ try: assert result1.fingerprints[0] == result2.fingerprints[0] except (IndexError, AssertionError) as error: getLogger(__name__).exception( 'add_keypair IndexError/AssertionError: ' + str(error)) return None fingerprint = result1.fingerprints[0] if self.is_passphrase_valid(passphrase=passphrase, fingerprint=fingerprint): old_fingerprint = self.get_fingerprint(site, user) if not old_fingerprint: sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?)" database_execute(sql, (site, user, fingerprint)) else: sql = "UPDATE keys SET SITE=? WHERE fingerprint=?" database_execute(sql, (site, old_fingerprint)) if fingerprint != old_fingerprint: getLogger(__name__).warn('updating %s fingerprint to %s' % (user, fingerprint)) return fingerprint else: return None def add_public_key(self, site, user, public_key): """ add a public key into the gpg key database """ try: result1 = self.gpg.import_keys(b64decode(public_key)) fingerprint = result1.fingerprints[0] sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?)" database_execute(sql, (site, user, fingerprint)) return fingerprint except TypeError as error: getLogger(__name__).critical("add_public_key TypeError " + str(error)) except DatabaseError as error: getLogger(__name__).critical("add_public_key DatabaseError " + str(error)) def is_passphrase_valid(self, passphrase, label=None, user=None, fingerprint=None): if not fingerprint: fingerprint = self.get_fingerprint(label, user) sign_result = self.gpg.sign("test", keyid=fingerprint, passphrase=passphrase) return sign_result.data != '' def generate(self, passphrase, site, user): """ Generate a new 2048 bit GPG key and add it to the gpg manager. """ data = self.gpg.gen_key_input(key_length=2048, passphrase=passphrase) dat = self.gpg.gen_key(data) fingerprint = dat.fingerprint sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?);" database_execute(sql, (site, user, fingerprint)) return fingerprint def get_fingerprint(self, site, user): sql = "select fingerprint from keys where site = ? and user = ?" result = database_execute(sql, (site, user)) if not len(result): return None return result[0][0] def has_key(self, site, user): """ Check whether a key is present for a certain site and user """ return self.get_fingerprint(site, user) is None def encrypt(self, data, site, user, armor=False): """ encrypt data for user at site. """ fingerprint = self.get_fingerprint(site, user) cryptdata = self.gpg.encrypt_file(StringIO(data), fingerprint, always_trust=True, armor=armor) return str(cryptdata) def decrypt(self, data, passphrase): """ decrypt data received from site. """ datafile = StringIO(data) result = self.gpg.decrypt_file(datafile, passphrase=passphrase, always_trust=True) return str(result) @staticmethod def add_pkcs7_padding(contents): # Input strings must be a multiple of the segment size 16 bytes in length segment_size = 16 # calculate how much padding is needed old_contents_length = len(contents) next_mult = old_contents_length + (segment_size - old_contents_length % segment_size) getLogger(__name__).debug( 'old contents length %s || new contents length %s' % (old_contents_length, next_mult)) # do the padding padding_byte = chr(next_mult - old_contents_length) contents = contents.ljust(next_mult, padding_byte) return contents @staticmethod def remove_pkcs7_padding(contents): """ Remove PKCS#7 padding bytes >>> gpg.remove_pkcs7_padding('some_content'.ljust(16, chr(4))) 'some_content' >>> gpg.remove_pkcs7_padding('some_content') 'some_content' >>> gpg.remove_pkcs7_padding('') '' :param contents: :return: contents without padding """ if len(contents) < 1: getLogger(__name__).debug( 'contents is empty. No PKCS#7 padding removed') return contents bytes_to_remove = ord(contents[-1]) # will work up to 255 bytes # check if contents have valid PKCS#7 padding if bytes_to_remove > 1 and contents[-2] != contents[-1]: getLogger(__name__).debug('no PKCS#7 padding detected') return contents getLogger(__name__).debug('removing %s bytes of PKCS#7 padding' % bytes_to_remove) return contents[0:(len(contents) - bytes_to_remove)]
def gen(this): gpg=GPG(gnupghome=os.path.join(GNUPG_HOME,user.pk)) input_data = gpg.gen_key_input(key_type="RSA", key_length=1024) key=gpg.gen_key(input_data)