Php 如何将无符号整数从0可逆地随机/加密到大约2^24?

Php 如何将无符号整数从0可逆地随机/加密到大约2^24?,php,security,ssl,encryption,Php,Security,Ssl,Encryption,背景/背景 这些信息可能会提供更多的背景知识,但不是理解我的问题的基本知识所必需的阅读,如下所列 作为我正在设计的高可靠性安全协议栈的一部分,我将SSL数据流分块为“帧”或“块”,以提高网络可靠性并减轻底层网络损坏:丢弃/损坏/错误传输的帧将能够重新传输,我的网络层也将高度容忍物理断开连接。为了完成这些壮举,帧将包括帧ID、帧块大小和帧校验和 我的问题是,这个“帧层”必须是未加密的,因为它需要在尝试解密之前验证数据块是否成功到达。。。由于整个堆栈都是开源的,攻击者破译帧头数据并立即知道他们查看的

背景/背景
这些信息可能会提供更多的背景知识,但不是理解我的问题的基本知识所必需的阅读,如下所列

作为我正在设计的高可靠性安全协议栈的一部分,我将SSL数据流分块为“帧”或“块”,以提高网络可靠性并减轻底层网络损坏:丢弃/损坏/错误传输的帧将能够重新传输,我的网络层也将高度容忍物理断开连接。为了完成这些壮举,帧将包括帧ID、帧块大小和帧校验和

我的问题是,这个“帧层”必须是未加密的,因为它需要在尝试解密之前验证数据块是否成功到达。。。由于整个堆栈都是开源的,攻击者破译帧头数据并立即知道他们查看的是有效的还是损坏的数据非常容易。加密层将使用SSL,它使用两端的公钥和私钥进行加密,因此解密将是非常重要的,但我仍然希望消除这个小的攻击向量。 今天早些时候,我在漫不经心地思考这一切,并提出了一个有趣的想法:链路的两端都同意一些模糊协议/方案参数,这些参数以可逆的方式“扰乱”ID/大小/校验和数据。此协议将发生在SSL层内。。。这意味着需要对整个SSL数据流进行解码,以使标头信息有意义。。。但是这个动作会突然变得非常困难,因为ID/size/checksum头在这一点上基本上是无意义的“线噪声”,如果我稍微随机化块大小,头的位置将变得不可预测,解密本质上将成为从数据流中删除随机字节的一个巨大实验。。。通过屋顶发送攻击难度

至少,我认为会是这样。我不是密码分析师/密码学家,这是我第一次设计安全协议。也许有人可以打电话给我,告诉我我是不是在胡说八道

另外,橡皮鸭编程真的很有效:我想我应该提到我在键入这篇文章时提出了块大小的随机化方法^^

我的问题

我需要一个小的算法集合,我可以随机地将一个或多个算法堆叠在彼此之上,每个算法将采用一个或多个可修改的参数,并使用所述参数来转换可变的比特宽度数,从而使其与原始值无关

最重要的是,当我提供运行的算法列表和使用的参数时,我需要一种方法将“加密”值反转回其原始值

虽然我更喜欢将这些算法的输出保持在与我当前设计中相同的物理字节数,但如果能提高安全性,我不介意稍微增加网络有效负载。
(当前标头当前为2-3字节:15位ID、1位“大小刻度”标志以及8位(1-256字节)或16位(257-65791字节)块大小值。)


另外,FWIW,这个系统可能会跨越多种语言,但我目前正在用PHP(作为控制台脚本)实现/原型化它,因为我目前对这种语言有最多的经验。

一个解决方案是块密码,它的块大小足以容纳您所需的最大位数:15+1+16=32位。DES(64位)或AES(128位)都有足够大的块大小来处理这个问题,尽管有一些空间开销。如果开销太大,则具有32位块大小选项,可能更适合,但在库中这远不如DES或AES所支持的那样好。

加密整数 转换为字符串,然后像普通一样加密它

<?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);
}

PHP有很多加密功能,包括对称加密和公钥加密,你看过手册的相关章节了吗?@GordonM:我决定在SSL层使用phpseclib(),因为它比PHP的OpenSSL库快。你做了一个很好的观点,我没有办法重新实现所有这些:)或AES在任何流模式,如CTR与固定大小的24位。HRM,这听起来很有趣的考虑。斑点密码看起来特别实用,因为它看起来非常简单,开销非常低,如您所说。我不需要图书馆的支持;Wikipedia上有一个示例C编码器实现,我只需要找到一个解码器,它将是一个直端口。进一步考虑,如果我需要更多比特,AES或DES可能会证明是非常宝贵的;我怎样才能使用其中的一个呢?也就是说,我可以在哪里找到示例编码器/解码器实现,或者我应该寻找什么库函数?我刚刚意识到我可能需要考虑的另一个问题是,如果要求PHP以本机方式处理非常大的数字,PHP往往会阻塞;特别是在某些情况下,它可能在32位和64位平台上产生悲惨的不一致结果。我的日常工作跨越建筑宽度是至关重要的,我已经在其他地方使用GMP解释了这一点。更简单的算法更可取,因为我可能也需要为系统的这一部分推出基于GMP的实现。呵呵