changed diretory structure and added readme
This commit is contained in:
parent
ba87eb7b60
commit
40e20da059
42
Aes256.py
42
Aes256.py
@ -1,42 +0,0 @@
|
||||
#!/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))
|
||||
BIN
FLO_Secret
BIN
FLO_Secret
Binary file not shown.
281
FLO_Secret.py
281
FLO_Secret.py
@ -1,281 +0,0 @@
|
||||
#!/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
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
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()
|
||||
|
||||
|
||||
304
Fin.py
304
Fin.py
@ -1,304 +0,0 @@
|
||||
#!/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
|
||||
|
||||
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
|
||||
|
||||
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()
|
||||
0
Flo.png
Normal file → Executable file
0
Flo.png
Normal file → Executable file
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
25
README.md
Normal file → Executable file
25
README.md
Normal file → Executable file
@ -1,2 +1,25 @@
|
||||
# FLOShamir
|
||||
A decentralised platform for creating shared secrets
|
||||
This 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.
|
||||
A shared secret is a way of splitting a secret into n in keys such that m out of n keys are required to decrypt the message. Built using Shamir's shared secret algorithm, this app stores the encrypted secret message on blockchain and splits the key into n shares and any of the m share holders can decrypt the message.
|
||||
Storing secrets on the blockchain makes sure that the file can't be altered and is accessible from anywhere.Also allowing us to use shared secret algorithm for large messages.
|
||||
|
||||
##requirements
|
||||
1. linux operating system(working on a cross platform version).
|
||||
2. You need to run a full flo-qt wallet to run it. Download it from here https://github.com/floblockchain/flo
|
||||
3. Some amount of FLO if you want to post a secret
|
||||
|
||||
**WARNING: Currently the app is using the testnet**
|
||||
|
||||
##Usage
|
||||
-> Clone/download this repository. (https://github.com/akhil2015/FLOShamir)
|
||||
-> Run the binary file inside bin folder.
|
||||
###To create a shared-secret
|
||||
-> click on POST to create a new shared secret message
|
||||
-> You will get a pdf containing your Secret ID and the shares of the keys used to encrypt it.
|
||||
-> It is a good practise to destroy the pdf once the shares have been distributed.
|
||||
###To read a shared secret
|
||||
-> Click on GET to read the message.
|
||||
-> Enter the Secret ID and shares of the keys and your are done
|
||||
-> You should get a screen with the secret message displayed there.
|
||||
|
||||
|
||||
|
||||
93
check.py
93
check.py
@ -1,93 +0,0 @@
|
||||
#!/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))
|
||||
108
gui.py
108
gui.py
@ -1,108 +0,0 @@
|
||||
#!/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()
|
||||
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
#!/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')
|
||||
57
util.py
57
util.py
@ -1,57 +0,0 @@
|
||||
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", "sendtoaddress",receiver,"0.01",'""','""',"true","false","10",'UNSET',str(page_html)])
|
||||
txid = str(txid)
|
||||
txid = txid[2:-3]
|
||||
return txid
|
||||
|
||||
def readUnitFromBlockchain(txid):
|
||||
rawtx = subprocess.check_output(["flo-cli", "getrawtransaction", str(txid)])
|
||||
rawtx = str(rawtx)
|
||||
rawtx = rawtx[2:-3]
|
||||
tx = subprocess.check_output(["flo-cli",, "decoderawtransaction", str(rawtx)])
|
||||
content = json.loads(tx)
|
||||
text = content['floData']
|
||||
return text
|
||||
|
||||
#write data chunk to blockchain
|
||||
def writeDatatoBlockchain(text):
|
||||
n_splits = len(text)//350 + 1 #number of splits to be created
|
||||
splits = list(sliced(text, n_splits)) #create a sliced list of strings
|
||||
tail = writeUnitToBlockchain(splits[n_splits]) #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-1,0):
|
||||
splits[i] = 'next:'+cursor+splits[i]
|
||||
cursor = writeUnitToBlockchain(splits[i])
|
||||
return cursor
|
||||
|
||||
#TODO read data chunk from blockchain
|
||||
def readDatafromBlockchain(cursor):
|
||||
text = []
|
||||
cursor_data = readUnitFromBlockchain(cursor)
|
||||
text.append(cursor_data[69:]) #TODO enter cursor values
|
||||
while(cursor_data[:5]=='next:'):
|
||||
cursor = cursor_data[5:69]
|
||||
cursor_data = readUnitFromBlockchain(cursor)
|
||||
text.append(cursor_data[69:])
|
||||
text.join('')
|
||||
return text
|
||||
Loading…
Reference in New Issue
Block a user