2016-12-25 3 views
1

encode_text()関数は、LSBの符号化方式を実装しています。最初に記録されたメッセージの長さ、次にメッセージそのもの。強くすると、1ビットを変更するとWAVファイルが変更されます。ステガノグラフィ

numberOfBitsメッセージを書き込むために割り当てられたビット数。 1バイトまたは2つまたは3つのビットに書き込みます。

レコードの1ビットを使用してエンコーディングするこの方法は、音の変化を耳に感じるべきではありません。目の画像の変化だけでなく、しかし、そうではありません。なんらかの理由で、音の始めは"ノイズ"に変更されます。そうではありません。保存

読み取り()()あなたは、データファイルを読み込んで、それらを焼く場合はOK、何も変更はありません。

問題は何ですか?encode_text()機能です。あるいは私は何か悪いことをしたでしょうか?

import java.io.*; 
import java.util.Arrays; 

public class wavIO 
{ 

private String myPath; 
private long myChunkSize; 
private long mySubChunk1Size; 
private int myFormat; 
private long myChannels; 
private long mySampleRate; 
private long myByteRate; 
private int myBlockAlign; 
private int myBitsPerSample; 
private long myDataSize; 

public byte[] myData; 

public String getPath() 
{ 
    return myPath; 
} 
public void setPath(String newPath) 
{ 
    myPath = newPath; 
} 

public wavIO() 
    { 
    myPath = ""; 
    } 
public wavIO(String tmpPath) 
    { 
    myPath = tmpPath; 
    } 

// read a wav file into this class 
public boolean read() 
{ 
    DataInputStream inFile = null; 
    myData = null; 
    byte[] tmpLong = new byte[4]; 
    byte[] tmpInt = new byte[2]; 

    try 
    { 
     inFile = new DataInputStream(new FileInputStream(myPath)); 

     //System.out.println("Reading wav file...\n"); // for debugging only 

     String chunkID = "" + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte(); 

     inFile.read(tmpLong); // read the ChunkSize 
     myChunkSize = byteArrayToLong(tmpLong); 

     String format = "" + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte(); 

     // print what we've read so far 
     //System.out.println("chunkID:" + chunkID + " chunk1Size:" + myChunkSize + " format:" + format); // for debugging only 



     String subChunk1ID = "" + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte(); 

     inFile.read(tmpLong); // read the SubChunk1Size 
     mySubChunk1Size = byteArrayToLong(tmpLong); 

     inFile.read(tmpInt); // read the audio format. This should be 1 for PCM 
     myFormat = byteArrayToInt(tmpInt); 

     inFile.read(tmpInt); // read the # of channels (1 or 2) 
     myChannels = byteArrayToInt(tmpInt); 

     inFile.read(tmpLong); // read the samplerate 
     mySampleRate = byteArrayToLong(tmpLong); 

     inFile.read(tmpLong); // read the byterate 
     myByteRate = byteArrayToLong(tmpLong); 

     inFile.read(tmpInt); // read the blockalign 
     myBlockAlign = byteArrayToInt(tmpInt); 

     inFile.read(tmpInt); // read the bitspersample 
     myBitsPerSample = byteArrayToInt(tmpInt); 
     // print what we've read so far 
     //System.out.println("SubChunk1ID:" + subChunk1ID + " SubChunk1Size:" + mySubChunk1Size + " AudioFormat:" + myFormat + " Channels:" + myChannels + " SampleRate:" + mySampleRate); 


     // read the data chunk header - reading this IS necessary, because not all wav files will have the data chunk here - for now, we're just assuming that the data chunk is here 
     String dataChunkID = "" + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte() + (char)inFile.readByte(); 

     inFile.read(tmpLong); // read the size of the data 
     myDataSize = byteArrayToLong(tmpLong); 


     // read the data chunk 
     myData = new byte[(int)myDataSize]; 
     inFile.read(myData); 

     // close the input stream 
     inFile.close(); 

    } 
    catch(Exception e) 
    { 
     return false; 
    } 

    return true; // this should probably be something more descriptive 
} 

// write out the wav file 
public boolean save(String outputPath) 
{ 
    try 
    { 
     //DataOutputStream outFile = new DataOutputStream(new FileOutputStream(myPath)); 
     DataOutputStream outFile = new DataOutputStream(new FileOutputStream(outputPath)); 

     // write the wav file per the wav file format 
     outFile.writeBytes("RIFF");     // 00 - RIFF 
     outFile.write(intToByteArray((int)myChunkSize), 0, 4);  // 04 - how big is the rest of this file? 
     outFile.writeBytes("WAVE");     // 08 - WAVE 
     outFile.writeBytes("fmt ");     // 12 - fmt 
     outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4); // 16 - size of this chunk 
     outFile.write(shortToByteArray((short)myFormat), 0, 2);  // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation 
     outFile.write(shortToByteArray((short)myChannels), 0, 2); // 22 - mono or stereo? 1 or 2? (or 5 or ???) 
     outFile.write(intToByteArray((int)mySampleRate), 0, 4);  // 24 - samples per second (numbers per second) 
     outFile.write(intToByteArray((int)myByteRate), 0, 4);  // 28 - bytes per second 
     outFile.write(shortToByteArray((short)myBlockAlign), 0, 2); // 32 - # of bytes in one sample, for all channels 
     outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2); // 34 - how many bits in a sample(number)? usually 16 or 24 
     outFile.writeBytes("data");     // 36 - data 
     outFile.write(intToByteArray((int)myDataSize), 0, 4);  // 40 - how big is this data chunk 
     outFile.write(myData);      // 44 - the actual data itself - just a long string of numbers 
    } 
    catch(Exception e) 
    { 
     System.out.println(e.getMessage()); 
     return false; 
    } 

    return true; 
} 

