不经意传输实验文档

不经意传输实验

  1. 实验相关技术—不经意传输协议
    不经意传输(OT,oblivious transfer)是一个密码学协议,目前被广泛的应用于安全多方计算(SMPC,Secure Multi-Party Computation)。它由 Rabin 在 1981 年提出,但 Rabin 最初的方案不是很完善,不能保证两方每次都能在满足要求的情况下获得秘密,还不具有应用意义。所以 1985 年 Even 等人在其基础上提出的新的 1-out-2 OT 协议。
    1985 1-out-of-2 OT
    Even 等人的提出的 1-out-of-2 OT 协议基于公钥密码体制,给出了 OT 公理化的定义和实现。场景设计: Alice(服务器端S) 拥有两个秘密 m1 和 m2 ,而 Bob(客户端C) 想要知道其中一个。在 OT 协议执行完成之后,Bob 获得了其中一个秘密,但是不知道另外一条秘密 ,并且 Alice 也不知道 Bob 选择的是 m1 ,还是 m2 。

该协议的安全性在于步骤 3) 中,服务器端 S 无法知晓客户端 C 的选择的随机数 r , 从而对客户端 C 的最终选择也就无从知晓。
不经意传输协议可用于隐私信息检索(Private Information Retrieval – PIR,也叫匿踪查询)是安全多方计算中很实用的一项技术,用来保护用户的查询隐私。其目的是保证用户向服务器(数据源方)提交查询请求时,在用户查询信息不被泄漏的条件下完成查询。即整个查询过程中服务器不知道用户具体查询信息及查询出的数据项。
2. 实验环境
申请资源:2台ECS

操作系统:Window 10 及以上

预装:AnaConda
3. 实验步骤1-配置编程环境
配置编程环境(资源环境如果较卡顿,可以打开任务管理器将占据CPU资源过大的进程关掉)
1)申请实验资源后,“云产品资源”选项卡下将显示已申请:云服务器ECS-1 和云服务器ECS-2 。
2)本地打开系统的“远程桌面”,复制云服务器ECS-1 中“弹性IP”对应的 IP 地址到远程桌面连接的“计算机©:”处,点击“连接”。
3)弹出“输入你的凭据”窗口,将云服务器ECS-1 中的“用户名”和“密码”复制到窗口,确认连接到远程计算机。
4)连接到云服务器ECS-1 后,全屏状态,在左下角“开始”菜单,“应用”中打开“Anaconda Prompt”。输入
jupyter-lab
5)在弹出的浏览器页面中,选择“Notebook”下“Python 3”,默认建立一个Python文件。可重命名为“Server.ipynb”,后续步骤3中的代码放置于此文件中。
6)关于云服务器ECS-2 的远程连接,Python文件建立与以上步骤2)-5)类似,可将云服务器ECS-2 上的Python文件命名为“Clint.ipynb”。
4. 实验步骤2-实现基本的RSA算法
实现基本的RSA算法
在服务器端和客户端均需要实现基本的 RSA 算法,即步骤 2 的代码需放入步骤 3 和 4 的代码中,即文件“Server.ipynb”和“Clint.ipynb”中。
在本实验示例代码中,可能用到 random、sympy 库,需先导入。
import random
import sympy

在RSA算法的简单实现示例中,需要完成6个函数功能,分别是:
1)gcd(a, b) ,功能:求 a 与 b 的最大公约数。输入:整数 a 和 b。输出: a 与 b 的最大公约数。请同学们自行编写函数 gcd(a, b) 。
示例代码如下:

求 a 与 b 的最大公约数

def gcd(a, b):
while b != 0:
a, b = b, a % b
return a

2)multiplicative_inverse(e, phi),功能:求 e 模 phi 的乘法逆元,用于计算私钥。输入:公钥 e,欧拉函数phi。输出:私钥 d 和 欧拉函数 phi 。请同学们自行编写函数 multiplicative_inverse(e, phi) 。
示例代码如下:

求乘法逆元,用于计算私钥

