就是怎么在 PHP/mcrypt 和 PyCrypto 之间 DES(或其他加密算法,比如3DES/RSA/..) 通信的问题,我这里还额外考察了下 .NET 平台的算法
网上询问相关问题的还挺多,尤其是 PHP 和 .NET 之间的 DES 转换。主要是 PHP/mcrypt 隐藏了 padding 的细节,且只保留了 ZERO_PADDING 模式,所以不明白cyrpto原理的不太容易找到症结所在。我的传输方案统一用 pkcs#7 padding.
首先是给服务器端增加的 PKCS#7 PADDING 函数,来自PHP官方函数手册上某人的注释
function padding_pkcs7($crypto, $mode, $dat)
{
$block = mcrypt_get_block_size($crypto, $mode);
$len = strlen($dat);
$padding = $block - ($len % $block);
$dat .= str_repeat(chr($padding),$padding);
return $dat;}
function strip_pkcs7($crypto, $mode, $text)
{
$block = mcrypt_get_block_size($crypto, $mode);
$packing = ord($text{strlen($text) - 1});
if($packing and ($packing < $block)){
for($P = strlen($text) - 1; $P >= strlen($text) - $packing; $P--){
if(ord($text{$P}) != $packing){
$packing = 0;
}
}
}
return substr($text,0,strlen($text) - $packing);
}
本地端 .NET 平台的 descrypto 封装
# -*- coding: utf-8 -*-
# ipcrypto.py
from System import Array, Byte
from System.Security.Cryptography import DESCryptoServiceProvider, CryptoStream, CryptoStreamMode, PaddingModefrom System.IO import MemoryStream, StreamWriter, StreamReader
from hashlib import md5
def s2ab(s): return Array[Byte](tuple(Byte(ord(c)) for c in s))
def ab2s(ab, len=0):
if len == 0: len = ab.Length return ''.join([chr(ab[i]) for i in range(len)])
class descrypto():
def __init__(self, password):
pwmd5 = md5(password).digest()
self.key = s2ab(pwmd5[:8])
self.iv = s2ab(pwmd5[8:]) self.des = DESCryptoServiceProvider() # 缺省 des.Mode = CipherMode.CBC
def enc(self, input):
ms = MemoryStream()
encStream = CryptoStream(ms, self.des.CreateEncryptor(self.key, self.iv), CryptoStreamMode.Write)
sw = StreamWriter(encStream)
sw.Write(input)
sw.Flush()
encStream.FlushFinalBlock() return ab2s(ms.GetBuffer(), ms.Length)
def dec(self, input):
ms = MemoryStream(s2ab(input))
length = len(input)
decStream = CryptoStream(ms, self.des.CreateDecryptor(self.key, self.iv), CryptoStreamMode.Read)
byteArray = Array.CreateInstance(Byte, length)
length = decStream.Read(byteArray, 0, length)
return ab2s(byteArray, length)
本地端 PyCrypto 的封装
# -*- coding: utf-8 -*-
# pycrypto.py
from hashlib import md5from Crypto.Cipher import DES
class descrypto():
def __init__(self, password):
pwmd5 = md5(password).digest()
self.key = pwmd5[:8] self.iv = pwmd5[8:]
def enc(self, input):
des = DES.new(self.key, DES.MODE_CBC, self.iv)
lastblock = len(input) % 8
if lastblock > 0:
padding = 8 - lastblock input += padding * chr(padding)
return des.encrypt(input)
def dec(self, input):
des = DES.new(self.key, DES.MODE_CBC, self.iv)
ret = des.decrypt(input)
padding = ord(ret[-1])
for i in range(padding):
if ord(ret[-1 - i]) != padding:
padding = 0
break
if padding > 0:
ret = ret[:-padding]
return ret
Topic:
技术
评论
如果php空间设置了mbstring.func_overl
如果php空间设置了mbstring.func_overload,strlen返回的就不一定是字节数。这种情况下应该用
mb_strlen($string, '8bit');
http://us.php.net/manual/en/function.mb-strlen.php#77040