精华内容
下载资源
问答
  • PHP的加密函数库Mcrypt使用介绍

    千次阅读 2008-09-01 00:04:00
    Sunday, November 27, 2005 PHP的加密函数库Mcrypt使用介绍 (tags: tech php) 翻译文章,原文链接: PHP Cryptography: An Introduction Using Mcrypt作者:Robert Peake翻译:ericfish此文...
    Sunday, November 27, 2005 
    

    PHP的加密函数库Mcrypt使用介绍 (tags: tech php)

    翻译文章,原文链接:
     
    PHP Cryptography: An Introduction Using Mcrypt
    作者:Robert Peake
    翻译:ericfish

    此文介绍双向加密算法,解释它于其它常用PHP函数的不同,比如md5和rot13,以及如何在单向哈希算法和双向加密之间做出正 确的选择。同时介绍作为可动态加载php插件mcrypt的安装。文中将以加密cookies和数据库信息(如信用卡卡号)作为应用实例,以脚本语言的形 式给出加密/解密方案,并提供编码、源码编译命令和创建新的插件的解决方案。

    为什么要使用密码?
    The human heart has hidden treasures,
    In secret kept, in silence sealed.
    -Charlotte Bront?, Evening Solace

    人的本性中有着隐藏的欲望,从计算的角度来讲,这就是密码学。

    密码学定义
    英文牛津字典里的描述是:一种秘密的写作习惯…只有那些拥有密钥的人才能理解。
    从现代定义应该是:用数学的方法将一种形式转换成另一种新的形式(加密),然后可以将新的形式转换回原来的形式(解密)。

    比较
    Scheme  Direction  Security        Results  Key?   Type 
    md5        one-way    secure         same      no       hashing 
    rot13       two-way     not secure  same      no       mapping 
    mcrypt    two-way     secure         different  yes     encryption

    首先必须指出的是mcrypt是一个双向加密算法,虽然它也有可以生成单向的哈希,但我们的主要用途还是能够同时加密和解密的能力。Md5则是一个单向的加密算法。
    一个最简单的单向算法,比如把每个字符的ASCII码求和。示例如下:

    Listing 1: A simple one-way mapping (one_way.php)

    <?php

    //return an ordinal summation
    function one_way ($string){
    for ($i=0; $i < strlen($string); $i++) {
    $result += ord(substr($string,$i));
    }
    return $result;
    }

    $test_1 = "Hello, world.";
    $test_2 = "(%PHP Int'l Mag%)";
    $test_3 = "foo";

    print $test_1;
    print ' = ';
    print one_way($test_1);
    print '<br />';

    print $test_2;
    print ' = ';
    print one_way($test_2);
    print '<br />';

    print $test_3;
    print ' = ';
    print one_way($test_3);

    ?>

    Listing 2: Browser Output

    Hello, world. = 1174
    (%PHP Int'l Mag%) = 1174
    foo = 324

    正如例子中所显示的,使用单向机密算法所得到的加密的值所对应的原文可能并不唯一。但md5和上面最简单的示例不同,它是一种能够保证输出唯一的算法。
    md5的原则是:对每个输入a,它能够生产对应的一个b,但对每一个b而言,要把它在还原成a是很困难的。这就是为什么我们认为用单向算法生成唯一的hashes是安全的。Md5通常被用于创建唯一的文件签名并用来与其它的签名进行比较。
    我 还见过使用md5来加密用户在数据库中的密码。当用户输入他们的密码后,系统创建对应的md5 hash码,并与系统中存储的md5 hash码进行比较。如果他们相同,那么绝大部分情况下它们所对应的明文也是相同的。在PHP的加密算法中使用来DES来实现这一功能,DES是UNIX 中/etc/passwd存储密码所使用的加密标准。这一点有时是很有用的,比如在php与htaccess间创建接口,或与/etc/password 本身。

    rot13是一种最简单的双向机密算法。该算法的规则是对26个字母分别使用其在字母表中右边第十三个字母替换。

    Listing 3: A simple rot13 test (rot13.php)

    <?php
    $s = 'abcdefghijklmonpqrstuvwxyz';
    $s_0 = str_rot13($s);

    print '<code>';
    print $s;
    print "<br />/n";
    print $s_0;
    print '</code>';
    ?>


    Listing 4: Output

    abcdefghijklmonpqrstuvwxyz
    nopqrstuvwxyzbacdefghijklm


    很显然,rot13虽然简单但不安全。rot13一般用于世界性的新闻组网络系统中模糊一些敏感性文字,使它们必须通过解码才能被阅读。
    需 要指出的是一些更高级的算法比如base_64和rawurlencode 和rot13一样都属于映射的类型。它们都通过表格中一对一的字符映射实现。正因如此它们只能被用于暂时模糊数据。因为在数学上对这些类型的加密进行方向 解密是比较容易实现的,所以它们不应该被视为一种安全的方案。
    相比而言,mcrypt中提供的算法通过引入密钥的概念正好实现了以上两种算法的优 点。一般来说密钥即密码的意思,它是可以由任何字符组成的针对特定算法定长的字符串。通过结合密钥和注入的随机数(称为'IV'),mcrypt加密算法 的过程为每个待加密的唯一值a,加密后另外一个不同的值b被生成,这个b值如果要它还原成a,就必须将密钥和与加密时相同的随机数组返回给mcrypt解 密算法。这才是真正意义上的加密,也是mcrypt库提供给我们的。

    合理的使用
    何时使用mcrypt?何时使用哈希或者映射?

    如果你只是需要简单的模糊信息,那么映射就可以满足。所谓模糊,也就是说使数据不能被直接阅读。但如果你传输的是敏感数据,则不要用映射,因为数据并没有被真正地加密,它只是用一种可被预知的方式映射字符。
    如果你只是需要比较数据,那么可以使用md5。它可以被用来比较文件、密码、甚至比较那些你不希望被别人猜到和复制的唯一键。你还可以使用md5用来作为对安全加密算法的附加安全手段,我们回在下面的文中提到。
    如果你有信息被存储在不安全的地方,你的信息将会横穿互联网(如电子邮件),或者其它一些安全需求比较高的信息,那么就需要使用到mcrypt所提供的双向密钥加密算法了。

    安装
    此安装主要针对Linux系统,但对于UNIX(包括Mac OS X)和Windows系统也同样适用。对于Debian的用户,安装mcrypt也一样简单。

    # apt-get install php4-mcrypt
    # apacectl restart

    我建议将mcrypt做为动态加载的插件安装到PHP中。它将使得PHP更容易维护和升级,因为你不用一直去重新编译。如果你一定要把mcrypt包含到PHP中,在命令行配置时可以用mcrypt='/path/to/mcrypt' 来加载。
    但无论如何,首先你需要安装libmcrypt. Libmcrypt可以在SourceForge被下载。使用root用户输入:

    # wget -c
    'http://path/to/nearest/sourceforge/mirror/
    for/latest/libmcrypt'
    # gunzip libmcrypt-X.X.X.tar.gz
    # tar -xvf libmcrypt-X.X.X.tar
    # cd libmcrypt-X.X.X
    # ./configure

    现在你应该已经把libmcrypt作为一个共享组件了(但不是一个PHP的共享组件)。运行命令:

    # ldconfig

    它将使得共享对象可以在C/C++开发中被使用。下面把mcrypt动态组件编译到PHP中。首先,你需要PHP-devel 包中包含的 'phpize‘ 命令。

    当你当前运行的PHP中已经有了 PHP-devel 后,输入:

    # cd ext/mcrypt
    # phpize
    # aclocal
    # ./configure
    # make clean
    # make
    # make install

    现在/usr/lib/php4 目录下面应该有了mcrypt.so 的文件,在 /etc/php.ini 添加:

    extension=mcrypt.so

    然后输入命令:

    # apachectl restart

    这样我们就已经将mcrypt功能安装成功了。


    测试Mcrypt
    我写了一个嵌套循环的php页面,可以用于检验libmcrypt安装的完整性

    Listing 5: A simple loop to test all ciphers and modes (mcrypt_check_sanity.php)

    <?php
    /* run a self-test through every listed
    * cipher and mode
    */
    function mcrypt_check_sanity() {
     $modes = mcrypt_list_modes();
     $algorithms = mcrypt_list_algorithms();

     foreach ($algorithms as $cipher) {
      if(mcrypt_module_self_test($cipher)) {
       print $cipher." ok.<br />/n";
      }
      else {
       print $cipher." not ok.<br />/n";
      }
      foreach ($modes as $mode) {
       if($mode == 'stream') {
        $result = "not tested";
       }
       else if(mcrypt_test_module_mode($cipher,$mode)) {
        $result = "ok";
       }
       else {
        $result = "not ok";
       }
       print $cipher." in mode".$mode." ".$result."<br />/n";
      }
     }
    }

    // a variant on the example posted in
    // mdecrypt_generic
    function mcrypt_test_module_mode($module,$mode) {
     /* Data */
     $key = 'this is a very long key, even too
     long for the cipher';
     $plain_text = 'very important data';

     /* Open module, and create IV */
     $td = mcrypt_module_open($module,'',$mode, '');
     $key = substr($key, 0,mcrypt_enc_get_key_size($td));
     $iv_size = mcrypt_enc_get_iv_size($td);
     $iv = mcrypt_create_iv($iv_size,MCRYPT_RAND);

     /* Initialize encryption handle */
     if (mcrypt_generic_init($td, $key, $iv) != -1) {

      /* Encrypt data */
      $c_t = mcrypt_generic($td, $plain_text);
      mcrypt_generic_deinit($td);

      // close the module
      mcrypt_module_close($td);

      /* Reinitialize buffers for decryption*/
      /* Open module, and create IV */
      $td = mcrypt_module_open($module, '',$mode, '');
      $key = substr($key, 0,mcrypt_enc_get_key_size($td));

      mcrypt_generic_init($td, $key, $iv);
      $p_t = trim(mdecrypt_generic($td,$c_t)); //trim to remove padding

      /* Clean up */
      mcrypt_generic_deinit($td);
      mcrypt_module_close($td);
     }

     if (strncmp($p_t, $plain_text,strlen($plain_text)) == 0) {
      return TRUE;
     }
     else {
      return FALSE;
     }
    }

    // function call:
    mcrypt_check_sanity();
    ?>

    如果其中的一些算法(英文叫cipher)能够正常工作,那么我们就开始将这些算法应用到实例中了。如果它们还不能工作,那么你还需要花一点时间在php.net上的mcrypt说明。

    加密 Cookies
    Cookies长久以来一直被打上来间谍软件(spyware)的烙印。这是因为大多数情况下它们在一种可预见的方式下使用。很多流行的站点将用户信息通过明文的方式存储在cookie里。恶意站点可以通过伪装成原站点的手段来获取这些信息。
    这种方法还能引起原站点的安全性问题,比如在cookie中设置对该站点进行攻击的数据。
    无论是第三方的站点窃取cookie信息,还是恶意用户通过更改cookie来攻击站点,都可以通过加密来避免。一个加密的cookie信息对于第三方是毫无用处的,而且它几乎不可能被篡改。
    并 不著名的PHP sessions也提供了一种安全存储cookie的方法,可以通过于session关联来保证安全。(However, brute force attacks using the common cookie value 'PHPSESSID' would soon defeat this layer of "security." )更多关于session安全的问题可以阅读Chris Shiflett的文章:"The Truth About Sessions" ( www.php-mag.net/itr/online_artikel/psecom,id,513,nodeid,114.html ).
    使用真正的加密算法的好处是你不被限制在使用一个唯一键值上。当你需要把一些重要的信息(如密码)放到cookie中,使用加密是最合适的方法。
    最好将密钥的信息存放在服务器一端。
    在Listing 6 中我们将用最简单的方法来实现两个方法,使用'ecb'模式的'blowfish'算法。因为ecb模式不需要IV,使得过程能够尽量的简单。

    Listing 6: cookie encryption/decryption functions (twofish_cookie.php)

    <?php

    function my_encrypt($string) {
     $key = 'supersecret';
     $key = md5($key);

     /* Open module, trim key to max length */
     $td = mcrypt_module_open('twofish','','ecb', '');
     $key = substr($key, 0,mcrypt_enc_get_key_size($td));

     /* Initialize encryption handle
     * (use blank IV)
     */
     if (mcrypt_generic_init($td, $key, '') != -1) {
      /* Encrypt data */
      $c_t = mcrypt_generic($td, $string);
      mcrypt_generic_end($td);
      mcrypt_module_close($td);
      return $c_t;
     } //end if
    }

    function my_decrypt($string) {
    $key = 'supersecret';
    $key = md5($key);

    /* Open module, trim key to max length */
    $td = mcrypt_module_open('twofish','','ecb', '');
    $key = substr($key, 0,mcrypt_enc_get_key_size($td));

    /* Initialize encryption handle
    * (use blank IV)
    */
    if (mcrypt_generic_init($td, $key, '') !=-1) {

    /* Encrypt data */
    $c_t = mdecrypt_generic($td, $string);
    mcrypt_generic_end($td);
    mcrypt_module_close($td);
    return trim($c_t); //trim to remove
    //padding
    } //end if
    }

    function my_encryptcookie($string) {
    return base64_encode(my_encrypt($string));
    }

    function my_decryptcookie($string) {
    return my_decrypt(base64_decode($string));
    }

    ?>

    注意我们使用了md5来加密字符串"supersecret"来生成密钥。并且算法的输出是定长的,并将不够的长度用空格代替,所以我们需要用trim()去掉这些返回的空格来还原它。
    在加密后需要将字节输出转换成字符串,但在把密文传给解密函数前需要把它还原为字节码。这点在设置cookies和用于邮件传输协议数据的时候是很重要的。
    接下来我们可以测试输出了:

    <?php
    include("twofish_cookie.php");
    print my_decrypt(my_encrypt
    ("Hello, world.<br />/n"));
    print my_decryptcookie
    (my_encryptcookie("Hello, world.<br />/n"));
    ?>

    因为加密解密函数的可逆性,我们同样还可以写成:

    <?php
    include("twofish_cookie.php");
    print my_encrypt(my_decrypt("Hello, world."));
    ?>

    但不能将base_64的函数用到加密中去,否则加密会出现问题:

    <?php
    include("twofish_cookie.php");
    print my_encryptcookie(my_decryptcookie("Hello, world."));
    ?>


    此时浏览器会输出:

    Hello+worlc

    因为base64是一个交迭的映射方法,此时base64_decrypt方法被使用在一个已解密的字符串上。因为在加密和解密中映射的相同,所以在rot13中交迭的部分是没有逻辑的,但base64中不同。我们来看一个设置cookie的例子,Listing 7.

    Listing 7: set_twofish_cookie.php

    <?php
    include("twofish_cookie.php");
    if($_COOKIE['test']) print
    my_decryptcookie($_COOKIE['test']);
    else {
    $s = my_encryptcookie("Hello, world.");
    if(setcookie('test', $s, time()+3600)) {
    print 'Cookie set.';
    }
    }
    ?>

    当页面第一次载入的时候会设置一个加密的名为 'test'的cookie,在接下去再次从同一客户端访问时它将会返回解密后的cookie。
    现在你已经成功的将一个加密的cookie值保存到了客户端浏览器中,并且成功的在应用中解密了这个信息。这种方法比起用base64或者URL来编码你的信息要更为有效得多,而且它比使用session的安全性要高得多。


    加密SQL数据
    现在我们来考虑一个更高技得应用。假如你在运营一个涉及信用卡信息得电子商务公 司。你需要一个地方去存储这些信息,一般来讲SQL数据库是比较常见得选择。你可能会在每次交易 进行的时候存储这些数据,或者你需要更长时间的存储来实现一些预定的服务。而这些信息在数据库里面的时间越长,它们积累的可能性就高,你的数据库被恶意入 侵的可能性也越高。如果所有数据都是用明文的方式存储在数据库中,那么一旦数据库被入侵,所有这些信息马上可以被入侵者所掌握。
    另外,随着网上大量使用PHPMyAdmin来管理MySQL数据库,黑客就有了另外一种不涉及系统权限的入侵途径,它们能够在PHPMyAdmin下面建立目录的权限就足够了。如果数据是明文的,黑客只需要用本机浏览器就能够方便的获得这些敏感信息。
    那么解决方法是什么呢?双向加密使你能够安全的保存和获得数据,因为当它们在数据库里,它们使加密的,当它们被显示给授权的用户时它们才被解密。(见 Listing 8)

    Listing 8: AES Encryption (aes_sql.php)

    <?php
    function my_encrypt($string) {
     srand((double) microtime() * 1000000);
     //for sake of MCRYPT_RAND

     $key = 'supersecret';
     $key = md5($key);

     /* Open module, and create IV */
     $td = mcrypt_module_open('rijndael-128','','cfb', '');
     $key = substr($key, 0,mcrypt_enc_get_key_size($td));
     $iv_size = mcrypt_enc_get_iv_size($td);
     $iv = mcrypt_create_iv($iv_size,MCRYPT_RAND);

     /* Initialize encryption handle */
     if (mcrypt_generic_init($td, $key, $iv) !=-1) {
      /* Encrypt data */
      $c_t = mcrypt_generic($td, $string);
      mcrypt_generic_deinit($td);
      mcrypt_module_close($td);
      $c_t = $iv.$c_t;
      return $c_t;
     } //end if
    }

    function my_decrypt($string,$key) {
     $key = md5($key);

     /* Open module, and create IV */
     $td = mcrypt_module_open('rijndael-128','','cfb', '');
     $key = substr($key, 0,mcrypt_enc_get_key_size($td));
     $iv_size = mcrypt_enc_get_iv_size($td);
     $iv = substr($string,0,$iv_size);
     $string = substr($string,$iv_size);

     /* Initialize encryption handle */
     if (mcrypt_generic_init($td, $key, $iv) !=-1) {
      /* Encrypt data */
      $c_t = mdecrypt_generic($td, $string);
      mcrypt_generic_deinit($td);
      mcrypt_module_close($td);
      return $c_t;
     } //end if
    }
    ?>

    这里我们使用cbc模式,该模式包含了IV。所以预先生成我IV,因为它是定长,所以我们在解密前用了substr()函数。接下来是一个简单的测试。

    <?php
    include("aes_sql.php");

    $string = "Hello, world.";
    print my_decrypt(my_encrypt($string),'supersecret');
    ?>

    注意到这里我们没有像cookie方法那样在这里创建包装函数。如果你需要将除了blob类型以外的数据存到数据库中去的时候,你需要像前面定义cookie函数那样定义包装函数,它将保证SQL屈居被正确的执行。
    这个例子与前面cookie的例子另一个不同之处在于,这里的解密函数需要将密钥传进去。在网站系统中,可以将这个密钥与系统的密码关联。这种将密码传入解密函数的方法,为你的应用增加了一个安全级别,因为攻击者必须要知道这个密码才行。
    然而如果入侵者可以进入到你的系统中,那么发现这个密码应该也不会是一件很困难的事情,因为它以明文方式写在你的PHP脚本之中。

    接下去我们将讨论如何用加密的函数来模糊密码,从而进一步提高安全性。
    你可以使用一些其它的数据库中的信息,也可以对密钥再进行加密,但这种方式变成了一种无限地循环。
    The process of creating an automatic encryption scheme that is impervious to tampering if penetrated is ultimately beyond the scope of this article. We can, however, look at how to introduce some serious roadblocks.
    第一种方法是考虑使用PHP encoder。第二种方法是通过编译命令行应用来做这个工作。

    Listing 9: C my_crypt command line application

    #include <mcrypt.h>
    #include <stdio.h>
    #include <stdlib.h>
    /* #include <mhash.h> */
    main( int argc, char *argv[] ) {
    return my_crypt();
    }

    int my_crypt() {
    MCRYPT td;
    int i;
    char *key;
    char password[20];
    char block_buffer;
    char *IV;
    int keysize=16; /* 128 bits */
    key=calloc(1, keysize);
    strcpy(password, "supersecret");
    /* Generate the key using the password */
    /*
    mhash_keygen( KEYGEN_MCRYPT, MHASH_MD5,
    key, keysize, NULL, 0, password,
    strlen(password));
    */

    memmove( key, password, strlen(password));
    td = mcrypt_module_open("rijndael-128",
    "", "cfb", "");
    if (td==MCRYPT_FAILED) {
    return 1;
    }
    IV = malloc(mcrypt_enc_get_iv_size(td));
    /* Put random data in IV. Note these are not
    * real random data, consider using
    * /dev/random or /dev/urandom.
    */
    /* srand(time(0)); */
    for (i=0; i< mcrypt_enc_get_iv_size( td);
    i++) {
    IV[i]=rand();
    }
    i=mcrypt_generic_init( td, key, keysize,
    IV);
    if (i<0) {
    mcrypt_perror(i);
    return 1;
    }
    /* Encryption in CFB is performed in bytes
    */
    while ( fread (&block_buffer, 1, 1, stdin)
    == 1 ) {
    mcrypt_generic (td, &block_buffer, 1);
    fwrite ( &block_buffer, 1, 1, stdout);
    }
    /* Deinit the encryption thread,
    * and unload the module
    */
    mcrypt_generic_end(td);
    return 0;
    }

    Listing 10: C my_decrypt command line application
    #include <mcrypt.h>
    #include <stdio.h>
    #include <stdlib.h>
    /* #include <mhash.h> */
    main( int argc, char *argv[] ) {
    char password[20];
    if (argc < 2) {
    return 1;
    } else {
    strcpy(password, argv[1]);
    return my_decrypt(password);
    }
    }

    int my_decrypt(char *the_pass) {
    MCRYPT td;
    int i;
    char *key;
    char password[20];
    char block_buffer;
    char *IV;
    int keysize=16; /* 128 bits */
    key=calloc(1, keysize);
    strcpy(password, the_pass);
    /* Generate the key using the password */
    /*
    mhash_keygen( KEYGEN_MCRYPT, MHASH_MD5,
    key, keysize, NULL, 0, password,
    strlen(password));
    */

    memmove( key, password, strlen(password));
    td = mcrypt_module_open("rijndael-128",
    "", "cfb", "");
    if (td==MCRYPT_FAILED) {
    return 1;
    }
    IV = malloc(mcrypt_enc_get_iv_size(td));
    /* Put random data in IV.
    * Note these are not real random data,
    * consider using /dev/random or
    * /dev/urandom.
    */
    /* srand(time(0)); */
    for (i=0; i< mcrypt_enc_get_iv_size( td);
    i++) {
    IV[i]=rand();
    }
    i=mcrypt_generic_init( td, key, keysize,
    IV);
    if (i<0) {
    mcrypt_perror(i);
    return 1;
    }
    /* Encryption in CFB is performed in bytes
    */
    while ( fread (&block_buffer, 1, 1, stdin)
    == 1 ) {
    /* mcrypt_generic (td, &block_buffer,
    1); */
    /* Comment below and uncomment above to
    * encrypt
    */
    mdecrypt_generic (td, &block_buffer, 1);
    fwrite ( &block_buffer, 1, 1, stdout);
    }
    /* Deinit the encryption thread, and unload
    * the module */
    mcrypt_generic_end(td);
    return 0;
    }

    在PHP中可以做如下测试:

    <?php
    function my_crypt($string) {
    return `echo "$string" | my_crypt`;
    }

    function my_decrypt($string,$password) {
    return trim(`echo "$string" | my_decrypt
    "$password"`);
    }
    ?>

    但这种方法的一个最大的弱点是因为它通过命令行调用,所以任何在系统中的用户可以输入:

    # ps -aux

    如果此时my_decrypt正在运行,他们就可以看到password。

    所有这些说明了你可以不断的为那些进入到你的系统并想要解密你的数据的人制造障碍。但是不论如何被破解的可能性总是存在的。二战的时候英国捕获了一 种叫Enigma的加密算法,不管该算法在当时来看是多么的复杂,最终它还是被解密了,并成功的获取到德国的机密信息。同样的,在计算机被入侵的情况下, 加密的作用在于为了在对方解密之前,你能够重新取得计算机的控制权争取时间。


    结论
    现在相信你已经对mcrypt的作用有了一个不错的了解,但还有大量的关于加密算法的相关内容需要去发现。这也是我写此文的目的:帮助你获取一些关于mcrypt的信息,和一些加密算法信息,但并没有打算使它太过全面。

    我们还审视了一些问题,比如如何存放密钥,因为PHP是一种明文的脚本更加加剧了这一问题,即使通过PHP编码或者编译成二进制编码也不能提供完全安全的解决方案。
    我们通过两个例子:一个属于客户端的数据传输(通过cookie),另一个保存数据在服务器端(SQL)。mcrypt结合PHP能够帮助你在互联网上传输经过密钥加密的安全数据,从加密单调的数据结构到刚完成的情书。

    下载原代码

    Robert Peake has been a professional PHP developer and project manager since 2000. He is currently CTO for The David Allen Company . Reach him online: cyberscribe at php dot net.

    This article was originally published in
    Issue 03.04 of the International PHP Magazine.

    Links and Literature
    Please note that due to recent security concerns about colissions in MD5, SHA1 is now the preferred secure hash algorithm
    For more on rot13 and Usenet see http://en.wikipedia.org/wiki/Rot13
    Thanks to Eddie Urenda of UCLA for verifying the Debian libmcrypt install procedure
    Much more on mcrypt is available at http://mcrypt.sourceforge.net/
    For the gory details of MIME compliancy, see RFC 1521 at http://www.faqs.org/rfcs/rfc1521.html
    Thanks to Derick Rethans of PHP for pointing out the significance of IV in non-ecb modes
    For more on the role of Enigma in World War II see http://www.bbc.co.uk/history/war/wwtwo/enigma_04.shtml
    展开全文
  • 现在我不知道怎么去做大智慧软件的dll函数,现在我也不知道现在大智慧有没有现在在自己的动态库进行加密、加壳、反跟踪;还有一点就是不知道现在大智慧的提供接口的方式,是以动态链接库的还是以com提供的,现在只有...

       反汇编得到数据

     

     

                                                  

     

         现在我不知道怎么去做大智慧软件的dll函数,现在我也不知道现在大智慧有没有现在在自己的动态库进行加密、加壳、反跟踪;还有一点就是不知道现在大智慧的提供接口的方式,是以动态链接库的还是以com提供的,现在只有试试了。在网上找的倒是看不出来,现在我就试试看能不能找到结构在分析一下:接下来我就一种工具去看一下OllyDbg现在就要分析我们数据了.现在的结果已经很明确就是不能做出函数

         如果想得到动态库的函数现在还棉铃两个问题。就是破解大智慧炒股软件。因为哥哥告诉,去破解我想我们现在的目前的技术,我们能去破解的话我们就可以做出来。另外还有一种办法就是联系大智慧给我们接口函数,我们在去水平开发。

         这样的结果也不能满足我想还是在解决这样的问题,至少需要去理解研究一下。可是目前的时间已经有点不允许我这么做了。

      把这样的问题带给公司我不知道我能说什么。给老总说的时候我还是有信心的,可是现在我完全背离了我的说法,我想这是这么回事?

        最后这件事情能不能放下?也是一个问题。

        好了,即使现在我们有动态库函数,那么我们的com组件这么办?

        还是一个技术问题。我听公司说,我们还会接其他的公司项目去做,至少我想我们必须完成者个项目。才能给老总完全的信念,如果我们首战失败了,那我们以后的信念在哪里。这是一个问题。

       也不能让公司失望而归。

     

        在面临现在技术问题时候,我们束手无策了。我们为难了。我们邀破解。可是我们的技术。即使破解了。我们的技术难题还有很多。我想如果这样的话,对于自己的开发代价也是不可估量的,我说的都是像我这样的。开发人,其他人呢,相信公司的同事他们这么看法。在去分析了。分析了。

       

     

     

     

     

     

     

     

     

    展开全文
  • 1、数组指针 2、函数指针 函数指针做函数参数的思想精华——调用者任务的人 和 实现任务的人 解耦合 (回调函数的本质:提前做了个协议的约定(把函数的参数、函数返回值...3)函数指针应用(2)——动态库升级成框架

    1、数组指针

        二维数组。

    2、函数指针

          函数指针做函数参数的思想精华——调用者任务的人  和 实现任务的人  解耦合
        (回调函数的本质:
    提前做了一个协议的约定把函数的参数、函数返回值提前约定))
        (C++编译器通过多态的机制(提前布局vptr指针和虚函数表,找虚函数入口地址来实现))

    1)基本功能演示:

    #define  _CRT_SECURE_NO_WARNINGS 
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    //=====> 函数指针做函数参数的思想精华:
    // 调用者任务的人  和 实现任务的人  解耦合
    
    int myadd(int a, int b)    //原来子任务
    {
    	int c = 0;
    	c = a + b;
    	printf("func myadd() do \n");
    	return c;
    }
    
    int myadd2(int a, int b)  //后续子任务 
    {
    	int c = 0;
    	c = a + b;
    	printf("func myadd2() do \n");
    	return c;
    }
    
    int myadd3(int a, int b)  //后续子任务 
    {
    	int c = 0;
    	c = a + b;
    	printf("func myadd3() do \n");
    	return c;
    }
    
    int myadd4(int a, int b)  //后续子任务 
    {
    	int c = 0;
    	c = a + b;
    	printf("func myadd4() do \n");
    	return c;
    }
    
    // int (*myFuncVar)(int a, int b)——函数指针变量——返回类型为int,两个int型变量
    int myMianOp(  int(*myFuncVar)(int a, int b)  )   
    {
    	myFuncVar(10, 20);  //间接的调用 myadd函数
    	return 0;
    }
    
    void main()
    {
    	myMianOp(myadd);  //调用者
    	myMianOp(myadd2); //调用者
    	myMianOp(myadd3); //调用者
    	myMianOp(myadd4); //调用者
    }


    2)函数指针应用一——正向调用:甩开C++编译器,自己找到DLL中函数的地址,然后去调用函数

    a)新建一个MFC应用程序(以便使用系统函数),拖一个Button控件(DllPlay),双击控件编写代码;

              
             b)一般情况下,提供DLL时还会同时提供一个.h文件,通过这个.h文件,我们就可以知道DLL提供了哪些函数。(如果没有提供,我们可以借助VC6.0Tools——Depends,导入DLL,查看DLL提供的Function)。下述SOCKETCLIENT.DLL可在http://yun.baidu.com/s/1c0x2kP6函数指针动态库下载。
           c)接着a),双击进去以后,首先在该文件的全局域声明要使用的函数的函数指针类型,然后在Button的单击事件中继续编写。

    //声明一个函数指针类型
    //客户端初始化 获取handle上下
    typedef int(*CltSocketInit)(void **handle /*out*/);
    
    //客户端发报文
    typedef int(*CltSocketSend)(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/);
    
    //客户端收报文
    typedef int(*CltSocketRev)(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/);
    
    //客户端释放资源
    typedef int(*CltSocketDestory)(void *handle/*in*/);
    
    void C函数指针正向调用Dlg::OnBnClickedButton1()
    {
    	HINSTANCE hInstance;
    	hInstance = ::LoadLibrary("c:/socketclient.dll");  //导入动态库(先把DLL放到C盘下)
    	if (hInstance == NULL)
    	{
    		AfxMessageBox("LoadLibrary(DLL) 失败!");
    		return;
    	}
    	//首先获得了"cltSocketInit"函数的地址(GetProcAddress),然后再转换成CltSocketInit类型,再利用上面定义的函数指针类型定义变量cltSocketInit
    	CltSocketInit cltSocketInit = (CltSocketInit)::GetProcAddress(hInstance, "cltSocketInit");   
    	if (cltSocketInit == NULL)
    	{
    		return;
    	}
    	CltSocketSend cltSocketSend = (CltSocketSend)::GetProcAddress(hInstance, "cltSocketSend");
    	CltSocketRev cltSocketRev = (CltSocketRev)::GetProcAddress(hInstance, "cltSocketRev");
    	CltSocketDestory cltSocketDestory = (CltSocketDestory)::GetProcAddress(hInstance, "cltSocketDestory");
    
    	//执行动态库函数调用
    	unsigned char buf[128];
    	int buflen = 128;
    	unsigned char outbuf[4096];
    	int outbuflen = 4096;
    
    	strcpy_s((char *)buf,128, "aaaaaaaaaafffffffffdddddd");
    	buflen = 9;
    
    	void *handle = NULL;
    	int ret = 0;
    
    	//利用函数指针变量间接调用函数
    	ret = cltSocketInit(&handle);
    	ret = cltSocketSend(handle, buf, buflen);
    	ret = cltSocketRev(handle, outbuf, &outbuflen);
    	ret = cltSocketDestory(handle);
    
    	if (memcmp(buf, outbuf, outbuflen) == 0)
    	{
    		AfxMessageBox("发送数据和接受的数据一样 ok");
    	}
    	else
    	{
    		AfxMessageBox("发送数据和接受的数据不一样");
    	}
    }
               选择项目属性->配置属性->常规->字符集,改为“未设置”(error C2665: “AfxMessageBox”: 2 个重载中没有一个可以转换所有参数类型)。运行,出现以下错误:
    错误	1	error MSB8031: Building an MFC project for a non-Unicode character set is deprecated. You must change the project property to Unicode or download an additional library. See http://go.microsoft.com/fwlink/p/?LinkId=286820 for more information.	C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppBuild.targets	369	5	函数指针正向调用
    
            这是因为:用于多字节字符编码 (MBCS) 的 MFC 库 (DLL) 不再包含于 Visual Studio 中,但是可用作插件,您可以在任何装有 Visual Studio Professional、Visual Studio Premium 或 Visual Studio Ultimate 的计算机上下载和安装。(在 Visual Studio 中,必须启用 MFC。)包括英语(美国)和 DLL 的本地化版本。
    需要下载安装Multibyte MFC Library for Visual Studio 2013:http://www.microsoft.com/zh-cn/download/details.aspx?id=40770

    运行:

              

            3)函数指针应用二——动态库升级成框架(动态库:抽象类一个套接口,单独封装成模块,供别人调用;无法扩展。框架:能自由的扩展,方便后续产品入围,而不轻易改变框架)
    需求:比如在一个socket通信库中,完成数据加密功能,有n个厂商的加密产品供你选择,还有后续的加密产品,所以就需要实现动态库和第n个厂商产品的解耦合,支持后续加密产品的入围。

            
    实现步骤:
        1)、动态库中定义协议,并完成任务的调用:

    //完成发送报文的时候,进行数据加密
    //定义函数指针类型,通过函数指针类型 来约定 厂商 去实现 加密解密函数的原型
    //方式一:
    typedef int (*EncData)(unsigned char *in, int inlen, unsigned char *out, int *outlen);
    typedef int (*DecData)(unsigned char *in, int inlen, unsigned char *out, int *outlen);
    int socketclient_sendAndEnc1(void *handle, unsigned char *buf, int buflen, EncData encDataCallback);
    
    //方式二:直接函数指针做参数
    int socketclient_sendAndEnc2(void *handle, unsigned char *buf, int buflen,
    					int (*EncData)(unsigned char *in, int inlen, unsigned char *out, int *outlen)
    	);
    //动态库中定义实现以上函数
    __declspec(dllexport)
    int socketclient_sendAndEnc1(void *handle, unsigned char *buf, int buflen, EncData encDataCallback)     //encDataCallback函数指针类型变量
    {
    	int		ret = 0;
    	unsigned char   cryptbuf[4096];
    	int		ryptbuflen = 4096;
    
    	Sck_Handle	*tmpHandle = NULL;
    	if (handle == NULL || buf==NULL || encDataCallback==NULL)
    	{
    		ret = -1;
    		printf("func socketclient_sendAndEnc1() err :%d  check handle == NULL err \n", ret);
    		return ret;
    	}
    
    	ret = encDataCallback(buf, buflen, cryptbuf, &cryptbuflen);    //间接的调用子任务,实现第三方加密产品和调用者的分离
    	if (ret != 0)
    	{
    		ret = -2;
    		printf("func socketclient_sendAndEnc1() err :%d  check handle == NULL err \n", ret);
    		return ret;
    	}
    
    	tmpHandle = (Sck_Handle *)handle;
    	tmpHandle->len = cryptbuflen;
    
    	tmpHandle->p = (unsigned char *)malloc(cryptbuflen);
    	if (tmpHandle->p == NULL) 
    	{
    		ret = -3;
    		printf("func socketclient_sendAndEnc1() err :%d  mallocerr \n", ret);
    		return ret;
    	}
    
    	//把加密的明文  缓存到 内存中
    	memcpy(tmpHandle->p, cryptbuf, cryptbuflen);
    	
    	return 0;
    }
         2)、加密厂商完成协议函数的编写:
    //某后续第三方加密产品实现
    int Hw_EncData(unsigned char *in, int inlen, unsigned char *out, int *outlen)
    {
    	printf("func Hw_EncData begin....\n ");   //此处不是具体加密实现
    	strcpy((char *)out, "123456789");   //伪加密
    	*outlen = 9;
    
    	printf("func Hw_EncData end....\n ");
    	return 0;
    }
         3)、对接调试——通过函数指针做参数,加入到动态库中。也就是说,函数指针建立起了第三方和主动态库之间的联系。
    int ret = 0;
    ret = socketclient_sendAndEnc1(handle, buf, buflen, Hw_EncData);   //把第三方加密产品——Hw_EncData注入

           分析具体是怎么分离的:main函数调用动态库的socketclient_sendAndEnc1(发送并加密),但是并不调用自己的加密函数,而是通过其中的函数指针转而去调用第三方加密产品Hw_EncData。也就是说不管第三方产品有多少,我的动态库都不用改变!实现了动态库和第三方加密产品的解耦合!赋予了动态库生命力!

           回调函数:利用函数指针做函数参数,实现的一种调用机制,具体任务的实现者,可以不知道什么时候被调用。
           回调机制原理:
               当具体事件发生时,调用者通过函数指针调用具体函数
               回调机制将调用者和被调函数分开,两者互不依赖
               任务的实现 和 任务的调用 可以耦合  (提前进行接口的封装和设计)


    上述使用到的动态库和完整工程下载:http://pan.baidu.com/s/1c0x2kP6

    展开全文
  • 微信扫扫 作者:CoderZh  微信关注:hacker-thinking (个程序员的思考)  本文出处:http://blog.coderzh.com/2016/01/10/a-password-security-design-example/  文章版权归本人所有,欢迎转载,...

      

    微信扫一扫

    作者:CoderZh 
    微信关注:hacker-thinking (一个程序员的思考) 
    本文出处:http://blog.coderzh.com/2016/01/10/a-password-security-design-example/ 
    文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追律责任的权利。

          向原作者致敬!

        在前一篇文章《设计安全的账号系统的正确姿势》中,主要提出了一些设计的方法和思路,并没有给出一个更加具体的,可以实施的安全加密方案。经过我仔细的思考并了解了目前一些方案后,我设计了一个自认为还比较安全的安全加密方案。本文主要就是讲述这个方案,非常欢迎和期待有读者一起来讨论。

    首先,我们明确一下安全加密方案的终极目标:

    即使在数据被拖库,代码被泄露,请求被劫持的情况下,也能保障用户的密码不被泄露。

    说具体一些,我们理想中的绝对安全的系统大概是这样的:

    1. 首先保障数据很难被拖库。
    2. 即使数据被拖库,攻击者也无法从中破解出用户的密码。
    3. 即使数据被拖库,攻击者也无法伪造登录请求通过验证。
    4. 即使数据被拖库,攻击者劫持了用户的请求数据,也无法破解出用户的密码。

    如何保障数据不被拖库,这里就不展开讲了。首先我们来说说密码加密。现在应该很少系统会直接保存用户的密码了吧,至少也是会计算密码的 md5 后保存。md5 这种不可逆的加密方法理论上已经很安全了,但是随着彩虹表的出现,使得大量长度不够的密码可以直接从彩虹表里反推出来。

    所以,只对密码进行 md5 加密是肯定不够的。聪明的程序员想出了个办法,即使用户的密码很短,只要我在他的短密码后面加上一段很长的字符,再计算 md5 ,那反推出原始密码就变得非常困难了。加上的这段长字符,我们称为盐(Salt),通过这种方式加密的结果,我们称为 加盐 Hash 。比如:

    salt

    上一篇我们讲过,常用的哈希函数中,SHA-256、SHA-512 会比 md5 更安全,更难破解,出于更高安全性的考虑,我的这个方案中,会使用 SHA-512 代替 md5 。

    salt

    通过上面的加盐哈希运算,即使攻击者拿到了最终结果,也很难反推出原始的密码。不能反推,但可以正着推,假设攻击者将 salt 值也拿到了,那么他可以枚举遍历所有 6 位数的简单密码,加盐哈希,计算出一个结果对照表,从而破解出简单的密码。这就是通常所说的暴力破解。

    为了应对暴力破解,我使用了加盐的慢哈希。慢哈希是指执行这个哈希函数非常慢,这样暴力破解需要枚举遍历所有可能结果时,就需要花上非常非常长的时间。比如:bcrypt 就是这样一个慢哈希函数:

    bcrypt

    通过调整 cost 参数,可以调整该函数慢到什么程度。假设让 bcrypt 计算一次需要 0.5 秒,遍历 6 位的简单密码,需要的时间为:((26 * 2 + 10)^6) / 2 秒,约 900 年。

    好了,有了上面的基础,来看看我的最终解决方案:

    password_secutity

    上图里有很多细节,我分阶段来讲:

    1. 协商密钥

    基于非对称加密的密钥协商算法,可以在通信内容完全被公开的情况下,双方协商出一个只有双方才知道的密钥,然后使用该密钥进行对称加密传输数据。比如图中所用的 ECDH 密钥协商。

    2. 请求 Salt

    双方协商出一个密钥 SharedKey 之后,就可以使用 SharedKey 作为 AES 对称加密的密钥进行通信,客户端传给服务端自己的公钥 A ,以及加密了的用户ID(uid)。服务端从数据库中查找到该 uid 对于的 Salt1 和 Salt2 ,然后再加密返回给客户端。

    注意,服务端保存的 Salt1 和 Salt2 最好和用户数据分开存储,存到其他服务器的数据库里,这样即使被 SQL 注入,想要获得 Salt1 和 Salt2 也会非常困难。

    3. 验证密码

    这是最重要的一步了。客户端拿到 Salt1 和 Salt2 之后,可以计算出两个加盐哈希:

    SaltHash1 = bcrypt(SHA512(password), uid + salt1, 10)
    SaltHash2 = SHA512(SaltHash1 + uid + salt2)
    

    使用 SaltHash2 做为 AES 密钥,加密包括 uid,time,SaltHash1,RandKey 等内容传输给服务端:

    Ticket = AES(SaltHash2, uid + time + SaltHash1 + RandKey)
    AES(SharedKey, Ticket)
    

    服务端使用 SharedKey 解密出 Ticket 之后,再从数据库中找到该 uid 对应的 SaltHash2 ,解密 Ticket ,得到 SaltHash1 ,使用 SaltHash1 重新计算 SaltHash2 看是否和数据库中的 SaltHash2 一致,从而验证密码是否正确。

    校验两个哈希值是否相等时,使用时间恒定的比较函数,防止试探性攻击。

    time 用于记录数据包发送的时间,用来防止录制回放攻击。

    4. 加密传输

    密码验证通过后,服务端生成一个随机的临时密钥 TempKey(使用安全的随机函数),并使用 RandKey 做为密钥,传输给客户端。之后双方的数据交互都通过 TempKey 作为 AES 密钥进行加密。

    假设被拖库了

    以上就是整个加密传输、存储的全过程。我们来假设几种攻击场景:

    1. 假设数据被拖库了,密码会泄露吗?

      数据库中的 Salt1 ,Salt2 , SaltHash2 暴露了,想从 SaltHash2 直接反解出原始密码几乎是不可能的事情。

    2. 假设数据被拖库了,攻击者能不能伪造登录请求通过验证?

      攻击者在生成 Ticket 时,需要 SaltHash1 ,但由于并不知道密码,所以无法计算出 SaltHash1 ,又无法从 SaltHash2 反推 SaltHash1 ,所以无法伪造登录请求通过验证。

    3. 假设数据被拖库了,攻击者使用中间人攻击,劫持了用户的请求,密码会被泄露吗?

      中间人拥有真实服务器所有的数据,仿冒了真实的 Server ,因此,他可以解密出 Ticket 中的 SaltHash1 ,但是 SaltHash1 是无法解密出原始密码的。所以,密码也不会被泄露。

      但是,中间人攻击可以获取到最后的 TempKey ,从而能监听后续的所有通信过程。这是很难解决的问题,因为在服务端所有东西都暴露的情况下,中间人假设可以劫持用户数据,仿冒真实 Server , 是很难和真实的 Server 区分开的。解决的方法也许只有防止被中间人攻击,保证 Server 的公钥在客户端不被篡改。

      假设攻击已经进展到了这样的程度,还有办法补救吗?有。由于攻击者只能监听用户的登录过程,并不知道真实的密码。所以,只需要在服务端对 Salt2 进行升级,即可生成新的 SaltHash2 ,从而让攻击者所有攻击失效。

      具体是这样的:用户正常的登录,服务端验证通过后,生成新的 Salt2 ,然后根据传过来的 SaltHash1 重新计算了 SaltHash2 存入数据库。下次用户再次登录时,获取到的是新的 Salt2 ,密码没有变,同样能登录,攻击者之前拖库的那份数据也失效了。

    Q & A

    1. 使用 bcrypt 慢哈希函数,服务端应对大量的用户登录请求,性能承受的了吗?

      该方案中,细心一点会注意到, bcrypt 只是在客户端进行运算的,服务端是直接拿到客户端运算好的结果( SaltHash1 )后 SHA-512 计算结果进行验证的。所以,把性能压力分摊到了各个客户端。

    2. 为什么要使用两个 Salt 值?

      使用两个 Salt 值,是为了防止拖库后,劫持了用户请求后将密码破解出来。只有拥有密码的用户,才能用第一个 Salt 值计算出 SaltHash1 ,并且不能反推回原始密码。第二个 Salt 值可以加大被拖库后直接解密出 SaltHash1 的难度。

    3. 为什么要动态请求 Salt1 和 Salt2 ?

      Salt 值直接写在客户端肯定不好,而且写死了要修改还得升级客户端。动态请求 Salt 值,还可以实现不升级客户端的情况下,对密码进行动态升级:服务端可定期更换 Salt2 ,重新计算 SaltHash2 ,让攻击者即使拖了一次数据也很快处于失效状态。

    4. 数据库都已经全被拖走了,密码不泄露还有什么意义呢?

      其实是有意义的,正如刚刚提到的升级 Salt2 的补救方案,用户可以在完全不知情的情况下,不需要修改密码就升级了账号体系。同时,保护好用户的密码,不被攻击者拿去撞别家网站的库,也是一份责任。

    欢迎大家针对本文的方案进行讨论,如有不实或者考虑不周的地方,请尽情指出。或者有更好的建议或意见,欢迎交流。

    展开全文
  • 1.1 加密方案 1.1.1 开发UDF加解密函数库...调研基于win32平台,采用vc++2005开发加解密动态库函数申明示例: extern "C" __declspec(dllexport) char * __cdecl reversestring(char *pSrc);  注: (1).
  • iOS使用动态库

    千次阅读 2019-03-05 11:06:21
    从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。咱们自定义的私有组件和公有组件也是一种库的分类 开源:源代码是公开的,可以看到每个实现文件(.m文件)的实现,例如GitHub上的常用的...
  • 起因 理论功底 动态库和静态库 介绍 静态库和动态库的区别 举个例子, iOS 项目中使用 Embeded Framework ...静态库和动态库如何构建和加载 ...静态库和动态库依赖关系 ...制作动态库
  • Linux静态库和动态库学习总结

    万次阅读 2012-02-29 22:42:45
    之前由于工作需要,要封装个Linux加密解密转换的动态库,这个之前只做过Windows下面的,Linux下面还真没有做过,之后做了整个晚上才算做好,不过其中也学到了不少东西,包括Linux下的动态库和静态库,MakeFile...
  • python 动态库和静态库

    千次阅读 2019-02-13 10:27:03
    学习Python这门语言首先要了解 什么是编译与解释,什么是连接,什么是动态库与静态库,   什么是编译: 编译就是先把高级语言设计的程序翻译成二进制的机器语言,然后CPU直接执行机器码就可以了。把翻译再执行...
  • 用C/C++实现SMC动态代码加密技术

    万次阅读 2007-01-29 22:10:00
    摘要:所谓SMC(Self Modifying Code)技术,就是一种将可执行文件中的代码或数据进行加密,防止别人使用逆向工程工具(比如一些常见的反汇编工具)对程序进行静态分析的方法,只有程序运行时才对代码和数据进行解密...
  • Jna调用动态链接

    万次阅读 2014-12-06 23:09:20
    最近由于工作需要,在和其它系统交互的问题上不仅仅是WebService的交互,还需要利用Java调用其它语言编写的动态链接,例如编译好的dll文件.好,简单看一下这个问题的来源。 我们的系统和其它系统进行交互的时候...
  • 有时候我们会对明文敏感数据进行加密,像密码,平时使用比较多的可能是MD5 Sha1 属于不可逆的,那么C#中也有基于私钥的一种加密形式,所谓私钥加密,就是允许我们生成一对钥匙(这里指向量值和向量键)那么有了这对...
  • java调用dll动态库方法

    千次阅读 2015-07-03 15:48:02
    2、把自己要调用的动态库,放入你指定的目录,我这里放入的是F:\\EhfscliaxDll.dll  3、把jar导入到web项目的lib目录中,如果不是web项目,可以放入jdk的ext目录中, 4、执行如下代码:返回http://中文...
  • 动态盐值加密MD5,java实现
  • VC++动态连接详解

    千次阅读 2017-01-18 17:52:37
    Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无-静态链接动态链接”的时代。静态链接动态链接都是共享代码的方式,...
  • C++动态链接/静态链接编程

    千次阅读 2013-10-30 21:58:58
    转载:...VC++ 动态链接 (DLL) 编程(一) ――理解 作者: 宋宝华 e-mail: ...1. 概论 先来阐述一下 DLL(Dynamic Linkable Library) 的概念,你可以简单的把 DLL 看成一种仓库,
  • VC++ 动态链接编程

    千次阅读 2016-08-15 11:08:25
    VC++动态链接编程 ... 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无-静态链接
  • php 正则表达式函数库

    千次阅读 2012-02-17 10:03:13
    关于正则表达式 (regular expression),似乎译成:字符串解析处理,较合乎...本函数库让 php 也能处理复杂的字符串操作。它采用了 posix 1003.2 的扩充常规处理 (regular expression) 的标准。更多关于正则表达式的信息
  • Python优秀函数库集锦(二)

    千次阅读 2016-04-14 16:25:44
    moviepy – 个用来进行基于脚本的视频编辑模块,适用于多格式,包括动图 GIFs。 scikit-video – SciPy 视频处理常用程序。 地理位置 地理编码地址以及用来处理经纬度的。 GeoDjango – 世界级...
  • 加密算法总结

    万次阅读 多人点赞 2016-07-28 16:51:42
    加密算法总结, 对称加密,非对称加密,单向加密, MD5, MD5、SHA、HMAC、RIPE-MD、HAVAL、N-Hash、Tiger、DES、AES、IDEA、BlowFish、Twofish、RSA、DSA、ECC
  • 摘 要:介绍了动态链接这种模块复用方法及在VC中对它的调用,并给出了一个通过复用来实现数据加密的具体实例。引言 模块化思想贯穿于软件工程各个发展阶段,模块复用是构建大系统的一种重要思想。模块复用方法有...
  • Windows下的VC++动态链接编程

    千次阅读 2015-10-20 21:31:49
    动态链接DLL(DynamicLinkable Library),你可以简单的把它看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在的发展史上经历了“无-静态链接动态链接”的时代。静态链接动态链接都...
  • 破解TexturePacker加密资源

    万次阅读 多人点赞 2014-08-06 21:27:39
    很多cocos2d开发的游戏,比如圣火英雄传、武侠Q传等,都使用TexturePacker加密资源。通过linux so注入、劫持API的方法,我破解出多款游戏的美术资源。
  • VC++动态链接编程

    千次阅读 2011-05-19 10:29:00
    VC++动态链接编程
  • HMAC-based One-Time Password 简写,表示基于 HMAC 算法加密次性密码。是事件同步,通过某特定的事件次序及相同的种子值作为输入,通过 HASH 算法运算出一致的密码。 1.3、TOTP Time-based One-Ti...
  • VC++动态链接(DLL)编程

    千次阅读 2010-03-28 00:33:00
    VC++动态链接(DLL)编程作者:宋宝华 e-mail:21cnbao@21cn.com 1.概论先来阐述一下 DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。...
  • 摘 要:介绍了动态链接这种模块复用方法及在VC中对它的调用,并给出了一个通过复用来实现数据加密的具体实例。引言 模块化思想贯穿于软件工程各个发展阶段,模块复用是构建大系统的一种重要思想。模块复用方法有...
  • C#调用动态链接

    千次阅读 2011-11-24 10:42:33
    动态链接(也称为 DLL ,即为“ Dynamic Link Library ”的缩写)是 Microsoft Windows 最重要的组成要素之,打开 Windows 系统文件夹,你会发现文件夹中有很多 DLL 文件, Windows 就是将一些主要的系统功能以 ...
  • Python常见的几代码加密方法

    千次阅读 2020-01-16 17:35:03
    去年11月在PyCon China 2018 杭州站分享了Python 源码加密,讲述了如何通过修改 Python 解释器达到加解密 Python 代码的目的。然而因为笔者拖延症发作,一直没有及时整理成文字版,现在终于战胜了它,才有了本文。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 45,735
精华内容 18,294
关键字:

一种动态库加密函数