DeepLearning / 云计算安全 / 人工智能AI · 2022年3月12日 4

同态加密的人脸识别v1-简单实现

一、方案介绍

人脸识别:dlib_Face //因为简单

加密算法:Paillier(加法同态)

服务器架构:

注意:以下思路几乎是在参考和学习后自己提出的方法:

(如有问题,后续再做修改)

1、初步设想与无法实现的原因

按照已有论文中的服务器架构的图:

  • 客户提取待识别人脸特征后转为 csv 并加密上传至数据库服务器DS
  • 而 DS 拥有所有已知人脸特征的密文

我先前的设想:

  • 在 DS 中计算待识别人脸特征密文与数据库中人脸密文的平方欧式距离
  • 将平方欧氏距离传至认证服务器AS,AS 将之解密得到平方欧氏距离明文,再据此做人脸识别的判定

无法实现的原因:我昨夜思来想去这一步里平方是密文相乘操作,按理说Paillier无法实现同态。然后今早我改了代码尝试了一下确实这样不能成行(因为密文不能做乘法)。

2、现做法及安全性解释

因为平方欧式距离计算起来是三步:

  • 先计算两个不同特征列表对应元素的差
  • 再将差平方
  • 最后再求差平方的和

因为paillier不能做平方那一步。所以:

  • 客户端生成特征密文后发送至数据库服务器DS,在DS中做密文的差值。
  • 做差后就停下来 直接发给身份验证服务器AS
  • AS拿到之后直接解密,解密后做平方和,即为所求平方欧式距离

该方案也能保证一定的安全性:

在此过程中,客户端发送数据由于是密文,DS不会知道客户端特征明文,而AS拿到的是差值,虽然有密钥,也不会知道客户端和DS中存放的原本特征明文,只能计算出差值,因此两个服务器都没法直接得到特征值明文,安全性应该没啥大问题

注:仅个人之见,习同态甚少,如有纰漏,敬请指正!

二、代码解释

我将所有加密操作放在同一份代码文件 HE_All_paillier.py 中了,通过使用类和csv文件位置来粗糙地模拟服务器与客户端各自的访问权限。

代码中的详细问题可以在注释中得到很好的解释

另外,人脸部分:

录入人脸可以采用Client中 get_faces_from_camera.py 文件使用电脑摄像头进行人脸检测和截取;也可以自行下载符合大小规范的图片输入到文件夹data中的对应位置,记住要保持文件结构。

提取特征可以在上述操作完成后进行统一的处理,代码参考 features_extraction_to_csv.py 。

三、运行效果:

代码结构图如下:

我将所有加密操作放在同一份代码文件 HE_All_paillier.py 中了,通过使用类和csv文件位置来粗糙地模拟服务器与客户端各自的访问权限。

效果图:

人脸图涉及照片,还是别放出来了

计算特征向量密文:

密文相减:

对相减的结果解密并计算平方欧氏距离:

人脸识别效果:

不放人像

四、写在最后:

开始由于论文中采用的加密算法不同,导致走了许多弯路,比如量化和自己造轮子写加密

本方案和代码还有许多许多疏漏之处和不足,但由于最近考研复试在即,毕业设计中期也将到DDL,明天就要提交本综合实验的材料,因此Vision-1的同态加密人脸识别的代码实现且至此不变。

但是基于实际情况和应用场景,代码完整性还远远不足,远未到可用的地步,待最近事宜结束后,我将再次优化至v2,彼时将更新到GitHub和我的个人博客网站个人博客网站


附上代码与简单介绍:

from phe import paillier # 开源库
import time # 做性能测试
import cv2
import os
import dlib
from pandas import read_csv
from skimage import io
import csv
import numpy as np

paillier.DEFAULT_KEYSIZE = 512 # 私钥大小参数设置

'''生成公私钥'''
public_key,private_key = paillier.generate_paillier_keypair()

'''类: client客户端'''
class Client_Pai(object):

        def read_csv(): # 读取特征.csv入列表
                nd = np.genfromtxt('./Client/unknwn_feature.csv', delimiter=',', skip_header=True)
                final_list = nd.tolist()
                return final_list
        

'''类: dataServer数据服务器'''        
class DS_Pai(object):

        def read_csv(): # 读取特征.csv入列表
                nd = np.genfromtxt('./data/feas_DB.csv', delimiter=',', skip_header=True)
                final_list = nd.tolist()
                return final_list

'''类: AuthServer数据服务器'''        
class AS_Pai(object):

        def read_csv(): # 读取特征.csv入列表
                nd = np.genfromtxt('./AuthServer/mid.csv', delimiter=',', skip_header=True)
                final_list = nd.tolist()
                return final_list





'''Client 操作'''

# 读取csv已提取特征
unknwn_feature = Client_Pai.read_csv()

# 加密并存入csv
unknwn_enc = [public_key.encrypt(m) for m in unknwn_feature]
file = open('./Client/enc_unknwn_fea.csv','w') 
file.write(str(unknwn_enc))
file.close()
# print(unknwn_enc)



'''DS 操作'''

# 读取csv已提取特征以便加密,当然这一步本不该DS做,简单起见放到一起了
DBfeatures = DS_Pai.read_csv()

# 加密并存入csv,同理,其实只有生成后的密文csv才是该服务器拥有的数据
DB_enc = [public_key.encrypt(m) for m in DBfeatures]
file = open('./DataServer/enc_feas_DB.csv','w') 
file.write(str(DB_enc))
file.close()
# print(DB_enc)

# 特征密文同态相减
mid = []
for i in range(0,128):
        mid[i] = unknwn_enc[i] - DB_enc[i]

# 密文相减结果写入csv并发送给AS(存入对应文件夹)      
file = open('./AuthServer/mid.csv','w') 
file.write(str(unknwn_enc))
file.close()


'''AS操作'''
dd = 0
for i in range(0,128):
        mid[i] = private_key.decrypt(mid[i])
        dd = dd + mid[i]*mid[i]

print(dd)