比尔盖子 博客

Page 3 of 21

想加密数据?不要购买 ACOS5-64 智能卡!

更新 1:经过 tonghuix 与官方的交涉,现在我获得了全套管理工具,和 PKCS#11 的动态库,已经可以和 gpg 联合使用了。然而灵活性还是太差,因为私有中间件只能在 x86 上工作,打算进行反向工程。

如果你熟悉并使用以 RSA 为代表的非对称加密算法,来加密文件、签名电子邮件或者登录 SSH 服务器,那么你肯定会遇到密钥便携性的问题。如果你带着个装有私钥的 U 盘四处跑,私钥什么时候被拷贝走了估计你也不会知道。

为了解决这个问题,可以将私钥放到一个黑盒里,并由黑盒完成全部的加密和签名,同时没有办法从中获取私钥,还可以设置 PIN 码。这个黑盒就是智能卡。有两种规格的智能卡可以实现上述需求:其一是 OpenPGP card,由 FSFE 主导开发,开箱即用,但很难获得;第二是各类符合 PKCS#11 标准的智能卡。

ACOS5-64 就是一款 PKCS#11 的智能卡。它不但支持非对称加密,还支持对称加密,从特性上看,是一款十分强大的智能卡。然而千万不要购买它,这卡……没!有!驱!动!对,你没有看错!

既然支持 PKCS#11,那么应该直接使用通用工具就可以了吧?图样图森破!PKCS#11 允许厂商提供一个动态库来提供 PKCS#11,而这个动态库就相当于私有驱动。而 ACOS5-64 支持 PKCS#11,却没有提供驱动。事实上,ACS 公司确实开发了相关的驱动,但附在 SDK 里,需要另行购买,然而,这个驱动究竟是 Windows Only,还是也有 so 模块我们不得而知。而且,就算有 Linux 模块,但因为这是二进制驱动,因此无法在非 x86 下正常工作。

但不同于其它卡片的是,此卡的具体规格和 Datasheet 均可获得,不需要签署 NDA。曾有一 MIT 学生在 2010 年企图在 OpenSC 框架下实现此卡驱动,然而他仅仅完成了基本功能,以及 RSA 1024 的支持,最终因为众多坑放弃开发。

也就是说,这卡在任何系统平台与应用程序上,均完全无法使用!

wget 滚动显示文件名的 Bug —— 低级错误永不可避

更新 2:wget 1.16.1 版本已包括补丁,问题彻底解决。
更新 1:我的补丁已经被接受了,Bug 已修复。

wget 是 GNU 开发的实用下载工具,最近它刚刚发布了 v1.16。

进度条样式

先介绍一下背景,wget 向来就有两种进度条,“点形”和“条形”,其中,“条形”还有可选的跑马灯效果。

刷屏点形”是指这样的效果

  0K .......... .......... .......... .......... ..........  0%  107K 8m30s
 50K .......... .......... .......... .......... ..........  0% 52.0K 13m0s
100K .......... .......... .......... .......... ..........  0% 31.3K 18m21s
150K .......... .......... .......... .......... ..........  0% 22.0K 24m4s

如果你的终端设备功能有限,不能做到即时更新屏幕内容,或者是重定向到了文件,“点形”进度条就很实用。

“条形”就是指这样的效果

filename   0%[                     ] 134.05K  59.7KB/s

很适合可以即时更新的终端。

这两种类型可以使用

wget --progress=dot
wget --progress=bar

切换。

跑马灯

现在问题来了。如果文件名称很长,条形进度条左侧那一点点空间显示不下该怎么办呢?wget 的开发者想出了一个跑马灯效果,很像大街上的 LED 横幅,不停的让文字滚动,这样用户就可以“管窥”整个文件名了。

然而,盖子发现一个特别郁闷,而且能逼死强迫症患者的问题。wget 的滚动有 Bug,文件名的最后一个字符始终不显示!就象这样:

this_is_a_
his_is_a_f
is_is_a_fi
s_is_a_fil
_is_a_file
is_a_file_
s_a_file_n
_a_file_na
a_file_nam
            <-- WTF!
this_is_a_

实现

progress.c 中,不难发现这段代码

  if (((orig_filename_cols > MAX_FILENAME_COLS) && !opt.noscroll) && !done)
    offset_cols = ((int) bp->tick) % (orig_filename_cols - MAX_FILENAME_COLS);      
  else
    offset_cols = 0;
  offset_bytes = cols_to_bytes (bp->f_download, offset_cols, cols_ret);
  bytes_in_filename = cols_to_bytes (bp->f_download + offset_bytes, MAX_FILENAME_COLS, cols_ret);
  memcpy (p, bp->f_download + offset_bytes, bytes_in_filename);
  p += bytes_in_filename;

