背景/上下文 这些信息可能提供额外的情境化见解,但不需要阅读以理解我的问题的基本基础知识,如下所列。
作为我正在设计的高可靠性安全协议栈的一部分,我将SSL数据流分块为“帧”或“块”以提高网络可靠性并减轻底层网络损坏:丢弃/损坏/错误传输的帧将是能够重传,我的网络层也将高度容忍物理断开连接。为了实现这些功能,帧将包括帧ID,帧块大小和帧校验和。
我的问题是,这个“框架层”必须是未加密的,因为它需要在尝试解密之前验证数据块是否成功到达......并且因为整个堆栈将是开源的,所以它非常容易攻击者解密帧头数据并立即知道他们是在查看有效还是损坏的数据。加密层将使用两端使用公钥和私钥保护的SSL,因此解密将显着不重要,但我仍然想要消除这个小的攻击向量。
今天早些时候,我正在无所事事地思考所有这些并提出了一个有趣的想法:链接的两端都同意一些混淆协议/方案参数,这些参数以可逆的方式“扰乱”ID /大小/校验和数据。此协议将发生在SSL层内...意味着需要对整个SSL数据流进行解码以使头信息有意义......但是此操作突然变得非常困难,因为ID /大小/校验和标头会在这一点上基本上是毫无意义的“线路噪声”,如果我稍微随机化块大小,标头位置将变得不可预测,并且解密将基本上成为从数据流中删除随机字节的巨大实验...通过发送攻击难度屋顶。
至少,我认为它会像这样运作。我不是密码分析师/密码学家,这是我的第一个安全协议设计。也许有人可以打电话给我,告诉我,如果我在这里说话。
此外,橡皮鸭编程确实有效:我想我会提到我在输入这篇文章时想出了块大小随机化的东西。 ^^
我的问题
我需要一小部分算法,我可以随机堆叠一个或多个算法,每个算法将采用一个或多个可修改的参数,并使用所述参数转换变量位宽数,使其成为可能与其原始价值无关。
最重要的是,当我提供运行的算法列表和使用的参数时,我需要一种方法将“加密”值反转回原始值。
虽然我更喜欢这些算法的输出保持与我当前设计中相同数量的物理字节进行传输,但如果提高安全性,我不介意稍微大一点的网络有效负载。 (目前标头当前为2-3个字节:一个15位ID,一个1位“大小标度”标志,以及一个8位(1-256字节)或16位(257-65791字节)的块大小值。)
此外,FWIW,这个系统可能会跨越多种语言,但我目前正在用PHP(作为控制台脚本)实现/原型化,因为我目前对这种语言有最丰富的经验。
转换为字符串,然后像平常一样加密它。
<?php
declare(strict_types=1);
/**
* Encrypt an integer using libsodium.
* Requires PHP 7.2+ or paragonie/sodium_compat.
*
* @source https://stackoverflow.com/a/48013001/2224584
* @param int $integer
* @param string $key
* @return string
*/
function encryptInteger(int $int, string $key): string
{
$littleEndian = pack('V', $int);
$nonce = random_bytes(24);
return sodium_bin2hex(
$nonce .
sodium_crypto_secretbox($littleEndian, $nonce, $key)
);
}
/**
* Decrypt an integer using libsodium.
* Requires PHP 7.2+ or paragonie/sodium_compat.
*
* @source https://stackoverflow.com/a/48013001/2224584
* @param string $ciphertext
* @param string $key
* @return string
* @throws Exception
*/
function decryptInteger(string $ciphertext, string $key): int
{
$decoded = sodium_hex2bin($ciphertext);
if (!is_string($decoded)) {
throw new Exception('Invalid encoding');
}
if (mb_strlen($decoded, '8bit') < 40) {
throw new Exception('Message too short!');
}
$nonce = mb_substr($decoded, 0, 24, '8bit');
$encrypted = mb_substr($decoded, 24, null, '8bit');
$decrypted = sodium_crypto_secretbox_open(
$encrypted,
$nonce,
$key
);
if (!is_string($decrypted)) {
throw new Exception('Invalid ciphertext');
}
$unpacked = unpack('V', $decrypted);
if (!is_array($unpacked)) {
throw new Exception('Invalid value');
}
return (int) array_shift($unpacked);
}
您可以在here中看到此代码(需要PHP 7.2)。这使用经过身份验证的加密并为您处理nonce。
请参阅SeedSpring,它使用AES-CTR从秘密种子生成确定性伪随机输出。
一种解决方案是具有足够大的块大小的块密码,以保持您需要的最大位数:15 + 1 + 16 = 32位。 DES(64位)或AES(128位)具有足够大的块大小来处理这个问题,尽管有一些空间开销。如果开销太大,那么Speck cipher有一个32位的块大小选项,并且可能更合适,但这远远不如DES或AES那样在库中得到支持。