背景

2022国家级护网行动即将开启,根据阿里云给出的安全建议,需要将登陆Linux的方式改为密钥对方式。我这里使用的远程工具是自己开发的,能够同时管理Windows和Linux,但是以前不支持密钥对的登陆方式,所以需要改造一下。

护网行动是什么?护网行动从2016年开始,是一场由公安部组织的网络安全攻防演练,目的是针对全国范围的真实网络目标为对象的实战攻防活动,旨在发现、暴露和解决安全问题,检验我国各大企事业单位、部属机关的网络安全防护水平和应急处置能力。护网行动每年举办一次,为期2-3周。

我使用的远程工具 RDManager:https://blog.bossma.cn/tools/new-version-of-rdmanager-replace-poderosa-with-putty/,这个工具访问Linux使用了putty,putty的密钥对登陆方式使用的是自有格式的ppk文件,但是阿里云上下载的是pem格式的密钥文件,所以需要将pem格式转换为ppk格式。

思路

putty本身提供了一个工具,可以将其他格式的密钥文件转换为自有的ppk文件,这个工具的名字是puttygen。在linux上可以通过命令进行转换,在Windows上则必须使用GUI工具手动操作,这多有不便。我期望的是能通过编程的方式进行这个转换,这样只需要在RDManger中上传pem文件,就可以自动转换为putty的ppk格式的文件,不需要再去使用puttygen。

