当前智能手机功能越来越强大,但由此带来的安全性和通信隐私性问题也日渐显露。随着近年来手机窃听事件频发,用户语音通信的机密性需求日益提升。因此,本文设计并实现了一套机制,使得通信双方在不可信的互联网网络环境下能够进行安全的即时语音通信。本文所述的系统由五个部分构成:
(1)输入AES密钥。用户在屏幕输入保密通信所需要的AES密钥,在后续的语音通信中,AES密钥将用于加密语音通信信息。
(2)发起通信请求。某一个通信方A对另一通信方B发起通信请求,如果B同意进行通信,则接受对方请求。
(3)确定AES密钥。通信接收方B在收到通信A方的请求后,输入AES密钥,点击接受后开启密钥确定线程。通信双方所输AES密钥相同时通信连接建立成功,否则失败。
(4)通信双方数据的加解密。
(5)传输。
以下是该系统的详细设计过程
1.输入AES密钥
通信双方在建立连接之前,通信请求方在界面上输入AES密钥,发送给通信接收方,同时开启语音通信线程。主要代码如下:
privatevoidopenFriendPopup(finalStringname,finalintphoto,intflag){ Viewview=LayoutInflater.from(this).inflate( R.layout.aesput,null); Buttonsendase=(Button)view .findViewById(R.id.sendase); finalAlertDialogalertDialog=newAlertDialog.Builder(this).setView( view).create(); sendase.setOnClickListener(newView.OnClickListener(){ publicvoidonClick(Viewv){ Key_Deal.setFlag(Key_Deal.VOICE_FLAG); MainHandler.SendRequestForCall(name); MainHandler.startVoiceActivity(name,photo); alertDialog.dismiss(); } }); if(flag==0){ sendase.setEnabled(false); } alertDialog.show(); }
输入AES密钥的实现过程中,通信请求方在弹出窗口中输入AES密钥,点击发送语音按钮,通过主线程的MainHandler实例向好友发送语音请求,并使用startVoiceActivity()开启语音通信线程。
2.发起通信请求
通信请求方发起通信请求,通信接收方在接收到请求方的语音邀请时,主动输入AES密钥,点击接受,并开启语音通信线程,同时将请求方的密钥与自己主动输入的密钥进行比较。主要代码如下:
privatevoidinitClick(){ accept.setOnClickListener(newView.OnClickListener(){ publicvoidonClick(Viewv){ if(flag==Key_Deal.VOICE_FLA.equals(getaes())){ startVoiceActivity(); Key_Deal.setFlag(Key_Deal.VOICE_FLAG); Voice_Info.setIP(IP); Key_Info.setIP(IP); } } });
发起通信请求的实现过程中,使用startVoiceActivity()开启语音通信线程,同时设置IP,为后续语音信息的发送提供IP参数。
3.确定AES密钥
publicstaticvoidstartKeyInit(){ byte[]publicKey=MyKey.getPublicKey(); byte[]s_c=MyKey.getS_c(); Key_Infokey_Info=newKey_Info(); byte[]head=newbyte[]{0x00}; key_Info.setHead(head); key_Info.setPublicKey(publicKey); key_Info.setS_c(s_c); Key_Thread.send(key_Info); }
以上代码是开始密钥确定线程过程。密钥确定过程首先获取通信方的公钥和s_c验证,并设置为key_Info中的公钥和s_c验证,最后发送出去。
publicstaticvoidsendPartOfAesOne(){ ase=FriendList_Activity.getaes(); byte[]byase1=MyKey.parseHexStr2Byte(ase); MyKey.setAesPassword1(byase1); MyKey.setAesKey(byase1); Key_Infokey_Info=newKey_Info(); byte[]head=newbyte[]{0x02}; key_Info.setHead(head); key_Info.setPartOfPassword(byase1); Key_Thread.send(key_Info); }
以上代码是获取发送邀请方AES。取出界面编辑框中的AES密钥并将其转化为二进制存入二进制数组中,通过MyKey实例将获取的AES密钥设置为AesPassword1,将获取的AES密钥存入key_Info并发送出去。
publicstaticvoidsendPartOfAesTwo(){ ase=BeCalled_Activity.getaes(); byte[]byase2=MyKey.parseHexStr2Byte(ase); MyKey.setAesPassword2(byase2); Key_Infokey_Info=newKey_Info(); byte[]head=newbyte[]{0x03}; key_Info.setHead(head); key_Info.setPartOfPassword(byase2); Key_Thread.send(key_Info); }
以上代码是发送接收方获取AES过程。基本实现过程与获取发送邀请方AES过程一致。
publicstaticvoidinitAESKey(){ if(aesPassword1.length==0aesPassword2.length==0) return; aes1 = parseByte2HexStr(aesPassword1); aes2=parseByte2HexStr(aesPassword2); if(aes1.equals(aes2)){ aesKey=parseHexStr2Byte(aes1); } }
以上代码是通信双方的密钥的比较过程。通信请求方将发送的密钥保存并设置为aesPassword1,通信接收方将发送的密钥保存并设置为aesPassword2,然后将两者通信密钥从二进制转化为十六进制并进行比较,两者相同则设置为最终双方的通信密钥。
系统设计中的确定AES密钥过程是整个系统的核心部分,该部分包括开始密钥确定线程、获取发送邀请方AES、获取发送接收方AES、比较两个AES并确定通信AES四个过程。
通信连接成功如图3所示的语音通信界面。
图3语音通信
4.通信双方数据的加解密
publicstaticbyte[]AESencrypt(byte[]byteContent){ if(aesKey==null) returnnull; try{ SecretKeySpeckey=newSecretKeySpec(aesKey,AES); Ciphercipher=Cipher.getInstance(; cipher.init(Cipher.ENCRYPT_MODE,key); byte[]result=cipher.doFinal(byteContent); returnresult; }catch(NoSuchAlgorithmExceptione){ e.printStackTrace(); }catch(NoSuchPaddingExceptione){ e.printStackTrace(); }catch(InvalidKeyExceptione){ e.printStackTrace(); }catch(IllegalBlockSizeExceptione){ e.printStackTrace(); }catch(BadPaddingExceptione){ e.printStackTrace(); } returnnull; }
以上代码是数据加密过程。首先创建密码器,接着以加密模式初始化,然后对将要发送出去的语音数据流内容进行加密。
publicstaticbyte[]AESdecrypt(byte[]content){ if(aesKey==null) returnnull; try{ byte[]enCodeFormat=aesKey; SecretKeySpeckey=newSecretKeySpec(enCodeFormat,); Ciphercipher=Cipher.getInstance(AES); cipher.init(Cipher.DECRYPT_MODE,key); byte[]result=cipher.doFinal(content); returnresult; }catch(NoSuchAlgorithmExceptione){ e.printStackTrace(); }catch(NoSuchPaddingExceptione){ e.printStackTrace(); }catch(InvalidKeyExceptione){ e.printStackTrace(); }catch(IllegalBlockSizeExceptione){ e.printStackTrace(); }catch(BadPaddingExceptione){ e.printStackTrace(); } returnnull; }
以上代码是数据的解密过程。首先创建密码器,接着以解密模式初始化,然后对接收到的语音数据流内容进行解密。通信双方的数据传输都需要加密过程,接收到的数据都需要解密过程。
5.传输
classSendRunnableimplementsRunnable{ publicvoidrun(){ try{ System.out.println(Voice:StartSendThread!); Voice_InfovoiceInfo=null; datagramSocket=newDatagramSocket(Voice_Constant.SEND_PORT); while(runing){ if(Voice_Buffer.SendBuffereIsEmpty()){ Thread.sleep(50); continue; } voiceInfo=Voice_Buffer.getSendInfo(); if(voiceInfo==null) continue; inetAddress=InetAddress.getByName(voiceInfo.getIP()); byte[]data=voiceInfo.getBytes(); datagramPacket=newDatagramPacket(data,data.length, inetAddress,Voice_Constant.RECEIVE_PORT); if(datagramSocket!=null) datagramSocket.send(datagramPacket); } }catch(Exceptione){ e.printStackTrace(); }finally{ if(datagramSocket!=null) datagramSocket.close(); datagramSocket=null; datagramPacket=null; inetAddress=null; System.out.println(Voice:StopSendThread!); } } }
语音的传输过程采用UDP协议,保证双方能够快速传输数据。首先将要传输的数据(已加密)保存到Buffer,再取出Buffer内的数据将其转化为二进制存储在二进制数组data里,以data和一些参数实例化datagramPacket,最后通过套接字发送datagramPacket以达到数据传输的效果。
通过以上的五个主要步骤,能够有效地保证通信双方语音的安全性。
本文所述系统综合运用密码学(加解密)、计算机(Android平台开发)和网络通信(Wi-Fi通信等)等理论与技术,设计并实现了一种在公开网络环境下的安全语音通信系统。该系统在每次通话之前通信双方均需手动输入通信的AES密钥,并透明地比较通信双方所输AES密钥确定最终的通信密钥;密钥确定完成之后,系统自动、透明地利用确定的AES密钥对用户语音信息进行实时加密保护,保证了用户通信过程的私密性。本文所述系统研发过程中,充分考虑了研究热点和发展趋势,选取目前在国内外移动互联市场占有率最高的Android移动智能终端为平台进行开发,并针对目前国家高度重视的保密问题展开研究,具有良好的应用价值和市场前景。
(完)