Crittografia in Dart

Di - 13 April 2013 - in

Giunti quasi alla conclusione di questa rubrica, oggi parleremo di dart:crypto, libreria che contiene definizioni di funzioni relative alla crittografia; pensando agli ambiti di applicazione della crittografia emerge un certo numero di esempi, ma nell’articolo di oggi ci limiteremo a parlare di autenticazione e immagazzinamento di dati personali.

Al momento i metodi disponibili sono:

  • MD5
  • SHA-1
  • SHA-256

ed esiste il supporto per l’autenticazione basata su messaggi hash-based, HMAC.

Vediamo subito qualche esempio pratico iniziando con un programma che verifichi che la password inserita sia corretta. Lo scenario è il seguente: al momento della registrazione, la password dell’utente viene codificata in MD5 e all’hash viene aggiunta una stringa arbitraria — detta salt — e la stringa risultante viene nuovamente codificata in MD5; al momento del login, saranno eseguite le stesse operazioni sulla password inserita e se l’hash ottenuto sarà identico all’hash memorizzato l’utente risulterà autenticato.

import 'dart:crypto';

void main() {
  if(login("lamiapassword")) {
    print("Sei autenticato!");
  } else {
    print("Password errata.");
  }
}

bool login(String password) {
  final String salt = "4ll3b041c";
  String hashMemorizzato = "e16c72318c0665c2dcfca6e988133e54";
  String passwordHash;
  String saltedPasswordHash;
  MD5 md = new MD5();
  md.add(password.codeUnits);
  passwordHash = CryptoUtils.bytesToHex(md.close(););
  md = md.newInstance();
  md.add(( passwordHash + salt ).codeUnits);
  saltedPasswordHash = CryptoUtils.bytesToHex(md.close());
  if ( saltedPasswordHash == hashMemorizzato ) return true;
  return false;
}

Le variabili di login():

  • salt, la stringa arbitraria e immutabile da aggiungere all’hash della password inserita;
  • hashMemorizzato, l’hash memorizzato nel database al momento della registrazione dell’utente
  • passwordHash, l’hash della password inserita
  • saltedPasswordHash, l’hash della stringa passwordHash concatenata a salt;

md rappresenta l’istanza di MD5() — che implementa l’interfaccia Hash()
ed i metodi utilizzati sono .add() e .close(); il primo aggiunge i dati espressi in code points da codificare, il secondo invece termina il calcolo dell’hash e ne restituisce la lista di bytes.

Avendo utilizzato il metodo statico CryptoUtils.bytesToHex() per convertire in formato stringa l’output di md.close() notiamo una proprietà interessante di String, ovvero la conversione automatica da hex a testo; provando a stampare \x61\x62\x63 otterremo infatti abc.

Passiamo ora ad un esempio un po’ più complesso ovvero l’autenticazione tramite protocollo OAuth all’API di Twitter: dati il consumerKey e il consumerSecret dell’applicazione Twitter alla quale vogliamo accedere, questa funzione restituisce un request_token URL valido (cfr oauth/request_token).

String getRequestUrl(String consumerKey, String consumerSecret){
  Random rndm = new Random();

  DateTime date = new DateTime.now();
  String requestTokenUrl = "https://api.twitter.com/oauth/request_token";
  int oauthTimestamp = date.millisecondsSinceEpoch~/1000;

  MD5 md5 = new MD5();
  md5.add([rndm.nextInt(99)]);

  String nonce = CryptoUtils.bytesToHex(md5.close());
  String oauthSignatureMethod = "HMAC-SHA1";
  String oauthVersion = "1.0";

  String sigBase = "GET&" + encodeUriComponent(requestTokenUrl) + "&"
  + encodeUriComponent(
      "oauth_consumer_key=" + encodeUriComponent(consumerKey)
      + "&oauth_nonce=" + encodeUriComponent(nonce)
      + "&oauth_signature_method=" + encodeUriComponent(oauthSignatureMethod)
      + "&oauth_timestamp=" + oauthTimestamp.toString()
      + "&oauth_version=" + oauthVersion
      );

  String sigKey = consumerSecret + "&";

  HMAC hmac = new HMAC(new SHA1(), sigKey.codeUnits);
  hmac.add(sigBase.codeUnits);

  String oauthSig = CryptoUtils.bytesToBase64((hmac.close()));
  String requestUrl = requestTokenUrl + "?"
    + "oauth_consumer_key=" + consumerKey
    + "&oauth_nonce=" + nonce
    + "&oauth_signature_method=" + oauthSignatureMethod
    + "&oauth_timestamp=" + oauthTimestamp.toString()
    + "&oauth_version=" + oauthVersion
    + "&oauth_signature=" + encodeUriComponent(oauthSig) ;

  return requestUrl;

}

Molti degli elementi utilizzati li conosciamo già, concentriamoci dunque sulla top-level function encodeUriComponent e la classe HMAC(): la prima funzione è definita in dart:uri e il suo compito è codificare una stringa in modo tale da renderla utilizzabile in una URL, e.g. ” ” => “%20”, “&” => “%26”, “~” => “%7E” e così via.

Per quanto riguarda la classe HMAC, il suo costruttore prende in ingresso l’algoritmo da utilizzare ed una chiave per la codifica. La logica è simile a quanto visto per MD5: il metodo .add() aggiunge dati da codificare e .close() restituisce l’hash. A differenza di quanto visto nell’esempio precedende, l’hash ottenuto, che utilizzeremo come OAuth signature sarà convertito in Base64.

Come sempre, il codice utilizzato in questo articolo è disponibile sull’account Engeene su GitHub.

Leave a Reply

Claudio d'Angelis Articolo scritto da

Programmatore e studente di Informatica, appassionato di musica, web e sistemi UNIX. Collabora con Googlab dall'Ottobre 2012.

Contatta l'autore

Previous post:

Next post: