生成 RSA 密匙对有许多中方式,而在操作系统中使用最多的就是大名鼎鼎的 openssl。另外也可以使用 ssh-keygen,不过 ssh-kengen 本质上也是使用 openssl 类库。所以下面分别来介绍下 openssl 和 Java 生成 RSA 密匙对的方式:

openssl 生成 RSA 密匙对

私钥生成

打开 Terminal 终端(Windows 用户可以使用 Git 客户端),RSA 私钥生成命令格式如下:

  1. openssl genrsa -out [rsa_private_key.pem] [rsa_length]

1)rsa_private_key 就是你想要指定生成的私钥文件名称。
2)rsa_length 指定的是密匙长度,越长表示加密型越强(当前 1024 长度已经被证实可被破解)

生成私钥命令示例:

  1. $ openssl genrsa -out id_rsa.pem 2048
  2. Generating RSA private key, 2048 bit long modulus (2 primes)
  3. ....................................................+++++
  4. .....................................................+++++
  5. e is 65537 (0x010001)

然后就会看到当前目录多出了一个 id_rsa.pem 私钥文件(文件名就是你所指定的文件名称):

  1. $ ls
  2. id_rsa.pem

生成的私钥文件内容如下:

  1. -----BEGIN RSA PRIVATE KEY-----
  2. MIIEpAIBAAKCAQEA0JkyQIXHWKfko2GgsmQXZ27m19pL6UzSCk1ZpxYB6jddi7zl
  3. 0gh3jbQzvfkfl2cmgVUPuVEE68Ol6lV8qSmN2dCTIdapEFJkNFgJTY7vClAnyVwM
  4. tsITSvfQAUNj6xZerw7KzHTra63DKc90qDSs/NkWHTR2yinTapMPpmTMGgM1wwqB
  5. XlCTJdahyk8DKV9jFxGWGy9ZOD9Vg2FbFhxHeBhX7qXeYfqTZQfc/f7ESCpz/L4s
  6. PMW0uKAVbzWdoANzX2Y8LLQhkZ3rp7PJy8L366iFCIHbrwExuTxhX5mcdpvSTrzi
  7. sM08wcwaUb1VXe08lqZBjgSmyup/gfs0jiLMCwIDAQABAoIBACx3G4Epgy7gyxoQ
  8. q4KbV2nS+B43CEt49qT/jAbT6CCXILey0oKND38DVKxAOH27nTegfDOSk6v2Dp3/
  9. Dw24L+aoUVS7P1qdVYLa6VDBES9vmquPlZ43jIlEffBm/xuTryc9zfj7S1uutJVr
  10. BYD9iYp0dARRtKivdcOYCZP8lI1Ok1esXnJPcBlb5B5wSKGm+ANpeNkGksUjNRMq
  11. esmAzwSqw0Ub0tHUok0HrVWdYE8FYpK1SVhzK5Py7OfrpIyiD4SEXYbDa846Qk6B
  12. HO2MxaeBhGtlRG/4Zql2RH9KCQhmdIGr3d5TYY9uJKegqkJojc/eRYJxxPG4tcD+
  13. XTqMUaECgYEA6KcyBWDc3yMiuTKP/AIH/Fw9Z2j4pd+e9Kt/qzqXCw58zh3/QOJZ
  14. v53XnDVkmiIVIWunMzZlpS5VCKCcxb/VaUVXqKUpHOqKYI6NpHJSfLqMgp1fXcj9
  15. D3dR00EbZo5x1Jd79WMGI7dLRZF7w/gMIMSYOvDEZ13ltyv9V5QTVtMCgYEA5YgK
  16. p+vAjPa36bkNu4JjIqnxUHpxauT/Co/7hqnLOlVFVrozdlzbgF5xe7rPDUxHNeef
  17. dMvyHDy7jLyOIgN2a53jlcf00PIrwlo2nLTGznSY4JLn2ttV7Mmmkfm5LKnCLogB
  18. Rj/wExa/8NQ+KV2eQU5Cjn/MMEMY8xyh3iIEYukCgYEAmEASNALXiA7uQlQcdca+
  19. gx+571p6ndJhq6wvuFZ3Uf0BH8HxsPxvzz30Q32NgHCdc2mH2bPXgOl5LFQvRBnu
  20. Bx4h53NuHEZAmD+x4dQOtyE9opxqNG27bcuf+Ke6zrqZM46OyF8tPWJOGBDE9dH1
  21. 3dvJ44h8f0irc9uNxypYHZECgYEArlo2bfOgofNPJJTTH5odn9kjWxSHTsGAEg/o
  22. 6hPUMg1PzF9IdCJ5Afu7jFcMrHdCqGm3MEszL8vaUz9vX9rtezXGCKKJDqbGIq3Q
  23. Shzv3yemcQBmalKt5F4Qz1W4GXsh66KYBTrQLE/doRw308gvTEAcQo5FFmwBabpY
  24. IpoIZvECgYARtMCDbDlRrjkkJWOA44fBZB+C72xv1Lm3N6MxhGNbEfoskZdTEVWA
  25. NBB0ZjqZqY7G+ER5arNYhkJ6Qvsw/xuys/vkBI2anuV2zr6mLlo37iIsMFsRINTc
  26. zBSxPHZZv007zQH/kKAKRzXxdduPRrQJo47OQBd5IUF092aOJOJRXg==
  27. -----END RSA PRIVATE KEY-----