首先查了下有没有现成的轮子,经过多次寻找,在Github上找到了一个项目:pem2ppk (https://github.com/akira345/pem2ppk),这个项目看名字就知道很贴合我的需求,它的主要功能就是读取pem文件,然后输出为ppk文件。我最终的解决方案主体也是从此而来。不过这个程序有两个问题:

  • 1、不是所有的pem文件都能转换成功,网上也是有人说成功了,有人说不行。
  • 2、不支持对密钥进行加密,别人拿走了这个ppk文件就可以直接使用。puttygen是有这个功能的。

除此之外,很难再找到比较贴合需求的资料了。怎么办?其实这个Github项目的很大一部分代码来源于另一篇文章:https://antonymale.co.uk/generating-putty-key-files.html,作者提到可以去看putty的源码。

受此启发,我也可以去看putty的源码,然后将相关处理翻译为C#的实现,这样应该是可以解决问题的。

实现

putty的源码官网上就可以下载到,不过我看的是一个几年前的版本:https://github.com/KasperDeng/putty,这个版本和新版本的主要逻辑都是一样的,搞懂C语言的若干函数和数据类型就很容易理解,而且旧版本更原始,没有那么多的抽象,反而更容易理解。

输出ppk内容不正确的问题

这个问题主要是由于填充(padding)使用不当造成的,pem2ppk项目在输出密钥的各个属性时都使用了前置填充,而putty并不是固定的都加了填充。

看putty的代码实现:https://github.com/KasperDeng/putty/blob/037a4ccb6e731fafc4cc77c0d16f80552fd69dce/putty-src/sshrsa.c#L654

    dlen = (bignum_bitcount(rsa->private_exponent) + 8) / 8;
plen = (bignum_bitcount(rsa->p) + 8) / 8;
qlen = (bignum_bitcount(rsa->q) + 8) / 8;
ulen = (bignum_bitcount(rsa->iqmp) + 8) / 8;
bloblen = 16 + dlen + plen + qlen + ulen;

这段代码是计算密钥的各个属性的值的字节数,然后用于初始化一个大的字节数组,将这些数据写进去。bignum_bitcount是计算值的比特位数,除以8就是得到字节数,为什么还要加8呢?这是因为C语言中除法的结果是向下取整的,比如数学计算结果是1.5,那么C语言中得到的就是1,为了不让任何一个比特丢失,所以这里加了一个8,预留好充足的空间。

再来看pem2ppk中的实现:https://github.com/akira345/pem2ppk/blob/d2baee08064953280984607d1e4ae1183127e5ad/PEM2PPK/PuttyKeyFileGenerator.cs#L24

private const int prefixSize = 4;
private const int paddedPrefixSize = prefixSize + 1;
byte[] publicBuffer = new byte[3 + keyType.Length + paddedPrefixSize + keyParameters.Exponent.Length +
paddedPrefixSize + keyParameters.Modulus.Length + 1];

这里keyParameters.Exponent和keyParameters.Modulus是公钥的两个属性,可以看到前边加了一个固定的长度paddedPrefixSize,这个paddedPrefixSize=prefixSize + 1,这里边的1就对应putty中的+8逻辑。

不过固定+1是有问题的,可以想一下C#和C语言在处理这些属性值时的差别。

在putty中如果数据比特数不能被8整除,那么+8之后再整除就可以得到正确的字节数,否则就会少1个字节;如果数据能被8整除,那么+8就会多1个空的字节,这个多的字节就是padding了。所以能被8整除的时候才会有这个padding。

在C#中开始处理的时候就已经都是字节了,所以C#中不需要处理位数不能被8整除的问题,但是需要在能被8整除的时候增加一个空字节,C#中如何判断数据的位数能被8整除呢?可以认为数据首byte的最高位是1的时候,比特数就能被8整数,此时最小二进制数是10000000,比它小的数就可以被舍弃掉至少1位。10000000也就是128,因此凡是大于等于这个数的都是能被8整数的,也就是需要padding的。

所以可以这样判断是否需要增加padding:https://gist.github.com/bosima/ee6630d30b533c7d7b2743a849e9b9d0#file-puttykeyfilegenerator-cs-L190

	private static bool CheckIsNeddPadding(byte[] bytes)
{
return bytes[0] >= 128;
} private static int GetPrefixSize(byte[] bytes)
{
return CheckIsNeddPadding(bytes) ? paddedPrefixSize : prefixSize;
}

实现ppk加密

pem2ppk项目中没有对key进行加密的实现,网上也没有找到C#的源代码可以实现这个功能。但是这个功能很关键,在RDManager中所有的密码都是加密处理的,这样服务器账号落盘的时候安全性才能有比较好的保障,但是阿里云导出的pem是没有加密的,虽然puttygen也可以给pem加密,但是还不是不能将加密以编程的方式集成到RDManager中。

解决这个问题的方式还是搬运putty的实现方式,将C语言的实现转换为C#的实现。其中有两个关键的处理:一是要在计算Private-MAC的值时给私钥增加padding,二是使用AES256进行加密处理。至于putty为什么要这样处理,我没有研究,只是照搬过来。

主要看下AES256加密的处理,有些参数很关键:

byte[] passKey = new byte[40];
...
byte[] iv = new byte[16];
byte[] aesKey = new byte[32];
Buffer.BlockCopy(passKey, 0, aesKey, 0, 32);
using (RijndaelManaged rijalg = new RijndaelManaged())
{
rijalg.BlockSize = 128;
rijalg.KeySize = 256;
rijalg.Padding = PaddingMode.None;
rijalg.Mode = CipherMode.CBC;
rijalg.Key = aesKey;
rijalg.IV = iv; ICryptoTransform encryptor = rijalg.CreateEncryptor(rijalg.Key, rijalg.IV);
return encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
}
  • iv是长度为16的字节数组,里边都是默认值0。
  • aeskey是一个长度为32的字节数组,不过计算的时候准备的是长度为40的字节数组,需要截一下。
  • Padding需要设置为PaddingMode.None,默认的不是这个。

其它就没什么好说的了。

为了不那么单调,来一张RDManger的使用界面:


以上就是本文的主要内容了。

完整代码在Github,欢迎访问:https://gist.github.com/bosima/ee6630d30b533c7d7b2743a849e9b9d0

C#生成putty格式的ppk文件(支持passphrase)的更多相关文章

  1. Rss 订阅:php动态生成xml格式的rss文件

    Rss 简介: 简易信息聚合(也 叫聚合内容)是一种描述和同步网站内容的格式.使用RSS订阅能更快地获取信息,网站提供RSS输出,有利于让用户获取网站内容的最新更新.网络用户可以在客户端借助于支持RS ...

  2. 使用 HTMLTestRunner 模块生成HTML格式的测试报告文件

    1.下载HTMLTestRunner.py HTMLTestRunner 是 Python 标准库的 unittest 模块的一个扩展.它生成易于使用的 HTML 测试报告.HTMLTestRunne ...

  3. Java生成xlsx格式的excel文件

    xlsx格式的写入的数据量据说有百万级,结合实际需要该格式. public static void main(String[] args) throws Exception { OutputStrea ...

  4. keil MDK中如何生成*.bin格式的文件

    在Realview MDK的集成开发环境中,默认情况下可以生成*.axf格式的调试文件和*.hex格式的可执行文件.虽然这两个格式的文件非常有利于ULINK2仿真器的下载和调试,但是ADS的用户更习惯 ...

  5. 在MDK中怎样生成*.bin格式的文件?

    在Realview MDK的集成开发环境中.默认情况下能够生成*.axf格式的调试文件和*.hex格式的可运行文件. 尽管这两个格式的文件很有利于ULINK2仿真器的下载和调试,可是ADS的用户更习惯 ...

  6. 如何使用Postman生成不同格式测试的报告

    Postman还可以生成测试报告,还是多种格式报告? Postman团队开源Newman作为Postman运营工具,该开源库使用命令行方式执行Postman 脚本,并且生成多种格式报告,还支持Post ...

  7. [转]使用ant让Android自动打包的build.xml,自动生成签名的apk文件(支持android4.0以上的版本)

    在android4.0以后的sdk里那个脚本就失效了,主要是因为 apkbuilder这个程序不见了: 人家sdk升级,我们的脚本也要跟上趟,修改一下喽. 上网一查,大家的文章还停留在我去年的脚本程度 ...

  8. 如何将位图格式图片文件(.bmp)生成geotiff格式图片?

    一.位图格式信息 位图BITMAPINFOHEADER 与BITMAPFILEHEADER: 先来看BITMAPINFOHEADER,只写几个主要的 biSize包含的是这个结构体的大小(包括颜色表) ...

  9. 在Mac OSX下使用ssh建立隧道(在Windows下建立隧道可以使用putty,其间会用到ppk文件)

    在Windows下建立隧道可以使用putty,其间会用到ppk文件.在Mac OSX下,同样的功能可以用ssh命令实现.具体是: ssh -D 8088 -Nf user@ip -i myppk.ss ...

随机推荐

  1. ArcGIS使用技巧(二)——数据恢复

    新手,若有错误还请指正! ArcGIS工程文件中图层的数据源位置移动之后,会显示红叹号(图1),需要进行数据恢复,就体现出之前所说的勾选"Store relative pathnames t ...

  2. Python工程打包

    Python项目打包 我是自己写了一个项目,然后需要打包成问一个exe文件,这样直接打开这个文件就可以运行,而不需要在pycharm中打开相应文件才能运行,也可以将打包好的文件发给其他人,不需要pyc ...

  3. 4.27-Postman和JMeter总结及实战描述

    一.数据格式 常用的请求方法有8种,但是最常用的有4-5种 1.GET 获取资源 2.POST 添加资源(对服务端已存在的资源也可以做修改和删除操作) 3.PUT 修改资源 4 .DELETE删除资源 ...

  4. Linux入门进阶 - 如何在Linux中使用export命令

    来自:Linux迷链接:https://www.linuxmi.com/linux-export.html Linux export命令会标记哪些值需要传递给一组子进程.这是bash shell提供的 ...

  5. Docker 日志管理最佳实践

    开源Linux 回复"读书",挑选书籍资料~ Docker-CE Server Version: 18.09.6 Storage Driver: overlay2 Kernel V ...

  6. 痞子衡嵌入式:大话双核i.MXRT1170之在线联合调试双核工程的三种方法(IAR篇)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT1170下在线联合调试双核工程的方法(基于IAR). 前段时间痞子衡写过一篇<双核i.MXRT1170之单独在线调试从 ...

  7. java高级用法之:绑定CPU的线程Thread-Affinity

    目录 简介 Java Thread Affinity简介 AffinityLock的使用 使用API直接分配CPU 总结 简介 在现代计算机系统中,可以有多个CPU,每个CPU又可以有多核.为了充分利 ...

  8. Tutorial 3_软件工作量估计和编码规范

    软件过程与管理实验 实验3:编码规范 本次实验内容是个人软件过程部分,通过本次实验,学生将掌握以下内容: 1.建立自己的编码规范和代码审查表. 2.会用COCOMO II模型对软件工作量进行估计. [ ...

  9. git rename branch

    git 不能直接重命名远程分支,如果需要重命名则执行以下步骤操作: 重命名本地分支 删除远程分支 推送本地分支(重命名后的)到远程 额外说明: 1. 重命名后的分支也会保留历史 commit(应该是本 ...

  10. vscode修改括号对颜色,自定义括号颜色

    新版的vscode 1.67(2022年4月更新的版本),自带括号颜色匹配,十分的方便. 至于怎么开启,已经有人写过,这里就不写了,更新到新版默认开启~ 括号颜色默认只有3种颜色,有时候感觉不够用. ...