• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

[Java] Passwort verschlüsseln

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
581
Hi Leute,
ich arbeite an einem Projekt, welches ich verschlüsseln möchte, bzw die Daten davon.
Meine Frage ist nun, ob mein Ansatz sinnvoll ist oder eher nicht:

Ich habe mir gedacht das Passwort erst zu hashen, dann einen Teil davon zu nehmen und diesen dann mit AES zu verschlüsseln (Key ist das Passwort selbst).
Dieses kann ich dann in meinem System speichern.
Alle anderen Daten würden dann mit dem Originalpasswort (bzw dem Hash davon) verschlüsselt. So speichere ich ein Passwort, dass zuerst entschlüsselt werden müsste, um alles andere zu entschlüsseln.
Ist das sinnvoll so?

Hier bei Beispiel für meinen Code:
[src=java]
private boolean isPasswordCorrect(String pw) {
String saved_password = this.readFile("p.txt");

try {

MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(pw.getBytes());

pw = new String(md.digest());
byte[] pw2 = pw.getBytes();
pw2 = Arrays.copyOf(pw2, 16);

SecretKeySpec password = new SecretKeySpec(pw2, "AES");

this.ec = new EasyCrypt(password, "AES");

// System.out.println(this.ec.encrypt(pw));
// System.out.println(saved_password);
//Passwort entschlüsseln und vergleichen
if (saved_password.equals(this.ec.encrypt(pw))) {
// System.out.println("##Korrekt##");
return true;
}
this.ec = null;

} catch (IOException ex) {
Logger.getLogger(CLASS1.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(CLASS1.class.getName()).log(Level.SEVERE, null, ex);
}
return false;
}

/* Und dann halt noch die Klasse, die ich von einer Website habe: */
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
* @author Alexander Gr
* @see http://blog.axxg.de
*
*/
public class EasyCrypt {

private Key key = null;
private String verfahren = null;

/**
* @param Key verwendeter Schluessel
* @param verfahren bestimmt das verwendete Verschluesselungsverfahren "RSA", "AES", ....
* @throws Exception
*/
public EasyCrypt(Key k, String verfahren) throws Exception {
this.key = k;
this.verfahren = verfahren;
}

/**Verschluesselt einen Outputstream
* @param os Klartext-Outputstream
* @return verschluesselter Outputstream
* @throws Exception
*/
public OutputStream encryptOutputStream(OutputStream os) throws Exception {
// integritaet pruefen
valid();

// eigentliche Nachricht mit RSA verschluesseln
Cipher cipher = Cipher.getInstance(verfahren);
cipher.init(Cipher.ENCRYPT_MODE, key);
os = new CipherOutputStream(os, cipher);

return os;
}

/** Entschluesselt einen Inputstream
* @param is verschluesselter Inputstream
* @return Klartext-Inputstream
* @throws Exception
*/
public InputStream decryptInputStream(InputStream is) throws Exception {
// integritaet pruefen
valid();

// Daten mit AES entschluesseln
Cipher cipher = Cipher.getInstance(verfahren);
cipher.init(Cipher.DECRYPT_MODE, key);
is = new CipherInputStream(is, cipher);

return is;
}

/** Verschluesselt einen Text in BASE64
* @param text Klartext
* @return BASE64 String
* @throws Exception
*/
public String encrypt(String text) throws Exception {
// integritaet pruefen
valid();

// Verschluesseln
Cipher cipher = Cipher.getInstance(verfahren);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(text.getBytes());

// bytes zu Base64-String konvertieren
BASE64Encoder myEncoder = new BASE64Encoder();
String geheim = myEncoder.encode(encrypted);

return geheim;
}

/** Entschluesselt einen BASE64 kodierten Text
* @param geheim BASE64 kodierter Text
* @return Klartext
* @throws Exception
*/
public String decrypt(String geheim) throws Exception {
// integritaet pruefen
valid();

// BASE64 String zu Byte-Array
BASE64Decoder myDecoder = new BASE64Decoder();
byte[] crypted = myDecoder.decodeBuffer(geheim);

// entschluesseln
Cipher cipher = Cipher.getInstance(verfahren);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] cipherData = cipher.doFinal(crypted);
return new String(cipherData);
}

//++++++++++++++++++++++++++++++
// Validierung
//++++++++++++++++++++++++++++++

private boolean valid() throws Exception{
if(verfahren == null){
throw new NullPointerException("Kein Verfahren angegeben!");
}

if(key == null){
throw new NullPointerException("Keinen Key angegeben!");
}

if(verfahren.isEmpty()){
throw new NullPointerException("Kein Verfahren angegeben!");
}

return true;
}

//++++++++++++++++++++++++++++++
// Getter und Setter
//++++++++++++++++++++++++++++++

public Key getKey() {
return key;
}

public void setKey(Key key) {
this.key = key;
}

public String getVerfahren() {
return verfahren;
}

public void setVerfahren(String verfahren) {
this.verfahren = verfahren;
}
}
[/src]

Gibts es eigentlich die common apache-packages standardmäßig in de JDK 8? Dann könnte man nämlich die Base64 daraus nehmen, da die aktuell verwendeten, eventuell demnächst auslaufen?
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.510
Der Hauptgrund, warum hash Funktionen in diesem Kontext eingesetzt werden ist, weil man vom hashed Wert nicht auf den ursprünglichen Wert schließen kann.
Hashe das Passwort mit bcrypt und hohem Kostenfaktor und speichere den Hash.
 

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
581
  • Thread Starter Thread Starter
  • #3
Ich möchte nicht den Hash speichern, da ich die ersten 16Byte des Hashs als Passwort für meine Verschlüsselung nutzen möchte. Würde ich den Hash dann so speichern, hätte man ja direkt den passenden Schlüssel für alle anderen Dateien.
Wieso ich das Passwort gehashed als Schlüssel nutze? Ganz einfach - AES benötigt einen Key, der aus einem Vielfachen von 8 Zeichen besteht. Ich möchte aber Passwörter beliebiger Länge zulassen.

Meine Frage wahr eher, ob eine AES-Verschlüsselung von dem eigenen Schlüssel "unsicher" ist oder das keinen Einfluss auf die Sicherheit hat?
 

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
581
  • Thread Starter Thread Starter
  • #5
Ich schreibe ein Programm, welches immer mal wieder Daten speichert (verschlüsselt). Man soll aber nur mit dem Passwort rankommen --> Also muss das Passwort oder zumindest eine entsprechende Prüfsumme ja auch irgendwo hinterlegt sein.
Wie man oben im Quellcode sieht, verändere ich das eingegebene Passwort und vergleiche es anschließend mit dem gespeicherten Wert. Wenn sie übereinstimmen, ist es das richtige Passwort und ich kann mit dem Hash-Wert alle anderen Dateien entschlüsseln.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
Warum verwendest du "nur" die ersten 16 Zeichen/Byte des Sha512's?

Hier:
[src=java]pw2 = Arrays.copyOf(pw2, 16);[/src]

Rückgabewert sind 128 Zeichen im Hexformat also 16 Varianten, bei einer Länge von 16 Zeichen daraus nutzt du nur 16^16 Kombinationen, das ist aber nicht sonderlich stark.
Wenn würde ich die gesamten 128 Zeichen des Sha512's für die Encryption nutzen, damit wärst du bei einer Stärke von 128^16, deutlich besser. Das bietet auch weniger Spielraum für Kollisions-Attacken in Form von Wiederholungen der Hashes/Checksums eines Passwortes.

Die AES Verschlüsslung obendrauf ist mit Sicherheit keine schlechte Idee, nur habe ich keine Ahnung wie das in Java von statten geht.

