【发布时间】:2015-04-23 02:55:28
【问题描述】:
我在 php(作为服务)中编写了一个代码来解密通过协议发送的密码。该协议要求密码为“Mac then Encrypt”ed (MtE) 使用 AES256,然后使用 base-64 编码。
消息结构如this comment on php.net中所述。
base46encoded (iv + ecrypted(mac + password))
这个过程很容易使用 php
public static function getPassword($password, $key, $mac_algorithm = 'sha1',
$enc_algorithm = MCRYPT_RIJNDAEL_256, $enc_mode = MCRYPT_MODE_CBC)
{
// truncating pre-shared key to 32 bytes.
$key = substr($key, 0, 32);
// decoding the message (being a password) from base64
$password = base64_decode($password);
// getting the iv size based on algorithm and encryption mode
$iv_size = mcrypt_get_iv_size($enc_algorithm, $enc_mode);
// extracting iv from message header (normally the first 32 byte) for decryption
$iv_dec = substr($password, 0, $iv_size);
// getting the encrypted message after the header (after the first 32 byte)
$password = substr($password, $iv_size);
// decrypting message using the pre-shared key and extracted iv
$password = mcrypt_decrypt($enc_algorithm, $key, $password, $enc_mode, $iv_dec);
// getting block size for hash algorithm in bytes (sha1 block size is 160 bit)
$mac_block_size = ceil(static::getMacAlgoBlockSize($mac_algorithm)/8);
// extracting the mac from the header of decrypted message
$mac_dec = substr($password, 0, $mac_block_size);
// extracting the valuable message
$password = substr($password, $mac_block_size);
// eliminate extra null terminators padded as the result of enc/decryption the following if and the next statement are check clauses for unpack function
$password = unpack('Z*', $password);
if (!isset($password[1]))
{
return false;
}
// obtaining the pure intended message (being the password) from the unpack result
$password = $password[1];
// regenerating the mac to control the authenticity and correctness of transmission
$mac = hash_hmac($mac_algorithm, $password, $key, true);
// see if transmitted mac (mac_dec) and the generated mac are the same and the data is valid
if($mac_dec == $mac)
{
return $password;
}
else
{
return false;
}
}
现在的问题是,在iOS中应用是围绕这个协议开发的,尝试了AESCrypt和CCCrypt,但是解密结果不一样(乱码)。
我们使用标准 CCHmac、Base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn 和 This SO answer 用于 CCCrypt。
【问题讨论】:
-
对不起,我迷失在 php 中(已经很久了)和变量名的重用:$password 是输入的 Base64 密码,二进制密码,结果解密,然后是自身的一个元素。如果我理解变量名中“dec”的含义,这也会对我有所帮助。变量命名对于理解代码非常重要。
-
@Zaph 我在 php 上添加了 cmets。非常感谢您在此问题上的投入和专业知识。
-
AES 使用 128 位(16 字节)的 iv,与块大小相同。 Common Crypto 支持 AES,因此注释“从消息头(通常是前 32 个字节)中提取 iv”不正确,请检查 ph 代码中的 iv 大小和块大小。 Rijndael 可以具有以下几种块大小之一:128、192 和 256 位块大小。基本上不要使用块大小为 192 或 256 的 Rijndael,因为它没有得到很好的研究,因此可能不太安全。
-
您误解了该文档,它指出:“绝密信息需要使用 192 或 256 密钥长度。” 密钥长度,而不是块大小,它们是两个不同的东西。 AES 支持 128、192 和 256 位密钥大小和 128 位块大小。除非您是在加密安全方面拥有超过 10K 小时经验的领域专家,否则不要设计自己的安全性。领域专家不依赖维基百科。
-
首先要了解这些常量的含义: MCRYPT_RIJNDAEL_128 MCRYPT_RIJNDAEL_192 MCRYPT_RIJNDAEL_256 这三个选项指定了与 Rijndael 加密一起使用的 block-size 不是密钥加密的大小(即强度)。
标签: php objective-c encryption