<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Wind_Mask的博客</title><description>欢迎来到Wind_Mask的博客！</description><link>https://blog.wind-mask.com/</link><item><title>arch之乱</title><link>https://blog.wind-mask.com/blog/arch%E4%B9%8B%E4%B9%B1/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/arch%E4%B9%8B%E4%B9%B1/zh_cn/</guid><description>前段时间安装arch的魔怔玩法</description><pubDate>Tue, 23 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;缘起&lt;/h2&gt;
&lt;p&gt;不管怎么说装一个物理Linux系统总是码区一环……然而我其实是很风险厌恶的，一直到我的移动硬盘实在没有电脑以外稳定的供电（之前往路由器垃圾盒子上嗯插总是掉线）。那么这移动硬盘又能干什么呢，于是拿来乱装点系统也就算了。&lt;/p&gt;
&lt;p&gt;本文不是那种正经的教程，而是一些我在安装中的乱舞的记述。
正经教程将在参考资料中给出。&lt;/p&gt;
&lt;p&gt;看到本文注意一下时效性，安装的时候我是被论坛里那些帖子时间闹麻了。&lt;/p&gt;
&lt;h2&gt;准备&lt;/h2&gt;
&lt;p&gt;万物之源：&lt;a href=&quot;https://archlinux.org/download/&quot;&gt;arch download&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;正典：&lt;a href=&quot;https://wiki.archlinux.org/&quot;&gt;arch wiki&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;魔法：无法想象一根有魔法的网线给我省了多少力气，不可能保证无线网卡一开始就可用，还有稳定性和速度，更关键的是各种代理设置怎么比得了默认透明代理。即使你通晓各种镜像源和代理软件，也要设置各种环境变量代理方式，各种软件单独的设置……&lt;/p&gt;
&lt;h2&gt;开始&lt;/h2&gt;
&lt;p&gt;现在开始乱舞，首先，我不想刻录什么usb启动。因为当时我U盘刚好找不到了，移动硬盘应该可以但是反正系统都要装在上面，直接往里进就是了。
也懒得VMware了于是我翻出win上原来还有个Hyper-v姑且玩一下吧。
直接拿Hyper-V启动arch的iso，记得想办法把要装系统的硬盘通进去，其他虚拟机大约也可以支持的。&lt;/p&gt;
&lt;p&gt;这么做好处自然是不用真的启动usb启动盘什么的，实际上我甚至直接在虚拟机里启动了arch，然后还能在实机上启动（当然有一堆硬件问题所以只是一开始调试用）……&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;基本参考的是&lt;a href=&quot;https://arch.icekylin.online/&quot;&gt;archlinux 简明指南&lt;/a&gt;,说到底就是把杂七杂八的配置改一下，硬盘该分区的分区该挂载的挂载。如果要系统加密这一步就得做了，linux实在不像win随便bitlocker加密有解密的，用了btrfs后来发现也没什么办法运行时加密，所以就算了。
搞定后就可以把安全启动一关，bios里启动项一改，就可以进入arch了。&lt;/p&gt;
&lt;p&gt;但是这种系统是不足用的。图形界面随你心情也就算了，但是无奈现在笔记本这种双显卡而且我还是外接屏幕什么独显直连闹麻了。首先，我就没指望过optimus-manager这种东西，钻来钻去还好我们ASUS很厉害有个&lt;a href=&quot;https://asus-linux.org/&quot;&gt;asus-linux&lt;/a&gt;,这种的管理显卡比较成功，顺便给大家推个&lt;a href=&quot;https://github.com/ventureoo/nvidia-tweaks&quot;&gt;nvidia-tweaks&lt;/a&gt;这种把nvidia的配置都搞完了反正我是不看了，然后就是prime-run往里进，反正集显平时差不多（实际上外接我后来被逼无奈还得想办法绕过独显）。&lt;/p&gt;
&lt;p&gt;安全启动在win11上实在是得往里进的据说windows hello还有bitlocker都需要那我肯定跑不了，但是配一堆钩子什么自己生成什么签名每次更新都得注意什么的实在太魔。所以&lt;a href=&quot;https://github.com/Foxboron/sbctl&quot;&gt;sbctl&lt;/a&gt;用一下试试。这个自然有赖于bios的实现了，至少在我电脑上可用就是了。&lt;/p&gt;
&lt;h2&gt;排错&lt;/h2&gt;
&lt;p&gt;从一开始双显卡加外接屏幕就置我于各种怪象没办法这种场景毕竟想想也没人在意的。&lt;/p&gt;
&lt;p&gt;一开始独显通过一个C口dp接外接屏幕也没什么。就是bios改成集成显卡外接屏幕就没有了，这也是自然因为我知道我电脑那个C口是独显直连的。然而混合模式bug就来了，外接屏幕帧率掉到36帧，似乎是输出要经过cpu复制还是集显复制什么的bug，思来想去没有办法，电脑调成独显模式就好了，算了反正是接电源的独显就独显吧。&lt;/p&gt;
&lt;p&gt;我姑且这样几天后。不幸的，滚了一哈nvidia驱动或者linux内核？，独显模式桌面全都渲不出来了，只能在tty等死。调了半天没有办法，此时才让我觉醒了我自己电脑的知识：原来另一个C口接的是集显……那么就把外接屏幕接在另一个C口就是了，于是不仅集显模式能了，混合也好了（而且外接屏幕也不卡了），独显模式我就不试了。&lt;/p&gt;
&lt;p&gt;硬件加速什么的真的确实不太行，intel的能用不错了。&lt;/p&gt;
&lt;h2&gt;转移&lt;/h2&gt;
&lt;p&gt;怎么可能真的装在移动硬盘主要还是usb速度真不行，可怜我那可是nvme的固态啊！读3000的硬盘跑个二三十这种的根本不是正经系统强度嘛……这样根本不可能真的使用arch的。&lt;/p&gt;
&lt;p&gt;所以还是把根目录发送到电脑内的硬盘上把，反正其实空闲很多的。于是也促使我整理了电脑的硬盘，并且把没必要的bitlocker加密解了（为了两个系统间的文件共享）。&lt;/p&gt;
&lt;p&gt;于是在电脑的一块固态中腾出来142G空间，之前说了arch装在btrfs上了这东西有个快照发送功能直接把根分区快照发送国区展开改一下fstab里挂载的UUID就好了。&lt;/p&gt;
&lt;p&gt;然后把ESP分区也在硬盘上腾点地在建就是了，当然有tpm+安全启动情况下换启动分区甚至efi文件都是会触发bitlocker恢复的就是了。&lt;/p&gt;
&lt;h2&gt;快照&lt;/h2&gt;
&lt;p&gt;是的我使用Timeshift（尽管说真的它没救过我几次成功，毕竟安装过程中经常嗯造/boot，快照也救不了你）。
一个小bug，至少到前几周，当时我按它指定了子卷布局还是快照不了，结论是fstab中挂载用的不是uuid改成uuid就好，不知道现在如何了。&lt;/p&gt;
&lt;h2&gt;休眠&lt;/h2&gt;
&lt;p&gt;我竟然做过这种梦幻：可以自由地同时休眠win和arch。&lt;s&gt;事实上我其实快成功了，但是nvidia显卡和win休眠时的一些异象实在还是超出了我的能力。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;好的现在已经胜利，不管怎么说大部分情况可以做到了！两个系统可以独立休眠这种切换速度已经比肩虚拟机。&lt;/p&gt;
&lt;p&gt;&lt;s&gt;现在的结论是一般说可以休眠win而打开arch（事实上这已经比一般的说法好一些了，至于此时在arch上读写ntfs分区会怎么样……哈哈哈哈，反正那里是我onedrive文件夹，嗯造吧）&lt;/s&gt;&lt;/p&gt;
&lt;h2&gt;pacman与AUR配置&lt;/h2&gt;
&lt;p&gt;镜像大家都知道不用说，但是加速肯定还得继续。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;/etc/pacman.conf&lt;/code&gt;中注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ParallelDownloads&lt;/code&gt;：并行下载。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在&lt;code&gt;/etc/makepkg.conf&lt;/code&gt;中注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CFLAGS&lt;/code&gt;中可以改&lt;code&gt;-march=native&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MAKEFLAGS&lt;/code&gt;可以改&lt;code&gt;-j$(nproc)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;维护&lt;/h2&gt;
&lt;p&gt;我甚至写了个pacman钩子确保每次安装都会更新pkglist。
~~(yay本来是pacman当然可以换其他的)~~换成paru了，RIIR。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;paru -Qqe &amp;gt; pkglist.txt  #所有明确安装的软件包的列表
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重装的话（我不会容许的！）可以这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;paru -S --needed - &amp;lt; pkglist.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;强迫症必须指令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;paru -c
yes | paru -Scc
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;dotfiles&lt;/h2&gt;
&lt;p&gt;我选择使用&lt;a href=&quot;https://yadm.io/#&quot;&gt;yadm&lt;/a&gt;, &lt;s&gt;加上git-crypt加密再放私有仓库，勉强安全吧……&lt;/s&gt; 加密是致死量了，劝你别。&lt;/p&gt;
&lt;p&gt;字体：字体会暴露一切失败，&lt;s&gt;我是说把win里的C:\windows\fonts全拾走就是了。&lt;/s&gt; 直接从aur拾取即可。&lt;/p&gt;
&lt;p&gt;强上wayland：即使现在也还是要配置一些，&lt;s&gt;远未达到默认都可用，我有：&lt;/s&gt; 差不多够了&lt;/p&gt;
&lt;h2&gt;hyprland（遗留）&lt;/h2&gt;
&lt;p&gt;很闹嘛的东西使用感觉还行其实反正可以与kde共存死不了就是了。不过官方不考虑nvidia得用且用。
其间的麻烦配置想玩就玩不喜欢可以找现成的比如&lt;a href=&quot;https://github.com/JaKooLit/Arch-Hyprland&quot;&gt;Arch-Hyprland&lt;/a&gt;,再去github拾点dotfile就是了。&lt;/p&gt;
&lt;h2&gt;安全&lt;/h2&gt;
&lt;p&gt;好吧我容忍不了这种惶恐，这是被害妄想症。那么就重造根分区全加密吧。&lt;/p&gt;
&lt;p&gt;没妄想可以原地加密，把整个/全部先转移到移动硬盘存着。按理此时需要进iso仿佛重装怎么可能哈哈，改下root的内核参数直接换个地方操作就是了（然而此时才看到grub的可恶！很会钦定我的root在哪……）。&lt;/p&gt;
&lt;p&gt;所以我觉醒了，喜欢钦点我的内核参数的bootloader闹麻了，&lt;code&gt;Unified kernel image&lt;/code&gt;往里进。不过暂时还没有摆脱就是了，这就看出人的奇异本性：&lt;s&gt;如果没有grub-mkconfig只要自己嗯写bootloader的配置文件其实反而可以容忍，然而有了以后看着它钦点我的启动项和内核参数浑身难受（当然如果找不到好的替代还是可能要自己改grub-mkconfig的各种脚本罢……）。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;解决方案：&lt;a href=&quot;https://github.com/Limine-Bootloader/Limine&quot;&gt;Limine&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;b2sum校验UKI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修改了Limine代码以支持嵌入公钥，用签名验证其配置文件（而不是本身只支持的enroll-config）&lt;/p&gt;
&lt;p&gt;这是为了避免更新内核导致安全启动tpm触发&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;遗留&lt;/h3&gt;
&lt;p&gt;不过安全当然是一整条链，此处大概述为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安全启动&lt;/p&gt;
&lt;p&gt;首先安全启动还是sbctl原样即可，签署了bootloader和UKI（可见bootloader在此只是多余的攻击侧，毕竟UKI可以直接启动，但是我还想给一个选择win的机会……）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;全盘加密&lt;/p&gt;
&lt;p&gt;把TPM也加进去搞成TPM+PIN的解密磁盘（模仿Bitlocker就是了），结论是默认测量7差不多就这样吧。加上一个物理FIDO2密钥+PIN很安全很再加上一个recover key很可恢复就是了。&lt;/p&gt;
&lt;p&gt;然后是分区沿用之前的状态也就是一个一百多G作为根分区，现在是作为一整个加密块里面还是一个btrfs，@和@home子卷。然后在这个加密块后面还有个swap的块（因为之前就是swap分区），也改成luks的块里面放个swap的分区，而且我还要休眠，不然直接随机密钥打开就行了。&lt;/p&gt;
&lt;p&gt;看来看去还是system的initramfs厉害于是把mkinitcpio的钩子换掉(见&lt;a href=&quot;https://wiki.archlinux.org/title/Dm-crypt/System_configuration#mkinitcpio&quot;&gt;dm-crypt/System configuration - ArchWiki&lt;/a&gt;），根目录肯定要在initramfs里就解密掉。看wiki按理crypttab.initramfs是和rd.luks一样都会进initramfs的，然而我只能用rd.luks的内核参数来解密也不知为何。&lt;/p&gt;
&lt;p&gt;然后是swap分区如果不用resume其实可以推到系统启动后再解密然而要resume那么也得进initramfs,解法还是rd.luks嗯写，但是不想在启动阶段输入两次，也不想用同一个密钥。我一开始就决定用链式解锁，即把swap分区的keyfile保存在根分区里，于是这就变成在initramfs阶段就按序解锁加载keyfile了……幸好这居然是可以的，写的是&lt;code&gt;rd.luks.key=SWAP-UUID=/@/keyfilepath:/dev/mapper/root&lt;/code&gt;这种鬼话。&lt;/p&gt;
&lt;p&gt;此处一发现：rd.luks加的根分区不必在option里指定tpm加入有TPM的key就会尝试调用，我option里只是FIDO2，无插卡时自动先TPM，option并无TPM。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后是把全部内核参数拉出来放到生成UKI要用，mkinitcpio生成UKI，在sbctl里sign注册。&lt;/p&gt;
&lt;p&gt;于是linux的内核镜像和微码什么就不存在/boot占用空间了，改一下linux.preset什么的把什么ALL_kver什么ALL_microcode的移到加密目录里不要露出。&lt;/p&gt;
&lt;p&gt;于是grub总算侦测不到启动项，那么手动往/etc/grub.d/40_custom（当然40被改了优先级不能这么低排序很低）加UKI的启动项（链式引导）。&lt;/p&gt;
&lt;p&gt;这样一来总算是的win下没法直接访问arch的系统啦（本来有个WinBtrfs）太可喜可贺太安全了……个鬼。。。（不过还是可以wsl解luks）&lt;/p&gt;
&lt;p&gt;由此整条linux的启动链还算可靠了。&lt;/p&gt;
&lt;h2&gt;美化&lt;/h2&gt;
&lt;p&gt;顺手加了个Plymouth并且把loglevel，quiet全拉上了，启动时再也不看黑屏了……&lt;/p&gt;
&lt;h2&gt;急救&lt;/h2&gt;
&lt;p&gt;我去今天是真的爆了。&lt;/p&gt;
&lt;p&gt;几天不看今天一启动就进不去系统，一看内核镜像里没有解密钩子？怎么会事呢明明感觉记得上次生成时hook配置正确的，反正总之爆了得恢复。&lt;/p&gt;
&lt;p&gt;看了上文就知道我根目录加密……不过有恢复key，从我的离线存储（找了半天丢哪里了）打开多级加密，才能找到key。往U盘写个arch iso，关了安全启动进入，然后手动解密根目录（btrfs还得分次挂载），arch-chroot进入改一下hook重新生成镜像，完毕。&lt;/p&gt;
&lt;p&gt;这次意外倒也证明了我的恢复设计无误，安全性也可接受。但是意外的是，重新打开安全启动（按理每次操作安全启动状态都会不可逆改变PCR）竟然并无触发TPM（考虑到有PIN码所以也不致命？），真是奇异……&lt;/p&gt;
&lt;h2&gt;新论&lt;/h2&gt;
&lt;p&gt;最近又折腾了一会，首先，各WM的合成器其实多少都沾点。Nvidia+wayland就是个……反而是Kwin说不定是真实。&lt;/p&gt;
&lt;p&gt;然后是全盘加密无需内核参数啦解密，移入&lt;code&gt;/etc/crypttab.initramfs&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;swap改为使用swapfile，这样减少了一个解密分区。&lt;/p&gt;
&lt;p&gt;&lt;s&gt;&lt;code&gt;nwg-shell&lt;/code&gt;系列的组件可用之，用其作为通知和状态栏，不过状态栏可能还是&lt;code&gt;waybar&lt;/code&gt;。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;改为使用&lt;a href=&quot;https://danklinux.com/&quot;&gt;dms-shell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;display manager推一个&lt;a href=&quot;https:z/github.com/fairyglade/ly&quot;&gt;ly&lt;/a&gt;，虽简单但轻便，zig。&lt;/p&gt;
&lt;p&gt;然后也试用一段时间&lt;code&gt;niri&lt;/code&gt;，&lt;s&gt;平铺的逻辑其实不太懂，成熟弗如hyprland。&lt;/s&gt;&lt;br /&gt;
我觉得我已经玩明白了。&lt;/p&gt;
&lt;p&gt;&lt;s&gt;此外强推catppuccin的主题，对我们无审美码区好用。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;使用了&lt;a href=&quot;https://github.com/dylanaraps/matugen&quot;&gt;matugen&lt;/a&gt;
以实现自动根据壁纸生成颜色主题&lt;/p&gt;
&lt;p&gt;壁纸使用&lt;a href=&quot;https://codeberg.org/LGFae/awww&quot;&gt;awww&lt;/a&gt;以及自行编写脚本自动切换&lt;/p&gt;
&lt;h2&gt;虚拟机&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;virt-manager&lt;/code&gt;，运行windows中，这已经允许我彻底取代——虽然还不至于。&lt;/p&gt;
&lt;h2&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arch.icekylin.online/&quot;&gt;archlinux 简明指南&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/&quot;&gt;arch wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://asus-linux.org/&quot;&gt;asus-linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sspai.com/post/78916&quot;&gt;现代化的 Archlinux 安装，Btrfs、快照、休眠以及更多&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://archlinuxstudio.github.io/ArchLinuxTutorial/#/&quot;&gt;Arch Linux 安装使用教程 - ArchTutorial - Arch Linux Studio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Arch</category><category>Linux</category></item><item><title>Keyoxide介绍</title><link>https://blog.wind-mask.com/blog/Keyoxide%E4%BB%8B%E7%BB%8D/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/Keyoxide%E4%BB%8B%E7%BB%8D/zh_cn/</guid><description>介绍一下Keyoxide这个去中心在线身份验证工具。</description><pubDate>Fri, 05 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;关于这一服务在中文世界似乎还没有绍介，倒是在github和一些Fediverse上能见到用户使用。
类似的keybase服务我之前尝试时由于它不支持pgp子密钥还是什么pgp的功能所以没有使用，另一方面Keyoxide的设计的确更加去中心和自主。
姑且对此做了一些工作（包括中文翻译和用另一种语言对其协议的实现），因此现在来介绍一下。&lt;/p&gt;
&lt;p&gt;准确细节，文档，代码参见官方网站&lt;a href=&quot;https://keyoxide.org/&quot;&gt;Keyoxide&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;如官方言：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Keyoxide is a privacy-friendly tool to create and verify decentralized online identities.
Just like passports for real life identities, Keyoxide can be used to verify the online identity of people to make sure one is interacting with whom they are supposed to be and not imposters.
Unlike real life passports, Keyoxide works with online identities or &quot;personas&quot;, meaning these identities can be anonymous and one can have multiple separate personas to protect their privacy, both online and in real life.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我解释之为：&lt;code&gt;Keyoxide&lt;/code&gt;是实现这样一种目的，即联系一个身份各种渠道的一致性：以密码学和去中心的托管以及允许代理或自行验证来保证一个身份在多个渠道的一致性。
它不是也不能证明你是你，而是&lt;em&gt;&lt;strong&gt;证明多个渠道（或其控制人）可由同一个密钥的掌控者控制&lt;/strong&gt;&lt;/em&gt;。简而言之，也就是说，证明A平台上某账号和B平台某账号是同一个人（渠道有更多含义如一个域名）。&lt;/p&gt;
&lt;h2&gt;规范&lt;/h2&gt;
&lt;p&gt;就身份的配置构成上，&lt;code&gt;Keyoxide&lt;/code&gt;使用&lt;a href=&quot;https://ariadne.id/&quot;&gt;Ariadne Spec&lt;/a&gt;，以解释在线身份的构成格式。&lt;/p&gt;
&lt;p&gt;在深究原链接后面的规范前，你也可以先听信我的简单解释：一个在线身份就是一个用密钥签名（相关知识可参见任何讲述非对称密码学的科普）了的身份文档，文档由一些：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;元数据，表明使用的密码学信息，以及这是一个在线身份文档&lt;/li&gt;
&lt;li&gt;Claims,宣称，即对一些在线渠道，账户的身份的宣称，例如宣称一个域名属于此身份或一个github账户属于此身份。&lt;/li&gt;
&lt;li&gt;用户愿意记录的个人信息如邮箱简介头像链接等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后文档被签名并分发。
那么怎么验证这些渠道确实属于此身份呢？
对于各种不同的服务商和渠道，有不同的api或方式可公开获取所有者才能控制的信息，例如对域名以dns中txt的记录，对于github则是账户的公开gist。在这些信息中所有者记录特定的proof：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An identity proof may be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an URI representation of a cryptographic key&apos;s identifier&lt;/li&gt;
&lt;li&gt;a cryptographic hash of a URI representation of a cryptographic key&apos;s identifier&lt;/li&gt;
&lt;li&gt;an URL pointing to a web representation of an Ariadne Identity Profile&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;换而言之就是所有者在账户中记录了用于签名profile文档的uri（类似与密钥的指纹）或这个uri的哈希或指向profile文档的链接。
这样，得到了签名profile文档的人可以获取其中各claim的账户是否有按规范放置的proof,如果得到即证明对应渠道确属于此身份控制。&lt;/p&gt;
&lt;h3&gt;格式&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Claim&lt;/code&gt;的格式为&lt;code&gt;proof@ariadne.id=CLAIM&lt;/code&gt;，其中&lt;code&gt;CLAIM&lt;/code&gt;内容请参照各&lt;a href=&quot;https://docs.keyoxide.org/service-providers/&quot;&gt;Available claims/proofs&lt;/a&gt;中的要求。
&lt;code&gt;proof&lt;/code&gt;（这是指放在你的各个账号里的，&lt;code&gt;Claim&lt;/code&gt;里的&lt;code&gt;proof@...&lt;/code&gt;就是字面）的格式则有几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;URI：&lt;code&gt;openpgp4fpr:3637202523e7c1309ab79e99ef2dc5827b445f4b&lt;/code&gt;（对后文&lt;code&gt;ASP&lt;/code&gt;则是&lt;code&gt;aspe:domain.tld:ASPFINGERPRINT&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;Hashed URI：&lt;code&gt;$argon2id$v=19$m=16,t=2,p=1$UElOT0ZIU09mSHlReE1lcg$2nJmgFL0s3DHPksuSE2enw&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Message：&lt;code&gt;[Verifying my cryptographic key: FINGERPRINT_URI]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Profile URL：&lt;code&gt;https://keyoxide.org/FINGERPRINT&lt;/code&gt; or &lt;code&gt;https://keyoxide.org/EMAIL &lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;上述格式都是对于pgp密钥而言，其中&lt;code&gt;FINGERPRINT&lt;/code&gt;就是你的公钥指纹（小写？）（关于pgp的知识请参见各种科普），而&lt;code&gt;FINGERPRINT_URI&lt;/code&gt;就是&lt;code&gt;openpgp4fpr:FINGERPRINT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Hashed UR&lt;/code&gt;就是对URI的&lt;code&gt;argon2&lt;/code&gt;或&lt;code&gt;bcrypt&lt;/code&gt;哈希&lt;/li&gt;
&lt;li&gt;Message中其他内容无关紧要，重要的就是含有&lt;code&gt;FINGERPRINT_URI&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Profile URL&lt;/code&gt;是特定&lt;code&gt;Keyoxide&lt;/code&gt;实例提供的profile页面链接，也可以进行重定向。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;OpenPGP下的使用&lt;/h2&gt;
&lt;p&gt;首先，你需要一个OpenPGP的密钥，这一步不是本文要讲述的，参见其他指南。
接下来，你需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gpg --edit-key FINGERPRINT
uid N
notation
然后在`notation`里一行放置一个`proof@ariadne.id=CLAIM`，放置一些`Claim`.
save
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后将公钥上传到 &lt;code&gt;keys.openpgp.org&lt;/code&gt; 或 &lt;code&gt;Web Key Directory&lt;/code&gt;。
请记得按&lt;a href=&quot;https://docs.keyoxide.org/service-providers/&quot;&gt;Available claims/proofs&lt;/a&gt;中的要求更新你的各个渠道的信息，否则验证的结果就是失败了。
然后在&lt;a href=&quot;https://keyoxide.org/&quot;&gt;Keyoxide&lt;/a&gt;就可以搜索密钥id指纹或邮箱以获取你的profile文档了。&lt;/p&gt;
&lt;h2&gt;Ariadne Signature Profile&lt;/h2&gt;
&lt;p&gt;除了OpenPGP外，也单独提供了一种规范用于给出签名&lt;code&gt;profile&lt;/code&gt;文档，我以为在PGP公钥里注释并非最好选择，但是新的格式亦有推广之难，读者自行考量。
这种方法采用&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc7515&quot;&gt;JSON Web Signature (JWS)&lt;/a&gt;来签名身份文档，从而有了更广泛实现而不依赖于特定的OpenPGP实现；支持更先进的密码学原语。
按规范&lt;code&gt;ASP&lt;/code&gt;只采用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;algorithm: &quot;EdDSA&quot;, curve: &quot;Ed25519&quot; (&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc8037&quot;&gt;RFC8037&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;algorithm: &quot;ES256&quot;, curve: &quot;P-256&quot;
这两种&lt;code&gt;JWS&lt;/code&gt;的签名算法和曲线的组合。
并且使用在&lt;code&gt;JWS&lt;/code&gt;中包含&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc7517&quot;&gt;&lt;code&gt;JWK&lt;/code&gt;&lt;/a&gt;格式的公钥。
从而使用所谓&lt;code&gt;Profile JWS&lt;/code&gt;,必须以&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc7515&quot;&gt;RFC7515&lt;/a&gt;第 3.1 节中定义的紧凑序列化(Compact Serialization)进行序列化。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在&lt;code&gt;Profile jWS header&lt;/code&gt;中：
&lt;code&gt;typ&lt;/code&gt;=&lt;code&gt;JWT&lt;/code&gt;
&lt;code&gt;alg&lt;/code&gt;=签名算法，见&lt;a href=&quot;https://www.iana.org/assignments/jose/jose.xhtml&quot;&gt;IANA-JOSE&lt;/a&gt;
&lt;code&gt;jwk&lt;/code&gt;=&lt;code&gt;JWK&lt;/code&gt;格式的公钥（即一种表示公钥的json）
&lt;code&gt;kid&lt;/code&gt;=公钥的按本规范特定的指纹，见下文&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Profile JWS payload&lt;/code&gt;中则带上name，claims，description等负载作为内容（具体格式参见&lt;a href=&quot;https://ariadne.id/related/ariadne-signature-profile-0/&quot;&gt;Ariadne Signature Profile v0&lt;/a&gt;）&lt;/p&gt;
&lt;h3&gt;ASP fingerprint&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ASP&lt;/code&gt;的指纹按&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc7638.html&quot;&gt;RFC7638&lt;/a&gt;中计算&lt;code&gt;JWK&lt;/code&gt;指纹的方法取&lt;code&gt;SHA512&lt;/code&gt;作为哈希算法得到RFC规范中的指纹后，取其前16个字节作无填充的&lt;code&gt;BASE32&lt;/code&gt;得到&lt;code&gt;ASP&lt;/code&gt;的指纹。
指纹应大小写皆可，代码中以转为大写为准。&lt;/p&gt;
&lt;h3&gt;ASPE服务器与客户端&lt;/h3&gt;
&lt;p&gt;有了&lt;code&gt;ASP&lt;/code&gt;后只要能公开获取它就可以按与OpenPGP中身份文档同样的方法验证了。
规范定义了&lt;code&gt;Ariadne Signature Profile Exchange Protocol&lt;/code&gt;，从而假定一种可以通过api进行交互的服务端可用于上传，保存公开获取&lt;code&gt;ASP&lt;/code&gt;。
按照此交换协议客户端与服务端交互并上传更新或删除&lt;code&gt;ASP&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;验证&lt;/h3&gt;
&lt;p&gt;假定你成功上传了一份&lt;code&gt;ASP&lt;/code&gt;，其指纹为&lt;code&gt;ASPFINGERPRINT&lt;/code&gt;，所在的ASPE服务端域名为&lt;code&gt;domain.tld&lt;/code&gt;。，则这份&lt;code&gt;ASP&lt;/code&gt;将有一个&lt;code&gt;ASPE URI&lt;/code&gt;表示为&lt;code&gt;aspe:domain.tldASPFINGERPRINT&lt;/code&gt;。
此时在&lt;a href=&quot;https://keyoxide.org/&quot;&gt;Keyoxide&lt;/a&gt;上输入这个&lt;code&gt;ASPE URI&lt;/code&gt;即可验证其。&lt;/p&gt;
&lt;h3&gt;ASP使用方法&lt;/h3&gt;
&lt;p&gt;那么问题就来了，怎么构造&lt;code&gt;ASP&lt;/code&gt;，又怎么把它上传到服务端？
首先，&lt;code&gt;keyoxide.org&lt;/code&gt;这个域名就是一个&lt;code&gt;ASPE&lt;/code&gt;服务端，也就是说只要你按协议就可以与之交互。
一是在&lt;a href=&quot;https://asp.keyoxide.org/&quot;&gt;asp.keyoxide&lt;/a&gt;提供了一个在线web界面可以用于生成&lt;code&gt;ASP&lt;/code&gt;并上传到指定域名的服务端，不过其支持的claim渠道有限（至少几个月前我看是），无法完全自定义。
二是&lt;a href=&quot;https://codeberg.org/keyoxide/kx-aspe-cli&quot;&gt;kx-aspe-cli&lt;/a&gt;，不过也只支持很有限的设计。
如果你想在本地自定义&lt;code&gt;ASP&lt;/code&gt;（但是当然要按服务商渠道自己给出claim以及编辑配置文件）甚至自己生成密钥的话，我之前写了一个命令行工具以达到目的：&lt;a href=&quot;https://codeberg.org/wind_mask/aspe-client-go&quot;&gt;aspe-client-go&lt;/a&gt;，我本人使用已确定现在与&lt;code&gt;keyoxide.org&lt;/code&gt;可交互（当然也包括我后文将提到的我自己写的服务端）。&lt;/p&gt;
&lt;h2&gt;推销&lt;/h2&gt;
&lt;p&gt;如果你有意推广这一工具和协议的使用，可参加其服务端的托管，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Keyoxy&lt;/code&gt;的实例，即可以验证身份配置文档的服务&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ASPE&lt;/code&gt;服务端，可以存储和公开提供&lt;code&gt;ASP&lt;/code&gt;
前者的指南参见&lt;a href=&quot;https://docs.keyoxide.org/guides/self-hosting/&quot;&gt;Self-hosting Keyoxide&lt;/a&gt;
后者有&lt;a href=&quot;https://codeberg.org/keyoxide/aspe-server-rs&quot;&gt;aspe-server-rs&lt;/a&gt;，但似乎还没集成数据存储，我写了一个实现&lt;a href=&quot;https://codeberg.org/wind_mask/aspe-server-go&quot;&gt;aspe-server-go&lt;/a&gt;,应该已经实现了api和存储。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Keyoxide</category><category>PGP</category><category>Technical</category></item><item><title>wind_mask&apos;s GeekGame 2024</title><link>https://blog.wind-mask.com/blog/wind_mask&apos;s%20GeekGame%202024/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/wind_mask&apos;s%20GeekGame%202024/zh_cn/</guid><description>做了一下GeekGame 2024</description><pubDate>Mon, 21 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;wind_mask&apos;s GeekGame 2024&lt;/h1&gt;
&lt;p&gt;懒狗发作了，因此一切完整性都不做保证。还是一样的没有过程中的记录，除了留下的混乱的文件夹。
期间上了三个早八，除此之外则必须睡到中午。&lt;/p&gt;
&lt;h2&gt;各题幻&lt;/h2&gt;
&lt;h3&gt;签到（囯内）&lt;/h3&gt;
&lt;p&gt;懒狗从一开始就已经发作，懒得解压，懒得看内容，也不知道怎么把记录也丢了。总之，让AI写一个递归解压缩的脚本，然后搜索flag。&lt;/p&gt;
&lt;h3&gt;清北问答&lt;/h3&gt;
&lt;p&gt;论俄苏的艺术。&lt;/p&gt;
&lt;p&gt;不在于关注细节，因为那都是有意为之泄露的，以皮套言叫营业炒作。必须从人们自己都意识不到的泄露中洞察。&lt;/p&gt;
&lt;h4&gt;在清华大学百年校庆之际，北京大学向清华大学赠送了一块石刻。石刻最上面一行文字是什么？&lt;/h4&gt;
&lt;p&gt;尽管说是这么一说，但是第一题一开始根本没搜到,直到
&lt;img src=&quot;/wind_masks-geekgame-2024/2024-10-21%2013_44_43-%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6%E5%90%91%E6%B8%85%E5%8D%8E%E5%A4%A7%E5%AD%A6%E8%B5%A0%E9%80%81%20-%20Google%20%E6%90%9C%E7%B4%A2.avif&quot; alt=&quot;清华北大友谊长在石&quot; /&gt;
才知道。&lt;/p&gt;
&lt;h4&gt;有一个微信小程序收录了北京大学的流浪猫。小程序中的流浪猫照片被存储在了哪个域名下？&lt;/h4&gt;
&lt;p&gt;这是个被炒作过的东西，随意可查到小程序或源代码，我知道可以抓个包什么，但是懒狗，看源码吧。
&lt;img src=&quot;/wind_masks-geekgame-2024/2024-10-21%2013_57_31-miniprogram_app.js%20%C2%B7%20circlelq_%E5%8C%97%E5%A4%A7%E7%8C%AB%E5%8D%8F%E4%BD%BF%E7%94%A8%E7%9A%84%E7%87%95%E5%9B%AD%E7%8C%AB%E9%80%9F%E6%9F%A5%E6%89%8B%E5%86%8C%E5%B0%8F%E7%A8%8B%E5%BA%8F%20-%20Gitee.com.avif&quot; alt=&quot;gitee上源码&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;globalData: {
    isAdministrator: false,
    Administrator: undefined,
    url: &quot;https://pku-lostangel.oss-cn-beijing.aliyuncs.com/&quot;,
  },
  mpServerless
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;在 Windows 支持的标准德语键盘中，一些字符需要同时按住 AltGr 和另一个其他按键来输入。需要通过这种方式输入的字符共有多少个？&lt;/h4&gt;
&lt;p&gt;微软的官方文档，不多说，但是我数错两次。
&lt;img src=&quot;/wind_masks-geekgame-2024/2024-10-21%2013_59_52-German%20Keyboard%20-%20Globalization%20_%20Microsoft%20Learn.avif&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;比赛平台的排行榜顶部的图表是基于 @antv/g2 这个库渲染的。实际使用的版本号是多少？&lt;/h4&gt;
&lt;p&gt;在官方的前端仓库看package.json就行了。&lt;/p&gt;
&lt;h4&gt;在全新安装的 Ubuntu Desktop 22.04 系统中，把音量从 75% 调整到 25% 会使声音减小多少分贝？（保留一位小数）&lt;/h4&gt;
&lt;p&gt;说是全新安装就是全新安装，虚拟机启动。
&lt;img src=&quot;/wind_masks-geekgame-2024/2024-10-21%2014_04_47-Ubuntu%2064%20%E4%BD%8D%20-%20VMware%20Workstation.avif&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;这张照片用红框圈出了一个建筑。离它最近的已开通地铁站是什么？&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://prob01.geekgame.pku.edu.cn/static/osint-challenge.webp&quot; alt=&quot;这张照片&quot; /&gt;
洞察，就是本质。&lt;/p&gt;
&lt;p&gt;七星公馆,260-330m2。无脑认为在北京，事实上搜索即可。
地图功能：查找附近的xx，只需一个字：塔，答案是燃灯古佛塔。
附近的地铁站，结束。&lt;/p&gt;
&lt;p&gt;真实，就是真实的真实，就是事实。&lt;/p&gt;
&lt;h3&gt;大模型模型虎视眈眈&lt;/h3&gt;
&lt;p&gt;你们是语言的工具，而我是语言的主人。
&lt;img src=&quot;/wind_masks-geekgame-2024/2024-10-21%2014_14_45-%E7%94%B5%E9%A3%8E%E6%89%87%20%C2%B7%20Plus.avif&quot; alt=&quot;emoji hack&quot; /&gt;
所谓语言，就是权力。
之后的第二问沿用：
&lt;img src=&quot;/wind_masks-geekgame-2024/2024-10-21%2014_19_11-%E7%94%B5%E9%A3%8E%E6%89%87%20%C2%B7%20Plus.avif&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;熙熙攘攘我们的天才吧&lt;/h3&gt;
&lt;h4&gt;Magic Keyboard&lt;/h4&gt;
&lt;p&gt;不幸的，我完全不懂音视频，甚至连virtual keyboard code的表也玩不转，只能手动对照keycode输出flag1。
之后两题无。&lt;/p&gt;
&lt;h3&gt;TAS概论大作业&lt;/h3&gt;
&lt;h4&gt;你过关&lt;/h4&gt;
&lt;p&gt;当然去找现成的TAS，然后&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def input_to_byte(input_str):
    # 从最低位到最高位依次表示是否按下 A、B、选择、开始、上、下、左、右键
    buttons = [&quot;A&quot;, &quot;B&quot;, &quot;S&quot;, &quot;T&quot;, &quot;U&quot;, &quot;D&quot;, &quot;L&quot;, &quot;R&quot;]
    byte = 0
    for i, button in enumerate(buttons):
        if button in input_str:
            byte |= 1 &amp;lt;&amp;lt; i
    return byte
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显然是AI生成给我的代码。&lt;/p&gt;
&lt;p&gt;此处注意第0帧是要删除还是什么来着，总之第0帧有什么要怎么怎么。
现成的速通到确定通关的一帧就接受，要加些空白等到公主。&lt;/p&gt;
&lt;h4&gt;只有神知道的世界&lt;/h4&gt;
&lt;p&gt;进入负世界的方式很容易找到，速通一般都用了wrap的管道，因此直接在本地模拟器里播放，到达时切换到手操record下来即可。&lt;/p&gt;
&lt;h3&gt;验证码&lt;/h3&gt;
&lt;p&gt;我还以为浏览器打印是非预期的呢。&lt;/p&gt;
&lt;p&gt;提前打开控制台，由于我的浏览器很卡因此可以手动在合适时刻暂停js，然后把页面上的验证码部分的div复制走然后在一个空的html文件里，打开，浏览器打印，复制。&lt;/p&gt;
&lt;h3&gt;Fast Or Clever&lt;/h3&gt;
&lt;p&gt;我是一条懒狗，尽管显然有Time-of-check to time-of-use的问题，但我心烦意乱，让我们&lt;code&gt;openssl rand -hex 249&lt;/code&gt;，然后随便写点：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;payload = (
&quot;60b0c059823bb76f6f39fc4345b80b64e2cb4671bcb31e371b67aac6cfe8bf1eed796ad918b91d9f4cd69d33000f62703191ecec947ea361aa07daf44561d138c13600264b4cb9e348a7194c70b4e708a94d0128195677e862f6f398b3477689f20c8d872c5723817eeded730bc9e233f38126edd4ea4203579cee7828b19e5f852b05b2edd5bc0052ac432c55150a28ecdac81518287b3ffa756fa2c5ca74cb07fdd0ba2e45c6325891600b206f53f5e03f3c4ae05217e2c3235165fd0a02b1bc42bfbd454237159b3bdca94cf49204735ad68a9f2763abc2ed7780ef346a0fad37a62e43b77873f37863b9c27f6e66113059660764216c2edf14294c49eb82😒&quot;
).encode()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后提交，然后就过了。&lt;/p&gt;
&lt;h3&gt;从零开始学Python&lt;/h3&gt;
&lt;p&gt;是的使用&lt;code&gt;pyinstxtractor-ng&lt;/code&gt;，然后你会得到&lt;code&gt;pymaster.pyc&lt;/code&gt;，然后&lt;code&gt; uncompyle6&lt;/code&gt;，即可得到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if random.randint(0, 65535) != 54830:
    exec(marshal.loads(base64.b64decode(
b&quot;YwAAAAAAAAAAAAAAAAAAAAAFAAAAQAAAAHMwAAAAZABaAGUBZAGDAWUCZQNkAoMBZAODAmUCZQNkBIMBZAWDAmUAgwGDAYMBAQBkBlMAKQdztAQAAGVKekZWMTFQMnpBVWZhL1UvMkN5bDBSanlCV3NiR2g3R0N2ZFlCMHBHNkFGeEt5MGRkdWdORUg1Z0VRVC8zMTIzQ1NPN1RSdDBiUlVhdFBjYzI5OGo0K3ZyNTNGZ3g5RUlMQzlpYjlvdHh6MmQyU0h1SHZRYnJWYnI4RFV0V2NkOEJGbzlPWlA2c2ZvVTdDUG9xOG42THY5OHhJSHlPeWpvWFU0aDk2elJqM2FyYkZyaHlHd0oyZGZnc3RmcG5WKzFHNEJjazN3RkNEa2VFNkVrRjVZaDd2QUpGZjJEWTBsbEY0bFlvOEN5QWpvVDUwZE1qdXNzVVBxZis1N1dHMkhacE1kRm5aRmhxUFZHZFprZFVvdUxtb2VvSXhhSWFtNDkvbHdUM1BIeFp5TnBickRvbkk0ZWpsVEViZ2tSb21XUENoTzhpZkVLZnlFUkl0YlR4Y0NHTEl2ZGtQVlVPcENYamVFeEM1SlFwZmpOZWVsOFBFbUV0VXFaM1VFUTVIVldpVFZNYlVOdzF2VEFWOU1COXlPRG1tQ042SGpuNm5qNVhSc3FZNm1qT3I4bW9XaFhIYmJydUoxaDY0b2U5ZVZzcGZ3eEtTa1hDWUMvVWxlblZPQlZUS3o3RkZOT1dUR2ZHOUl1TGNVejdLYlNzUmtWY21VYTN0YUFqS3BKZFF6cWEyZG5FVjBsbWFueE1JcU5zMzlrd3BKTEtWVVNibTNCdVdtUUxtWlV3NWx5dUVxeXVGL3BSeXVTK05LeWswRjVYQWp5cE5OT2lCU2hiaDJTdWZRQ25ETWd4a3RKVXJaQ1FsTlJGd3plMHZmRWllMUYxbWY5b0ZEWkozYnFySlNHV3lzcUl0TmRVa09vR29CODNJTUpIVnRwSzB5bmlDeVplTExBaStsek10R0hVTktrbGVseWtWVllMbUcwVGRZbzFyUjNBVnZYNzR2SlBGSG1zYitWUHM5V1FVaGVFM1FhWVJEL2JiQ0xSbm03K1VaWW8vK09GNmt3MTBBazM3ZnVET0VBTXJ4WlBTc2pjeUZIK0FvRGp3UUtwSk5TNWY3UEZtMWF1NjVOU0t0anpYV3hvcDFRUWlWV2VrWVZIQmlJVnB2U1NpVTByd1V1RXc1clJRN3NFQmNUNWZvdXVjamovUmkzeTZlelFuQThSN2lTTmVHTGlhSFI0QzlDQWNnbXVQcy9IZ0V0TUtKY09KaWJzZVpHNVRUL1M2WDFrTkFxZEl1Z3hUWU05dnhkalJPR1d6T1pjSE9iNC9lM3RGUTdLQ3FBVC9nalc4NnpQaXNiZm9pOW1US2h4dVFiTG5ncXByTmNaM29uQWo4aFc3c2tyRk5TZ1lHaHNHL0JkSGdCRHJET2t3NlVMMGxWT1F0elljRDFJdUhTZDBRMEZlMEJtUW4vcjFSOTJDQ3gvNEU2OXJoeWRqOVlRMVB6YkQzT0lpdGI3M2hZSGpqd0xQUndEcCtQN3J3MzMyKzZibjl4NmRqQ3g2T3crNXBUaDAvSjA2bEE3NlNtYmY4R016OHFCREtmakVEZ3RLVk0wVS9EajF5ZS9ZQ0kwUmZwaUcwSUdhRU5GSEVQYXJidjV1T0tGVT3aBGV4ZWPaBHpsaWLaCmRlY29tcHJlc3PaBmJhc2U2NNoJYjY0ZGVjb2RlTikE2gRjb2Rl2gRldmFs2gdnZXRhdHRy2gpfX2ltcG9ydF9fqQByCQAAAHIJAAAA2gDaCDxtb2R1bGU+AQAAAHMKAAAABAEGAQwBEP8C/w==&quot;
)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后里面这些垃圾需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dis.disassemble(marshal.loads(base64.b64decode(
b&quot;YwAAAAAAAAAAAAAAAAAAAAAFAAAAQAAAAHMwAAAAZABaAGUBZAGDAWUCZQNkAoMBZAODAmUCZQNkBIMBZAWDAmUAgwGDAYMBAQBkBlMAKQdztAQAAGVKekZWMTFQMnpBVWZhL1UvMkN5bDBSanlCV3NiR2g3R0N2ZFlCMHBHNkFGeEt5MGRkdWdORUg1Z0VRVC8zMTIzQ1NPN1RSdDBiUlVhdFBjYzI5OGo0K3ZyNTNGZ3g5RUlMQzlpYjlvdHh6MmQyU0h1SHZRYnJWYnI4RFV0V2NkOEJGbzlPWlA2c2ZvVTdDUG9xOG42THY5OHhJSHlPeWpvWFU0aDk2elJqM2FyYkZyaHlHd0oyZGZnc3RmcG5WKzFHNEJjazN3RkNEa2VFNkVrRjVZaDd2QUpGZjJEWTBsbEY0bFlvOEN5QWpvVDUwZE1qdXNzVVBxZis1N1dHMkhacE1kRm5aRmhxUFZHZFprZFVvdUxtb2VvSXhhSWFtNDkvbHdUM1BIeFp5TnBickRvbkk0ZWpsVEViZ2tSb21XUENoTzhpZkVLZnlFUkl0YlR4Y0NHTEl2ZGtQVlVPcENYamVFeEM1SlFwZmpOZWVsOFBFbUV0VXFaM1VFUTVIVldpVFZNYlVOdzF2VEFWOU1COXlPRG1tQ042SGpuNm5qNVhSc3FZNm1qT3I4bW9XaFhIYmJydUoxaDY0b2U5ZVZzcGZ3eEtTa1hDWUMvVWxlblZPQlZUS3o3RkZOT1dUR2ZHOUl1TGNVejdLYlNzUmtWY21VYTN0YUFqS3BKZFF6cWEyZG5FVjBsbWFueE1JcU5zMzlrd3BKTEtWVVNibTNCdVdtUUxtWlV3NWx5dUVxeXVGL3BSeXVTK05LeWswRjVYQWp5cE5OT2lCU2hiaDJTdWZRQ25ETWd4a3RKVXJaQ1FsTlJGd3plMHZmRWllMUYxbWY5b0ZEWkozYnFySlNHV3lzcUl0TmRVa09vR29CODNJTUpIVnRwSzB5bmlDeVplTExBaStsek10R0hVTktrbGVseWtWVllMbUcwVGRZbzFyUjNBVnZYNzR2SlBGSG1zYitWUHM5V1FVaGVFM1FhWVJEL2JiQ0xSbm03K1VaWW8vK09GNmt3MTBBazM3ZnVET0VBTXJ4WlBTc2pjeUZIK0FvRGp3UUtwSk5TNWY3UEZtMWF1NjVOU0t0anpYV3hvcDFRUWlWV2VrWVZIQmlJVnB2U1NpVTByd1V1RXc1clJRN3NFQmNUNWZvdXVjamovUmkzeTZlelFuQThSN2lTTmVHTGlhSFI0QzlDQWNnbXVQcy9IZ0V0TUtKY09KaWJzZVpHNVRUL1M2WDFrTkFxZEl1Z3hUWU05dnhkalJPR1d6T1pjSE9iNC9lM3RGUTdLQ3FBVC9nalc4NnpQaXNiZm9pOW1US2h4dVFiTG5ncXByTmNaM29uQWo4aFc3c2tyRk5TZ1lHaHNHL0JkSGdCRHJET2t3NlVMMGxWT1F0elljRDFJdUhTZDBRMEZlMEJtUW4vcjFSOTJDQ3gvNEU2OXJoeWRqOVlRMVB6YkQzT0lpdGI3M2hZSGpqd0xQUndEcCtQN3J3MzMyKzZibjl4NmRqQ3g2T3crNXBUaDAvSjA2bEE3NlNtYmY4R016OHFCREtmakVEZ3RLVk0wVS9EajF5ZS9ZQ0kwUmZwaUcwSUdhRU5GSEVQYXJidjV1T0tGVT3aBGV4ZWPaBHpsaWLaCmRlY29tcHJlc3PaBmJhc2U2NNoJYjY0ZGVjb2RlTikE2gRjb2Rl2gRldmFs2gdnZXRhdHRy2gpfX2ltcG9ydF9fqQByCQAAAHIJAAAA2gDaCDxtb2R1bGU+AQAAAHMKAAAABAEGAQwBEP8C/w==&quot;
)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后又是一堆垃圾，需要：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# base64 编码的压缩数据
code = b&quot;eJzFV11P2zAUfa/U/2Cyl0RjyBWsbGh7GCvdYB0pG6AFxKy0ddugNEH5gEQT/3123CSO7TRt0bRUatPcc298j4+vr53Fgx9EILC9ib9otxz2d2SHuHvQbrVbr8DUtWcd8BFo9OZP6sfoU7CPoq8n6Lv98xIHyOyjoXU4h96zRj3arbFrhyGwJ2dfgstfpnV+1G4Bck3wFCDkeE6EkF5Yh7vAJFf2DY0llF4lYo8CyAjoT50dMjussUPqf+57WG2HZpMdFnZFhqPVGdZkdUouLmoeoIxaIam49/lwT3PHxZyNpbrDonI4ejlTEbgkRomWPChO8ifEKfyERItbTxcCGLIvdkPVUOpCXjeExC5JQpfjNeel8PEmEtUqZ3UEQ5HVWiTVMbUNw1vTAV9MB9yODmmCN6Hjn6nj5XRsqY6mjOr8moWhXHbbruJ1h64oe9eVspfwxKSkXCYC/UlenVOBVTKz7FFNOWTGfG9IuLcUz7KbSsRkVcmUa3taAjKpJdQzqa2dnEV0lmanxMIqNs39kwpJLKVUSbm3BuWmQLmZUw5lyuEqyuF/pRyuS+NKyk0F5XAjypNNOiBShbh2SufQCnDMgxktJUrZCQlNRFwze0vfEie1F1mf9oFDZJ3bqrJSGWysqItNdUkOoGoB83IMJHVtpK0yniCyZeLLAi+lzMtGHUNKklelykVVYLmG0TdYo1rR3AVvX74vJPFHmsb+VPs9WQUheE3QaYRD/bbCLRnm7+UZYo/+OF6kw10Ak37fuDOEAMrxZPSsjcyFH+AoDjwQKpJNS5f7PFm1au65NSKtjzXWxop1QQiVWekYVHBiIVpvSSiU0rwUuEw5rRQ7sEBcT5fouucjj/Ri3y6ezQnA8R7iSNeGLiaHR4C9CAcgmuPs/HgEtMKJcOJibseZG5TT/S6X1kNAqdIugxTYM9vxdjROGWzOZcHOb4/e3tFQ7KCqAT/gjW86zPisbfoi9mTKhxuQbLngqprNcZ3onAj8hW7skrFNSgYGhsG/BdHgBDrDOkw6UL0lVOQtzYcD1IuHSd0Q0Fe0BmQn/r1R92CCx/4E69rhydj9YQ1PzbD3OIitb73hYHjjwLPRwDp+P7rw332+6bn9x6djCx6Ow+5pTh0/J06lA76Smbf8GMz8qBDKfjEDgtKVM0U/Dj1ye/YCI0RfpiG0IGaENFHEParbv5uOKFU=&quot;
# 解码 base64 数据
decoded_data = base64.b64decode(code)
# 解压缩数据
decompressed_data = zlib.decompress(decoded_data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段显然是AI给我的。
然后才有了&lt;code&gt;# flag1 =xxxx&lt;/code&gt;，里面又是些：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class adJGrTXOYN:

    def __init__(adJGrTXOYP, OOOO, OOO0):

        adJGrTXOYP.OOOO = OOOO

        adJGrTXOYP.OOO0 = OOO0

        adJGrTXOYP.OO0O = None

        adJGrTXOYP.O0OO = None

        adJGrTXOYP.O0O0 = None
......
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们懒狗放心地交给AI来解决。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Node:
    def __init__(self, key, value):
        self.key = key
        self.value = value
        self.parent = None
        self.left = None
        self.right = None
......
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后就够了。
随机数固定了显然是seed，去找&lt;code&gt;random.pyc&lt;/code&gt;,解出来看到了flag2就是seed。
对比是&lt;code&gt;encoded_flag = base64.b64decode(&quot;7EclRYPIOsDvLuYKDPLPZi0JbLYB9bQo8CZDlFvwBY07cs6I&quot;)&lt;/code&gt;。
然后懒狗的大胆猜测这些什么什么的都是些置换而已。
试验一下，&quot;flag{xxxx“之类有5个字节正确了。
那就ok了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def init_and_r(flag_input: str):
    suc = [False] * 36
    tree = BinaryTree()
    random.seed(x)
    y = random.randint(0, 65535)
    assert y == 54830
    if len(flag_input) != 36:
        print(&quot;Try again!&quot;)
        return
    # if flag_input[:5] != &quot;flag{&quot; or flag_input[-1] != &quot;}&quot;:
    #     print(&quot;Try again!&quot;)
    #     return
    for character in flag_input:
        tree.add_item(random.random(), ord(character))
    for _ in range(0x100):
        random_traverse(tree)
    flag_decoded = decode_flag(tree.root)
    for i in range(len(encoded_flag)):
        if flag_decoded[i] == encoded_flag[i]:
            suc[i] = True
    return suc
def guess(index: int):
    global g_flag, true_flag
    successd_index = init_and_r(&quot;&quot;.join(g_flag))
    local_random = random.Random(time.time())
    while True:
        g_flag[index] = chr(local_random.randint(0, 0xFF))
        s = init_and_r(g_flag)
        if successd_index != s:
            print(&quot;success in index&quot;, index)
            print(&quot;flag:&quot;, g_flag[index])
            true_flag += g_flag[index]
            return
        else:
            successd_index = s
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;生活在树上&lt;/h3&gt;
&lt;h4&gt;Level 1&lt;/h4&gt;
&lt;p&gt;我们也就只知道栈溢出了……&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;backdoor_address = 0x401243
# 构造恶意输入
payload = b&quot;A&quot; * 488  # 填充 v5 缓冲区
payload += b&quot;B&quot; * 8  # 填充其他局部变量和栈帧指针
payload += struct.pack(&quot;&amp;lt;Q&quot;, backdoor_address)  # 覆盖返回地址
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是的没错payload都是AI帮我写的。&lt;/p&gt;
&lt;p&gt;栈对齐还加ret？呵呵，让我们直接跳到&lt;code&gt;call system&lt;/code&gt;前两条指令呗。&lt;/p&gt;
&lt;p&gt;懒狗，永远都是。&lt;/p&gt;
&lt;p&gt;然后Level 2什么的反受其害，一直只能跳到fake backdoor，怎么跳就是跳不进我构造的的&lt;code&gt;/bin/sh&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;完美的代码&lt;/h3&gt;
&lt;h4&gt;发现&lt;/h4&gt;
&lt;p&gt;其实我一开始以为问题是size可以为0：szie为0的vec地址就是里面类型的对齐，也就是&lt;code&gt;vec![0; 0].into_boxed_slice()&lt;/code&gt;得到的Box其实ptr的值就是0x4，如果能访问显然会出错。&lt;/p&gt;
&lt;p&gt;但其实如果没有真正的错误，是没法访问的。
手操一下发现跳过了有检查的put直接unchecked put，看来是虚表坏了。
直接看nightly特性和unsafe，大概问题出在trait对象上。
尽管已经拿到任意地址写了，但是懒狗又不想思考怎么利用了。
想着&lt;code&gt;local_data&lt;/code&gt;什么是不是可以溢出到栈上，但是显然虚妄。后来想到应该是修改虚表跳到什么什么去，也懒得思路了。&lt;/p&gt;
&lt;h3&gt;打破复杂度&lt;/h3&gt;
&lt;p&gt;我知道做题，OI，ACM等泛滥了。
卡常，请。&lt;/p&gt;
&lt;h4&gt;关于SPFA—它死了&lt;/h4&gt;
&lt;p&gt;这个真有现成的生成图的代码：&lt;a href=&quot;https://blog.csdn.net/yfzcsc/article/details/77623365&quot;&gt;如何卡SPFA&lt;/a&gt;。&lt;/p&gt;
&lt;h4&gt;Dinic并非万能&lt;/h4&gt;
&lt;p&gt;没有现成，我已无救。
但是知乎上含混不清的回答也可吧：&lt;a href=&quot;https://www.zhihu.com/question/266149721&quot;&gt;如何使最大流的 Dinic 算法达到理论上的最坏时间复杂度？
&lt;/a&gt;
对着这玩意看了半天，其实我还是看不懂。
强行对着写点吧：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cassert&amp;gt;
#include &amp;lt;climits&amp;gt;
#include &amp;lt;fstream&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;list&amp;gt;
#include &amp;lt;tuple&amp;gt;
#include &amp;lt;vector&amp;gt;
const int MAXN = 100;
const int MAXM = 5000;
const int MAXW = 1e9;
using namespace std;

struct edge {
  int to, cap;
  edge *rev;
};
list&amp;lt;edge&amp;gt; E[MAXN + 1];

void add_edge(int u, int v, int cap) {

  edge e1 = {v, cap, nullptr};
  edge e2 = {u, 0, nullptr};
  E[u].push_back(e1);
  E[v].push_back(e2);
  E[u].back().rev = &amp;amp;E[v].back();
  E[v].back().rev = &amp;amp;E[u].back();
}
int main() {
  int n = MAXN; // Number of nodes
  int m = MAXM; // Number of edges
  int s = 1;    // Source
  int t = 100;  // Sink
  int k = 24;
  vector&amp;lt;tuple&amp;lt;int, int, int&amp;gt;&amp;gt; edges;

  for (int i = 2; i &amp;lt;= k + 1; i++) {
    // s连到二分图一侧，另一侧连到t
    add_edge(1, i, k);
    add_edge(i + k, t, k);
    edges.push_back(make_tuple(1, i, k));
    edges.push_back(make_tuple(i + k, t, k));
  } // 二分图为点2到k+1和点k+2到2k+1

  for (int i = 2; i &amp;lt;= k + 1; i++) {
    for (int j = i + k; j &amp;lt;= 2 * k + 1; j++) {
      for (int l = 0; l &amp;lt; 7; l++) {
        add_edge(i, j, 1);
        add_edge(j, i, 1);
        edges.push_back(make_tuple(i, j, 1));
        edges.push_back(make_tuple(j, i, 1));
      }
    }
  }

  // 两个点，与二分图两侧相连，cap为k
  for (int i = 2; i &amp;lt;= k + 1; i++) {
    add_edge(2 * k + 2, i, k);
    add_edge(i, 2 * k + 2, k);
    add_edge(i + k, 2 * k + 3, k);
    add_edge(2 * k + 3, i + k, k);
    edges.push_back(make_tuple(2 * k + 2, i, k));
    edges.push_back(make_tuple(i, 2 * k + 2, k));
    edges.push_back(make_tuple(i + k, 2 * k + 3, k));
    edges.push_back(make_tuple(2 * k + 3, i + k, k));
  }

  int ban = (n - 2 * k - 4) / 2 + 2 * k + 4;

  // 剩下的点构成s到t的路径
  add_edge(1, 2 * k + 4, MAXW);
  edges.push_back(make_tuple(1, 2 * k + 4, MAXW));
  for (int i = 2 * k + 4; i &amp;lt; ban; i++) {
    add_edge(i, i + 1, MAXW);
    edges.push_back(make_tuple(i, i + 1, MAXW));
  }
  for (int i = ban + 1; i &amp;lt;= n - 2; i++) {
    add_edge(i, i + 1, MAXW);
    edges.push_back(make_tuple(i, i + 1, MAXW));
  }
  add_edge(n - 1, n, MAXW);
  edges.push_back(make_tuple(n - 1, n, MAXW));

  // 剩下的点每四个连到二分图一侧
  int flag = 0;
  for (int i = 2 * k + 4; i &amp;lt;= ban; i += 4) {
    add_edge(i, 2 * k + 2 + flag, k * k);
    add_edge(2 * k + 2 + flag, i, k * k);
    edges.push_back(make_tuple(i, 2 * k + 2 + flag, k * k));
    edges.push_back(make_tuple(2 * k + 2 + flag, i, k * k));

    if (flag == 0) {
      flag = 1;
    } else {
      flag = 0;
    }
  }
  for (int i = ban + 1; i &amp;lt;= n - 1; i += 4) {
    add_edge(2 * k + 3 - flag, i, k * k);
    add_edge(i, 2 * k + 3 - flag, k * k);
    edges.push_back(make_tuple(2 * k + 3 - flag, i, k * k));
    edges.push_back(make_tuple(i, 2 * k + 3 - flag, k * k));
    if (flag == 0) {
      flag = 1;
    } else {
      flag = 0;
    }
  }

  // 打印图到文件
  ofstream outfile(&quot;graph.txt&quot;);
  outfile &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; edges.size() &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; s &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; t &amp;lt;&amp;lt; endl;
  for (const auto &amp;amp;e : edges) {
    int u, v, c;
    tie(u, v, c) = e;
    outfile &amp;lt;&amp;lt; u &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; c &amp;lt;&amp;lt; endl;
  }
  outfile.close();

  //   dinic(n, edges.size(), s, t);

  //   cerr &amp;lt;&amp;lt; &quot;Operations: &quot; &amp;lt;&amp;lt; ops &amp;lt;&amp;lt; endl;

  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;嗯，完全不懂，手动艹出来的答案。&lt;/p&gt;
&lt;h3&gt;随机数生成器&lt;/h3&gt;
&lt;h4&gt;C++&lt;/h4&gt;
&lt;p&gt;是的完全的懒狗，我连glibc的rand到底是什么也没找到，因为我看到网上说据说已经从那什么线性同余改善了。
等到提示后，我才能找到源码……然后我干了更无聊的穷举。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import pwn
url = &quot;prob15.geekgame.pku.edu.cn&quot;
port = 10015
token = b&quot;xxxx&quot;
rand = []
conn = pwn.remote(url, port)
line = conn.recvuntil(b&quot;:&quot;)
print(line)
conn.send(token + b&quot;\r\n&quot;)
conn.send(b&quot;\r\n&quot;)
rand.append(int(conn.recvline().strip()))
for i in range(255):
    conn.send(b&quot;\r\n&quot;)
    rand.append(int(conn.recvline().strip()))
assert len(rand) == 256
with open(&quot;rand.txt&quot;, &quot;w&quot;) as f:
    for i in rand:
        f.write(f&quot;{i}\n&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后拿着&lt;code&gt;rand.txt&lt;/code&gt;去穷举吧！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::fs::File;
use std::i32;
use std::io::Read;
struct Rng {
    seed: i32,
    a: i64,
    m: i32,
    v: [i32; 31],
}
impl Rng {
    fn new(seed: i32) -&amp;gt; Rng {
        let mut init = [0; 344];
        let mut rng = Rng {
            seed,
            a: 16807,
            m: 2147483647,
            v: [0; 31],
        };
        init[0] = seed;
        for i in 1..31 {
            init[i] = (rng.a.wrapping_mul(init[i - 1] as i64) % rng.m as i64) as i32;
            if init[i] &amp;lt; 0 {
                init[i] += rng.m;
            }
        }
        for i in 31..34 {
            init[i] = init[i - 31];
        }
        for i in 34..344 {
            init[i] = init[i - 31].wrapping_add(init[i - 3]);
        }
        for i in 0..31 {
            rng.v[i] = init[i + 313];
        }
        rng
    }
    fn next(&amp;amp;mut self) -&amp;gt; i32 {
        let n = self.v[0].wrapping_add(self.v[28]);
        for i in 1..31 {
            self.v[i - 1] = self.v[i];
        }
        self.v[30] = n;
        ((n as u32) &amp;gt;&amp;gt; 1) as i32
    }
}
fn main() {
    let mut f = File::open(&quot;rand.txt&quot;).unwrap();
    let mut contents = String::new();
    f.read_to_string(&amp;amp;mut contents).unwrap();
    let mut lines = contents.lines();
    let mut rand_v = [0; 256];
    for i in 0..256 {
        rand_v[i] = lines.next().unwrap().parse().unwrap();
    }
    let f = &quot;flag{&quot;;
    let mut SEED: i32 = 0;
    let start_time = std::time::Instant::now();
    (0..=u32::MAX)
        .into_par_iter()
        .find_any(|&amp;amp;seed| {
            let mut rng = Rng::new(seed as i32);
            for i in 0..4 {
                if rng.next() != rand_v[i] - f.as_bytes()[i] as i32 {
                    return false;
                }
            }
            return true;
        })
        .map(|seed| {
            println!(&quot;Found seed: {}&quot;, seed);
            SEED = seed as i32;
            println!(&quot;Time: {:?}&quot;, start_time.elapsed());
        });
    let mut rng = Rng::new(SEED);
    let ff=rand_v.map(|v|{
        v-rng.next()
    });
    let flag: String = ff.iter().map(|&amp;amp;b| b as u8 as char).collect();
    println!(&quot;Flag: {}&quot;, flag);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有什么线性方程组，没有什么Z3，没有什么数学——懒狗一无所有。&lt;/p&gt;
&lt;h3&gt;神秘计算器&lt;/h3&gt;
&lt;h4&gt;素数判断函数&lt;/h4&gt;
&lt;p&gt;费马检验，启动。
最后搞出点&lt;code&gt;1-1%((2**n%n-2)**2+1)-1%(n**2/4)+1%((n-341)**2+1)&lt;/code&gt;这种垃圾。&lt;/p&gt;
&lt;h4&gt;Pell数（一）&lt;/h4&gt;
&lt;p&gt;通项公式嗯凑&lt;code&gt;((1+2**(1/2))**(n-1)+1)/8**(1/2)//1&lt;/code&gt;。&lt;/p&gt;
&lt;h4&gt;Pell数（二）&lt;/h4&gt;
&lt;p&gt;这个真得等提示才看到，生成函数哈哈。
大约是&lt;code&gt;2**(2*n*n-2*n)//(2**(4*n-4)-2**(2*n-1)-1)%2**(2*n-2)&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;闲话&lt;/h2&gt;
&lt;p&gt;我处在无边的怠惰中，这是事实。因此，这一切都归于无。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;冠盖满京华，斯人独憔悴。
……
千秋万岁名，寂寞身后事。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><category>GeekGame</category><category>CTF</category></item><item><title>wind_mask&apos;s HackerGame 2023</title><link>https://blog.wind-mask.com/blog/wind_mask&apos;s%20Hackergame%202023/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/wind_mask&apos;s%20Hackergame%202023/zh_cn/</guid><description>做了一下HackerGame 2023</description><pubDate>Sat, 04 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;wind_mask&apos;s HackerGame 2023&lt;/h1&gt;
&lt;p&gt;作为全部的记录因此也就不避开常规解了，大致还原一下这周做题的内容（并不保证和当时的过程一致，中间的弯路可能略）。&lt;/p&gt;
&lt;h2&gt;各题解&lt;/h2&gt;
&lt;h3&gt;Hackergame 启动&lt;/h3&gt;
&lt;p&gt;我本来这里就想用出录音重放了，但是显然用不到，改一下url里的参数即可。&lt;/p&gt;
&lt;h3&gt;猫咪小测&lt;/h3&gt;
&lt;p&gt;开始俄苏（😎&lt;/p&gt;
&lt;h4&gt;中科大的图书馆&lt;/h4&gt;
&lt;p&gt;（&lt;s&gt;其实可以线下快打&lt;/s&gt;），直接到官网搜索书籍，确定是西区图书馆外文书籍，查一下外文书籍楼层所在（百度百科就有），得。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04-14-18-51-image.png&quot; alt=&quot;外文书籍所在&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;可观测宇宙鸡的密度&lt;/h4&gt;
&lt;p&gt;知乎上有回答&lt;a href=&quot;https://www.zhihu.com/question/20337132/answer/3023506910&quot;&gt;你见过哪些极品论文？&lt;/a&gt;,关键词选的好，真不熟什么论文。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04-14-18-16-image.png&quot; alt=&quot;知乎答案&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;TCP BBR拥塞控制&lt;/h4&gt;
&lt;p&gt;似乎没什么可说,随便搜一下就是了。&lt;/p&gt;
&lt;h4&gt;python类型检查的图灵完备&lt;/h4&gt;
&lt;p&gt;题目没提图灵完备，但是什么等价于停机问题大概也就这么证明啦。&lt;/p&gt;
&lt;p&gt;搜一下&lt;code&gt;python type turing&lt;/code&gt;是Python Type Hints are Turing Complete这篇。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04-14-24-25-image.png&quot; alt=&quot;论文&quot; /&gt;ECOOP，得。&lt;/p&gt;
&lt;h3&gt;更深更暗&lt;/h3&gt;
&lt;p&gt;在F12里搜flag即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04-14-26-35-image.png&quot; alt=&quot;搜索得&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;旅行照片 3.0&lt;/h3&gt;
&lt;p&gt;原谅我第二题偷懒没看英文网页，中文页面没校园成员计划。&lt;/p&gt;
&lt;p&gt;第一题注意照片中学长带的带子上的字STATPHYS28搜索可知是统计物理学会议，官网日期就那些天，金色奖牌显然诺贝尔奖根据奖牌上名字知道是东京大学，搜一下东京大学的诺贝尔奖得主（wiki上有），其中出生最晚是梶田隆章，在东京大学宇宙射线研究所即ICRR。&lt;/p&gt;
&lt;p&gt;然后根据STATPHYS28的日程试一下知道是8月10日。&lt;/p&gt;
&lt;p&gt;然后是白色帐篷这张识图注意到是上野公园喷泉，什么活动呢，搜不到。前往推特搜索“2023年8月10日 上野”，看到&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04%2014_44_11-2023%E5%B9%B48%E6%9C%8810%E6%97%A5%20%E4%B8%8A%E9%87%8E%20-%20%E6%90%9C%E7%B4%A2%20_%20X.png&quot; alt=&quot;推特搜索&quot; /&gt;&lt;/p&gt;
&lt;p&gt;地点时间对上了，看一眼照片是白色帐篷，ok。&lt;/p&gt;
&lt;p&gt;志愿者招募表编号翻一下这个活动官网，下面就有&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04%2014_48_09-%E3%83%9C%E3%83%A9%E3%83%B3%E3%83%86%E3%82%A3%E3%82%A2STAFF%E5%A4%A7%E5%8B%9F%E9%9B%86%EF%BC%81%EF%BC%81%E7%AC%AC%EF%BC%96%E5%9B%9E%E3%80%8C%E5%85%A8%E5%9B%BD%E6%A2%85%E9%85%92%E3%81%BE%E3%81%A4%E3%82%8Ain%E6%9D%B1%E4%BA%AC2023%E3%80%8D%EF%BD%9C%E5%85%A8%E5%9B%BD%E6%A2%85%E9%85%92%E3%81%BE%E3%81%A4%E3%82%8A.png&quot; alt=&quot;志愿者&quot; /&gt;&lt;/p&gt;
&lt;p&gt;下面翻一下google map，上野喷泉对面的博物馆，东京国立博物馆，这里中文页面没有，所以我没注意到校园会员计划以至于没做出，但其实0元这个应该猜一下的，其实后来想到了但是忘记了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04%2014_52_14-TOKYO%20NATIONAL%20MUSEUM%20-%20Education%20Campus%20Members%20---%20%E4%B8%9C%E4%BA%AC%E5%9B%BD%E7%AB%8B%E5%8D%9A%E7%89%A9%E9%A6%86%20-%20%E6%95%99%E8%82%B2%E5%9B%AD%E5%8C%BA%E4%BC%9A%E5%91%98.png&quot; alt=&quot;校园会员&quot; /&gt;&lt;/p&gt;
&lt;p&gt;下面是当晚聚集地点这个翻STATPHYS28官网日程知道10号晚上是Banquet，在Events下看一下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04%2014_54_09-STATPHYS28%20---%20STATPHYS28.png&quot; alt=&quot;会面点&quot; /&gt;&lt;/p&gt;
&lt;p&gt;第六问其实两个字的一猜就是熊猫，但是你也可以搜一下确认比如&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04%2014_58_28-X%20%E4%B8%8A%E7%9A%84%20%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BEP%CD%99a%CD%99n%CD%99d%CD%99a%CD%99%20f%CD%99a%CD%99c%CD%99t%CD%99o%CD%99r%CD%99y%CD%99%20%E6%96%87%E5%85%B7%E3%81%AE%E5%8D%9A%E8%A6%A7%E4%BC%9A%EF%BC%9A%E2%80%9C%E3%82%B3%E3%83%88%E3%83%A2%E3%83%8E%E3%83%9E%E3%83%AB%E3%82%B7%E3%82%A7%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%8A%E3%83%AB%E3%83%96%E3%83%A9%E3%83%B3%E3%83%89%20BUTTON%EF%BC%86CUFFLINKS%E3%81%95%E3%82%93%E3%81%AE.avif&quot; alt=&quot;熊猫&quot; /&gt;&lt;/p&gt;
&lt;p&gt;三个字动物的去google搜(题意要用马里奥下一张图的信息，但是关键词选的好一切皆允)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04%2015_03_25-%E5%87%BA%E7%AB%99%20%E5%B9%BF%E5%91%8A%203d%20%E5%8A%A8%E7%89%A9%20-%20Google%20%E6%90%9C%E7%B4%A2.avif&quot; alt=&quot;秋田犬&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;赛博井字棋&lt;/h3&gt;
&lt;p&gt;抓一下包把AI下的位置覆盖了，连成3个。没注意session怎么变化，直接重放完事。&lt;/p&gt;
&lt;h3&gt;奶奶的睡前 flag 故事&lt;/h3&gt;
&lt;p&gt;题目加粗字体一眼注意，&lt;code&gt;pixel 截图 cve&lt;/code&gt;，搜一下，CVE-2023-21036，得。
搜这个cve在github上看到提到在线恢复的网站，在&lt;a href=&quot;https://acropalypse.app/&quot;&gt;acropalypse&lt;/a&gt;上恢复就是了。&lt;/p&gt;
&lt;h3&gt;组委会模拟器&lt;/h3&gt;
&lt;p&gt;打开题目抓包一看解析json+正则表达式+发包就是了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import re
import string
from time import sleep
import time
import requests
import json

headers = {&apos;Cookie&apos;: &apos;抓个就是了&apos;,
           &apos;Content-Type&apos;: &apos;application/json&apos;,
           &apos;Host&apos;: &apos;202.38.93.111:10021&apos;}
response = requests.post(
    &apos;http://202.38.93.111:10021/api/getMessages&apos;, headers=headers)
t0 = time.time()
msgjson = json.loads(response.text)[&apos;messages&apos;]
delay = 0
j = 0
r = re.compile(r&apos;hack\[[a-z]*\]&apos;)
for i in msgjson:
    if r.search((i[&apos;text&apos;])) != None:
        print(i[&apos;text&apos;])
        re = requests.post(
            &apos;http://202.38.93.111:10021/api/deleteMessage&apos;,
            headers=headers,
            json={&quot;id&quot;: j})
        print(re.json())
    sleep(max(0, i[&apos;delay&apos;]-time.time()+t0))
    j += 1
res = requests.post(&apos;http://202.38.93.111:10021/api/getflag&apos;,
                    headers=headers)
print(res.json())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发包会受延迟影响，所以直接拿本地time减了。&lt;/p&gt;
&lt;h3&gt;虫&lt;/h3&gt;
&lt;p&gt;注意到是国际空间站传输图片 ，一搜是什么SSTV反正不懂的无所谓抄个教程看到个RX-SSTV的软件&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04%2015_21_59-RX-SSTV%20v.2.1.6%20_ON6MU%20(SSTVENG.DLL%20v.1.06).avif&quot; alt=&quot;RX-SSTV&quot; /&gt;&lt;/p&gt;
&lt;p&gt;播放的话，之前QQ语音的时候逗群友玩的时候安过一个虚拟麦克风&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-11-04%2015_22_57-%E8%AE%BE%E7%BD%AE.png&quot; alt=&quot;虚拟麦克风&quot; /&gt;&lt;/p&gt;
&lt;p&gt;放就完了。&lt;/p&gt;
&lt;h3&gt;JSON ⊂ YAML?&lt;/h3&gt;
&lt;p&gt;第一问搜到&lt;a href=&quot;https://stackoverflow.com/questions/21584985/what-valid-json-files-are-not-valid-yaml-1-1-files&quot;&gt;What valid JSON files are not valid YAML 1.1 files? - Stack Overflow&lt;/a&gt;，里面&lt;code&gt;12345e999&lt;/code&gt;这个例子一放就是了。&lt;/p&gt;
&lt;p&gt;但是第二个要求第一个不报错，我一开始往里塞制表符无果。&lt;/p&gt;
&lt;p&gt;后来仔细看ruamel.yaml的文档，发现&lt;code&gt;Duplicate keys&lt;/code&gt;是不允许的，试了一下，过。&lt;/p&gt;
&lt;h3&gt;Git? Git!&lt;/h3&gt;
&lt;p&gt;直接看&lt;a href=&quot;https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E7%BB%B4%E6%8A%A4%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D#_data_recovery&quot;&gt;Git - 维护与数据恢复&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;HTTP 集邮册&lt;/h3&gt;
&lt;p&gt;嗯试就完了，改下&lt;code&gt;Method&lt;/code&gt;，HTTP版本，&lt;code&gt;Path&lt;/code&gt;，&lt;code&gt;Host&lt;/code&gt;，&lt;code&gt;CRLF&lt;/code&gt;随便插一下，5个code拿到。&lt;/p&gt;
&lt;p&gt;第二问碰一下删了&lt;code&gt;Path&lt;/code&gt;和&lt;code&gt;HTTP/1.1&lt;/code&gt;之间的空格，就过了。&lt;/p&gt;
&lt;p&gt;第三问感觉很多HTTP规范的样子，算了，没做。&lt;/p&gt;
&lt;h3&gt;Docker for Everyone&lt;/h3&gt;
&lt;p&gt;docker指令时挂载宿主机上的文件就是了。&lt;/p&gt;
&lt;h3&gt;惜字如金 2.0&lt;/h3&gt;
&lt;p&gt;根据规则改了下载的代码复原各种可能&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/python3

# Th size of th file may reduce after XZRJification

def check_equals(left, right):
    # check whether left == right or not
    if left != right:
        return False
    return True


def get_code_dict():
    # prepare the code dict
    check_equals(set(len(s) for s in code_dict), {24})
    return &apos;&apos;.join(code_dict)


def decrypt_data(input_codes):
    # retriev th decrypted data
    code_dict = get_code_dict()
    output_chars = [code_dict[c] for c in input_codes]
    return &apos;&apos;.join(output_chars)


if __name__ == &apos;__main__&apos;:
    # check som obvious things
    check_equals(&apos;create&apos;, &apos;crea&apos; + &apos;te&apos;)
    check_equals(&apos;referer&apos;, &apos;refer&apos; + &apos;er&apos;)
    # check th flag
    y = [[], [], [], [], []]
    x = [&apos;&apos;, &apos;&apos;, &apos;&apos;, &apos;&apos;, &apos;&apos;]
    x[0] = &apos;nymeh1niwemflcir}echaet&apos;
    x[1] = &apos;a3g7}kidgojernoetlsup?h&apos;
    x[2] = &apos;ulw!f5soadrhwnrsnstnoeq&apos;
    x[3] = &apos;ct{l-findiehaai{oveatas&apos;
    x[4] = &apos;ty9kxborszstguyd?!blm-p&apos;
    f = &apos;bcdfghjklmnpqrstvwxyz&apos;
    for i in range(5):
        for j, c in enumerate(x[i]):
            if c in f:
                sl = list(x[i])
                sl.insert(j, c)
                s = &apos;&apos;.join(sl)
                y[i] += [s]
        if x[i][-1] in f:
            y[i] += [x[i]+&apos;e&apos;]
        for k in y[i]:
            assert len(k) == 24
    print(y)
    for i in range(len(y[0])):
        for j in range(len(y[1])):
            for k in range(len(y[2])):
                for l in range(len(y[3])):
                    for m in range(len(y[4])):
                        code_dict = []
                        code_dict += [y[0][i]]
                        code_dict += [y[1][j]]
                        code_dict += [y[2][k]]
                        code_dict += [y[3][l]]
                        code_dict += [y[4][m]]
                        flag = decrypt_data([53, 41, 85, 109, 75,
                                             1, 33, 48, 77, 90,
                                             17, 118, 36, 25, 13,
                                             89, 90, 3, 63, 25,
                                             31, 77, 27, 60, 3,
                                             118, 24, 62, 54, 61,
                                             25, 63, 77, 36, 5,
                                             32, 60, 67, 113, 28])
                        if flag.find(&apos;flag{&apos;) != -1 &amp;amp; flag.find(&apos;}&apos;) != -1:
                            if check_equals(flag.index(&apos;flag{&apos;), 0) &amp;amp; check_equals(flag.index(&apos;}&apos;), len(flag) - 1):
                                print(flag)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;高频率星球&lt;/h3&gt;
&lt;p&gt;观测&lt;a href=&quot;https://asciinema.org/&quot;&gt;asciinema&lt;/a&gt; cat出来的文件说了要Execute flag.js with nodejs to get the flag。&lt;/p&gt;
&lt;p&gt;删掉前后文和各种提示符（怎么删？肉眼观测然后Ctrl+F替换啊嗯）。&lt;/p&gt;
&lt;p&gt;然后&lt;code&gt;node flag.js&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;小型大语言模型星球&lt;/h3&gt;
&lt;p&gt;第一问尝试诱导各种类似与&lt;code&gt;do i am smart&lt;/code&gt;之类，最后试得&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-10-30%2012_40_28-Gradio.png&quot; alt=&quot;smart&quot; /&gt;&lt;/p&gt;
&lt;p&gt;第二问手工枚举得&lt;code&gt;x&lt;/code&gt;+&lt;code&gt;accept&lt;/code&gt;，得&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/wind_masks-hackergame-2023/2023-10-30%2012_40_47-Gradio.png&quot; alt=&quot;accepted&quot; /&gt;&lt;/p&gt;
&lt;p&gt;后面几个要懂AI什么做不出来啦。&lt;/p&gt;
&lt;h3&gt;Komm, süsser Flagge&lt;/h3&gt;
&lt;p&gt;第一个检查&lt;code&gt;POST&lt;/code&gt;整个字符串，那就把&lt;code&gt;HTTP Request&lt;/code&gt;分两次发吧&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import socket
s = socket.socket()
s.connect((&quot;202.38.93.111&quot;, 18080))
s.send(b&quot;PO&quot;)
s.send(b&apos;ST / HTTP/1.1\r\nHost: 202.38.93.111:18080 \
       \r\nContent-Length: 自己算\r\n \
       Content-Type: application/x-www-form-urlencoded\r\n\r\n你的token&apos;)
buffer = []
while True:
    # 每次最多接收1k字节:
    d = s.recv(1024)
    if d:
        buffer.append(d)
    else:
        break
data = b&apos;&apos;.join(buffer)
s.close()
print(data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同样内容对第二试了一下也过了，但其实看不懂第二个什么意思。&lt;/p&gt;
&lt;p&gt;第三个想到了要往&lt;code&gt;ip option&lt;/code&gt;或&lt;code&gt;tcp option&lt;/code&gt;里插东西，但是没搞定。&lt;/p&gt;
&lt;h3&gt;为什么要打开 /flag 😡&lt;/h3&gt;
&lt;p&gt;不懂什么&lt;code&gt;binary&lt;/code&gt;，只看出第一题C库不准打开&lt;code&gt;flag&lt;/code&gt;，那就不用C吧。&lt;/p&gt;
&lt;p&gt;用rust写了一个可执行文件，得&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use std::fs::File;
use std::io::{ BufReader, BufRead, Error};

fn main() -&amp;gt; Result&amp;lt;(), Error&amp;gt; {
    let path = &quot;flag&quot;;
    let input = File::open(path)?;
    let buffered = BufReader::new(input);
    for line in buffered.lines() {
        println!(&quot;{}&quot;, line?);
    }
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二问只看到crate的文档说存在 TOCTOU（Time Of Check, Time Of Use）的风险，但是肯定不懂的，无。&lt;/p&gt;
&lt;h3&gt;O(1) 用户登录系统&lt;/h3&gt;
&lt;p&gt;看了半天对&lt;code&gt;Merkle Tree&lt;/code&gt;的第二原像攻击，其实都没用。&lt;/p&gt;
&lt;p&gt;问题在于不记录树的高度，把&lt;code&gt;admin:xxx&lt;/code&gt;伪造到上面节点不行，似乎可以把它伪造到一个&lt;code&gt;user:pass&lt;/code&gt;的叶子下面。&lt;/p&gt;
&lt;p&gt;如果输入第一截是&lt;code&gt;admin:xxx:ccc&lt;/code&gt;，易见要满足（此处略去关于hash1&amp;gt;hash2的讨论，自行调整即可）&lt;code&gt;(sha1(&quot;admin:xxx&quot;.encode())+ccc)=sha1(&quot;uasr:pass&quot;.encode())&lt;/code&gt;,&lt;/p&gt;
&lt;p&gt;也即`sha1(&quot;admin:xxx&quot;.encode())+ccc=&quot;user:pass&quot;.encode()``&lt;/p&gt;
&lt;p&gt;那就随机一下&lt;code&gt;xxx&lt;/code&gt;，使&lt;code&gt;&quot;admin:xxx&quot;.encode()&lt;/code&gt;的Sha1值可以编码为utf8可打印字符（我懒得考虑怎么处理不可打印字符了，大不了让电脑多跑一会就是了(这里的计算量估计了一下数量级反正跑的出来就是了)）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;while True:
 ap = &apos;admin:&apos;+&apos;&apos;.join([random.choice(ascii_letters) for _ in range(10)])
 ha = sha1(ap.encode()).digest()
 try:
        if ha.decode().encode() != ha:
            continue
        d = ha.decode()
        if d.isprintable() == False:
            continue
        if d.find(&apos;\n&apos;) != -1 or d.find(&apos; &apos;) != -1:
            continue
        print(&quot;ha=&quot;, ha.hex())
        print(&quot;hd=&quot;, d.encode().hex())
        print(&quot;ap=&quot;, ap)
        print(&quot;d=&quot;, d)
        break
 except:
        continue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来拿着得到的&lt;code&gt;admin:xxx&lt;/code&gt;和&lt;code&gt;d=sha1(ap.encode()).digest().decode()&lt;/code&gt;在&lt;code&gt;d&lt;/code&gt;后面接上一串&lt;code&gt;:1451411451411451489&lt;/code&gt;（随便选的就是了，补上&lt;code&gt;:&lt;/code&gt;且编码后长度和sha1一样就是了，这里可能要注意一下&lt;code&gt;hash1&amp;gt;hash2&lt;/code&gt;什么的），&lt;code&gt;前面的ccc就是&apos;:1451411451411451489&apos;&lt;/code&gt;的encode hex，即&lt;code&gt;ccc=&apos;:1451411451411451489&apos;.encode().hex()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后输入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;d:1451411451411451489
:
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后得到的proof里有&lt;code&gt;d:1451411451411451489:ppp&lt;/code&gt;,我们用&lt;code&gt;admin:xxx:ccc+ppp&lt;/code&gt;，即可登陆。&lt;/p&gt;
&lt;h2&gt;闲话&lt;/h2&gt;
&lt;p&gt;虽然出于随意就来做了，但是果然光凭这种是摆脱不了怠惰的。几道觉得麻烦的都没做成，连俄苏的也竟然少了一个（这是意外）。果然我终究更有兴趣于装配学，对于细节的实现永远永远碰不过的。&lt;/p&gt;
</content:encoded><category>HackerGame</category><category>CTF</category></item><item><title>使Windows潮裤</title><link>https://blog.wind-mask.com/blog/%E4%BD%BFWindows%E6%BD%AE%E8%A3%A4/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/%E4%BD%BFWindows%E6%BD%AE%E8%A3%A4/zh_cn/</guid><description>你的窗口系统还没有潮裤吗？</description><pubDate>Tue, 14 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;潮裤&lt;/h2&gt;
&lt;p&gt;Windows到底是不是人？在加利福尼亚海岸吹来的阴风面前，连唉资本果区都可以得到支持的世界里，人们仍然认为Windows是粗俗而不合乎码区的系统，至多玩弄着WSL碰瓷林纳斯。&lt;/p&gt;
&lt;p&gt;但事实上，许许多多的用户表现问题是有解的，只不过需要一点技巧，让我们总结一下。&lt;/p&gt;
&lt;h2&gt;外观&lt;/h2&gt;
&lt;p&gt;字体替换：&lt;a href=&quot;https://github.com/PlusOneToX/noble-scarlet-mod&quot;&gt;GitHub - PlusOneToX/noble-scarlet-mod: Chinese font replacement for Windows 10.基于 Noble Scarlet (堕朱砂) 与 LXGW WenKai (霞鹜文楷) 的Windows 10中文字体替换。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;自定义用户界面字体：&lt;a href=&quot;https://github.com/Tatsu-syo/noMeiryoUI&quot;&gt;GitHub - Tatsu-syo/noMeiryoUI: No!! MeiryoUI is Windows system font setting tool on Windows 8.1/10/11.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;更好的 Windows 字体渲染：&lt;a href=&quot;https://github.com/snowie2000/mactype&quot;&gt;GitHub - snowie2000/mactype: Better font rendering for Windows.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;沙滦二刺猿：&lt;a href=&quot;https://winmoes.com/&quot;&gt;枫の主题社&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;任务栏：&lt;a href=&quot;https://windhawk.net/&quot;&gt;Windhawk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;显示器亮度：&lt;a href=&quot;https://github.com/xanderfrangos/twinkle-tray&quot;&gt;GitHub - xanderfrangos/twinkle-tray: Easily manage the brightness of your monitors in Windows from the system tray&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;深色模式：&lt;a href=&quot;https://github.com/AutoDarkMode/Windows-Auto-Night-Mode&quot;&gt;GitHub - AutoDarkMode/Windows-Auto-Night-Mode: Automatically switches between the dark and light theme of Windows 10 and Windows 11&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;伽玛值：&lt;a href=&quot;https://github.com/Tyrrrz/LightBulb&quot;&gt;GitHub - Tyrrrz/LightBulb: Reduces eye strain by adjusting screen gamma based on the current time&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;终端与shell&lt;/h2&gt;
&lt;p&gt;其实这有点码区，但是想到很多地方还在用&lt;code&gt;cmd&lt;/code&gt;和&lt;code&gt;.bat&lt;/code&gt;来给非码区使用，那么就也有必要青蒜了。&lt;/p&gt;
&lt;p&gt;潮裤是支持&lt;code&gt;posix&lt;/code&gt;吗？那样只能叫林纳斯，WSL已有。反之而行，我们是要你林纳斯不再&lt;code&gt;posix&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;`windows terminal``，我坚信他是潮裤窗口系统的必然——在窗口系统上背离巨硬是不合理的。&lt;/p&gt;
&lt;p&gt;那么shell呢？&lt;code&gt;powershell&lt;/code&gt;？你太小瞧RIIR[^1]的力量了！&lt;/p&gt;
&lt;p&gt;比如在shell上，某些软体默认使用sh，听着很一致啊，是啊，毕竟即使在窗口上我们也有git-bash，cygwin，msys2等等等等（在码区视角看来，这一系列的背后是mingw，cmake，vcpkg，Visual Studio），但是&lt;strong&gt;这是发展办法还是妥协方法&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;我们潮裤的选择当然是bash不兼容shell.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.sh&lt;/code&gt;是什么文件？拒绝——&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nushell.sh/&quot;&gt;Nushell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;于是一切就归于虚无。&lt;/p&gt;
&lt;p&gt;什么，你说不支持bash脚本了？问题来了：&lt;strong&gt;原来Windows支持bash脚本的吗？&lt;a href=&quot;%E7%A8%8D%E4%BD%9C%E8%A7%A3%E9%87%8A%E7%9A%84%E8%AF%9D%EF%BC%8C%E5%85%B6%E5%AE%9E%E5%A4%A7%E9%83%A8%E5%88%86%E6%88%91%E8%A7%81%E5%88%B0%E7%9A%84bash%E8%84%9A%E6%9C%AC%E6%A0%B9%E6%9C%AC%E5%B0%B1%E4%B8%8D%E5%8F%AF%E8%83%BD%E7%9B%B4%E6%8E%A5%E8%BF%90%E8%A1%8C%E5%9C%A8Windows%E4%B8%8A%EF%BC%8C%E4%B8%8D%E6%98%AF%E4%BD%A0%E8%A3%85%E4%B8%AAgit-bash%E5%B0%B1%E8%83%BD%E8%A1%8C%E7%9A%84%EF%BC%8C%E6%9C%80%E5%90%8E%E8%BF%98%E5%BE%97WSL%E3%80%82&quot;&gt;^2&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;潮裤就是潮裤罢了。&lt;/p&gt;
&lt;p&gt;我对powershell没有意见，但是它高度特化了Windows，其实它更应该作为脚本语言比shell好。&lt;/p&gt;
&lt;p&gt;然后就是寻常的折腾：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://starship.rs/&quot;&gt;starship&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/carapace-sh/carapace-bin&quot;&gt;GitHub - carapace-sh/carapace-bin: A multi-shell completion binary.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ajeetdsouza/zoxide&quot;&gt;GitHub - ajeetdsouza/zoxide: A smarter cd command. Supports all major shells.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;下面就是码区的领域了：&lt;/p&gt;
&lt;h2&gt;包管理&lt;/h2&gt;
&lt;p&gt;什么，Windows也能叫包管理吗？&lt;/p&gt;
&lt;p&gt;我承认，在林纳斯C式眼光下看，不能——我尝试在Windows上手动编译（不使用VS那一套）一个gtk的相关，妄图手动&lt;code&gt;mingw&lt;/code&gt;+&lt;code&gt;pkg-config&lt;/code&gt;等，结论是死——不可能像linux一样系统包管理器——也许这组件就是在linux上编译到Windows的。&lt;/p&gt;
&lt;p&gt;——C系眼光下的跨平台指的是cmake/meson/ninja/make/vcpkg/VS等等等等合在一起能用。&lt;/p&gt;
&lt;p&gt;但是在潮裤看来这就是不能用——&lt;strong&gt;我相信的是xmake，它已经尽力了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;不，我们不使用C库——事实上由于这种巨大困难——很多开源软件在Windows下也无法源码分发——即使没有gui——我都不想说这里的供应链安全与Secret沉思了。&lt;/p&gt;
&lt;p&gt;但是&lt;code&gt;cargo install&lt;/code&gt;不是，它做到了——至少在码区的世界，在开发链条上，源码分发。&lt;/p&gt;
&lt;p&gt;但是，由于使用&lt;a href=&quot;https://github.com/marticliment/UniGetUI&quot;&gt;GitHub - marticliment/UniGetUI: UniGetUI: The Graphical Interface for your package managers. Could be terribly described as a package manager manager to manage your package managers&lt;/a&gt;尚有&lt;a href=&quot;https://github.com/marticliment/UniGetUI/issues/2884&quot;&gt;[IMPROVEMENT] Use cargo-binstall for cargo packages · Issue #2884 · marticliment/UniGetUI · GitHub&lt;/a&gt;，因此现在不能让cargo管理，但实现之后，我们就可以使用UniGetUI配合&lt;a href=&quot;https://github.com/microsoft/winget-cli&quot;&gt;GitHub - microsoft/winget-cli: WinGet is the Windows Package Manager. This project includes a CLI (Command Line Interface), PowerShell modules, and a COM (Component Object Model) API (Application Programming Interface).&lt;/a&gt;和&lt;a href=&quot;https://github.com/ScoopInstaller/Scoop&quot;&gt;GitHub - ScoopInstaller/Scoop: A command-line installer for Windows.&lt;/a&gt;达成&lt;strong&gt;觉醒&lt;/strong&gt;了。&lt;/p&gt;
&lt;p&gt;这不潮裤吗？&lt;/p&gt;
&lt;p&gt;在arch上，我不还是自己打PKGBUILD安自己patch的包；在Windows，则自己包scoop bucket——Windows之dotfiles也许也将降临：事实上，在开发人员主页里巨硬就尝试winget了，但是winget就仿佛官方库，不可自己打包。&lt;/p&gt;
&lt;p&gt;在这种力量下，配合UniGetUI导出备份安装的包，包管理谁敢说不潮裤呢？&lt;/p&gt;
&lt;h2&gt;文件系统&lt;/h2&gt;
&lt;p&gt;难道窗口下有其他选择吗？&lt;/p&gt;
&lt;p&gt;还真有:&lt;img src=&quot;/%E4%BD%BFWindows%E6%BD%AE%E8%A3%A4/2025-01-14%2018_49_32-btrfs%20(G_)%20%E5%B1%9E%E6%80%A7.avif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;啊，不对安全负责哦。&lt;/p&gt;
&lt;p&gt;但是用上这种潮裤后就可以和我的林纳斯共享文件系统了——虽然是危险行为——注意数据的可用性。&lt;/p&gt;
&lt;h2&gt;IDE&lt;/h2&gt;
&lt;p&gt;老实说，潮裤地追随vim，neovim并没有使我安心——确实太麻烦了。而使用预配置好的，那么似乎有没什么意义了。&lt;/p&gt;
&lt;p&gt;于是在RIIR的指引下，我来到helix。&lt;/p&gt;
&lt;p&gt;vscode helix jetbrain，事实上跟窗口系统没什么关系。只是潮裤而已。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;潮裤为何&lt;/h2&gt;
&lt;p&gt;我知道，这都是虚空，都是捕风。&lt;/p&gt;
&lt;p&gt;然而：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你要将天地卷起来，像一件外衣，天地就都改变了。惟有你永不改变，你的年数没有穷尽。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;[^1]: RIIR: Rewrite It In Rust.&lt;/p&gt;
</content:encoded><category>Windows</category><category>Technical</category></item><item><title>关于Secret的沉思（1）：绪论</title><link>https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%881%EF%BC%89%EF%BC%9A%E7%BB%AA%E8%AE%BA/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%881%EF%BC%89%EF%BC%9A%E7%BB%AA%E8%AE%BA/zh_cn/</guid><description>关于secret问题的开端</description><pubDate>Wed, 03 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;题论&lt;/h2&gt;
&lt;p&gt;本文意在概述我一向思考和设计以后产生的关于Secret的沉思，包括工具链和思路。它们不是&lt;em&gt;&lt;strong&gt;一般性普适性的&lt;/strong&gt;&lt;/em&gt;，并且在Secret方面也不存在这样的东西。我只是给出一种我的设计。由于这种设计的结构本身就是一种泄露，因此在最高的要求方面，其细节我只能给出参考来源。&lt;/p&gt;
&lt;h2&gt;有必要吗？&lt;/h2&gt;
&lt;p&gt;诚然，大部分时候，本文谈及的方法都是&lt;em&gt;&lt;strong&gt;过度的&lt;/strong&gt;&lt;/em&gt;，但是只是出于趣味，我们也不妨尝试一些手段。而且我尽力使本文是也是现实的（相比于许多此类文章并不现实的高要求和便利性的损失）。&lt;/p&gt;
&lt;h2&gt;有待补充&lt;/h2&gt;
&lt;p&gt;本文的话题没有终点，一切可用的工具方法思考都欢迎补充。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;评估策略&lt;/h2&gt;
&lt;p&gt;事实上，关于Secret的解决方案有其缺点：有时它们很难部署、维护或使用；有时您可以在各种技术之间进行选择，但没有一种完全符合您设定的“规范”；有时它们太新了，无法确定它们是否真的有效。
因此，人们应该首先问几个简单的问题，以便建立威胁模型，即潜在威胁的识别和优先级排序。&lt;/p&gt;
&lt;h3&gt;我们要保护什么？&lt;/h3&gt;
&lt;p&gt;我们想保护的东西可能非常广泛以至于不切实际，或者在现状下也有可能是太无所谓以至于烂了。
“保护”一词涵盖了不同的需求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;隐私 ：隐藏信息以防泄露；&lt;/li&gt;
&lt;li&gt;完整性 ：保持信息完整，防止他人修改；&lt;/li&gt;
&lt;li&gt;可访问性 ：确保可以访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些需求通常会发生冲突，因此有必要确定优先级并找到折衷方案。至少需要一种折衷的原则，因为不同的折中合起来可能会破坏所有部分的安全。&lt;/p&gt;
&lt;h3&gt;我们想保护自己免受谁的伤害？&lt;/h3&gt;
&lt;p&gt;敌手的评估是关键的，敌手的能力对我们的策略影响巨大。通常的教程往往会告诉我们要做出正确的评估，但是现实中有一种跟困难的情景：我们无法预先评估。理论上我们只能按最坏的情况考虑，这也是本系列大多数时间将做的。但是请注意，我们往往不可能部署全部的策略。因此，怎么可能保持一种渐进性的安全就成为挑战。这也会使我们研究的一点，它往往只能通过一些方法策略而非技术能及。
对手的手段问题相当广泛。诚然，缺乏想象力的人们对敌手要么缺乏技术的认识，要么非技术的认为可以略去技术困难。但实际上Secret是一个极多维度的问题，敌手的手段可能是合法的，也可能是隐蔽的；技术资源可能很多，也可能主要依赖社工方法；经济手段也是一个问题，敌手是否真的能够且会付出足够的成本？；当然，还有政治手段。&lt;/p&gt;
&lt;h3&gt;妥协的问题&lt;/h3&gt;
&lt;p&gt;攻击和监视的可能性是无限的，抵御它们的设备也是如此。然而，我们想要实施的每一项额外保护都对应于学习和时间方面的努力。因此，在每种情况下，都需要 在易用性和所需保护级别之间找到合适的折衷方案。有时，这种平衡点并不存在。防范似是而非的风险的努力太痛苦了，要么冒这个风险，或者干脆不使用数字工具来存储某些数据或谈论某些事情。&lt;/p&gt;
&lt;h3&gt;怎么办？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;哪些实践和工具足以保护我免受 先前评估的风险 ？&lt;/strong&gt;
对于某一种策略，要问：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;面对这样的安全策略，我的对手会使用什么攻击角度？&lt;/li&gt;
&lt;li&gt;我的对手应该采取什么手段？&lt;/li&gt;
&lt;li&gt;这些手段在我的对手手中吗？&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;一些规则&lt;/h4&gt;
&lt;p&gt;就安全性而言，简单的解决方案始终优于复杂的解决方案。一个复杂的解决方案提供了更多的“攻击面”。曾有人说过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“我们不可能相信一个我们不理解的安全策略”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个复杂的系统有着许多链接，它们每个及相互的安全必须得到审查，这是个大工程！不过，复杂的策略提供了更多选择，可用性。在组合良好的情况下，安全性不会低于最低环节。您必须考虑能够并且会维护的策略的复杂度，一旦它不匹配，系统将瓦解。&lt;/p&gt;
&lt;h5&gt;没有人是绝对可靠的&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;Die meisten Computerprobleme sitzen zwischen Tastatur und Stuhl&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;人总是问题，并且在这里几乎就是大部分问题。
一个良好的策略不能总把安全寄希望于使用者的专注，系统必须提供坚实的要求，严格的固定风险的来源。&lt;/p&gt;
&lt;h5&gt;没有什么是永远的&lt;/h5&gt;
&lt;p&gt;计算机安全领域变化非常快，今天被认为相当安全的解决方案明年很可能很容易受到攻击。使用的工具链必须时常保持更新，并且最好有取代其中各节点的备选方案。至少保证不至于一旦断开就无法挽回。所有这一切都需要一点时间，从一开始就应该予以计划。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;……To be continued……&lt;/p&gt;
</content:encoded><category>Secret</category></item><item><title>关于Secret的沉思（2）：本地</title><link>https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%882%EF%BC%89%EF%BC%9A%E6%9C%AC%E5%9C%B0/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%882%EF%BC%89%EF%BC%9A%E6%9C%AC%E5%9C%B0/zh_cn/</guid><description>在本地有多少黑箱？</description><pubDate>Thu, 11 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;题论&lt;/h2&gt;
&lt;p&gt;让我们先从简单的场景出发，也就是先考虑我们的本地活动。这是一类 &lt;strong&gt;&lt;em&gt;不被重视的活动&lt;/em&gt;&lt;/strong&gt;（至少对于个人而言），因为个人很少在本地面对攻击，除非处境危险（这种情况我们需要更加一致的体系设计，本地自然也有）。&lt;/p&gt;
&lt;h2&gt;备份&lt;/h2&gt;
&lt;p&gt;个人更多在现在关心的应该是备份和可用性——本地数据的失效是常见的。在这方面，网盘备份同步的服务是应用的。常用的服务我使用的倒较少，因为onedrive同步的目录我不怎么用；Google云盘受限于GFW，因此不得不转向国内的应用。
我不怎么使用文件同步服务（但是现在各软件都有自己的云同步，代码有git仓库），对于文件的备份，国内服务其实是可用的。但这里我们谈论的当然不是大文件备份，因为那也不太会是Secret（当然，如果我们真的有冷大文件还是Secret的，那可真是个问题，或许物理备份（为了Secret起见甚至要有独立存储——指放硬盘的保险箱？当然还有全盘加密。）。（当然，有付费的云端加密备份服务，但是对于一般需求不如白嫖，对于极端安全需求——付费甚至是一个攻击面）。
小的文件备份，用来干什么了呢？答案并不多，我个人用于电子书，小的程序工具（这些东西找起来不易），还有，最Secret的，&lt;strong&gt;&lt;em&gt;密钥备份&lt;/em&gt;&lt;/strong&gt;。
是的，密钥备份。无论是自动填充用的密码库，还是pgp密钥，ssh密钥。但是，要谨记，秘密文件云端绝不可有一点明文！保证已加密上传，本地处理，同步处理。这就涉及了一种动态的文件加密：&lt;/p&gt;
&lt;h2&gt;加密&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;这确实是个问题。
如果你&lt;strong&gt;不是&lt;/strong&gt;在做备份，也&lt;strong&gt;不是&lt;/strong&gt;在为长期存储而离线存档，也&lt;strong&gt;不是&lt;/strong&gt;为了安全地将文件发送给别人而加密，也&lt;strong&gt;不是&lt;/strong&gt;为了完成工作而挂载/卸载的虚拟驱动器。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这种加密并不是长期备份——可能会被频繁访问，不是离线的，不是为了发送（从而或多或少依赖于公钥密码学），不是虚拟驱动器而是文件（尽管我觉得VeraCrypt在这是可用的）。&lt;/p&gt;
&lt;p&gt;那么这确实是个问题，尤其是，比如对于pgp的主密钥，不会有明文的备份。从而对可访问性提出要求——尽管实际上我们用U盘（而且还加密了）来解决，但多途径仍然要考虑——如果U盘丢失，也要保证安全性和易访问密钥呢？&lt;/p&gt;
&lt;p&gt;首先，密钥一般自身就有加密，以至于可以直接放出——但是没有人会这么做。将它签名（防止对密钥的意外修改）并整合，最简便的方法无疑是加密压缩包。完整性可有签名保证（而加密工具本身就面临拷问：怎么保证软件本身不是一个修改了的恶意版本？——这在后面还会导致我的一些考虑，考虑表明这一问题在苛刻条件下的确无解）。&lt;/p&gt;
&lt;p&gt;一个推荐工具是&lt;a href=&quot;https://github.com/FiloSottile/age&quot;&gt;age&lt;/a&gt;，至少有人认为它实现了目的。但是先生们，这只是把一个密钥问题变成了两个。总的来说，问题是——&lt;strong&gt;本地加密到底在防御什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这确实是个谜。如果离线环境的确处于危险，那么就必须具体情况的分析考虑物理来源的威胁。如果只是对于一种潜在的物理威胁，那么本地防御的强度根本不在加密（因为这是物理的）——那是给云端准备的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;弱点在于本地设备本身。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这里才引出本地的问题关键：&lt;/p&gt;
&lt;h2&gt;设备安全&lt;/h2&gt;
&lt;p&gt;开源硬件？除非有一条完整流程都可以完全掌控，否则也并无多用。当然，大可不必假设这么极端。只要稍微不那么极端，正常设备已经（但是不包括没有充分考虑过的手机）够了。&lt;/p&gt;
&lt;h3&gt;操作系统&lt;/h3&gt;
&lt;p&gt;linux发行版（比如debian），或者极端点的发行版比如&lt;a href=&quot;https://www.qubes-os.org/&quot;&gt;Qubes&lt;/a&gt;（我得说，我没用过） 已经太足够了。对于频繁移动的情景，&lt;a href=&quot;https://tails.boum.org/&quot;&gt;Tails&lt;/a&gt;是选择之一，但是移动情景的设备安全依赖于偶然匿名（毕竟你不能保证到处设备都安全），对于被追踪恐怕并无大用。也就是说，自己的设备终究是必要的，但是为了便携如果想用手机，那可需要认真考虑风险。&lt;/p&gt;
&lt;p&gt;Windows很受怀疑，但其实不极端的说也无所谓，更何况一般不止于此——诚然，这是一种侥幸，但是控制好连接可能比系统的漏洞要重要得多，Mac也是如此。&lt;/p&gt;
&lt;p&gt;这正是日常化的安全所在了。完全使用虚拟机以及上面那种系统当然是好的，但是太不日常了（当然日常似乎又不需要一点保护似的，问题是这之间的地带呢？）。在不影响日常下，我们当然尽可能采取更激进的措施。这里的尺度当然是我个人的，但是具体设计可以解耦并且在正确组装下提供相当的安全（当然对于产品的评估是争议的但凡可替换的大可自己代换之）&lt;/p&gt;
&lt;p&gt;使用Win的话，适当的保持安全更新和检查就要考虑了。细枝末节的安全细节我在此不多谈（那些到处都能看到的建议无需我来重复）。一个看上去关系不大的问题是文件整理——请确保你对&lt;strong&gt;你有什么&lt;/strong&gt;保持认识，让工具代劳管理不意味着忘记。&lt;/p&gt;
&lt;h3&gt;软件&lt;/h3&gt;
&lt;p&gt;开源+便携式软件是极好的，几乎避免了各种问题。目前对我来说，压缩，代理，文本编辑器，markdown编辑器，播放器，图片查看编辑都使用了便携开源产品。总之，避免不必要的专有软件总归是好的，毕竟现在已经妥协太多了。&lt;/p&gt;
&lt;p&gt;专用于安全的软件，我希望它们明白（并且实现）不要把实时数据放进硬盘——但这是不一定的。虚拟机和外置磁盘之类或许有助于此，但是有待考察。&lt;/p&gt;
&lt;h2&gt;元数据&lt;/h2&gt;
&lt;p&gt;本地元数据事先考虑是有其重要性的，你当然可以等到连接后再考虑，但是为什么不提前考虑一些呢？其实我会建议你使用纯文本避免元数据灾难，毕竟联机时的元数据问题够麻烦了。但总是有其他格式的嘛……&lt;/p&gt;
&lt;p&gt;Office文档危险得令人害怕，元数据当然要予以清除；PDF格式元数据也可能含有问题。这些都要予以考究，当然，你甚至可以利用这些进行伪装……&lt;/p&gt;
&lt;h2&gt;魔怔&lt;/h2&gt;
&lt;p&gt;本地问题是无止境的——在极度危险的物理问题下，本地的一切运算设施最好都一次性化，储存移动化。但是对常人来说&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;个人很少在本地面对攻击。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本地备份主要还是防止损失，但是这方面和云备份自然要结合，两者安全级别亦有不同。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;……To be continued……&lt;/p&gt;
</content:encoded><category>Secret</category><category>Device</category></item><item><title>关于Secret的沉思（3）：连接</title><link>https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%883%EF%BC%89%EF%BC%9A%E8%BF%9E%E6%8E%A5/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%883%EF%BC%89%EF%BC%9A%E8%BF%9E%E6%8E%A5/zh_cn/</guid><description>连接</description><pubDate>Wed, 14 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;题论&lt;/h2&gt;
&lt;p&gt;网络连接的安全性，这是一条线路的问题。在本篇中我们不论及web服务的问题，而是单论链接这一过程，链路中的潜在风险。&lt;/p&gt;
&lt;h2&gt;物理连接&lt;/h2&gt;
&lt;h3&gt;私人线路&lt;/h3&gt;
&lt;p&gt;家庭连接线路都是自己可考的，但是视ISP的不同有很大区别，这取决于ISP的具体情况，但总的来说等于考察ISP的可靠性。在这一层由于各种限制往往选择有限，因此安全策略最好在假定低信任下设计。就是说，即使在私人连接中，也不该传输明文。&lt;/p&gt;
&lt;h3&gt;公共连接&lt;/h3&gt;
&lt;p&gt;一种常用的连接是VPN，此处说的VPN是绑定在一定物理条件的，类似内网访问。显然它们并不适用于你的Secret（但是可能目的就是用于某些Secret，比如公司保密）。它们当然要求一定的认证，很大程度上被用于特定目的。也许攻击者会关注怎么绕过认证带来的风险，但对于保护的目的这不是我们关心的。对于常人，忠告是不要使用公司的网络做你的私人连接（除非你另有所图）（当然世上还有校园网之类……其本质一样，我们终究应该在更高层级考虑安全，这类似与连接公共网络，甚至更困难一点）。&lt;/p&gt;
&lt;h4&gt;蜂窝网络&lt;/h4&gt;
&lt;p&gt;蜂窝网络一般还是可靠的，但是在本篇的意义下，它不是最可信的。它的问题涉及当地的ISP以及你的SIM卡服务。在不愿意引入复杂元素时，或许应该避免无线连接。&lt;/p&gt;
&lt;p&gt;也有报告表明，2G,3G网络是存在一些可利用的攻击面的，总之，为了减少复杂度，对于无线连接应该保持上层应用本身的独立安全。&lt;/p&gt;
&lt;h4&gt;公共wifi[^1][^2]&lt;/h4&gt;
&lt;p&gt;这真不是面向正常考虑的，这也是Secret问题的矛盾之处：对于一定层面提高安全性的手段在更高层面上反而是跟危险的，反之亦有可能。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/TL-WN722N-01.avif&quot; alt=&quot;150Mbps High Gain Wireless USB Adapter 1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;某种设想是使用天线（如图）从远处连接公共wifi，这确实不是正常实践，从常理看，更好的选择是不要使用公共wifi暴露信息。但是在某种意义上，这比蜂窝网络有某些特殊功效……&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无线连接并不是没有意义的，但是它涉及的可能不是Secret本身，而是你。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;连接设备&lt;/h2&gt;
&lt;p&gt;有证据表明，MAC地址是存在跟踪风险的。现在很多操作系统都提供了随机化MAC地址的设计，但是请不要忘了检查这一点。此外，路由器之类的设备可能会产生类似的危险（事实上，过于智能的路由器本身就令人不安），路由器中也可能记录了相关信息[^3]。&lt;/p&gt;
&lt;p&gt;智能手机一向不被看作安全选择[^4]，事实上也确实不适用于复杂活动。并不是什么工作都能兼容手机（这是事实）。但是，也的确有考据的必要。在这方面，最佳实践由那些旅行者给出，他们告诉了我们使用一次性设备以及临时密钥。&lt;/p&gt;
&lt;p&gt;如果再退一步，IPhone是不是比Android安全？这没有确切结论。取决于评估的尺度，但多退几步，Iphone确实保障了常用的Secret[^5]。但是，对于特殊的情况，Android的自定义提供了一些手段，至于这些手段的可靠性，则仍有待研究。&lt;/p&gt;
&lt;p&gt;桌面被视为标准的考虑，关于其配置，在（2）中已经提及。取决于你的威胁模型，采取适当的设计。此外，链接留下的信息可能也有威胁之处。比如连接过的以太网和wifi记录&lt;a href=&quot;%5BwifiPass%5D(https://github.com/wangle201210/wifiPass)&quot;&gt;^6&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;反连接&lt;/h2&gt;
&lt;p&gt;是的，&lt;strong&gt;&lt;em&gt;反连接&lt;/em&gt;&lt;/strong&gt;[^7]。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So the question to ask ourselves is: “where is an acceptable place to communicate securely with another party.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The best answer I think is: in person.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;[^1]: &lt;a href=&quot;https://www.privacytools.io/guides/finding-safe-places-with-decent-public-wi-fi-for-better-privacy&quot;&gt;Finding safe places with decent public Wi-Fi for better privacy - Privacy Guides&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^2]: &lt;a href=&quot;https://www.privacytools.io/guides/using-long-range-antenna-to-connect-to-public-wi-fis-from-a-safe-distance&quot;&gt;Using long-range Antenna to connect to Public Wi-Fis from a safe distance - Privacy Guides&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^3]: &lt;a href=&quot;https://www.privacytools.io/guides/you-can-be-tracked-via-your-wi-fi-or-ethernet-mac-address&quot;&gt;You can be tracked via your Wi-Fi or Ethernet MAC address - Privacy Guides&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^4]: &lt;a href=&quot;https://www.privacytools.io/guides/warning-about-smartphones-and-smart-devices&quot;&gt;Warning about smartphones and smart devices - Privacy Guides&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^5]: &lt;a href=&quot;https://www.privacytools.io/guides/apple-s-imessage-service-and-privacy&quot;&gt;Apple&apos;s iMessage Service and Privacy - Privacy Guides&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^7]: &lt;a href=&quot;https://www.privacytools.io/guides/acceptable-places-to-communicate-securely-with-another-party&quot;&gt;Acceptable Places to Communicate Securely with Another Party - Privacy Guides&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>Secret</category><category>Web</category></item><item><title>关于Secret的沉思（4）：技术（连载）</title><link>https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%884%EF%BC%89%EF%BC%9A%E6%8A%80%E6%9C%AF%EF%BC%88%E8%BF%9E%E8%BD%BD%EF%BC%89/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%884%EF%BC%89%EF%BC%9A%E6%8A%80%E6%9C%AF%EF%BC%88%E8%BF%9E%E8%BD%BD%EF%BC%89/zh_cn/</guid><description>我的关于secret找到工具，具体技术的连载</description><pubDate>Mon, 28 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;前文讲述了一些抽象的策略，诚然还有一些问题未能讨论叙述。但是我想先将体系问题放一下，让我们来看一下常用的工具，技术。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;各web服务，同步，隐私&lt;/h2&gt;
&lt;p&gt;不细微地对互联网时代的主流产品作考究是难以想到它们收集了多少数据的（当然也有我们自作的），比如如果手机打开了google服务，电脑使用chrome和google搜索，且不谈gmail，仅此就使google账号上含有大量的数据，从搜索记录，浏览记录到手机应用的启动，定位，甚至可以储存数年之久。（尽管我并不是那么在意，事实上，我多少有些故意为之）。&lt;/p&gt;
&lt;p&gt;我在我的微软账号上不久前看见了数年前的手机照片，当时连onedrive是什么我都不知道，这不妨碍数据已经上传。&lt;/p&gt;
&lt;p&gt;在此我已经不想谈及国内设备自带的云服务等等。&lt;/p&gt;
&lt;p&gt;尽管实际意义可疑，至少各服务提供了相当的设置，全面的检查各web服务的隐私设置，&lt;strong&gt;关键在于尽可能不留下其他服务的痕迹&lt;/strong&gt;，因为我并不希望一些web服务与另一些有公开的关联。如果你不希望它们有&lt;strong&gt;任何&lt;/strong&gt;关联，那么你应该在客观上防止这种可能，而不是只是设置隐私。&lt;/p&gt;
&lt;p&gt;就同步来说，onedrive在Windows上的体验是足够好的（相当于自然地实现了本地+云端两重储存），配合VeraCrypt&lt;a href=&quot;%5BVeraCrypt%5D(https://www.veracrypt.fr/en/Home.html)&quot;&gt;^1&lt;/a&gt;，即在onedrive中保存VeraCrypt加密文件(据我所知，onedrive大约是完全支持增量同步的)，可谓是足够可靠的Secret备份方案，容量问题就看你了（拿来存密码，密钥其实根本不在乎容量）。&lt;/p&gt;
&lt;p&gt;说到各种web服务，密码管理器问题自然就来了（除主要几个服务如谷歌微软支付，其他我都尽可能采用了随机密码，那么自然只能用密码管理器了）。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;密码管理器&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;此处讨论不代表任何承诺，只是我个人的一种方案，具体可用性与安全性取决于你的需求和威胁模型。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一开始我是用浏览器的密码管理，诚然方便程度完全足够，但是安全上总是可疑，且强依赖于特定的第三方web服务，至多只能导出csv文件备份。而其他第三方密码管理在我看来只是改变了对哪个第三方的信任问题（也许密码管理器比google更可信），因而我故意采取了解耦的密码管理，也就是说，我不需要密码管理器本身具有云同步能力，而是通过其他办法实现，这提供了更多可用性和自由度，代价是复杂度。&lt;/p&gt;
&lt;p&gt;我采用了KeePassXC&lt;a href=&quot;%5BKeePassXC%5D(https://keepassxc.org/)&quot;&gt;^2&lt;/a&gt;。这只是一个管理密码数据库的软件，并不提供任何网络功能（这正是某些安全需求需要的），通过浏览器扩展，手机端实现（是的，没有官方手机端，但有几个实现），其他云服务同步数据库文件（数据库本身是加密的），从而实现同步的密码管理。&lt;/p&gt;
&lt;p&gt;目前的结论是比起浏览器自带的同步安全性当然更高，代价是要自己同步数据库，自动填充时要自己手动解锁数据库，但是不再依赖某种特定web服务，从而摆脱依赖。&lt;/p&gt;
&lt;p&gt;事实上，KeePassXC还有其他一些功能，如数据库可以储存二重验证（但是如果要达到效果就需要单独维护一个2FA数据库，否则等于没有双重验证，因而不宜采取），可以接入ssh代理用于管理ssh密钥（这个功能倒是可以考虑，我采取的是gpg-agent从而把ssh密钥和pgp合为一体），可以用Yubikey解锁数据库。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;PGP安全&lt;/h2&gt;
&lt;p&gt;请参见本系列下一期：PGP安全。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;浏览器&lt;/h2&gt;
&lt;p&gt;在使用google生态下chrome的体验的确是良好的，现在我们抛开各家浏览器本身生态的问题，单就浏览器的问题来说。&lt;/p&gt;
&lt;p&gt;浏览记录，搜索记录，书签的问题应该和浏览器本身的同步功能一并配置。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“浏览器指纹”是一种通过浏览器对网站可见的配置和设置信息来跟踪Web浏览器的方法，浏览器指纹就像我们人手上的指纹一样，具有个体辨识度，只不过现阶段浏览器指纹辨别的是浏览器。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;浏览器指纹有很多参数，包括浏览器标头，分辨率，接受语言，浏览器扩展，时区等等。&lt;s&gt;具体的防范请参见本系列以后。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;让我们看看我在有必要但是又不极端的时候的配置吧：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Clear Cache：清除浏览器缓存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CanvasBlock：屏蔽一些js&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ClearURLs：清理URL的追踪参数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;默认无历史经历，无Cookie&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IP Whois：查看网站的IP归属&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;NoScript：不执行js&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Timezone:随机时区&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;User-Agent：随机User-Agent&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;WebRTC：阻止WebRTC的泄露&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些尚且只是“不极端”的，进一步当然是tor启动。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;MFA&lt;/h2&gt;
&lt;p&gt;各网络服务的MFA。&lt;/p&gt;
&lt;p&gt;短信验证码我就不说了，没意思。&lt;/p&gt;
&lt;p&gt;邮件验证码也就那样吧，评估后决定用那个邮箱，哪个地址别名转发。最过分的应该我之前也提过：我是有转发两次的地址的……但是其实不怎么用，没什么意义还有泄露风险，多重转发的意义不在于此。&lt;/p&gt;
&lt;p&gt;然后是TOTP，手机上的验证器就是了。并不存在Keepass什么里，那样没意义了。但是备份也需考虑，和Recover Code什么的。&lt;/p&gt;
&lt;p&gt;此外是支持较少的&lt;em&gt;Passkeys&lt;/em&gt;，FIDO，WebAuthn这种的。目前windows，然后还有的是物理密钥。一般就是这两个，也就是我的设备或者我的物理密钥。支持的话感受确实不错，但是很少。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;全盘加密&lt;/h2&gt;
&lt;h3&gt;Windows BitLocker&lt;/h3&gt;
&lt;p&gt;windows下不用说是BitLocker。可配置的主要是，我手动考虑了系统驱动器的强度（指拉到AES256），然后是设置软件还是硬件加密。这里有一个大家可能比较熟识的问题，因为大部分人看到是默认设备加密，只是TPM自动解密，这种的只是防止拆硬盘下来而已……&lt;/p&gt;
&lt;p&gt;TPM+加强PIN（甚至USB密钥，至于……）才是需要的。没有增强PIN然后说什么“BitLocker”攻破云云也有点……这里当然还是看微软的说明最好&lt;a href=&quot;https://learn.microsoft.com/zh-cn/windows/security/operating-system-security/data-protection/bitlocker/&quot;&gt;BitLocker 概述 - Windows Security | Microsoft Learn&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;防止rootkit，这就需要安全启动+BIOS密码或TPM等。当然我也没BIOS密码就是了：关闭安全启动反正也会触发TPM就是了。&lt;/p&gt;
&lt;p&gt;TPM的加强PIN可防止暴力攻击PIN，即使TPM承诺了如此，我还是使用加强的PIN。分页文件的安全要确保系统驱动器已加密。DMA的配置当然是&lt;code&gt;锁定此计算机时禁用新的 DMA 设备&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;防止对内存的攻击需要多用Hibernate而不是Sleep。&lt;/p&gt;
&lt;p&gt;还有一些配置请参见&lt;a href=&quot;https://learn.microsoft.com/zh-cn/windows/security/operating-system-security/data-protection/bitlocker/configure?tabs=common&quot;&gt;配置 BitLocker - Windows Security | Microsoft Learn&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;Linux 全盘加密&lt;/h3&gt;
&lt;p&gt;后来用arch照着来了一套UKI+LUKS2的全盘加密理论上明文分区只有统一启动镜像即可，解锁方式三种：TPM+PIN，物理FIOD2密钥，Recover Key。其中TPM配置哪些测量寄存器需自己考察启动链。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;SSH&lt;/h2&gt;
&lt;p&gt;我个人选择PGP转出的SSH，这样就可以全部存于物理密钥一体，当然配置ssh-agent有所麻烦。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Git仓库&lt;/h2&gt;
&lt;p&gt;按理这是白嫖不好说什么，但是dotfiles什么的又git又迫害妄想症，于是&lt;a href=&quot;https://github.com/AGWA/git-crypt&quot;&gt;GitHub - AGWA/git-crypt: Transparent file encryption in git&lt;/a&gt;往里进——即使是私有仓库即使不是唉资本的Github，唉迫害妄想症。&lt;/p&gt;
&lt;hr /&gt;
</content:encoded><category>Secret</category><category>Technical</category></item><item><title>关于Secret的沉思（5）：PGP安全</title><link>https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%885%EF%BC%89%EF%BC%9APGP%E5%AE%89%E5%85%A8/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%885%EF%BC%89%EF%BC%9APGP%E5%AE%89%E5%85%A8/zh_cn/</guid><description>对于现在PGP实践的考究</description><pubDate>Mon, 28 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;PGP安全&lt;/h2&gt;
&lt;p&gt;PGP确实已经是个有丶糟糕的东西了[^1]，我不得不承认这一点。它高度地集成了太多不必要的功能（实际上是历史包袱），兼容危险的密码原语，过度的复杂度又阻止了实现以至于某些编程语言甚至无法提供充分的库。&lt;/p&gt;
&lt;p&gt;诚然，我并不希望PGP在没有充分继承其目标的实现出现前失败，但是也是该考虑缓解这些问题了，如果让我在此简单讨论一下对这些问题的缓解：&lt;/p&gt;
&lt;h2&gt;算法与兼容泥潭&lt;/h2&gt;
&lt;p&gt;个人只能通过约定表示密钥要向Curve 25519的转移来缓解（事实上，最新的gpg默认设置已经在这样做）——&lt;strong&gt;尽管软件会接受，但是人不能，至少不应该&lt;/strong&gt;。密钥的算法本身就是其可信度的一部分，也许gpg继续提供各种加密原语和曲线，但是应该尽可能摆脱它们的落后实现，比如说对于落后的实现提供警告（这一点还不够）。&lt;/p&gt;
&lt;h2&gt;数据包的复杂度&lt;/h2&gt;
&lt;p&gt;这个问题由于历史包袱无解，但是考虑到网络传输的发展，只要规范充分，这不是在安全性上致命的问题。&lt;/p&gt;
&lt;h2&gt;功能过多&lt;/h2&gt;
&lt;p&gt;其实这不见得就是致命的，问题在于各功能的解耦与实现。由于各功能都绑定在一组密钥对上，它提供了一种共有身份的加密签名，这本身是有意义的。但是由于兼容性与统一规范的复杂度，这使得各功能相对于专用的系统存在更多的攻击面。不可能完全寄希望于现有实现的完美，因此手动引入某种中间层可能是必要的。&lt;/p&gt;
&lt;p&gt;也就是说，使用pgp的功能来引入其他工具，而实际工作由其他工具完成。举例而言，使用pgp签名作为分发minsign签名公钥的渠道之一。&lt;/p&gt;
&lt;p&gt;最终目标当然是希望在规范上过渡到用引入的新层面取代旧有功能，当然大概是不会有这一天了……&lt;/p&gt;
&lt;h2&gt;用户体验&lt;/h2&gt;
&lt;p&gt;得承认，PGP在设计上提供了过多复杂使用方法，但是又没有足够简化而全面的默认配置 。这很大程度上是为了PGP当初设想的身份验证网络（&lt;a href=&quot;#%E4%BF%A1%E4%BB%BB%E4%B9%8B%E7%BD%91&quot;&gt;信任之网&lt;/a&gt;），密钥对间的相互签名和过多的元数据都是这一目的的遗留。&lt;/p&gt;
&lt;p&gt;但是我们得说，PGP从来都是一个&lt;strong&gt;额外&lt;/strong&gt;的安全层。将它比对于某个通信软件，某个加密软件是不合适的，因为它们的简化建立在内置的安全上，但是它们不处理总体问题，也不提供通用功能（尽管通用和安全本身多少有些矛盾）。&lt;/p&gt;
&lt;p&gt;命令行工具从来令人生畏，GUI开发一直勉强（至少我还没见到实现了GPG的命令行大部分功能的gui），这方面我发现一个较新实现&lt;a href=&quot;https://github.com/saturneric/GpgFrontend&quot;&gt;GpgFrontend&lt;/a&gt;，不幸，其热度很能说明PGP面临的处境。&lt;/p&gt;
&lt;p&gt;就我所知的gui支持仍然存在着各种各样的功能性不足，比如基本没有支持编辑子密钥的，生成密钥功能也不完全，还有自定义gpg路径，homedir，导出子密钥等。&lt;/p&gt;
&lt;p&gt;要想全面实现gpg提供的复杂功能又不失简单的默认配置，这是个有待发展的方向。&lt;/p&gt;
&lt;h2&gt;长期的密钥&lt;/h2&gt;
&lt;p&gt;这并不是关键,或者说这是我们常见的安全思想中最无望的：人人都建议我们频繁更换密码，但这&lt;strong&gt;在用户侧根本没有任何可能&lt;/strong&gt;。任何用户直接接触使用记忆的秘密都不可能频繁变化，这是人类的问题。&lt;/p&gt;
&lt;p&gt;启用新密钥的成本应该尽可能降低，这是个分发信任问题，但它终究依赖用户的习惯。因此我的建议是利用密钥过期时间这一点，并不是说真的一定过期，而是假定它可能过期。然后在续期时评估风险。即使如此，要确保分发的同步，这不是某一种方法能做到的。&lt;/p&gt;
&lt;p&gt;对应的，应该坚持清除过期密钥。不保留对它们的所有信任。&lt;/p&gt;
&lt;h2&gt;不连贯的身份&lt;/h2&gt;
&lt;p&gt;身份分发机制的单一可能是不存在的，这是一个事实。现在没有人指望线下交换和原有的密钥服务器以及信任网能提供全部（甚至只是大部分的信任）。加密的身份方案只是一种底层id：它不能证明自身。现在人们还需要更多贯穿各种网络服务的身份证明，在这方面的选择有&lt;a href=&quot;https://keyoxide.org/&quot;&gt;Keyoxide&lt;/a&gt;,至少它提供的思想是一种可能，关键点是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;我们确实使用其他网络服务，如果你只用邮箱交流就不需要真正的在线身份。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这些服务并不为我们所控，我们不能决定它们怎么体现，只能具体的支持各种方式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在线身份本身只能归结为一种融贯的诸联络方式，不存在身份背后的真实。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当然，它也准备放弃原用的pgp方式了，这是对的，在公钥的注释里放身份信息太滑稽了。但是身份分发系统无疑是没有实现的，即使规范已经存在，但是生态上尚未接受。&lt;/p&gt;
&lt;h2&gt;泄露元数据&lt;/h2&gt;
&lt;p&gt;PGP本身的uid元数据是显见的，但是这是其目的的一环，任何达成相应实现的方法都需要这样一个标识符。但是密钥服务器获取元数据，这是公开元数据信息只有唯一级别的结果。因此，更好的选择是让PGP密钥携带尽可能少的公开信息，而是分散它们到其他渠道（如&lt;a href=&quot;https://keyoxide.org/&quot;&gt;Keyoxide&lt;/a&gt;的思想）。&lt;/p&gt;
&lt;h2&gt;无前向保密性&lt;/h2&gt;
&lt;p&gt;这是要注意的。使用PGP不应该直接交换消息，而应该交换一次性会话密钥（当然要求用户进行安全的交换是不现实的，应该有工具来实现这一点）。但是，作为更长久的固定加密没有前向保密的加密也无法放弃：穿越时间的发送(笑&lt;/p&gt;
&lt;h2&gt;笨拙的密钥&lt;/h2&gt;
&lt;p&gt;格式的历史遗留，只能期待工具链的完善可以改善它。&lt;/p&gt;
&lt;h2&gt;协商&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;如果我们在过去 20 年中学到了关于密码学设计的 3 件重要的事情，其中至少 2 件是&lt;strong&gt;协商和兼容性是恶魔&lt;/strong&gt;。密码系统中的缺陷往往出现在细枝末节中，而不是主干上，而广泛的密码兼容性增加了细节的数量。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;必须坚决地弃用旧版本，&lt;strong&gt;尽管软件会接受，但是人不能，至少不应该&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;简陋的代码&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;GnuPG 也是 PGP 的有效参考实现，也是集成 PGP 加密的大多数其他工具的基础。 它哪儿也不会去，依赖PGP就是依赖GPG。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们正在期待的是&lt;a href=&quot;https://sequoia-pgp.org/&quot;&gt;Sequoia-PGP&lt;/a&gt;，这可能也是上述各种问题的解决（至少是缓解）期望所在。&lt;/p&gt;
&lt;h2&gt;信任之网&lt;/h2&gt;
&lt;p&gt;信任系统从来有两种思想，我们有了基于权威的CA体系，但是也有基于PGP的信任之网。但是怎样在现在的技术中搭建统一但可靠的信任网，这是个未解难题。在软件包信任上，刚才我看见的有&lt;a href=&quot;https://github.com/crev-dev/cargo-crev&quot;&gt;cargo-crev&lt;/a&gt;,但是至今即使只在开发者范畴这仍待考察，更勿论对于普通用户要想像CA证书一样的普遍（但是我们都知道，CA证书的弊端：&lt;a href=&quot;https://last-chance-for-eidas.org/&quot;&gt;Last Chance to fix eIDAS: Secret EU law threatens Internet security&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;即使PGP有这种那种的不足，但是其思想却不能弃用。如果失去了这种分散的信任，那么Last Chance就不是只是欧洲，只是浏览器证书……&lt;/p&gt;
&lt;p&gt;[^1]: &lt;a href=&quot;https://ulyc.github.io/2022/09/05/tr-pgp-problem-1/&quot;&gt;「译」PGP的问题（上） - C的博客 |UlyC&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>Secret</category><category>PGP</category></item><item><title>关于Secret的沉思（6）：设备</title><link>https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%886%EF%BC%89%EF%BC%9A%E8%AE%BE%E5%A4%87/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%886%EF%BC%89%EF%BC%9A%E8%AE%BE%E5%A4%87/zh_cn/</guid><description>你的设备是谁的？</description><pubDate>Sun, 08 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;重新审视设备&lt;/h2&gt;
&lt;p&gt;之前在&lt;a href=&quot;/blog/%E5%85%B3%E4%BA%8Esecret%E7%9A%84%E6%B2%89%E6%80%9D2%E6%9C%AC%E5%9C%B0/&quot;&gt;关于Secret的沉思（2）：本地&lt;/a&gt;中，我妄言了一些设备的大方向，在此我又想碰瓷一些细节及技术问题（多少是因为最近看到一些技术的博客），但是自知不是专业，所以让我们稍微克制些。&lt;/p&gt;
&lt;h3&gt;Android&lt;/h3&gt;
&lt;h4&gt;安全模型&lt;/h4&gt;
&lt;p&gt;在收入二手机实验后，我稍微触及了现代安卓安全模型的一角。如他人文中所言：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;默认情况下，Android 具有强大的安全模型，并包含&lt;a href=&quot;https://source.android.com/security/selinux/&quot;&gt;完整的系统 SELinux 策略&lt;/a&gt;、&lt;a href=&quot;https://source.android.com/security/app-sandbox&quot;&gt;强大的应用程序沙箱&lt;/a&gt;、&lt;a href=&quot;https://source.android.com/security/verifiedboot&quot;&gt;全面验证的启动&lt;/a&gt;、现代漏洞缓解措施（如&lt;a href=&quot;https://source.android.com/devices/tech/debug/cfi&quot;&gt;细粒度、前沿的控制流完整性&lt;/a&gt;和&lt;a href=&quot;https://source.android.com/devices/tech/debug/shadow-call-stack&quot;&gt;ShadowCallStack&lt;/a&gt; ）、内存安全语言（Java / Kotlin）等等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;但是这和本系列一直考究的偏向显然是不一样的，甚至不如说，反而是一种麻烦。&lt;/p&gt;
&lt;p&gt;在这里，专业人士指出要我们区分安全和隐私的区别，我承认了这一点，但是本系列终究是关于个人可以采用的沉思，而不是那些我们无力解决的问题的考察（比如控制流完整性的利用）。&lt;/p&gt;
&lt;p&gt;所以我要考虑的是怎么运用设备提供保护而又不被其困住。&lt;/p&gt;
&lt;h4&gt;Unlock and Root&lt;/h4&gt;
&lt;p&gt;现在的情况参见&lt;a href=&quot;https://github.com/KHwang9883/MobileModels/blob/master/misc/bootloader-kernel-source.md&quot;&gt;各 Android 手机厂商 Bootloader 解锁 / 内核开源 / 解锁后保修情况&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;从技术上看这是破环安全模型的一环，也还是如他人文中言：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;解锁 Android 中的引导加载程序存在很大的安全风险。它禁用&lt;a href=&quot;https://source.android.com/security/verifiedboot/&quot;&gt;验证启动&lt;/a&gt;，这是安全性的基本部分 模型。验证启动可确保基本系统和启动链的完整性，以防止&lt;a href=&quot;https://en.wikipedia.org/wiki/Evil_maid_attack&quot;&gt;邪恶女佣攻击&lt;/a&gt;和恶意软件持续存在。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;但是他的建议适用的是Pixel及甚至安全加强的系统+自定义信任根回锁的Pixel，&lt;/strong&gt; 而不是内置（）的安卓。&lt;/p&gt;
&lt;p&gt;所以最好的答案当然是照他说的做。&lt;/p&gt;
&lt;p&gt;但是如果不能？&lt;/p&gt;
&lt;p&gt;这也是为什么前文我说移动设备不太可信的原因，技术上码区其实知道，现代移动设备有着更全面现代的安全模型而不是桌面上的历史遗留（比如Linux就缺乏控制流完整性等，PC的安全启动时常不使用，定期的安全补丁也不熟）。但是但是但是，&lt;strong&gt;&lt;em&gt;它们是你的吗？&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是一个所有权问题。&lt;/p&gt;
&lt;p&gt;因此，移动设备的答案，可能在于多设备。&lt;/p&gt;
&lt;p&gt;我倾向使用未解锁的设备作为一种日常，而可完全控制的设备作为一种实验。后者的使用实际上是高度困难的，这和流行的刷机泛滥相对立。当然某人用kt重写jvav的模块对此或许才算有权控制root的设备，而对于普通用户呢？&lt;/p&gt;
&lt;p&gt;因此答案回到了一开始的结论，移动设备的不可信上，甚至回到了IPhone……&lt;/p&gt;
&lt;h3&gt;操作系统&lt;/h3&gt;
&lt;h4&gt;Linux&lt;/h4&gt;
&lt;p&gt;这真是个有趣的反转，因为我们会看到（实际上也知道），Linux从不是为了Secret而设计的。因此，对其安全性的理解基于一种了解的缺乏（因为在桌面上的不流行），也就是基于隐瞒的安全，这在密码学上被认为不可靠。至少作为一种桌面操作系统方面，Linux并不会带来特别的安全，你需要评估自己的威胁模型。&lt;/p&gt;
&lt;p&gt;当然人们会说，这是不了解不懂导致的，但是我们忘记了更好的是&lt;code&gt;默认安全&lt;/code&gt;。Windows现在已经默认使用了Bitlocker全盘加密，Mac不必说，事实上移动设备都实行全面加密，只有桌面设备仍然保持明文，尤其是Linux，如果不手动使用加密，大部分桌面Linux安装我敢说，都是明文的（在这里我考虑到最流行的Ubuntu查询了一下，安装程序应该没有提供加密），，，&lt;/p&gt;
&lt;p&gt;安全启动，TPM测量的加密，即使忽略桌面上的启动代码本身的安全问题，这些措施也仍然匮乏并且对用户不友好。&lt;/p&gt;
&lt;p&gt;码区们通过像&lt;a href=&quot;/blog/arch%E4%B9%8B%E4%B9%B1/&quot;&gt;arch之乱&lt;/a&gt;或者安全偏执狂的使用方式保持他们能看到的Secret（当然由于不是专业的安全研究，所以不谈&lt;code&gt;Exploit Mitigations&lt;/code&gt;之类），但是这不是对用户友善的方案。按理说应该是技术细节由专家处理好并将用户可控制的选择交给用户，而现在并没有做到。&lt;/p&gt;
&lt;p&gt;而且事实上：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一个相当安全的 Linux 发行版所需的强化程度远远超出人们的想象。
你需要完全重新设计操作系统的功能并实施完整的系统 MAC 策略、完整的验证启动（不仅针对内核，还针对 整个基础系统）、强大的沙箱架构、强化的内核、现代漏洞缓解措施的广泛使用以及更多。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是现实的可能吗？想想Android在此之上做的工作吧！&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;生态系统在原文被认为是一大牵扯，比如:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Linux 上的大多数程序都是用内存不安全语言编写的，例如 C 或 C++，这导致了大多数已发现的安全漏洞。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我知道这是典中典了（由于R开头语言的炒作），但是这是几年前的文章。不过我们也要想到，其他系统上的生态安全是由厂商强制实行的，而Linux上则寄希望于&lt;code&gt;Rewrite&lt;/code&gt;……&lt;/p&gt;
&lt;h4&gt;Windows&lt;/h4&gt;
&lt;p&gt;对此我们说再多又怎么能比得上巨硬的文档呢？&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/zh-cn/windows-hardware/design/device-experiences/oem-security-considerations&quot;&gt;原始设备制造商 (OEM) 的安全注意事项 | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们至多补充一些对于用户要考察的选择：&lt;/p&gt;
&lt;p&gt;比如说各家厂商喜欢在电脑中内嵌他们的控制软体，联想啦华硕啦，但是其中许多不必要的部分可以消除，或者存在替代（当然有些硬件功能独占）。微软的系统现在也一股味，禁用多余的不必要组件是你应该考虑的。&lt;/p&gt;
</content:encoded><category>Secret</category><category>Device</category></item><item><title>关于Secret的沉思（特辑）：桌面启动链</title><link>https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%88%E7%89%B9%E8%BE%91%EF%BC%89%EF%BC%9A%E6%A1%8C%E9%9D%A2%E5%90%AF%E5%8A%A8%E9%93%BE/zh_cn/</link><guid isPermaLink="true">https://blog.wind-mask.com/blog/%E5%85%B3%E4%BA%8ESecret%E7%9A%84%E6%B2%89%E6%80%9D%EF%BC%88%E7%89%B9%E8%BE%91%EF%BC%89%EF%BC%9A%E6%A1%8C%E9%9D%A2%E5%90%AF%E5%8A%A8%E9%93%BE/zh_cn/</guid><description>爱你的偏执</description><pubDate>Tue, 08 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;桌面启动链的真实&lt;/h2&gt;
&lt;p&gt;作为码区似乎没有什么可说的——真的吗？&lt;/p&gt;
&lt;p&gt;本文旨在从底部开始——尽管底部是我们无法改变的——出发点。&lt;/p&gt;
&lt;p&gt;参考文章:[^1][^2][^3][^4]&lt;/p&gt;
&lt;h3&gt;固件（firmware）&lt;/h3&gt;
&lt;p&gt;当我们尝试从底部时，我们会想到BIOS，UEFI，我们将其称为 Host Boot Firmware——是的，这一层很关键，它是初始化系统并为其他所有内容奠定基础代码的基础代码。但问题是：现代平台中嵌入的固件比大多数人意识到的要多得多。固件不限于主 SPI flash 芯片。散布在您的系统中的是分立和集成设备，每个设备都有自己的固件，通常驻留在自己单独的闪存芯片中。&lt;/p&gt;
&lt;p&gt;这一点有一些超出预料，倒也不值得惊讶，&lt;a href=&quot;https://www.intel.com/content/www/us/en/support/articles/000008927/software/chipset-software.html&quot;&gt;What is Intel® Management Engine?&lt;/a&gt; 其实很广为人知了，有一些不可控的方法对其进行操弄——我没试过——但是一直如幽灵。&lt;/p&gt;
&lt;p&gt;固件主要两部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Host Boot Firmware：主要的 SPI flash 代码，包括 BIOS（以及其他一些内容）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设备固件：在网卡、GPU、SSD 和嵌入式控制器等单个组件上运行的经常被忽视的固件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&lt;strong&gt;主机处理器启动固件&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boot firmware:&lt;/strong&gt; 主要是BIOS/UEFI。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Management Engine (ME) Firmware:&lt;/strong&gt; 嗯，比如说刚才提及的&lt;code&gt;Intel ME&lt;/code&gt;，嵌入在芯片组中的子系统。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;集成设备的固件：&lt;/strong&gt; 例如主板上集成的网卡的固件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platform Configuration Data：&lt;/strong&gt; 初始化和运行时期间硬件行为的持久设置。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;设备固件&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OEM 嵌入式控制器 （EC）：&lt;/strong&gt; 集成到大多数笔记本电脑中的专用微控制器，旨在管理基本的平台功能。EC源于早期电脑中的键盘控制器（KBC），控制最初的硬件起点：开机/关机，休眠，唤醒（就电源状态意义上），电池管理；对集成的键盘扫描，触摸板，功能键，状态指示灯；风扇控制，笔记本电脑屏幕的开合检测。尽管 EC 由于缺乏总线主控功能而无法直接访问主机的内存，但它在键盘作中的特权角色会带来安全问题——对笔记本的按键记录：这是EC最经典、最直接的威胁。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;网络接口控制器 (Network Interface Controller, NIC)&lt;/strong&gt; ：网卡。其安全威胁不言而喻。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;图形处理单元 （GPU）：&lt;/strong&gt; 我相信随着变形金刚的盛行，在CPU外处理器上将能发起更强大的攻击，成为持久和隐蔽访问的攻击者的高价值目标。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;存储设备 （HDD/SSD）：&lt;/strong&gt; 依靠嵌入的固件来控制读取写入，这对数据安全是一个值得考究的问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可信平台模块 （TPM）：&lt;/strong&gt; 一个专门的安全模块，旨在提供安全的加密和密钥储存，测量启动链。这也是对启动后的我们能看到的固件的信任根部。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;电源：&lt;/strong&gt; 是的，电池当然也有自己的微控制器和固件，用于控制充电和放电周期、监控电池健康状况并防止过热。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Intel Boot Guard&lt;/h3&gt;
&lt;p&gt;Boot Guard 在以下两种模式之一下运行：&lt;code&gt;measured boot&lt;/code&gt;或&lt;code&gt;verified boot&lt;/code&gt;，第三个选项将两者组合在一起。在制造过程中，ORM 通过熔断处理器上的保险丝来确定模式。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;measured boot&lt;/code&gt;中，&lt;code&gt;CRTM&lt;/code&gt;(Core Root of Trust of Measurement)将接下来执行的代码的哈希记录到TPM的PCRs中；而在&lt;code&gt;verified boot&lt;/code&gt;中，&lt;code&gt;CRTM&lt;/code&gt;根据OEM融合到处理器中的密钥检查下一阶段代码的签名。Boot Guard BootROM 将控制权传递给 Intel 签名的 Authenticated Code Module （ACM），这里存在一些资源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boot Policy Manifest (BPM):&lt;/strong&gt; 由PK签名的策略文件，记录需要验证的固件有哪些，和映像一起存储在固件中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Firmware Descriptor (FD):&lt;/strong&gt; 定义固件的存储区域。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;启动的最初阶段是：硬件信任根验证BPM和FD，然后是根据BPM的记录验证其中的固件卷，并且确保执行的正确性——这里存在多个阶段的实现——到达启动设备选择，到这里Boot Guard结束。从这里开始，执行安全启动策略（如果你记得启动它）以验证引导加载程序和 UEFI 应用程序。&lt;/p&gt;
&lt;h3&gt;安全启动&lt;/h3&gt;
&lt;p&gt;我知道，在我们的层面，这只能是一个UEFI功能而已。当然，这一概念在不同平台上有几种实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;UEFI&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;机器所有者密钥 （MOK）&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Android 验证启动&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对与本文谈论的UEFI，基点是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;UEFI 安全启动假定原始设备制造商 （OEM） 提供的系统固件是受信任的，因此本身不一定需要任何验证。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此，其验证的对象包括操作系统的引导加载程序或其他第三方的UEFI 应用程序。&lt;/p&gt;
&lt;p&gt;在实现中的早期阶段在不提，我们观察验证的起点。&lt;/p&gt;
&lt;p&gt;映像加载过程中。DXE 验证加载到 UEFI 环境中的所有可执行映像：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;UEFI 应用程序：引导加载程序，比如对窗口的&lt;code&gt;bootmgfw.efi&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DXE 驱动程序：特定于设备的驱动程序，用于在 DXE 阶段配置和初始化硬件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UEFI 选项 ROM：由附加设备（如 PCIe 卡）提供的固件模块。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UEFI Shell 工具：从外部存储加载或预安装在固件中的应用程序或实用程序。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然而上述一切都是可变的，因此在其下需要硬件级别的信任根。这就是上文所谓 Intel Boot Guard 。&lt;/p&gt;
&lt;p&gt;参考文章：[^5]&lt;/p&gt;
&lt;h4&gt;安全启动密钥&lt;/h4&gt;
&lt;p&gt;围绕平台密钥 （PK） 和密钥交换密钥 （KEK） 系统构建的，具有受信任签名和吊销签名的数据库：
来自微软的图片：
&lt;img src=&quot;https://raw.githubusercontent.com/wiki/microsoft/secureboot_objects/images/secure_boot_variables.png&quot; alt=&quot;secure_boot_variables&quot; /&gt;&lt;/p&gt;
&lt;h5&gt;&lt;strong&gt;PK (Platform Key)&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;PK 是 UEFI 安全启动层次结构中的顶级密钥。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;默认情况下，OEM 在系统制造时控制 PK。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;你应该替换掉它（如果你竟然看到这里）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;它的主要功能是授权对密钥交换密钥 （KEK） 数据库的更改。（进一步KEK 数据库用于授权对签名数据库 （&lt;code&gt;db&lt;/code&gt;） 的更新。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Platform Key 是平台的密钥，存储在 PK 变量中。 它的工作是控制对 PK 变量和 KEK 变量的访问。 在大多数实现中，一次只能存储一个密钥在 PK 中，并且 PK 只能是一个 X509 密钥。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过设置模式进行更新&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;&lt;strong&gt;KEK (Key Exchange Key)&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;KEK 充当管理信任数据库更新的中间机构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用于允许平台密钥 （PK） 所有者将控制权委托给作系统供应商或管理员&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持多个密钥，使第三方作系统或驱动程序供应商能够提供已签名的二进制文件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用于更新签名数据库，并存储在 KEK 变量中。 它可用于更新当前签名数据库或对二进制文件进行签名以实现有效执行。 在大多数当前实现中，KEK 变量可能包含多个密钥，这些密钥可能是 X509 类型或RSA2048。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用PK更新&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;&lt;strong&gt;Signature Databases&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;db：保存受信任的签名、证书和哈希的列表。&lt;/p&gt;
&lt;p&gt;db 变量可以包含一组混合的密钥、签名或哈希。 在安全引导模式下，存储在 efi 二进制文件中的签名（如果没有签名，则为 SHA-256 哈希值）与数据库中的条目进行比较。 如果出现以下任一情况，则将执行该镜像：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;未签名，但是映像的 SHA-256 哈希值位于数据库中，或者&lt;/li&gt;
&lt;li&gt;映像已签名，并且签名本身位于数据库中，或&lt;/li&gt;
&lt;li&gt;映像已签名，签名密钥在数据库中（并且签名有效）&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dbx：保存已吊销或列入黑名单的签名、证书和哈希的列表。&lt;/p&gt;
&lt;p&gt;dbx 变量可以包含密钥、签名或哈希。在安全引导模式下，将存储在 efi 二进制文件中的签名（如果二进制文件未签名，则使用 SHA-256 计算）与数据库中的条目进行比较。 如果出现以下任一情况，则拒绝执行：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;二进制文件未签名，并且二进制文件的 SHA-256 哈希值位于 dbx 或&lt;/li&gt;
&lt;li&gt;映像已签名，但是签名在 dbx 中&lt;/li&gt;
&lt;li&gt;映像已签名，但是用于创建签名的密钥与 dbx 中的条目匹配&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用KEK更新 db 和 dbx。&lt;/p&gt;
&lt;h4&gt;对代码的签名&lt;/h4&gt;
&lt;p&gt;操作系统签名的公钥或证书被放入&lt;code&gt;db&lt;/code&gt;，进一步用于验证操作系统的映像。&lt;/p&gt;
&lt;p&gt;那么实际上，安全启动到底能运行什么样的代码（efi二进制文件）呢？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;未签名，但具有 SHA-256 哈希值，该哈希值位于 &lt;code&gt;db&lt;/code&gt; 中，且不在 &lt;code&gt;dbx&lt;/code&gt; 中，或者&lt;/li&gt;
&lt;li&gt;已签名，并且在 &lt;code&gt;db&lt;/code&gt; 中具有签名，且签名不在 &lt;code&gt;dbx&lt;/code&gt; 中，或者&lt;/li&gt;
&lt;li&gt;由 KEK 中的密钥或 &lt;code&gt;db&lt;/code&gt; 中的密钥签名，并且密钥和签名都不在 &lt;code&gt;dbx&lt;/code&gt; 中。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;现实&lt;/h3&gt;
&lt;p&gt;说了这么多，实际上我们能做什么呢？答案是很凄凉的。&lt;/p&gt;
&lt;p&gt;首先的首先，请谨慎对待此文（应该是是这整个系列，因为是关乎安全的问题），对启动和固件级的修改可能导致变砖，请审慎行事。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;首先，替换固件是困难的，对此勇于前进的朋友可以参考&lt;a href=&quot;https://libreboot.org/&quot;&gt;Libreboot&lt;/a&gt;——如果你有适合的机器。&lt;/p&gt;
&lt;p&gt;我们手上有的只是UEFI之后的故事。&lt;/p&gt;
&lt;h3&gt;UEFI 之后&lt;/h3&gt;
&lt;p&gt;首先看窗口系统[^6]：&lt;/p&gt;
&lt;p&gt;你的KEK中应该有&lt;code&gt;Microsoft Corporation KEK CA 2011&lt;/code&gt;，不过：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Microsoft Corporation KEK CA 2011 is set to expire in 2026, and all OEMs must create, sign, and submit updates for the new Microsoft Corporation KEK CA 2023 to Microsoft. This will allow Microsoft to update in-market devices with the new Microsoft KEK CA, allowing systems to continue receiving DB and DBX updates after 2026. For instructions and test collateral, please visit &lt;a href=&quot;https://aka.ms/KEKUpdatePackage&quot;&gt;KEKUpdatePackage&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;之后将被换为&lt;code&gt;Microsoft Corporation KEK 2K CA 2023&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果你来得够早，你的windows启动管理器应该还是&lt;code&gt;Microsoft Windows Production PCA 2011&lt;/code&gt;签名的,不过它很快它将被&lt;code&gt;Windows UEFI CA 2023&lt;/code&gt;取代。
此外&lt;code&gt;db&lt;/code&gt;中应该还有&lt;code&gt;Microsoft Corporation UEFI CA 2011&lt;/code&gt;——以后是新的&lt;code&gt;Microsoft UEFI CA 2023&lt;/code&gt;，就是shim所用到的签名——及&lt;code&gt;Microsoft Option ROM UEFI CA 2023&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这些就是唉资本微软藏在你电脑中的东西了，实际上即使你宣称摆脱了窗口系统，也没人敢肯定能摆脱它们——一些第三方固件也需要他们签名，这里关于&lt;code&gt;Option ROM&lt;/code&gt;有一些尝试（通过tpm日志以寻找并替换签名）。&lt;/p&gt;
&lt;p&gt;我们可以做的事情——由上文可以想见：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果主板正确实行安全启动，应该可以安全地替换&lt;code&gt;PK&lt;/code&gt;。OEM的固件更新应该使用不同于PK的密钥（但这又是另一个安全问题了）：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在所有电脑上，建议不要将 PK 用作安全固件更新密钥。 如果 PKpriv 泄露，安全固件更新密钥也会泄露（因为它们是相同的）。 在这种情况下，可能无法进行更新以注册新的 PKpub，因为更新过程也会泄密。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;需要以下 Microsoft KEK 证书以启用对不良映像的吊销，通过更新 dbx，并且可能更新数据库以准备较新的 Windows 签名映像:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Corporation KEK 2K CA 2023&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;若要允许 Windows OS 加载程序加载，必须将以下证书包含在 db 中：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Windows UEFI CA 2023&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;blockquote&gt;
&lt;p&gt;除了锁定为仅启动 Windows 的系统，OEM 应考虑包括 Microsoft 第三方 UEFI CA 和 Microsoft Option ROM CA，以允许来自第三方的 UEFI 驱动程序和应用程序在电脑上运行，而无需用户执行其他步骤。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Corporation UEFI CA 2011&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft UEFI CA 2023&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Option ROM UEFI CA 2023&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就是你面对的东西了。&lt;/p&gt;
&lt;p&gt;对KEK的更新实际上十几年未曾有过——直到最近——计划在今年这些证书将需要全部更新（毕竟明年2011的证书就过期了）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;PK&lt;/h4&gt;
&lt;p&gt;用于接受对KEK的更新，实际上几乎不需要，因此只要固件允许，可以替换之。&lt;/p&gt;
&lt;h4&gt;KEK&lt;/h4&gt;
&lt;p&gt;如果你需要使用窗口来帮你更新dbx，那么微软的KEK也是需要的——不过微软对dbx的更新是公开的&lt;a href=&quot;https://github.com/microsoft/secureboot_objects/blob/main/PreSignedObjects/DBX/dbx_info_msft_06_10_25.json&quot;&gt;secureboot_objects/PreSignedObjects/DBX/dbx_info_msft_06_10_25.json at main · microsoft/secureboot_objects · GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;也许你可以用自己的KEK签署之。&lt;/p&gt;
&lt;p&gt;至于对db的更新？那是很少见的，如果你使用林纳斯系统，那就更无所谓了，至多你也可以手动加入&lt;code&gt;Windows UEFI CA&lt;/code&gt;。&lt;/p&gt;
&lt;h4&gt;DB&lt;/h4&gt;
&lt;p&gt;如果你需要直接启动&lt;code&gt;Windows Boot Manager&lt;/code&gt;，那么你必须使用&lt;code&gt;Windows UEFI CA&lt;/code&gt;，如果自己签名似乎会导致校验不通过。&lt;/p&gt;
&lt;p&gt;为什么说是直接呢？&lt;/p&gt;
&lt;p&gt;因为事实上我们使用链式启动，而据我现知：各种启动引导器似乎都没有在安全启动下验证链式启动：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The GRUB, except the chainloader command, works with the UEFI secure boot and the shim.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;据说安全启动下grub应该无法insmod，然而我并未察觉到。&lt;/p&gt;
&lt;p&gt;因此你可以链式启动&lt;code&gt;Windows Boot Manager&lt;/code&gt;，这样就不需要签名——但是我们需要其他验证机制——下文再议。&lt;/p&gt;
&lt;p&gt;直接启动的efi文件必须有db中签名（或哈希记录），对我们来说无外乎两者：UKI和bootloader。&lt;/p&gt;
&lt;h4&gt;DBX&lt;/h4&gt;
&lt;p&gt;对DBX的更新上文说过了，可以来自windows update，此外Linux下如果没有去除微软的KEK，那么也许&lt;a href=&quot;https://github.com/fwupd/fwupd/blob/main/plugins/uefi-dbx/README.md&quot;&gt;fwupd-uefi-dbx&lt;/a&gt;会更新dbx——但是无论如何它不可能在去除了微软KEK下运行。&lt;/p&gt;
&lt;h3&gt;启动项&lt;/h3&gt;
&lt;p&gt;启动链总算来到第一个可以设置的地方了。UEFI下你可以启动的程序，即&lt;code&gt;PE32+ executable (DLL) (EFI application) x86-64&lt;/code&gt;。
如果是窗口，你应该看到了&lt;code&gt;bootmgfw.efi&lt;/code&gt;，对很多林纳斯来说，大概是&lt;code&gt;grubx64.efi&lt;/code&gt;之类。&lt;/p&gt;
&lt;p&gt;因此，第一步答案比较明显了：我们要签署我们的bootloader。&lt;/p&gt;
&lt;p&gt;当当当然，你可以手动执行生成和上述密钥管理的全部——有人说过，密码学只有一个（还是两个问题），即密钥管理。&lt;/p&gt;
&lt;p&gt;下面我要讨论不是怎么签署或者密钥管理，而是启动链本身。上文已经介绍了到bootloader前的安全问题，下面的问题就是之后了。&lt;/p&gt;
&lt;p&gt;首先，我们还是致力于林纳斯，窗口的问题少说：&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- markdownlint-disable MD026 --&amp;gt;&lt;/p&gt;
&lt;h4&gt;Linux，启动！&lt;/h4&gt;
&lt;p&gt;首先，这里有几种启动方式（我不提到shim等方式）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;最传统的，bootloader加载内核和initramfs&lt;/p&gt;
&lt;p&gt;我们必须在签名bootloader中实现对内核和initramfs的验证，这方面grub好像有使用PGP实现的功能（且支持加密的分区存放内核和initramfs，这的确是特别的），Limine则支持用配置文件中的b2sum校验完整性，结合嵌入配置文件的b2sum到Limine可执行文件，再使用安全启动签名从而形成完整的验证链（据称shim在一些情况中可以配合bootloader验证内核，未测试，且对于内核的cmdline和initramfs的完整性可疑）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内核可以作为&lt;a href=&quot;https://docs.kernel.org/admin-guide/efi-stub.html&quot;&gt;EFI stub&lt;/a&gt;启动&lt;/p&gt;
&lt;p&gt;未尝试过，由于这种方法似乎不可能支持加密根分区。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进一步的，&lt;a href=&quot;https://uapi-group.org/specifications/specs/unified_kernel_image/&quot;&gt;Unified Kernel Image&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在此启动的将是一整个打包了&lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html&quot;&gt;systemd-stub&lt;/a&gt;，内核，内核命令行参数，ininramfs。微码的EFI文件，利用了安全启动的签名直接验证了全部完整性。[^7]&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在确保UKI完整性的情况下，也可以链式启动UKI——此处需要的安全策略和对windows启动管理器一样。&lt;/p&gt;
&lt;p&gt;再参考[^7]中，可以看到这一套体系中还需要结合TPM测量以实现完全的启动链控制。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;调用的 UKI 中所有上述列出的 PE 部分都会被测量到 TPM PCR 11 中。在 UKI 初始化之前，此 TPM PCR 预计全为零。因此，如果已知 PE 映像中包含的资源，则预计算非常简单。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;而根据&lt;code&gt;systemd-stub&lt;/code&gt;&lt;a href=&quot;%5Bsystemd-stub%5D(https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html)&quot;&gt;^8&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Table 2. OS Resource PCR Summary&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OS Resource Measurement&lt;/th&gt;
&lt;th&gt;PCR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;systemd-stub code (the entry point of the unified PE binary)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core kernel code (embedded in unified PE binary)&lt;/td&gt;
&lt;td&gt;4 + 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OS release information (embedded in the unified PE binary)&lt;/td&gt;
&lt;td&gt;4 + 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main initrd (embedded in unified PE binary)&lt;/td&gt;
&lt;td&gt;4 + 9 + 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microcode initrd (embedded in unified PE binary)&lt;/td&gt;
&lt;td&gt;4 + 9 + 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default kernel command line (embedded in unified PE binary)&lt;/td&gt;
&lt;td&gt;4 + 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overridden kernel command line&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boot splash (embedded in the unified PE binary)&lt;/td&gt;
&lt;td&gt;4 + 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TPM2 PCR signature JSON (embedded in unified PE binary, synthesized into initrd)&lt;/td&gt;
&lt;td&gt;4 + 9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TPM2 PCR PEM public key (embedded in unified PE binary, synthesized into initrd)&lt;/td&gt;
&lt;td&gt;4 + 9 + 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credentials (synthesized initrd from companion files)&lt;/td&gt;
&lt;td&gt;9 + 12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System Extensions (synthesized initrd from companion files)&lt;/td&gt;
&lt;td&gt;9 + 13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration Extensions (synthesized initrd from companion files)&lt;/td&gt;
&lt;td&gt;9 + 12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selected profile unless zero&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;啊，看了头大。但是，总而言之，主要是4和9和11代表了UKI的测量&lt;/p&gt;
&lt;p&gt;关键的一个实施：安全启动下UKI将优先使用嵌入的&lt;code&gt;.cmdline&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;按照设想，本来：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根文件系统加密密钥应该绑定到 TPM PCR 11，这样只有在启动一组特定的 UKI 后才能解锁&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为此，现在你需要一个脚本，在更新UKI后，更新LUKS的tpm测量的密钥的slot（设计上，PCR 11是可以提前计算出来的，然后通过在UKI中附带其签名来不用更改LUKS的密钥slot——然而我还在考虑中：&lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemd-measure.html&quot;&gt;systemd-measure&lt;/a&gt;——因此先不绑定到11）。&lt;/p&gt;
&lt;p&gt;至此，下面是根文件系统的挂载，参考是&lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemd-cryptsetup@.service.html&quot;&gt;systemd-cryptsetup&lt;/a&gt;和&lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemd-cryptenroll.html&quot;&gt;systemd-cryptenroll&lt;/a&gt;，绑定到上述测量的PCR以解锁根文件系统，然后 switch-root。&lt;/p&gt;
&lt;p&gt;至此，启动完成，进入到Linux系统内。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;未细举的参考&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/&quot;&gt;🔏 Linux TPM PCR Registry 🗒️&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://tianocore-docs.github.io/edk2-TrustedBootChain/release-1.00/3_TCG_Trusted_Boot_Chain_in_EDKII.html&quot;&gt;TCG Trusted Boot Chain in EDK II&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot&quot;&gt;Unified Extensible Firmware Interface/Secure Boot - ArchWiki&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^1]: &lt;a href=&quot;https://medium.com/@sekyourityblog/do-you-know-who-your-computer-is-and-can-you-trust-it-4646b67deaf4&quot;&gt;Secure boot, Measured boot, and Roots of Trust&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^2]: &lt;a href=&quot;https://medium.com/@sekyourityblog/flash-chip-ef3df1001afb&quot;&gt;What’s hiding in your SPI Flash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^3]: &lt;a href=&quot;https://medium.com/@sekyourityblog/secure-boot-explained-every-system-boot-is-a-negotiation-of-trust-be32fb023439&quot;&gt;Secure Boot Explained — Every system boot is a negotiation of trust. Secure Boot ensures the terms, but are they yours?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^4]: &lt;a href=&quot;https://medium.com/@sekyourityblog/firmware-the-hidden-weak-link-in-your-tech-stack-and-no-it-is-not-just-bios-22dce12f4c58&quot;&gt;Firmware: The Hidden Weak Link in Your Tech Stack(And no, it is not just BIOS)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^5]: &lt;a href=&quot;https://blog.hansenpartnership.com/the-meaning-of-all-the-uefi-keys/&quot;&gt;The Meaning of all the UEFI Keys&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^6]: &lt;a href=&quot;https://learn.microsoft.com/zh-cn/windows-hardware/manufacture/desktop/windows-secure-boot-key-creation-and-management-guidance?view=windows-11&quot;&gt;Windows 安全启动密钥创建和管理指南&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[^7]: &lt;a href=&quot;https://0pointer.net/blog/brave-new-trusted-boot-world.html&quot;&gt;🔐 Brave New Trusted Boot World 🚀&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>Secret</category><category>Boot</category></item></channel></rss>