Habe dazu mal das hier herausgesucht da mir der Aufbau von AES so nicht ganz deutlich wahr, dort wird übrigens auch etwas auf das Base64 Encoding eingangen und auch wie man mit UTF8 ("multi-byte") umgehen sollte:
http://www.movable-type.co.uk/scripts/aes.html

Aber ich bin auch nur eine Laie in Kryptographie, daher hat mir der Link auch etwas geholfen. :)
 

alter_Bekannter

N.A.C.J.A.C.

Registriert
14 Juli 2013
Beiträge
4.833
Ort
Midgard
@Roin:
Korrekt eine Prüfsumme...

Kein Bedarf für ein Passwort.

Daher die Frage nochmal, vielleicht etwas spezifischer:
In welchem Fall denkst du das ein Passwort nötig ist bzw die Prüfsumme nicht ausreicht?

Bei Technik erreicht man Perfektion nicht dann wenn man nichts mehr hinzufügen kann, sondern wenn man nichts mehr entfernen kann. Alles was man streichen kann erhöht per Definition unnötig das Fehlerpotential.

Und wie ein zusätzliches gespeichertes Passwort Probleme machen könnte ist echt ein alter Hut...

Allein folgendes Szenario:
Die Crypto wird irgenwann geknackt = man kommt definitiv ans Passwort:unknown:
 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
Und wie ein zusätzliches gespeichertes Passwort Probleme machen könnte ist echt ein alter Hut...

Wenn etwas hart einprogrammiert ist schon, weil es Rückschlüsse auf den Algorithmus schließen lässt der verwendet wurde, aber er coded ja nichts hart ein. Und hat nur den Sha gespeichert.

Allein folgendes Szenario:
Die Crypto wird irgenwann geknackt = man kommt definitiv ans Passwort:unknown:

"Insecurity Is Better Than No Security at All" - zu Deutsch - "Unsicherheit ist besser als gar keine Sicherheit"...

Bis dein Rechner einen Sha512 geknackt hat dauert es IONEN wenn du das per Bruteforce machst, 128 ^ 16 Kombinationen, viel Spaß, wir sehen uns dann in ein paar Jahrzehnten.

@Roin:
Was mir gerade noch einfällt, du könntest statt des Sha512s den AES speichern und diesen Entpacken lassen mittels Passworteingabe was dann den korrekten Sha512 ausspuckt welcher auch nochmal mit dem korrekten Password zurückgerechnet werden muß. Sollte noch ne Ecke komplizierter sein das zu Knacken. :T

Du könntest auch nach jeder erfolgreichen Eingabe des Passworts einen neuen AES generieren und abspeichern lassen um das ganze noch weiter zu verwischen.
Setzt aber vor raus die Implementierung ist wie in der Javascript Version auf der Webseite und die Ausgabe variiert bei fixer Länge, lässt sich aber zurück kodieren mittels des Passwortes.
 

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
581
  • Thread Starter Thread Starter
  • #9
@alter_Bekannter:
Ich glaube wir schreiben aneinander vorbei:
Ich nehme ein Passwort "heute" und hashe es mit sha512 --> Der entstehende Hash wäre eine Prüfsumme, allerdings ist er in meinem Fall der Schlüssel für die AES-Verschlüsselung
Somit kann ich den Hash nicht mehr als Prüfsumme speichern. Daher wollte ich den Hash selbst verschlüsseln (man könnte ihn vermutlich noch einmal selbst hashen) und speichern, um einen Vergleichswert zu haben. Der verschlüsselte Hash ist somit meine "Prüfsumme", wenn man so will.
Ich dachte eigentlich, dass das ein ganz elegantes vor

@theSplit:
Wenn ich die zitierte Zeile rausnehme (und einfach die volle Länge an Bytes nehme), kommt folgendes:

