qyb的博客

决赛,我们来啦!

胜利属于穆里尼奥,在70分钟内巴萨都打不进10个人的国米2个球,瓜迪奥拉完败。

上半场莫塔被罚下后一度有些混乱,但是下半场45分钟除了那个失球,基本上防守没有出太大差错。也得感谢塞萨尔今天做出了几次关键扑救。

希望今年收获双冠!甚至三冠

Topic: 运动

生活,就是一个28天接着一个28天

对线上产品实施定期更新已经坚持了大半年。在去年开始这个流程的时候,俺雄心勃勃的制定了三周更新的计划,史称"三周迭代"。但是执行几个月后,感觉大家有点吃不消,就改成了4周的模式。为了确保流程,强制定义了几个重要时间节点,发布在 wiki 上。附图就是接下来 28 天的时间安排。

十几次更新做下来,一个是大家做项目的能力显著提高,另外就是"持续运营"这个概念被广泛接受。我觉得这个是迄今为止我为部门做的最大贡献了

Topic: 商业

IronPython 2.6.1 补上了 SSL 支持

CPython 2.6 里面,把以前的 socket.ssl() 去掉,新增加了一个 ssl module,提供了更完善的API,包括 server-side SSL。IronPython 2.6.0 刚发布的时候,估计把和 CPython 2.6 兼容性的工作重心放在语言核心方面了,漏掉了对这个 ssl 模块的支持,现在终于在 2.6.1 里面补上了。

就我个人测试,IP 的 client-side ssl 是能用的,但是还有点小小的兼容性问题。我在mail-list里指出了这点,开发者为此新开了一个 issue #26778。server-side 用起来明显和 CPython 不同,使用自制的证书(我的翻墙 Proxy)会在握手阶段报一个 "The credentials supplied to the package were not recognized" 错误,现在正在等待列表上的开发者给我回复..

BTW: 我猛然发现我的翻墙工具基本上和 GAppProxy 一样。只不过他是用 gzip 压缩,而我是用 des 来穿过 GFW(这样安全性要好那么一点点);而且我 HTTPS 支持部分的代码比他漂亮,呵呵

Topic: 技术

从U盘安装 Windows XP

假如你的机器没有光驱(常见于上网本,或超便携笔记本)而需要重装操作系统,那就只能从USB安装了。而最方便快捷的方法无疑是生成USB安装盘。

我是因为光驱挂了,所以去往上找相关方案的。搜了一圈,看起来最傻瓜的方法是MSFN 论坛上的一个 "WinSetupFromUSB with GUI",我用的是当前最新的 1.0 beta6

但是它的界面过于 geek 了,经我实战校验,只需要三步(参考下图):
1. 选择一个操作系统类型
2. 选择安装光盘路径,换言之就是那个i386的父目录
3. GO
总之可以忽略界面开始的两个格式化相关按钮。如果为了清理空间而格式化的话,大可以在资源管理器里弄

然后就是从U盘启动,选择First Step,进入 XP 文本安装状态,大约5分钟完成,重起,继续从U盘启动,选择Second Step,进入 XP 图形安装界面,10-15分钟装完,再次重起。接下来就没U盘啥事了。


install xp from usb

Topic: 技术

几个邮件服务商的EHLO SIZE结果

  • gmail.com, 35651584
  • hotmail.com, 29696000
  • sina.cn, 52428800
  • 126/QQ, 不支持在 EHLO 的时候响应 SIZE

考虑到附件大小编码后要增加1/3,上述三个邮箱 SIZE * 0.75 后分别为:26,738,688/gmail,22,272,000/hotmail, 39,321,600/sina

换句话说,向别人发邮件带个20M附件是靠谱的. 再大些的话,就得先看看对方服务器是否支持了

Topic: 技术

昨日香巴拉穿越

好久没有运动了,加上衣服准备的不好,老婆还把可外挂登山杖的背包带去了西安,于是全程无杖,最后两个山头爬得是相当累。下一段时间得每天锻炼了...

这是为岗什卡做准备的系列训练之一。接下来是4月10日凤凰坨、4月17日海陀山,4月24日白河野外攀岩

如果没有重要事情的话,5月8日就去岗什卡了

Topic: 生活

搜狐邮件中心将推出本地客户端——极速邮

提前剧透一下:

  1. 该 Windows 客户端是用IronPython开发的,因此要求 .NET Framework 2.0 环境
  2. 该客户端采用了特殊协议,暂时只支持搜狐闪电邮系列邮箱。包括 @sohu.com、@vip.sohu.com、@sogou.com、@chinaren.com
  3. 大概 5 月发布
  4. 有可能同期以开源形式推出 Linux、MacOSX 的版本
Topic: 商业

翻墙代理的加密部分

就是怎么在 PHP/mcrypt 和 PyCrypto 之间 DES(或其他加密算法,比如3DES/RSA/..) 通信的问题,我这里还额外考察了下 .NET 平台的算法

网上询问相关问题的还挺多,尤其是 PHP 和 .NET 之间的 DES 转换。主要是 PHP/mcrypt 隐藏了 padding 的细节,且只保留了 ZERO_PADDING 模式,所以不明白cyrpto原理的不太容易找到症结所在。我的传输方案统一用 pkcs#7 padding.

首先是给服务器端增加的 PKCS#7 PADDING 函数,来自PHP官方函数手册上某人的注释

function padding_pkcs7($crypto, $mode, $dat)
{
$block = mcrypt_get_block_size($crypto, $mode);
$len = strlen($dat);
$padding = $block - ($len % $block);
$dat .= str_repeat(chr($padding),$padding);
return $dat;

}

