Skip to content

Category archive for: Programmation

Java 8 sur Raspberry Pi : No soucy !

Je continue mes expériences avec la JVM sur Raspberry Pi : attaquons-nous au JDK 8.

Vous pouvez télécharger le « JDK 8 (with JavaFX) for ARM Early Access » à l’adresse suivante : http://jdk8.java.net/fxarmpreview/
Update : Un nouveau build est disponible ici : http://jdk8.java.net/download.html

Dézippez le tar.gz obtenu dans le répertoire de votre choix. Exemple :

cd lerepertoiredemonchoix
tar zxvf jdk-8-ea-b36e-linux-arm-hflt-29_nov_2012.tar.gz

Ensuite, une solution simple pour utiliser la VM est de faire pointer la variable d’environnement JAVA_HOME sur ce répertoire et d’ajouter le chemin $JAVA_HOME/bin à la variable PATH.

Mais on peut mieux faire : utiliser jenv

Jenv
Jenv va nous permettre de gérer plusieurs environnements d’exécution Java en fonction du répertoire d’où la JVM est lancée.
Pour l’installer, il suffit de suivre les instructions du site :

$ git clone https://github.com/hikage/jenv.git ~/.jenv
$ echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(jenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l

Il faut maintenant paramétrer les JVMs disponibles, ex :

$ jenv add /usr/lib/jvm/java-7-openjdk
openjdk32-1.7.0.17 added
$ jenv add /path/to/jdk1.8.0
oracle32-1.8.0-ea added

Reste maintenant à définir les JDKs à utiliser en fonction du répertoire.
Tout d’abord, définissons le JDK global :

$ jenv global oracle32-1.8.0-ea

Autant utiliser le JDK 1.8 partout (si on peut ainsi envoyer des rapports de bugs et s’assurer de la compatibilité de nos applications, c’est toujours ça de pris !).

Pour les applications nécessitant java 7, pas de problèmes :

$ cd uneapplicationjava7
$ jenv local openjdk32-1.7.0.17

Bon, on teste ?
En global :

$ cd
$ java -version
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b36e)
Java HotSpot(TM) Client VM (build 25.0-b04, mixed mode)

et en local :

$ cd uneapplicationjava7
$ java -version
java version "1.7.0_17"
OpenJDK Runtime Environment (IcedTea7 2.3.8) (ArchLinux build 7.u17_2.3.8-1-arm)
OpenJDK Zero VM (build 22.0-b10, mixed mode)

Et voilà, vous avez un java 8 utilisable à côté de votre java 7.

Note: Si vous obtenez une erreur « java: No such file or directory » à l’exécution de « java -version », exécutez la commande suivante en root :

ln /lib/ld-linux.so.3 /lib/ld-linux-armhf.so.3

Installation de ceylon sur un raspberry pi

A l’occasion de Devoxx France 2013, j’ai pu participer à un Hands-on Ceylon en présence de Stéphane Epardaud et Emmanuel Bernard.

De retour chez moi, je constate que OpenJDK7 est disponible pour sur Arch Linux pour Raspberry Pi. Pile ce qu’il faut pour mon serveur perso :

Photo de mon serveur Pi

Il est beau mon serveur. Pas une bête de course, mais bien pratique pour des petites expérimentations à distance.

Donc: OpenJDK7 est disponible. Ca tombe bien Ceylon nécessite Java 7, alors allons-y !!

Note : les instructions suivantes sont pour la distribution Arch Linux du Raspberry Pi.

Préparation

Nous allons avoir besoin d’unzip, wget et du jdk 7 :

pacman -S unzip
pacman -S wget
pacman -S jdk7-openjdk

Installation
Commencez par télécharger et dézipper Ceylon :

wget http://ceylon-lang.org/download/dist/1_0_Milestone5
unzip 1_0_Milestone5

Puis définissez les variables d’environnement (à reclaquer dans votre .bash_profile pour les conserver au redémarrage) :

export JAVA_HOME=/usr/lib/jvm/java-7-openjdk
export PATH=$PATH:$HOME/ceylon-0.5/bin

Premier test

C’est parti pour un « Hello, world ! »

mkdir -p helloCeylon/source
cd helloCeylon

Et voici le code du programme (nommez le source/hello.ceylon) :