由于有一些字符占用 1 字节,有些占用 2 字节,因此下面部分的代码全都在处理把字符转换成字节数的问题,其实这段代码做的事情很简单

 if (orig_filename_cols > MAX_FILENAME_COLS
     && !opt.noscroll  // 没有禁用跑马灯滚动效果
     && !done)  // 下载仍未结束

     offset_cols = bp->tick % (orig_filename_cols - MAX_FILENAME_COLS);

bp->tickint,每刷新一次进度条,它会就自增 1,可以把它理解成进度条刷新的次数,(orig_filename_cols - MAX_FILENAME_COLS) 就不用多说了,显然是计算文件名超出最大允许长度的字符数。

最后,从 offset_cols 开始截取 orig_filename_cols,一直截取 MAX_FILENAME_COLS 个字符。

用取余数运算来实现不断截取字符串的特性,看起来还是挺巧妙的。不过,正是这里的代码存在着问题。

范围差 1

写程序的时候,经常因为该 + 1/- 1 而忘记了(len() vs. 下标),不该加减 1 的时候乱加减,导致典型的越界往往和正确范围只差 1 位。

再比如这些令人困惑的表述

def range(begin, end)
/* 11 日到 21 日间断电 */
/* 变量取值范围 0 ~ 256 */

到底包不包括这个 end,或者包不包括 21 日,或者 256?P.S:幸好数学家们早就意识到了这个问题,发明了区间表示法,圆括号表示“排除”,方括号表示“包括”。

wget 的“最后一个字符始终不显示”的 Bug,具有典型的“范围差 1”的特征,那真正的问题到底出不出在这里呢?

实验

为了看看 wget 的这个算法到底有没有 Bug,写个程序检验一下。

FILENAME = "this_is_a_file_name"
MAX = 10

def cut(string, _min, _max):
    assert _max <= len(string) - 1 
    return string[_min:_max]

for i in range(0, 20):
    offset = i % (len(FILENAME) - MAX)
    print(offset, offset + MAX, cut(FILENAME, offset, offset + MAX))

这就是 Python 版本的简单算法实现了,运行之后:

0 10 this_is_a_
1 11 his_is_a_f
2 12 is_is_a_fi
3 13 s_is_a_fil
4 14 _is_a_file
5 15 is_a_file_
6 16 s_a_file_n
7 17 _a_file_na
8 18 a_file_nam
                 <-- WTF!
0 10 this_is_a_

果然出错?那么问题究竟出在哪里呢?拿这个例子分析一下,”this_is_a_file_name” 有 19 个字符,而最大的允许字符是 10 个。那么,那么,相差 9,看来编写者认为 9 就是需要的滚动次数。然而,滚动 9 次,就是有 10 种组合啊!

果然忘记 + 1,而接下来就不用多说了。就等开发者接受补丁了。真是低级错误不可避啊……

OpenRC 无法正确配置 IPv6

Gentoo 的 OpenRC 配置 IP 的方式是非常简洁的,只需简单修改 /etc/conf.d/net 就能完成任务。
然而,比尔盖子的 Gentoo Hardened 一直无法正确的配置 IPv6,主要表现是可以配置地址和 DNS,却认为网关是无效地址。

config_eth0="106.187.49.164/24
             2400:8900::f03c:91ff:fe73:f8c7/64
"
routes_eth0="
    default via 106.187.49.1
    default via fe80::1
"

dns_servers_eth0="106.187.34.20 106.187.35.20 106.187.36.20 2400:8900::2 2400:8900::3"

有问题的就是这个 fe80::1

今天解决这个问题,发现这个问题的成因和解决方案都简单的气人。事实上,OpenRC 支持使用不同的工具初始化网络。在默认情况下,OpenRC 初始化网络的工具是最传统的工具,这些工具对 IPv6 支持有问题。而新的 iproute2 就没有这个问题。

emerge iproute2

然后在 /etc/conf.d/net 行首加 modules="iproute2" 让 OpenRC 使用 iproute2 的工具链配置网络即可。

高性能 ext4 临时文件系统

很多时候,我们的文件系统中并不保存重要数据。比如 /var/tmp, /usr/src/usr/portage,对于这些目录,我们可以专门创建一个文件系统,并以牺牲数据安全性(因为我们不需要)换取最高性能。

如果你的 ext4 分区中储存的是 /usr/portage 这样大量小文件构成的数据库,可以使用以下参数格式化:

mkfs.ext4 -b 2048 -i 2048 -O "dir_index" /dev/sdX

-b 2048 -i 2048 确保分区中有足够的 inodes,避免因大量小文件导致明明有空间却没有 inode 的困境发生;”dir_index” 会让内核以类似 ReiserFS 的 btree 储存文件,对于大量小文件有很大的性能提升。但其它类型的数据分区,比如 /usr/src/var/tmp 请勿使用此方法格式化,请使用默认参数。

