Aufgabe: Implementierung eines eigenen Hashalgorithmuses

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
m1LLo
User
Beiträge: 6
Registriert: Dienstag 8. Mai 2018, 15:51

Hallo erstmal,
ich beschäftige mich jetzt seit ca. 2 Wochen auf Grund eines Wahlpflichtmoduls mit Python und stolpere bei der aktuellen Aufgabe über die ein oder anderen Probleme bei denen ich Hilfe gebrauchen könnte.

Zur aktuellen Aufgabe:
Es soll ein Vorgegebener String mit einer eigenen "pseudo" Hashfunktion gehased werden.

Zum Problem:
Mein Verständnis bezüglich dem Umgang mit den Datentypen besonderst dem Ergebnis der Funktion "bytes" oder dem Datentyp "bytearray".
Wie kann ein String einmal 35 Bytes groß sein und der gleiche String als byte-Objekt 27Byte? Ich kann ja nur Bitoperationen auf int anwenden.
Wie bekomme ich jetzt den String in mehrer ints.

Mein versuchter Ansatz:
  • String umwandeln in Bytes
  • Falls String nicht mehrfaches der Blocksize entsprechend erweitern.
  • String in Blöcke zerhacken welche der länge der Blocksize entsprechen
  • Blöcke mit einem ersten Hashwert in Compressionfunktion schieben und dort XOR verknüpfen => neuer Hashwert
  • Neuen Hashwert mit nächstem Block in Compressionsfunktion.
  • Nachdem alle Blöcke abgearbeitet sind Hash Fertig
Mein Quellcode:

Code: Alles auswählen

from bitstream import *
import struct
import sys

hashstring = 'Dieser String soll gehased werden!1337'
hashlist = [(0x0123456789abcdef0123456789abcdef).to_bytes(32,'big')] #start Hash

#macht aus einem Hash und einem Block einen neuen Hash
def compress(preHash, block):
	#test = bytearray(preHash)
	#test2 = bytearray(block)
	#test2.append(not(block))
	#for i in range(len(test)):
	#	print("Hashwert",hex(test[i]))
	#	print("Blockwert",hex(test2[i]))
	#	print("---")
	hashTMP = (preHash) | (block)
	return hashTMP

#zerstückeln der Nachricht in Blöcke
def messegeAsBlocklist(message, blockSize):
	blocklist=list()
	for i in range(0, len(message) // blockSize,):
		blockTMP = (message[blockSize*i:(i+1)*blockSize])
		blocklist.append(blockTMP)
	return blocklist

#nachricht erweitern falls notwendig
def expandMessage(message, blockSize):
	expandCount = ((blockSize - (len(message) % blockSize)) % blockSize)
	message = bytes(message, "ascii")
	#es müssen mehr zeichen hinzugefügt werden als die Nachricht lang ist
	if len(message) < expandCount:
		for i in range(expandCount):
			message = message + (message[i]).to_bytes(1,'big')
	else:
		message = (message + message[0:(expandCount)])
	return (message)
	

def hashMessage(message, blockSize):
	#Erweitert die Nachricht falls nötig auf das nächste vielfache der BlockSize
	expandedMSG = expandMessage(message, blockSize)
	blocklist = messegeAsBlocklist(expandedMSG, blockSize)
	for i in range(len(blocklist)):
		hashlist.append(compress(hashlist[i], blocklist[i]))
	

# Testaufrufe
if __name__ == '__main__':
       hashMessage(hashstring, 32)
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

@m1LLo: wo hast Du einen String der 35 Byte groß ist, und wo das byte-Objekt mit 27 Bytes?

bitstream, struct und sys werden nicht verwendet, müssen also auch nicht importiert werden. Im ganzen Programm sind viel zu viele Klammernpaare, die den Lesefluß negativ beeinflussen. Variablen und Funktionen schreibt man generell klein_mit_unterstrich.

hashlist ist eine globale Variable, die man nicht verwenden sollte, denn so kann man hashMessage nur einmal verwenden. Zeile 17 kann so nicht funktionieren. Warum arbeitest Du nicht mit Ints? Diese TMP-Variablen sind überflüssig, aber vor allem das TMP darin, denn alle lokalen Variablen sind nur temporär. Zeile 30 läßt sich auch kurz als `- (len(message) % -blockSize)` schreiben. Zeile 31: Strings encodiert man am besten als UTF8. Und das passiert dann auch eine Zeile zu spät, weil sich die Länge als String von der als Bytes unterscheiden kann. Zeile 45: über einen Index iteriert man nur, wenn es nicht anders geht, hier reicht es über die blocklist zu iterieren, da man immer das letzte Element von hashlist nehmen kann.

So könnte es auch aussehen:
[codebox=python file=Unbenannt.txt]
def split_message_to_blocks(message, blocksize):
message = message.encode("utf8")
first_block = block = message[: blocksize]
for i in range(blocksize, len(message), blocksize):
yield block
block = message[i : i + blocksize]
while len(block) < blocksize:
block += first_block
yield block[:blocksize]

def hash_message(message, blocksize):
hash = 0x0123456789abcdef0123456789abcdef
blocks = split_message_to_blocks(message, blocksize)
for block in blocks:
hash |= int.from_bytes(block, 'big')
return hash.to_bytes(blocksize, 'big')
[/code]
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Code: Alles auswählen

def hash(string):
    return 0
Mehr "pseudo" geht nicht ;)
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
m1LLo
User
Beiträge: 6
Registriert: Dienstag 8. Mai 2018, 15:51