def multiplicative_inverse(e, phi):
d = 0
x1 = 0
x2 = 1
y1 = 1
temp_phi = phi
while e > 0:
temp1 = temp_phi//e
temp2 = temp_phi - temp1 * e
temp_phi = e
e = temp2
x = x2- temp1* x1
y = d - temp1 * y1
x2 = x1
x1 = x
d = y1
y1 = y
if temp_phi == 1:
return d + phi

3)generate_keypair(p, q),功能:生成公钥(e, n)和私钥(d, n)。输入:素数p,素数q。输出:公钥(e, n),私钥(d, n)。请同学们根据 RSA 算法原理,自行编写函数 generate_keypair(p, q)。
示例代码如下:

生成公钥(e, n)和私钥(d, n)

def generate_keypair(p, q):
n = pq #计算模数 n
phi = ((p-1)
(q-1)) #计算欧拉函数 phi
e = random.randrange(1, phi) #随机选择一个公钥 e

g = gcd(e, phi) #计算 e 与 phi 的最大公约数
while g != 1: # 要求 e 与 phi 互素,循环选择 e 达到要求
e = random.randrange(1, phi)
g = gcd(e, phi)

求公钥 e 对应的私钥 d,e 与 d 模 phi 互为乘法逆元

d = multiplicative_inverse(e, phi)
return ((e, n), (d, n))

4)encrypt(pk, plaintext),功能:加密算法。输入:公钥 pk,明文plaintext。输出:密文 cipher。请同学们自行编写函数
示例代码如下:

RSA 加密算法

def encrypt(pk, plaintext):
key, n = pk
cipher = (plaintext ** key)%n
return cipher

5)decrypt(pk, ciphertext),功能:解密算法。输入:私钥 pk,密文ciphertext。输出:明文plain。请同学们自行编写函数 decrypt(pk, ciphertext)。
示例代码如下:

RSA 解密算法

def decrypt(pk, ciphertext):
key, n = pk
plain = (ciphertext ** key) % n
return plain

  1. 实验步骤3-编写隐私查询服务器端代码
    在本实验示例代码中,将用到 socket、threading、time、sys库,需先导入。
    #-----隐私查询服务器----
    import socket
    import threading
    import time
    import sys

实验中,假设服务器端有数据 ‘m1’:111 和 ‘m2’:222。客户端想查询其中一个数据 m1 或者 m2,但是不想服务器知道客户端具体收到了哪个数据。先中服务器端初始化数据。
#给服务器端数据赋初值
query_data = {‘m1’:111,‘m2’:222}

服务器端建立 socket 服务,用于服务器端和客户端的连接服务。注意:此段代码中需要更新绑定的ECS的IP。
def socket_service():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 防止socket server重启后端口被占用(socket.error: [Errno 98] Address already in use)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((‘IP’, 6666))#此处需绑定分配ECS-1的私有地址
s.listen(10)
except socket.error as msg:
print(msg)
sys.exit(1)
print(‘Waiting connection…’)
while 1:
conn, addr = s.accept()
t = threading.Thread(target=deal_data, args=(conn, addr))
t.start()

当服务器端收到客户端连接请求后,处理收到的数据。不经意传输协议主要在这个函数中实现。请同学自行设计服务器与客户端的交互命令,实现不经意传输协议。
示例代码如下:

数据处理函数

def deal_data(conn, addr):
print(‘Accept new connection from {0}’.format(addr))
conn.send((‘Hi, Welcome to the server!’).encode())
#生成2对rsa密钥
p1 = sympy.randprime(1, 100)
q1 = sympy.randprime(1, 100)
p2 = sympy.randprime(1, 100)
q2 = sympy.randprime(1, 100)
public1, private1 = generate_keypair(p1, q1)
public2, private2 = generate_keypair(p2, q2)
print(public1)
print(private1)
print(public2)
print(private2)

