Kako bi olakšali generiranje forenzičkog materijala za laboratorijske vježbe i ispite napravili smo skripte koje je potrebno iz vršiti samo jednom. Automatizacija generiranja je zahtjevala korištenje liste jmbag-a studenta koji polažu kolegij Forenzika digitalnih dokumenata. Kako izgledaju navedene skirpte moguće je vidjeti ovdje. Također kako se koriste skripte i što je sve potrebno za pokretanje moguće je pročitati u predanom pdf dokumentu.
Kako bi svaki student prilikom provjere imao različit primjer zadatka potrebno je generirati kodove za svakog od studenata. To je napravljeno na sljedeći način:
def generate_codes(jmbags):
jmbag_code_dir = {} for jmbag in jmbags: jmbag = jmbag.strip() jmbag_int = int(jmbag) random.seed(jmbag_int) code = random.randint(0, jmbag_int * 65537) % 1000 code = str(code) while len(code) < 3: code += str(random.randint(0,9)) jmbag_code_dir[jmbag] = "answer" + str(code) return jmbag_code_dir
Unutar funkcije potrebno je poslati listu svih jmbag-a studenata za koje je potrebno kreirati forenzicki materijal. Kako bi se dobila nasumičnost za svakog studenta je potrebno postaviti seed na njegov jmbag jer svaki jmbag je jedinstven i pripada točno jednom studentu pa ga i preko njega možemo identificirati.
random.seed(jmbag_int)
code = random.randint(0, jmbag_int * 65537) % 1000
Prva od gore navedenih linija postavlja novi seed za svakog studenta te nakon toga kako bi se dobila još veća nasumičnost dodan je broj 65537 koji se koristi kao javni eksponent RSA enkripcije i na kraju je potrebno uzeti samo zadnje tri znamenke generiranog broja.
Sada dolazimo do prvog problema generiranja koda za svakog studenta, a to je što se događa ako su zadnje tri znamenke 007 automatski se brišu vodeće nule. Sljedeće dvije linije koda se brinu o tome da kod uvijek ima tri znamenke:
while len(code) < 3:
code += str(random.randint(0,9))
Također za svakog studenta je potrebno napraviti mapu gdje će mu biti pohranjene slike i audio materijal.
def generate_folder(dir):
os.mkdir("JMBAGS") file_answers = "" for key in dir.keys(): os.mkdir(os.path.join("JMBAGS/" + key)) generate_watermarks(key, dir.get(key)) file_answers += key + "->" + dir.get(key) + "\n" os.mkdir("ANSWERS") with open("ANSWERS/answers.txt", "w") as f: f.write(file_answers)
Nakon ovog koraka svaki student ima kreiranu mapu s njegovim jmbag-om te unutar mape se nalazi modificirana slika na kojoj je potrebno naći watermark, te se naknadno u taj folder mogu dodati i audio materijali tj. modifcirani audio materijal koji će generiratni kod iz gore navedene funkcije “zamutit” kako ne bi bez filtracije bio razumljiv korisniku.
Kako se točno automatski generiraju forenzički materijali audio sadržaja objašnjeno je u poglavlju Automatsko generiranje zvučnih forenzičkih materijala, a kako se automatski generiraju forenzički materijali slikovnog sadržaja moguće je pročitati u Automatsko generiranje slikovnih forenzičkih materijala
Postupak stvaranja zvučnih forenzičkih materijala se može razdvojiti na dva glavna dijela:
Budući da je cilj potpuno automatsko generiranje svih zapisa, potrebno je izbijeći snimanje ljudske osobe kako izgovara željeni tekst. Time se treba koristiti tehnologija računalnog stvaranja glasa iz proizvoljnog teksta, koja se naziva Text-To-Speech. Text-To-Speech tehnologija je danas iznimno razvijena te je gotovo nemoguće raspoznati razliku između stvarnog govornika i generiranog glasa. Za uporabu Text-To-Speech tehnologije u Python programskom jeziku, je danas u širokoj primijeni programska biblioteka gTTS. Google Text-To-Speech biblioteka koristi API od Google Translate online alata za generiranje glasa.
Ostale biblioteke koje su korištene su numpy, soundfile i pydub. Zatim je za određene funkcionalnosti nekih Python biblioteka potrebno postaviti ffmpeg na računalu. ffmpeg je svojevrsni švicarski nožić za audio-video modifikaciju.
from gtts import gTTS
text = generirani kod
language = “en”
audio = gTTS(text=text, lang=language, slow=False)
audio.save(“audio.mp3”)
Navedeni isječak generira proizvolja tekst na engleskome. Tekst koji se izgovara se postavalja kao text parametar, jezik kao lang parametar i slow se postavlja na False jer pre sporo čita inače.
sound = AudioSegment.from_mp3(“audio.mp3”)
sound.export(“audio.wav”, format=“wav”)
Navedenim linijama se generirana datoteka formata mp3 pretvara u format wav. Naime, gTTS može stvarati samo mp3 datoteke dok je wav pogodonija za uređivanje te ju je zato potrebno pretvoriti u drugi oblik.
signal, sr = sf.read(“audio.wav”)
RMS = math.sqrt(np.mean(signal**2))
noise = np.random.normal(0, RMS*8, signal.shape[0])
Zatim ponovno pročitatmo daototeku u wav formatu kako bi je mogli uređivati u potpunosti. U RMS varijablu računamo prosječnu glasnoću govora te time dobivamo dobru referentnu vrijednost za određivanje intenziteta manipulacije. Primjer tome je zadnja linija koja generira šum po normalnoj razdiobi. Zadnja dva parametra su jedini koji su bitni za ispravno generiranje šuma. Drugi parametar je standardna devijacija razdiobe te ona određuje raspon glasnoće šuma, dok zadnji parametar govori o duljini šuma. Time dobivamo šum određene glasnoće koji odgovara duljini glasa.
signal_noise = signal + noise
Budući da su svi zvučni signali u Pythonu prikazani kao numpy polja, moguće je dodavanjem zbrojiti signale te dobiti potpuni zapis.
Time smo sada dobili audio zapis koji sadržava šum dovoljno glasan da nije moguće razlikovati govor. Naime nailazimo na jedan problem a to je da šum potencijalno nije moguće ukloniti ako se frekvencije suvišno preklapaju sa stvarnim govorom. Zato je potrebno istražiti druge metode generiranja šuma koje ne uništavaju integritet glasa.
Kod automatskog generiranja slikovnog forenzičkog materijala konkretno se misli na stavljanje watermarka unutar slike. Kako bi watermark što skriveniji potrebno je za početnu sliku uzeti sliku sa jakim tamnim bojama kao što su: smeđa, crna, ljubičasta … Jer kod takvih boja watermark neće biti uočljiv golim okom i preko alata za analizu dodavanja elementa u sliku neće odmah biti uočljiv watermark nego će osoba morati malo korigirati parametre kako bi watermark bio vidljiv i razumljiv.
Početna slika:
Za umetanje watermarka unutar slike korišten je python library Pillow. Dokumentaciju library-a moguće je vidjeti ovdje.
Na početku je potrebno učitati sliku. Pillow library omogućuje otvaranje bilo koje ekstenzije slike, ali je zato radi modifikacije potrebno napraviti konverziju u RGBA model boja. RGBA je zapravo model boja isti kao i RGB samo je moguće mjenjati koliko će koja boja biti izražena (A - alfa faktor). Nakon učitanjavanja slike potrebno je napraviti novi sloj na kojem će se pisati generairani watermark. Sljedeće dvije linije rade opisani postupak:
img = Image.open('slika.jpg').convert(“RGBA”)
txt = Image.new('RGBA', img.size, (255,255,255,0))
Nakon što je slika učitana i kreiran je sloj na kojem će se pisati potrebno je postaviti font s kojim će se pisati i sami tekst koji će biti napisan. Kada su svi ti parametri određeni moguće je “spojiti” dva sloja tj. sliku i tekst funckijom .Draw(), ali još uvijek ništa nije ubačeno u sliku.
text = generirani kod
font = ImageFont.truetype(“arial.ttf”, 82)
d = ImageDraw.Draw(txt)
Sada je potrebno odrediti poziciju na kojoj će se nalaziti watermark. Na početnoj slici je to najbolje postaviti na neko tamno područje kao što je npr. voda ispred grada u ovom slučaju. Ovih nekoliko linija računa poziciju gdje će se nalaziti watermark:
width, height = img.size
textwidth, textheight = d.textsize(text, font)
x=width/2-textwidth/2
y=height-textheight-300
Nakon što je određena pozicija slike potrebno je konačno ubaciti watermark u sliku. Za to je zadužena operacija d.text() koja na gore kreiranom zajedničkom sloju ubacuje tekst s atributima koji su gore postavljeni i postavlja boju teksta u crnu s vidljivosti (alpha faktorom) od 6% kako bi bio što neprimjetniji. Zašto je ovdje alpha faktor baš 6%, jer kod analize ubacivanja teksta u sliku watermark neće biti vidljiv ako se alpha faktor smanji preblizu nule. Funckija alpha_composite() spaja dva sloja do kraja te ih pretvara u jednu sliku u kojoj je umetnut watermark. Na kraju postupka slika se pohranjuje u točno određenu mapu studenta ovisno o njegovom jmbag-u.
d.text((x,y+100), text, fill=(0,0,0,6), font=font)
watermarked = Image.alpha_composite(img, txt)
watermarked.save(f'./JMBAGS/{key}/watermarked.png')
Usporedba slika prije i poslije umetanja watermarka (lijeva je početna):
Kako izgleda watermark kada se napravi adekvatna analiza za pretragu (answer518):
Automatsko generiranje forenzičkog materijala je uspiješno izvedena. Kvaliteta samog generiranog sadržaja je vrlo kvalitetna u smislu nije na prvi pogleda vidljiva razlika kod modificirane slike, a niti kod zvučnog sadržaja od originala. Također kodovi su različiti za svakog studenta tako da se dane skripte mogu koristi za kreiranje laboratorijskih vježbi i samog ispita. Skripte koje su napravljene za automatsko generiranje forenzičkog materijala su iznimno lake za pokretanje tj. nije potrebna nikakva modifikacija nego samo pokretanje skripte prateći upute koje su predane u pdf dokumentu.
Rasprave
Nisam siguran razlikuje li se ovo od trenutnog generiranja i zadataka za labose iz FDD? Ako da, možete li istaknuti kako? Nema primjera za automatsko generiranje zvučnih mateijala. Koji su uvjeti za pokretanje koda i postoje li neke upute za geneirranje baze zadataka? Razumijem da je na ovo stranici objašnjeno što rade neki dijelovi koda, ali kako se kod ukupno pokreće i uz koje parametre?
Trenutno nismo sigurni razlikuje li se generiranje labosa od našeg načina jer nismo imali uvid u to.
Sve što je potrebno za pokretanje koda se nalazi u PDF dokumentu. Potpuni programski kod se nalazi na GitHubu (https://github.com/MarinoRabuzin/ForenzikaSeminar) što je navedeno u Sažetku i u PDF dokumentu.