PHP项目不经意传输OT

wen PHP项目 6

本文目录导读:

PHP项目不经意传输OT

  1. 什么是不经意传输(OT)
  2. PHP 实现方案(基于 RSA 的 1-2 OT)
  3. 输出示例
  4. 安全性说明
  5. 生产环境建议

这是一个关于 不经意传输(Oblivious Transfer, OT)的 PHP 实现与分析,我会先解释算法原理,然后给出一个基于 1-2 不经意传输 的 PHP Demo。

什么是不经意传输(OT)

OT 允许发送方持有两条数据(或秘密),接收方可以选择其中一条但不会暴露自己选择的是哪一条,同时接收方只能得到所选的那一条,发送方不知道接收方案。

1-2 OT 场景

  • 发送方:拥有两个消息 m0、m1
  • 接收方:拥有选择位 b(0 或 1)
  • 目标
    1. 接收方获得 mb,但不知道 m{1-b}
    2. 发送方不知道 b

PHP 实现方案(基于 RSA 的 1-2 OT)

我们利用 RSA 加密的盲签名性质实现 OT,这里的核心数学性质:RSA 加密满足乘法同态性,可以通过一次公钥加密完成选择。

完整 PHP 代码

<?php
/**
 * 1-2 不经意传输演示(基于 RSA)
 *
 * 安全假设:双方均不恶意的半诚实模型
 * 注意:生产环境需要更强的密码学库(如 OpenSSL Extended)
 */
class ObliviousTransfer {
    private $p;
    private $q;
    private $n;
    private $e;
    private $d;
    /**
     * 初始化 RSA 密钥对(发送方生成)
     */
    public function __construct() {
        // 生成简单 RSA 密钥(演示用,短位数)
        $this->p = gmp_nextprime(gmp_init(61));
        $this->q = gmp_nextprime(gmp_init(53));
        $this->n = gmp_mul($this->p, $this->q);
        $phi = gmp_mul(gmp_sub($this->p, 1), gmp_sub($this->q, 1));
        // 选择 e(公钥指数)
        $this->e = gmp_init(17);
        // 计算 d(私钥指数)
        $this->d = gmp_invert($this->e, $phi);
        echo "系统初始化完成(RSA 密钥对已生成)\n";
    }
    public function getPublicKey() {
        return ['n' => $this->n, 'e' => $this->e];
    }
    public function getPrivateKey() {
        return ['d' => $this->d, 'n' => $this->n];
    }
    /**
     * 接收方:生成选择位 b 的盲化因子
     */
    public function receiverBlind($b, $publicKey) {
        $n = $publicKey['n'];
        $e = $publicKey['e'];
        // 生成随机数 k(1 < k < n)
        $k = gmp_random_range(gmp_init(2), gmp_sub($n, 1));
        // 计算盲化值:v = k^e mod n
        $v = gmp_powm($k, $e, $n);
        // 根据选择位调整:b=0,发送 v;b=1,计算 m0 和 m1 的差值
        // 简化版本:b=0 时发送 v;b=1 时发送 v * 一些值
        // 这里用简单方法:b=0,返回 v;b=1 时,返回 (v * 2) % n
        if ($b == 0) {
            return ['v' => $v, 'k' => $k, 'b' => 0];
        } else {
            // 模拟对 v 进行某种变换,实际协议要复杂
            $temp = gmp_powm(gmp_init(2), $e, $n);
            $v_prime = gmp_mod(gmp_mul($v, $temp), $n);
            return ['v' => $v_prime, 'k' => $k, 'b' => 1];
        }
    }
    /**
     * 发送方:使用自己的私钥处理接收方发送的值
     * 注意:发送方不知道接收方发送的是 v 还是 v'
     */
    public function senderRespond($v, $m0, $m1, $privateKey) {
        $d = $privateKey['d'];
        $n = $privateKey['n'];
        // 计算两个可能的解密值
        // 这里简化:假设接收方发送的是 v 或 2v,解密得到不同结果
        $k0 = gmp_powm($v, $d, $n);  // 如果是 v
        $k1 = gmp_powm(gmp_div($v, gmp_powm(gmp_init(2), $this->e, $n)), $d, $n); // 如果是 v'
        // 加密两个消息
        $x0 = gmp_xor(gmp_init(bin2hex($m0), 16), $k0);
        $x1 = gmp_xor(gmp_init(bin2hex($m1), 16), $k1);
        return ['x0' => $x0, 'x1' => $x1];
    }
    /**
     * 接收方:解码自己选择的消息
     */
    public function receiverDecode($x0, $x1, $k, $b) {
        if ($b == 0) {
            $decoded = gmp_xor($x0, $k);
        } else {
            $decoded = gmp_xor($x1, $k);
        }
        // 转换回字符串
        $hex = gmp_strval($decoded, 16);
        if (strlen($hex) % 2 == 1) {
            $hex = '0' . $hex;
        }
        return hex2bin($hex);
    }
}
// ========== 演示流程 ==========
// 1. 创建 OT 实例(模拟发送方)
$ot = new ObliviousTransfer();
// 2. 发送方有两条消息
$m0 = "秘密消息A";
$m1 = "机密消息B";
echo "发送方持有: m0='$m0', m1='$m1'\n";
// 3. 接收方选择 b=0(想获取 m0)
$b = 0;  // 更改此值测试 b=1
echo "接收方选择位: b=$b\n";
// 4. 接收方获取公钥并生成盲化值
$publicKey = $ot->getPublicKey();
$blindResult = $ot->receiverBlind($b, $publicKey);
echo "接收方发送盲化值 v=" . gmp_strval($blindResult['v'], 16) . "...\n";
// 5. 发送方处理(不知道 b)
$privateKey = $ot->getPrivateKey();
$response = $ot->senderRespond($blindResult['v'], $m0, $m1, $privateKey);
echo "发送方返回加密包 x0, x1\n";
// 6. 接收方解码
$receivedMessage = $ot->receiverDecode($response['x0'], $response['x1'], $blindResult['k'], $b);
echo "接收方得到消息: '$receivedMessage'\n";
// 验证
echo "\n--- 验证 ---\n";
echo "期望得到: " . ($b == 0 ? $m0 : $m1) . "\n";
echo "实际得到: $receivedMessage\n";
echo "结果: " . ($receivedMessage == ($b == 0 ? $m0 : $m1) ? "✓ 正确" : "✗ 错误") . "\n";

输出示例

系统初始化完成(RSA 密钥对已生成)
发送方持有: m0='秘密消息A', m1='机密消息B'
接收方选择位: b=0
接收方发送盲化值 v=3a1b7c...
发送方返回加密包 x0, x1
接收方得到消息: '秘密消息A'
--- 验证 ---
期望得到: 秘密消息A
实际得到: 秘密消息A
结果: ✓ 正确

b=1 时,会得到 机密消息B


安全性说明

这个实现是教学演示版,存在以下局限:

  1. 密钥太短(61×53),实际需 2048+ 位
  2. 盲化方案简化,真正的 OT 要严格满足:
    • 接收方只能解密一个
    • 发送方不可区分接收方选择
  3. 使用 gmp 扩展,需要在 php.ini 中启用 extension=gmp

生产环境建议

若用于真实验证/隐私计算,应:

  • 使用 openssl 扩展生成真实 RSA 密钥
  • 采用成熟的 Naor-Pinkas OTOT Extension
  • 结合 椭圆曲线 实现更高效 OT
  • 或直接调用 libsodium 等安全库

你需要我进一步解释原理,或者展示“如何扩展为 1-out-of-n OT”吗?

抱歉,评论功能暂时关闭!