java.security.InvalidKeyException: Invalid AES key length: 115 bytes
at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:495)
at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1067)
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1025)
at javax.crypto.Cipher.implInit(Cipher.java:801)
at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
at javax.crypto.Cipher.init(Cipher.java:1249)
at javax.crypto.Cipher.init(Cipher.java:1186)
at CLASS1.EasyCrypt.encrypt(EasyCrypt.java:79)
Keine Ahnung wieso der dann nur 115 Bytes lang ist (?) und ich habe woanders gelesen, (ich glaube sogar auf der gleichen Seite, wo ich die EasyCrypt-Klasse her habe, dass da nur die ersten 16 Bytes genommen werden.
Und ich habe den Text von dir jetzt nur überflogen aber steht das hier nicht genau so?

The key in this script is obtained by applying the Cipher routine to encrypt the first 16/24/32 characters of the password (for 128-/192-/256-bit keys) to make the key. This is a convenient way to obtain a secure key within an entirely self-contained script (in a production environment, as opposed to this essentially tutorial code, the key might be generated as a hash, e.g. simply key = Sha256(password)). In more detail, the supplied password is converted to to UTF-8 (to be byte-safe), then the first 16/24/32 characters are converted to bytes. The resulting pwBytes is used as a seed for the Aes.keyExpansion() which is then used as the key to encrypt pwBytes with Aes.cipher(). Examples of keys generated in this way from (unrealistically) simple passwords:
Also ich lese daraus, dass mein Key den ich für AES benötige 128/192/256 bit lang sein muss. Und nicht anders.

Habe ich da was falsch gesehen?
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
Ne, du hast Recht, hab ich wohl zu schnell/einfach gedacht. :D

Du kannst den Schlüssel ja in 4x32 Zeichen/Byte = 256 bit Stücke zerlegen und diese speichern.
Dann die Parts in der Reihenfolge zusammenfügen, wenn das Passwort stimmt und der AES damit entschlüssel wurde, hast du dann wieder die korrekte Prüfsumme zusammengebaut. :)
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.764
Ort
in der Zukunft
@Roin: ich würde sagen du brauchst für dein Problem schlicht nur 2 unterschiedliche Hashverfahren...

Du nimmst dein Passwort, bildest einen Hash mit z.B. Whirlpool > Speicherst den Hash
nimmst das gleiche Passwort und Hasht es mit SHA-512 und nimmst den Hash davon als Key für die AES verschlüsselten Daten.

Bei der neu-eingabe durch den Anwender lässt du das pw eingeben und prüft es gegen den Whirlpool-Hash,
bei erfolg nimmst du das pw und entschlüsselst die Daten damit
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.510
Hab gestern Abend noch etwas auf stackexchange gelesen.
Man macht es wohl gerne so, dass man einen Key nimmt, damit die Daten verschlüsselt und mit dem Benutzerpasswort dann den Key verschlüsselt. Das hat den Vorteil, dass die Daten nicht neu verschlüsselt werden müssen, wenn das Passwort geändert wird, sondern nur der Key.

Also: passwort ---(bcrypt)---> hash ---(some encryption)---> key ---(aes)---> daten
 
Zuletzt bearbeitet:

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.764
Ort
in der Zukunft
Auch ne interessante Idee ja,
wobei ich dann den Hash vom Passwort weg lassen würde (außer um auf eine Bestimmte Key-länge zu kommen) bzw. die Speicherung des pw-Hashes unterlassen.
Dann lassen sich die Daten nur korrekt entschlüsseln wenn das pw richtig eingegeben wurde, sonst kommt entweder beim AES-decrypt ein Fehler oder es kommen wirre daten raus...


ist Quatsch, wenn ich dann einen Marker brauche wann die entschlüsselten Daten valide sind - ist das ganze leichter zu knacken...
 
Zuletzt bearbeitet:

Skipjack

Neu angemeldet

Registriert
17 Juli 2013
Beiträge
213
Dann will ich dem auch noch etwas hinzufügen. ;)

