LAMPIRAN A: LISTING PROGRAM unit uMP3; interface uses SysUtils, Windows, Messages, Classes; //mp3 header frame type TRawMP3Header = record AudioVersion, LayerIdx, Protection, BitrateIdx, SamplingRateIdx, Padding, PrivateBit, ChannelMode, ModeExt, Copyright, Original, Emphasis: Integer; end; //array untuk frame header MP3 type TMP3HeaderArray = array[0..3] of byte; //Tabel bitrate (bps) const bmpeg1: array[1..14, 1..3] of Word = ( (32, 32, 32), (40, 48, 64), (48, 56, 96), (56, 64, 128), (64, 80, 160), (80, 96, 192), (96, 112, 224), (112, 128, 256), (128, 160, 288), (160, 192, 320), (192, 224, 352), (224, 256, 384), (256, 320, 416), (320, 384, 448)); //Tabel Sampling Rate (Hz) const samplingRate: array[0..3] of integer = ( 44100, 48000, 32000, 0); //Tabel sampling per frame const samplingPerFrame: array[1..3] of Integer = ( 1152, 1152, 384); function FindFirstHeader(filename: string): Integer; function FindNextFrame(filename: string; prevHeaderPos: Integer; prevHeader: TMP3HeaderArray): Integer; function getMP3Header(filename: string; pos: Integer): TMP3HeaderArray; function frameSize(headerArray: TMP3HeaderArray): Integer; function isAvailableToSteg(filename: string; framePos: Integer; length: Integer): Boolean; function isStegged(filename: string; framePos: Integer): Boolean; function FrameCount(filename: string): Integer; function FrameAvailableToStegCount(filename: string; length: Integer): Integer;

Universitas Sumatera Utara

function MaxStegSize(filename: string; length: Integer): Integer; function FileSize(FileName : String) : Int64; function HideFile(mp3File:string; hiddenFile: string; resultFile: string; length: Integer): Integer; function RevealFile(mp3File:string): string; procedure Split(const Delimiter: Char; Input: string; const Strings: TStrings); function LeftPad(S: string; Ch: Char; Len: Integer): string; implementation //function untuk mendapatkan lokasi frame pertama function FindFirstHeader(filename: string): Integer; var filemp3: File; headerArray: array[0..3] of byte; count, pos: Integer; begin Result:=-1; if FileExists(filename) then begin AssignFile(filemp3, filename); FileMode:=fmOpenRead; Reset(filemp3,1); //looping sampai dapat header file pos:=0; while not eof(filemp3) do begin seek(filemp3, pos); BlockRead(filemp3, headerArray, 4, count); if ((headerArray[0]=$FF) and ((headerArray[1]=$FB) or (headerArray[1]=$FA))) then begin Result:=pos; break; end else begin pos:=pos+1; end; end; CloseFile(filemp3); end else begin exit; end; end; //function untuk mendapatkan frame selanjutnya function FindNextFrame(filename: string; prevHeaderPos: Integer; prevHeader: TMP3HeaderArray): Integer; var filemp3: File; count: Integer; posNow: Integer; headArray: TMP3HeaderArray; begin if FileExists(filename) then begin AssignFile(filemp3, filename);

Universitas Sumatera Utara