while 1:
data = conn.recv(1024)
command = data.decode()
#如果服务器端收到客户端的命令“get public keys”,则发送2个公钥给客户端
if command == ‘get public keys’:
s = (public1.str()+‘?’+public2.str()).encode()
print(s)
conn.send(s)
#如果服务器端收到客户端的命令“Query Data”
if command == ‘Query Data’:
# 解密数据
print(‘---------------解密数据---------’)
c = conn.recv(1024)
c = int.from_bytes(c, byteorder=‘big’)
print©

      r1 = decrypt(private1,c)  
      r2 = decrypt(private2,c)
      print('服务器端收到的 2 个解密后的随机数:')
      print(r1)
      print(r2)
       
      m1 = query_data['m1'] 
      m2 = query_data['m2'] 
      
      e1 = m1^r1
      e2 = m2^r2
      #int转bytes
      e1 = e1.to_bytes(8,byteorder = 'big',signed = False)           
      e2 = e2.to_bytes(8,byteorder = 'big',signed = False)
       
      conn.send(e1)
      time.sleep(4)
      conn.send(e2)

  if command == 'exit' or not data:
      print('{0} connection close'.format(addr))
      conn.send(bytes('Connection closed!'),'UTF-8')
      break          

conn.close()

最后,编写主函数,程序的执行起点,调用socket_service()。
if name == ‘main’:
socket_service()

  1. 实验步骤4-编写隐私查询客户端代码
    先放入步骤2基本的RSA算法的代码。

在本实验示例代码中,将用到 socket、sys、random、 numpy库,需先导入。
#--------------隐私查询客户端-------------
import socket
import sys
import random
import numpy as np

客户端建立 socket 服务,用于服务器端和客户端的通信,同时完成不经意传输协议。请同学自行设计服务器与客户端的交互命令,实现不经意传输协议。

建立 socket 服务

def socket_client():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#此处需绑定分配 ECS-1 的 私有地址,端口号与服务器端一致即可
s.connect((‘IP’, 6666))
except socket.error as msg:
print(msg)
sys.exit(1)
print(s.recv(1024))
#目的在于接受:Accept new connection from (…
while 1:
command = input(‘please input command: ‘)
s.send(command.encode())
#向服务器端请求公钥
if command == ‘get public keys’:
print(’----------get public keys----------’)
ku1,ku2 = s.recv(1024).decode().split(‘?’)

      ku1 = tuple(eval(ku1))
      ku2 = tuple(eval(ku2))
       
      print(ku1)
      print(ku2)
  #向服务器端查询数据,请用户选择,若用户输入“1”表示查询数据 m1,用户输入“2”表示查询数据 m2。
  if command == 'Query Data':
      p = input('please input public key 1 or 2: ')
      if p =='1':
          k = ku1
      if p =='2':
          k = ku2
      else:
          k = ku1
      #随机生成0——1000的随机整数
      r = random.randint(0,1000)
      print('random number:')
      print(r)
      #把整数转换为bytes;
      #第一个参数8表示bytes的长度是8bytes
      #byteorder这是设置为大端;signed表示是否有符号;
      #r_b = r.to_bytes(8,byteorder = 'big',signed = False)
      # 加密数据
      crypto = encrypt(k,r)
      crypto = crypto.to_bytes(8,byteorder = 'big',signed = False)
      s.send(crypto)
                  
      for i in np.arange(2):
          e = s.recv(1024)
          e = int.from_bytes(e, byteorder='big')
          m = e^r            
          print(m)             

  if command == 'exit':
      break

s.close()

最后,编写客户端主函数,程序的执行起点,调用socket_client()。
if name == ‘main’:
socket_client()

  1. 测试过程
    1)先启动服务器端。启动成功后,将提示:
    Waiting connection…
    2)启动客户端。启动成功后,将提示:
    b’Hi, Welcome to the server!’
    please input command:
    3)客户端输入命令:get public keys。服务器端返回数据后,将提示:
    ----------get public keys------------------
    (2455, 2923)
    (733, 2449)
    please input command:
    注意:每次运行生成的公钥不一样。
    4)客户端输入命令:Query Data。将提示:
    please input public key 1 or 2:
    5)客户端输入“1”或者“2”,若输入“1”表示查询数据 m1,用户输入“2”表示查询数据 m2。客户端输入后,服务器端将返回所查询的数据。
    please input public key 1 or 2: 2
    random number
    566
    1573
    222
    注意:这里示例选择了数据 m2,即返回了“222”,正确。
    测试结果如下:
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值