公钥生成

接着生成公钥,命令如下:

  1. openssl rsa -in [rsa_private_key.pem] -out [rsa_public_key.pem] -pubout

1)rsa_private_key 就是你之前生成的私钥的文件名称(公钥生成规则是通过计算私钥数值,所以一定要是你之前生成的私钥文件)。
2)rsa_public_key 指定要生成的公钥的文件名称。

生成公钥命令示例:

  1. openssl rsa -in id_rsa.pem -out id_rsa_pub.pem -pubout

之后同样的就会看到公钥文件 id_rsa_pub:

  1. $ ls
  2. id_rsa.pem id_rsa_pub.pem

生成的公钥文件内容如下:

  1. -----BEGIN PUBLIC KEY-----
  2. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0JkyQIXHWKfko2GgsmQX
  3. Z27m19pL6UzSCk1ZpxYB6jddi7zl0gh3jbQzvfkfl2cmgVUPuVEE68Ol6lV8qSmN
  4. 2dCTIdapEFJkNFgJTY7vClAnyVwMtsITSvfQAUNj6xZerw7KzHTra63DKc90qDSs
  5. /NkWHTR2yinTapMPpmTMGgM1wwqBXlCTJdahyk8DKV9jFxGWGy9ZOD9Vg2FbFhxH
  6. eBhX7qXeYfqTZQfc/f7ESCpz/L4sPMW0uKAVbzWdoANzX2Y8LLQhkZ3rp7PJy8L3
  7. 66iFCIHbrwExuTxhX5mcdpvSTrzisM08wcwaUb1VXe08lqZBjgSmyup/gfs0jiLM
  8. CwIDAQAB
  9. -----END PUBLIC KEY-----

私钥转换为 PKCS8 格式

这一步非必须!只是主要用于程序解析方便!!!!

PKCS全称是公钥密码标准(The Public-Key Cryptography Standards (PKCS)),是大多数语言都遵循的标准。

比如当使用 Java 开发语言时解析私钥就需要使用 java.security.spec.PKCS8EncodedKeySpec 类,而该类就需要私钥是 PKCS8 格式。

所以这步为可选操作,根据实际需要~

命令如下:

  1. openssl pkcs8 -topk8 -inform PEM -in [rsa_private_key.pem] -outform PEM -nocrypt > [rsa_private_key_pkcs8.pem]

