GAN增强网络安全

密码技术与我们息息相关,使用密码技术不仅仅能够保证信息的机密性,而且可以保证信息的完整性和可用性,防止信息被篡改、伪造和假冒。一直以来,设计和破解密码都是人类的专利,然而,随着人工智能的发展,Google Brain的研究成果《让神经对抗网络学习保护通信》(learning to Protect Communications with Adversarial Neural Cryptography), 试图让用0和1思考的机器学习对信息进行加密。

下面简要介绍一下对称加密算法:假设两个人要进行通信,定义为Alice和Bob,很自然,Alice和Bob想要私密的通信,可是有一个破坏者Eve想要窃取Alice和Bob之间的通信信息,所以Alice就把要发送的信息(我们称其为明文P)用秘钥K进行加密得到密文C,然后将密文C发送给Bob,Eve和Bob都能够接触到密文C,由于Bob手中有秘钥K,就可以将密文C恢复成明文P,也就是能够得到Alice发送的信息,然而Eve仅仅能够接触到密文,没有秘钥,所以就不能够得到明文P, 这就是对称加密算法。

对称加密系统

Alice,Bob,Eve三个都是神经网络,它们的参数分别为, 。我们向神经网络Alice中投入明文P和秘钥K数据,它的计算结果会作为密文C,与秘钥K一起交给另一个神经网络Bob,并优Bob进行解密得到。Eve接收到密文C, 试图去恢复明文P,得到。这三个神经网络模块共同构成了对抗神经网络的主体,Alice和Bob组成的网络看做GAN中的生成模型G, 而Eve则被看做GAN中的批判模型D,我们希望Eve恢复秘钥的概率为0.5,在这里是对等于恢复秘钥的位数为明文的1/2,即相当于瞎猜一样。

下面介绍一些网络的细节:

  • Alice和Bob有着相同的网络结构,但是输入,输出和参数不同。
  • P和K是由-1和1组成的比特串,是位于区间(-1,1)之间的浮点数,在最后计算准确率的时候,把中的浮点数转换成整数-1和1,大于等于0的为1,小于0的则为-1。
  • 每一个明文对应一个密文
Alice、Bob和Eve神经网络的输入和输出
网络模型输入输出
AliceP, K
BobC, K
EveC

损失函数

Eve目标是能够准确地从窃听到的密文C中恢复出明文P,也就是说要尽可能地缩小P和之间误差,选择使用L1范数作为Eve的损失函数,其中d就是指的是P和之间的L1范数值。

Alice和Bob的目标不仅仅使得能够 使得P和之间的误差比较小,而且还要能够安全准确地进行通信,Alice和Bob之间的损失函数为:

网络架构

首先一个全连接层,输入数量等于输出数量,全连接层的输入为明文P和秘钥K,全连接层后面跟着4个1-D的卷积层,每个卷积层的window size,input depth输入深度和output depth输出深度分别为[4, 1, 2], [2, 2, 4], [1, 4, 4]和[1, 4, 1],步长strides分别为1,2,1,1,这样,最后一层的向量的个数为明文长度。除了最后一个卷积层,其他层(全连接层+3个卷积层)的激活函数为sigmoid函数,最后一个卷积层的激活函数为tanh函数,是因为要使得的取值位于(-1,1)区间。下图是Alice神经网络的架构,由于Bob和Alice网络架构相似,不同的是Bob的输入为密文C和秘钥K。

由于Eve的输入仅仅只有秘钥K,所以网络架构和Alice和Bob的略微有些差别。需要在全连接层前面再多加上一个N*2N全连接层

结果

下面的训练结果取自明文和密文的长度都是16, minibatch的大小为4096。理想的结果应当时Bob恢复明文的错误比特数为0,Eve恢复明文的比特数为8。在这个例子中,训练刚开始,Bob和Eve的错误位数都是8, 对于一个16位的二进制文本来说,随便生成的16位数字在概率上错误位数就是8--这时候Bob和Eve都还没有具备解密的能力,伴随的神经网络之间的对抗,每个神经网络不断的调整参数值,Alice和Bob也逐渐获得了极强的加密和解密能力。 当迭代7000次的时候,Bob预测明文的错误率大幅度下滑,在15000次迭代之后,Bob恢复明文的错误率已经几乎为0,而这时Eve的错误位数仍然在8左右波动,也就是说Eve的破解密码的能力基本上等同于瞎猜,所以这时候Alice发出的信息非常安全 。

