无聊的时候瞎写的,欢迎大虾们指正Common\NDV.php
/**
 * NDV (Not complete Digital Visa)
 * 非完整数字签证
 *
 * +----------------------------------------------------------------------------------------+
 * * NDV(基础函数库文件),属于KSEF(Kee Simply Efficient Framework)项目扩展库函数
 * @author Kee <[email protected]>
 * @date 2012年12月10日
 * @version Alpha 1.0
 * +----------------------------------------------------------------------------------------+
 */
class NDV{
  private $Str_list = array();
  private $SafeStr = null;
  private $BinCode = null;
  private $Md5Code = null;
  private $Sh1Code = null;
  private $SafeCode = null;
  
  public function NDVa($str, $mode = 'NDV'){
    $this-> NDV_list($str);
    $this-> NDV_Safe_Add();
    $this-> NDV_4in1();
    if($mode == 'NDV'){
      //输出52位混合编码,默认选项
      return $this-> SafeCode;
    }elseif($mode == 'BIN'){
      //输出20位二进制校验码
      return $this-> BinCode;
    }elseif($mode == 'MD5'){
      //输出32为MD5校验码
      return $this-> Md5Code;
    }elseif($mode == 'SH1'){
      //输出32位Sh1校验码
      return $this-> Sh1Code;
    }
  }  private function NDV_list($str) {
    $Str_Len = strlen($str);    //计算字符串长度
    $Str_Arr = array();         //拆解字符串数组
    $Str_list = array();         //混序列表
//  $mod3 = $Str_Len%3;       //模3值
    $Len3 = intval($Str_Len / 3); //除3取整
    $list = 0;
    
    //进行一次循环,拆解字符串,混序排列
    for ($i = 0, $x = 0; $i < $Str_Len; $x++) {
      $Str_Arr[$x] = md5(md5(substr($str, $i, 3)) . md5($str));   //拆解字符串,取字符串摘要获取64位混合编码
      //混序排列
      $this->BinCode .= $Str_Arr[$x] % 2;
      if ($Str_Arr[$x] % 2 == 1) {
        //如果模2值为1,则序列下沉
        $Str_list[$Len3] = $Str_Arr[$x];
        $Len3--;
      } elseif ($Str_Arr[$x] % 2 == 0) {
        //如果模2值为0,则序列上浮
        $Str_list[$list] = $Str_Arr[$x];
        $list++;
      }
      $i+=3;
    }
    $this->Str_list = $Str_list;
//    return $this;   //返回数据
  }  private function NDV_Safe_Add() {
    $safenum = null;
    if(count($this-> Str_list) >= 16){
      //如果混合序列大于或等于16组,则进行数据合并,提取512位安全编码
      for($i=0; $i<16; $i++){
        $this-> SafeStr .= (String)($this-> Str_list[$i]);
      }
    }else {
      $safenum = 16-count($this-> Str_list);
      for($i=count($this-> Str_list); $i<16; $i++){
        //不足16组,验证数据补充
        @$this-> Str_list[$i] = md5($this->BinCode.md5($this-> Str_list[$i-1]));
        $this-> BinCode .= $this-> Str_list[$i]%2;
      }
      for($i=0; $i<16; $i++){
        //提取512位混合编码
        @$this-> SafeStr .= (String)($this-> Str_list[$i]);
      }
    }
    $this-> Md5Code = md5($this-> SafeStr);
    $this-> Sh1Code = substr(sha1($this-> SafeStr), 0, 32);
    return $this;
  }
  
  private function NDV_4in1(){
    //四选一
    $se = array();
    $se[0] = substr($this-> SafeStr, 0, 128);
    $this-> BinCode .= $se[0]%2;
    $se[1] = substr($this-> SafeStr, 128, 128);
    $this-> BinCode .= $se[1]%2;
    $se[2] = substr($this-> SafeStr, 256, 128);
    $this-> BinCode .= $se[2]%2;
    $se[3] = substr($this-> SafeStr, 384, 128);
    $this-> BinCode .= $se[3]%2;
    $senum = $this-> SafeStr%4;
    $SafeCode = md5($se[$senum]);
    if($SafeCode%2 == 0){
      $SafeCode = substr($SafeCode, 0, 16);
    }elseif($SafeCode%2 == 1){
      $SafeCode = substr($SafeCode, 16, 16);
    }
    $SafeCode .= $this-> BinCode;
    $this-> SafeCode = $SafeCode;
    return $this;
  }
}function NDV($str , $mode = 'NDV'){
  $ndv = new NDV();
  return $ndv-> NDVa($str,$mode);
}$string = '111111111111';
var_dump(NDV($string));
var_dump(NDV($string,'BIN'));
var_dump(NDV($string,'MD5'));
var_dump(NDV($string,'SH1'));乱七八糟的还是挺多的,而且也挺不伦不类的,因为原本就没打算写类的,只是用类封装方便些!欢迎大虾们指正!!
这个是Alpha版的,还有很多问题...
主要的作用是对用户密码进行数字签证,因为是对数据进行混序填充,破坏原信息签证,添加二进制码进行重新签证,所以叫做不完整数字签证,整个过程有点混乱,大虾们多担待...嘿嘿!