void hello() {
    print("Hello, World!");
}

Simple, n’est-ce pas ?

Pour lancer la compilation :

ceylon compile source/hello.ceylon

Attendez un peu … et le compilateur devrait répondre :

Note: Created module default

Super, notre premier module est prêt !

Lançons-le pour vérifier (le hello passé au paramètre run est le nom de la méthode à appeler) :

ceylon run --run hello default

Attendez un peu … et …

Hello, World!

Yes, ça marche !!! Voilà, vous pouvez faire du Ceylon sur Raspberry Pi 😉

Déstresser en codant : des annotations à glisser dans les programmes Java

En développant, on est souvent amener à reprendre ou à être confronté :) au code d’autres personnes. Et il n’est pas rare de vouloir laisser un commentaire bien senti (ou totalement hypocrite) sur la qualité de ce code.

On peut aussi développer un bout de code et vouloir laisser un petit message à ceux qui tomberont sur ce code (pour expliquer les circonstances, atténuantes ou non, qui ont mené à ce programme).

Réjouissez-vous ! c’est possible, et de manière plus élégante qu’un simple commentaire java : avec des annotations.

Des annotations pour faire des commentaires
Parmi les annotations destinées à commenter le code, on trouve :

  • @AhaMoment
  • @LegacySucks
  • @Fail
  • @OhNoYouDidnt
  • @RTFM
  • @WTF

et le génial @BossMadeMeDoIt pour reporter la responsabilité sur son chef :).

Mais il y a aussi des annotations prenant des paramètres, par exemple (exemples issus du site) :

@AnimalsHarmedDuringTheMaking(
    number = 1,
    animal = "hamster",
    disclosure = "didn't feed Fermie for 2 days to finish this on time")
public class ConstantTimePrimalityTest {

ou

@ProbablyIllegalIn(number = 17, region = STATES)
public Money extractFractionalPennies(Account account);

et

@WrittenWhile("surfing Chatroulette")
public interface You {
  void spinRightRoundBabyRightRound(Me me);
}

Des annotations pour générer des actions

En fournissant un agent à la jvm (option -javaagent:gag-agent.jar), vous pouvez aussi déclencher des comportements « particuliers » :

@Roulette(
    probability = 0.005,
    exception = PayYourContractorException,
    message = "Courtesy reminder")
public Service getRockSolidService() {

lancera une exception avec une probabilité de 5 pour mille … bon, ça reste à utiliser avec des pincettes 😉
De son côté, l’annotation @Noop désactivera une méthode.

Et il y a encore plein d’autres annotations à explorer, jetez un coup d’oeil à la JavaDoc.

[ Google Annotations Gallery ]
[ La JavaDoc ]

Exemple de stockage de mot de passe en Java : Hashage et salage, est-ce suffisant ?

Récemment, plusieurs cas de vol de mots de passe ont frappé des sociétés du net; problème : les mots de passe étaient parfois stockés en clair dans la BDD.

Bon, nous faisons tous des erreurs de jeunesse, mais je m’étonne toujours que des gros sites omettent encore de brouiller les mots de passe, et quand je dis brouiller, je ne parle pas de chiffrement (qui suppose qu’une opération de déchiffrement est possible), mais de hashage et de salage !

Je ne prétends pas être un expert en sécurité, mais je vais essayer de vous fournir une structure de base pour l’authentification par mot de passe de vos utilisateurs (pour les pressés, l’implémentation est en fin d’article :) ).

Pourquoi brouiller le mot de passe ?

Je pense que la nécessité de ne pas stocker un mot de passe en clair est évidente pour tout le monde : ainsi l’accès à votre BDD ne suffit pas à avoir les informations de connexion d’un utilisateur (et je ne parle pas juste de piratage : un administrateur/développeur malintentionné ne peut pas lire vos mots de passe via un SELECT).

Comment s’y prendre ?

En utilisant une fonction de hachage, c’est à dire (dixit wikipedia) :

« une fonction particulière qui, à partir d’une donnée fournie en entrée, calcule une empreinte servant à identifier rapidement, bien qu’incomplètement, la donnée initiale »

La caractéristique principale d’une fonction de hachage en cryptographie est qu’on ne peut pas facilement effectuer l’opération inverse (à partir de DFCD3454, retrouver ‘Renard’) : exactement ce qu’il nous faut.

Quelle fonction de hachage utiliser ?

Il existe plein de fonctions de hachage (MD5, SHA-1, SHA-256, RIPEMD-160 …), mais certaines d’entre elles ne doivent plus être utilisées :

