def prepareMetadataChunks(metadataTuple, privateHandle): """Encrypts, signs and adds the necessary flags to the metadata chunks. Arguments: metadataTuple {tuple of {bytes}} -- Output of squashAndSplitMetadataChunk(), where every element of the tuple is a metadata chunk. privateHandle {bytes} -- Self-explanatory. Returns: list -- List of metadata chunks - in order - ready to be encoded into trytes and sent in an iota tx. """ encryptionKey = encryption.getEncryptionKey(privateHandle) signingKey, verifyingKey = encryption.getKeypair(privateHandle) metadataChunkList = [] address_gen = datamap.createDatamapGenerator(verifyingKey, len(metadataTuple) + 2) next( address_gen ) # first address is the treasure chunk's so we don't need it right now for i, metadataChunk in enumerate(metadataTuple): encryptedChunk, nonce, _ = encryption.encryptAES( metadataChunk, encryptionKey) preparedChunk = encryptedChunk + nonce address = iota_utils.trytesToBytes(next(address_gen)[:-1]) if i == 0: preparedChunk = addMetadataFlags(preparedChunk, len(metadataTuple)) signature = encryption.signChunk(preparedChunk + address, signingKey) finalMetadataChunk = b"".join([preparedChunk, signature]) metadataChunkList.append(finalMetadataChunk) return metadataChunkList
def fileToChunks(filename, privateHandle, startingHash, password=None): """Takes a filename and returns the file converted to rev2 compliant chunks, already signed. Arguments: filename {str} -- Self-explanatory. Also needs to include the extension. privateHandle {bytes} -- Bytestring to use as the private handle. Can and should be generated using encryption.getPrivateHandle(). startingHash {bytes} -- Hash on the main hashchain corresponding to the position of the first chunk of the file on the datamap. Keyword Arguments: password {str} -- Optional argument. Use it to password protect a particular file in a multi-file upload (default: {None}) Returns: list -- Every element is a chunk, in the same order as the bytes are read from the file. """ signingKey, _ = encryption.getKeypair(privateHandle) encryptionKey = encryption.getEncryptionKey(privateHandle) f = open(filename, mode="rb") filesize = os.path.getsize(filename) chunksize = 1013 numberOfChunks = math.ceil(filesize / chunksize) fileList = [] if password is not None: encryptionKey = encryption.getEncryptionKey(encryptionKey + password.encode("utf-8")) numberOfChunks = math.ceil((filesize - 997) / chunksize) + 1 chunksize = 997 address_gen = datamap.createDatamapGenerator(startingHash, numberOfChunks + 1) for i in range(0, numberOfChunks): chunk = f.read(chunksize) encrypted_chunk, nonce, tag = encryption.encryptAES( chunk, encryptionKey) address_trytes = next( address_gen )[: -1] #the real address is 81 chars, but the byte conversion only works with even numbers, so we use the first 80 chars of the address to sign and check address_bytes = iota_utils.trytesToBytes(address_trytes) if password is not None and i == 0: unsigned_chunk = b"".join([encrypted_chunk, nonce, tag]) chunksize = 1013 else: unsigned_chunk = b"".join([encrypted_chunk, nonce]) signature = encryption.signChunk(unsigned_chunk + address_bytes, signingKey) completed_chunk = unsigned_chunk + signature fileList.append(completed_chunk) f.close() return fileList
def test_End_to_End(): number_of_files = random.randint(4, 10) filenameList = ["testfile_" + str(i+1) for i in range(number_of_files)] initialize_multiple_files(filenameList) passwordFlagList = [bool(random.getrandbits(1)) for i in filenameList] passwordDict = {filename:"oyster" for filename, flag in zip(filenameList, passwordFlagList) if flag} privateHandle = encryption.getPrivateHandle() _, verifyingKey = encryption.getKeypair(privateHandle) encryptionKey = encryption.getEncryptionKey(privateHandle) rawMetadataChunk = fileprocessor.makeMetadataChunk(filenameList, passwordFlagList, verifyingKey) metadataChunkTuple = fileprocessor.squashAndSplitMetadataChunk(rawMetadataChunk) allChunksList = [b"TreasureChunkHere"] + fileprocessor.prepareMetadataChunks(metadataChunkTuple, privateHandle) for filename in filenameList: offsetHash = bytes.fromhex(rawMetadataChunk[filename]["offsetHash"]) if filename in passwordDict: # This statement is only True if filename has been added to the keys in the dict, which means it has a password fileChunks = fileprocessor.fileToChunks(filename, privateHandle, offsetHash, password=passwordDict[filename]) else: fileChunks = fileprocessor.fileToChunks(filename, privateHandle, offsetHash) allChunksList += fileChunks firstMetadataChunk = allChunksList[1] metadataChunkNumberFlag_bytes, _ = fileprocessor.stripMetadataFlags(firstMetadataChunk) numberFlag = int(np.fromstring(metadataChunkNumberFlag_bytes, dtype='uint8')) metadataArray = allChunksList[1:numberFlag+1] metadataJSON = fileprocessor.unpackMetadata(metadataArray, encryptionKey) decrypted_filenameList = list(metadataJSON.keys()) for filename in decrypted_filenameList: startIdx = metadataJSON[filename]["startIdx"] endIdx = startIdx + metadataJSON[filename]["chunkCount"] passwordFlag = bool(metadataJSON[filename]["password"]) decrypted_filename = "decrypted_"+filename fileList = allChunksList[startIdx:endIdx] if passwordFlag: fileprocessor.chunksToFile(fileList, encryptionKey, decrypted_filename, password=passwordDict[filename]) else: fileprocessor.chunksToFile(fileList, encryptionKey, decrypted_filename) assert read_binary_file(filename) == read_binary_file(decrypted_filename) assert SHA256.new(read_binary_file(filename)).digest() == SHA256.new(read_binary_file(decrypted_filename)).digest() address_gen = datamap.createDatamapGenerator(verifyingKey, None, 1) for chunk in allChunksList[1:]: #first chunk is the protocol chunk and doesn't get signed when doing local simulations data_chunk, signature = encryption.splitChunkAndSignature(chunk) address = iota_utils.trytesToBytes(next(address_gen)[:-1]) encryption.verifyChunk(data_chunk + address, signature, verifyingKey.hex()) assert True cleanup()
def test_verify_chunk_signatures(self): _, verifyingKey = encryption.getKeypair(self.privateHandle) address_gen = datamap.createDatamapGenerator(verifyingKey, len(self.chunkList) + 1) for chunk in self.chunkList: datachunk, signature = encryption.splitChunkAndSignature(chunk) address = iota_utils.trytesToBytes(next(address_gen)[:-1]) encryption.verifyChunk(datachunk + address, signature, verifyingKey.hex()) assert True
def test_bytes_to_trytes_to_bytes(self): byte_string = iota_utils.trytesToBytes(self.trytes) assert byte_string == self.message