FileMode:=fmOpenRead; Reset(filemp3, 1); posNow:=prevHeaderPos+FrameSize(prevHeader); while not eof(filemp3) do begin seek(filemp3, posNow); BlockRead(filemp3, headArray, 4, count); if ((headArray[0]=$FF) and ((headArray[1] and $E0)=$E0) and ((headArray[2] and $F0)$F0)) then begin Result:=posNow; break; end else begin posNow:=posNow+1; end; end; CloseFile(filemp3); end else begin exit; end; end; //function untuk parsing mp3 header procedure ParseHeaderArray(headerArray: TMP3HeaderArray; var RawHeader: TRawMP3Header); begin RawHeader.AudioVersion:=(headerArray[1] shr 3) and $3; RawHeader.LayerIdx:=(headerArray[1] shr 1) and $3; RawHeader.Protection:=(headerArray[1] and $1); RawHeader.BitrateIdx:=(headerArray[2] shr 4) and $F; RawHeader.SamplingRateIdx:=(headerArray[2] shr 2) and $3; RawHeader.Padding:=(headerArray[2] shr 1) and $1; RawHeader.PrivateBit:=(headerArray[2] and 1); RawHeader.ChannelMode:=(headerArray[3] shr 6) and $3; RawHeader.ModeExt:=(headerArray[2] shr 4) and $3; RawHeader.Copyright:=(headerArray[2] shr 3) and $1; RawHeader.Original:=(headerArray[2] shr 2) and $1; RawHeader.Emphasis:=(headerArray[2] and 1); end; //function untuk mendapatkan mp3 header dari current pos function getMP3Header(filename: string; pos: Integer): TMP3HeaderArray; var filemp3: File; headerArray: TMP3HeaderArray; count: integer; begin if FileExists(filename) then begin AssignFile(filemp3, filename); FileMode:=fmOpenRead; Reset(filemp3,1); seek(filemp3, pos); BlockRead(filemp3, headerArray, 4, count); Result:=headerArray; CloseFile(filemp3);

Universitas Sumatera Utara

end else begin exit; end; end; //function untuk mengetahui ukuran frame function frameSize(headerArray: TMP3HeaderArray): Integer; var myRawMP3Header: TRawMP3Header; begin ParseHeaderArray(headerArray, myRawMP3Header); Result:=trunc(samplingPerFrame[myRawMP3Header.LayerIdx]/ 8 * bmpeg1[myRawMP3Header.BitrateIdx][myRawMP3Header.LayerIdx] * 1000 / samplingRate[myRawMP3Header.SamplingRateIdx] + myRawMP3Header.Padding); end;

//function untuk mengecek apakah sebuah frame mengandung pesan rahsia function isStegged(filename: string; framePos: Integer): Boolean; var filemp3: File; pos, n, count: Integer; buf: array[0..254] of Char; begin Result:=False; if FileExists(filename) then begin AssignFile(filemp3, filename); FileMode:=fmOpenRead; Reset(filemp3,1); pos:=framePos; seek(filemp3, pos+36); BlockRead(filemp3, buf, 4, count); for n := 0 to 4 do begin if (buf[n] + buf[n + 1] + buf[n + 2] + buf[n + 3] = 'STEG') then begin Result := true; CloseFile(filemp3); Exit; end end; CloseFile(filemp3); end else begin exit; end; end; //function untuk memeriksa apakah sebuah frame dapat digunakan sebagai penampung pesan function isAvailableToSteg(filename: string; framePos: Integer; length: Integer): Boolean; var pos, i : Integer; buf: array[0..254] of byte; available: Boolean;

Universitas Sumatera Utara

filemp3lagi: TFileStream; begin available:=False; Result:=available; if FileExists(filename) then begin filemp3lagi:=TfileStream.Create(filename, fmOpenRead or fmShareDenyNone); pos:=framePos; filemp3lagi.seek(pos, soFromBeginning); filemp3lagi.Read(buf, length); for i := 0 to length-2 do begin if (buf[i]=buf[i+1]) then begin available:=True; end else begin available:=False; Result:=available; filemp3lagi.Free; exit; end; end; Result:=available; filemp3lagi.Free; end else begin exit; end; end; //function untuk menghitung jumlah frame function FrameCount(filename: string): Integer; var pos, posNext, count: Integer; frameHeader: TMP3HeaderArray; begin pos:=FindFirstHeader(filename); frameHeader:=getMP3Header(filename, pos); count:=0; posNext:=pos; while posNext-1 do begin count:=count+1; posNext:=FindNextFrame(filename, posNext, frameHeader); if posNext-1 then frameHeader:=getMP3Header(filename, posNext); end; Result := count; end; //function untuk menghitung jumlah frame yang dapat dijadikan media steganografi function FrameAvailableToStegCount(filename: string; length: Integer): Integer; var pos, posNext, count: Integer; frameHeader: TMP3HeaderArray; begin