  • MD5 ne doit plus être utilisé comme algorithme de signature (collision en quelques secondes)
  • SHA-1 est aussi vulnérable à la collision
  • SHA-256 et RIPEMD-160 sont pour l’instant OK

Ce n’est pas suffisant !

Et non …

Les pirates ont à leur disposition des dictionnaires appelés « rainbow tables« .

L’idée est très simple : Imaginons que je récupère une liste de mots de passe hashés en SHA-1. Que faire pour les forcer ?

Et si j’avais une gigantesque base de mots de passe générés automatiquement et déjà hashés en SHA-1, je pourrais comparer directement les hashs et en déduire le mot de passe ?  C’est précisément le principe des rainbow tables : des tables précalculées de hashs qui permettent de trouver très rapidement le mot de passe initial.

Il faut donc rajouter une étape à notre algorithme …

Le salage

L’idée du salage est d’ajouter au mot de passe de l’utilisateur une chaîne aléatoire (le sel) qui va compliquer l’utilisation des rainbow tables sur le hash en multipliant le nombre de hash possibles pour un même mot de passe.

Un premier algorithme

Pour gérer nos mots de passe, il suffirait donc de :

  • demander son mot de passe à l’utilisateur
  • générer un sel
  • le stocker
  • l’ajouter au mot de passe
  • hasher le sel+mot de passe
  • stocker le résultat

Et pour vérifier un mot de passe :

