Archive for March, 2005

late-bound data binding 的妙处

搞定 支持 aspx 语法的 Template 引擎 后即开始编写 template以及试验从 windows forms 程序传递数据。在我的设计标准中,数据结构 Custom Object 有先于 DataSet,一般尽量避免 late-bound data binding:
< %#="" databinder.eval(container,="" "dataitem.title")="" %="">
而是建议 bind to cutom object:
< %#="" ((wbeditor.post)="" container.dataitem).title="" %="">‘>

asp.net web 系统是应该这么做的,但是用在 Template 引擎 中有个问题:asp.net host 固定要到 bin 目录下去找包含 WBEditor.Post 类定义的 DLL。从程序发布 (depolyment) 的观点来看,不是很舒服的结构。这种情况下 late-bound data binding 就很有用了。它不要依赖于 DLL,而是在 run-time 通过 reflection 去取值。

有趣的是 DataBinder.Eval 不仅仅能对付 Container.DataItem,还能用在 object 上。< %#="" databinder.eval(post,="" "createddate",="" "d")="" %="">

1 comment March 28th, 2005

支持 aspx 语法的 Template 引擎

最近需要一个 .NET 下的 Template 引擎来支持自定义网页模版。一般如 Velocity(java), Smarty(php) 等 Template 引擎都自带一套语法。而 CodeSmith 的概念是用 ASPX 语法。这个概念卖点不仅仅在于能直接用已经熟悉了的ASPX 语法,还在于能嵌入 inline code,并且能用 server control,例如 DataGrid DataList 和 Repeater。Template 本身可以用 WebMatrix 来编辑。所以是很酷的设计。

m3rlin 中找到了 hosting the ASP.NET runtime 的办法,包括创建新的 AppDomain 和 通过 HttpContext 传递数据等等。这样我有了能用在 windows forms 程序中的支持 ASPX 语法的 Template 引擎。

ps. Template 引擎通常可以用来做代码生成工具的核心。

1 comment March 28th, 2005

HTML 语法加亮编辑器

终于为下一版的 WB Editor 搞定了HTML 语法加亮编辑器。

老的编辑器的原理同这篇文章。它实现了实时染色的功能 (highlight on the fly),但是一篇文章新载入时,全文染色效率极差 (feel it’s being choked)。

想了很多办法试图分页,但不成功。于是开始分析 SharpDevelop 的编辑器和 JSource 的编辑器的代码。发现如果自己从头做工程量巨大。接着向 SharpDevelop 开发者询价,得到个目前无法支付的价格。

回头再想,全文染色慢的主要原因就是用 SelectionStart 和 SelectionLength 两个属性来操作。甚至根据 Syntax colorizing with Speller engine using TOM and CSAPI 一文,用了 TOM 接口也没有改观。

再研究,能不能直接生成 rtf,终于发现 Delphi 的文章 Automatic Syntax Highlighting Using a RichEdit Control 介绍了 rtf 的格式以及 Syntax Highlighting With RichEdit 一文给出了生成 HTML 语法加亮 rtf 的办法。

用我现成的 HTML Tokenizer 接上去一试效果很好,200 多K 的HTML 加亮没有延迟的感觉。准备升级 WB Editor 2 了。

Add comment March 24th, 2005

OleDbCommand.Parameters

折腾了两天,才发现 OLE DB .NET 不支持 named parameters。

The SQL Server .NET data provider (SqlClient) supports named parameters. Therefore, when you use the SqlCommand object, you do not have add the parameters in any particular order, but the parameters must have the correct name. In this case, you must add the at sign (@) prefix to the parameter names.

Alternatively, the OLE DB .NET data provider does not support named parameters. Therefore, when you use the OleDbCommand object, you must add the parameters in the correct order (which is the same order that is defined at the backend stored procedure). In this case, you do not need to add the “@” prefix to the parameter names, and the parameter names do not have to match those that are defined at the stored procedure.