function strip_pkcs7($crypto, $mode, $text)
{
$block = mcrypt_get_block_size($crypto, $mode);
$packing = ord($text{strlen($text) - 1});
if($packing and ($packing < $block)){
for($P = strlen($text) - 1; $P >= strlen($text) - $packing; $P--){
if(ord($text{$P}) != $packing){
$packing = 0;
}
}
}
return substr($text,0,strlen($text) - $packing);
}

本地端 .NET 平台的 descrypto 封装

# -*- coding: utf-8 -*-
# ipcrypto.py
from System import Array, Byte
from System.Security.Cryptography import DESCryptoServiceProvider, CryptoStream, CryptoStreamMode, PaddingMode

from System.IO import MemoryStream, StreamWriter, StreamReader

from hashlib import md5

def s2ab(s):

return Array[Byte](tuple(Byte(ord(c)) for c in s))

def ab2s(ab, len=0):
if len == 0: len = ab.Length

return ''.join([chr(ab[i]) for i in range(len)])

class descrypto():
def __init__(self, password):
pwmd5 = md5(password).digest()
self.key = s2ab(pwmd5[:8])
self.iv = s2ab(pwmd5[8:])

self.des = DESCryptoServiceProvider() # 缺省 des.Mode = CipherMode.CBC

def enc(self, input):
ms = MemoryStream()
encStream = CryptoStream(ms, self.des.CreateEncryptor(self.key, self.iv), CryptoStreamMode.Write)
sw = StreamWriter(encStream)
sw.Write(input)
sw.Flush()
encStream.FlushFinalBlock()

return ab2s(ms.GetBuffer(), ms.Length)

def dec(self, input):
ms = MemoryStream(s2ab(input))
length = len(input)
decStream = CryptoStream(ms, self.des.CreateDecryptor(self.key, self.iv), CryptoStreamMode.Read)
byteArray = Array.CreateInstance(Byte, length)
length = decStream.Read(byteArray, 0, length)
return ab2s(byteArray, length)

本地端 PyCrypto 的封装

# -*- coding: utf-8 -*-
# pycrypto.py
from hashlib import md5

from Crypto.Cipher import DES

class descrypto():
def __init__(self, password):
pwmd5 = md5(password).digest()
self.key = pwmd5[:8]

self.iv = pwmd5[8:]

def enc(self, input):
des = DES.new(self.key, DES.MODE_CBC, self.iv)
lastblock = len(input) % 8
if lastblock > 0:
padding = 8 - lastblock

input += padding * chr(padding)

return des.encrypt(input)

def dec(self, input):
des = DES.new(self.key, DES.MODE_CBC, self.iv)
ret = des.decrypt(input)
padding = ord(ret[-1])
for i in range(padding):
if ord(ret[-1 - i]) != padding:
padding = 0
break
if padding > 0:
ret = ret[:-padding]
return ret

Topic: 技术

翻墙代理的远程部分

既然要翻墙,肯定要有一台墙外主机。为了配合加密,以及 HTTP/HTTPS 协议代理,需要编译有 mcrypt 和 curl 的 PHP;在如今我估计这应该都属于web主机标配环境.

如果是文本数据,就加密后返回;如果非文本数据,就不加密了。返回给本地代理以第一个字符是"0" or "1"来指示接下来的数据是否经过加密。

配合其运行的代码见
翻墙代理的本地部分

翻墙代理的加密部分


$PASSWORD = "yourpasswordhere";
$pw_md5 = md5($PASSWORD, true);
$key = substr($pw_md5, 0, 8);

$iv = substr($pw_md5, 8, 8);

$input = file_get_contents("php://input");

$td = mcrypt_module_open('des', '', 'cbc', '');
mcrypt_generic_init($td, $key, $iv);
if (strlen($input) > 0 && $input % 8 == 0) {

$input = strip_pkcs7("des", "cbc", mdecrypt_generic($td, $input));

$req = explode("\r\n\r\n", $input, 3);

$rawreqline = explode(" ", $req[0]);

$url = parse_url($rawreqline[1]);

$_headers = explode("\r\n", trim($req[1]));
//$_headers[count($_headers)] = "X-Forwarded-For: ".$_SERVER['REMOTE_ADDR'];
if ($url["scheme"] == "http" || $url["scheme"] == "https") {
$ch = curl_init($rawreqline[1]);
/* avoid HTTP/1.1 Transfer-Encoding: chunked */
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
curl_setopt($ch, CURLOPT_HEADER, 1);
if ($url["scheme"] == "https") {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if ($rawreqline[0] == "POST" && count($req) == 3) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req[2]);
}

$data = curl_exec($ch);

curl_close($ch);
}

$text_mode = "0";

$res = explode("\r\n\r\n", $data, 2);
$header = explode("\r\n", $res[0], 2); // STATUS HEADER
$headers = explode("\r\n", $header[1]);
foreach ($headers as $hline) {
$h = explode(":", $hline, 2);
$k = strtolower(trim($h[0]));
if ($k == "content-type" && strpos(strtolower(trim($h[1])), "text/") === 0) {
$text_mode = "1";
break;
}
}
if ($text_mode == "1") {
mcrypt_generic_deinit($td);
mcrypt_generic_init($td, $key, $iv);
$data = mcrypt_generic($td, padding_pkcs7("des", "cbc", $data));
}
$data = $text_mode . $data;
}
?>

Topic: 技术
订阅 RSS - qyb的博客