通过套接字流加密的音频字节

时间:2014-05-10 21:48:21

标签: java aes audio-streaming

我在评论之后更新了问题,以使问题更加清晰。我正在尝试通过TCP编写加密语音呼叫的代码。当然,SSL是安全连接的选择之一,但刚才我正在研究TCP,就像任何其他项目一样。

该程序旨在捕获来自麦克风的音频,使用AES对其进行加密,然后将数据发送到服务器。在服务器端,接收到的数据将被解密并发送给扬声器。但是使用这些代码,我在运行时从客户端获得LineUnavailable Exception:

  

无法打开该行:javax.sound.sampled.LineUnavailableException:行格式为PCM_SIGNED 16000.0 Hz,8位,立体声,2字节/帧,不支持。

通常,没有加密,代码没有问题,而我对记录的数据使用BufferedOutputStream(s.getOutputStream())对象;并且声音通过网络成功传输,即我的硬件支持上述PCM格式。

另一方面,在一个简单的独立捕获/播放java模块中,我测试了加密代码,我已经设法在捕获和保存过程之间加密和解密音频数据,而它是一个byte []数据,就在它被保存到输出wav文件之前。加密过程本身似乎没有问题。

当我使用ByteArrayOutputStream来编写来自DataLine的音频数据而不是使用之前直接采用s.getOutputStream()方法的BufferedOutputStream对象时,网络问题出现了。这里使用ByteArrayOutputStream的原因是将捕获的字节作为输入参数传递给加密方法。值得注意的是,ByteArrayOutputStream运行良好,同时在没有套接字的情况下将音频字节保存到本地磁盘上的wav文件中。

现在的问题是,考虑到TCP网络,工作的OutputStream对象和等待加密的字节之间的分解。我最后的测试是在下面的代码中使用DataOutput / InputStream对象的失败。仍需要任何适当的输入/输出流方法的想法,以实现成功的通信,如果有的话。

捕获和发送数据的代码片段是:

public void run() {

    try {
        dos = new DataOutputStream(s.getOutputStream());// need the exact stream obj.
    } catch (IOException ex) {
        return;
    }

    AudioFormat format =new AudioFormat(16000,8,2,true,true);   
    DataLine.Info info = new DataLine.Info(TargetDataLine.class,format);   

    if (!AudioSystem.isLineSupported(info)) {
        System.err.println("Line matching " + info + " not supported.");// throws the exception
        return;
    }

    try {
        line = (TargetDataLine) AudioSystem.getLine(info);    
        line.open(format, line.getBufferSize());    
    } catch (LineUnavailableException ex) {
        System.err.println("Unable to open the line: " + ex);// related to exception
        return;
    }

    byte[] data = new byte[256];   
    int numBytesRead=0;    
    line.start();   

    // In the nonsecure call version, the audio data is written directly
    // to the BufferedOutputStream(s.getOutputStream()) and transmitted without problem
    ByteArrayOutputStream caps = new ByteArrayOutputStream(); //?

    while (thread != null) {
        numBytesRead = line.read(data, 0,128);  
        try {
            caps.write(data, 0, numBytesRead);   
        } catch (Exception ex) {
            System.err.println("Unable to read/write line data: " + ex);   
            break;    
        }    
    }   

    line.stop();    
    line.close();    
    line = null; 

    try {    
        caps.flush();    
        caps.close();    
    } catch (IOException ex) { ex.printStackTrace(); } 


    try {
        SecretKeySpec skeySpec = CryptUtil.getSecretKeySpec("password12345678","AES",128);
        byte[] encrypted = CryptUtil.encrypt(caps.toByteArray(), skeySpec);
        dos.writeInt(encrypted.length);
        dos.write(encrypted,0,encrypted.length);
    } catch (Exception ex) { }

}

接收和播放数据的代码片段是:

public void run() {

    AudioFormat format =new AudioFormat(16000,8,2,true,true);   

    try {
        dis = new DataInputStream(s.getInputStream());// need the exact stream obj.  
    } catch (Exception e) {
        System.err.println("Could not get InputStream: " + e);
    }


    try {
        int length = dis.readInt();                    
        byte[] message = new byte[length];
        dis.readFully(message); 

        SecretKeySpec skeySpec = CryptUtil.getSecretKeySpec("password12345678","AES",128);
        byte[] audioBytes = CryptUtil.decrypt(message, skeySpec);

        ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
        playStream = new AudioInputStream(bais, format, audioBytes.length / format.getFrameSize()); 
    } catch (Exception e) {
        System.err.println("Could not decrypt the stream: " + e);
    }

    DataLine.Info info = new DataLine.Info(SourceDataLine.class,format);   

    try {
        line = (SourceDataLine) AudioSystem.getLine(info);    
        line.open(format, bufSize);    
    } catch (LineUnavailableException ex) {
        System.err.println("Unable to open the line: " + ex);
        return;
    }

    byte[] data = new byte[256];   
    int numBytesRead = 0;    
    line.start();   

    while (thread != null) {
        try{
            numBytesRead = playStream.read(data);    
            line.write(data, 0,numBytesRead);    
        } catch (Exception e) {
            System.err.println("Error during playback: " + e);
            break;
        }
    }   

    if (thread != null) {
        line.drain();
    }   

    line.stop();
    line.close();
    line = null;
}

1 个答案:

答案 0 :(得分:0)

最好尝试使用更简单的方法,使用Encryptor4j在代码中利用流加密:https://github.com/martinwithaar/Encryptor4j

包装OutputStream以进行加密:

Encryptor encryptor = new Encryptor(secretKey, "AES/CTR/NoPadding", 16);

InputStream is = null;
OutputStream os = null;
try {
  is = new FileInputStream("original.jpg");
  os = encryptor.wrapOutputStream(new FileOutputStream("encrypted.jpg"));
  byte[] buffer = new byte[4096];
  int nRead;
  while((nRead = is.read(buffer)) != -1) {
    os.write(buffer, 0, nRead);
  }
  os.flush();
} finally {
  if(is != null) {
    is.close();
  }
  if(os != null) {
    os.close();
  }
}

用于解密的InputStream:

Encryptor encryptor = new Encryptor(secretKey, "AES/CTR/NoPadding", 16);

InputStream is = null;
OutputStream os = null;

try {
  is = encryptor.wrapInputStream(new FileInputStream("encrypted.jpg"));
  os = new FileOutputStream("decrypted.jpg");
  byte[] buffer = new byte[4096];
  int nRead;
  while((nRead = is.read(buffer)) != -1) {
    os.write(buffer, 0, nRead);
  }
  os.flush();
} finally {
  if(is != null) {
    is.close();
  }
  if(os != null) {
    os.close();
  }
}