Monthly Archives: November 2007

编程

越来越受不了JAVA的官僚主义了

前言:
    发发牢骚而已。在JAVA的世界里,毕竟还是官僚主义占上风。如果在别的地方发牢骚,肯定要被人批死。在自己的blog。我的地盘我做主。

——start——

    不知道是否是玩python的后遗症,还是一直以来就没有真正的喜欢过JAVA,反正最近是越来越受不了JAVA的官僚主义了。
    开口一定要设计模式,不然现得你浅薄。程序中一定要用很多的框架,不然显得你很没品。千万别题JDBC,别人会当你和很无知,现在都Hibernate3.xx/EJB3了。程序中一定要有很多的接口,不然就是你的设计能力太差,连接口都不用。配置文件也是越多越好,而且都是XML的。即标准又方便,要改的时候改配置文件就可以了。
    设计重要,但重要的是好的设计,不是过度设计。过度的设计同样将带来复杂度的提升。好的设计可以便于日后的扩展,但关键是很多东西是不可以预知的。一个设计不可能在最开始就做得尽善尽美。好的设计应当是一个可重构的设计。
    说到设计,JAVA中的接口是滥用得最厉害的东西。在很多JAVA程序中,有事没事加一堆的接口,还美其名曰解耦。有耦合才需要解,没耦合,你解个啥。就入Dao到service间的接口,好处是实现和调用没有关系,以后换数据库方便。但,有多少情况要换数据库?即使万一真的要换,到时候再重构一次,抽取出个接口能麻烦多少。而且在经过hibernate的封装后数据库间的差别已经消灭得差不多了。
    而且在大多情况下也不是加了接口就一定可以解耦的。接口只是解耦的一种途径,并不是万能药。
    框架也是。现在用JAVA做WEB开发,确实很难不用框架。但框架就和设计模式一样,是为了方便开发的,如果为了框架而框架那就是自讨苦吃。在提供方便性的同时,将一些实现细节进行了封装。如果对框架的理解不够透彻,很可能带来不少问题(最近有些问题比较头大,不知道是否和hibernate+OpenSessionInView有关)。在一个工程中开发框架尽可能统一,这里说的是尽可能,不说一定(绝对就官僚了)。一些简单的问题,为什么就不可以用简单的方法处理?难道写个1+1也要MVC一吧?
    配置文件也是个讨厌的东西。真不知道为什么JAVA要这么多的配置文件。哪有这么多的东西需要在发布后进行修改的。就入struts里的view,难道真的有人在项目发布后修改过?直接在代码中配置,IDE可以提供代码提示等,配置文件的书写比直接写XML流畅得多。

编程

Crypto 加密的基本流程

前言:
    Crypto是微软的加密API,如果看懂了,使用起来是很简单的一件事,不过就是最开始没有看懂,被虐了两天。然后又被其他问题给虐了两天。最后做出来的东西也不是让自己十分满意。不过还好,最后的结果还不算太糟。
    本想对代码进行一次整理,写一个demo代码,不过现在有些慵懒了,还是随便贴些笔记好了。

PS:   
    发现Delphi盒子要卖了。这似乎也验证了一句话,有商业价值的东西才会有持续的生命力。

Crypto 加密的基本流程

  1. 创建/获取一个密码容器CSP
  2. 创建/获取/导入一个密钥
  3. 使用密钥进行加密/解密
加密具体流程:
  1. 创建/获取一个密码容器CSP。这一部分基本上所有程序都一样,直接复制过来到程序里就可以了。
