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 | P, K | |
| Bob | C, K | |
| Eve | C |
損失函數
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 osplainTextLength = 16 keyLength = 16 N = plainTextLength / 2 batch = 4096 learningRate = 0.0008 TRAIN_STEP= 20000 iterations = 1def get_random_block(N, batch):return 2 * np.random.randint(2, size=(batch, N)) - 1def 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 losswith 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 Losswith 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 Losswith tf.name_scope('A_B_loss'):Alice_Bob_loss = Bob_loss + (1 - Eve_loss) ** 2tf.summary.scalar('Alice_Bob_loss_value', Alice_Bob_loss)# errorboolean_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 * plainTextLengthEve_bits_wrong = plainTextLength - accuracy_E * plainTextLengthtf.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_varsEve_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 BobfeedDict = {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 EveEve_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 * plainTextLengthAB_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 tfdef _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 outputdef _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,所以可以適當增加網絡復雜度。
總結
- 上一篇: XML 需要用的空间
- 下一篇: uniGUI 实操感受