mcrypt_encrypt

(PHP 4 >= 4.0.2,PHP 5,PHP 7 < 7.2.0,PECL mcrypt >= 1.0.0)

mcrypt_encrypt使用给定参数加密明文

警告

此函数已于 PHP 7.1.0 版中弃用,并于 PHP 7.2.0 版中移除。强烈建议不要依赖此函数。

描述

mcrypt_encrypt(
    string $cipher,
    string $key,
    string $data,
    string $mode,
    string $iv = ?
): string|false

加密数据并将其返回。

参数

cipher

MCRYPT_ciphername 常量之一,或算法名称作为字符串。

key

用于加密数据的密钥。如果提供的密钥大小不受密码支持,该函数将发出警告并返回false

data

将使用给定的 ciphermode 加密的​​数据。如果数据的​​大小不是 n * 块大小,则数据将使用 '\0' 填充。

返回的密文可能大于 data 给出的数据大小。

mode

MCRYPT_MODE_modename 常量之一,或以下字符串之一:"ecb"、"cbc"、"cfb"、"ofb"、"nofb" 或 "stream"。

iv

用于 CBC、CFB、OFB 模式中的初始化,以及 STREAM 模式中某些算法中的初始化。如果提供的 IV 大小不受链接模式支持,或者没有提供 IV,但链接模式需要一个 IV,则该函数将发出警告并返回false

返回值

返回加密后的数据作为字符串,或者在失败时返回false

示例

示例 #1 mcrypt_encrypt() 示例

<?php
# --- 加密 ---

# 密钥应为随机二进制,使用 scrypt、bcrypt 或 PBKDF2 将字符串转换为密钥
# 密钥使用十六进制指定
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");

# 显示密钥大小,使用 16、24 或 32 字节密钥分别用于 AES-128、192
# 和 256
$key_size = strlen($key);
echo
"Key size: " . $key_size . "\n";

$plaintext = "This string was AES-256 / CBC / ZeroBytePadding encrypted.";

# 创建一个随机 IV 用于 CBC 编码
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

# 创建与 AES 兼容的密文(Rijndael 块大小 = 128)
# 保持文本机密性
# 仅适用于绝不以 00h 值结尾的编码输入
#(因为默认零填充)
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
$plaintext, MCRYPT_MODE_CBC, $iv);

# 将 IV 预置以便在解密时可用
$ciphertext = $iv . $ciphertext;

# 对生成的密文进行编码,以便它可以用字符串表示
$ciphertext_base64 = base64_encode($ciphertext);

echo
$ciphertext_base64 . "\n";

# === 警告 ===

# 生成的密文没有添加完整性或真实性
# 并且没有针对填充预言攻击进行保护。

# --- 解密 ---

$ciphertext_dec = base64_decode($ciphertext_base64);

# 获取 IV,iv_size 应使用 mcrypt_get_iv_size() 创建
$iv_dec = substr($ciphertext_dec, 0, $iv_size);

# 获取密文(除了最前面的 $iv_size)
$ciphertext_dec = substr($ciphertext_dec, $iv_size);

# 可以从明文末尾删除 00h 值字符
$plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,
$ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

echo
$plaintext_dec . "\n";
?>

上面的示例将输出

Key size: 32
ENJW8mS2KaJoNB5E5CoSAAu0xARgsR1bdzFWpEn+poYw45q+73az5kYi4j+0haevext1dGrcW8Qi59txfCBV8BBj3bzRP3dFCp3CPQSJ8eU=
This string was AES-256 / CBC / ZeroBytePadding encrypted.

参见

添加说明

用户贡献说明 16 个说明

61
scott at paragonie dot com
9 年前
如果您正在编写代码以在 2015 年加密/解密数据,您应该使用 openssl_encrypt() 和 openssl_decrypt()。底层库(libmcrypt)自 2007 年以来已被放弃,并且性能远不如 OpenSSL(它利用现代处理器上的 AES-NI 并且在缓存时序方面是安全的)。

此外,MCRYPT_RIJNDAEL_256 不是 AES-256,而是 Rijndael 块密码的不同变体。如果您想要 mcrypt 中的 AES-256,您必须使用带有 32 字节密钥的 MCRYPT_RIJNDAEL_128。OpenSSL 使您更清楚地了解使用的是哪种模式(例如 'aes-128-cbc' 与 'aes-256-ctr')。

OpenSSL 还对 CBC 模式使用 PKCS7 填充,而不是 mcrypt 的 NULL 字节填充。因此,与 OpenSSL 相比,mcrypt 更有可能使您的代码容易受到填充预言攻击。

