2017-06-28 33 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)提供了不同的格式,也许有人知道? –