代码实现

import tensorflow as tf
import numpy as np
import Net
import os

plainTextLength = 16
keyLength = 16
N = plainTextLength / 2
batch = 4096
learningRate = 0.0008
TRAIN_STEP= 20000
iterations = 1



def get_random_block(N, batch):
    return 2 * np.random.randint(2, size=(batch, N)) - 1


def train():
    with tf.name_scope('input_variable'):
        plain = tf.placeholder(tf.float32, shape=[None, plainTextLength], name='plainText')
        key = tf.placeholder(tf.float32, shape=[None, keyLength], name='keyText')

    Zeros = tf.zeros_like(plain, dtype=tf.float32, name='zeroVector')

    #
    Alice_output, Bob_output, Eve_output = Net._build_Network(plain, key, plainTextLength, keyLength)
    reshape_Bob_output = tf.reshape(Bob_output, shape=[-1, plainTextLength])
    reshape_Eve_output = tf.reshape(Eve_output, shape=[-1, plainTextLength])
    # Bob L1 loss
    with tf.name_scope('Bob_loss'):
        Bob_loss = tf.reduce_mean(tf.abs(reshape_Bob_output - plain))
    tf.summary.scalar('Bob_loss_value', Bob_loss)
    # Eve L1 Loss
    with tf.name_scope('Eve_loss'):
        Eve_loss = tf.reduce_mean(tf.abs(reshape_Eve_output - plain))
    tf.summary.scalar('Eve_loss_value', Eve_loss)
    # Alice_Bob Loss
    with tf.name_scope('A_B_loss'):
        Alice_Bob_loss = Bob_loss + (1 - Eve_loss) ** 2
    tf.summary.scalar('Alice_Bob_loss_value', Alice_Bob_loss)

    # error
    boolean_P = tf.greater(plain, Zeros)
    boolean_B = tf.greater_equal(reshape_Bob_output, Zeros)
    boolean_E = tf.greater_equal(reshape_Eve_output, Zeros)
    accuracy_B = tf.reduce_mean(tf.cast(tf.equal(boolean_B, boolean_P), dtype=tf.float32))
    accuracy_E = tf.reduce_mean(tf.cast(tf.equal(boolean_E, boolean_P), dtype=tf.float32))
    Bob_bits_wrong = plainTextLength - accuracy_B * plainTextLength
    Eve_bits_wrong = plainTextLength - accuracy_E * plainTextLength
    tf.summary.scalar('accuracy_B_value', accuracy_B)
    tf.summary.scalar('accuracy_E_value', accuracy_E)
    tf.summary.scalar('Bob_bits_wrong', Bob_bits_wrong)
    tf.summary.scalar('Eve_bits_wrong', Eve_bits_wrong)

    A_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, 'Alice')
    B_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, 'Bob')
    AB_vars = A_vars + B_vars
    Eve_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, 'Eve')

    Alice_Bob_optimizer = tf.train.AdamOptimizer(learningRate).minimize(Alice_Bob_loss, var_list=AB_vars)
    Eve_optimizer = tf.train.AdamOptimizer(learningRate).minimize(Eve_loss, var_list=Eve_vars)

    merged = tf.summary.merge_all()

    with tf.Session() as session:
        session.run(tf.global_variables_initializer())
        train_writer = tf.summary.FileWriter('F:\\MachineLearning+DeepLearningCode\\adversarial_crypto\\adver_logs', session.graph)
        if not os.path.exists('adver_logs'):
            os.makedirs('adver_logs')
        for step in range(TRAIN_STEP):
            # train Bob
            feedDict = {plain: get_random_block(plainTextLength, batch),
                        key: get_random_block(keyLength, batch)}
            for index in range(iterations):
                _, Bob_error, Bob_accuracy, Bob_wrong_bits = session.run(
                    [Alice_Bob_optimizer, Bob_loss, accuracy_B, Bob_bits_wrong], feed_dict=feedDict)
            Bob_accuracy_bits = Bob_accuracy * plainTextLength
            # train Eve
            Eve_feedDict = {plain: get_random_block(plainTextLength, 2 * batch),
                            key: get_random_block(keyLength, 2 * batch)}
            for index in range(2 * iterations):
                session.run(Eve_optimizer, feed_dict=Eve_feedDict)
            Eve_error, Eve_accuracy, Eve_wrong_bits = session.run([Eve_loss, accuracy_E, Eve_bits_wrong], feed_dict=Eve_feedDict)
            Eve_accuracy_bits = Eve_accuracy * plainTextLength
            AB_error, summary = session.run([Alice_Bob_loss, merged], feed_dict=feedDict)
            '''
            if step % 500 == 0:
                print('Step:', step)
                print('Eve_error:', Eve_error, 'Eve accuracy bits', Eve_accuracy_bits, '  AB_error:', AB_error)
                print('Bob_loss:', Bob_error, '  Bob Accuracy Bits:', Bob_accuracy_bits)
            '''
            train_writer.add_summary(summary, step)