From: http://support.microsoft.com/kb/310071/EN-US/

另:Microsoft Support 开始用 URL Re-Write 技术了 :)

Add comment March 18th, 2005

.NET 下制作 Shareware 的关键技术探讨二:非对称加密

前文描述了.NET 为 Shareware 程序开发提供了许可证检测机制,使得开发者可以集中精力到如何验证许可证。

把一个信息经由不可信任的途径传达给接受者的时候,就需要进行加密。对于信息接受者来说,则需要确认信息的来源是来自正确的,就需要进行数字签名。Shareware 程序拥有者要告诉远在用户机器上的自己的程序用户有权使用这么个信息,是要加密的。因为你不想让其他人知道这个信息是如何表达的,更不能让人家如法炮制出相同的信息。

.NET 提供了加密和数字签名等现在用在网络安全方面的技术用到 Shareware 上是绝对好的。下面是用 .NET RSACryptoServiceProvider 的一个办法。

RSA 是一种非对称加密技术 Asymmetric Cryptography,即加密用的密码和解密用的密码是分开,相互不能推演的。如果知道了解密用的密码,无法知道加密用的密码。这比对称加密安全性好,因为 Shareware 总是需要一个密码用来解注册码,用对称加密的情况下,如果被人从程序中分析到了解密的密码,有可能复制注册机。而用非对称加密,即使解密的密码泄漏,也无法做出注册机。

1、生成和保存密码

创建个新的 RSACryptoServiceProvider 对象,.NET 就随机生成了密码。
RSACryptoServiceProvider 对象可以把密码输出成 xml。

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
Console.WriteLine(rsa.ToXmlString(true));

这个 xml 是要好好保存起来的秘密。其中包含了用来做注册机的加密用的 private key 和 将来在程序中用来解密的用 public key。

<RSAKeyValue>
  <Modulus></Modulus>
  <Exponent></Exponent>
  <P></P>
  <Q></Q>
  <DP></DP>
  <DQ></DQ>
  <InverseQ></InverseQ>
  <D></D>
</RSAKeyValue>

2、注册机

根据上面的密码 xml,可以这样生成注册机所需要的 RSACryptoServiceProvider 对象。然后用数字签名的办法生成注册码。

SignData 是做数字签名。它与单纯的加密解密有区别。

如果要变成注册码是这样一句话:某人于某时某地购买了我的软件。单纯的加密后的解密你会看到这句原话(从内存里什么地方挖出来)。而用数字签名办法,解密后看不到原话,而是一个单向计算出来的 Hash 值。所以对所传送的信息多了一层保护。RSACryptoServiceProvider 提供了直接的生成数字签名和验证数字签名的方法。

private static byte[]CreateKey()
{
    byte[] digestInput = fileEncoding.GetBytes(GetRegistrationInfo());
    RSACryptoServiceProvider RSAalg= new RSACryptoServiceProvider();
    RSAalg.ImportParameters(GetPrivateKeyParam()); 
    return RSAalg.SignData(digestInput, new SHA1CryptoServiceProvider());
}

private static string GetRegistrationInfo()
{
    return GetValue(“NAME”)+GetValue(“PURCHASE_TIME”)+GetValue(“FROM”);
}

private static RSAParametersGetPrivateKeyParam()
{
    RSAParameters param = new RSAParameters(); 
    param.D= Convert.FromBase64String(“…”); 
    param.DP = Convert.FromBase64String(“…”);
    param.DQ = Convert.FromBase64String(“…”); 
    param.Q = Convert.FromBase64String(“…”); 
    param.P = Convert.FromBase64String(“…”); 
    param.Exponent= Convert.FromBase64String(“…”); 
    param.Modulus= Convert.FromBase64String(“…”); 
    param.InverseQ= Convert.FromBase64String(“…”); 
    return param;
}

从 XML 中生成 private key 来制作数字签名,需要用到全部参数:D, DP, DQ, P, Q, Exponent, Modulus, InverseQ.