1)rsa_private_key 是你之前生成的私钥文件名。
2)rsa_private_key_pkcs8 转换为 pkcs8 格式的私钥文件名。

转换PKCS8格式命令示例:

  1. openssl pkcs8 -topk8 -inform PEM -in id_rsa.pem -outform PEM -nocrypt > id_rsa_pkcs8.pem

现在除了私钥公钥之外还会有一个私钥对应的 PKCS8 内容格式文件:

  1. $ ls
  2. id_rsa.pem id_rsa_pkcs8.pem id_rsa_pub.pem

生成的私钥PKCS8格式文件内容如下:

  1. -----BEGIN PRIVATE KEY-----
  2. MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQmTJAhcdYp+Sj
  3. YaCyZBdnbubX2kvpTNIKTVmnFgHqN12LvOXSCHeNtDO9+R+XZyaBVQ+5UQTrw6Xq
  4. VXypKY3Z0JMh1qkQUmQ0WAlNju8KUCfJXAy2whNK99ABQ2PrFl6vDsrMdOtrrcMp
  5. z3SoNKz82RYdNHbKKdNqkw+mZMwaAzXDCoFeUJMl1qHKTwMpX2MXEZYbL1k4P1WD
  6. YVsWHEd4GFfupd5h+pNlB9z9/sRIKnP8viw8xbS4oBVvNZ2gA3NfZjwstCGRneun
  7. s8nLwvfrqIUIgduvATG5PGFfmZx2m9JOvOKwzTzBzBpRvVVd7TyWpkGOBKbK6n+B
  8. +zSOIswLAgMBAAECggEALHcbgSmDLuDLGhCrgptXadL4HjcIS3j2pP+MBtPoIJcg
  9. t7LSgo0PfwNUrEA4fbudN6B8M5KTq/YOnf8PDbgv5qhRVLs/Wp1VgtrpUMERL2+a
  10. q4+VnjeMiUR98Gb/G5OvJz3N+PtLW660lWsFgP2JinR0BFG0qK91w5gJk/yUjU6T
  11. V6xeck9wGVvkHnBIoab4A2l42QaSxSM1Eyp6yYDPBKrDRRvS0dSiTQetVZ1gTwVi
  12. krVJWHMrk/Ls5+ukjKIPhIRdhsNrzjpCToEc7YzFp4GEa2VEb/hmqXZEf0oJCGZ0
  13. gavd3lNhj24kp6CqQmiNz95FgnHE8bi1wP5dOoxRoQKBgQDopzIFYNzfIyK5Mo/8
  14. Agf8XD1naPil3570q3+rOpcLDnzOHf9A4lm/ndecNWSaIhUha6czNmWlLlUIoJzF
  15. v9VpRVeopSkc6opgjo2kclJ8uoyCnV9dyP0Pd1HTQRtmjnHUl3v1YwYjt0tFkXvD
  16. +AwgxJg68MRnXeW3K/1XlBNW0wKBgQDliAqn68CM9rfpuQ27gmMiqfFQenFq5P8K
  17. j/uGqcs6VUVWujN2XNuAXnF7us8NTEc15590y/IcPLuMvI4iA3ZrneOVx/TQ8ivC
  18. WjactMbOdJjgkufa21XsyaaR+bksqcIuiAFGP/ATFr/w1D4pXZ5BTkKOf8wwQxjz
  19. HKHeIgRi6QKBgQCYQBI0AteIDu5CVBx1xr6DH7nvWnqd0mGrrC+4VndR/QEfwfGw
  20. /G/PPfRDfY2AcJ1zaYfZs9eA6XksVC9EGe4HHiHnc24cRkCYP7Hh1A63IT2inGo0
  21. bbtty5/4p7rOupkzjo7IXy09Yk4YEMT10fXd28njiHx/SKtz243HKlgdkQKBgQCu
  22. WjZt86Ch808klNMfmh2f2SNbFIdOwYASD+jqE9QyDU/MX0h0InkB+7uMVwysd0Ko
  23. abcwSzMvy9pTP29f2u17NcYIookOpsYirdBKHO/fJ6ZxAGZqUq3kXhDPVbgZeyHr
  24. opgFOtAsT92hHDfTyC9MQBxCjkUWbAFpulgimghm8QKBgBG0wINsOVGuOSQlY4Dj
  25. h8FkH4LvbG/Uubc3ozGEY1sR+iyRl1MRVYA0EHRmOpmpjsb4RHlqs1iGQnpC+zD/
  26. G7Kz++QEjZqe5XbOvqYuWjfuIiwwWxEg1NzMFLE8dlm/TTvNAf+QoApHNfF1249G
  27. tAmjjs5AF3khQXT3Zo4k4lFe
  28. -----END PRIVATE KEY-----