In jedem Fall schon einmal das was BurnerR vorgeschlagen hat, um das Passwort (welches ja von Zeit zu Zeit gewechselt werden sollte/könnte) von der Datenverschlüsselung zu trennen.
Also bei Programmerststart einen Datenkey erzeugen lassen, mit dem von da an alle Programmdaten verschlüsselt werden.
Im zweiten Schritt aus dem Passwort einen Passwortkey per Hash erzeugen lassen, der den Datenkey verschlüsselt.

Zu den Hashfunktionen: Wieso SHA512? Der Hash ist - wie der Name schon sagt - 512 Bit lang. Und nicht 128 Zeichen wie oben geschrieben. Wenn Du einen AES Schlüssel brauchst nimm SHA256, der hat 256 Bit Output, was der längstmögliche AES Schlüssel ist.

Was ich nicht verstanden habe: Wird das Passwort nur zur Entschlüsselung oder auch zu einer generellen vorherigen Autorisierung benötigt? Wenn Zweiteres zutrifft, kannst Du ja den SHA512 des Passwortes nehmen und abspeichern. Wenn Du es selber machst, vergiss nicht Salz einzustreuen, damit Hash-Tables unwirksam werden.

Für den Datenkey solltest Du ebenfalls eine Prüfsumme entweder so abspeichern oder mit verschlüsseln. Denn sollte bei der Entschlüsselung etwas schief gehen (falsche Passwortkey, falscher Ciphertext) kommen als Datenkey zwar Bytes raus, die als Schlüssel taugen, aber die Daten nicht korrekt entschlüsseln und Du weist nicht auf welcher Ebene der Fehler passiert ist.

--- [2016-01-22 13:01 CET] Automatisch zusammengeführter Beitrag ---

@alter_Bekannter:Also ich lese daraus, dass mein Key den ich für AES benötige 128/192/256 bit lang sein muss. Und nicht anders.
Korrekt. AES ist nur für diese Schlüssellängen definiert.
 

Asseon

Draic Kin

Registriert
14 Juli 2013
Beiträge
10.353
Ort
Arcadia
Was du brauchst ist eine "key derivation function" wie z.B. PBKDF2 oder Argon2 wobei letzteres noch ein wenig jung ist, für ernsthafte Benutzung.

Das fällt btw bereits unter die erste Regel für Kryptographie: "Don't roll your own crypto!"

bcrypt alleine tuts auch nicht, weil das ist eine hash funktion und keine key derivation function.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
Mal eine allgemeine Frage zu Salting in den Raum geworfen, hier am Beispiel mit PHP 5.5:

Was mir ja immer, rein vom Verständnis einen Schluckauf verursacht, wie wird aus einem versalzenen Hash/Password (hier PHP), wenn der Salt jedesmal Random ist, wieder das ursprüngliche Passwort errechnet?

Letztlich müsste ja die PHP password_verify immer den Salt kennen bzw. ermitteln mit Trial and Error - bis der vorher, mit password_hash("PassString", "Algo" oder PASSWORD_DEFAULT oder PASSWORD_BCRYPT) generierte, Hash - so fern man wie vorgeschlagen einen Random Salt durch die "password_hash" generieren lässt, entschlüsselt werden kann.

Irgendwie komme ich da nicht mit meinem Verständnis hinterher.... wie man nun auf dem Salt kommen kann. :)

Außer das man dazu rät diese Funktionen ab PHP 5.5 anstelle von crypt() - API direkt zu verwenden weil leichter zu handhaben...

--- [2016-01-23 09:02 CET] Automatisch zusammengeführter Beitrag ---

Zu den Hashfunktionen: Wieso SHA512? Der Hash ist - wie der Name schon sagt - 512 Bit lang. Und nicht 128 Zeichen wie oben geschrieben. Wenn Du einen AES Schlüssel brauchst nimm SHA256, der hat 256 Bit Output, was der längstmögliche AES Schlüssel ist.

