Reputation:
I've been trying to make a simple RSA encrypted chat app. The problem I've come across is having to send the rsa Public key over the tcp connection, as net.Conn , to my knowledge only accepts the type []byte.
Problem code
conn.Write([]byte(public_key))
This is the code that is producing my complications.This code is under the function handleRequest. I understand that conn.Write can only accept the type []byte, but is there anywhere around this. How can I deliver the public_key to my client? I have included all my server code just in case. Also if you wish to obtain all server/client code comment so and I will create a github link. Thankyou
Just in case-server code
main.go
package main
import (
"fmt"
"github.com/jonfk/golang-chat/tcp/common"
"io"
"log"
"net"
"os"
)
const (
CONN_HOST = "0.0.0.0"
CONN_PORT = "3333"
CONN_TYPE = "tcp"
)
var (
connections []net.Conn
)
func main() {
setUP(3072)
l, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
// Close the listener when the application closes.
defer l.Close()
fmt.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
for {
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
// Save connection
connections = append(connections, conn)
// Handle connections in a new goroutine.
go handleRequest(conn)
}
}
// Handles incoming requests.
func handleRequest(conn net.Conn) {
//I use the common library but this is how it would look like using go's net library.
conn.Write([]byte(public_key))
//Using the import common library this is what the command would be
//common.WriteMsg(conn,string(public_key))
for {
msg, err := common.ReadMsg(conn)
if err != nil {
if err == io.EOF {
// Close the connection when you're done with it.
removeConn(conn)
conn.Close()
return
}
log.Println(err)
return
}
broadcast(conn, msg)
}
}
func removeConn(conn net.Conn) {
var i int
for i = range connections {
if connections[i] == conn {
break
}
}
connections = append(connections[:i], connections[i+1:]...)
}
func broadcast(conn net.Conn, msg string) {
for i := range connections {
if connections[i] != conn {
err := common.WriteMsg(connections[i], msg)
if err != nil {
log.Println(err)
}
}
}
}
encryption.go
package main
import (
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"log"
)
var private_key *rsa.PrivateKey
var public_key *rsa.PublicKey
var encrypted,decrypted []byte
func setUP(size int) bool{
var err error
if private_key,err = rsa.GenerateKey(rand.Reader,size); err != nil {
log.Fatal(err)
return false
}
private_key.Precompute()
if err= private_key.Validate();err != nil {
log.Fatal(err)
return false
}
public_key = &private_key.PublicKey
return true
}
func encrypt(msg string) string {
var err error
var label []byte
md5h := md5.New()
if encrypted,err = rsa.EncryptOAEP(md5h,rand.Reader,public_key,[]byte(msg),label); err != nil {
log.Fatal(err)
}
return string(encrypted)
}
func decrypt(msg string) string {
var err error
var label []byte
md5h := md5.New()
if decrypted,err = rsa.DecryptOAEP(md5h,rand.Reader,private_key,[]byte(msg),label); err != nil {
log.Fatal(err)
}
return string(decrypted)
}
Upvotes: 2
Views: 2449
Reputation: 423
i have this question, and there was simple answer, serialising whit marshal
private_key, err = rsa.GenerateKey(rand.Reader, 2048)
public_key = &private_key.PublicKey
pubInJason,err:=json.Marshal(public_key)
fmt.Println("public key in jason: ",string(pubInJason))
pub2:=&rsa.PublicKey{}
err=json.Unmarshal(pubInJason,pub2)
fmt.Println("public key from jason: ",pub2)
Upvotes: 1
Reputation: 1491
If you are sending data from a Go program to another Go one (as you show in your examples), you can use the package encoding/gob
https://golang.org/pkg/encoding/gob/ to serialize (Encode
) an object into a slice of bytes and deserialize (Decode
) the received bytes back into the Go object. Here's an example (also https://play.golang.org/p/3bxbqGtqQY):
package main
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"encoding/gob"
"fmt"
"log"
)
func main() {
priv, _ := rsa.GenerateKey(rand.Reader, 512) // skipped error checking for brevity
pub := priv.PublicKey
// adapted from https://golang.org/pkg/encoding/gob/#example__basic:
// Initialize the encoder and decoder. Normally enc and dec would be
// bound to network connections and the encoder and decoder would
// run in different processes.
var network bytes.Buffer // Stand-in for a network connection
enc := gob.NewEncoder(&network) // Will write to network.
dec := gob.NewDecoder(&network) // Will read from network.
enc.Encode(&pub)
var pub2 = rsa.PublicKey{}
dec.Decode(&pub2)
if pub.N.Cmp(pub2.N) != 0 || pub.E != pub2.E {
log.Fatal("Public Keys at source and destination not equal")
}
fmt.Printf("OK - %#v\n", pub2)
}
Output similar to:
OK -rsa.PublicKey{N:10881677056019504919833663670523712169444878787643568603135265932739968735275981472697621424678110007129031867528249518560683510901399549383480944574041391, E:65537}
Sending gob blobs can be faster and more efficient then doing JSON encoding especially if you are doing a lot of it, but you need to decide whether it is a significant factor for you and whether you prefer text (JSON) or binary format (gob or protobufs) for data transport.
Upvotes: 2
Reputation: 54081
You need to serialise the rsa.PublicKey
to a []byte
. There are multiple ways of doing this, but I'd probably go with JSON.
The struct looks like this, and everthing within it is a) Public and b) Serializable with JSON.
type PublicKey struct {
N *big.Int // modulus
E int // public exponent
}
Upvotes: 2