文件内容调整

正常来说到此就结束了,但是如果是给程序(如 Java)使用的话还不行。我们还需要调整密钥内容,将生成的密钥文件中头尾两段去掉并删除文件中的回车换行符。

注意:程序(如Java)主要使用的是 PKCS8 私钥文件和公钥文件,因为 PKCS8私钥文件本质上就是私钥文件内容,只是格式不同而已。所以我们调整私钥PKCS8文件内容和公钥内容即可。

即删除 PKCS8 私钥文件(id_rsa_pkcs8.pem)首尾行:

  1. -----BEGIN PRIVATE KEY-----
  2. -----END PRIVATE KEY-----

删除公钥文件(id_rsa_pub.pem)首尾行:

  1. -----BEGIN PUBLIC KEY-----
  2. -----END PUBLIC KEY-----

最后再去掉两个文件中的换行符。最终结果如下所示:

PrivateKey:

  1. MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQmTJAhcdYp+SjYaCyZBdnbubX2kvpTNIKTVmnFgHqN12LvOXSCHeNtDO9+R+XZyaBVQ+5UQTrw6XqVXypKY3Z0JMh1qkQUmQ0WAlNju8KUCfJXAy2whNK99ABQ2PrFl6vDsrMdOtrrcMpz3SoNKz82RYdNHbKKdNqkw+mZMwaAzXDCoFeUJMl1qHKTwMpX2MXEZYbL1k4P1WDYVsWHEd4GFfupd5h+pNlB9z9/sRIKnP8viw8xbS4oBVvNZ2gA3NfZjwstCGRneuns8nLwvfrqIUIgduvATG5PGFfmZx2m9JOvOKwzTzBzBpRvVVd7TyWpkGOBKbK6n+B+zSOIswLAgMBAAECggEALHcbgSmDLuDLGhCrgptXadL4HjcIS3j2pP+MBtPoIJcgt7LSgo0PfwNUrEA4fbudN6B8M5KTq/YOnf8PDbgv5qhRVLs/Wp1VgtrpUMERL2+aq4+VnjeMiUR98Gb/G5OvJz3N+PtLW660lWsFgP2JinR0BFG0qK91w5gJk/yUjU6TV6xeck9wGVvkHnBIoab4A2l42QaSxSM1Eyp6yYDPBKrDRRvS0dSiTQetVZ1gTwVikrVJWHMrk/Ls5+ukjKIPhIRdhsNrzjpCToEc7YzFp4GEa2VEb/hmqXZEf0oJCGZ0gavd3lNhj24kp6CqQmiNz95FgnHE8bi1wP5dOoxRoQKBgQDopzIFYNzfIyK5Mo/8Agf8XD1naPil3570q3+rOpcLDnzOHf9A4lm/ndecNWSaIhUha6czNmWlLlUIoJzFv9VpRVeopSkc6opgjo2kclJ8uoyCnV9dyP0Pd1HTQRtmjnHUl3v1YwYjt0tFkXvD+AwgxJg68MRnXeW3K/1XlBNW0wKBgQDliAqn68CM9rfpuQ27gmMiqfFQenFq5P8Kj/uGqcs6VUVWujN2XNuAXnF7us8NTEc15590y/IcPLuMvI4iA3ZrneOVx/TQ8ivCWjactMbOdJjgkufa21XsyaaR+bksqcIuiAFGP/ATFr/w1D4pXZ5BTkKOf8wwQxjzHKHeIgRi6QKBgQCYQBI0AteIDu5CVBx1xr6DH7nvWnqd0mGrrC+4VndR/QEfwfGw/G/PPfRDfY2AcJ1zaYfZs9eA6XksVC9EGe4HHiHnc24cRkCYP7Hh1A63IT2inGo0bbtty5/4p7rOupkzjo7IXy09Yk4YEMT10fXd28njiHx/SKtz243HKlgdkQKBgQCuWjZt86Ch808klNMfmh2f2SNbFIdOwYASD+jqE9QyDU/MX0h0InkB+7uMVwysd0KoabcwSzMvy9pTP29f2u17NcYIookOpsYirdBKHO/fJ6ZxAGZqUq3kXhDPVbgZeyHropgFOtAsT92hHDfTyC9MQBxCjkUWbAFpulgimghm8QKBgBG0wINsOVGuOSQlY4Djh8FkH4LvbG/Uubc3ozGEY1sR+iyRl1MRVYA0EHRmOpmpjsb4RHlqs1iGQnpC+zD/G7Kz++QEjZqe5XbOvqYuWjfuIiwwWxEg1NzMFLE8dlm/TTvNAf+QoApHNfF1249GtAmjjs5AF3khQXT3Zo4k4lFe