Universitas Sumatera Utara

pos:=FindFirstHeader(filename); frameHeader:=getMP3Header(filename, pos); count:=0; posNext:=pos; while posNext-1 do begin if (isAvailableToSteg(filename, posNext+36, length)) then begin count:=count+1; end; posNext:=FindNextFrame(filename, posNext, frameHeader); if posNext-1 then frameHeader:=getMP3Header(filename, posNext); end; Result := count-1; end; //function untuk mendapatkan maximum steg data dalam sebuah MP3 function MaxStegSize(filename: string; length: Integer): Integer; var posmp3, posmp3old, n, posNext: Integer; firsttime, available: Boolean; begin firsttime:= True; posmp3:=FindFirstHeader(filename); posmp3old:=posmp3; posNext:=FindNextFrame(filename, posmp3, getMP3Header(filename, posmp3)); n:=0; posmp3:=posmp3+40; //loop sampai semua pesan rahasia dibaca while (posNext-1) do begin if (firsttime) then begin if (isAvailableToSteg(filename,posmp3old+36,length)) then begin posmp3:=posNext+40; posmp3old:=posNext; posNext:=FindNextFrame(filename, posmp3old, getMP3Header (filename,posmp3old)); firsttime:=False; end else begin posmp3old:=posNext; posNext:=FindNextFrame(filename, posmp3old, getMP3Header (filename,posmp3old)); posmp3:=posmp3old+40; end; end; available:=isAvailableToSteg(filename,posmp3old+36,length); if ((available) AND (not firsttime)) then begin posmp3:=posmp3+1; n:=n+1; end else if ((not available) AND (not firsttime)) then begin posmp3:=posNext;

Universitas Sumatera Utara

end; if ((posmp3>=posNext) AND (not firsttime) AND (posNext-1)) then begin posmp3old:=posNext; posNext:=FindNextFrame(filename, posmp3old, getMP3Header (filename,posmp3old)); posmp3:=posmp3old+40; end; end; Result:=n; end;

//funnction untuk menyisipkan pesan dalam MP3 function HideFile(mp3File:string; hiddenFile: string; resultFile: string; length: Integer): Integer; var posmp3, poshidden, posmp3old, n, m, posNext, len, i: Integer; buff1: byte; firsttime, available: Boolean; key: string; streamHidden, streamHasil: TFileStream; begin Result:=-1; firsttime:= True; if (FileSize(hiddenFile)>MaxStegSize(mp3File, length)) then begin exit; end; CopyFile(PAnsiChar(mp3file), PAnsiChar(resultFile), False); //berikan penanda berupa panjang pesan dan ekstensi key:=inttostr(FileSize(hiddenFile))+'#'+LeftPad(extractFileExt( hiddenFile), ' ', 5); len:=strlen(PAnsiChar(key)); //membuka file hasil streamHasil:=TFileStream.Create(resultFile, fmOpenReadWrite or fmShareDenyNone); posmp3:=FindFirstHeader(resultFile); posmp3old:=posmp3; posNext:=FindNextFrame(resultFile, posmp3, getMP3Header(resultFile, posmp3)); streamHasil.Seek(posmp3, soFromBeginning); //membuka file yang akan disisipkan streamHidden:=TfileStream.Create(hiddenFile, fmOpenRead or fmShareDenyNone); poshidden:=0; streamHidden.Seek(poshidden, soFromBeginning); n:=0; posmp3:=posmp3+40; m:=streamHidden.Size; //loop sampai seluruh data dibaca while ((n=posNext) AND (not firsttime) AND (posNext-1)) then begin posmp3old:=posNext; posNext:=FindNextFrame(resultFile, posmp3old, getMP3Header (resultFile, posmp3old)); posmp3:=posmp3old+40; end; end; streamHasil.Free; streamHidden.Free; Result:=n; end;