//以下获得一个CSP句柄
    if(CryptAcquireContext(
        &hProv,   //out 密码容器
        NULL,                //NULL表示使用默认密钥容器,默认密钥容器名为用户登陆名。
        NULL,
        PROV_RSA_FULL, //in 使用RSA密钥
        0))
    {
        printf("A cryptographic provider has been acquired. \n");
    }
    else//密钥容器不存在
    {
        if(CryptAcquireContext(
            &hProv,
            NULL,
            NULL,
            PROV_RSA_FULL,
            CRYPT_NEWKEYSET))//创建密钥容器
        {
            //创建密钥容器成功,并得到CSP句柄
            printf("A new key container has been created.\n");
        }
        else
        {
            HandleError("Could not create a new key container.\n");
        }      
    }
  1. 创建/获取一个密钥。这里有些程序里会创建一个sessionKey会话密钥用于对称加密,这里创建的是非对称加密的密钥。
    //——————————————————————–
    // 从密钥容器中取交换密钥
    if(CryptGetUserKey(  
        hProv,    //CSP句柄,也就是在一里面创建的,密码容器。
        AT_KEYEXCHANGE,    //密钥的类型,这里指名的是交换密钥。还有一个AT_SIGNATURE,这个是数字签名用的。
        &hKey)) //out 获取到的密钥
    {
        printf("The signature key has been acquired. \n");
    }
    else
    {
        if(GetLastError() == NTE_NO_KEY) //密钥容器里不存在key pair创建之
        {
            if(CryptGenKey(
                hProv,            //in CSP句柄
                AT_SIGNATURE,    //in 创建的密钥对类型为signature key pair
                0,                //key类型,这里用默认值
                &hKey))         //out 创建成功返回新创建的密钥对的句柄
            {
                printf("Created a signature key pair.\n");
            }
            else
            {
                MyHandleError("Error occurred creating a signature key.\n");
            }
        }
        else
        {
            MyHandleError("Error during CryptGetUserKey for signkey.");
        }
    }
  1. 使用密钥进行加密
        //——————————————————————–
        // 加密数据
        if(!CryptEncrypt(
            hKey,            //in 密钥
            0,                //如果数据同时进行散列和加密,这里传入一个散列对象
            TRUE,    //如果是最后一个被加密的块,输入TRUE.如果不是输入FALSE.
                            //这里通过判断是否到文件尾来决定是否为最后一块。
            0,                //保留
            pbBuffer,        // in/out输入被加密数据,输出加密后的数据。将pbBuffer分配大一些,防止长度不够。
            &dwCount,        // in/out输入被加密数据实际长度,输出加密后数据长度。这个需要根据pbBuffer的实际输入长度进行计算(strlen?),不然不能正常运行。
            dwBufferLen))    //in pbBuffer的大小。这里填大点,
        {
            HandleError("Error during CryptEncrypt. \n");
        }
到这里加密就已经做完了,加密后的数据保存在pbBuffer中。
  1. 导出公/私钥
私钥在加密的时候需要,以后使用的时候不再生成,直接导入。(备注:如果需要导出私钥需要在创建密钥时候设置参数,具体见MSDN)
解密的时候需要用到公钥,需要将公钥分发给解密用户。
    //——————————————————————–
    // 因为接收消息者要验证数字签名,所以要导出公钥给接收者。
    if(CryptExportKey(  
        hKey,  //in 密钥句柄
        NULL,   
        PUBLICKEYBLOB,// out 公钥输出数据。在导出后,需要将公钥的数据保存成文件等,以便分发。
        0,   
        NULL,
        &dwBlobLen)) //out 得到公钥的大小
    {
        printf("Size of the BLOB for the public key determined. \n");
    }
    else
    {
        MyHandleError("Error computing BLOB length.");
    }
  1. 销毁容器和Key
在完成加密后,需要对key和容器进行销毁,相关函数如下。
    if(hKey)
CryptDestroyKey(hKey);
    if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
解密的具体流程:
  1. 同加密流程
  2. 导入解密用的公钥。
    HCRYPTKEY hPubKey;
    if(CryptImportKey(
        hProv,//in CSP密码容器
        pbKeyBlob,//in 需要导入的公钥数据(在加密的时候导出的公钥,加密中的4)
        dwBlobLen,//in 公钥数据的长度
        0,
        0,
        &hPubKey))//out 公钥导入得到的公钥句柄
    {
        printf("The key has been imported.\n");
    }
    else
    {
        MyHandleError("Public key import failed.");
    }
  1. 解密
解密的参数和加密的参数基本相同。
        //——————————————————————–
        // Decrypt data.
        if(!CryptDecrypt(
            hPubKey, //in 解密用的公钥,也就是在2中导入的公钥
            0,
           TRUE,    //如果是最后一个被加密的块,输] ]>