changed directory structure

This commit is contained in:
Akhil Bharti 2018-06-25 16:11:31 +05:30
parent 40e20da059
commit 43de69b24e
10 changed files with 911 additions and 0 deletions

42
_temp/Aes256.py Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env python3
import os
from Crypto.Cipher import AES
def pad(data):
padding = 16 - len(data) % 16
return data + padding * ' '
def unpad(data):
return data[:length]
def keyGen():
#Generating random key of 32 bytes
key=os.urandom(32)
#print("Key Generated")
#print(key)
return key
def encryptMsg(plaintext,key):
#Initialization vector in AES should be 16 bytes
IV = 16*'\x00'
#Creation of encryptor and decryptor object using above details
cipher=AES.new(key,AES.MODE_CBC,IV)
return cipher.encrypt(pad(plaintext))
def decryptMsg(ciphertext, key):
#Initialization vector in AES should be 16 bytes
IV = 16*'\x00'
#Creation of encryptor and decryptor object using above details
cipher=AES.new(key,AES.MODE_CBC,IV)
return unpad(cipher.decrypt(ciphertext));
msg=input('Enter The Message To Be Encrypted : ')
length=len(msg)
key = keyGen()
print("Key generated : "+str(key))
ciphertext = encryptMsg(msg,key)
print("Encrypted Text : "+str(ciphertext))
plaintext = decryptMsg(ciphertext, key)
print("Decrypted Text : "+str(plaintext))

2
_temp/TODO.md Normal file
View File

@ -0,0 +1,2 @@
1.clean this directory
2.convert this into a python lib

93
_temp/check.py Executable file
View File

@ -0,0 +1,93 @@
#!/usr/bin/env python3
from secretsharing import PlaintextToHexSecretSharer
import base64
import os
from Crypto.Cipher import AES
# This function splits the secret and returns a list of shares
def splitSecret(secret,threshold,splits):
shares = PlaintextToHexSecretSharer.split_secret(secret, threshold, splits)
return shares
# This function recovers the secret using the list of shares and returns the reconstructed secret
def recoverSecret(shares):
secret = PlaintextToHexSecretSharer.recover_secret(shares)
return secret
def pad(data):
padding = 16 - len(data) % 16
return data + padding * ' '
def unpad(data):
return data[:length]
def keyGen():
# Generating random key of 32 bytes
key = os.urandom(32)
# print("Key Generated")
# print(key)
return key
def encryptMsg(plaintext, key):
# Initialization vector in AES should be 16 bytes
IV = 16 * '\x00'
# Creation of encryptor and decryptor object using above details
cipher = AES.new(key, AES.MODE_CBC, IV)
return cipher.encrypt(pad(plaintext))
def decryptMsg(ciphertext, key):
# Initialization vector in AES should be 16 bytes
IV = 16 * '\x00'
# Creation of encryptor and decryptor object using above details
cipher = AES.new(key, AES.MODE_CBC, IV)
return unpad(cipher.decrypt(ciphertext));
msg = input('Enter The Message To Be Encrypted : ')
length = len(msg)
key = keyGen()
print("Key generated : " + str(key))
#Enter Threshold And No of splits for key
threshold=0
splits=0
while(True):
splits=input('Enter Max No of splits\n')
splits=int(splits)
threshold=input('Enter Threshold Value\n')
threshold=int(threshold)
if(splits>=threshold and threshold>=2):
break
else:
print("Please Choose Correct Pair Of values bcoz threshold<=split and threshold>=2")
#Formatting key inorder to convert bytes of string using base64
key_formatted=base64.b64encode(key).decode('utf-8')
print("Formatted Key="+key_formatted)
#Generating shares of formatted key
shared_key=splitSecret(key_formatted,threshold,splits)
print("Shared Keys="+str(shared_key))
#Recovering Keys using first threshold
recovered_key=recoverSecret(shared_key[:threshold])
#Converting recovered_key to bytes using base64 module
recovered_key=base64.b64decode(recovered_key)
print("Recovered Key="+str(recovered_key))
print(type(recovered_key))
#issue why recovered key!=key?
if(recovered_key==key):
print("True")
#Encryption using key generated
ciphertext = encryptMsg(msg,key)
print("Encrypted Text : " + str(ciphertext))
#Decryption using recovered key gives error(issue)
plaintext = decryptMsg(ciphertext,recovered_key)
print("Decrypted Text : " + str(plaintext))

View File