3、验证数字签名

在 Shareware 程序中,从密码 xml 文件生成验证数字签名所需要的 SACryptoServiceProvider 对象,然后请用户输入他的名字、以及购买软件的时间地点。组成一个句子:某人于某时某地购买了我的软件,用 SACryptoServiceProvider 验证一下它的数字签名是否符合注册机生成注册码。

private static bool VerifyKey(byte[]digestInput, byte[] signed)

    RSACryptoServiceProviderRSAalg = new RSACryptoServiceProvider();
    RSAalg.ImportParameters(GetPublicKeyParam()); 
    return RSAalg.VerifyData(digestInput, new SHA1CryptoServiceProvider(),signed);
}

private
static RSAParametersGetPublicKeyParam()

    RSAParameters param = new RSAParameters();
    param.Exponent = Convert.FromBase64String(“…”);
    param.Modulus = Convert.FromBase64String(“…”); 
    return param;
}

从 XML 中生成 public key 来验证数字签名,只要用两个参数:Exponent, Modulus. 别人即使从你散发出去的程序本身破解得到了public key,没有其它多大用处。

当然,破解不仅仅是要得到密码。如果来个暴力破解,把你的程序反编译出来,把你的 public key 换成他的,与他自己的注册机配合的,那你不就被抢劫一空了,或者反编译出来删掉前文所述的 LicenseProvdier,或者 …….,还有很多办法。

.NET 提供的许可证监测机制,非对称加密是否能真正发挥,还得看程序本身的加扰程度。下一篇文章介绍。

Tags:

Add comment March 16th, 2005

.NET 下制作 Shareware 的关键技术探讨一:Licensing

制作 Shareware 有三个关键点:

  • 如何保护对象(程序),在创建对象的时候检测许可证 (License)。
  • 加密/解密 用户信息和注册信息。
  • 程序加扰 (obfuscate) 或者程序加密,反破解。

.NET 为前两者提供了基本支持,非常方便。这里先说检测许可证。许可证可以有通用注册码、验证用户名的注册码、验证用户机器的注册码等形式。当用户花钱购买了 Shareware 程序,Shareware 程序拥有者就会发送注册码给用户。(Share-It 有在线注册码生成功能,一收到钱立即自动生成注册码)。

Shareware 程序运行时要检测和验证用户是否具有有效的注册码,以决定用户是否能执行程序。

.NET 下的程序都是面向对象的,所以 .NET 在对象的创建机制上,提供了许可证检测的一个接口,Shareware 程序开发可以在此基础上加入自己的注册码验证算法。

.NET Licensing 一文介绍了许可证检测的办法:

[LicenseProviderAttribute(typeof(LicFileLicenseProvider))]
public class LicensedClass : IDisposable
{
    private License license = null;
    public LicensedClass()
    {
        license = LicenseManager.Validate(typeof(LicensedClass), this);
        Console.WriteLine(“Hello from the licensed class.”);
    }
    public void Dispose() 
    {
        if (license != null
        {
            license.Dispose();
            license = null;
        }
    }
}

有了这么个结构,程序开发可以把检测许可证交由 .NET 完成,而自己集中精力设计如何验证注册码。把上面的 LicFileLicenseProvider 换成自己的 Custom LicenseProvider。比如,不读文件而去读注册表,见:CodeGuru: Licensed Applications using the .NET Framework我的一些文章收藏 (RSS格式)

不论是从文件或者从注册表得到注册码,它包含了户是否可以运行程序的信息,而且它一定是只能 Shareware 程序拥有者说了算。因此这个信息是必须加密的。

.NET 提供了非对称加密 (Asymmetric Cryptography) 工具可以用来处理注册码。下一篇文章里继续介绍。

Add comment March 3rd, 2005


Calendar

March 2005
M T W T F S S
« Nov   Nov »
 123456
78910111213
14151617181920
21222324252627
28293031  

Posts by Month

Posts by Category


1