def generateKeyAndSendNewInterest(self, probeTokenData): """ """ pib = self.keyChain.getPib() try: identity = pib.getIdentity(self.identityName) self.key = self.keyChain.createKey(identity) except Exception as e: identity = self.keyChain.createIdentityV2(self.identityName) self.key = identity.getDefaultKey() cert = CertificateV2() cert.setName( Name(self.key.getName()).append("cert-request").appendVersion( int(time.time()))) cert.getMetaInfo().setType(ContentType.KEY) cert.getMetaInfo().setFreshnessPeriod(24 * 3600) cert.setContent(self.key.getPublicKey()) signingInfo = SigningInfo(self.key) now = Common.getNowMilliseconds() signingInfo.setValidityPeriod( ValidityPeriod(now, now + 24 * 3600 * 1000.0)) self.keyChain.sign(cert, signingInfo) #cert = self.keyChain.selfSign(self.key) # Does not work because validity period is greater than certserver default interestName = Name(self.caPrefix).append("CA").append("_NEW") newInterest = Interest(interestName) newInterest.setMustBeFresh(True) newInterest.setCanBePrefix(False) ecdhPub = "{}\n".format(self.ecdh.getBase64PubKey()) ecdhCertReq = "{}\n".format( b64encode(cert.wireEncode().toBytes()).decode('utf-8')) probeToken = "{}\n".format( b64encode(probeTokenData.wireEncode().toBytes()).decode('utf-8')) jsonDump = json.dumps( { "ecdh-pub": ecdhPub, "cert-request": ecdhCertReq, "probe-token": probeToken }, indent=4) print(jsonDump) newInterest.setApplicationParameters(jsonDump) newInterest.appendParametersDigestToName() self.keyChain.sign(newInterest, SigningInfo(self.key)) print(newInterest.getName()) self.face.expressInterest(newInterest, self.onNewData, self.onTimeout)
def sendCommand(self, commandInterest, arguments, responseHandle): def onData(interest, data): # TODO: verify data responseHandle(commandInterest, Response(data)) def onTimeout(interest): responseHandle(commandInterest, NdnCtrl.Timeout) interest = Interest(commandInterest) if arguments: interest.setParameters(json.dumps(arguments)) interest.appendParametersDigestToName() # TODO: sign interest self.face_.expressInterest(interest, onData, onTimeout)
def sendProbeInterest(self): probeInterest = Interest( Name(self.caPrefix).append("CA").append("_PROBE")) probeInterest.setMustBeFresh(True) probeInterest.setCanBePrefix(False) probeInterest.setApplicationParameters( json.dumps({"email": "*****@*****.**"}, indent=4)) probeInterest.appendParametersDigestToName() print("Expressing interest: {}".format(probeInterest.getName())) self.face.expressInterest(probeInterest, self.onProbeData, self.onTimeout)
async def retx_sync_interest(self): while self.running: interest = Interest(Name(self.prefix)) interest.applicationParameters = self.encode(self.state) interest.appendParametersDigestToName() # await fetch_data_packet(self.face, interest) self.face.expressInterest(interest, self.on_sync_data) logging.info("retx") timeout = uniform(SYNC_INTERVAL_MIN, SYNC_INTERVAL_MAX) try: await asyncio.wait_for(self.sync_event.wait(), timeout) except asyncio.TimeoutError: pass self.sync_event.clear()
def test_append_parameters_digest(self): name = Name("/local/ndn/prefix") interest = Interest(name) self.assertTrue(not interest.hasApplicationParameters()) # No parameters yet, so it should do nothing. interest.appendParametersDigestToName() self.assertEqual("/local/ndn/prefix", interest.getName().toUri()) applicationParameters = Blob(bytearray([ 0x23, 0x01, 0xC0 ])) interest.setApplicationParameters(applicationParameters) self.assertTrue(interest.hasApplicationParameters()) interest.appendParametersDigestToName() self.assertEqual(name.size() + 1, interest.getName().size()) self.assertTrue(interest.getName().getPrefix(-1).equals(name)) SHA256_LENGTH = 32 self.assertEqual(SHA256_LENGTH, interest.getName().get(-1).getValue().size()) self.assertEqual(interest.getName().toUri(), "/local/ndn/prefix/" + "params-sha256=a16cc669b4c9ef6801e1569488513f9523ffb28a39e53aa6e11add8d00a413fc")
async def run(cmd: str): async def face_loop(): nonlocal face, running while running: face.processEvents() await asyncio.sleep(0.01) running = True face = Face() keychain = KeyChain() face.setCommandSigningInfo(keychain, keychain.getDefaultCertificateName()) event_loop = asyncio.get_event_loop() face_task = event_loop.create_task(face_loop()) if cmd == "track-repo": if len(sys.argv) < 3: print("Usage:", sys.argv[0], "track-repo <repo>", file=sys.stderr) else: repo = sys.argv[2] interest = Interest( Name(LOCAL_CMD_PREFIX).append("track-repo").append(repo)) data = await fetch_data_packet(face, interest) if isinstance(data, Data): result = struct.unpack("i", data.content.toBytes())[0] if result == 1: print("OK") elif result == 2: print("FAILED") else: print("PENDING") else: print("error: Couldn't connect to", interest.name.toUri(), file=sys.stderr) elif cmd == "create-branch": if len(sys.argv) < 4: print("Usage:", sys.argv[0], "create-branch <repo> <branch>", file=sys.stderr) else: repo = sys.argv[2] branch = sys.argv[3] interest = Interest( Name(LOCAL_CMD_PREFIX).append("create-branch").append( repo).append(branch)) data = await fetch_data_packet(face, interest) if isinstance(data, Data): result = struct.unpack("i", data.content.toBytes())[0] if result == 1: print("OK") elif result == 2: print("FAILED") else: print("PENDING") else: print("error: Couldn't connect to", interest.name.toUri(), file=sys.stderr) elif cmd == "mount": if len(sys.argv) < 4: print("Usage:", sys.argv[0], "mount <repo> <branch>", file=sys.stderr) else: repo = sys.argv[2] branch = sys.argv[3] interest = Interest( Name(LOCAL_CMD_PREFIX).append("mount").append(repo).append( branch)) data = await fetch_data_packet(face, interest) if isinstance(data, Data): print("Finished.") else: print("error: Couldn't connect to", interest.name.toUri(), file=sys.stderr) elif cmd == "unmount": if len(sys.argv) < 4: print("Usage:", sys.argv[0], "unmount <repo> <branch>", file=sys.stderr) else: repo = sys.argv[2] branch = sys.argv[3] interest = Interest( Name(LOCAL_CMD_PREFIX).append("unmount").append(repo).append( branch)) data = await fetch_data_packet(face, interest) if isinstance(data, Data): print("Finished.") else: print("error: Couldn't connect to", interest.name.toUri(), file=sys.stderr) elif cmd == "commit": if len(sys.argv) < 6: print("Usage:", sys.argv[0], "commit <repo> <branch> <dest-branch> <message>", file=sys.stderr) else: repo = sys.argv[2] branch = sys.argv[3] dest_branch = sys.argv[4] commit_msg = sys.argv[5] interest = Interest(Name(LOCAL_CMD_PREFIX).append("commit")) interest.applicationParameters = b'\x00'.join([ repo.encode(), branch.encode(), dest_branch.encode(), commit_msg.encode() ]) interest.appendParametersDigestToName() data = await fetch_data_packet(face, interest) if isinstance(data, Data): print("Finished.") else: print("error: Couldn't connect to", interest.name.toUri(), file=sys.stderr) else: print("Unrecognized command:", cmd, file=sys.stderr) running = False await face_task
def onNewData(self, interest, data): """ !! Again \n in public key?? Got data: { "ecdh-pub": "Aqxofe3QdsAfgbtS8TMxv31oudNKoSV307ci5gNXm88h\n", "salt": "12935684137560555161", "request-id": "14275252044236690531", "status": "0", "challenges": [ { "challenge-id": "Email" } ] } 1. Verify data 2. Derive shared secret """ content = data.getContent() print("Got data: ", content) if not VerificationHelpers.verifyDataSignature(data, self.anchor): print("Cannot verify signature from: {}".format(self.caPrefix)) else: print("Successfully verified data with hard-coded certificate") contentJson = json.loads(content.__str__()) peerKeyBase64 = contentJson['ecdh-pub'] self.status = contentJson['status'] self.requestId = contentJson['request-id'] self.challenges = contentJson['challenges'] print(peerKeyBase64) serverPubKey = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256R1(), b64decode(peerKeyBase64)) shared_key = self.ecdh.private_key.exchange(ec.ECDH(), serverPubKey) derived_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=contentJson['salt'].encode(), info=b'handshake data', backend=default_backend()).derive(shared_key) self.ecdh.derived_key = derived_key print(shared_key) for t in shared_key: print(t) challengeInterestName = Name( self.caPrefix).append("CA").append("_CHALLENGE").append( self.requestId) challengeInterest = Interest(challengeInterestName) challengeInterest.setMustBeFresh(True) challengeInterest.setCanBePrefix(False) # Encrypt the interest parameters challengeJson = json.dumps( { "selected-challenge": "Email", "email": "*****@*****.**" }, indent=4) raw = self.pad(challengeJson, 16) print("raw", raw) iv = Random.new().read(AES.block_size) #cipher = AES.new(self.ecdh.derived_key, AES.MODE_CBC, iv) cipher = AES.new(shared_key, AES.MODE_CBC, iv) print(iv) xx = cipher.encrypt(raw) print(cipher.decrypt(xx)) print("Printing iv:") for t in iv: print(t) encoder = TlvEncoder(256) saveLength = len(encoder) encoder.writeBlobTlv(632, iv) encoder.writeBlobTlv(630, cipher.encrypt(raw)) #encoder.writeTypeAndLength(36, len(encoder) - saveLength) challengeInterest.setApplicationParameters(Blob(encoder.getOutput())) challengeInterest.appendParametersDigestToName() self.keyChain.sign(challengeInterest, SigningInfo(self.key)) with open('foobar.tlv', 'wb') as f: f.write(challengeInterest.wireEncode().buf()) self.face.expressInterest(challengeInterest, self.onChallengeData, self.onTimeout)
async def run(local_repo_path: str, repo_prefix: str): async def face_loop(): nonlocal face, running while running: face.processEvents() await asyncio.sleep(0.01) options = {'cloning': False} running = True face = Face() keychain = KeyChain() face.setCommandSigningInfo(keychain, keychain.getDefaultCertificateName()) event_loop = asyncio.get_event_loop() face_task = event_loop.create_task(face_loop()) storage = FileStorage(local_repo_path) producer = GitProducer(face, Name(repo_prefix).append("objects"), storage) refs = [] empty_cnt = 0 while empty_cnt < 2 and running: cmd = sys.stdin.readline().rstrip("\n\r") # print("<<", cmd, file=sys.stderr) if cmd == "capabilities": print("push") print("fetch") print("option") print("") sys.stdout.flush() elif cmd.startswith("option"): opt_name, opt_val = cmd.split()[1:] if opt_name == "cloning": options['cloning'] = (opt_val == 'true') print("ok") else: print("unsupported") sys.stdout.flush() elif cmd == "list" or cmd == "list for-push": interest = Interest(Name(repo_prefix).append("ref-list")) data = await fetch_data_packet(face, interest) if isinstance(data, Data): reflist = data.content.toBytes().decode("utf-8") print(reflist) if reflist.strip() == "": refs = {} else: refs = [ item.split(" ")[1] for item in reflist.strip().split("\n") ] refs = {name.split("/")[-1] for name in refs} else: print("error: Couldn't connect to", repo_prefix, file=sys.stderr) running = False print("") sys.stdout.flush() elif cmd.startswith("fetch"): fetcher = GitFetcher(face, Name(repo_prefix).append("objects"), storage) while True: # Fetch files hash_name, ref_name = cmd.split()[1:] fetcher.fetch(hash_name, "commit") await fetcher.wait_until_finish() # Set refs file ref_file_path = os.path.join(local_repo_path, ref_name) with open(ref_file_path, 'w') as f: f.write(hash_name) # Read commands for next fetch cmd = sys.stdin.readline().rstrip("\n\r") if not cmd.startswith("fetch"): break print("") sys.stdout.flush() elif cmd.startswith("push"): while True: # Push commands # TODO: DELETE ALL HARDCODED THINGS # TODO: MAKE DATA AND INTEREST REAL branch, commit, _ = parse_push(cmd, local_repo_path) repo_name = repo_prefix.split("/")[-1] # Create Branch if not exist if branch not in refs: print("Non-existing branch. Try to create...", file=sys.stderr) interest = Interest( Name(LOCAL_CMD_PREFIX).append("create-branch").append( repo_name).append(branch)) data = await fetch_data_packet(face, interest) if isinstance(data, Data): result = struct.unpack("i", data.content.toBytes())[0] if result == 1: print("Creation succeeded", file=sys.stderr) elif result == 2: print("Creation is FAILED", file=sys.stderr) print("error refs/heads/{} FAILED".format(branch)) break else: print("Creation is PENDING", file=sys.stderr) print("error refs/heads/{} PENDING".format(branch)) break else: print("error: Couldn't connect to", interest.name.toUri(), file=sys.stderr) break # BranchInfo Interest interest = Interest( Name(repo_prefix).append("branch-info").append(branch)) data = await fetch_data_packet(face, interest) branchinfo = None if isinstance(data, Data): branchinfo = pickle.loads(data.content.toBytes()) if branchinfo is None or 'custodian' not in branchinfo.__dict__: print("ERROR Interest got no response: ", interest.name, file=sys.stderr) print("error refs/heads/{} DISCONNECTED".format(branch)) break # Push Interest interest = Interest( Name(branchinfo.custodian).append("push").append( repo_name).append(branch)) interest.applicationParameters = commit.encode("utf-8") interest.appendParametersDigestToName() interest.interestLifetimeMilliseconds = 20000 interest.mustBeFresh = True data = await fetch_data_packet(face, interest) if isinstance(data, Data): result = struct.unpack("i", data.content.toBytes())[0] if result == 1: print("OK push succeeded", interest.name, file=sys.stderr) print("ok refs/heads/{}".format(branch)) elif result == 2: print("ERROR push failed", interest.name, file=sys.stderr) print("error refs/heads/{} FAILED".format(branch)) else: print("PROCESSING push is not finished yet", interest.name, file=sys.stderr) print("error refs/heads/{} PENDING".format(branch)) else: print("ERROR Interest got no response: ", interest.name, file=sys.stderr) print("error refs/heads/{} DISCONNECTED".format(branch)) break # Read commands for next fetch cmd = sys.stdin.readline().rstrip("\n\r") if not cmd.startswith("push"): break print("") sys.stdout.flush() elif cmd == "": empty_cnt += 1 else: pass producer.cancel() running = False await face_task