  • demander son mot de passe à l’utilisateur
  • lire le sel enregistré
  • l’ajouter au mot de passe
  • hasher le sel+mot de passe
  • comparer le résultat obtenu avec le hashage stocké

Bon … c’est ok sur le principe, ce type d’algorithme est utilisable et est même assez répandu, mais il reste un gros problème : les fonctions de hashage à notre disposition …

Le problème avec les fonctions de hachage

Le souci est que les fonctions de hachage disponibles sont très rapides ! Oui, vous avez bien lu : la rapidité est un défaut.

Les fonctions de hachage ont généralement comme objectif d’être rapide (notamment pour générer des signatures), mais dans le cas d’une authentification, la vitesse est notre ennemi !

Si l’algorithme est rapide, le crackage est rapide; même si on rajoute un sel, une attaque par dictionnaire peut donc suffire à craquer notre mot de passe (la puissance de calcul actuelle est telle qu’avec la bonne carte graphique vous pouvez génére 2,5 millions de SHA-1 en une seconde)

Alors, une solution ?

Oui, il y a une solution : l’algorithme bcrypt.

En vulgarisant un peu, il s’agit d’une fonction de hachage reposant sur l’algorithme Blowfish. Elle est conçue de façon à pouvoir être ralentie en augmentant le nombre de passage dans la fonction (workfactor).

Elle embarque la gestion d’un salage pour contourner les rainbow tables. Mais cette fois, le temps de crackage d’une clé dépassera la centaine de millisecondes (voire plus, en fonction des paramètres de bcrypt).

En conclusion

Le plus simple actuellement est de gérer les mots de passe avec bcrypt. En java, vous pouvez utiliser la bibliothèque jbcrypt, dont voici le bloc de dépendance maven :

<dependency>
  <groupId>org.mindrot</groupId>
  <artifactId>jbcrypt</artifactId>
  <version>0.3m</version>
</dependency>

L’utilisation de la bibliothèque est assez simple (exemple issu du site de jbcrypt) :

// Hashage d'un mot de passe
String hashed = BCrypt.hashpw(password, BCrypt.gensalt());

// Il est possible d'augmenter la complexité (et donc le temps
// de traitement) en passant le "workfactor" en paramètre
// ici : 12 La valeur par défaut est 10
String hashed = BCrypt.hashpw(password, BCrypt.gensalt(12));

// Vérification d'un mot de passe à partir du hash
if (BCrypt.checkpw(candidate, hashed))
	System.out.println("It matches");
else
	System.out.println("It does not match");

Il suffit de stocker le hash du mot de passe, et tout est géré : le sel est embarqué dedans ainsi que le « workfactor ».

Update

Pour info, voici quelques temps de hachage sur ma machine (Core i5 à  2,4 GHz) :

workfactor = 5 – temps moyen = 4ms
workfactor = 6 – temps moyen = 6ms
workfactor = 7 – temps moyen = 13ms
workfactor = 8 – temps moyen = 26ms
workfactor = 9 – temps moyen = 51ms
workfactor = 10 – temps moyen = 102ms
workfactor = 11 – temps moyen = 217ms
workfactor = 12 – temps moyen = 422ms
workfactor = 13 – temps moyen = 820ms
workfactor = 14 – temps moyen = 1650ms
workfactor = 15 – temps moyen = 3259ms

A vous de moduler votre workfactor en fonction de vos besoins de qualité de service et de sécurité.

Tutorial : Premier développement Google AppEngine avec Go

Update: Quelques modifications sont à prendre en compte suite à l’arrivée de la version 1 de Go (vous pouvez utiliser l’application gofix pour mettre à jour votre code et changer la version d’api de 3 à go1).

Le but de cet article est d’expliquer comment mettre en ligne une application AppEngine en Go.

Je ne vais pas m’étendre sur l’installation du SDK et sur la structure du langage :

Et en avant pour cette première application.

Développement d’un générateur de triangle de Sierpinski en Go

Ce programme tout bête utilise un algorithme binaire tout simple pour générer un triangle de Sierpinski dont la taille est paramétrable (paramètre passé en ligne de commande). Pour plus de détails, suivez les commentaires du programme.

package main

import (
  "fmt"
  "strings"
  "strconv"
  "flag"
  "os"
)

func main() {
  // Analyse de la ligne de commande
  flag.Parse()

  // La variable chargée de stocker le nombre de lignes
  // à afficher
  var nbLignes int

  // Parsing des paramètres en ligne de commande
  if flag.NArg() == 0 {
    // Si pas d'arguments => 16 lignes
    nbLignes = 16
  } else {
    // Sinon, on prend la valeur passée en paramètres
    var err os.Error
    nbLignes, err = strconv.Atoi(flag.Arg(0))
    if err != nil {
      fmt.Println(err)
      os.Exit(1)
    }
  }

  // Algorithme d'affichage du triangle
  for i:=0; i<=(nbLignes - 1); i++ {
    // Padding pour redresser le triangle
    fmt.Print(strings.Repeat(" ", nbLignes -i))

    // Construction d'une ligne
    for j:=0;j<=i;j++ {
      if ((^i & j) != 0) {
        fmt.Print("  ")
      } else {
        fmt.Print(" *")
      }
    }
    fmt.Print("\n")
  }
}

Exemple de triangle généré :

                 *
                * *
               *   *
              * * * *
             *       *
            * *     * *
           *   *   *   *
          * * * * * * * *
         *               *
        * *             * *
       *   *           *   *
      * * * *         * * * *
     *       *       *       *
    * *     * *     * *     * *
   *   *   *   *   *   *   *   *
  * * * * * * * * * * * * * * * *

Modification du code pour tourner sur GAE

Nous allons maintenant nous attaquer à la version Google AppEngine.

Tout d’abord, installez le SDK (passez par le site en anglais pour pouvoir télécharger le sdk : http://code.google.com/intl/en/appengine/downloads.html)

Un programme Google AppEngine se base sur le package http de Go pour mettre en place un handler de connexion.
Exemple:

import "http"

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprint(w, "Hello");
}

En première intention, nous allons faire un programme qui affiche un triangle de Sierpinski de 16 lignes, non paramétrable.
Il faudra alors :