Universitas Sumatera Utara

//function untuk mendapatkan hidden file function RevealFile(mp3File:string): string; var filemp3: File; posmp3, posmp3old, n, count, posNext: Integer; buff1: byte; firsttime:Boolean; res: string; remaining, len: Integer; A: TStringList; resultExt: string; streamHasil: TFileStream; begin Result:='None'; firsttime:=True; res:=''; remaining:=255; A := TStringList.Create; //Buka file mp3 AssignFile(filemp3, mp3File); FileMode:=fmOpenRead; Reset(filemp3,1); posmp3:=FindFirstHeader(mp3File); posmp3old:=posmp3; posNext:=FindNextFrame(mp3File, posmp3, getMP3Header(mp3File, posmp3)); seek(filemp3, posmp3); //Mengetahui ukuran dan ekstensi file hasil steganografi posmp3:=posmp3+40; while (firsttime) do begin if (isStegged(mp3File,posmp3old)) then begin seek(filemp3, posmp3); BlockRead(filemp3, buff1, 1, count); res:=res+Char(buff1); if (buff1=ord('.')) then begin remaining:=4; end; remaining:=remaining-1; if (remaining=posNext) then begin posmp3old:=posNext; posNext:=FindNextFrame(mp3File, posmp3old, getMP3Header (mp3File,posmp3old));

Universitas Sumatera Utara

posmp3:=posmp3old+40; end; end; Split('#', res, A); len:=strtoint(A[0]); resultExt:=trim(A[1]); streamHasil:=TFileStream.Create(mp3File+resultExt, fmCreate or fmShareDenyNone); posmp3:=posNext; posmp3old:=posmp3; posNext:=FindNextFrame(mp3File, posmp3, getMP3Header(mp3File, posmp3)); n:=0; posmp3:=posmp3+40; while (n=posNext) then begin posmp3old:=posNext; posNext:=FindNextFrame(mp3File, posmp3old, getMP3Header (mp3File,posmp3old)); posmp3:=posmp3old+40; end; end; streamHasil.Free; CloseFile(filemp3); Result:=mp3File+resultExt; end; // mengembalikan ukuran sebenarnya dari sebuah file. Return zero jika file tidak ditemukan function FileSize(FileName : String) : Int64; var SearchRec : TSearchRec; begin if FindFirst(FileName, faAnyFile, SearchRec ) = 0 then Result := Int64(SearchRec.FindData.nFileSizeHigh) shl Int64(32) + Int64(SearchREc.FindData.nFileSizeLow) else Result := 0; end; //split string

Universitas Sumatera Utara

procedure Split(const Delimiter: Char; Input: string; const Strings: TStrings); begin Assert(Assigned(Strings)); Strings.Clear; Strings.Delimiter := Delimiter; Strings.DelimitedText := Input; end;

//pad string (left) function LeftPad(S: string; Ch: Char; Len: Integer): string; var RestLen: Integer; begin Result := S; RestLen := Len - Length(s); if RestLen < 1 then Exit; Result := S + StringOfChar(Ch, RestLen); end; end.