Hallo Sirius3,
danke für deine Mühe.
Sirius3 hat geschrieben:bitstream, struct und sys werden nicht verwendet, müssen also auch nicht importiert werden.
Ja das sind noch Überreste von Code welcher einfach nur zum Experimentieren da waren.
Sirius3 hat geschrieben:@m1LLo: wo hast Du einen String der 35 Byte groß ist, und wo das byte-Objekt mit 27 Bytes?
Das war nur eins der Experimente. Hier ein Beispielcode

Code: Alles auswählen

hallo = "Hallo Tester"
hallo1 = b'Hallo Tester'
print(type(hallo))[quote="Sirius3"]Zeile 31: Strings encodiert man am besten als UTF8. Und das passiert dann auch eine Zeile zu spät, weil sich die Länge als String von der als Bytes unterscheiden kann[/quote]
print(type(hallo1))
print(sys.getsizeof(hallo))
print(sys.getsizeof(hallo1))
hallo ist hier 37 Bytes groß und hallo1 29 Bytes. Das verwirrt mich irgendwie.
Sirius3 hat geschrieben:hashlist ist eine globale Variable, die man nicht verwenden sollte, denn so kann man hashMessage nur einmal verwenden.

Ok das macht Sinn und so weit hab ich auch noch gar nicht gedacht, aber das wäre mir bei meinem Test aufgefallen :-)
Sirius3 hat geschrieben: Zeile 30 läßt sich auch kurz als `- (len(message) % -blockSize)` schreiben
Es stimmt zwar dass daraus dann eine Nachricht wird die definitiv ein mehrfaches der Blocksize ist aber es werden dann auch Nachrichten die bereits die richtige Länge haben nocheinmal um Blocksize erweitert. Finde ich sehr unschön.
Sirius3 hat geschrieben:Zeile 31: Strings encodiert man am besten als UTF8. Und das passiert dann auch eine Zeile zu spät, weil sich die Länge als String von der als Bytes unterscheiden kann.
Ok ich sollte mich wohl dringend endlich mal mit Encoding beschäftigen.
Sirius3 hat geschrieben:Zeile 45: über einen Index iteriert man nur, wenn es nicht anders geht, hier reicht es über die blocklist zu iterieren, da man immer das letzte Element von hashlist nehmen kann
Also du meinst bei dieser Operation mittels pop() sich das Element geben lassen und aus der Liste entfernen wie ein Stack. Ich komme leider aus dem C/Assembler Bereich da kennt man sowas wie iterierbare Objekte nicht weswegen ich es oft einfach vergesse und auf die C-Art mache.
Sirius3 hat geschrieben:yield block
Soso. Interessant was mit dieser Sprache so alles geht. Natürlich hätte ich das so niemals als Anfänger gemacht aber dank deiner Ausführung habe ich mir das jetzt mal angeeignet.

Alles in allem viele Dank für deine Hilfe und ich werde natürlich weiter üben :-)
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

m1LLo hat geschrieben:hallo ist hier 37 Bytes groß und hallo1 29 Bytes. Das verwirrt mich irgendwie.
Was glaubst Du gibt `sys.getsizeof(hallo)` aus? Wenn Du das nachgelesen hast, dann verstehst Du auch das Ergebnis.
m1LLo hat geschrieben:Es stimmt zwar dass daraus dann eine Nachricht wird die definitiv ein mehrfaches der Blocksize ist aber es werden dann auch Nachrichten die bereits die richtige Länge haben nocheinmal um Blocksize erweitert. Finde ich sehr unschön.
Vor Du Vermutungen anstellst, probier's einfach aus. Das hilft immer beim Verstehen von Programmen.
m1LLo hat geschrieben:Also du meinst bei dieser Operation mittels pop() sich das Element geben lassen und aus der Liste entfernen wie ein Stack.
Du willst ja eine Liste haben, also ist "entfernen" das falsche, Du kannst aber das letzte Element abfrage:

Code: Alles auswählen

    blocklist = messegeAsBlocklist(expandedMSG, blockSize)
    for block in blocklist:
        hashlist.append(compress(hashlist[-1], block))
m1LLo
User
Beiträge: 6
Registriert: Dienstag 8. Mai 2018, 15:51

Sirius3 hat geschrieben:Was glaubst Du gibt `sys.getsizeof(hallo)` aus? Wenn Du das nachgelesen hast, dann verstehst Du auch das Ergebnis.
Es wird laut Doku die große eines Objektes in Bytes ausgeben. Find es eben einfach merkwürdig.
Sirius3 hat geschrieben:Vor Du Vermutungen anstellst, probier's einfach aus. Das hilft immer beim Verstehen von Programmen.
Ok ich habe meinen Fehler gefunden: Ich habe es nicht in Python ausprobiert sondern die Ergebnisse aus dem Windowsrechner genutzt. Dieser gibt nur dummerweise z.B. bei (32%-5) als Ergebnis 2 aus. Rechenart vom Windowsrechner: 32%(-5)=2 also (-5)*(-6)+2
Python rechnet jedoch 32%(-5)=-3 also (-5)*(-7)-3
Was jetzt richtig ist weis ich leider nicht da die mathematische Definition, für negative Zahlen, von Modulo mir nicht mehr geläufig ist.
Sirius3 hat geschrieben:hashlist.append(compress(hashlist[-1], block))
Ok auf die Idee dass ich die Liste ja mit negativen Indizes nutzen könnte bin ich erst gar nicht gekommt :-) Vielen Dank. Durch die Unterhaltung mit dir habe ich das Gefühl viel mehr von Python zu lernen als zuvor.
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

@m1LLo: die Größe eines Objekts ist aber nichts, was normalerweise weiterhilft. Was willst Du denn damit tun?

Im Gegensatz zu anderen Programmiersprachen ist das Verhalten bei Modulo in Python genau definiert.
Antworten