如何在go中通过tcp连接发送rsa.PublicKey?

时间:2016-07-27 11:57:02

标签: encryption go tcp rsa

我一直在尝试制作一个简单的RSA加密聊天应用。我遇到的问题是必须通过tcp连接发送rsa公钥,因为net.Conn,据我所知只接受type []字节。

问题代码

 conn.Write([]byte(public_key))

这是产生我的复杂功能的代码。此代码位于函数handleRequest下。我知道conn.Write只能接受type []字节,但是它周围的任何地方都有。如何将public_key发送给我的客户?为了以防万一,我已经包含了所有服务器代码。此外,如果您希望获得所有服务器/客户端代码注释,我将创建一个github链接。三江源

仅限于案例服务器代码

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)
}

3 个答案:

答案 0 :(得分:2)

您需要将rsa.PublicKey序列化为[]byte。有多种方法可以做到这一点,但我可能会选择JSON。

结构看起来像这样,并且在其中的内容是a)Public和b)使用JSON进行序列化。

type PublicKey struct {
    N *big.Int // modulus
    E int      // public exponent
}

答案 1 :(得分:2)

如果您要将Go程序中的数据发送到另一个Go程序(如您在示例中所示),则可以使用程序包encoding/gob https://golang.org/pkg/encoding/gob/来序列化(Encode)将对象转换为字节切片并将接收到的字节反序列化(Decode)回Go对象。这是一个例子(也是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)
}

输出类似于:

OK -rsa.PublicKey{N:10881677056019504919833663670523712169444878787643568603135265932739968735275981472697621424678110007129031867528249518560683510901399549383480944574041391, E:65537}

发送gob blob可以比JSON编码更快更高效,特别是如果你做了很多,但你需要确定它是否是一个重要的因素,你喜欢文本(JSON)还是二进制格式(gob或protobufs)用于数据传输。

答案 2 :(得分:0)

我有这个问题,并且有一个简单的答案,序列化白方元帅

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)