使用不安全的写入方式提升性能:

tune2fs -o journal_data_writeback /dev/sdX

禁用日志:

tune2fs -O ^has_journal /dev/sdX

使用以下挂载参数(写在 /etc/fstab):

defaults,noatime,nodiratime,barrier=0,nosuid,nodev,data=writeback

noatimenodiratime 彻底禁用一切访问时间记录;barrier=0 禁用为安全保护而设计的写入屏障;nosuidnodev 提升安全性;data=writeback 使用不安全而最高效的写入方式。

效果拔群!

服务器 SSH 端口再次变更

由于众所周知的原因,现将服务器端口号重新变更为 22000。望互相转告,以免影响诸位的正常使用。

啥?你说我为啥不用 iptables 转发端口?抵抗的行为会让服务器 IP 遭殃的……

GRUB 2 里的 play 命令

GRUB 2 中,有个 play 命令,用来让蜂鸣器播放音频。这可不是什么玩法……

它接受无限个参数,对于一个典型的三参数的调用,文档如下

play [tempo] [pitch] [duration] {pitch2 duration2...}

tempo 是全局速度,所有的 pitch 都受到它的影响;pitch 即要播放的音频,单位为赫兹;duration 是持续时间。

为了播放音乐,需要搞清楚一个调用究竟是多长时间。把 play 看作一个函数,接受 tempo 和 duration 两个参数。经过试验:

tempo duration 时间
60 1 1 s
60 2 2 s
30 1 2 s
30 2 4 s
120 1 1/2 s
120 2 1 s

从这里大概可以看出来,

时长 (s) = 60 / t * d

这样,如果使 t = 60000,d 就正好对应于 0.001 s,即一毫秒。这样,就可以轻松的将基于毫秒时长的 Linux 下 beep 调用翻译成 GRUB 2 的 play 调用了。

另外,这还可以用于 sleep。GRUB 2 提供的 sleep 分辨率只有一秒,但使用 play,让 pitch = 0 Hz,就曲线实现了毫秒级的 sleep 命令。

Buffalo WZR-HP-G450H 刷 OpenWRT

三年前,比尔盖子买了一台 Buffalo WHR-HP-G54,这台路由器是曾经的神器,具有和 Linksys WRT54G 对抗的能力,是 802.11g 路由器的经典。

然而,仅 16 MB 的内存和 4 MB 的闪存,连运行 Linux 3.x 都存在困难,直接导致内核 OOM 杀掉重要进程,从而无限重启。虽然网络上充斥更换内存颗粒的教程,但比尔盖子这样的硬件杀手,即使有热风枪,也不敢下手,否则主板大概就要被我烤糊了。

后来,又使用树莓派充当路由器。ath9k_htc 的 USB 设备虽然开放,然而却有很多 Bugs,导致连接不稳定。就连 OpenWRT 团队,自己打了一堆没有并入内核的补丁,也只能说是基本而不是彻底解决 ath 的问题;发射功率低,信号不好;再加上受限于 USB 2.0 的传输速度(算上树莓派的硬限制,USB 2.0 的理论速度绝对是达不到的);同时,缺少有线接口,导致无线出现问题时无法上网,因此不适合长期使用。

因此,最近便打算购买一款新的路由器。

Continue reading

服务器 SSH 端口变更

由于众所周知的原因。服务器 SSH 的端口变更为 22001,请及时更换,以免影响您的正常使用。

关于龙芯开发的一点见解

月初的时候,Bowen Han 在《关于》页面问了这么一个问题:

我发现现在龙芯的开发者们都很分散,做的工作最后都因为版本的更新失效了,不知道你有什么高见么,龙芯官方不怎么给力啊。

感谢你的评论。这条评论我搁置了很长时间,十分抱歉。

我不想做完备的论述,此时此刻我还在调试 YeeLoong 8089D 用的 SM712 显卡驱动。我只想简单说一说我的第一看法,但是我依然不小心把它写成了一篇长论述。因此,特别将这个回答独立成博文一篇。

Continue reading

Fedora 20 的 r8168 与 rtl8723be 驱动

今天在 Freenode 的 #fedora-zh 上,有个网友的笔记本有线网卡使用的是 r8168,无线网卡是 rtl8723be,r8168 的驱动 r8169 存在问题,rtl8723be 的驱动才刚刚进入 Linux 3.16。因此两者均无法使用,需要下载 Realtek 发布的驱动。

如果在有网络的情况下,倒是非常好解决的。啥,你说没网?请先阅读《无网络》部分,使其有网络后,从这里继续。

Continue reading

« Older posts Newer posts »

Copyright © 2019 比尔盖子 博客

Theme by Anders NorenUp ↑