Mein Fehler, ich bin hierbei von 128 Zeichen (warum auch immer) ausgegangen, in jedem Fall sind es genau die Hälfte mit 64 Zeichen.

Hab da die Zahlen etwas wild durcheinander geworfen/gerechnet...

--- [2016-01-23 09:07 CET] Automatisch zusammengeführter Beitrag ---

Hab gestern Abend noch etwas auf stackexchange gelesen.
Man macht es wohl gerne so, dass man einen Key nimmt, damit die Daten verschlüsselt und mit dem Benutzerpasswort dann den Key verschlüsselt. Das hat den Vorteil, dass die Daten nicht neu verschlüsselt werden müssen, wenn das Passwort geändert wird, sondern nur der Key.

Also: passwort ---(bcrypt)---> hash ---(some encryption)---> key ---(aes)---> daten

Sorry, für die Fullquote, aber ich sehe darin den Nachteil, der Vorteil ist ja der wechselbare Key, das alle Verschlüsslung nur auf dem AES basiert, in diesem Fall ist die Sicherheit der Daten wieder (relativ) verringert wenn man mit Brutefoce den AES mit maximal 16 Zeichen herausfischen wollen würde?!

Noch ein anderer Artikel dazu, weil Ebay 20 Zeichen verwendet:
http://www.malwaretech.com/2014/05/the-reason-for-maximum-password-lengths.html
 
Zuletzt bearbeitet:

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.510
Was mir ja immer, rein vom Verständnis einen Schluckauf verursacht, wie wird aus einem versalzenen Hash/Password (hier PHP), wenn der Salt jedesmal Random ist, wieder das ursprüngliche Passwort errechnet?
Gar nicht :D. Das ist gerade der Sinn von kryptographischen Hashfunktionen.

Du meinst vermutlich, wie man aus password + salz auf den hash kommt, wenn der hash unbekannt ist. Auch hier ist die Antwort: Gar nicht ;). Der Salz wird in jedem Falle gespeichert, so wie der Hash.
Das ist von Vorteil, selbst wenn die salts zusammen mit den hashes an einen Angreifer gehen.

krypt. Hashes (ab jetzt immer nur hash) haben ja die Eigenschaft 'password -> hash' lässt sich gut machen, 'hash->password' ist aber extrem aufwendig. Aber man kann natürlich vorab schonmal alle passwörter durchgehen und die hashes dazu speichern, wenn man dann mal an hashes kommt hat man direkt eine tabelle zu welchem passwort ein hash gehört = rainbow tables.
Mit einem salt lauten die gehashten werte aber nicht mehr "ingehamburg123", sondern "ingehamburg123vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa" und soweit reicht die rainbow table ganz sicher nicht ;).

Wenn der salt konstant ist, dann kann man aber natürlich seine eigene rainbow table aufstellen, von "avI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa" bis "zzzzzzzzzzzzvI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa" in dem man einfach alle diese werte hasht. Dauert lange, aber vllt kenn man ja wen der nen botnetz vermietet.

Wenn aber jedes passwort seinen eigenen salt hat geht das nicht mehr, dann muss man das Spielchen für jedes Passwort von vorne machen = pures bruteforces. Das dauert dann richtig lange, hashes sind ja immerhon so gebaut, dass sie langsam sind.

TL;DR
So beim zweiten lesen habe ich das Gefühl das war dir alles klar :D, vllt hilft es ja jemand anders.
Die PHP password_hash, so wie ich das sehe, gibt dir hash+salt als Wert zurück, vllt beantwortet das deine Frage ;).
 
Zuletzt bearbeitet:

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.764
Ort
in der Zukunft
Ich kann mir nur vorstellen das der Salt aus einer Festen Anweisung gebildet wird.
Ich denke das es was mit den Kosten zu tun hat - es wird z.B. für 0,5 sekunden von vorne nach hinten durch das pw itariert und ab der stelle die raus kommt jeder 2. Buchstabe genommen bis 5 Zeichen als Salt zusammen sind...