//function untuk kompresi dan enkripsi pesan rahasia function TfrmMain.encryptAndCompress(filename: string; password: string): Boolean; var SourceCrypt, DestCrypt, InputStream, OutputStream: TFileStream; CompressionStream: TZCompressionStream; begin Result:=False; //Proses Kompresi try InputStream := TFileStream.Create(filename, fmOpenRead or fmShareDenyNone); OutputStream := TFileStream.Create('tmpCrypt.tmp.zip', fmCreate); CompressionStream := TZCompressionStream.Create(OutputStream, zcMax); CompressionStream.CopyFrom(InputStream, InputStream.Size); CompressionStream.Free; //Result:=True; OutputStream.Free; InputStream.Free; except MessageDlg('File IO error',mtError,[mbOK],0); end; //Proses Enkripsi try SourceCrypt:= TFileStream.Create('tmpCrypt.tmp.zip',fmOpenRead or fmShareDenyNone); DestCrypt:= TFileStream.Create('tmpCrypt.tmp'+ExtractFileExt (filename),fmCreate); DCP_rijndael1.InitStr(password,TDCP_sha1); DCP_rijndael1.EncryptStream(SourceCrypt,DestCrypt,SourceCrypt.Size); // Proses meng-encrypt pesan rahasia DCP_rijndael1.Burn; Result:=True;

Universitas Sumatera Utara

DestCrypt.Free; SourceCrypt.Free; except MessageDlg('File IO error',mtError,[mbOK],0); end; DeleteFile('tmpCrypt.tmp.zip'); end; //function untuk memeriksa ukuran file setelah dikompresi dan dienkripsi function TfrmMain.checkSizeAfter(filename: string; password: string): Integer; var SourceCrypt, DestCrypt, InputStream, OutputStream: TFileStream; CompressionStream: TZCompressionStream; begin //kompresi try InputStream := TFileStream.Create(filename, fmOpenRead or fmShareDenyNone); OutputStream := TFileStream.Create('tmpCrypt.tmp.zip', fmCreate); CompressionStream := TZCompressionStream.Create(OutputStream, zcMax); CompressionStream.CopyFrom(InputStream, InputStream.Size); CompressionStream.Free; OutputStream.Free; InputStream.Free; except MessageDlg('File IO error',mtError,[mbOK],0); end; //enkripsi try SourceCrypt:= TFileStream.Create('tmpCrypt.tmp.zip',fmOpenRead or fmShareDenyNone); DestCrypt:= TFileStream.Create('tmpCrypt.tmp',fmCreate); DCP_rijndael1.InitStr(password,TDCP_sha1); DCP_rijndael1.EncryptStream(SourceCrypt,DestCrypt,SourceCrypt.Size); DCP_rijndael1.Burn; Result:=DestCrypt.Size; DestCrypt.Free; SourceCrypt.Free; except MessageDlg('File IO error',mtError,[mbOK],0); end; DeleteFile('tmpCrypt.tmp'); DeleteFile('tmpCrypt.tmp.zip'); end;

procedure TfrmMain.btnSisipClick(Sender: TObject); var n: Integer; begin if ((txtPassword.Text='') or (txtPassword2.Text='')) then begin messageDlg('Masukkan Kunci!!', mtError, [mbOK], 0); exit;

Universitas Sumatera Utara

