在《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)
有兴趣的可以研究一下。