2017-06-28 63 views
4

使用包https://github.com/golang/crypto/tree/master/ed25519我試圖獲得給定私鑰的公鑰。ed25519.公共結果是不同的

這些數據是從http://www.bittorrent.org/beps/bep_0044.html:試驗2(可變鹽)

問題是,ed25519.Public()贏得噸返回相同的公共密鑰時,我用給定的私鑰饋送它。 golang實現返回PVK的最後32個字節。但在我的測試數據中,這是意想不到的。

這裏https://play.golang.org/p/UJNPCyuGQB

package main 

import (
    "encoding/hex" 
    "golang.org/x/crypto/ed25519" 
    "log" 
) 

func main() { 
    priv := "e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74db7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d" 
    pub := "77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548" 
    sig := "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17ddf9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08" 
    // d := hex.EncodeToString([]byte(priv)) 
    privb, _ := hex.DecodeString(priv) 
    pvk := ed25519.PrivateKey(privb) 
    buffer := []byte("4:salt6:foobar3:seqi1e1:v12:Hello World!") 
    sigb := ed25519.Sign(pvk, buffer) 
    pubb, _ := hex.DecodeString(pub) 
    sigb2, _ := hex.DecodeString(sig) 
    log.Println(ed25519.Verify(pubb, buffer, sigb)) 
    log.Printf("%x\n", pvk.Public()) 
    log.Printf("%x\n", sigb) 
    log.Printf("%x\n", sigb2) 
} 

代碼是如何產生比使用golang的BEP相同的公鑰?

+0

添加更多,我看着https://github.com/orlp/ed25519在https://github.com/orlp/ed25519/bl ob/master/src/keypair.c#L15它生成(我認爲)PBK,它的ge_p3_tobytes更復雜https://github.com/orlp/ed25519/blob/master/src/ge.c#L321 golang版本是https://github.com/golang/crypto/blob/master/ed25519/ed25519.go#L43 –

回答

3

這是由於不同的ed25519私鑰格式。 ed25519密鑰以32字節種子開始。該種子用SHA512散列產生64個字節(也翻轉了幾位)。這些字節的前32個字節用於生成公鑰(也是32個字節),最後32個字節用於生成簽名。

Golang私鑰格式是32字節的種子與32字節的公鑰結合在一起。您使用的Bittorrent文檔中的私鑰是散列的64字節結果(或者可能只有64個隨機字節與散列結果使用相同的方式)。

由於無法反轉散列,因此無法將Bittorrent鍵轉換爲Golang API可接受的格式。

您可以根據現有軟件包生成一個Golang庫版本。

以下代碼取決於內部軟件包golang.org/x/crypto/ed25519/internal/edwards25519,因此如果您想使用它,您需要將該軟件包複製出來以便它可用於您的代碼。它也非常「粗糙和準備好」,我基本上只是複製了現有代碼所需的代碼塊,以使其工作。

請注意,公鑰和簽名格式是相同的,所以只要您不共享私鑰,您就不需要使用此代碼來獲得工作實現。如果你想檢查測試向量,你將只需要它。

首先生成一個私人的公鑰:

// Generate the public key corresponding to the already hashed private 
// key. 
// 
// This code is mostly copied from GenerateKey in the 
// golang.org/x/crypto/ed25519 package, from after the SHA512 
// calculation of the seed. 
func getPublicKey(privateKey []byte) []byte { 
    var A edwards25519.ExtendedGroupElement 
    var hBytes [32]byte 
    copy(hBytes[:], privateKey) 
    edwards25519.GeScalarMultBase(&A, &hBytes) 
    var publicKeyBytes [32]byte 
    A.ToBytes(&publicKeyBytes) 

    return publicKeyBytes[:] 
} 

下生成簽名:

// Calculate the signature from the (pre hashed) private key, public key 
// and message. 
// 
// This code is mostly copied from the Sign function from 
// golang.org/x/crypto/ed25519, from after the SHA512 calculation of the 
// seed. 
func sign(privateKey, publicKey, message []byte) []byte { 

    var privateKeyA [32]byte 
    copy(privateKeyA[:], privateKey) // we need this in an array later 
    var messageDigest, hramDigest [64]byte 

    h := sha512.New() 
    h.Write(privateKey[32:]) 
    h.Write(message) 
    h.Sum(messageDigest[:0]) 

    var messageDigestReduced [32]byte 
    edwards25519.ScReduce(&messageDigestReduced, &messageDigest) 
    var R edwards25519.ExtendedGroupElement 
    edwards25519.GeScalarMultBase(&R, &messageDigestReduced) 

    var encodedR [32]byte 
    R.ToBytes(&encodedR) 

    h.Reset() 
    h.Write(encodedR[:]) 
    h.Write(publicKey) 
    h.Write(message) 
    h.Sum(hramDigest[:0]) 
    var hramDigestReduced [32]byte 
    edwards25519.ScReduce(&hramDigestReduced, &hramDigest) 

    var s [32]byte 
    edwards25519.ScMulAdd(&s, &hramDigestReduced, &privateKeyA, &messageDigestReduced) 

    signature := make([]byte, 64) 
    copy(signature[:], encodedR[:]) 
    copy(signature[32:], s[:]) 

    return signature 
} 

最後,我們可以使用這兩個函數來演示測試向量:

privateKeyHex := "e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74db7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d" 

expectedPublicKey := "77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548" 
expectedSig := "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17ddf9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08" 

privateKey, _ := hex.DecodeString(privateKeyHex) 
publicKey := getPublicKey(privateKey) 

fmt.Printf("Calculated key: %x\n", publicKey) 
fmt.Printf("Expected key: %s\n", expectedPublicKey) 
keyMatches := expectedPublicKey == hex.EncodeToString(publicKey) 
fmt.Printf("Public key matches expected: %v\n", keyMatches) 

buffer := []byte("4:salt6:foobar3:seqi1e1:v12:Hello World!") 
calculatedSig := sign(privateKey, publicKey, buffer) 

fmt.Printf("Calculated sig: %x\n", calculatedSig) 
fmt.Printf("Expected sig: %s\n", expectedSig) 
sigMatches := expectedSig == hex.EncodeToString(calculatedSig) 
fmt.Printf("Signature matches expected: %v\n", sigMatches) 
+0

非常感謝,我將安排複製粘貼代碼,您的解決方案清晰直觀,這真的很感激。我不明白爲什麼(golang | bitorrent)提供了不同的格式,也許有人知道? –