  • Modifier le nom de package (le package main est réservé aux programmes individuels)
  • Ajouter une procédure init()
  • Modifier la méthode main en handler HTTP
  • Supprimer le code de paramétrage du nombre de lignes
  • Supprimer les imports inutilisés

Voici ce que ça donne :

package handler

import (
  "fmt"
  "strings"
  "net/http"
)

func init() {
  http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
  nbLignes := 16

  fmt.Fprint(w, "<html><pre>");

  // Algorithme d'affichage du triangle
  for i:=0; i<=(nbLignes - 1); i++ {
    // Padding pour redresser le triangle
    fmt.Fprint(w, strings.Repeat(" ", nbLignes -i))

    // Construction d'une ligne
    for j:=0;j<=i;j++ {
      if ((^i & j) != 0) {
        fmt.Fprint(w,"  ")
      } else {
        fmt.Fprint(w," *")
      }
    }
    fmt.Fprint(w,"\n")
  }

  fmt.Fprint(w, "</pre></html>");
}

Publication de l’application sur Google AppEngine

Pour publier sur GAE, votre application doit respecter une arborescence du type :

sierpinski/
  app.yaml
  sierpinski/
    sierpinski.go

où app.yaml est le descripteur de l’application :

application: sierpinski-go
version: 1
runtime: go
api_version: go1

handlers:
- url: /.*
  script: _go_app

Les éléments à indiquer dans le fichier sont les suivants :

  • L’identifiant de l’application (que vous déclarez lors de l’enregistrement de l’application dans GAE)
  • La version de l’application (1 pour l’instant)
  • La version d’API de go à utiliser
  • Dans la partie handlers, il faut déclarer l’expression régulière servant à déclarer les pages devant être servies par le script; ici, toutes les pages

Si tout est ok, vous pouvez maintenant tester votre application :

dev_appserver.py sierpinski/

Connectez votre navigateur sur http://localhost:8080 et vous devriez obtenir votre triangle :)

Dernière étape : la publication.

Lancez alors la commande :

appcfg.py update sierpinski/

Après quelques secondes, votre application sera disponible sur GAE.

Le résultat :
[ http://sierpinski-go.appspot.com ]

Bonus : paramétrer le nombre de lignes à afficher

Pour se faire plaisir et pousser un peu plus le concept, ajoutons un paramètrage du nombre de lignes à afficher :

package handler

import (
  "fmt"
  "strings"
  "strconv"
  "net/http"
)

func init() {
  http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
  // Nombre de lignes par défaut
  nbLignes := 16

  // Parsing du nombre de ligne depuis l'url
  nbLignesParam := r.FormValue("nbLignes")
  if nbLignesParam != "" {
    nbConv, err := strconv.Atoi(nbLignesParam)
    if err == nil && nbConv <= 64 {
      nbLignes = nbConv
    }
  }

  fmt.Fprint(w, "<html><pre>");

  for i:=0; i<=(nbLignes - 1); i++ {
    // Padding pour redresser le triangle
    fmt.Fprint(w, strings.Repeat(" ", nbLignes -i))

    // Construction d'une ligne
    for j:=0;j<=i;j++ {
      if ((^i & j) != 0) {
        fmt.Fprint(w,"  ")
      } else {
        fmt.Fprint(w," *")
      }
    }
    fmt.Fprint(w,"\n")
  }

  fmt.Fprint(w, "</pre></html>");
}

(peu de modifications : ajout de l’import strconv et parsing de l’url avec request.FormValue)

On redéploie !

appcfg.py update sierpinski/

Si vous avez déjà déployé la version précédente, il faudra sélectionner la bonne version à publier dans la console appengine

Et voilà le résultat :
[ http://sierpinski-go.appspot.com/?nbLignes=64 ]

ou encore, la version 32 lignes :

                                 *
                                * *
                               *   *
                              * * * *
                             *       *
                            * *     * *
                           *   *   *   *
                          * * * * * * * *
                         *               *
                        * *             * *
                       *   *           *   *
                      * * * *         * * * *
                     *       *       *       *
                    * *     * *     * *     * *
                   *   *   *   *   *   *   *   *
                  * * * * * * * * * * * * * * * *
                 *                               *
                * *                             * *
               *   *                           *   *
              * * * *                         * * * *
             *       *                       *       *
            * *     * *                     * *     * *
           *   *   *   *                   *   *   *   *
          * * * * * * * *                 * * * * * * * *
         *               *               *               *
        * *             * *             * *             * *
       *   *           *   *           *   *           *   *
      * * * *         * * * *         * * * *         * * * *
     *       *       *       *       *       *       *       *
    * *     * *     * *     * *     * *     * *     * *     * *
   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

[ http://sierpinski-go.appspot.com/?nbLignes=32 ]