@ -0,0 +1,304 @@
#!/usr/bin/env python3
from tkinter import *
from tkinter import messagebox
from fpdf import FPDF
from secretsharing import PlaintextToHexSecretSharer
import base64
import os
from Crypto.Cipher import AES
import subprocess
from more_itertools import sliced
import json
#This function is for generating pdf
def generate_pdf(splits,threshold,shared_key,txid):
cnt=1
for i in range(splits):
pdf=FPDF()
pdf.add_page()
pdf.set_font('Arial','B',16)
pdf.image('Flo.png',20,20,33)
pdf.multi_cell(0,10,'A secret has been encrypted and posted on the blockchain of the FLO cryptocurrency.',0,'C',False)
pdf.multi_cell(0,10,'',0,'C','False')
pdf.multi_cell(0,10,'The key to decrypt this secret has been split in '+str(splits)+' shares like this one. By design, the secret can be decrypted with any '+str(threshold)+' of these shares.',0,'C',False)
pdf.multi_cell(0,10,'',0,'C','False')
pdf.multi_cell(0,10,'Below is the part of the key that belongs to this share',0,'C',False)
pdf.multi_cell(0,10,'',0,'C','False')
pdf.multi_cell(0,10,str(shared_key[i]),0,'C',False)
pdf.multi_cell(0,10,'',0,'C','False')
pdf.multi_cell(0,10,'Transaction Id For This Encryption Is Given Below',0,'C',False)
pdf.multi_cell(0,10,str(txid),0,'C',False)
pdf.set_y(-35)
pdf.set_font('Arial','B',8)
pdf.cell(0,10,'Page %s' % pdf.page_no(),0,0,'C')
pdf.output('sharedkey'+str(cnt)+'.pdf','F')
cnt+=1
# This function splits the secret and returns a list of shares
def splitSecret(secret,threshold,splits):
#Formatting key inorder to convert bytes of string using base64
secret = base64.b64encode(secret).decode('utf-8')
shares = PlaintextToHexSecretSharer.split_secret(secret, threshold, splits)
for i in range(splits):
shares[i]=base64.b64encode(shares[i].encode('utf-8')).decode('utf-8')
return shares
# This function recovers the secret using the list of shares and returns the reconstructed secret
def recoverSecret(shares):
for i in range(len(shares)):
shares[i] = (base64.b64decode(shares[i])).decode('utf-8')
secret = PlaintextToHexSecretSharer.recover_secret(shares)
#Converting recovered_key to bytes using base64 module
secret=base64.b64decode(secret)
return secret
def pad(data):
padding = 16 - len(data) % 16
return data + padding * chr(padding+97)
def unpad(data):
data = str(data)
padding = ord(data[-2]) - 96
return data[2:-padding]
def keyGen():
# Generating random key of 32 bytes
key = os.urandom(32)
return key
def encryptMsg(plaintext, key):
# Genarating Initialization vector for AES (16 bytes)
IV = os.urandom(16)
# Encrypting The plaintext
cipher = AES.new(key, AES.MODE_CBC, IV)
plaintext=base64.b64encode(plaintext.encode('utf-8')).decode('utf-8')
ciphertext = cipher.encrypt(pad(plaintext))
# Append IV and Ciphertext
ciphertext = base64.b64encode(IV).decode('utf-8') + base64.b64encode(ciphertext).decode('utf-8')
return ciphertext
def decryptMsg(ciphertext, key):
# Initialization vector in AES should be 16 bytes
IV = base64.b64decode(ciphertext[:24])
ciphertext=base64.b64decode(ciphertext[24:])
# Creation of encryptor and decryptor object using above details
cipher = AES.new(key, AES.MODE_CBC, IV)
plaintext=unpad(cipher.decrypt(ciphertext));
plaintext = (base64.b64decode(plaintext)).decode('utf-8')
return plaintext
#this function writes on a single flo-data filed
def writeUnitToBlockchain(text,receiver):
txid = subprocess.check_output(["flo-cli","--testnet", "sendtoaddress",receiver,"0.01",'""','""',"true","false","10",'UNSET',str(text)])
txid = str(txid)
txid = txid[2:-3]
return txid
def readUnitFromBlockchain(txid):
rawtx = subprocess.check_output(["flo-cli","--testnet", "getrawtransaction", str(txid)])
rawtx = str(rawtx)
rawtx = rawtx[2:-3]
tx = subprocess.check_output(["flo-cli","--testnet", "decoderawtransaction", str(rawtx)])
content = json.loads(tx)
text = content['floData']
return text
def writeDatatoBlockchain(text):
n_splits = len(text)//350 + 1 #number of splits to be created
splits = list(sliced(text, 350)) #create a sliced list of strings
tail = writeUnitToBlockchain(splits[n_splits-1],'oV9ZoREBSV5gFcZTBEJ7hdbCrDLSb4g96i') #create a transaction which will act as a tail for the data
cursor = tail
if n_splits == 1:
return cursor #if only single transaction was created then tail is the cursor
#for each string in the list create a transaction with txid of previous string
for i in range(n_splits-2,-1,-1):
splits[i] = 'next:'+cursor+" "+splits[i]
cursor = writeUnitToBlockchain(splits[i],'oV9ZoREBSV5gFcZTBEJ7hdbCrDLSb4g96i')
return cursor
def readDatafromBlockchain(cursor):
text = []
cursor_data = readUnitFromBlockchain(cursor)
while(cursor_data[:5]=='next:'):
cursor = cursor_data[5:69]
#print("fetching this transaction->>"+cursor)
text.append(cursor_data[70:])
cursor_data = readUnitFromBlockchain(cursor)
text.append(cursor_data)
#print(text)
text=('').join(text)
return text
class GUI:
def __init__(self, root):
self.root = root
self.frame = Frame(self.root)
self.vcmd = (self.frame.register(self.onValidate),
'%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
#validation for input as integers
def onValidate(self, d, i, P, s, S, v, V, W):
ind=int(i)
if d == '1': #insert
if not P[ind].isdigit():
return False
return True
def Main(self):
try:
self.PostFrame.destroy()
except:
None
try:
self.GetFrame.destroy()
except:
None
self.MainFrame = Frame(self.root, height=1000,width=500)
self.MainFrame.pack()
WelcomeLabel = Label(self.MainFrame,text="Welcome To FLO-Secret App",font=("Arial", 20))
WelcomeLabel.grid(column = 1, columnspan =2)
label =Label(self.MainFrame,text=" ")
label.grid(row = 2, columnspan =2)
PostButton = Button(self.MainFrame,text="POST",command=self.Post)
PostButton.grid(row =3,column=1)
GetButton = Button(self.MainFrame,text="GET",command=self.Get)
GetButton.grid(row =3, column=2)
contentText = "\n\nWhat is this?\n\tThis app let you save encrypted secret in the FLO blockchain and produces a number of keys that must be combined to be able to decrypt the secret.\n\nThis is a zero knowledge application.\n\tThe creation of the master key and shared keys and the encryption of the secret with the main key happens in the app. The app then sends the encrypted information to be posted in the FLO blockchain. This is the only information sent to our servers. The server reply with the hash of the transaction and the app produces the pdf containing information about the shares and the transaction.\n\nHow to encrypt an information? \n\tCurrently, we are only supporting messages typed or copied to a text area. Click in POST, select the number of total shares and the number of required shares, type or paste the information and click Submit.\n\nHow to decrypt a secret?\n\tClick in GET, type the number of minimum required shares and the hash of the transaction and press Find secret. Then insert the hash of each share and click decrypt. If everything is ok, you should be able to see the decrypted information."
Context = Message(self.MainFrame, text = contentText)
Context.grid(column = 1, columnspan =2)
def Post(self):
self.MainFrame.destroy()
self.PostFrame = Frame(self.root)
self.PostFrame.pack()
PL1 = Label(self.PostFrame,text="Enter Total Number of shares : ")
PL1.grid(row=1, column =1)
self.PE1 = Spinbox(self.PostFrame, from_ = 2, to = 1000, validate="key", validatecommand=self.vcmd)
self.PE1.grid(row=1, column =2)
PL2 = Label(self.PostFrame,text="Enter Minimum Number of required shares : ")
PL2.grid(row=2, column =1)
self.PE2 = Spinbox(self.PostFrame, from_ = 2, to = 1000, validate="key", validatecommand=self.vcmd)
self.PE2.grid(row=2, column =2)
PL3 = Label(self.PostFrame,text="Enter the message to be encrypted")
PL3.grid(row=3, column =1, columnspan=2)
PTextFrame = Frame(self.PostFrame)
self.PTextBox = Text(PTextFrame,height=10,width=50)
PScroll = Scrollbar(PTextFrame)
PScroll.config( command = self.PTextBox.yview )
self.PTextBox.pack(side = LEFT)
PScroll.pack(side = RIGHT,fill = Y )
PTextFrame.grid(column=1,columnspan=2)
PBackButton = Button(self.PostFrame,text="Back",command=self.Main)
PBackButton.grid(row=5, column =1)
self.PNextButton = Button(self.PostFrame,text="Submit",command=self.Encryption)
self.PNextButton.grid(row=5, column =2)
def Encryption(self):
splits = int(self.PE1.get())
threshold = int(self.PE2.get())
if (threshold > splits or threshold<2) :
messagebox.showwarning("Invalid!", "Minimum-Shares-Required should be greater than 2 and lesser than or equal to Total-Shares ")
return
self.PE1.config(state='disabled')
self.PE2.config(state='disabled')
self.PTextBox.config(state='disabled')
key = keyGen()
plaintext = self.PTextBox.get("1.0",'end-1c')
shared_key = splitSecret(key,threshold,splits)
ciphertext = encryptMsg(plaintext,key)
try:
txid = writeDatatoBlockchain(ciphertext)
generate_pdf(splits,threshold,shared_key,txid)
except:
messagebox.showerror("Connection Failed!", "Please run the node(Flo-Core)!")
return
print("Shared Keys="+str(shared_key))
print('txid: ',txid)
self.PNextButton.destroy()
messagebox.showinfo("Successful!", "Your data is successfully encrypted and stored in the FLO Blockchain!")
def Get(self):
self.MainFrame.destroy()
self.GetFrame = Frame(self.root)
self.GetFrame.pack()
GL1 = Label(self.GetFrame,text="Enter Number of required shares : ")
GL1.grid(row=1,column=1)
self.GE1 = Spinbox(self.GetFrame, from_ = 2, to = 1000, validate="key", validatecommand=self.vcmd)
self.GE1.grid(row=1,column=2)
GL2 = Label(self.GetFrame,text="Enter Transaction hash : ")
GL2.grid(row=2,column=1)
self.GE2 = Entry(self.GetFrame)
self.GE2.grid(row=2,column=2)
txid = self.GE2.get()
self.GFindButton = Button(self.GetFrame,text="Find Secret",command=self.GetSharedKey)
self.GFindButton.grid(row=3,column=2)
self.GBackButton=Button(self.GetFrame,text="Back",command=self.Main)
self.GBackButton.grid(row=3,column=1)
def GetSharedKey(self):
try:
txid = self.GE2.get()
self.ciphertext = readDatafromBlockchain(txid)
except:
messagebox.showerror("Data retrieval Failed!", "Please enter valid transaction hash!\nAlso run the node(Flo-Core)!")
return
self.numOfShares = int(self.GE1.get())
self.GFindButton.destroy()
self.GBackButton.destroy()
self.GE1.config(state='disabled')
self.GE2.config(state='disabled')
GLArray = [None] * self.numOfShares
self.GEArray = [None] * self.numOfShares
for i in range(self.numOfShares):
GLArray[i] = Label(self.GetFrame, text="Shared key #"+str(i+1))
GLArray[i].grid(column=1)
self.GEArray[i] = Entry(self.GetFrame)
self.GEArray[i].grid(column=2)
self.GBackButton=Button(self.GetFrame,text="Back",command=self.Main)
self.GBackButton.grid(column=1)
self.GDecryptButton = Button(self.GetFrame,text="Decrypt",command=self.DecryptMsg)
self.GDecryptButton.grid(column=2)
def DecryptMsg(self):
shares = [None] * self.numOfShares
for i in range(self.numOfShares):
shares[i] = self.GEArray[i].get()
try:
key=recoverSecret(shares)
plaintext = decryptMsg(self.ciphertext,key)
except:
messagebox.showerror("Decryption Failed!", "Please enter the correct shared keys!")
return
for i in range(self.numOfShares):
shares[i] = self.GEArray[i].config(state='disabled')
self.GDecryptButton.destroy()
self.GBackButton.destroy()
GL3 = Label(self.GetFrame, text="Found Secret Message")
GL3.grid(column=1, columnspan=2)
GTextFrame = Frame(self.GetFrame)
self.GLMsg = Text(GTextFrame,height=10,width=50)
self.GLMsg.insert(END, plaintext)
self.GLMsg.config(state='disabled')
GScroll = Scrollbar(GTextFrame)
GScroll.config( command = self.GLMsg.yview )
self.GLMsg.pack(side = LEFT)
GScroll.pack(side = RIGHT,fill = Y)
GTextFrame.grid(column=1,columnspan=2)
self.GBackButton=Button(self.GetFrame,text="Back",command=self.Main)
self.GBackButton.grid(column=1)
root = Tk()
root.title("FloSecret")
gui = GUI(root)
gui.Main()
root.mainloop()

108
_temp/gui.py Executable file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env python3
from tkinter import *
class GUI:
def __init__(self, root):
self.root = root
def Main(self):
try:
self.PostFrame.destroy()
except:
None
try:
self.GetFrame.destroy()
except:
None
self.MainFrame = Frame(self.root)
self.MainFrame.pack()
WelcomeLabel = Label(self.MainFrame,text="Welcome To FloSecret App")
WelcomeLabel.pack()
PostButton = Button(self.MainFrame,text="POST",command=self.Post)
PostButton.pack()
GetButton = Button(self.MainFrame,text="GET",command=self.Get)
GetButton.pack()
def Post(self):
self.MainFrame.destroy()
self.PostFrame = Frame(self.root)
self.PostFrame.pack()
PL1 = Label(self.PostFrame,text="Enter Total Number of shares : ")
PL1.grid(row=1, column =1)
self.PE1 = Entry(self.PostFrame)
self.PE1.grid(row=1, column =2)
PL2 = Label(self.PostFrame,text="Enter Minimum Number of required shares : ")
PL2.grid(row=2, column =1)
self.PE2 = Entry(self.PostFrame)
self.PE2.grid(row=2, column =2)
PL3 = Label(self.PostFrame,text="Enter the message to be encrypted")
PL3.grid(row=3, column =1, columnspan=2)
self.PTextBox = Text(self.PostFrame,height=10,width=50)
PScroll = Scrollbar(self.PostFrame)
self.PTextBox.configure(yscrollcommand=PScroll.set)
self.PTextBox.grid(row=4, column =1, columnspan=2)
PScroll.grid(row=4, column =1,sticky = E,columnspan=2)
PBackButton=Button(self.PostFrame,text="Back",command=self.Main)
PBackButton.grid(row=5, column =1)
PNextButton=Button(self.PostFrame,text="Post",command=self.SendToFlo)
PNextButton.grid(row=5, column =2)
def SendToFlo(self):
#get a master key
#encrypt using AES
#store in FLO Blockchain
#return the hash n shared keys
return
def Get(self):
self.MainFrame.destroy()
self.GetFrame = Frame(self.root)
self.GetFrame.pack()
GL1 = Label(self.GetFrame,text="Enter Number of required shares : ")
GL1.grid(row=1,column=1)
self.GE1 = Entry(self.GetFrame)
self.GE1.grid(row=1,column=2)
GL2 = Label(self.GetFrame,text="Enter Transaction hash : ")
GL2.grid(row=2,column=1)
self.GE2 = Entry(self.GetFrame)
self.GE2.grid(row=2,column=2)
GButton = Button(self.GetFrame,text="Find Secret",command=self.GetSharedKey)
GButton.grid(row=3,column=1)
GBackButton=Button(self.GetFrame,text="Back",command=self.Main)
GBackButton.grid(row=3,column=2)
def GetSharedKey(self):
try:
numOfShares = int(self.GE1.get())
except:
print("Invalid Int")
return
GLArray = [None] * numOfShares
GEArray = [None] * numOfShares
for i in range(numOfShares):
GLArray[i] = Label(self.GetFrame, text="Shared key #"+str(i+1))
GLArray[i].grid(column=1)
GEArray[i] = Entry(self.GetFrame)
GEArray[i].grid(column=2)
GButton2 = Button(self.GetFrame,text="Decrypt",command=self.DecryptMsg)
GButton2.grid(column=1, columnspan=2)
def DecryptMsg(self):
#retrive the encryted data from the transaction in FLO blkchain
#decrypt the message using AES and shared key
#display the message
return
root = Tk()
root.title("FloSecret")
gui = GUI(root)
gui.Main()
root.mainloop()

18
_temp/pdf_gen.py Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
#Refer from this site- https://pyfpdf.readthedocs.io/en/latest/Tutorial/index.html
from fpdf import FPDF
pdf = FPDF()
pdf.add_page()
#Header
pdf.set_font('Arial', 'B', 16)
#width,height,msg,border,align,background
pdf.image('Flo.png',20,20,33)
pdf.multi_cell(0,10,'A secret has been encrypted and posted on the blockchain of the FLO cryptocurrency.',0,'C',False)
pdf.multi_cell(0,10,'The key to decrypt this secret has been split in 3 shares like this one. By design, the secret can be decrypted with any 2 of these shares.',0,'C',False)
pdf.multi_cell(0,10,'Bellow is the part of the key that belongs to this share',0,'C',False)
#add shared key using multi_cell
#footer
pdf.set_y(-35)
pdf.set_font('Arial', 'B', 8)
pdf.cell(0, 10, 'Page %s' % pdf.page_no(), 0, 0, 'C')
pdf.output('sharedkey.pdf','F')

56
_temp/util.py Executable file
View File

@ -0,0 +1,56 @@
from secretsharing import PlaintextToHexSecretSharer
import subprocess
import json
from Crypto.Cipher import AES
from more_itertools import sliced
# This function splits the secret and returns a list of shares
def splitSecret(secret,threshold,splits):
shares = PlaintextToHexSecretSharer.split_secret(secret, threshold, splits)
return shares
# This function recovers the secret using the list of shares and returns the reconstructed secret
def recoverSecret(shares):
secret = PlaintextToHexSecretSharer.recover_secret(shares)
return secret
def writeUnitToBlockchain(text,receiver):
txid = subprocess.check_output(["flo-cli","--testnet", "sendtoaddress",receiver,"0.01",'""','""',"true","false","10",'UNSET',str(text)])
txid = str(txid)
txid = txid[2:-3]
return txid
def readUnitFromBlockchain(txid):
rawtx = subprocess.check_output(["flo-cli","--testnet", "getrawtransaction", str(txid)])
rawtx = str(rawtx)
rawtx = rawtx[2:-3]
tx = subprocess.check_output(["flo-cli","--testnet", "decoderawtransaction", str(rawtx)])
content = json.loads(tx)
text = content['floData']
return text
def writeDatatoBlockchain(text):
n_splits = len(text)//350 + 1 #number of splits to be created
splits = list(sliced(text, 350)) #create a sliced list of strings
#TODO pass this receiving address as parameter
tail = writeUnitToBlockchain(splits[n_splits-1],'oV9ZoREBSV5gFcZTBEJ7hdbCrDLSb4g96i') #create a transaction which will act as a tail for the data
cursor = tail
if n_splits == 1:
return cursor #if only single transaction was created then tail is the cursor
#for each string in the list create a transaction with txid of previous string
for i in range(n_splits-2,-1,-1):
splits[i] = 'next:'+cursor+" "+splits[i]
cursor = writeUnitToBlockchain(splits[i],'oV9ZoREBSV5gFcZTBEJ7hdbCrDLSb4g96i')
return cursor
def readDatafromBlockchain(cursor):
text = []
cursor_data = readUnitFromBlockchain(cursor)
while(cursor_data[:5]=='next:'):
cursor = cursor_data[5:69]
text.append(cursor_data[70:])
cursor_data = readUnitFromBlockchain(cursor)
text.append(cursor_data)
text=('').join(text)
return text

BIN
bin/FLO_Secret Executable file

Binary file not shown.

BIN
bin/Flo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

288
main.py Executable file
View File

@ -0,0 +1,288 @@
#!/usr/bin/env python3
from tkinter import *
from tkinter import messagebox
from secretsharing import PlaintextToHexSecretSharer
import base64
import os
from Crypto.Cipher import AES
import subprocess
from more_itertools import sliced
import json
###Utility function###
# This function splits the secret and returns a list of shares
def splitSecret(secret,threshold,splits):
#Formatting key inorder to convert bytes of string using base64
secret = base64.b64encode(secret).decode('utf-8')
shares = PlaintextToHexSecretSharer.split_secret(secret, threshold, splits)
for i in range(splits):
shares[i]=base64.b64encode(shares[i].encode('utf-8')).decode('utf-8')
return shares
# This function recovers the secret using the list of shares and returns the reconstructed secret
def recoverSecret(shares):
for i in range(len(shares)):
shares[i] = (base64.b64decode(shares[i])).decode('utf-8')
secret = PlaintextToHexSecretSharer.recover_secret(shares)
#Converting recovered_key to bytes using base64 module
secret=base64.b64decode(secret)
return secret
def pad(data):
padding = 16 - len(data) % 16
return data + padding * chr(padding+97)
def unpad(data):
data = str(data)
padding = ord(data[-2]) - 96
return data[2:-padding]
def keyGen():
# Generating random key of 32 bytes
key = os.urandom(32)
return key
def encryptMsg(plaintext, key):
# Genarating Initialization vector for AES (16 bytes)
IV = os.urandom(16)
# Encrypting The plaintext
cipher = AES.new(key, AES.MODE_CBC, IV)
plaintext=base64.b64encode(plaintext.encode('utf-8')).decode('utf-8')
ciphertext = cipher.encrypt(pad(plaintext))
# Append IV and Ciphertext
ciphertext = base64.b64encode(IV).decode('utf-8') + base64.b64encode(ciphertext).decode('utf-8')
return ciphertext
def decryptMsg(ciphertext, key):
# Initialization vector in AES should be 16 bytes
IV = base64.b64decode(ciphertext[:24])
ciphertext=base64.b64decode(ciphertext[24:])
# Creation of encryptor and decryptor object using above details
cipher = AES.new(key, AES.MODE_CBC, IV)
plaintext=unpad(cipher.decrypt(ciphertext));
plaintext = (base64.b64decode(plaintext)).decode('utf-8')
return plaintext
def writeUnitToBlockchain(text,receiver):
txid = subprocess.check_output(["flo-cli","--testnet", "sendtoaddress",receiver,"0.01",'""','""',"true","false","10",'UNSET',str(text)])
txid = str(txid)
txid = txid[2:-3]
return txid
def readUnitFromBlockchain(txid):
rawtx = subprocess.check_output(["flo-cli","--testnet", "getrawtransaction", str(txid)])
rawtx = str(rawtx)
rawtx = rawtx[2:-3]
tx = subprocess.check_output(["flo-cli","--testnet", "decoderawtransaction", str(rawtx)])
content = json.loads(tx)
text = content['floData']
return text
def writeDatatoBlockchain(text):
n_splits = len(text)//350 + 1 #number of splits to be created
splits = list(sliced(text, 350)) #create a sliced list of strings
#for split in splits:
# print(split)
#print('no.of splits: '+str(n_splits))
tail = writeUnitToBlockchain(splits[n_splits-1],'oV9ZoREBSV5gFcZTBEJ7hdbCrDLSb4g96i') #create a transaction which will act as a tail for the data
cursor = tail
if n_splits == 1:
return cursor #if only single transaction was created then tail is the cursor
#for each string in the list create a transaction with txid of previous string
for i in range(n_splits-2,-1,-1):
splits[i] = 'next:'+cursor+" "+splits[i]
#print(splits[i])
cursor = writeUnitToBlockchain(splits[i],'oV9ZoREBSV5gFcZTBEJ7hdbCrDLSb4g96i')
return cursor
def readDatafromBlockchain(cursor):
text = []
cursor_data = readUnitFromBlockchain(cursor)
while(cursor_data[:5]=='next:'):
cursor = cursor_data[5:69]
#print("fetching this transaction->>"+cursor)
text.append(cursor_data[70:])
cursor_data = readUnitFromBlockchain(cursor)
text.append(cursor_data)
#print(text)
text=('').join(text)
return text
###START OF GUI###
class GUI:
def __init__(self, root):
self.root = root
self.frame = Frame(self.root)
self.vcmd = (self.frame.register(self.onValidate),
'%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
#validation for input as integers
def onValidate(self, d, i, P, s, S, v, V, W):
ind=int(i)
if d == '1': #insert
if not P[ind].isdigit():
return False
return True
def Main(self):
try:
self.PostFrame.destroy()
except:
None
try:
self.GetFrame.destroy()
except:
None
self.MainFrame = Frame(self.root, height=1000,width=500)
self.MainFrame.pack()
WelcomeLabel = Label(self.MainFrame,text="Welcome To FLO-Secret App",font=("Arial", 20))
WelcomeLabel.grid(column = 1, columnspan =2)
label =Label(self.MainFrame,text=" ")
label.grid(row = 2, columnspan =2)
PostButton = Button(self.MainFrame,text="POST",command=self.Post)
PostButton.grid(row =3,column=1)
GetButton = Button(self.MainFrame,text="GET",command=self.Get)
GetButton.grid(row =3, column=2)
contentText = "\n\nWhat is this?\n\tThis app let you save encrypted secret in the FLO blockchain and produces a number of keys that must be combined to be able to decrypt the secret.\n\nThis is a zero knowledge application.\n\tThe creation of the master key and shared keys and the encryption of the secret with the main key happens in the app. The app then sends the encrypted information to be posted in the FLO blockchain. This is the only information sent to our servers. The server reply with the hash of the transaction and the app produces the pdf containing information about the shares and the transaction.\n\nHow to encrypt an information? \n\tCurrently, we are only supporting messages typed or copied to a text area. Click in POST, select the number of total shares and the number of required shares, type or paste the information and click Submit.\n\nHow to decrypt a secret?\n\tClick in GET, type the number of minimum required shares and the hash of the transaction and press Find secret. Then insert the hash of each share and click decrypt. If everything is ok, you should be able to see the decrypted information."
Context = Message(self.MainFrame, text = contentText)
Context.grid(column = 1, columnspan =2)
def Post(self):
self.MainFrame.destroy()
self.PostFrame = Frame(self.root)
self.PostFrame.pack()
PL1 = Label(self.PostFrame,text="Enter Total Number of shares : ")
PL1.grid(row=1, column =1)
self.PE1 = Spinbox(self.PostFrame, from_ = 2, to = 1000, validate="key", validatecommand=self.vcmd)
self.PE1.grid(row=1, column =2)
PL2 = Label(self.PostFrame,text="Enter Minimum Number of required shares : ")
PL2.grid(row=2, column =1)
self.PE2 = Spinbox(self.PostFrame, from_ = 2, to = 1000, validate="key", validatecommand=self.vcmd)
self.PE2.grid(row=2, column =2)
PL3 = Label(self.PostFrame,text="Enter the message to be encrypted")
PL3.grid(row=3, column =1, columnspan=2)
PTextFrame = Frame(self.PostFrame)
self.PTextBox = Text(PTextFrame,height=10,width=50)
PScroll = Scrollbar(PTextFrame)
PScroll.config( command = self.PTextBox.yview )
self.PTextBox.pack(side = LEFT)
PScroll.pack(side = RIGHT,fill = Y )
PTextFrame.grid(column=1,columnspan=2)
PBackButton = Button(self.PostFrame,text="Back",command=self.Main)
PBackButton.grid(row=5, column =1)
self.PNextButton = Button(self.PostFrame,text="Submit",command=self.Encryption)
self.PNextButton.grid(row=5, column =2)
def Encryption(self):
splits = int(self.PE1.get())
threshold = int(self.PE2.get())
if (threshold > splits or threshold<2) :
messagebox.showwarning("Invalid!", "Minimum-Shares-Required should be greater than 2 and lesser than or equal to Total-Shares ")
return
self.PE1.config(state='disabled')
self.PE2.config(state='disabled')
self.PTextBox.config(state='disabled')
key = keyGen()
plaintext = self.PTextBox.get("1.0",'end-1c')
shared_key = splitSecret(key,threshold,splits)
ciphertext = encryptMsg(plaintext,key)
try:
txid = writeDatatoBlockchain(ciphertext)
except:
messagebox.showerror("Connection Failed!", "Please run the node(Flo-Core)!")
return
print("Shared Keys="+str(shared_key))
print('txid: ',txid)
self.PNextButton.destroy()
messagebox.showinfo("Successful!", "Your data is successfully encrypted and stored in the FLO Blockchain!")
def Get(self):
self.MainFrame.destroy()
self.GetFrame = Frame(self.root)
self.GetFrame.pack()
GL1 = Label(self.GetFrame,text="Enter Number of required shares : ")
GL1.grid(row=1,column=1)
self.GE1 = Spinbox(self.GetFrame, from_ = 2, to = 1000, validate="key", validatecommand=self.vcmd)
self.GE1.grid(row=1,column=2)
GL2 = Label(self.GetFrame,text="Enter Transaction hash : ")
GL2.grid(row=2,column=1)
self.GE2 = Entry(self.GetFrame)
self.GE2.grid(row=2,column=2)
txid = self.GE2.get()
self.GFindButton = Button(self.GetFrame,text="Find Secret",command=self.GetSharedKey)
self.GFindButton.grid(row=3,column=2)
self.GBackButton=Button(self.GetFrame,text="Back",command=self.Main)
self.GBackButton.grid(row=3,column=1)
def GetSharedKey(self):
try:
txid = self.GE2.get()
self.ciphertext = readDatafromBlockchain(txid)
except:
messagebox.showerror("Data retrieval Failed!", "Please enter valid transaction hash!\nAlso run the node(Flo-Core)!")
return
self.numOfShares = int(self.GE1.get())
self.GFindButton.destroy()
self.GBackButton.destroy()
self.GE1.config(state='disabled')
self.GE2.config(state='disabled')
GLArray = [None] * self.numOfShares
self.GEArray = [None] * self.numOfShares
for i in range(self.numOfShares):
GLArray[i] = Label(self.GetFrame, text="Shared key #"+str(i+1))
GLArray[i].grid(column=1)
self.GEArray[i] = Entry(self.GetFrame)
self.GEArray[i].grid(column=2)
self.GBackButton=Button(self.GetFrame,text="Back",command=self.Main)
self.GBackButton.grid(column=1)
self.GDecryptButton = Button(self.GetFrame,text="Decrypt",command=self.DecryptMsg)
self.GDecryptButton.grid(column=2)
def DecryptMsg(self):
shares = [None] * self.numOfShares
for i in range(self.numOfShares):
shares[i] = self.GEArray[i].get()
try:
key=recoverSecret(shares)
plaintext = decryptMsg(self.ciphertext,key)
except:
messagebox.showerror("Decryption Failed!", "Please enter the correct shared keys!")
return
for i in range(self.numOfShares):
shares[i] = self.GEArray[i].config(state='disabled')
self.GDecryptButton.destroy()
self.GBackButton.destroy()
GL3 = Label(self.GetFrame, text="Found Secret Message")
GL3.grid(column=1, columnspan=2)
GTextFrame = Frame(self.GetFrame)
self.GLMsg = Text(GTextFrame,height=10,width=50)
self.GLMsg.insert(END, plaintext)
self.GLMsg.config(state='disabled')
GScroll = Scrollbar(GTextFrame)
GScroll.config( command = self.GLMsg.yview )
self.GLMsg.pack(side = LEFT)
GScroll.pack(side = RIGHT,fill = Y)
GTextFrame.grid(column=1,columnspan=2)
self.GBackButton=Button(self.GetFrame,text="Back",command=self.Main)
self.GBackButton.grid(column=1)
root = Tk()
root.title("FloSecret")
gui = GUI(root)
gui.Main()
root.mainloop()