[Linux] 在 Linux CLI 使用 ssh-keygen 生成 RSA 密钥
RSA 是一种公钥加密算法,在 1977 年由麻省理工学院的 Ron Rivest, Adi Shamir, Leonard Adleman 三人一起提出,因此该算法命名以三人姓氏首字母组合而成。
SSH 是 Secure Shell 缩写,是建立在应用层和传输层基础上的安全协议,为计算机上运行的 Shell 提供安全的传输和使用环境。
传统的 rsh, FTP, POP 和 Telnet 网络协议因为传输时采用明文,很容易受到中间人方式攻击。为了防止远程传输信息出现泄露,SSH 协议支持对传输的数据进行加密,因此它还能防止 DNS 和 IP 欺骗。另外采取 SSH 协议传输的数据可以进行压缩,所以可以加快数据传输速度。最初 SSH 协议由芬兰的 Tatu Ylönen 在 1995 年设计开发,目前属于 SSH Communications Security 拥有,由于版权原因,1999 年 10 月开源软件 OpenSSH 被开发出来,它已成为事实上的 SSH 协议标准实现(SSH Communications Security 提供的 SSH 软件使用不同于 OpenSSH 的私钥格式),也是目前 Linux 标准配置。
基本框架
SSH 协议主要分成三个协议:
1. 传输层协议(The Transport Layer Protocol):传输层协议提供服务器认证,数据机密性,信息完整性等支持。
2. 用户认证协议(The User Authentication Protocol):用户认证协议为服务器提供客户端的身份鉴别。
3. 连接协议(The Connection Protocol):连接协议将加密的信息隧道划分成若干逻辑通道,提供给更高层应用协议使用。
验证方式
SSH 提供两种安全验证方式:
1. 基于口令:客户端使用账号和口令登录服务器,所有传输数据都会被加密。但可能存在伪造服务器冒充真正的服务器与客户端进行交互,不能避免中间人攻击。
2. 基于密钥:使用一对密钥(私钥 + 公钥),将公钥放置到服务器注册。当用户从客户端登录服务器时,服务器会接到使用密钥(即注册在服务器的公钥)进行安全验证请求,服务器首先比对从客户端发送过来的公钥与在己方注册的公钥是否一致,如果一致,服务器会使用该公钥加密数据向客户端发起 "挑战"[1],从而避免中间人攻击。
OpenSSH 提供的工具
OpenSSH 提供了以下几个工具:
1. ssh:实现 SSH 协议,用以建立安全连接,它替代了较早的 rlogin 和 Telnet。
2. scp, sftp:利用 SSH 协议远程传输文件,它替代了较早的 rcp。
3. sshd:SSH 服务器守护进程,运行在服务器端。
4. ssh-keygen:用以生成 RSA 或 DSA 密钥对。
5. ssh-agent, ssh-add:管理密钥的工具。
6. ssh-keyscan:扫描网络中的主机,记录找到的公钥。
生成密钥对
使用 ssh-keygen 生成一个密钥对(私钥 + 公钥):
$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/xavier/.ssh/id_rsa): id_rsa Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in id_rsa. Your public key has been saved in id_rsa.pub. The key fingerprint is: ce:89:59:3d:a1:3a:99:b3:01:46:78:0f:d1:cc:d4:fa xavier@Qbee-X The key's randomart image is: +--[ RSA 2048]----+ | .=.. | | . .+ . | | . + . . | | o o. o . | | o ..S o | | . . XE. . | | X + | | = | | . | +-----------------+
ssh-keygen 默认使用 RSA 算法,长度为 2048 位,生成一个私钥文件 id_rsa 和一个公钥文件 id_rsa.pub,两个文件默认保存在用户的 ~/.ssh 目录下。你可以在命令行交互过程指定密钥文件路径,也可以设置密钥口令,如果设置了密钥口令,在使用密钥进行登录时,需要输入口令。
ssh-keygen 支持 -f 选项指定密钥文件路径,-t 选项指定加密算法,-b 选项指定密钥长度,-N 选项指定密钥口令,-C 选项指定注释。
只要将公钥文件 id_rsa.pub 提交给服务器,读取该文件包含的字符串并追加到服务器端用户的主目录 ~/.ssh/authorized_keys 文件中,持有私钥的客户端就可以使用 SSH 协议登录服务器了。
SSH 1 协议支持 RSA 算法,SSH 2 协议支持 RSA 和 DSA 两种算法。ssh-keygen 使用 -t 选项来指明加密算法,rsa1 表示支持 SSH 1,dsa, ecdsa, rsa 表示支持 SSH 2。
生成支持 SSH 1 的 RSA 密钥:
$ ssh-keygen -t rsa1 -f id-rsa1 Generating public/private rsa1 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in id-rsa1. Your public key has been saved in id-rsa1.pub. The key fingerprint is: c8:81:8f:dc:cd:ba:86:d2:56:e8:d5:13:3f:57:a5:f9 xavier@Qbee-X The key's randomart image is: +--[RSA1 2048]----+ | | | . .| | . . + | | . = =. + | | o.=.So . . | | . o.o o . E| | o +. . o | | . = .. | | o .. | +-----------------+
从私钥文件生成公钥文件:
$ ssh-keygen -y -f id-rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmg/9Hoc98c6AIlEPYK6VqE3ZTlMlfXqn2VgU0NAPXeRmYX+jHYZXA5AxMNTD8KgZIuilK23qzzKBy0hgoO9DDpsBg98Pf4NLkHjTcjpPFX1TBD6RWO/OX/g4uN+gZH1/zoREJa4fit8SSG2V2GoQkqrhfRYCy+a9mQX29ZvOLfYK/aMVjb+yfzLJychdvV3CQkDvkd5R/DHNU6ZQ3pyIEjA/cUQqqmgxQj0f72y8IXv8zesXtjXaaKG17R2oSN1MNDZo/y4m426MYxl4mMQMvM5yR3UvhD93pgNgaR8LY/vspcIeE6cJZsGl21oYtrDZ/GdmF5ulMGwjIDfTJRLvb
修改私钥文件的注释和口令(仅支持 RSA1,如果原 RSA1 文件含有注释或口令,才会提示修改相应的注释或口令。):
$ ssh-keygen -c Enter file in which the key is (/home/xavier/.ssh/id_rsa): id-rsa1 Key now has comment 'Hello' Enter new comment: HelloWorld The comment in your key file has been changed.
修改私钥文件口令(命令:ssh-keygen -p [-P old_password] [-N new_password] [-f keyfile]):
$ ssh-keygen -p -f id-rsa Key has comment 'id-rsa' Enter new passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved with the new passphrase.
如果想要取消口令,只需要在输入密码为空即可。私钥口令只是对私钥文件的访问权限,修改和删除口令并不影响私钥内容。
公钥指纹
由于公钥长度一般都是 1024 或 2048 个字节,不方便进行比对,因此通常使用一个较短的字符串来代表它,这个就是公钥指纹。公钥指纹的计算方法一般就是对公钥字符串进行 MD5 或者 SHA-1 等摘要计算得到,一个 1024 字节长度的 RSA 算法公钥,经过指纹计算后得到的公钥指纹只有 128(MD5摘要)字节或者 160(SHA-1)字节。
你可以使用 ssh-keygen 工具来计算公钥指纹:
$ ssh-keygen -l -f id_rsa.pub 2048 ce:89:59:3d:a1:3a:99:b3:01:46:78:0f:d1:cc:d4:fa xavier@Qbee-X (RSA)
如果客户端是第一次访问服务器,系统会提示以下信息:
$ ssh xavier@192.168.1.5 The authenticity of host '192.168.1.5 (192.168.1.5)' can't be established. RSA key fingerprint is 1c:bb:f1:e5:40:34:75:d3:37:b7:8f:b3:4a:6f:b6:47. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.1.5' (RSA) to the list of known hosts.
这是因为客户端第一次连接目标服务器,客户端没有目标服务器的公钥存根,因此系统告诉你目前正在连接的服务器所使用的公钥指纹(公钥指纹代表着公钥,但长度较短便于识别),需要你看看这个指纹是否正确,如果正确就正式建立连接,如果指纹可疑就不要建立连接。
这个公钥指纹是基于服务器的公钥计算而来,服务器的公钥一般保存在 /etc/ssh/ssh_host_rsa_key.pub 文件中。如果你事先知道服务器公钥,那么你自然可以轻松识别指纹并决定是否建立连接,但如果是在互联网中连接陌生服务器,你并知道目标服务器的公钥,这样就无法识别当前指纹是不是恶意的中间人服务器提供的,为了解决这个问题,服务器端管理员需要提前公示自己的公钥,或者是从证书机构申请证书,用户只要使用公示的公钥,或者去颁证机构认证下载证书就可以识别当前连接的服务器是否是虚假的中间人。
一旦你确认指纹合法性并建立连接后,客户端就会将服务器的公钥保存在 $HOME/.ssh/known_hosts 文件中,下次连接时系统自动将对方发过来的公钥与已知公钥进行比对,如果正确就直接建立连接,如果不正确将给出警告提示说公钥不匹配并阻止建立连接。
当由于公钥不匹配而无法建立连接时,可能有几个原因,一是目标服务器更换了公钥;二是目标服务器更换了 IP 地址或者域名,导致你连接到其他主机致使公钥不匹配;三是有恶意攻击者截断了连接,正在使用伪造的主机地址试图欺骗你建立连接。无论是哪个原因,你都应该保持警惕,谨慎建立连接。
注:
[1] "挑战" 是指服务器使用公钥加密数据发送给客户端,客户端使用配对的私钥对数据进行解密,客户端成功解密后将答案发回服务器进行验证,结果一致则挑战成功,表示客户端是合法用户可以进行安全通信。
附:
1. RSA 算法