C#生成putty格式的ppk文件(支持passphrase)

背景

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的使用界面:

C#生成putty格式的ppk文件(支持passphrase)

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

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

Original: https://www.cnblogs.com/bossma/p/16428919.html
Author: 波斯马
Title: C#生成putty格式的ppk文件(支持passphrase)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/683673/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 那些舍不得删除的 MP3–批量修改mp3的ID3tag

    整理电脑时发现很多mp3。那是大约2001年至2009年之间。那个时候大家听歌,还是习惯从网上下载mp3。虽然现在听歌比从前方便多了,简单到只需在APP中输入歌名,但用播放器听mp…

    技术杂谈 2023年6月21日
    070
  • Creating Apps With Material Design —— Creating Lists and Cards

    转载请注明http://blog.csdn.net/eclipsexys翻译自Developer Android。时间仓促,有翻译问题请留言指出,谢谢 创建Lisst和Cards …

    技术杂谈 2023年5月30日
    091
  • 设计模式 11 外观模式

    外观模式(Facade Pattern)属于 结构型模式 在生活中,经常遇到这样的情况:办理一个业务,需要找很多部门签字盖章,这些部门往往距离较远,无奈只得四处奔波。这时候相信所有…

    技术杂谈 2023年7月25日
    071
  • test2

    test2 posted on2017-04-09 12:27 gcczhongduan 阅读(141 ) 评论() 编辑 Original: https://www.cnblog…

    技术杂谈 2023年5月31日
    081
  • 前端矩阵知识

    概述 矩阵,是线性代数中涉及的内容,线性代数在科学领域有很多应用的场景,如下: 大部分同学在大学时期应该都学过一本叫做线性代数的书,如果没猜错的话,你们的老师在教学的时候大多都是概…

    技术杂谈 2023年5月31日
    074
  • Eureka

    一 什么是SpringCloud? Author:呆萌老师 QQ:2398779723 微信:it_daimeng Spring Cloud是&#x4…

    技术杂谈 2023年7月24日
    072
  • 计算机的基本认识

    所有图片均为西部开源所有,仅作为随笔所用。 计算机是什么? 计算机的硬件组成 装机 主要设备 有CPU,内存(硬盘,内存条),主板,电脑就能跑起来了CPU拥有核显的话可以不用再装显…

    技术杂谈 2023年6月21日
    071
  • 保姆教程系列二、Nacos实现注册中心

    前言: 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i 上篇我们介绍到 保姆教程系列一、Linux搭建Nacos 注册中心原理 一、环境准备 Java版本:1.8+ (L…

    技术杂谈 2023年7月11日
    093
  • resttemplate的ReadTimeout和ConnectTimeout

    问题描述:今天,在做微服务开发中,A服务区调用B服务,获取数据做导出excel操作。A服务出现了”java.net.SocketTimeoutException: Re…

    技术杂谈 2023年5月31日
    096
  • Invalid argument supplied for foreach() in wp-include/script-loader.php如何解决

    今天小美眉说网站头部多了一行错误提示:Warning: Invalid argument supplied for foreach() in /wp-includes/script…

    技术杂谈 2023年5月30日
    099
  • B树-插入

    B树系列文章 1. B树-介绍 2. B树-查找 3. B树-插入 4. B树-删除 插入 根据B树的以下两个特性 每一个结点最多有m个子结点 有k个子结点的非叶子结点拥有 k −…

    技术杂谈 2023年6月21日
    095
  • VMware及win10虚拟机的安装及环境配置

    一、安装VMware 1.1、下载VMware安装包 在此给大家一个迅雷的链接:点击下载提取码:sp84 1.2、点击下一步 1.3、点击我接受,点击下一步 1.4、更换安装位置,…

    技术杂谈 2023年6月21日
    087
  • django–ORM表的多对一关系

    *多对一关系是什么 Django使用 django.db.models.ForeignKey定义多对一关系。 ForeignKey需要一个位置参数:与该模型关联的类 class I…

    技术杂谈 2023年6月21日
    087
  • 实践torch.fx第一篇——基于Pytorch的模型优化量化神器

    第一篇——什么是torch.fx 今天聊一下 比较重要的 torch.fx,也趁着这次机会把之前的 torch.fx笔记整理下,笔记大概拆成三份,分别对应三篇: 什么是torch….

    技术杂谈 2023年7月11日
    069
  • Linux性能监控(一)-sar

    sar是一个非常全面的一个分析工具,对文件的读写,系统调用的使用情况,磁盘IO,CPU相关使用情况,内存使用情况,进程活动等都可以进行有效的分析。sar工具将对系统当前的状态进行取…

    技术杂谈 2023年7月11日
    071
  • 【编程教室】PONG-100行代码写一个弹球游戏

    大家好,欢迎来到 Crossin的编程教室 ! 今天跟大家讲一讲:如何做游戏 游戏的主题是弹球游戏《PONG》,它是史上第一款街机游戏。因此选它作为我这个游戏开发系列的第一期主题。…

    技术杂谈 2023年7月24日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球