2009-03-14 13 views
0

Quoi qu'il en soit, je commence à faire des programmes Java (une programmation newb) et j'ai décidé de faire une simple classe utilitaire qui convertit le texte en chaînes SHA-1. Je prévois d'utiliser ceci pour crypter les mots de passe pour les bases de données. N'hésitez pas à commenter et j'aimerais apprendre de vous les gars. Voici mon code:Que pensez-vous de ma classe Java simple qui crypte le texte en SHA-1?

/* 
* Utility class that encrypts a string created for storing passwords 
* into databases 
*/ 

import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 

/** 
* 
* @author mamamambo 
*/ 
public final class Encryptor { 
    // Salt for extra security 
    private static String salt = "54L7"; 

    private static String encrptionAlgorithm = "SHA-1"; 

    private Encryptor() { } 

    public static String encrypt(String str) { 
     StringBuffer encryptedResult = new StringBuffer(); 
     String strWithSalt = salt + str; 

     try { 
      MessageDigest md = MessageDigest.getInstance(encrptionAlgorithm); 
      md.update(strWithSalt.getBytes()); 
      byte[] digest = md.digest(); 

      for (byte b : digest) { 
       int number = b; 
       // Convert negative numbers 
       number = (number < 0) ? (number + 256) : number; 
       encryptedResult.append(Integer.toHexString(number)); 
      } 

     } catch (NoSuchAlgorithmException ex) { 
      System.out.println(ex.toString()); 
     } 

     return encryptedResult.toString(); 
    } 
} 

Répondre

0

Tout d'abord, avoir un sel constant est juste la sécurité par l'obscurité. Vous devriez vraiment avoir un sel aléatoire unique pour chaque hash.

Aussi (je ne suis pas un expert Java mais), pourquoi md.digest() comprendrait-il des nombres négatifs?

+0

Les octets de Java sont signés de sorte qu'ils peuvent aller de -128 à +127. – James

+0

@James: oh, d'accord. étrange. =) –

3

Si vous utilisez ceci pour créer des mots de passe hachés, pourquoi ne pas simplement stocker les octets directement dans la base de données. L'avantage est que vous connaissez la taille du champ à l'avance. Je suis également d'accord que si vous faites l'effort d'utiliser des sels alors il est logique de créer et de stocker un sel unique pour chacun car cela rend les tables arc-en-ciel inutiles même si vous connaissez les sels (par exemple si votre base de données devient publique). Pour créer un code d'utilisation de sel aléatoire comme celui-ci:

//declaracations at top of class 
static Random srnd; 
//static constructor 
static { 
    srnd = new SecureRandom(); 
} 

//just before you need to use the salt 
byte[] salt = new byte[20]; 
srnd.nextBytes(salt); 

Notez que vous devez créer l'objet SecureRandom en dehors de la méthode et le mettre en cache, car il faut un certain temps pour initialiser. De plus, il n'est pas nécessaire d'ajouter les octets du salt à la chaîne avant d'appeler update, il suffit d'appeler update deux fois avec le salt dans le premier appel et le mot de passe à hacher dans le second.

Notez que si vous avez vraiment besoin de la sortie sous forme de chaîne, je vous recommande d'utiliser un Formatter pour vous assurer que chaque nombre est à 3 chiffres. Utilisez le code comme ceci:

StringBuilder sb = new StringBuilder(); 
Formatter formatter = new Formatter(sb); 
formatter.format("%03d", integerToOutput); 
String output = sb.toString(); 
+0

Salut James, comment suggérez-vous que je stocke des octets dans la base de données? (Par exemple, sur une base de données MySQL) – ajushi

+0

Je ne suis pas un utilisateur de MySQL moi, mais je trouve cela dans leurs documents: http://dev.mysql.com/doc/refman/5.1/en/binary-varbinary.html – James

+0

Je vais vérifier James, merci! – ajushi

1

Je suis d'accord avec les autres répondants de ne pas avoir un sel hardcoded. Si vous avez cela et que quelqu'un sait de quoi il s'agit (disons un employé mécontent), alors cette personne peut facilement récupérer les mots de passe en utilisant des techniques standard (peut-être une nouvelle table arc-en-ciel construite à partir de ce sel connu).

Bien que vous puissiez créer un sel aléatoire pour chaque utilisateur et le stocker avec l'enregistrement d'utilisateur, une autre approche consiste simplement à utiliser un champ qui ne changera pas, comme l'ID numérique de l'utilisateur. De cette façon, un attaquant qui acquiert la table utilisateur doit attaquer chaque utilisateur individuellement au lieu d'attaquer tous en même temps (c'est-à-dire qu'une seule table arc-en-ciel ne peut pas toucher toute la table utilisateur). N'utilisez pas d'adresse e-mail car cela pourrait changer, ce qui rendrait impossible l'authentification de l'utilisateur. Notez cependant qu'une fois que votre table d'utilisateur est compromise, si l'attaquant connaît le schéma salt and hash (ce que vous êtes hash, et le hash lui-même), il peut obtenir des mots de passe en commençant par les mots de passe populaires. version hachée/salée contre chaque enregistrement d'utilisateur.

j'ai écrit quelques articles sur ce sujet si vous êtes intéressé:

1

Plutôt que d'ajouter 256, utilisez les opérations de bits:

number &= 0xFF; 

Cela fonctionnera bien, car à ce moment-là, c'est tout Déjà été élargi à un int. Ou tout simplement

encryptedResult.append(Integer.toHexString((int)b & 0xFF)); 

la distribution est le sucre - les règles linguistiques obligent un casting de toute façon.

J'aime les opérations de bits parce que le code dit « coupant les bits supplémentaires » plutôt que « compter sur l'effet de l'addition des chiffres exprimés en notation complément à deux ».

Dans tous les cas, c'est encore une mauvaise idée: les nombres 0-15 seront convertis en une chaîne d'un octet, créant des ambiguïtés. Les séquences d'octets 0xBB 0x0B et 0x0B 0xBB seront converties en la même chose.

Utilisez à la place un codage base64. C'est une norme industrielle bien comprise et un peu plus efficace que ce que vous faites.

+0

salut paulmurray, comment j'implémenterais l'encodage en base64? – ajushi

+0

Je java? Vous tapez "bas64 encoder java" dans google. Au travail, j'utilise l'encodeur dans les bibliothèques Sun, car nous déployons sur Solaris et c'est OK. Alternativement, vous pouvez snarf une des plusieurs implémentations là-bas sur le web: http://www.source-code.biz/snippets/java/2.htm – paulmurray

0

Plutôt que de rouler votre propre pourquoi utilisez-vous pas jBCrypt. BCrypt est une solution éprouvée et éprouvée pour stocker les mots de passe.

La grande chose au sujet jBCrypt, est que stocke le sel dans le résultat lui-même. Deuxièmement, jBCrypt est juste un seul fichier Java.

Dans mon projet, je viens de copier le fichier dans mon répertoire util.