最后,如果您没有对密文进行身份验证(先加密后 MAC),您就做错了。

进一步阅读

https://paragonie.com/blog/2015/05/using-encryption-and-authentication-correctly

https://paragonie.com/blog/2015/05/if-you-re-typing-word-mcrypt-into-your-code-you-re-doing-it-wrong
23
jesse at pctest dot com
19 年前
解决 3DES 与 .NET 的 TripleDESCryptoServiceProvider 的不兼容性

mcrypt 的 3DES 仅接受 192 位密钥,但 Microsoft 的 .NET 和许多其他工具都接受 128 位和 192 位密钥。
如果您的密钥太短,mcrypt 会“热心地”在末尾填充空字符,但 .NET 拒绝使用最后一个三分之一全是空字符的密钥(这是一个错误的密钥)。这会阻止您在 .NET 中模拟 mcrypt 的“短密钥”行为。

如何解决这个问题?需要了解一些 DES 理论。
3DES 三次运行 DES 算法,使用 192 位密钥的每个三分之一作为 64 位 DES 密钥。

加密 Key1 -> 解密 Key2 -> 加密 Key3

并且 .NET 和 PHP 的 mcrypt 都以相同的方式执行此操作。
问题出现在 .NET 上的短密钥模式中,因为 128 位只有两个 64 位 DES 密钥。
他们使用的算法是

加密 Key1 -> 解密 Key2 -> 加密 Key1

mcrypt 本身没有这种操作模式。
但在您自己开始运行三次 DES 之前,这里有一个快速修复方法
<?php
$my_key
= "12345678abcdefgh"; // 128 位(16 字节)密钥
$my_key .= substr($my_key,0,8); // 在末尾追加前 8 个字节
$secret = mcrypt_encrypt(MCRYPT_3DES, $my_key, $data, MCRYPT_MODE_CBC, $iv); // CBC 是 .NET 中的默认模式
?>

就像变魔术一样,它起作用了。

还有一个注意事项:数据填充
mcrypt 始终使用空字符填充数据。
但 .NET 有两种填充模式:“Zeros”和“PKCS7”。
Zeros 与 mcrypt 方案相同,但 PKCS7 是默认模式。
PKCS7 并不复杂,只是
它不使用空字符,而是追加填充字节的总数(这意味着,对于 3DES,它可以是 0x01 到 0x07 之间的值)。
如果您的明文是“ABC”,它将被填充为
0x41 0x42 0x43 0x05 0x05 0x05 0x05 0x05

您可以在 PHP 中通过计算最后一个字符出现的次数来删除这些字符,如果它与它的序数值匹配,则将字符串截断该数量的字符。
<?php
$block
= mcrypt_get_block_size('tripledes', 'cbc');
$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;
}
}
}
$text = substr($text,0,strlen($text) - $packing);
?>

要填充打算使用 .NET 解密的字符串,只需添加填充字节数量的 chr() 值。
<?php
$block
= mcrypt_get_block_size('tripledes', 'cbc');
$len = strlen($dat);
$padding = $block - ($len % $block);
$dat .= str_repeat(chr($padding),$padding);
?>

就这么简单。
了解这些后,您可以在 PHP 中加密、解密和完全复制任何 .NET 3DES 行为。
4
your dot brother dot t at hotmail dot com
9 年前
加密没有身份验证检查。它可以通过三种方法实现,在 http://en.wikipedia.org/wiki/Authenticated_encryption#Approaches_to_Authenticated_Encryption 中进行了描述。
先加密后 MAC(EtM)、加密并 MAC(E&M)、先 MAC 后加密(MtE)。

以下是 MtE 的建议

<?php
public static function getMacAlgoBlockSize($algorithm = 'sha1')
{
switch(
$algorithm)
{
case
'sha1':
{
return
160;
}
default:
{
return
false;
break;
}
}
}

public static function
decrypt($message, $key, $mac_algorithm = 'sha1',
$enc_algorithm = MCRYPT_RIJNDAEL_256, $enc_mode = MCRYPT_MODE_CBC)
{
$message= base64_decode($message);
$iv_size = mcrypt_get_iv_size($enc_algorithm, $enc_mode);

$iv_dec = substr($message, 0, $iv_size);
$message= substr($message, $iv_size);

$message= mcrypt_decrypt($enc_algorithm, $key, $message, $enc_mode, $iv_dec);

$mac_block_size = ceil(static::getMacAlgoBlockSize($mac_algorithm)/8);
$mac_dec = substr($message, 0, $mac_block_size);
$message= substr($message, $mac_block_size);

$mac = hash_hmac($mac_algorithm, $message, $key, true);

if(
$mac_dec == $mac)
{
return
$password;
}
else
{
return
false;
}
}

