新闻中心
Go语言生成OpenSSH兼容的SSH密钥对教程

本教程详细介绍了如何使用go语言生成ssh密钥对,重点在于创建符合openssh `authorized_keys`文件格式的公钥。文章将引导读者从rsa私钥的生成,到其pem编码存储,再到通过`golang.org/x/crypto/ssh`包将公钥转换为openssh标准格式并保存,提供完整的代码示例和最佳实践,确保密钥的安全性和兼容性。
Go语言生成SSH密钥对:从RSA到OpenSSH格式
在Go语言中进行安全通信或自动化部署时,经常需要程序化地生成SSH密钥对。虽然Go标准库提供了生成RSA密钥和PEM编码的功能,但要生成符合OpenSSH authorized_keys文件格式的公钥,则需要借助额外的包。本教程将详细介绍如何生成一个RSA私钥,并将其对应的公钥转换为OpenSSH可识别的格式。
1. 理解SSH密钥对和格式差异
SSH密钥对由一个私钥和一个公钥组成。私钥需要严格保密,而公钥则可以公开。当客户端尝试通过SSH连接到服务器时,服务器会使用存储在其authorized_keys文件中的公钥来验证客户端的私钥。
Go标准库中的crypto/rsa和crypto/x509包可以生成和处理RSA密钥,并将其编码为PKCS#1或PKIX格式的PEM块。然而,OpenSSH的authorized_keys文件对公钥的格式有特定的要求,它通常以ssh-rsa AAAAB3Nz...这样的字符串开头,而不是标准的PEM编码。
2. 生成RSA私钥
首先,我们需要生成一个RSA私钥。这是密钥对的基础。rsa.GenerateKey函数用于生成指定位数的RSA私钥。
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"golang.org/x/crypto/ssh" // 导入用于OpenSSH格式公钥的包
)
// generatePrivateKey 生成指定位数的RSA私钥
func generatePrivateKey(bits int) (*rsa.PrivateKey, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, fmt.Errorf("生成RSA私钥失败: %w", err)
}
return privateKey, nil
}注意事项:
Whimsical
Whimsical推出的AI思维导图工具
182
查看详情
- rand.Reader是Go语言中加密安全的随机数源,用于生成密钥的随机部分。
- 密钥位数(bits)通常建议选择2048或4096位,以提供足够的安全性。
3. PEM编码私钥并保存
生成私钥后,通常将其编码为PEM格式并保存到文件中。PEM是一种文本编码格式,常用于存储加密密钥和证书。
// encodeAndS*ePrivateKey 将RSA私钥编码为PEM格式并保存到文件 func encodeAndS*ePrivateKey(privateKey *rsa.PrivateKey, path string) error { // 将RSA私钥转换为PKCS#1 DER编码 privateKeyDER := x509.MarshalPKCS1PrivateKey(privateKey) // 创建PEM编码块 privateKeyBlock := &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: privateKeyDER, } // 将PEM编码写入文件 privateKeyFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) // 权限设置为0600确保私钥安全 if err != nil { return fmt.Errorf("创建私钥文件失败: %w", err) } defer privateKeyFile.Close() if err := pem.Encode(privateKeyFile, privateKeyBlock); err != nil { return fmt.Errorf("PEM编码私钥失败: %w", err) } return nil }
注意事项:
- 私钥文件的权限应设置为0600(只有文件所有者可读写),以防止未经授权的访问。这是SSH密钥管理的最佳实践。
- x509.MarshalPKCS1PrivateKey用于将rsa.PrivateKey转换为PKCS#1 DER编码的字节切片。
- pem.Encode将PEM块写入输出流。
4. 生成OpenSSH格式的公钥
这是本教程的核心部分。Go标准库的crypto/rsa包生成的rsa.PublicKey无法直接用于OpenSSH的authorized_keys文件。我们需要使用golang.org/x/crypto/ssh包来完成转换。
// generateAndS*ePublicKey 将RSA公钥转换为OpenSSH格式并保存到文件
func generateAndS*ePublicKey(privateKey *rsa.PrivateKey, path string) error {
// 从RSA私钥中提取公钥
publicKey := &privateKey.PublicKey
// 使用golang.org/x/crypto/ssh将RSA公钥转换为OpenSSH格式
sshPublicKey, err := ssh.NewPublicKey(publicKey)
if err != nil {
return fmt.Errorf("转换为OpenSSH公钥格式失败: %w", err)
}
// 将OpenSSH公钥编码为authorized_keys文件所需的格式
authorizedKeyBytes := ssh.MarshalAuthorizedKey(sshPublicKey)
// 将公钥写入文件
// 注意:OpenSSH公钥文件的权限通常可以放宽,但0644是一个常见且安全的选择
if err := ioutil.WriteFile(path, authorizedKeyBytes, 0644); err != nil {
return fmt.Errorf("写入OpenSSH公钥文件失败: %w", err)
}
return nil
}关键函数:
- ssh.NewPublicKey(publicKey *rsa.PublicKey): 这个函数接收一个*rsa.PublicKey(或其他加密算法的公钥),并返回一个ssh.PublicKey接口类型。这是将标准Go公钥转换为golang.org/x/crypto/ssh包内部表示的关键一步。
- ssh.MarshalAuthorizedKey(pub ssh.PublicKey): 这个函数将ssh.PublicKey接口编码为OpenSSH authorized_keys文件所需的字节切片。它会自动添加ssh-rsa前缀和密钥内容。
5. 完整示例代码
将上述函数组合起来,可以创建一个完整的程序来生成SSH密钥对并保存到指定文件。
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"golang.org/x/crypto/ssh"
)
// generatePrivateKey 生成指定位数的RSA私钥
func generatePrivateKey(bits int) (*rsa.PrivateKey, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, fmt.Errorf("生成RSA私钥失败: %w", err)
}
return privateKey, nil
}
// encodeAndS*ePrivateKey 将RSA私钥编码为PEM格式并保存到文件
func encodeAndS*ePrivateKey(privateKey *rsa.PrivateKey, path string) error {
privateKeyDER := x509.MarshalPKCS1PrivateKey(privateKey)
privateKeyBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyDER,
}
privateKeyFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return fmt.Errorf("创建私钥文件失败: %w", err)
}
defer privateKeyFile.Close()
if err := pem.Encode(privateKeyFile, privateKeyBlock); err != nil {
return fmt.Errorf("PEM编码私钥失败: %w", err)
}
return nil
}
// generateAndS*ePublicKey 将RSA公钥转换为OpenSSH格式并保存到文件
func generateAndS*ePublicKey(privateKey *rsa.PrivateKey, path string) error {
publicKey := &privateKey.PublicKey
sshPublicKey, err := ssh.NewPublicKey(publicKey)
if err != nil {
return fmt.Errorf("转换为OpenSSH公钥格式失败: %w", err)
}
authorizedKeyBytes := ssh.MarshalAuthorizedKey(sshPublicKey)
if err := ioutil.WriteFile(path, authorizedKeyBytes, 0644); err != nil {
return fmt.Errorf("写入OpenSSH公钥文件失败: %w", err)
}
return nil
}
// MakeSSHKeyPair 是一个辅助函数,用于生成SSH密钥对并保存到指定路径
func MakeSSHKeyPair(pubKeyPath, privateKeyPath string) error {
// 1. 生成RSA私钥 (建议使用2048或4096位)
privateKey, err := generatePrivateKey(2048)
if err != nil {
return err
}
// 2. 保存PEM编码的私钥
if err := encodeAndS*ePrivateKey(privateKey, privateKeyPath); err != nil {
return err
}
// 3. 生成并保存OpenSSH格式的公钥
if err := generateAndS*ePublicKey(privateKey, pubKeyPath); err != nil {
return err
}
return nil
}
func main() {
// 定义密钥文件的路径
homeDir, err := os.UserHomeDir()
if err != nil {
fmt.Printf("获取用户主目录失败: %v\n", err)
os.Exit(1)
}
keyDir := filepath.Join(homeDir, ".ssh_go_keys")
if err := os.MkdirAll(keyDir, 0700); err != nil {
fmt.Printf("创建密钥目录失败: %v\n", err)
os.Exit(1)
}
privateKeyFile := filepath.Join(keyDir, "id_rsa_go")
publicKeyFile := filepath.Join(keyDir, "id_rsa_go.pub")
fmt.Printf("正在生成SSH密钥对...\n私钥: %s\n公钥: %s\n", privateKeyFile, publicKeyFile)
if err := MakeSSHKeyPair(publicKeyFile, privateKeyFile); err != nil {
fmt.Printf("生成SSH密钥对失败: %v\n", err)
os.Exit(1)
}
fmt.Println("SSH密钥对生成成功!")
// 验证生成的文件内容 (可选)
privateKeyContent, err := ioutil.ReadFile(privateKeyFile)
if err != nil {
fmt.Printf("读取私钥文件失败: %v\n", err)
} else {
fmt.Println("\n--- 私钥内容 (部分) ---")
fmt.Println(string(privateKeyContent[:200]) + "...") // 打印前200字节
}
publicKeyContent, err := ioutil.ReadFile(publicKeyFile)
if err != nil {
fmt.Printf("读取公钥文件失败: %v\n", err)
} else {
fmt.Println("\n--- 公钥内容 ---")
fmt.Println(string(publicKeyContent))
}
}运行示例:
- 确保你已经安装了Go环境。
- 在你的Go模块中运行 go get golang.org/x/crypto/ssh 来安装所需的第三方包。
- 将上述代码保存为 main.go。
- 运行 go run main.go。 程序将在你的用户主目录下创建一个.ssh_go_keys目录,并在其中生成id_rsa_go(私钥)和id_rsa_go.pub(公钥)。
总结
通过利用Go标准库的crypto/rsa和crypto/x509包来生成和PEM编码私钥,并结合golang.org/x/crypto/ssh包来生成OpenSSH兼容的公钥,我们可以轻松地在Go程序中实现SSH密钥对的自动化生成。遵循文件权限等安全最佳实践,可以确保所生成密钥的安全性。
以上就是Go语言生成OpenSSH兼容的SSH密钥对教程的详细内容,更多请关注其它相关文章!
# 详细介绍
# 苏州网站推广官网首页
# 湖北咨询网站建设价格
# 分类信息平台推广营销
# 信贷产品营销推广
# 黄石品牌seo推广
# 保洁网站建设策划书范文
# 网络营销中的推广案例
# 南沙网站搜索优化
# 网络营销网站建设推广
# 宁波关键词排名效果
# 客户端
# 创建一个
# 设置为
# go
# 是一个
# 所需
# 这是
# 并保存
# 转换为
# 公钥
# crypto
# 标准库
# ai
# 字节
# 编码
# go语言
# golang
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
c++如何实现一个简单的软件渲染器_c++从零开始的3D图形学
4399免费游戏网址入口 4399小游戏免费入口点开即玩
电脑IP地址怎么查 查看本机IP地址的几种方法
怎样在Excel中做仪表盘_Excel仪表盘设计与关键指标展示方法
Safari怎么安装扩展程序 浏览器插件安装与管理方法【详解】
PHP URL参数传递与500错误调试指南
如何优雅地解决Livewire文件上传难题?SpatieLivewireFilepond让一切变得简单
Odoo 16:在表单视图中基于当前记录动态修改Tree视图属性
TikTok国际版网页端快速入口 TikTok全球版短视频浏览教程
解决Tabulator日期时间排序问题的专业指南
vivo手机互传视频怎么操作_vivo手机互传视频详细传输方法
Win11如何开启讲述人功能 Win11屏幕阅读器(讲述人)开启与关闭【教程】
Django表单验证失败时保留用户输入数据的最佳实践
微信网页版官方快速登录入口 微信网页版网页版账号直达
Pyrogram与g4f集成:异步编程实践与常见错误解决
Lar*el DB::listen 事件中的查询执行时间单位解析
抖音网页版平台入口 抖音网页版官网在线访问教程
极速漫画官方主页网址 极速漫画漫画在线浏览官网链接
PHP 枚举:根据字符串获取枚举案例的策略与实现
漫蛙漫画网页端入口 漫蛙2官方正版漫画站点
PDF文件体积过大处理_PDF压缩技巧详解
c++中为什么推荐使用using替代typedef_c++现代化类型别名
Win11怎么关闭快速启动_Win11彻底关机设置教程
深入理解J*aScript中的B样条曲线与节点向量生成
PrimeNG Sidebar背景色自定义指南:CSS覆盖与主题化实践
2026年CSGO开箱网站推荐 CSGO开箱平台精选
qq游戏免费畅玩入口_qq游戏电脑版快速启动
sublime如何优雅地处理行尾空格_sublime自动清理多余空白字符配置
Win11怎么开启卓越性能模式 Win11电源选项启用高性能释放硬件潜力【方法】
J*a里如何实现线程安全的懒加载单例_懒加载单例实现方法解析
UE5.7引擎表现爆炸优化无敌!5090跑4K稳定60FPS
如何使用spryker/configurable-bundles-products-resource-relationship模块解决复杂产品捆绑关系难题
谷歌google账号怎么注册账号 谷歌账号注册官方流程
PHP表单数据传递:如何通过隐藏输入字段获取动态ID
QQ邮箱官方网页版登录 QQ邮箱个人邮箱快速访问
一加Ace 6T实拍样张首次公布!李杰:主摄实力完全看齐4K档性能旗舰
Lar*el Excel导入时生成自定义递增ID的策略与实践
黑猫投诉统一入口官网 消费者权益保护投诉平台
HuggingFaceEmbeddings中向量嵌入维度调整的限制与理解
163邮箱登录密码 163邮箱忘记密码找回
在J*a里如何理解依赖关系的方向_依赖方向在模块结构中的作用
qq游戏大厅官方下载_qq游戏免费下载安装入口
创客贴用户入口官网登录 创客贴网页版电脑版系统
“在文档元素之后找到了标记”是什么错误? 检查并修复XML中多个根元素的3个方法
Composer的 "licenses" 命令如何帮助你遵守开源协议_检查项目依赖的许可证合规性
J*aScript 字符串标签转换:使用正则表达式高效替换
taptap防沉迷怎么解除 taptap解除健康系统限制说明【2025最新】
漫蛙Manwa2官网入口地址分享 漫蛙漫画PC版永久访问通道
uc手机浏览器网页版入口 uc浏览器手机版便捷登录首页
React中useState与局部变量:理解组件状态管理与渲染机制


2025-11-18
浏览次数:次
返回列表
dS*ePrivateKey 将RSA私钥编码为PEM格式并保存到文件
func encodeAndS*ePrivateKey(privateKey *rsa.PrivateKey, path string) error {
// 将RSA私钥转换为PKCS#1 DER编码
privateKeyDER := x509.MarshalPKCS1PrivateKey(privateKey)
// 创建PEM编码块
privateKeyBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyDER,
}
// 将PEM编码写入文件
privateKeyFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) // 权限设置为0600确保私钥安全
if err != nil {
return fmt.Errorf("创建私钥文件失败: %w", err)
}
defer privateKeyFile.Close()
if err := pem.Encode(privateKeyFile, privateKeyBlock); err != nil {
return fmt.Errorf("PEM编码私钥失败: %w", err)
}
return nil
}