在《Go加密解密之RSA》中,说到了RSA密钥的生成问题,例子中的密钥,是通过openssl生成的。其实,通过那篇文章,可以很容易的反向,用Go生成openssl那样的密钥保存在文件中。该番外篇就是做这事。
首先回顾一下上篇文章加解密流程:
1、读取密钥(可以写死在一个变量中保存,也可以从一个外部文件读取) 2、通过encoding/pem中的Decode函数解析到block类型中 3、通过crypto/x509中相应的Parse方法得到密钥(即crypto/rsa包中的PrivateKey和PublicKey)
根据这个流程,我们可以很容易的反过来生成密钥,保存到文件中。
首先,我们需要生成密钥,在crypto/rsa包中有一个函数:
func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error)
该函数中,random可以直接传crypto/rand中的rand.Reader,而bits是密钥长度。
这样得到了一个PrivateKey类型的指针。我们看一下PrivateKey的定义:
type PrivateKey struct {
PublicKey // public part.
D *big.Int // private exponent
Primes []*big.Int // prime factors of N, has >= 2 elements.
// Precomputed contains precomputed values that speed up private
// operations, if available.
Precomputed PrecomputedValues
}
可见,该类型中嵌入了PublicKey这个类型。而PublicKey类型的定义如下:
type PublicKey struct {
N *big.Int // modulus
E int // public exponent
}
这些是RSA算法规定的。
接下来就是找到x509和pem中对应的方法处理。关键代码如下:
func GenRsaKey(bits int) error {
// 生成私钥文件
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return err
}
derStream := x509.MarshalPKCS1PrivateKey(privateKey)
block := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: derStream,
}
file, err := os.Create("private.pem")
if err != nil {
return err
}
err = pem.Encode(file, block)
if err != nil {
return err
}
// 生成公钥文件
publicKey := &privateKey.PublicKey
derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return err
}
block = &pem.Block{
Type: "PUBLIC KEY",
Bytes: derPkix,
}
file, err = os.Create("public.pem")
if err != nil {
return err
}
err = pem.Encode(file, block)
if err != nil {
return err
}
return nil
}
以上代码将公钥和私钥分别写入public.pem和private.pem中了。 生成这两个文件后,可以用上篇文章中的方法验证一下正确性。
完整示例代码在github上。myblog_article_code rsa/rsa_gen_key.go这个文件
注:rsa中还有另外一个方法生成密钥
func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err error)
有兴趣的可以研究一下。