正如问题所述,谁能告诉我如何将base64
编码的公钥转换为crypto.PublicKey
或ecdsa.PublicKey
?我在网上找不到这样的例子.任何有关这方面的文件或片段都将不胜感激.
正如问题所述,谁能告诉我如何将base64
编码的公钥转换为crypto.PublicKey
或ecdsa.PublicKey
?我在网上找不到这样的例子.任何有关这方面的文件或片段都将不胜感激.
由于特别提到了ECDSA
,ParsePKIXPublicKey
应该是要使用的功能,如对问题的 comments 中所指出的.ParsePKCS1PublicKey
将用于较旧格式的RSA公钥(可由报头-----BEGIN RSA PUBLIC KEY-----
识别).顺便说一句,ParsePKIXPublicKey
还可以使用编码的密钥类型对象标识符来解析较新格式的RSA公钥(可由头部-----BEGIN PUBLIC KEY-----
识别,请注意缺失的RSA
).除了支持ECDSA和RSA外,还支持DSA和ED25519.
下面是一个完整的、自包含的示例,展示了如何使用OpenSSL创建ECDSA
和RSA
格式的样例密钥,并使用go读取公钥.
Generation of an RSA public key个
openssl genrsa -out rsaPrivateKey.pem 1024
openssl rsa -in rsaPrivateKey.pem -pubout > rsaPublicKey.pem
Generation of an ECDSA public key个
openssl ecparam -name prime256v1 -genkey -out ecdsaPrivateKey.pem
openssl ec -in ecdsaPrivateKey.pem -pubout -out ecdsaPublicKey.pem
Test个
测试可能如下所示:
package main
import (
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"log"
"os"
)
func main() {
rsaPublicKey, err := readPublicKey("rsaPublicKey.pem")
if err != nil {
log.Fatal(err)
}
err = printPublicKey(rsaPublicKey)
if err != nil {
log.Fatal(err)
}
ecdsaPublicKey, err := readPublicKey("ecdsaPublicKey.pem")
if err != nil {
log.Fatal(err)
}
err = printPublicKey(ecdsaPublicKey)
if err != nil {
log.Fatal(err)
}
}
这里使用两个函数readPublicKey
和printPublicKey
,它们分别用公钥读取和打印PEM文件.
如文档所示,读取RSA或ECDSA密钥的代码应该是相同的:
func readPublicKey(filename string) (pub any, err error) {
publicKey, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, errors.New("decoding public key PEM failed")
}
pub, err = x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
return pub, nil
}
最后,可以通过类型切换轻松地访问数据,如注释中引用的documentation所示.
func printPublicKey(pub any) error {
switch pub := pub.(type) {
case *rsa.PublicKey:
fmt.Println("pub is of type RSA:", pub)
case *dsa.PublicKey:
fmt.Println("pub is of type DSA:", pub)
case *ecdsa.PublicKey:
fmt.Println("pub is of type ECDSA:", pub)
case ed25519.PublicKey:
fmt.Println("pub is of type Ed25519:", pub)
default:
return errors.New("unknown type of public key")
}
return nil
}
Differentiation of the key types个
使用很酷的在线ASN.1脚本解码器https://lapo.it/asn1js/,用户可以输入生成的ECDSA pem.
这将在第一对象识别符ecPublicKey (ANSI X9.62 public key type)
中显示.
而对于RSA
人来说,这将是rsaEncryption (PKCS #1)
人.
secp256k1个
并不是所有的曲线类型都受GO的加密包支持,特别是secp256k1
.例如,您可以通过上述在线工具中的第二个对象标识符来标识曲线类型.
try 将上面的代码与其一起使用将产生以下错误消息:x509: unsupported elliptic curve
.
在这种情况下,您可以例如使用包github.com/decred/dcrd/secp256k1
.
为了获得secp256k1.ParsePubKey
的适当输入形式,例如可以使用未压缩的密钥格式(0x04+x+y),该格式又可以通过Unmarshal
从asn1
包中提取(也参见ParsePKIXPublicKey
的内部 struct ).
Self-contained example个
Generation of an ECDSA public key with secp256k1 curve type个
openssl ecparam -name secp256k1 -genkey -out ecdsaSecp256k1PrivateKey.pem
openssl ec -in ecdsaSecp256k1PrivateKey.pem -pubout -out ecdsaSecp256k1PublicKey.pem
用于测试的自含式示例可能如下所示:
package main
import (
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
"github.com/decred/dcrd/dcrec/secp256k1"
"log"
"os"
)
type publicKeyInfo struct {
Raw asn1.RawContent
算法rithm pkix.算法rithmIdentifier
PublicKey asn1.BitString
}
func readSecp256k1PublicKey(filename string) (*secp256k1.PublicKey, error) {
publicKey, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, errors.New("decoding public key PEM failed")
}
var pki publicKeyInfo
if _, err := asn1.Unmarshal(block.Bytes, &pki); err != nil {
return nil, err
}
pub, err := secp256k1.ParsePubKey(pki.PublicKey.Bytes)
if err != nil {
return nil, err
}
return pub, nil
}
func main() {
pub, err := readSecp256k1PublicKey("ecdsaSecp256k1PublicKey.pem")
if err != nil {
log.Fatal(err)
}
fmt.Printf("public key %T", pub)
}
调试控制台上的输出将为:
public key *secp256k1.PublicKey