解决方案 »

  1.   

    似乎一套程序里边用不到这么多的加密方式吧,基本上一个md5的function就能统领全局了.
    不过捏,楼主的作为还是值得称赞的.
      

  2.   

    一般来说,如果算法不公开,给一个加盐sha1已经能够应付绝大部分的攻击了。如果你的盐足够长,例如2048位,则基本不可能被碰撞。
    当然,你这种打乱的算法,就算公开了也不容易被碰撞,安全性自然更高一筹。
      

  3.   

    整个算法是这样的:
    首先对输入的字符串进行拆解为每三个字符为一组的md5值加上对整个字符串的md5值合并在一起的64位长字符串再进行一次md5,然后存入数组,直到拆解完整个字符串为止;
    然后对整个数组的每组数据进行除2取余(模2处理),由于除数是2,所以余数不是0就是1,也就形成了一组二进制代码(BinCode),然后对余数进行分析,为1的数据下沉,为0的数据上浮,打乱整个数组的原有排序.形成一个新的数组.
    再然后对数组进行分析,如果数据下标大于16,也就是多于16组数据,则舍弃后面的数据;如果小于16组数据,则进行填充,使之达到16组数据.然后16组数据,每组32个字符串联形成一个512位的长字符串;
    再次对512位字符进行拆解,形成4组128位的数组;
    然后对512位除以4取余,因为除数是4,所以有0,1,2,3四个余数,对应的是这个数组的四个下标,然后取对应余数的那组数据进行一次md5,生成32位校验码,对这个校验码再进行一次除2取余,余数是0则取前16位字符,余数是1则取后面16位字符,然后于整个算法进行过程中生成的20二进制编码合并形成最终的36位混合编码
    整个算法的目的就是为了增加对于md5的碰撞,因为在整个算法的过程中全部产生的数据都是根据数据本身产生的新数据,最终生成的36位混合编码都是不完整的数据编码,(这也是为什么这个算法会取名非完整数字签证的原因)增加了对加密数据的碰撞难度,又同时,在36编码生成之前,也会对原始的512位字串进行一次Md5,以及sha1验证,即使碰撞出了36位的混合编码,但是也要同时符合另外两组校验码才行,基本上应该很难...
      

  4.   

    楼主的算法有理论依据吗?我们知道 MD5 有碰撞,并且理论上很容易计算得到
    那么为什么 MD5 会有碰撞呢?
    道理很简单,当你试图将无限的宇宙放进一个有限的空间里时,碰撞就必然发生了既然 MD5 有碰撞,那么无论对已碰撞的 MD5 数据做什么变形,他还是“碰撞的”
      

  5.   

    碰撞是必然产生的,这是无可避免的,但是可以人为的干预碰撞的产生,也就是对代码的不断更新,使原有的碰撞算法失效不是吗?
    说到理论依据,要实在有的话,也只是对MD5进行变形而已,同样是对数据进行填充然后进行摘要处理而已....
    小子没学过什么精深的算法,也做不出来太复杂的算法,只是对原有的md5进行复杂处理,仅此而已,呵呵
      

  6.   

    本帖最后由 xuzuning 于 2012-12-11 15:26:19 编辑
      

  7.   

    恩,这是个问题,再字符串数组排列之初,只要碰撞出原始的数据就可以了...
    是没考虑到这个地方....呵呵
    整个算法都依赖于数据本身,即使怎么样变形都是一个样...
    似乎是多此一举了,呵呵
    请教一下:"md5(md5(substr($str, $i, 3)) . md5($str))",如果对这条算法进行不同算法的签证,是否可以减少被碰撞的几率?比如:"md5(sh1(substr($str, $i, 3)) . md5($str))"或者根据字串进行模处理,进而选择不同的签证算法?又好像没什么必要....
    我还是好好想想吧....
      

  8.   

    刚才在 #13 加了点内容,我想对你会有帮助可以这样想,如果两个不相同的字符串具有相同的 MD5 值,那么还同时具有相同的哈希值的可能性是极小的了
    从概率上说,假定具有相同的MD5的可能性是万分之一、具有相同的SHA1的可能性也是是万分之一
    那么同时具有相同的MD5、SHA1的可能性就是 万万分之一