PublicKey:

  1. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0JkyQIXHWKfko2GgsmQXZ27m19pL6UzSCk1ZpxYB6jddi7zl0gh3jbQzvfkfl2cmgVUPuVEE68Ol6lV8qSmN2dCTIdapEFJkNFgJTY7vClAnyVwMtsITSvfQAUNj6xZerw7KzHTra63DKc90qDSs/NkWHTR2yinTapMPpmTMGgM1wwqBXlCTJdahyk8DKV9jFxGWGy9ZOD9Vg2FbFhxHeBhX7qXeYfqTZQfc/f7ESCpz/L4sPMW0uKAVbzWdoANzX2Y8LLQhkZ3rp7PJy8L366iFCIHbrwExuTxhX5mcdpvSTrzisM08wcwaUb1VXe08lqZBjgSmyup/gfs0jiLMCwIDAQAB

JAVA 生成 RSA 密匙对

Java 生成密匙对比较简单,直接上码:

  1. public static void main(String[] args) throws Exception {
  2. genKeyPair();
  3. }
  4. public static void genKeyPair() throws Exception {
  5. KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
  6. keyPairGen.initialize(2048);
  7. KeyPair keyPair = keyPairGen.generateKeyPair();
  8. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  9. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  10. System.out.println("PrivateKey: \n" + encodeToString(privateKey.getEncoded()));
  11. System.out.println("PublicKey: \n" + encodeToString(publicKey.getEncoded()));
  12. }
  13. private static String encodeToString(byte[] encoded) {
  14. return Base64.getEncoder().encodeToString(encoded);
  15. }
  16. private static byte[] decodeToByte(String decoded) {
  17. return Base64.getDecoder().decode(decoded);
  18. }

其他就不多说了~

扩展

在使用证书时我们经常会遇到各种格式的问题,如:

1)RSA这种加密算法和X509、PKCSXX有什么关系?
2)PKCSXX系列直接又有什么关系?
3)为什么用 openssl 创建的 rsa private key,需要导成pkcs8之后才能被程序所使用?

而且在上面的示例中我们也使用了 PKCS8 标准格式,关于上面三个疑问在知乎上也有相应的问题,而且也有有大佬给出了很清晰的解释:

知乎:加密算法和文件格式RSA、X509、PKCSXX?OR https://www.zhihu.com/question/22524886