end; if (txtPassword.TexttxtPassword2.Text) then begin messageDlg('Kedua Kunci tidak sesuai! Periksa kembali!!!', mtError, [mbOK], 0); exit; end; if (not FileExists(txtFilename.Text)) or (not FileExists (txtHiddenFile.Text)) then begin messageDlg('Masukkan File MP3 dan Pesan Rahasia', mtError, [mbOK], 0); exit; end; stegFileResult:= extractFilePath(txtFilename.Text) + 'RSteg-'+ extractFileName(txtFilename.Text) ; txtStegFileResult.Text:=stegFileResult; if (encryptAndCompress(txtHiddenFile.Text, txtPassword.Text)) then begin n:=HideFile(txtFilename.Text, 'tmpCrypt.tmp'+ExtractFileExt (txtHiddenFile.Text), stegFileResult, 20); if (n>-1) then begin messageDlg('Penyisipan Pesan Berhasil!'+#13+'File hasil steganografi adalah '+stegFileResult+#13+'Jumlah Byte yang disisipkan adalah '+inttostr(n), mtInformation, [mbOK], 0); end else begin messageDlg('Penyisipan Gagal! Ukuran pesan melebihi kapasitas maximal MP3', mtError, [mbOK], 0); end; end else begin messageDlg('Proses Kompresi dan Enkripsi Gagal!', mtError,[mbOK],0); end; end; procedure TfrmMain.btnMaxMP3Click(Sender: TObject); var max: Integer; begin if FileExists(txtFilename.Text) then begin max:=MaxStegSize(txtFilename.Text, 20); messageDlg('Kapasitas Maksimal MP3 adalah '+inttostr(max), mtInformation, [mbOK], 0); btnMaxMP3.Caption:='Kapasitas Max MP3 = '+inttostr(max); end else begin messageDlg('File tidak dapat ditemukan ', mtError, [ mbOK], 0); end; end;

procedure TfrmMain.btnCipherSizeClick(Sender: TObject);

Universitas Sumatera Utara

var sizeAfter: Integer; begin if (txtPassword.Text='') then begin messageDlg('Masukkan Kunci!!!', mtError, [ mbOK], 0); exit; end; if (not FileExists(txtHiddenFile.Text)) then begin messageDlg('File tidak ditemukan ', mtError, [ mbOK], 0); exit; end; sizeAfter:=checkSizeAfter(txtHiddenFile.Text, txtPassword.Text); messageDlg('Jumlah byte pesan setelah dienkripsi adalah '+inttostr(sizeAfter), mtInformation, [mbOK], 0); btnCipherSize.Caption:='Ukuran byte terenkripsi = '+inttostr(sizeAfter); end; end.

//Function untuk dekripsi dan dekompresi pesan function TForm4.decompressAndDecrypt(filename: string; kunci: string): Boolean; var SourceCrypt, DestCrypt, InputStream, OutputStream: TFileStream; DeCompressionStream: TZDecompressionStream; begin Result:=False; //Proses dekripsi try SourceCrypt:= TFileStream.Create(filename, fmOpenRead or fmShareDenyNone); DestCrypt:= TFileStream.Create('tmpDecrypt.tmp.zip',fmCreate); DCP_rijndael1.InitStr(kunci,TDCP_sha1); // dekripsi pesan DCP_rijndael1.DecryptStream(SourceCrypt,DestCrypt,SourceCrypt.Size); DCP_rijndael1.Burn; DestCrypt.Free; SourceCrypt.Free; DeleteFile(filename); //Result:=True; except MessageDlg('File IO error',mtError,[mbOK],0); end; //Proses dekompresi try InputStream := TFileStream.Create('tmpDecrypt.tmp.zip', fmOpenRead or fmShareDenyNone); OutputStream := TFileStream.Create(filename, fmCreate);

Universitas Sumatera Utara

DecompressionStream := TZDecompressionStream.Create(InputStream); OutputStream.CopyFrom(DecompressionStream, 0); DecompressionStream.Free; OutputStream.Free; InputStream.Free; DeleteFile('tmpDecrypt.tmp.zip'); Result:=True; except MessageDlg('File IO error',mtError,[mbOK],0); end; end;

procedure TForm4.btnUngkapClick(Sender: TObject); var resultName:string; begin if (txtkunci.Text='') then begin messageDlg('Masukkan kunci pada kolom di atas!',mtError, [mbOK], 0); exit; end; if (not FileExists(txtStegFileResult.Text)) then begin messageDlg('Masukkan File Stegged-Mp3!', mtError, [mbOK], 0); exit; end; resultName:=RevealFile(txtStegFileResult.Text); if (resultName'None') then begin //decompress and decrypt if (decompressAndDecrypt(resultName, txtkunci.Text)) then begin messageDlg('Pengungkapan Pesan Berhasil!'+#13+'File Hasil Pengungkapan Pesan adalah '+resultName, mtInformation, [mbOK], 0); end else begin messageDlg('Pengungkapan Pesan Gagal!', mtError, [mbOK], 0); end; end else begin messageDlg('Pengungkapan Pesan Gagal!', mtError, [mbOK], 0); end; end; end.

Universitas Sumatera Utara