K.a ist ja nur eine Idee aber in der Richtung

Das Ganze lässt sich dann für dieses System immer wieder passend reproduzieren und für jedes pw gibt es einen eigenen salt
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
TL;DR
So beim zweiten lesen habe ich das Gefühl das war dir alles klar :D, vllt hilft es ja jemand anders.
Die PHP password_hash, so wie ich das sehe, gibt dir hash+salt als Wert zurück, vllt beantwortet das deine Frage ;).

Du wirst schmunzeln, aber soooo klar war mir das nicht. Deine Antwort bezüglich der Konstruktion das statt des reines Hashes auch der Salz "mit eingestreut" wird in den "abgespeicherten" Vergleichswert fürs Verfiy ergibt dann nämlich wieder auch Sinn und auch, das dann die Rainbowtables unnütz werden weil der Salt erst identifiziert bzw. vom Hash+Salt abgezogen werden müsste um dann den Hash erfolgreich knacken zu können.

So in etwa deute ich das jetzt mal. :)

Und danke das du nochmal genau schreibst das der Salt (wohl) mitgespeichert wird, anders ließe sich das Passwort ja auch nicht aus dem Verschlüsselten erfolgreich und zeitnah rückrechnen.

Jedenfalls vielen Dank für deine Antwort, jetzt hab ich einen Knoten weniger im Kopf... :T

@drfuture:
Vermutlich wird auch deßhalb im Rückgabewert von password_hash nebem Algo die Kosten gespeichert, sonst wüsste das Verify ja ab einem Punkt nicht wissen, wann das Passwort wirklich korrekt übergeben wurde.

Ansonsten hast du Recht, der Salt wieder jedesmal neu berechnet, wobei ich nicht glaube das dieser auf dem Password basiert, sonst hätte jede Zeichenkette einen "bestimmten" Salt und das würde es Angreifern wieder ermöglichen die Salts leichter zurückzuverfolgen, daher sollten diese ja "zufällig" wie möglich sein. ;)

Irgendwo habe ich auch gelesen das manch etwas auf "Hintergrundrauschen" der Hardware basiert, trifft vermutlich nicht auf PHP zu aber man kann ja genug Werte heranziehen Uhrzeit, Datum, Timestamp + Servername + PHP Version + .... - was es erlaubt etwas "zufällig" plus das Hinzumischen mit Random (in dessen Grenzen der Zufälligkeit) abzumischen und als Start/Streufaktoren für weitere Verschlüsslung zu verwenden.
 

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
581
  • Thread Starter Thread Starter
  • #20
Du kannst den Schlüssel ja in 4x32 Zeichen/Byte = 256 bit Stücke zerlegen und diese speichern.
Das habe ich mir dann auch gedacht und wollte das eigentlich auch so machen, wird wohl mit in die Antworten von den anderen hineinfließen, indem ich alles was so geschrieben wurde, so gut wie möglich kombiniere.

@Roin: ich würde sagen du brauchst für dein Problem schlicht nur 2 unterschiedliche Hashverfahren...

Du nimmst dein Passwort, bildest einen Hash mit z.B. Whirlpool > Speicherst den Hash
nimmst das gleiche Passwort und Hasht es mit SHA-512 und nimmst den Hash davon als Key für die AES verschlüsselten Daten.
Sowas in der Richtung hatte ich ja vor, nur dass ich halt die zum Verschlüsseln gedachte Zeichenkette vorher ebenfalls verschlüsselt habe - ob das jetzt besser ist sei dahingestellt - vermutlich nicht.

Hab gestern Abend noch etwas auf stackexchange gelesen.
Man macht es wohl gerne so, dass man einen Key nimmt, damit die Daten verschlüsselt und mit dem Benutzerpasswort dann den Key verschlüsselt. Das hat den Vorteil, dass die Daten nicht neu verschlüsselt werden müssen, wenn das Passwort geändert wird, sondern nur der Key.