public static function
encrypt($message, $key, $mac_algorithm = 'sha1',
$enc_algorithm = MCRYPT_RIJNDAEL_256, $enc_mode = MCRYPT_MODE_CBC)
{

$mac = hash_hmac($mac_algorithm, $message, $key, true);
$mac = substr($mac, 0, ceil(static::getMacAlgoBlockSize($mac_algorithm)/8));
$message= $mac . $message;

$iv_size = mcrypt_get_iv_size($enc_algorithm, $enc_mode);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

$ciphertext = mcrypt_encrypt($enc_algorithm, $key,
$message, $enc_mode, $iv);

return
base64_encode($iv . $ciphertext);
}
?>
5
Anonymous
13 年前
在其他笔记中,有一些关于加密和 IV 的误解,尤其是针对 CBC 模式。

最重要的点:加密本身没有任何数据完整性或身份验证的证明。如果您需要确保数据是秘密的,并且没有被篡改,您需要先加密,然后使用带密钥的 HMAC。

对于 CBC 模式,IV 不需要保密。它可以与明文一起发送。它需要是唯一的和随机的。这样每条消息都使用不同的 IV 加密。

生成 IV 的最佳方法是使用 mcrypt_create_iv()。

密钥必须是二进制的,而不是 ASCII。要从密码创建密钥

<?php
$password
= "MyPassword!1!";
$aes256Key = hash("SHA256", $password, true); // 我们想要一个 32 字节的二进制数据块
?>
4
Scott.a.Herbert at googlemail.com
11 年前
始终使用标准加密算法比“自己编写”更好,首先,标准算法已经过世界级密码分析专家的测试,而除非你是世界级密码分析专家(如果你确实是,为什么还要考虑自己编写?!),否则你将无法具备测试它的必要技能(例如,如果你只是用密钥对每个字符进行异或运算,它看起来可能很安全(文本将不同),但如果你统计每个字符重复出现的次数,你会发现字母“E”的加密结果比加密后的“Z”出现的更频繁(假设是英文的明文)

其次,你可能认为你的算法的隐藏特性使其更加安全,但事实是,你的算法可能*仅仅*因为它是秘密的而安全,如果有人能够侵入你的网站并窃取你的代码(但没有你的密钥),他们也许能够破解你的加密数据,如果有人入侵并发现你正在使用 Blowfish(例如),这将无济于事。
2
MadMass
11 年前
请注意,IV 必须在 mcrypt_encrypt 和 mcrypt_decrypt 中保持一致,否则解密后数据将损坏。
2
Anonymous
13 年前
我注意到有些人使用 a-z、A-Z 和 0-9 作为密钥,并声明“16 个字符是 128 位密钥”。这是不正确的。仅使用这些字符,每个字符最多只能获得 6 位的熵

log2(26 + 26 + 10) = 5.954196310386876

因此,实际上你只在 16 个字符中获得 95 位的熵,这仅占如果你使用完整范围所获得的密钥空间的 0.0000000117%。

为了从使用 a-z、A-Z 和 0-9 的密钥中获得完整的熵,你应该将密钥长度乘以 1.3333 以弥补每个字节丢失的 2 位熵。
1
Anonymous
16 年前
我应该提到 ECB 模式会忽略 IV,因此使用 ECB 模式和 IV 的示例具有误导性(手册中的示例显示的是相同的内容)。此外,重要的是要知道 ECB 模式适用于随机数据,而结构化数据应该使用更强大的模式,如 MCRYPT_MODE_CBC

此外,rtrim($decryptedtext, "\0") 将是比我懒惰的 trim() 更好的去除 NULL 填充的选项...
-3
Robin Leffmann
14 年前
与 mcrypt_encrypt() 手册页以及关于 CBC 与 CFB 模式的说明中暗示的相反,mcrypt_encrypt() 也可以很好地用于加密二进制数据。

一个简单的示例验证了解密后的输出在截取到原始长度后是二进制相同的

<?php

// 448 位密钥(56 字节) - mcrypt/php 用于 Blowfish 密码的唯一大小
// (使用更小的密钥也能正常工作,因为 mcrypt 会追加 \0 以达到正确的密钥大小)
$key = 'SADFo92jzVnzSj39IUYGvi6eL8v6RvJH8Cytuiouh547vCytdyUFl76R';

// Blowfish/CBC 使用 8 字节的 IV
$iv = substr( md5(mt_rand(),true), 0, 8 );

// 对一些随机数据进行 50 次加密/解密操作,并使用 md5() 验证完整性
for( $i = 0; $i < 50; $i++ )
{
// 创建一个随机长度的随机二进制字符串
$size = mt_rand( 25000, 500000 );
$c = 0; $data = null;
while(
$c++ * 16 < $size )
$data .= md5( mt_rand(), true );
$data = substr( $data, 0, $size );
$cksum = md5( $data );

// 使用 Blowfish/CBC 加密
$enc = mcrypt_encrypt( MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_CBC, $iv );

echo
$size . ' -> ' . strlen( $enc ) . ' -> ';

// 解密(使用相同的 IV - 这是 CBC 模式的必要条件)
$dec = mcrypt_decrypt( MCRYPT_BLOWFISH, $key, $enc, MCRYPT_MODE_CBC, $iv );

// 使用 substr() 截取输出,而不是使用 rtrim(),正如一些
// mcrypt 手册页中建议的那样 - 这是二进制数据,而不是明文
echo ( md5(substr($dec, 0, $size)) == $cksum ? 'ok' : 'bad' ) . PHP_EOL;
}

?>
-5
stefan at katic dot me dot rs
10 年前
我尝试(并成功)在 JAVA 中进行加密和解密,将其传递给 PHP,并再次进行操作,在我注意到一些有趣的事情时没有损坏数据。所以,我的代码是这样的
$data = 'one';
$key = '1234567890123456';

function encrypt($data, $key){
return base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$key,
$data,
MCRYPT_MODE_CBC,
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
)
);
}
function decrypt($data, $key){
$decode = base64_decode($data);
return mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$key,
$decode,
MCRYPT_MODE_CBC,
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
);


}
$encrypted = encrypt($data, $key);
$decrypted= decrypt($encrypted, $key);

