私はすぐに言わなければなりません:私はコンパイルされた言語で書きませんでした。
アプリケーションは何をしますか
[k]-クライアント
[c]-サーバー
1.確立されたTCP接続を介して、[k]は公開キーrsaを転送します。
2.受け入れられた公開鍵を使用して、[c]メッセージを暗号化して送信します[to]
3. [k]はメッセージを復号化して表示します。
コンソールでは次のように表示されます。
サーバー
package main
必要なパッケージをインポートします
import( // / . "fmt" // Unix networks sockets, including TCP/IP, UDP . // TCP . "net" // "os" // / "bufio" // "crypto/rsa" // "crypto/rand" // sha1 "crypto/sha1" // "strconv" // "big" )
パッケージへのアクセスは、ドットを介した名前によって行われます。
例:
fmt
Println()
、
os
。
Exit()
など
必要なパッケージ名がわからない場合は、コードの一番上の行でパッケージソースを確認できます。
たとえば、 crypto / rsaの場合、 6行目のrsa.go
goinstallコマンドを使用すると、他の開発者からパッケージをインストールできます。
この場合、「bitbucket.org/user/project」、「github.com/user/project」、または「project.googlecode.com/hg」のようなものをインポートします
必要な定数を宣言する
const( // tcp tcpProtocol = "tcp4" // rsa keySize = 1024 // readWriterSize = keySize/8 )
接続「c」とこの接続「pubK」へのキーを一緒に保持するには、remoteConnデータ型を構造体として宣言します。
type remoteConn struct { c *net.TCPConn pubK *rsa.PublicKey }
変数の型の前のアスタリスク「*」は、変数が宣言された型のデータへの参照であることを意味します
net.TCPConnは、TCP接続情報の構造を含むデータ型です。
rsa.PublicKey-データ型。 送信メッセージの暗号化に必要です。
慣れるために、次のように表示されるエラーを処理します。
この関数は、タイプがos.Errorである単一の
err
値を取ります。
この場合、 osパッケージのエラータイプ(
os.Error
)を使用しています。
func checkErr(err os.Error){ if err != nil { // fmt.Println(err) // os.Exit(1) } }
タイプnet.TCPAddrの構造への参照となるグローバル変数
listenAddr
を宣言します
var listenAddr = &net.TCPAddr{IP: net.IPv4(192,168,0,4), Port: 0}
net.TCPAddrの前のアンパサンド "&"は、このタイプへの参照を返します。
この場合の「ポート:0」は、すべての空きポートを意味します。
次の関数は、接続と公開鍵を組み合わせて、この接続を
remoteConn
構造に暗号化します。
そして、値ではなく、
remoteConn
へのリンクを返します。
func getRemoteConn(c *net.TCPConn) *remoteConn{ return &remoteConn{c: c, pubK: waitPubKey(bufio.NewReader())} }
bufio.NewReader()
-接続「c」からバイトバッファーを作成します。 戻り値の型
*bufio.Reader
(
*bufio.Reader
へのリンク)
waitPubKey()
-「クライアント」から特定のシーケンスで
PublicKey
が送信されることを期待する
この関数は、バッファー(
*bufio.Reader
)への参照を受け取ります。このバッファーには、接続 "c"からのすべてのバイトが含まれます
// rsa.PublicKey func waitPubKey(buf *bufio.Reader) (*rsa.PublicKey) { // line, _, err := buf.ReadLine(); checkErr(err) // line - []byte ( ) // <code><b>line</b></code> if string(line) == "CONNECT" { // , line, _, err := buf.ReadLine(); checkErr(err) // PublicKey.N // rsa.PublicKey pubKey := rsa.PublicKey{N: big.NewInt(0)} // pubKey.N == 0 // pubKey.N big.Int http://golang.org/pkg/big/#Int // pubKey.N big.Int pubKey.N.SetString(string(line), 10) // SetString() 2 : // string(line) - // 10 - // (2 , 8 , 10 , 16 ...) // pubKey.E line, _, err = buf.ReadLine(); checkErr(err) // strconv string int pubKey.E, err = strconv.Atoi(string(line)); checkErr(err) // rsa.PublicKey return &pubKey } else { // . : // fmt.Println("Error: unkown command ", string(line)) os.Exit(1) // } return nil }
次の関数は、
remoteConn
型の変数を参照するためのメソッドです
一連のアクションを実行して、メッセージを暗号化して送信します。
func (rConn *remoteConn) sendCommand(comm string) { // eComm, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, rConn.pubK, []byte(comm), nil) // sha1.New() hash.Hash // sha512.New() sha256.New() ... // rand.Reader io.Reader // /dev/unrandom Linux CryptGenRandom API Windows // rConn.pubK - func waitPubKey // []byte(comm) - comm ([]byte) checkErr(err) // // rConn.c.Write(eComm) // rConn.c ? - net.TCPConn Write() // http://golang.org/pkg/net/#TCPConn.Write }
以下は、以前に宣言された関数で動作し、最終的に「クライアント」サーバー名とグリーティングを異なる言語で送信する関数です。
func listen() { // l, err := net.ListenTCP(tcpProtocol, listenAddr); checkErr(err) // fmt.Println("Listen port: ", l.Addr().(*net.TCPAddr).Port) // l == *net.TCPListener == // .Addr() http://golang.org/pkg/net/#TCPListener.Addr == *net.TCPListener "" // net.Addr http://golang.org/pkg/net/#Addr TCPAddr - *net.TCPAddr // Network() String() c, err := l.AcceptTCP(); checkErr(err) // // AcceptTCP() - *net.TCPListener http://golang.org/pkg/net/#TCPListener.AcceptTCP // fmt.Println("Connect from:", c.RemoteAddr()) // 3 fmt.Print[f|ln]() // 1. c.RemoteAddr() // 2. c.RemoteAddr().(*net.TCPAddr) // 3. c.RemoteAddr().String() // : fmt.Println(), fmt.Print(), fmt.Printf() String() // // rConn := getRemoteConn() // rConn.sendCommand("Go Language Server v0.1 for learning") rConn.sendCommand("!") rConn.sendCommand("і!") rConn.sendCommand("і!") rConn.sendCommand("Hello!") rConn.sendCommand("Salut!") rConn.sendCommand("ハイ!") rConn.sendCommand("您好!") rConn.sendCommand("안녕!") rConn.sendCommand("Hej!") }
これでサーバーのレビューが完了しました。
func main() { listen() }
お客様
package main import( "fmt" "net" "os" "bufio" "crypto/rsa" "crypto/rand" "crypto/sha1" "strconv" ) const( tcpProtocol = "tcp4" keySize = 1024 readWriterSize = keySize/8 ) func checkErr(err os.Error){ if err != nil { fmt.Println(err) os.Exit(1) } } var connectAddr = &net.TCPAddr{IP: net.IPv4(192,168,0,2), Port: 0} // func connectTo() *net.TCPConn{ // "Enter port:" fmt.Print("Enter port:") // "%d" fmt.Scanf("%d", &connectAddr.Port) // Scanf fmt.Println("Connect to", connectAddr) // c ,err := net.DialTCP(tcpProtocol, nil, connectAddr); checkErr(err) return c } // PublicKey func sendKey(c *net.TCPConn, k *rsa.PrivateKey) { // PublicKey c.Write([]byte("CONNECT\n")) // N *big.Int c.Write([]byte(k.PublicKey.N.String() + "\n")) // String() *big.Int string // E int c.Write([]byte(strconv.Itoa(k.PublicKey.E) + "\n")) // strconv.Itoa() int string // []byte() "" } // // func getBytes(buf *bufio.Reader, n int) []byte { // n bytes, err:= buf.Peek(n); checkErr(err) // n skipBytes(buf, n) return bytes } // , func skipBytes(buf *bufio.Reader, skipCount int){ for i:=0; i<skipCount; i++ { buf.ReadByte() } } func main() { // c := connectTo() // "c" buf := bufio.NewReader() // k, err := rsa.GenerateKey(rand.Reader, keySize); checkErr(err) // sendKey(c, k) // for { // cryptMsg := getBytes(buf, readWriterSize) // msg, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, k, cryptMsg, nil) // checkErr(err) // fmt.Println(string(msg)) } }
コメントが1つもないソースは、次の場所にあります。
code.google.com/p/learning-go-language/source/browse