Commit 07dfe17d authored by Frederik Thor Wind Norup's avatar Frederik Thor Wind Norup
Browse files

added peer program to repo

parents
package encrypt
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"math/big"
"strings"
)
type PublicKey struct {
n *big.Int
e *big.Int
}
type PrivateKey struct {
n *big.Int
d *big.Int
}
// KeyGen generates a new RSA key
func KeyGen(k int) (pub *PublicKey, priv *PrivateKey) {
publicKey := new(PublicKey)
privateKey := new(PrivateKey)
publicKey.e = big.NewInt(3)
// call generatePQ to get our p q for calculating n and d
p, q := generatePQ(k, publicKey)
// n = p*q
n := big.NewInt(0).Mul(p, q)
// add n to our structs
publicKey.n = n
privateKey.n = n
// d = 3^-1 mod (p-1)(q-1)
factorMul := big.NewInt(0)
factorMul.Mul(p.Sub(p, big.NewInt(1)), q.Sub(q, big.NewInt(1)))
d := big.NewInt(0)
privateKey.d = d.ModInverse(publicKey.e, factorMul)
return publicKey, privateKey
}
// generatePQ takes k as bit length of n and publicKey exponent
func generatePQ(k int, pub *PublicKey) (p *big.Int, q *big.Int) {
for {
// generate random p and q
p, _ := rand.Prime(rand.Reader, k/2)
q, _ := rand.Prime(rand.Reader, k/2)
pGCD := big.NewInt(0)
qGCD := big.NewInt(0)
// check if GCD(3, p-1) = GCD(3, q-1) = 1 if so return our p and q
pGCD.GCD(nil, nil, pub.e, subOne(p))
qGCD.GCD(nil, nil, pub.e, subOne(q))
//isEqual := big.NewInt(1)
if big.NewInt(1).Cmp(pGCD) == 0 {
if big.NewInt(1).Cmp(qGCD) == 0 {
return p, q
}
}
}
}
// subOne subtracts 1 from n without saving it in n
func subOne(n *big.Int) *big.Int {
newN := big.NewInt(0).Sub(n, big.NewInt(1))
return newN
}
// Encrypt encrypts message
func Encrypt(m *big.Int, pub *PublicKey) *big.Int {
m.Exp(m, pub.e, pub.n)
return m
}
// Decrypt decrypts message
func Decrypt(m *big.Int, priv *PrivateKey) *big.Int {
m.Exp(m, priv.d, priv.n)
return m
}
// EncryptToFile encrypts given byte array to given fileName and encrypts with given cypherKey
func EncryptToFile(fileName string, cipherstring []byte, cipherKey string) {
// generate new cypher based on key
key := []byte(cipherKey)
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// ciphertext byte array that is length of given array + aes.blockSize
ciphertext := make([]byte, aes.BlockSize+len(cipherstring))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
// encrypt ciphertext and write to file
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], cipherstring)
ioutil.WriteFile(fileName, []byte(ciphertext), 0777)
}
// DecryptFromFile decrypts file on given string with a given cypher key
func DecryptFromFile(fileName string, cipherKey string) {
// read file and convert to bytes
cipherstring, err := ioutil.ReadFile(fileName)
if err != nil {
panic(err)
}
ciphertext := []byte(cipherstring)
// make a new cypherKey from given key
key := []byte(cipherKey)
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// decrypt text and write back to file
iv := ciphertext[:aes.BlockSize]
stream := cipher.NewCTR(block, iv)
plaintext := make([]byte, len(ciphertext[aes.BlockSize:]))
stream.XORKeyStream(plaintext, ciphertext[aes.BlockSize:])
ioutil.WriteFile(fileName, plaintext, 0777)
}
func encryptSign(m *big.Int, priv *PrivateKey) *big.Int {
m.Exp(m, priv.d, priv.n)
return m
}
func decryptSign(m *big.Int, pub *PublicKey) *big.Int {
m.Exp(m, pub.e, pub.n)
return m
}
func generateHash(m *big.Int) *big.Int {
data := m.Bytes()
hash := sha256.New()
hash.Write(data)
intHash := big.NewInt(0)
intHash.SetBytes(hash.Sum(nil))
return intHash
}
func GenerateSign(m *big.Int, priv *PrivateKey) *big.Int {
sign := generateHash(m)
sign = encryptSign(sign, priv)
return sign
}
func VerifySign(m *big.Int, s *big.Int, pub *PublicKey) bool {
calculatedHash := generateHash(m)
signedHash := decryptSign(s, pub)
verified := false
if calculatedHash.Cmp(signedHash) == 0 {
verified = true
} else {
fmt.Println("Unable to verify hash")
}
return verified
}
func PrivateKeyToString(key *PrivateKey) string {
d := key.d.String()
n := key.n.String()
encoded := d + ":" + n
return encoded
}
func StringToPrivateKey(encodedKey string) *PrivateKey {
splitString := strings.Split(encodedKey, ":")
key := new(PrivateKey)
d := big.NewInt(0)
d.SetString(splitString[0], 10)
key.d = d
n := big.NewInt(0)
n.SetString(splitString[1], 10)
key.n = n
return key
}
func PublicKeyToString(key *PublicKey) string {
if key.e == nil || key.n == nil {
panic("public Key value = nil")
}
e := key.e.String()
n := key.n.String()
encoded := e + ":" + n
return encoded
}
func StringToPublicKey(encodedKey string) *PublicKey {
splitString := strings.Split(encodedKey, ":")
key := new(PublicKey)
e := big.NewInt(0)
e.SetString(splitString[0], 10)
key.e = e
n := big.NewInt(0)
n.SetString(splitString[1], 10)
key.n = n
if key.e == nil || key.n == nil {
panic("public Key value = nil")
}
return key
}
func CreateDummyKey() *PublicKey {
dummyKey := new(PublicKey)
dummyKey.e = big.NewInt(1)
dummyKey.n = big.NewInt(1)
return dummyKey
}
func IsKeyInitialised(key string) bool {
if key == "1:1" {
return false
}
return true
}
module the-spice-boyz/encrypt
go 1.17
module main
go 1.17
package main
import (
"bufio"
"encoding/gob"
. "encrypt"
"fmt"
"log"
"net"
"os"
"strconv"
. "structs/clientlist"
. "structs/connection"
. "structs/counter"
. "structs/ledger"
/* "strconv" */
"math/big"
"math/rand"
"strings"
"sync"
"time"
)
// Peer is the main struct
type Peer struct {
ip string
counter *Counter
clients *ClientList
ledger *Ledger
mux sync.Mutex
msgChan chan *Message
enc *gob.Encoder
dec *gob.Decoder
sentID []string
pubKey string
privKey string
}
// Message is used for Marshalling structs (encoding/decoding)
type Message struct {
M string
PeerList []*Connection // list of peers
Conn *Connection
Trans *SignedTransaction
Counter *Counter
}
// MakeMessage creates a message with default values
func MakeMessage() *Message {
m := new(Message)
m.M = ""
m.PeerList = make([]*Connection, 0)
return m
}
// MakePeer creates a new peer object with initialized lists and maps
func MakePeer() *Peer {
peer := new(Peer)
peer.sentID = make([]string, 0)
pubKey, privKey := KeyGen(2000)
peer.pubKey = PublicKeyToString(pubKey)
peer.privKey = PrivateKeyToString(privKey)
return peer
}
func main() {
peer := MakePeer()
peer.ledger = MakeLedger()
peer.clients = MakeClientList()
peer.msgChan = make(chan *Message)
readerAddress := bufio.NewReader(os.Stdin)
fmt.Print("Enter IP address and port number: ")
readerIP, _ := readerAddress.ReadString('\n') // read input from user
conn, err := net.Dial("tcp", strings.TrimSpace(readerIP))
if err != nil {
fmt.Println("Not able to connect to: " + readerIP)
fmt.Println("Creating personal network...")
} else {
peer.addClientsToList(MakeConnection(peer.ip, "1:1"))
go recieve(peer, conn)
go sender(peer, conn)
peer.msgChan <- peer.textToFunctionCall("getListOfPeers")
peer.msgChan <- peer.textToFunctionCall("presence")
}
go handleMessage(peer) //gets user input for this peer
createServer(peer)
}
func createServer(peer *Peer) {
ln, _ := net.Listen("tcp", "127.0.0.1:0")
peer.ip = ln.Addr().String()
peer.counter = InitCounter(peer.ip)
defer ln.Close()
fmt.Println("Listening for connection on port: " + peer.ip)
for {
conn, _ := ln.Accept() // accept incomming connection request
if conn != nil {
peer.clients.AddClient(MakeConnection(peer.ip, peer.pubKey)) // adds new client with Connection struct
}
/* fmt.Println(peer.clients) // test print all connections */
fmt.Print("Got a connection on... ")
fmt.Println(conn.RemoteAddr().String())
go recieve(peer, conn)
go sender(peer, conn) //creates new thread that sends whatever it recieves
}
}
func (peer *Peer) addClientsToList(conn *Connection) {
peer.mux.Lock()
peer.clients.AddClient(conn)
peer.mux.Unlock()
}
// handleMessage handles user input and converts into message objects of corresponding functions
func handleMessage(peer *Peer) {
for {
reader := bufio.NewReader(os.Stdin) // reads user input in terminal
msg, err := reader.ReadString('\n') // saves user input from terminal in var text
if err != nil {
fmt.Println("Error occured... closing connection")
return
}
msg = strings.TrimSpace(msg)
if len(msg) != 0 {
m := peer.textToFunctionCall(msg)
peer.msgChan <- m
}
}
}
// sender encodes messages on connection with message object
func sender(peer *Peer, conn net.Conn) {
peer.enc = gob.NewEncoder(conn)
for {
m := <-peer.msgChan
peer.mux.Lock()
fmt.Println("encoding: " + m.M)
err := peer.enc.Encode(m)
if err != nil {
log.Fatal("encode error:", err)
}
peer.mux.Unlock()
}
}
// recieve decodes messages on connection and calls function based on message received
func recieve(peer *Peer, conn net.Conn) {
peer.dec = gob.NewDecoder(conn)
gob.Register(Connection{})
gob.Register(SignedTransaction{})
gob.Register(net.TCPConn{})
gob.Register(Counter{})
gob.Register(PublicKey{})
for {
var m *Message
err := peer.dec.Decode(&m)
if err != nil {
log.Fatal("decode error 1: ", err)
}
if m.M != "complete" {
peer.msgChan <- peer.doActionBasedOnMessage(m)
} else {
fmt.Println("Completed Task...")
}
}
}
// connectToClient connects a peer with given id. Also creates recieve and sender thread
func connectToClient(c *Connection, peer *Peer) {
conn, err := net.Dial("tcp", c.GetID())
if err != nil {
fmt.Println("Unable to connect to: " + c.GetID())
}
go recieve(peer, conn)
go sender(peer, conn)
}
// MakeTransaction returns an initialized Transaction object
func MakeTransaction(peer *Peer) *Transaction {
transaction := new(Transaction)
transaction.ID = peer.counter.CreateID()
transaction.From = peer.ip
randomPeer := peer.clients.GetListOfPeers()[getRandomIntInRange(len(peer.clients.GetListOfPeers()))]
transaction.To = randomPeer.GetID()
transaction.Amount = getRandomIntInRange(10)
return transaction
}
func MakeSignedTransaction(peer *Peer) *SignedTransaction {
signedTrans := new(SignedTransaction)
signedTrans.ID = peer.counter.CreateID()
signedTrans.From = peer.pubKey
randomPeer := peer.clients.GetListOfPeers()[getRandomIntInRange(len(peer.clients.GetListOfPeers()))]
signedTrans.To = randomPeer.GetPublicKey()
signedTrans.Amount = getRandomIntInRange(10)
// our message to hash
signValue := []byte(signedTrans.To + strconv.Itoa(signedTrans.Amount))
m := big.NewInt(0)
m.SetBytes(signValue)
sign := GenerateSign(m, StringToPrivateKey(peer.privKey))
signedTrans.Signature = sign.String()
return signedTrans
}
func getRandomIntInRange(max int) int {
rand.Seed(time.Now().UnixNano())
return rand.Intn(max)
}
// textToFunctionCall takes a string of the function needed to be executed on other peers and creates a Message object which provides the data needed
func (peer *Peer) textToFunctionCall(msg string) *Message {
m := new(Message)
switch {
case "getListOfPeers" == msg:
fmt.Println("Requesting list of peers...")
m.M = "getListOfPeers"
return m
case "presence" == msg:
fmt.Println("Broadcasting presence...")
m.M = "presence"
m.Conn = MakeConnection(peer.ip, peer.pubKey)
return m
case "transaction" == msg:
m.M = "transaction"
m.Trans = MakeSignedTransaction(peer)
peer.ledger.SignedTransaction(m.Trans)
peer.sentID = append(peer.sentID, m.Trans.ID)
return m
case "printPeer" == msg:
m.M = "printPeer"
return m
case "printLedger" == msg:
m.M = "printLedger"
return m
default:
m.M = "Wrongly Formatted message"
fmt.Println(m.M)
return m
}
}
// doActionBasedOnMessage translates a message object into an action on the recieving peer. Then returns a message telling that action is done.
func (peer *Peer) doActionBasedOnMessage(m *Message) *Message {
fmt.Println("got a message")
switch {
case m.M == "getListOfPeers":
fmt.Println("Returning list of connected peers...")
m.M = "peerList"
m.PeerList = peer.clients.GetListOfPeers()
return m
case m.M == "peerList":
peer.clients.ReplaceList(m.PeerList)
peer.clients.AddClient(MakeConnection(peer.ip, peer.pubKey))
peer.clients.SortList()
connectList := peer.clients.FindNextTenPeers(peer.ip)
for _, v := range connectList {
connectToClient(v, peer)
}
m.M = "complete"
return m
case m.M == "presence":
newPresence := m.Conn
currentPeerList := peer.clients.GetListOfPeers()
for i := 0; i < len(currentPeerList); i++ {
if currentPeerList[i].GetID() == newPresence.GetID() {
fmt.Println("Already broadcast this Connection... " + newPresence.GetID())
if !IsKeyInitialised(currentPeerList[i].GetPublicKey()) {
currentPeerList[i].AddPublicKey(m.Conn.GetPublicKey())
peer.clients.ReplaceList(currentPeerList)
}
} else {
fmt.Println("Broadcasting Connection... " + newPresence.GetID())
}
}
m.M = "complete"
return m
case m.M == "printPeer":
m.M = "complete"
return m
case m.M == "printLedger":
fmt.Println(peer.ledger.Accounts)
fmt.Println(peer.counter)
m.M = "complete"
return m
case m.M == "transaction":
found := false
for i := 0; i < len(peer.sentID); i++ {
if m.Trans.ID == peer.sentID[i] {
found = true
fmt.Println("found ID")
}
}
if found {
fmt.Println("found ID in sentIDs")
m.M = "complete"
} else {
fmt.Println("Updating ledger...")
peer.ledger.SignedTransaction(m.Trans)
peer.sentID = append(peer.sentID, m.Trans.ID)
peer.msgChan <- m
}
return m
default:
fmt.Println("Unable to find action: " + m.M)
m.M = "complete"
return m
}
}
package clientlist
import (
"fmt"
"sort"
. "structs/connection"
"sync"
)
// let me live
func init() {
fmt.Println("clientlist package: Initialized")
}
// ClientList holds list of sorted connections
type ClientList struct {
list []*Connection
lock sync.Mutex
}
// MakeClientList returns initialized list
func MakeClientList() *ClientList {
clientList := new(ClientList)
clientList.list = make([]*Connection, 0)
return clientList
}
func (cl *ClientList) ReplaceList(list []*Connection) {
cl.list = list
}
func (cl *ClientList) AddClient(conn *Connection) {
cl.lock.Lock()
cl.list = append(cl.list, conn)
cl.SortList()
cl.lock.Unlock()
}
func (cl *ClientList) SortList() {
sort.Slice(cl.list, func(i, j int) bool {
return cl.list[i].GetID() > cl.list[j].GetID()
})
}
func (cl *ClientList) GetListOfPeers() []*Connection {
return cl.list
}
func (cl *ClientList) FindNextTenPeers(ip string) []*Connection {
if len(cl.list) < 10 {
return make([]*Connection, 0)
}
nextPeers := make([]*Connection, 0)
index := indexOf(ip, cl.list)
for i := index; i < len(cl.list); i++ {
nextPeers = append(nextPeers, cl.list[i])
}
if index+10 > len(cl.list) {
for i := 0; i < 10-(len(cl.list)-index); i++ {
nextPeers = append(nextPeers, cl.list[i])