// return a printable summary of the wav file 
public String getSummary() 
{ 
    //String newline = System.getProperty("line.separator"); 
    String newline = "<br>"; 
    String summary = "<html>Format: " + myFormat + newline + "Channels: " + myChannels + newline + "SampleRate: " + mySampleRate + newline + "ByteRate: " + myByteRate + newline + "BlockAlign: " + myBlockAlign + newline + "BitsPerSample: " + myBitsPerSample + newline + "DataSize: " + myDataSize + "</html>"; 
    return summary; 
} 


// =========================== 
// CONVERT BYTES TO JAVA TYPES 
// =========================== 

// these two routines convert a byte array to a unsigned short 
public static int byteArrayToInt(byte[] b) 
{ 
    int start = 0; 
    int low = b[start] & 0xff; 
    int high = b[start+1] & 0xff; 
    return (int)(high << 8 | low); 
} 


// these two routines convert a byte array to an unsigned integer 
public static long byteArrayToLong(byte[] b) 
{ 
    int start = 0; 
    int i = 0; 
    int len = 4; 
    int cnt = 0; 
    byte[] tmp = new byte[len]; 
    for (i = start; i < (start + len); i++) 
    { 
     tmp[cnt] = b[i]; 
     cnt++; 
    } 
    long accum = 0; 
    i = 0; 
    for (int shiftBy = 0; shiftBy < 32; shiftBy += 8) 
    { 
     accum |= ((long)(tmp[i] & 0xff)) << shiftBy; 
     i++; 
    } 
    return accum; 
} 


// =========================== 
// CONVERT JAVA TYPES TO BYTES 
// =========================== 
// returns a byte array of length 4 
private static byte[] intToByteArray(int i) 
{ 
    byte[] b = new byte[4]; 
    b[0] = (byte) (i & 0x00FF); 
    b[1] = (byte) ((i >> 8) & 0x000000FF); 
    b[2] = (byte) ((i >> 16) & 0x000000FF); 
    b[3] = (byte) ((i >> 24) & 0x000000FF); 
    return b; 
} 

// convert a short to a byte array 
public static byte[] shortToByteArray(short data) 
{ 
    return new byte[]{(byte)(data & 0xff),(byte)((data >>> 8) & 0xff)}; 
} 


public void encode(String text, int numberOfBits) 
{ 
    byte[] byteMessage = text.getBytes(); 
    byte[] messageLength = bit_conversion(byteMessage.length); 
    encodeText(messageLength, myData, 0, numberOfBits); 
    encodeText(byteMessage, myData, 32, numberOfBits); 
} 

private void encodeText(byte[] addition, byte[] byteDataInputWav, int offset, int numberOfBits) 
{ 
    if(addition.length + offset > byteDataInputWav.length) 
    { 
     System.out.println("File not long enough!"); 
    } 
    else 
    { 
     for(int i=0; i<addition.length; ++i) 
     { 
      int add = addition[i]; 
      for(int bit=7; bit>=0; --bit, ++offset) 
      { 
       int b = (add >>> bit) & 1; 
       byteDataInputWav[offset] = (byte)((byteDataInputWav[offset] & numberOfBits) | b); 
      } 
     } 
    } 
} 

private byte[] bit_conversion(int i) 
{ 
    byte byte3 = (byte)((i & 0xFF000000) >>> 24); 
    byte byte2 = (byte)((i & 0x00FF0000) >>> 16); 
    byte byte1 = (byte)((i & 0x0000FF00) >>> 8); 
byte byte0 = (byte)((i & 0x000000FF)  ); 
return(new byte[]{byte3,byte2,byte1,byte0}); 
} 

public String decode(String inputPath) 
{ 
    byte[] byteDataOutputWav = myData; 
    int length = 0; 
int offset2 = 32; 
for(int i=0; i<32; ++i) 
{ 
    length = (length << 1) | (byteDataOutputWav[i] & 1); 
} 
byte[] result = new byte[length]; 
for(int b=0; b<result.length; ++b) 
{ 
     for(int i=0; i<8; ++i, ++offset2) 
     { 
      result[b] = (byte)((result[b] << 1) | (byteDataOutputWav[offset2] & 1)); 
     } 
} 
    return new String(result); 
} 


} 

答えて

0

すべてのバイトの最下位ビットを変更しています。したがって、1つのサンプルがサウンドファイルに何ビット含まれているかにかかわらず、フルスケールの~48dBのノイズしか導入されません。これは明らかに聞こえませんが、私はあなたが「音の始まりで」という意味であると思います。

おそらく通常の16ビットの最下位ビットのみを変更することで、〜96dBのノイズがフルスケールになります。

16ビットサンプルのLSBのみを変更した場合、ノイズは非常に柔らかくなります。しかし、大音量の音質の良い機器では、サウンドファイルの静かな部分で普通の人が聴こえることは、まだ知覚できることに注意してください。また、オーディオエディタなどでサウンドファイルを見ている人にとっては、かなりわかりやすいでしょう。効果的なステガノグラフィでは、少なくとも時間に依存するサウンドレベルにコーディングする必要があります。

関連する問題