我在评论之后更新了问题,以使问题更加清晰。我正在尝试通过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;
}
答案 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();
}
}