Java字节数组转WAV文件 分块加解密报不支持流格式异常求助
问题描述
编辑补充:感谢大家!问题已解决,需逐块解密并保留原始文件格式。
对音频文件按16字节大小分块加密后,解密输出文件时抛出Stream of unsupported format异常,涉及byte array转wav文件操作,相关实现代码如下:
public class Main { public static void main(String[] args) throws InvalidKeyException, UnsupportedAudioFileException, IOException, LineUnavailableException { File decryptedFile = new File("dec.wav"); File soundFile = new File("C:\\Users\\Daniel\\Desktop\\FROG1\\peeper5sec.wav"); String k = "KEY"; byte[] key = k.getBytes(); Object keyKey=frog_Algorithm.makeKey(key); AudioInputStream st = AudioSystem.getAudioInputStream(soundFile); byte[][] fileInByte = split(st.readAllBytes(),16); if (fileInByte == null) fileInByte[0] = st.readAllBytes(); byte enc[]=null; ByteArrayOutputStream outputStream = new ByteArrayOutputStream( ); for (int i = 0; i < fileInByte.length; i++) { byte tmp3[]=frog_Algorithm.blockEncrypt(fileInByte[i], 0, keyKey); outputStream.write(tmp3); } enc=outputStream.toByteArray(); FileOutputStream fos=new FileOutputStream(decryptedFile.getAbsolutePath()); //fos.AudioSystem.write(frog_Algorithm.blockDecrypt(enc, 0,keyKey)); //fos.close(); byte[] dec=frog_Algorithm.blockDecrypt(enc, 0,keyKey); for (int i = 0; i < dec.length; i++) { fos.write(dec[i]); } ByteArrayInputStream bais = new ByteArrayInputStream(dec); AudioInputStream stream = AudioSystem.getAudioInputStream(bais); AudioSystem.write(stream, getAudioFileFormat(stream), decryptedFile);
问题原因&解决方法
抛出异常的核心原因有4个:
- 解密逻辑和加密逻辑不匹配:加密是按16字节逐块调用
blockEncrypt处理,但解密时直接对整个密文数组单次调用blockDecrypt,没有和加密一样逐块解密,得到的明文数据是损坏的。 - WAV文件格式信息丢失:调用
st.readAllBytes()只读取了音频的裸帧数据,没有保留原WAV文件的格式参数(采样率、位深、声道数、编码规则),直接把纯音频字节流包装成ByteArrayInputStream传给AudioSystem时,系统无法从裸数据里识别音频格式,自然抛出不支持格式的异常。 - 文件写入逻辑冲突:提前用
FileOutputStream往目标文件写了解密后的字节,后面又调用AudioSystem.write往同一个文件写内容,会导致文件内容覆盖、错乱,而且代码全程没有关闭流的操作,会触发资源泄漏。 - 边界逻辑bug:如果
split方法返回null,直接执行fileInByte[0]赋值会触发空指针;且第一次调用st.readAllBytes()后流已经读到末尾,第二次调用readAllBytes()读不到任何有效数据。
修正步骤
- 读取原文件时第一时间保存原音频的
AudioFormat和原始音频数据长度,解密后生成音频流时直接复用这些参数,不需要从裸字节流探测格式。 - 解密逻辑和加密逻辑完全对齐:把密文按16字节分块后逐块调用
blockDecrypt,再把所有解密后的块拼接成完整的明文数组;如果最后一个块不足16字节,要和加密阶段使用的填充规则保持一致,避免解密后出现多余无效字节。 - 去掉提前用
FileOutputStream写文件的冗余逻辑,所有流操作完成后及时关闭,避免资源泄漏和文件损坏。 - 删除存在空指针风险的null判断分支,读取音频数据时一次性读完,不要重复调用
readAllBytes()。
修正后的核心代码参考:
public class Main { public static void main(String[] args) throws InvalidKeyException, UnsupportedAudioFileException, IOException, LineUnavailableException { File decryptedFile = new File("dec.wav"); File soundFile = new File("C:\\Users\\Daniel\\Desktop\\FROG1\\peeper5sec.wav"); String k = "KEY"; byte[] key = k.getBytes(); Object keyKey = frog_Algorithm.makeKey(key); // 读取原文件时提前保存格式信息和原始数据 AudioInputStream originalStream = AudioSystem.getAudioInputStream(soundFile); AudioFormat originalFormat = originalStream.getFormat(); byte[] originalAudioData = originalStream.readAllBytes(); int originalDataLen = originalAudioData.length; originalStream.close(); // 分块加密 byte[][] fileInByte = split(originalAudioData, 16); ByteArrayOutputStream encOut = new ByteArrayOutputStream(); for (int i = 0; i < fileInByte.length; i++) { encOut.write(frog_Algorithm.blockEncrypt(fileInByte[i], 0, keyKey)); } byte[] encData = encOut.toByteArray(); // 逐块解密,和加密逻辑一一对应 byte[][] encBlocks = split(encData, 16); ByteArrayOutputStream decOut = new ByteArrayOutputStream(); for (int i = 0; i < encBlocks.length; i++) { decOut.write(frog_Algorithm.blockDecrypt(encBlocks[i], 0, keyKey)); } byte[] decData = decOut.toByteArray(); // 复用原音频格式构造流,直接输出WAV文件 ByteArrayInputStream bais = new ByteArrayInputStream(decData); AudioInputStream decStream = new AudioInputStream(bais, originalFormat, originalDataLen); AudioSystem.write(decStream, AudioFileFormat.Type.WAVE, decryptedFile); decStream.close(); }
注意:如果分块时最后一个数据块不足16字节,需要按照FROG算法要求的填充规则补全后再加密,否则解密后末尾会出现多余的无效字节,导致音频播放末尾有杂音。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

