算法簡單,而且效率高,每次可以操作8個字節(jié)的數(shù)據(jù),加密解密的KEY為16字節(jié),即包含4個int數(shù)據(jù)的int型數(shù)組,加密輪數(shù)應(yīng)為8的倍數(shù),一般比較常用的輪數(shù)為64,32,16,QQ原來就是用TEA16來還原密碼的.
TEA算法 核心為:
#include <stdint.h>
void encrypt (uint32_t* v, uint32_t* k) { uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */ uint32_t delta=0x9e3779b9; /* a key schedule constant */ uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */ for (i=0; i < 32; i++) { /* basic cycle start */ sum += delta; v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); } /* end cycle */ v[0]=v0; v[1]=v1; }
void decrypt (uint32_t* v, uint32_t* k) { uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up */ uint32_t delta=0x9e3779b9; /* a key schedule constant */ uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */ for (i=0; i<32; i++) { /* basic cycle start */ v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); sum -= delta; } /* end cycle */ v[0]=v0; v[1]=v1; }
PHP部分代碼非我原創(chuàng),大家可以了解一下這方面的知識
<?php $date = '8345354023476-3434'; $key = '12345'; $t = new tea ( ); $tea = $t->encrypt ( $date, $key ); $eetea = $t->decrypt ( $tea, $key ); var_dump ( $tea ); var_dump ( $eetea ); class tea { private $a, $b, $c, $d; private $n_iter; public function __construct() { $this->setIter ( 32 ); } private function setIter($n_iter) { $this->n_iter = $n_iter; } private function getIter() { return $this->n_iter; } public function encrypt($data, $key) { // resize data to 32 bits (4 bytes) $n = $this->_resize ( $data, 4 ); // convert data to long $data_long [0] = $n; $n_data_long = $this->_str2long ( 1, $data, $data_long ); // resize data_long to 64 bits (2 longs of 32 bits) $n = count ( $data_long ); if (($n & 1) == 1) { $data_long [$n] = chr ( 0 ); $n_data_long ++; } // resize key to a multiple of 128 bits (16 bytes) $this->_resize ( $key, 16, true ); if ('' == $key) $key = '0000000000000000'; // convert key to long $n_key_long = $this->_str2long ( 0, $key, $key_long ); // encrypt the long data with the key $enc_data = ''; $w = array (0, 0 ); $j = 0; $k = array (0, 0, 0, 0 ); for($i = 0; $i < $n_data_long; ++ $i) { // get next key part of 128 bits if ($j + 4 <= $n_key_long) { $k [0] = $key_long [$j]; $k [1] = $key_long [$j + 1]; $k [2] = $key_long [$j + 2]; $k [3] = $key_long [$j + 3]; } else { $k [0] = $key_long [$j % $n_key_long]; $k [1] = $key_long [($j + 1) % $n_key_long]; $k [2] = $key_long [($j + 2) % $n_key_long]; $k [3] = $key_long [($j + 3) % $n_key_long]; } $j = ($j + 4) % $n_key_long; $this->_encipherLong ( $data_long [$i], $data_long [++ $i], $w, $k ); // append the enciphered longs to the result $enc_data .= $this->_long2str ( $w [0] ); $enc_data .= $this->_long2str ( $w [1] ); } return $enc_data; } public function decrypt($enc_data, $key) { // convert data to long $n_enc_data_long = $this->_str2long ( 0, $enc_data, $enc_data_long ); // resize key to a multiple of 128 bits (16 bytes) $this->_resize ( $key, 16, true ); if ('' == $key) $key = '0000000000000000'; // convert key to long $n_key_long = $this->_str2long ( 0, $key, $key_long ); // decrypt the long data with the key $data = ''; $w = array (0, 0 ); $j = 0; $len = 0; $k = array (0, 0, 0, 0 ); $pos = 0; for($i = 0; $i < $n_enc_data_long; $i += 2) { // get next key part of 128 bits if ($j + 4 <= $n_key_long) { $k [0] = $key_long [$j]; $k [1] = $key_long [$j + 1]; $k [2] = $key_long [$j + 2]; $k [3] = $key_long [$j + 3]; } else { $k [0] = $key_long [$j % $n_key_long]; $k [1] = $key_long [($j + 1) % $n_key_long]; $k [2] = $key_long [($j + 2) % $n_key_long]; $k [3] = $key_long [($j + 3) % $n_key_long]; } $j = ($j + 4) % $n_key_long; $this->_decipherLong ( $enc_data_long [$i], $enc_data_long [$i + 1], $w, $k ); // append the deciphered longs to the result data (remove padding) if (0 == $i) { $len = $w [0]; if (4 <= $len) { $data .= $this->_long2str ( $w [1] ); } else { $data .= substr ( $this->_long2str ( $w [1] ), 0, $len % 4 ); } } else { $pos = ($i - 1) * 4; if ($pos + 4 <= $len) { $data .= $this->_long2str ( $w [0] ); if ($pos + 8 <= $len) { $data .= $this->_long2str ( $w [1] ); } elseif ($pos + 4 < $len) { $data .= substr ( $this->_long2str ( $w [1] ), 0, $len % 4 ); } } else { $data .= substr ( $this->_long2str ( $w [0] ), 0, $len % 4 ); } } } return $data; } private function _encipherLong($y, $z, &$w, &$k) { $sum = ( integer ) 0; $delta = 0x9E3779B9; $n = ( integer ) $this->n_iter; while ( $n -- > 0 ) { //C v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); //C v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); $sum = $this->_add ( $sum, $delta ); $y = $this->_add ( $y, $this->_add ( ($z << 4),$this->a) ^ $this->_add($z , $sum) ^ $this->_add($this->_rshift ( $z, 5 ), $this->b ) ); $z = $this->_add ( $z, $this->_add ( ($y << 4),$this->a) ^ $this->_add($y , $sum) ^ $this->_add($this->_rshift ( $y, 5 ), $this->b ) ); } $w [0] = $y; $w [1] = $z; } private function _decipherLong($y, $z, &$w, &$k) { // sum = delta<<5, in general sum = delta * n $sum = 0xC6EF3720; $delta = 0x9E3779B9; $n = ( integer ) $this->n_iter; while ( $n -- > 0 ) { //C v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); //C v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); $z = $this->_add ( $z, -($this->_add ( ($y << 4),$this->a) ^ $this->_add($y , $sum) ^ $this->_add($this->_rshift ( $y, 5 ), $this->b ) ) ); $y = $this->_add ( $y, - ($this->_add ( ($z << 4),$this->a) ^ $this->_add($z , $sum) ^ $this->_add($this->_rshift ( $z, 5 ), $this->b ) ) ); $sum = $this->_add ( $sum, - $delta ); } $w [0] = $y; $w [1] = $z; } private function _resize(&$data, $size, $nonull = false) { $n = strlen ( $data ); $nmod = $n % $size; if (0 == $nmod) $nmod = $size; if ($nmod > 0) { if ($nonull) { for($i = $n; $i < $n - $nmod + $size; ++ $i) { $data [$i] = $data [$i % $n]; } } else { for($i = $n; $i < $n - $nmod + $size; ++ $i) { $data [$i] = chr ( 0 ); } } } return $n; } private function _hex2bin($str) { $len = strlen ( $str ); return pack ( 'H' . $len, $str ); } private function _str2long($start, &$data, &$data_long) { $n = strlen ( $data ); $tmp = unpack ( 'N*', $data ); $j = $start; foreach ( $tmp as $value ) $data_long [$j ++] = $value; return $j; } private function _long2str($l) { return pack ( 'N', $l ); } private function _rshift($integer, $n) { // convert to 32 bits if (0xffffffff < $integer || - 0xffffffff > $integer) { $integer = fmod ( $integer, 0xffffffff + 1 ); } // convert to unsigned integer if (0x7fffffff < $integer) { $integer -= 0xffffffff + 1.0; } elseif (- 0x80000000 > $integer) { $integer += 0xffffffff + 1.0; } // do right shift if (0 > $integer) { $integer &= 0x7fffffff; // remove sign bit before shift $integer >>= $n; // right shift $integer |= 1 << (31 - $n); // set shifted sign bit } else { $integer >>= $n; // use normal right shift } return $integer; } private function _add($i1, $i2) { $result = 0.0; foreach ( func_get_args () as $value ) { // remove sign if necessary if (0.0 > $value) { $value -= 1.0 + 0xffffffff; } $result += $value; } // convert to 32 bits if (0xffffffff < $result || - 0xffffffff > $result) { $result = fmod ( $result, 0xffffffff + 1 ); } // convert to signed integer if (0x7fffffff < $result) { $result -= 0xffffffff + 1.0; } elseif (- 0x80000000 > $result) { $result += 0xffffffff + 1.0; } return $result; } // }}} } ?>
上面的是TEA的算法,XTEA的算法為:
#include <stdint.h>
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const k[4]) { unsigned int i; uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9; for (i=0; i < num_rounds; i++) { v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); sum += delta; v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); } v[0]=v0; v[1]=v1; }
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const k[4]) { unsigned int i; uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds; for (i=0; i < num_rounds; i++) { v1 −= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); sum −= delta; v0 −= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); } v[0]=v0; v[1]=v1; }
那PHP中只需要把運(yùn)算的位置改下就OK
private function _teaencipherLong($y, $z, &$w, &$k) { $sum = ( integer ) 0; $delta = 0x9E3779B9; $n = ( integer ) $this->n_iter; while ( $n -- > 0 ) { $y = $this->_add ( $y, $this->_add ( $z << 4 ^ $this->_rshift ( $z, 5 ), $z ) ^ $this->_add ( $sum, $k [$sum & 3] ) ); $sum = $this->_add ( $sum, $delta ); $z = $this->_add ( $z, $this->_add ( $y << 4 ^ $this->_rshift ( $y, 5 ), $y ) ^ $this->_add ( $sum, $k [$this->_rshift ( $sum, 11 ) & 3] ) ); } $w [0] = $y; $w [1] = $z; } private function _decipherLong($y, $z, &$w, &$k) { // sum = delta<<5, in general sum = delta * n $sum = 0xC6EF3720; $delta = 0x9E3779B9; $n = ( integer ) $this->n_iter; while ( $n -- > 0 ) { $z = $this->_add ( $z, - ($this->_add ( $y << 4 ^ $this->_rshift ( $y, 5 ), $y ) ^ $this->_add ( $sum, $k [$this->_rshift ( $sum, 11 ) & 3] )) ); $sum = $this->_add ( $sum, - $delta ); $y = $this->_add ( $y, - ($this->_add ( $z << 4 ^ $this->_rshift ( $z, 5 ), $z ) ^ $this->_add ( $sum, $k [$sum & 3] )) ); } $w [0] = $y; $w [1] = $z; }
XXTEA的算法 核心為
#define MX (z>>5^y<<2) + (y>>3^z<<4)^(sum^y) + (k[p&3^e]^z);
long btea(long* v, long n, long* k) { unsigned long z=v[n-1], y=v[0], sum=0, e, DELTA=0x9e3779b9; long p, q ; if (n > 1) { /* Coding Part */ q = 6 + 52/n; while (q-- > 0) { sum += DELTA; e = (sum >> 2) & 3; for (p=0; p<n-1; p++) y = v[p+1], z = v[p] += MX; y = v[0]; z = v[n-1] += MX; } return 0 ; } else if (n < -1) { /* Decoding Part */ n = -n; q = 6 + 52/n; sum = q*DELTA ; while (sum != 0) { e = (sum >> 2) & 3; for (p=n-1; p>0; p--) z = v[p-1], y = v[p] -= MX; z = v[n-1]; y = v[0] -= MX; sum -= DELTA; } return 0; } return 1; }
也是運(yùn)算不一樣,這個就不寫了,有人已經(jīng)寫過這方面的代碼了 地址
經(jīng)典論壇交流: http://bbs.blueidea.com/thread-2928599-1-1.html
本文鏈接:http://m.95time.cn/tech/program/2009/6788.asp
出處:藍(lán)色理想
責(zé)任編輯:bluehearts
◎進(jìn)入論壇網(wǎng)絡(luò)編程版塊參加討論
|