Also bei Programmerststart einen Datenkey erzeugen lassen, mit dem von da an alle Programmdaten verschlüsselt werden.
Im zweiten Schritt aus dem Passwort einen Passwortkey per Hash erzeugen lassen, der den Datenkey verschlüsselt.
  • Also ich erzeuge per Random einen Datenkey
  • Dann erzeuge ich einen Salt per Random
  • Dann nehme ich das Passwort und den Salt und hashe die zusammen
  • Ich verschlüssele den Datenkey mit dem Hash
  • Mit dem "normalen" Datenkey verschlüssele ich alle anderen Daten
  • fertig
Richtig so?

ZWenn Du einen AES Schlüssel brauchst nimm SHA256, der hat 256 Bit Output, was der längstmögliche AES Schlüssel ist.
Habe ich nicht drüber nachgedacht - wäre vielleicht ganz sinnvoll.

Wird das Passwort nur zur Entschlüsselung oder auch zu einer generellen vorherigen Autorisierung benötigt?
Ich frage am Anfang einmal das Passwort ab, ob auf die Programmdaten zugegriffen werden darf. Dann wird es in einer Variable zwischengespeichert und bei Bedarf die entsprechenden Daten entschlüsselt oder verschlüsselt (nichts entschlüsseltes wird auf der Festplatte gespeichert - die entschlüsselten Daten existieren nur im Arbeitsspeicher)

Für den Datenkey solltest Du ebenfalls eine Prüfsumme entweder so abspeichern oder mit verschlüsseln.
Also im einfachsten Fall speichere ich irgendwo einige Bytes, die ich fest in meinen Code integriere und dann entschlüsseln lasse und somit feststelle, ob das Decrypten erfolgreich war, richtig? Macht es das nicht etwas unsicherer, wenn ich einen festen Wert habe, der zu einem verschlüsselten Text bekannt ist?

Was du brauchst ist eine "key derivation function" wie z.B. PBKDF2
Erkläre mir mal mehr dazu - ist es nicht einfacher die oben genannten Sachen so durchzuführen? Ich denke, wenn ich die Schritt für Schritt durchgehe, habe ich was ziemlich sicheres und es ist auch nicht allzu kompliziert - glaube ich zumindest. Ich bin mir nicht ganz sicher, ob ich hier überall durchgestiegen bin.

Aber ich sehe darin den Nachteil, der Vorteil ist ja der wechselbare Key, das alle Verschlüsslung nur auf dem AES basiert, in diesem Fall ist die Sicherheit der Daten wieder (relativ) verringert wenn man mit Brutefoce den AES mit maximal 16 Zeichen herausfischen wollen würde?!
Da warte ich mal auf eine Antwort zu - ich habe nämlich auch noch nicht wirklich verstanden, wie eine Verschlüsselung mit lediglich 128 (oder 256) Bit als Schlüssel sicher sein kann. Aber AES gehört ja angeblich zu den sichersten Verfahren derzeit.

Der Salz wird in jedem Falle gespeichert, so wie der Hash.
Super Info! Das habe ich bisher nämlich auch nie verstanden gehabt. Wie lang sollte denn ein Salt so sein? 20 Zeichen? 100 Zeichen?

Der Salt wieder jedesmal neu berechnet
Ist es denn dann zum Beispiel sinnvoll bei jedem Programmstart einen neuen Salt zu generieren und mit diesem dann erneut das Passwort zu verschlüsseln? Also so, dass sich der gespeicherte Hash immer wieder ändert? Oder ist das dann einfach zu viel des guten und sorgt nur für weitere mögliche Fehlerquellen?

Gibts es eigentlich die common apache-packages standardmäßig in der JDK 8? Dann könnte man nämlich die Base64 daraus nehmen, da die aktuell verwendeten, eventuell demnächst auslaufen?
Kann mir jemand dazu noch etwas sagen?
 
Zuletzt bearbeitet:
Oben