//一开始,我认为出了问题,因为我对 $decrypted 和 $data 进行了 '===' 比较。它不起作用(但后来又开始起作用,不知道为什么...)。所以我将两者都转储
var_dump($data);
var_dump($decrypted);
//结果
string(16) "one"
string(16) "one"
//显然,两者的长度都是 3,而不是 16。只是想让你知道可能会发生什么,我真的不知道这是否是 bug...
谢谢,
S.
-2
Anonymous
6 年前
<?php
# Vernam Cipher (One-time pad)
$k1 = '1.key';
$k2 = '2.key';
$d = 'The quick brown fox jumped over the lazy dog';
VernamCipher::createTestKeyFile($k1, 1024);
copy($k1, $k2);
$c1 = new VernamCipher($k1);
$eD = $c1->encryptWithHMAC($d);
echo
'Encrypted: ', bin2hex($eD);
$c2 = new VernamCipher($k2);
echo
PHP_EOL, 'Decrypted: ', $c2->decryptWithHMAC($eD);

class
VernamCipher
{
const
DEFAULT_HMAC_ALGO = 'sha3-256';
const
DEFAULT_HMAC_KEY_LENGTH = 16;
const
DEFAULT_HMAC_HASH_LENGTH = 32;
private
$keyFilePath;
private
$keyFileHandler;
private
$deferredFtruncate = false;
private
$deferredFtruncatePos;
private
$hmacAlgo = self::DEFAULT_HMAC_ALGO;
private
$hmacKeyLength = self::DEFAULT_HMAC_KEY_LENGTH;
private
$hmacHashLength = self::DEFAULT_HMAC_HASH_LENGTH;

function
__construct(string $keyFilePath, string $hmacAlgo = self::DEFAULT_HMAC_ALGO, int $hmacKeyLength = self::DEFAULT_HMAC_KEY_LENGTH)
{
$this->keyFilePath = $keyFilePath;
$this->openKeyFile();

if(
$hmacAlgo !== self::DEFAULT_HMAC_ALGO) {
if(
in_array($hmacAlgo, hash_algos())) {
$this->hmacAlgo = $hmacAlgo;
$this->hmacHashLength = strlen(hash($this->hmacAlgo, '', true));
}
else {
$this->hmacAlgo = self::DEFAULT_HMAC_ALGO;
$this->hmacHashLength = self::DEFAULT_HMAC_HASH_LENGTH;
}
}

if(
$hmacKeyLength !== self::DEFAULT_HMAC_KEY_LENGTH) {
$this->hmacKeyLength = $hmacKeyLength;
}
}
public function
encryptWithHMAC(string $data)
{
$hmacKey = $this->getBytes($this->hmacKeyLength);
$encData = $this->encrypt($data);
$dataHmac = $this->hashHmac($encData, $hmacKey);

return
$dataHmac.$encData;
}
public function
decryptWithHMAC(string $data)
{
$dataLength = strlen($data);

if(
$dataLength < $this->hmacHashLength)
throw new
Exception('data length '.$dataLength.' < hmac length '. $this->hmacHashLength);

$dataHmacRemote = substr($data, 0, $this->hmacHashLength);
$dataOnly = substr($data, $this->hmacHashLength);

$hmacKey = $this->getBytes($this->hmacKeyLength, false);
$dataHmacLocal = $this->hashHmac($dataOnly, $hmacKey);

if(
hash_equals($dataHmacLocal, $dataHmacRemote) === false)
throw new
Exception('Hashes not equals, remote: '.bin2hex($dataHmacRemote).' local:'. bin2hex($dataHmacLocal));

$this->deferredFtruncate();

return
$this->encrypt($dataOnly);
}
public function
encrypt(string $data) : string
{
$dataLength = strlen($data);
$bytes = $this->getBytes($dataLength);
for(
$i=0;$i<$dataLength;$i++)
$data{$i} = $data{$i} ^ $bytes{$i};

return
$data;
}
public function
decrypt(string $data) : string
{
return
$this->encrypt($data);
}
private function
hashHmac($data, $key)
{
return
hash_hmac($this->hmacAlgo, $data, $key, true);
}
# Don't use in production. You must use true random number generator.
public static function createTestKeyFile(string $filePath, int $size)
{
file_put_contents($filePath, random_bytes($size));
}
private function
deferredFtruncate()
{
if(!
$this->deferredFtruncate)
return;

ftruncate($this->keyFileHandler, $this->deferredFtruncatePos);
$this->deferredFtruncate = false;
}
public function
getBytes(int $length, $truncateNow = true) : string
{
fseek($this->keyFileHandler, 0, SEEK_END);
$currentPos = ftell($this->keyFileHandler);

if(
$currentPos < $length)
throw new
Exception('Not enough key materials, key size: '. $currentPos. ' needed: '.$length);

fseek($this->keyFileHandler, -$length, SEEK_END);
$bytes = fread($this->keyFileHandler, $length);

if(
$truncateNow)
ftruncate($this->keyFileHandler, $currentPos - $length);
else {
$this->deferredFtruncate = true;
$this->deferredFtruncatePos = $currentPos - $length;
}

return
$bytes;
}
private function
openKeyFile()
{
if(
$this->keyFileHandler)
return;

if((
$this->keyFileHandler = fopen($this->keyFilePath, 'rb+')) === false)
throw new
Exception('Cant open key file: '.$this->keyFilePath);

if(!
flock($this->keyFileHandler, LOCK_EX | LOCK_NB))
throw new
Exception('Cant lock key file: '.$this->keyFilePath);
}
}
?>
-5
stonecypher at gmail dot com
17 年前
这里大多数用户编写的密码示例都存在严重错误,而且在某些情况下,手册中说明的内容完全错误,例如“安全地以明文方式传输初始化向量”(这是不正确的:请参阅 Ciphers By Ritter,http://www.ciphersbyritter.com/GLOSSARY.HTM#IV,了解详细信息)。

mcrypt 本身是完全安全的,但正确且安全的用法并不明显。正确使用加密库非常重要;即使使用错误,即使产生的结果可以在另一端解包,也可能使强大的算法变得完全无用。

初始化向量必须使用可恢复的噪声源进行置换(任意 md5 散列是可接受的,因为它只是一个假的 OTP,其源内容完全不重要)。

密码应该使用带盐的单向散列重新生成(md5 再次可接受,即使它已经遭到破坏,因为你可以从破解的 md5 散列中恢复的唯一东西是用于生成密码的源数据,这毫无用处)。

使用合理的块模式非常重要(OFB 对几乎所有算法都不安全;切勿使用它。在所有情况下都优先使用 CBC,除非你需要处理降级信号并且无法重新传输)。

正确的用法示例实际上很长,需要很多解释,因此我开发了一个安全的包装库,它没有限制使用,并进行了非常详细的注释。它适合使用或学习。请参阅我的博客,了解有关 Stone PHP SafeCrypt 的详细信息

http://blog.sc.tri-bit.com/archives/101
-5
leilond at hotmail dot com
8 年前
我一直使用这种方法来防止很多错误

function encrypt( $string ) {
$algorithm = 'rijndael-128'; // 你可以使用任何可用的算法
$key = md5( "mypassword", true); // 16 字节的二进制原始数据。
$iv_length = mcrypt_get_iv_size( $algorithm, MCRYPT_MODE_CBC );
$iv = mcrypt_create_iv( $iv_length, MCRYPT_RAND );
$encrypted = mcrypt_encrypt( $algorithm, $key, $string, MCRYPT_MODE_CBC, $iv );
$result = base64_encode( $iv . $encrypted );
return $result;
}
function decrypt( $string ) {
$algorithm = 'rijndael-128';
$key = md5( "mypassword", true );
$iv_length = mcrypt_get_iv_size( $algorithm, MCRYPT_MODE_CBC );
$string = base64_decode( $string );
$iv = substr( $string, 0, $iv_length );
$encrypted = substr( $string, $iv_length );
$result = mcrypt_decrypt( $algoritmo, $key, $encrypted, MCRYPT_MODE_CBC, $iv );
return $result;
}
-5
gm dot outside+php at gmail dot com
9 年前
请注意,文档的以下部分不再正确(在提交后:http://git.php.net/?p=php-src.git;a=commit;h=a861a3a93d89a50ce58e1ab1abef1eb501f97483

> key
> 用于加密数据的密钥。如果密钥长度小于所需的密钥大小,则使用“\0”填充。最好不要使用 ASCII 字符串作为密钥。

该提交更改了行为,使其变得严格,如果密钥大小小于所需大小,则会发出以下警告

警告:mcrypt_encrypt(): 密钥大小 10 不支持此算法。脚本 script.php 第 5 行仅支持大小为 16 的密钥。

并且 mcrypt_encode() 将返回失败。
-7
telefoontoestel59 at hotmail dot com
9 年前
我尝试使用 rijndael-128 实现 mcrypt。作为参考,我从示例 #1 中获取了代码,并尝试先运行它,但在解密部分返回了错误:“IV 参数必须与块大小一样长”。过了一会儿,我发现生成的 IV 字符串的长度在每次运行时都不相同,而且几乎从不与 mcrypt_get_iv_size 的结果大小相同。为了解决这个问题,在合并 IV 和加密文本之前,我添加了空填充以匹配 IV 大小。在检索 IV 时,我可以使用 IV 大小和 rtrim 空填充来获得匹配的 IV。

来自示例 #1 的更改部分

<?php
# --- 加密 ---
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
$plaintext, MCRYPT_MODE_CBC, $iv);

# 添加空填充以匹配预期大小
while(strlen($iv) < $iv_size){
$iv .= "\0";
}

# 将 IV 预置,以便它可用于解密
$ciphertext = $iv . $ciphertext;
?>

<?php
# --- 解密 ---
mcrypt_get_iv_size()
$iv_dec = rtrim(substr($ciphertext_dec, 0, $iv_size));
?>
-10
ale_ferrer at yahoo dot com
18 年前
Mcript - Dot NET - 3DES 问题。

这是针对 3DES 算法与其与 .NET TripleDESCryptoServiceProvider(System.Security.Cryptography)交互时的问题的解决方案,它使用 CBC 模式,因为密钥被补充到 192 位,文本被填充。

所以,我们有两个问题
- 密钥补充由“jesse at pctest dot com”发布。
- 文本填充也由他发布,但补充方式略有不同。填充字节为 0x01 到 0x08,因为补充到 8 字节块。如果您的文本有完整的 8 字节块,则算法会添加另一个包含填充字节(0x08)的块。

这是一个以与 Dot NET 算法相同的形式加密文本的函数

<?PHP
function encryptNET3DES($key, $vector, $text){
$td = mcrypt_module_open (MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');

// 补充密钥
$key_add = 24-strlen($key);
$key .= substr($key,0,$key_add);

// 填充文本
$text_add = strlen($text)%8;
for(
$i=$text_add; $i<8; $i++){
$text .= chr(8-$text_add);
}

mcrypt_generic_init ($td, $key, $vector);
$encrypt64 = mcrypt_generic ($td, $text);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);

// 返回以 64 位代码形式加密的文本
return $encrypt64;
}
?>
To Top