def main(argv=None):
    train()

if __name__ == '__main__':
    tf.app.run()
#Net.py
import tensorflow as tf

def _conv1D(input, filter, stride, kernelSize, name, activation = tf.nn.sigmoid):
    with tf.variable_scope(name):
        return tf.layers.conv1d(inputs=input, filters=filter, strides=stride,
                                   kernel_size=kernelSize, padding='SAME', activation=activation, use_bias=False)

def _ConvNet(input, unitsLength):
    """
    构建网络架构
    """
    input = tf.convert_to_tensor(input, dtype=tf.float32)
    input = tf.reshape(input, shape=[-1, unitsLength, 1])
    # print(input.shape)
    with tf.name_scope('convlayers'):
        conv1 = _conv1D(input, 2, 1, [4], name='conv_1')
        conv2 = _conv1D(conv1, 4, 2, [2], name='conv_2')
        conv3 = _conv1D(conv2, 4, 1, [1], name='conv_3')
        output = _conv1D(conv3, 1, 1, [1], name='conv_4', activation=tf.nn.tanh)
        return output

def _build_Network(plain, key, plainTextLength, keyLength):
    unitsLength = plainTextLength + keyLength
    # 定义Alice网络
    with tf.variable_scope('Alice'):
        Alice_input = tf.concat([plain, key], axis=1)
        A_w = tf.Variable(tf.truncated_normal(shape=[unitsLength, unitsLength], mean=0, stddev=0.1))
        Alice_FC_layer = tf.nn.sigmoid(tf.matmul(Alice_input, A_w))
        Alice_output = _ConvNet(Alice_FC_layer, unitsLength)
        # print(Alice_output.shape)

    reshape_Alice_output = tf.reshape(Alice_output, shape=[-1, plainTextLength])

    # 定义Bob网络
    with tf.variable_scope('Bob'):
        Bob_input = tf.concat([reshape_Alice_output, key], axis=1)
        B_w = tf.Variable(tf.truncated_normal(shape=[unitsLength, unitsLength], mean=0, stddev=0.1))
        Bob_FC_layer = tf.nn.sigmoid(tf.matmul(Bob_input, B_w))
        Bob_output = _ConvNet(Bob_FC_layer, unitsLength)

    # 定义Eve 网络
    with tf.variable_scope('Eve'):
        E_w_1 = tf.Variable(tf.truncated_normal(shape=[plainTextLength, unitsLength], mean=0, stddev=0.1))
        E_FC_layer1 = tf.nn.sigmoid(tf.matmul(reshape_Alice_output, E_w_1))
        E_w_2 = tf.Variable(tf.truncated_normal(shape=[unitsLength, unitsLength], mean=0, stddev=0.1))
        E_FC_layer2 = tf.nn.sigmoid(tf.matmul(E_FC_layer1, E_w_2))
        Eve_output = _ConvNet(E_FC_layer2, unitsLength)
    # print('Alice:', Alice_output.shape, ' Bob:', Bob_output.shape, ' Eve:', Eve_output.shape)
    return Alice_output, Bob_output, Eve_output

下面的两幅图明文和密文的长度为16,minibatch大小为4096时的结果,在tensorboard中显示,可以看出,Bob几乎能够正确地恢复出明文,Eve恢复明文P的错误位数稳定于7.6bits。

当明文长度取值32比特时,Eve恢复明文时的错误比特数大约稳定于15.3比特(理想应该是16bites),当明文长度取值64比特时,Eve恢复明文时的错误比特数大约为30比特(理想应该是32比特), 我给出的解释是,当输入长度增大时,也相当于数据结构变复杂,而此时的网络架构对于输入数据就会显得简单,处于‘欠拟合’状态。可是在 对称密码中,如果分组长度为16的话,过于短小,一般为128bits,所以可以适当增加网络复杂度。

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页