it.scoppelletti.programmerpower.security.CryptoUtils.java Source code

Java tutorial

Introduction

Here is the source code for it.scoppelletti.programmerpower.security.CryptoUtils.java

Source

/*
 * Copyright (C) 2010 Dario Scoppelletti, <http://www.scoppelletti.it/>.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package it.scoppelletti.programmerpower.security;

import java.security.*;
import java.security.spec.*;
import java.util.*;
import javax.crypto.*;
import org.apache.commons.codec.binary.*;
import it.scoppelletti.programmerpower.*;
import it.scoppelletti.programmerpower.reflect.*;
import it.scoppelletti.programmerpower.security.spi.*;
import it.scoppelletti.programmerpower.types.*;

/**
 * Funzioni di utilit&agrave; per la crittografia.
 * 
 * <P>La classe {@code CryptoUtils} consente di istanziare i principali oggetti
 * <ACRONYM TITLE="Java Cryptography Architecture">JCA</ACRONYM> in base ai
 * parametri impostati in una collezione di propriet&agrave; {@code Properties}
 * e utilizzando un modello 
 * <ACRONYM TITLE="Service Provider Interfaces">SPI</ACRONYM>; questo approccio
 * consente di mantenere il codice sorgente delle procedure il pi&ugrave;
 * possibile indipendente dagli specifici algoritmi di crittografia
 * adottati.</P>
 *
 * <H4 ID="idAlg">1. Algoritmi di crittografia</H4>
 *
 * <P>Con un algoritmo di crittografia <DFN>simmetrica</DFN> (o <DFN>a chiave
 * segreta</DFN>), la stessa chiave riservata &egrave; utilizzata sia per
 * cifrare che per decifrare i dati.</BR>
 * <P>Con un algoritmo di crittografia <DFN>asimmetrica</DFN> (o <DFN>a chiave
 * pubblica</DFN>), si utilizza una coppia di chiavi (pubblica, privata) e i
 * dati cifrati con una delle chiave possono essere decifrati con
 * l&rsquo;altra.<BR>
 * Gli algoritmi asimmetrici sono normalmente pi&ugrave; lenti di quelli
 * simmetrici perch&eacute; non sono progettati per proteggere in modo
 * efficiente grandi quantit&agrave; di dati: nella pratica, gli algoritmi
 * asimmetrici sono usati per scambiare chiavi segrete per inizializzare gli
 * algoritmi simmetrici.</P>
 *  
 * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
 * <THEAD>
 * <TR>
 *     <TH>Codice</TH>
 *     <TH>Descrizione</TH>     
 * </TR>
 * </THEAD>
 * <TBODY>
 * <TR>
 *      <TD>{@code AES}</TD>
 *      <TD>Algoritmo <ACRONYM TITLE="Advanced Algorithm Standard">AES</ACRONYM>
 *      secondo le specifiche
 *      <ACRONYM TITLE="Federal Information Processing Standard">FIPS</ACRONYM>
 *      197; l&rsquo;algoritmo &egrave; noto anche come algoritmo
 *      {@code Rijndael} di Joan Daemen e Vincent Rijmen.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}, {@link #getKey}, {@link #getKeyGenerator}</DD>
 *      </DL>
 *      </TD>      
 * </TR> 
 * <TR>
 *      <TD>{@code AESWrap}</TD>
 *      <TD>Algoritmo di <DFN>incartamento</DFN> di una chiave AES descritto da
 *      <ACRONYM TITLE="Request For Comment">RFC</ACRONYM> 3394.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}</DD>
 *      <DL>
 *      </TD> 
 * </TR>
 * <TR>
 *      <TD>{@code ARCFOUR}</TD>
 *      <TD>Cifratore di flusso ARCFOUR descritto da K. Kaukonen e R. Thayer e
 *      che si ritiene completamente interscambiabile con la cifratura
 *      <ACRONYM TITLE="Ron's Code 4">RC4</ACRONYM> sviluppata da Ron
 *      Rivest.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}, {@link #getKey}, {@link #getKeyGenerator}</DD>
 *      </DL>
 *      </TD>      
 * </TR> 
 * <TR>
 *      <TD>{@code Blowfish}</TD>
 *      <TD>Cifratore a blocchi Blowfish progettato da Bruce Schneier.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}, {@link #getKey}, {@link #getKeyGenerator}</DD>
 *      </DL>
 *      </TD>      
 * </TR>
 * <TR>
 *      <TD>{@code DES}</TD>
 *      <TD>Algoritmo <ACRONYM TITLE="Digital Encryption Standard">DES</ACRONYM>
 *      descritto da FIPS 46-3.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}, {@link #getKey}, {@link #getKeyGenerator}</DD>
 *      <DL>
 *      </TD>      
 * </TR>  
 * <TR>
 *      <TD>{@code DESede}</TD>
 *      <TD>Algoritmo <ACRONYM TITLE="Triple DES">3DES</ACRONYM> implementato
 *      dall&rsquo;applicazione dell&rsquo;algoritmo DES per tre volte con tre
 *      distinte sotto-chiavi.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}, {@link #getKey}, {@link #getKeyGenerator}</DD>
 *      </DL>
 *      </TD>      
 * </TR>
 * <TR>
 *      <TD>{@code DESedeWrap}</TD>
 *      <TD>Algoritmo di incartamento di una chiave 3DES descritto da RFC
 *      3217.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}</DD>
 *      </DL>
 *      </TD> 
 * </TR>  
 * <TR>
 *      <TD>{@code DiffieHellman}</TD>
 *      <TD>Accordo delle chiavi di Diffie-Hellman definito da
 *      <ACRONYM TITLE="Public-Key Cryptography Standards">PKCS</ACRONYM>
 *      &#35;3, ver. 1.4.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getKey}, {@link #getKeyPairGenerator}</DD>
 *      </DT>
 *      </TD>            
 * </TR> 
 * <TR>
 *      <TD>{@code DSA}</TD>
 *      <TD>Algoritmo <ACRONYM TITLE="Digital Signature Algorithm">DSA</ACRONYM>
 *      definito da FIPS 186-2.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getKey}, {@link #getKeyPairGenerator}</DD>
 *      </DL>
 *      </TD>            
 * </TR> 
 * <TR>
 *      <TD>{@code EC}</TD>
 *      <TD>Algoritmo della curva ellittica definito da <ACRONYM
 *      TITLE="Standards for Efficient Cryptography Group">SECG</ACRONYM>.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getKey}, {@link #getKeyPairGenerator}</DD>
 *      </DL>
 *      </TD>
 * </TR>
 * <TR>
 *      <TD>{@code ECIES}</TD>
 *      <TD>Schema di crittografia integrato della curva ellittica.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}</DD>
 *      </DL>
 *      </TD>
 * </TR> 
 * <TR>
 *      <TD>{@code HmacMD5}</TD>
 *      <TD>Algoritmo
 *      <ACRONYM TITLE="Hashed Message Authentication Code">HMAC</ACRONYM>
 *      definito da RFC 2104 con codifica
 *      <ACRONYM TITLE="Message Digest 5">MD5</ACRONYM>.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getKey}, {@link #getKeyGenerator}</DD>
 *      </DL>
 *      </TD>      
 * </TR> 
 * <TR>
 *      <TD>{@code HmacSHA1}, {@code HmacSHA256}, {@code HmacSHA384},
 *      {@code HmacSHA512}</TD>
 *      <TD>Algoritmo HMAC definito da RFC 2104 con codifica
 *      <ACRONYM TITLE="Secure Hash Algorithm">SHA</ACRONYM> nella versione
 *      specificata dal codice stesso.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getKey}, {@link #getKeyGenerator}</DD>
 *      </DL>
 *      </TD>            
 * </TR>
 * <TR>
 *     <TD>{@code PBEWith}<VAR>digest</VAR>{@code And}<VAR>encryption</VAR>,
 *     {@code PBEWith}<VAR>prng</VAR>{@code And}<VAR>encryption</VAR></TD>
 *     <TD>Algoritmo <ACRONYM TITLE="Password Based Encryption">PBE</ACRONYM>
 *     caratterizzato da un algoritmo di codifica <VAR>digest</VAR>, oppure da
 *     un generatore di numeri pseudo-casuali <VAR>prng</VAR>, e da un
 *     algoritmo di crittografia <VAR>encryption</VAR>. Alcune possibili
 *     configurazioni sono definite da PKCS &#35;5, ver. 1.5 e 2.0.
 *     
 *     <DL>
 *     <DT><B>Vedi anche:</B></DT>
 *     <DD>{@link #getCipher}, {@link #getKey}</DD>
 *     </DL>
 *     </TD>
 * </TR> 
 * <TR>
 *     <TD>{@code PBKDF2WithHmacSHA1}</TD>
 *     <TD>Algoritmo PBE definito da PKCS &#35;5, ver. 2.0.
 *     
 *     <DL>
 *     <DT><B>Vedi anche:</B></DT>
 *     <DD>{@link #getKey}</DD>
 *     </DL>
 *     </TD>
 * </TR> 
 * <TR>
 *      <TD>{@code RC2}</TD>
 *      <TD>Algoritmo di crittografia a dimensione variabile della chiave
 *      <ACRONYM TITLE="Ron's Code 2">RC2</ACRONYM> sviluppato da Ron Rivest per
 *      la <ACRONYM TITLE="Rivest, Shamir & Adleman">RSA</ACRONYM> Data
 *      Security, Inc. e descritto da RFC 2268.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}, {@link #getKey}, {@link #getKeyGenerator}</DD>
 *      </DL>
 *      </TD>      
 * </TR>
 * <TR>
 *      <TD>{@code RC4}</TD>
 *      <TD>Algoritmo di crittografia a dimensione variabile della chiave RC4
 *      sviluppato da Ron Rivest per la RSA  Data Security, Inc.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}</DD>
 *      </DL>
 *      </TD>      
 * </TR> 
 * <TR>
 *      <TD>{@code RC5}</TD>
 *      <TD>Algoritmo di crittografia a dimensione variabile della chiave
 *      <ACRONYM TITLE="Rivest Cipher 5">RC5</ACRONYM> sviluppato da Ron Rivest
 *      per la RSA  Data Security, Inc. e definito da RFC 2040.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}</DD>
 *      </DL>
 *      </TD>      
 * </TR> 
 * <TR>
 *      <TD>{@code RSA}</TD>
 *      <TD>Algoritmo RSA definito da PKCS &#35;1.
 *      
 *      <DL>
 *      <DT><B>Vedi anche:</B></DT>
 *      <DD>{@link #getCipher}, {@link #getKey},
 *      {@link #getKeyPairGenerator}</DD>
 *      </DL>
 *      </TD>      
 * </TR>   
 * </TBODY>
 * </TABLE></P> 
 *
 * <H4>2. Cifratori a blocchi e cifratori di flusso</H4>
 * 
 * <P>I cifratori <DFN>a blocchi</DFN> processano un blocco intero di dati per
 * volta (normalmente i blocchi sono lunghi anche molti byte).<BR>
 * I cifratori <DFN>di flusso</DFN> processano i dati di input in piccole
 * unit&agrave; alla volta (tipicamente un byte).</P>
 *  
 * <H4 ID="idMode">3. Modalit&agrave; degli algoritmi di cifratura</H4>
 * 
 * <P>Utilizzando un semplice cifratore a blocchi, due blocchi di dati in chiaro
 * identici producono sempre due blocchi di dati cifrati identici, ma le
 * ripetizioni di blocchi identici possono facilitare gli analisti che tentano
 * di violare la cifratura.<BR>
 * Una <DFN>modalit&agrave; di feedback</DFN> aggiunge complessit&agrave; ai
 * dati da cifrare alterando ogni blocco prima della cifratura in funzione del
 * blocco precedente; per la cifratura del primo blocco dei dati, si utilizza un
 * <DFN>vettore di inizializzazione</DFN> {@code IV}.</P>  
 *
 * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
 * <THEAD>
 * <TR>
 *     <TH>Codice</TH>
 *     <TH>Descrizione</TH>     
 * </TR>
 * </THEAD>
 * <TBODY>
 * <TR>
 *      <TD>{@code NONE}</TD>
 *      <TD>Nessuna modalit&agrave;.</TD>      
 * </TR> 
 * <TR>
 *      <TD>{@code CBC}</TD>
 *      <TD>Modalit&agrave; <ACRONYM TITLE="Cipher Block Chaining">CBC</ACRONYM>
 *      definita da FIPS 81.</TD>
 * </TR>
 * <TR>
 *      <TD>{@code CFB}, {@code CFB}<VAR>x</VAR><BR>
 *      {@code OFB}, {@code OFB}<VAR>x</VAR></TD>
 *      <TD>Le modalit&agrave; <ACRONYM TITLE="Cipher FeedBack">CFB</ACRONYM> e
 *      <ACRONYM TITLE="Output FeedBack">OFB</ACRONYM> sono definite da FIPS
 *      81. Queste modalit&agrave; consentono ai cifratori a blocco di
 *      crittografare i dati in unit&agrave; pi&ugrave;
 *      piccole dell&rsquo;effettiva dimensione dei blocchi del cifratore.
 *      L&rsquo;eventuale parametro <VAR>x</VAR> specifica il numero di bit da
 *      processare alla volta; se il parametro non &egrave; specificato,
 *      &egrave; utilizzato un valore di default definito dallo specifico
 *      provider JCA.<BR>
 *      Ad esempio, le modalit&agrave; CFB8 o OFB8, convertono un cifratore a
 *      blocchi in un cifratore di flussi orientato ai byte.</TD>
 * <TR>
 *      <TD>{@code CTR}</TD>
 *      <TD>Semplificazione della modalit&agrave; OFB per la quale il blocco di
 *      input &egrave; sostituito da un contatore.</TD>
 * </TR>
 * <TR>
 *      <TD>{@code CTS}</TD>
 *      <TD>Modalit&agrave; <ACRONYM TITLE="Cipher Text Stealing">CTS</ACRONYM>
 *      descritta nella seconda edizione del libro &ldquo;Applied
 *      Cryptography&rdquo; di Bruce Schneier (John Wiley and Sons, 1996).</TD>
 * </TR> 
 * <TR>
 *      <TD>{@code ECB}</TD>
 *      <TD>Modalit&agrave; <ACRONYM TITLE="Elettronic CodeBook">ECB</ACRONYM>
 *      definita da FIPS 81.</TD>
 * </TR>
 * <TR>
 *      <TD>{@code PCBC}</TD>
 *      <TD>Modalit&agrave;
 *      <ACRONYM TITLE="Propagating Cipher Block Chaining">PCBC</ACRONYM>
 *      definita da Kerberos ver. 4.</TD>
 * </TR>
 * </TBODY>
 * </TABLE></P>
 *   
 * <H4 ID="idPadding">4. Modalit&agrave; di riempimento degli algoritmi di
 * cifratura</H4>
 * 
 * <P>Per poter essere cifrati da un cifratore a blocchi, i dati devono essere
 * <DFN>allineati</DFN> per arrivare ad una dimensione multipla della dimensione
 * dei blocchi aggiungendo dei byte <I>di riempimento</I> (<DFN>padding</DFN>)
 * che sono poi rimossi dal processo di decifratura. L&rsquo;allineamento
 * pu&ograve; essere a carico dell&rsquo;applicazione oppure demandato al
 * cifratore impostando una modalit&agrave; di riempimento.</P>
 *   
 * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
 * <THEAD>
 * <TR>
 *     <TH>Codice</TH>
 *     <TH>Descrizione</TH>     
 * </TR>
 * </THEAD>
 * <TBODY>
 * <TR>
 *      <TD>{@code NoPadding}</TD>
 *      <TD>Nessun riempimento.</TD>
 * </TR>
 * <TR>
 *      <TD>{@code ISO10126Padding}</TD>
 *      <TD>Modalit&agrave; di riempimento per i cifratori a blocchi descritta
 *      dal par. 5.2 &ldquo;Block Encryption Algorithms&rdquo; della
 *      raccomandazione <ACRONYM TITLE="World Wide Web Consortium">W3C</ACRONYM>
 *      &ldquo;XML Encryption Syntax and Processing&rdquo;.</TD>      
 * </TR>
 * <TR>
 *      <TD>{@code OAEPPadding},
 * {@code OAEPWith}<VAR>digest</VAR>{@code And}<VAR>mgf</VAR>{@code Padding}
 *      </TD>
 *      <TD>Schema
 *      <ACRONYM TITLE="Optimal Asymmetric Encryption Padding">OAEP</ACRONYM>
 *      definito da PKCS &#35;1/RFC 3447; lo schema &egrave; caratterizzato da
 *      un algoritmo di codifica <VAR>digest</VAR> e da una funzione di
 *      generazione di maschera <VAR>mgf</VAR>.</TD>
 * </TR>
 * <TR>
 *      <TD>{@code PKCS1Padding}</TD>
 *      <TD>Schema di riempimento descritto da PKCS &#35;1 e utilizzato con
 *      l&rsquo;algoritmo RSA.</TD>
 * </TR>
 * <TR>
 *      <TD>{@code PKCS5Padding}</TD>
 *      <TD>Schema di riempimento descritto da PKCS &#35;5, ver. 1.5.</TD>
 * </TR> 
 * <TR>
 *      <TD>{@code SSL3Padding}</TD>
 *      <TD>Schema di riempimento definito dalla sezione 5.2.3.2 &ldquo;CBC
 *      block cipher&rdquo; del protocollo
 *      <ACRONYM TITLE="Secure Sockets Layer">SSL</ACRONYM>, ver. 3.0.</TD>
 * </TR>
 * </TBODY>
 * </TABLE></P>
 *     
 * @see   <A HREF="http://csrc.nist.gov/publications/PubsFIPSArch.html"
 *        TARGET="_blank">FIPS 46-3: Data Encryption Standard (DES)</A>
 * @see   <A HREF="http://csrc.nist.gov/publications/PubsFIPSArch.html"
 *        TARGET="_blank">FIPS 81: DES Modes of Operation</A>        
 * @see   <A HREF="http://csrc.nist.gov/publications/PubsFIPSArch.html"
 *        TARGET="_blank">FIPS 186-2: Digital Signature Standard (DSS)</A>          
 * @see   <A HREF="http://csrc.nist.gov/publications/PubsFIPS.html"
 *        TARGET="_blank">FIPS 197: Advanced Encryption Standard</A>
 * @see   <A HREF="http://www.rsa.com/rsalabs" TARGET="_blank">PKCS &#35;1: RSA
 *        Cryptography Standard</A>         
 * @see   <A HREF="http://www.rsa.com/rsalabs" TARGET="_blank">PKCS &#35;3:
 *        Diffie-Hellman Key Agreement Standard</A>
 * @see   <A HREF="http://www.rsa.com/rsalabs" TARGET="_blank">PKCS &#35;5:
 *        Password-Based Cryptography Standard</A>          
 * @see   <A HREF="http://www.ietf.org/rfc/rfc2040.txt" TARGET="_blank">RFC
 *        2040: The RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS Algorithms</A>        
 * @see   <A HREF="http://www.ietf.org/rfc/rfc2104.txt" TARGET="_blank">RFC
 *        2104: HMAC: Keyed-Hashing for Message Authentication</A>
 * @see   <A HREF="http://www.ietf.org/rfc/rfc2268.txt" TARGET="_blank">RFC
 *        2268: A Description of the RC2(r) Encryption Algorithm</A>
 * @see   <A HREF="http://www.ietf.org/rfc/rfc2898.txt" TARGET="_blank">RFC
 *        2898 / PKCS #5: Password-Based Cryptography Specification</A>                       
 * @see   <A HREF="http://www.ietf.org/rfc/rfc3217.txt" TARGET="_blank">RFC
 *        3217: Triple-DES and RC2 Key Wrapping</A>          
 * @see   <A HREF="http://www.ietf.org/rfc/rfc3394.txt" TARGET="_blank">RFC
 *        3394: Advanced Encryption Standard (AES) Key Wrap Algorithm</A>
 * @see   <A HREF="http://www.ietf.org/rfc/rfc3447.txt" TARGET="_blank">RFC
 *        3447: Public-Key Cryptography Standards (PKCS) #1: RSA
 *        Cryptography</A>        
 * @see   <A HREF="http://web.mit.edu/kerberos" TARGET="_blank">Kerberos</A>        
 * @see   <A HREF="http://www.secg.org" TARGET="_blank">SEC1: Elliptic Curve
 *        Cryptography</A>                               
 * @see   <A HREF="http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt"
 *        TARGET="_blank">A Stream Cipher Encryption Algorithm &quot;Arcfour&quot;</A>
 * @see   <A HREF="http://www.mozilla.org/projects/security/pki/nss/ssl"
 *        TARGET="_blank">SSL/TLS</A>
 * @see   <A HREF="http://www.schneier.com/blowfish.html" TARGET="_blank">The
 *        Blowfish Encryption Algorithm</A>
 * @see   <A HREF="http://www.w3.org/TR/xmlenc-core" TARGET="_blank">XML
 *        Encryption Syntax and Processing</A>         
 * @since 1.0.0
 */
public final class CryptoUtils {

    /**
     * Nome della propriet&agrave; sulla quale deve essere impostato il codice 
     * di un algoritmo di cifratura. Il valore della costante &egrave;
     * <CODE>{@value}</CODE>.
     * 
     * @see #getCipher
     */
    public static final String PROP_CIPHERALGORITHM = "alg";

    /**
     * Nome della propriet&agrave; sulla quale deve essere impostato il codice 
     * di una modalit&agrave; per un algoritmo di cifratura. Il valore della
     * costante &egrave; <CODE>{@value}</CODE>.
     * 
     * @see #getCipher
     */
    public static final String PROP_CIPHERMODE = "mode";

    /**
     * Nome della propriet&agrave; sulla quale deve essere impostato il codice 
     * di una modalit&agrave; di riempimento di un algoritmo di cifratura. Il
     * valore della costante &egrave; <CODE>{@value}</CODE>.
     * 
     * @see #getCipher
     */
    public static final String PROP_CIPHERPADDING = "padding";

    /**
     * Nome della propriet&agrave; sulla quale deve essere impostato il codice 
     * di un&rsquo;operazione di cifratura. Il valore della costante &egrave;
     * <CODE>{@value}</CODE>.
     * 
     * @see #getCipher
     * @see it.scoppelletti.programmerpower.security.CipherOperation
     */
    public static final String PROP_CIPHEROPERATION = "op";

    /**
     * Nome della propriet&agrave; sulla quale deve essere impostato il codice 
     * di un algoritmo di crittografia. Il valore della costante &egrave;
     * <CODE>{@value}</CODE>.
     * 
     * @see #getKeyGenerator
     * @see #getKeyPairGenerator
     */
    public static final String PROP_KEYALGORITHM = "alg";

    /**
     * Nome della propriet&agrave; sulla quale deve essere impostata la
     * dimensione della chiave in numero di bit. Il valore della costante
     * &egrave; <CODE>{@value}</CODE>.
     * 
     * @see #getKeyGenerator
     * @see #getKeyPairGenerator 
     */
    public static final String PROP_KEYSIZE = "key.size";

    /**
     * Nome della propriet&agrave; sulla quale deve essere impostato il nome di 
     * una classe che implementa l&rsquo;interfaccia {@code CryptoKeyFactory}.
     * Il valore della costante &egrave; <CODE>{@value}</CODE>.
     * 
     * @see #getCipher
     * @see #getKey
     * @see it.scoppelletti.programmerpower.security.spi.CryptoKeyFactory
     */
    public static final String PROP_KEYFACTORY = "key.factory";

    /**
     * Nome della propriet&agrave; sulla quale pu&ograve; essere impostato il
     * prefisso da applicare al nome delle propriet&agrave; interrogate da un
     * provider {@code CryptoKeyFactory}. Il valore della costante &egrave;
     * <CODE>{@value}</CODE>.
     * 
     * @see #getCipher
     * @see #getKey
     * @see it.scoppelletti.programmerpower.security.spi.CryptoKeyFactory
     */
    public static final String PROP_KEYFACTORY_PREFIX = "key.factory.prefix";

    /**
     * Nome della propriet&agrave; sulla quale deve essere impostato il nome di 
     * una classe che implementa l&rsquo;interfaccia
     * {@code AlgorithmParameterSpecFactory}. Il valore della costante &egrave;
     * <CODE>{@value}</CODE>.
     * 
     * @see #getCipher
     * @see #getKeyGenerator
     * @see #getKeyPairGenerator 
     * @see it.scoppelletti.programmerpower.security.spi.AlgorithmParameterSpecFactory
     */
    public static final String PROP_PARAMFACTORY = "param.factory";

    /**
     * Nome della propriet&agrave; sulla quale pu&ograve; essere impostato il
     * prefisso da applicare al nome delle propriet&agrave; interrogate da un
     * provider {@code AlgorithmParameterSpecFactory}. Il valore della costante
     * &egrave; <CODE>{@value}</CODE>.
     * 
     * @see #getCipher
     * @see #getKeyGenerator
     * @see #getKeyPairGenerator
     * @see it.scoppelletti.programmerpower.security.spi.AlgorithmParameterSpecFactory
     */
    public static final String PROP_PARAMFACTORY_PREFIX = "param.factory.prefix";

    /**
     * Costruttore privato per classe statica.
     */
    private CryptoUtils() {
    }

    /**
     * Restituisce un cifratore.
     * 
     * <H4>1. Propriet&agrave;</H4>
     * 
     * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
     * <THEAD>
     * <TR>
     *     <TH>Propriet&agrave;</TH>
     *     <TH>Descrizione</TH>     
     * </TR>
     * </THEAD>
     * <TBODY>
     * <TR>
     *      <TD>{@code alg}</TD>
     *      <TD>Codice dell&rsquo;algoritmo di cifratura.</TD>
     * </TR>
     * <TR>
     *      <TD>{@code mode}</TD>
     *      <TD>Codice dalla modalit&agrave; dell&rsquo;algoritmo di
     *      cifratura.</TD>
     * </TR> 
     * <TR>
     *      <TD>{@code padding}</TD>
     *      <TD>Codice dalla modalit&agrave; di riempimento dell&rsquo;algoritmo
     *      di cifratura.</TD>
     * </TR> 
     * <TR>
     *      <TD>{@code op}</TD>
     *      <TD>Codice dell&rsquo;operazione di cifratura.</TD>
     * </TR>
     * <TR>
     *      <TD>{@code key.factory}</TD>
     *      <TD>Nome della classe di factory della chiave; la classe deve
     *      implementare l&rsquo;interfaccia {@code CryptoKeyFactory} e
     *      pu&ograve; prevedere altre propriet&agrave;.</TD>          
     * </TR>
     * <TR>
     *      <TD>{@code key.factory.prefix}</TD>
     *      <TD>Eventuale prefisso da applicare al nome delle propriet&agrave;
     *      interrogate dal provider {@code key.factory}.</TD>          
     * </TR> 
     * <TR>
     *      <TD>{@code param.factory}</TD>
     *      <TD>Nome della classe di factory dei parametri specifici
     *      dell&rsquo;algoritmo; la classe deve implementare
     *      l&rsquo;interfaccia {@code AlgorithmParameterSpecFactory} e
     *      pu&ograve; prevedere altre propriet&agrave;.<BR>
     *      Se la propriet&agrave; non &egrave; impostata, sono utilizzati i
     *      parametri di default definiti dallo specifico provider JCA.</TD>          
     * </TR>
     * <TR>
     *      <TD>{@code param.factory.prefix}</TD>
     *      <TD>Eventuale prefisso da applicare al nome delle propriet&agrave;
     *      interrogate dal provider {@code param.factory}.</TD>          
     * </TR>    
     * <TR>
     *     <TD COLSPAN="2">Le propriet&agrave; {@code mode} e {@code padding}
     *     devono essere entrambe impostate oppure entrambe non impostate.</TD>  
     * </TR> 
     * </TBODY>
     * </TABLE></P>
     *  
     * @param  props  Propriet&agrave;.
     * @param  prefix Prefisso da applicare al nome delle propriet&agrave; da
     *                interrogare. Pu&ograve; essere {@code null}.
     * @return        Oggetto.
     * @see    it.scoppelletti.programmerpower.security.spi.CryptoKeyFactory
     * @see    it.scoppelletti.programmerpower.security.spi.AlgorithmParameterSpecFactory
     * @see    <A HREF="{@docRoot}/it/scoppelletti/programmerpower/security/CryptoUtils.html#idAlg">Algoritmi
     *         di crittografia</A> 
     * @see    <A HREF="{@docRoot}/it/scoppelletti/programmerpower/security/CryptoUtils.html#idMode">Modalit&agrave;
     *         degli algoritmi di cifratura</A>
     * @see    <A HREF="{@docRoot}/it/scoppelletti/programmerpower/security/CryptoUtils.html#idMode">Modalit&agrave;
     *         di riempimento degli algoritmi di cifratura</A>                           
     */
    public static Cipher getCipher(Properties props, String prefix) {
        String alg, name, mode, modeName, padding, paddingName, value;
        Key key;
        Cipher cipher;
        AlgorithmParameterSpec params;
        CipherOperation op;

        if (props == null) {
            throw new ArgumentNullException("props");
        }

        name = Strings.concat(prefix, CryptoUtils.PROP_CIPHERALGORITHM);
        alg = props.getProperty(name);
        if (Strings.isNullOrEmpty(alg)) {
            throw new ArgumentNullException(name);
        }

        modeName = Strings.concat(prefix, CryptoUtils.PROP_CIPHERMODE);
        mode = props.getProperty(modeName);

        paddingName = Strings.concat(prefix, CryptoUtils.PROP_CIPHERPADDING);
        padding = props.getProperty(paddingName);

        if (Strings.isNullOrEmpty(mode) && !Strings.isNullOrEmpty(padding)) {
            throw new ArgumentNullException(modeName);
        }
        if (!Strings.isNullOrEmpty(mode) && Strings.isNullOrEmpty(padding)) {
            throw new ArgumentNullException(paddingName);
        }
        if (!Strings.isNullOrEmpty(mode)) {
            alg = alg.concat("/");
            alg = alg.concat(mode);
            alg = alg.concat("/");
            alg = alg.concat(padding);
        }

        name = Strings.concat(prefix, CryptoUtils.PROP_CIPHEROPERATION);
        value = props.getProperty(name);
        if (Strings.isNullOrEmpty(value)) {
            throw new ArgumentNullException(name);
        }

        op = Enums.valueOf(CipherOperation.class, value);

        key = CryptoUtils.getKey(props, prefix);
        params = CryptoUtils.getAlgorithmParameterSpec(props, prefix);

        try {
            cipher = Cipher.getInstance(alg);
            if (params != null) {
                cipher.init(op.toJCA(), key, params);
            } else {
                cipher.init(op.toJCA(), key);
            }
        } catch (GeneralSecurityException ex) {
            throw SecurityUtils.toSecurityException(ex);
        }

        return cipher;
    }

    /**
     * Restituisce una chiave di crittografia.
     * 
     * <H4>1. Propriet&agrave;</H4>
     * 
     * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
     * <THEAD>
     * <TR>
     *     <TH>Propriet&agrave;</TH>
     *     <TH>Descrizione</TH>     
     * </TR>
     * </THEAD>
     * <TBODY>
     * <TR>
     *      <TD>{@code key.factory}</TD>
     *      <TD>Nome della classe di factory della chiave; la classe deve
     *      implementare l&rsquo;interfaccia {@code CryptoKeyFactory} e
     *      pu&ograve; prevedere altre propriet&agrave;.</TD>          
     * </TR> 
     * <TR>
     *      <TD>{@code key.factory.prefix}</TD>
     *      <TD>Eventuale prefisso da applicare al nome delle propriet&agrave;
     *      interrogate dal provider {@code key.factory}.</TD>          
     * </TR> 
     * </TBODY>
     * </TABLE></P>
     *  
     * @param  props  Propriet&agrave;.
     * @param  prefix Prefisso da applicare al nome delle propriet&agrave; da
     *                interrogare. Pu&ograve; essere {@code null}.
     * @return        Oggetto.
     * @see    #toProperties
     * @see    it.scoppelletti.programmerpower.security.spi.CryptoKeyFactory
     */
    public static Key getKey(Properties props, String prefix) {
        String name, value;
        Class<?> factoryClass;
        CryptoKeyFactory factory;

        if (props == null) {
            throw new ArgumentNullException("props");
        }

        name = Strings.concat(prefix, CryptoUtils.PROP_KEYFACTORY);
        value = props.getProperty(name);
        if (Strings.isNullOrEmpty(value)) {
            throw new ArgumentNullException(name);
        }

        try {
            factoryClass = Class.forName(value);
            factory = (CryptoKeyFactory) factoryClass.newInstance();
        } catch (Exception ex) {
            throw new ReflectionException(ex);
        }

        name = Strings.concat(prefix, CryptoUtils.PROP_KEYFACTORY_PREFIX);

        return factory.newInstance(props, props.getProperty(name));
    }

    /**
     * Restituisce i parametri per la ricostruzione di una chiave di
     * crittografia.
     * 
     * <P>Il metodo {@code toProperties} rileva i provider del servizio
     * {@code KeyToPropertySetProvider} disponibili e delega il calcolo dei
     * parametri al primo di questi che supporta la tipologia della chiave di
     * crittografia {@code key}; se nessuno dei provider supporta la specifica
     * tipologia di chiavi, restituisce i parametri che rappresentano la chiave
     * codificata come sequenza di byte nel formato Base64 come definito da RFC
     * 2045.</P>
     * 
     * @param  key     Chiave.
     * @param  encoded Indica se restituire i parametri che rappresentano la
     *                 chiave codificata come sequenza di byte senza rilevare
     *                 gli eventuali provider {@code KeyToPropertySetProvider}
     *                 disponibili.
     * @return         Propriet&agrave;. 
     * @see #getKey
     * @see it.scoppelletti.programmerpower.security.spi.CryptoKeyFactory
     * @see it.scoppelletti.programmerpower.security.spi.EncodedKeyFactory
     * @see it.scoppelletti.programmerpower.security.spi.KeyToPropertySetProvider
     * @see <A HREF="http://www.ietf.org/rfc/rfc2045.txt" TARGET="_blank">RFC
     *      2045: Multipurpose Internet Mail Extensions (MIME) Part One: Format
     *      of Internet Message Bodies</A> 
     */
    public static Properties toProperties(Key key, boolean encoded) {
        byte[] data;
        KeyRep.Type keyType;
        Properties props;
        KeyToPropertySetService svc;
        SecurityResources res = new SecurityResources();

        if (key == null) {
            throw new ArgumentNullException("key");
        }

        if (!encoded) {
            svc = new KeyToPropertySetService(key);
            props = svc.query();
            if (props != null) {
                return props;
            }
        }

        if (key instanceof PublicKey) {
            keyType = KeyRep.Type.PUBLIC;
        } else if (key instanceof PrivateKey) {
            keyType = KeyRep.Type.PRIVATE;
        } else if (key instanceof SecretKey) {
            keyType = KeyRep.Type.SECRET;
        } else {
            throw new InvalidCastException(key.getClass().getName(), KeyRep.Type.class.getName());
        }

        data = key.getEncoded();
        if (data == null) {
            throw new SecurityException(res.getEncodedFormatNotSupportedException());
        }

        props = new Properties();
        if (keyType == KeyRep.Type.SECRET) {
            props.setProperty(CryptoUtils.PROP_KEYFACTORY, RawKeyFactory.class.getName());
        } else {
            props.setProperty(CryptoUtils.PROP_KEYFACTORY, EncodedKeyFactory.class.getName());
            props.setProperty(EncodedKeyFactory.PROP_KEYTYPE, keyType.name());
        }

        props.setProperty(RawKeyFactory.PROP_ALGORITHM, key.getAlgorithm());
        props.setProperty(RawKeyFactory.PROP_DATA, Base64.encodeBase64String(data));

        return props;
    }

    /**
     * Restituisce un generatore di chiavi simmetriche.
     * 
     * <H4>1. Propriet&agrave;</H4>
     * 
     * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
     * <THEAD>
     * <TR>
     *     <TH>Propriet&agrave;</TH>
     *     <TH>Descrizione</TH>     
     * </TR>
     * </THEAD>
     * <TBODY>
     * <TR>
     *      <TD>{@code alg}</TD>
     *      <TD>Codice dell&rsquo;algoritmo di crittografia.</TD>
     * </TR>
     * <TR>
     *      <TD>{@code param.factory}</TD>
     *      <TD>Nome della classe di factory dei parametri specifici
     *      dell&rsquo;algoritmo; la classe deve implementare
     *      l&rsquo;interfaccia {@code AlgorithmParameterSpecFactory} e
     *      pu&ograve; prevedere altre propriet&agrave;.</TD>          
     * </TR>
     * <TR>
     *      <TD>{@code param.factory.prefix}</TD>
     *      <TD>Eventuale prefisso da applicare al nome delle propriet&agrave;
     *      interrogate dal provider {@code param.factory}.</TD>          
     * </TR> 
     * <TR>
     *      <TD>{@code key.size}</TD>
     *      <TD>Dimensione della chiave (numero di bit).</TD>          
     * </TR> 
     * <TR>
     *     <TD COLSPAN="2">Le propriet&agrave; {@code param.factory} e
     *     {@code key.size} non possono essere entrambe impostate; se nessuna
     *     delle due propriet&agrave; &egrave; impostata, il generatore
     *     sar&agrave; inizializzato con i parametri di default definiti dallo
     *     specifico provider JCA.</TD>
     * </TR>
     * </TBODY>
     * </TABLE></P>
     *    
     * @param  props  Propriet&agrave;.
     * @param  prefix Prefisso da applicare al nome delle propriet&agrave; da
     *                interrogare. Pu&ograve; essere {@code null}.
     * @return        Oggetto.
     * @see    it.scoppelletti.programmerpower.security.spi.AlgorithmParameterSpecFactory
     * @see    <A HREF="{@docRoot}/it/scoppelletti/programmerpower/security/CryptoUtils.html#idAlg">Algoritmi
     *         di crittografia</A> 
     */
    public static KeyGenerator getKeyGenerator(Properties props, String prefix) {
        int keySize;
        String alg, name;
        KeyGenerator gen;
        AlgorithmParameterSpec params;
        SecurityResources res = new SecurityResources();

        if (props == null) {
            throw new ArgumentNullException("props");
        }

        name = Strings.concat(prefix, CryptoUtils.PROP_KEYALGORITHM);
        alg = props.getProperty(name);
        if (Strings.isNullOrEmpty(alg)) {
            throw new ArgumentNullException(name);
        }

        params = CryptoUtils.getAlgorithmParameterSpec(props, prefix);
        keySize = CryptoUtils.getKeySize(props, prefix);
        if (params != null && keySize >= 0) {
            throw new IllegalArgumentException(
                    res.getArgumentIncompatibilityException(Strings.concat(prefix, CryptoUtils.PROP_PARAMFACTORY),
                            Strings.concat(prefix, CryptoUtils.PROP_KEYSIZE)));
        }

        try {
            gen = KeyGenerator.getInstance(alg);
            if (params != null) {
                gen.init(params);
            }
            if (keySize >= 0) {
                gen.init(keySize);
            }
        } catch (GeneralSecurityException ex) {
            throw SecurityUtils.toSecurityException(ex);
        }

        return gen;
    }

    /**
     * Restituisce un generatore di coppie di chiavi (pubblica, privata).
     *      
     * <H4>1. Propriet&agrave;</H4>
     * 
     * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
     * <THEAD>
     * <TR>
     *     <TH>Propriet&agrave;</TH>
     *     <TH>Descrizione</TH>     
     * </TR>
     * </THEAD>
     * <TBODY>
     * <TR>
     *      <TD>{@code alg}</TD>
     *      <TD>Codice dell&rsquo;algoritmo di crittografia.</TD>            
     * </TR>
     * <TR>
     *      <TD>{@code param.factory}</TD>
     *      <TD>Nome della classe di factory dei parametri specifici
     *      dell&rsquo;algoritmo; la classe deve implementare
     *      l&rsquo;interfaccia {@code AlgorithmParameterSpecFactory} e
     *      pu&ograve; prevedere altre propriet&agrave;.</TD>          
     * </TR>
     * <TR>
     *      <TD>{@code param.factory.prefix}</TD>
     *      <TD>Eventuale prefisso da applicare al nome delle propriet&agrave;
     *      interrogate dal provider {@code param.factory}.</TD>          
     * </TR> 
     * <TR>
     *      <TD>{@code key.size}</TD>
     *      <TD>Dimensione della chiave (numero di bit).</TD>          
     * </TR> 
     * <TR>
     *     <TD COLSPAN="2">Le propriet&agrave; {@code param.factory} e
     *     {@code key.size} non possono essere entrambe impostate; se nessuna
     *     delle due propriet&agrave; &egrave; impostata, il generatore
     *     sar&agrave; inizializzato con i parametri di default definiti dallo
     *     specifico provider JCA.</TD>
     * </TR>
     * </TBODY>
     * </TABLE></P>       
     *  
     * @param  props  Propriet&agrave;.
     * @param  prefix Prefisso da applicare al nome delle propriet&agrave; da
     *                interrogare. Pu&ograve; essere {@code null}.
     * @return        Oggetto.
     * @see    it.scoppelletti.programmerpower.security.spi.AlgorithmParameterSpecFactory
     * @see    <A HREF="{@docRoot}/it/scoppelletti/programmerpower/security/CryptoUtils.html#idAlg">Algoritmi
     *         di crittografia</A>
     */
    public static KeyPairGenerator getKeyPairGenerator(Properties props, String prefix) {
        int keySize;
        String alg, name;
        KeyPairGenerator gen;
        AlgorithmParameterSpec params;
        SecurityResources res = new SecurityResources();

        if (props == null) {
            throw new ArgumentNullException("props");
        }

        name = Strings.concat(prefix, CryptoUtils.PROP_KEYALGORITHM);
        alg = props.getProperty(name);
        if (Strings.isNullOrEmpty(alg)) {
            throw new ArgumentNullException(name);
        }

        params = CryptoUtils.getAlgorithmParameterSpec(props, prefix);
        keySize = CryptoUtils.getKeySize(props, prefix);
        if (params != null && keySize >= 0) {
            throw new IllegalArgumentException(
                    res.getArgumentIncompatibilityException(Strings.concat(prefix, CryptoUtils.PROP_PARAMFACTORY),
                            Strings.concat(prefix, CryptoUtils.PROP_KEYSIZE)));
        }

        try {
            gen = KeyPairGenerator.getInstance(alg);
            if (params != null) {
                gen.initialize(params);
            }
            if (keySize >= 0) {
                gen.initialize(keySize);
            }
        } catch (GeneralSecurityException ex) {
            throw SecurityUtils.toSecurityException(ex);
        }

        return gen;
    }

    /**
     * Restituisce l&rsquo;insieme dei parametri specifici di un algoritmo di
     * crittografia.
     * 
     * <H4>1. Propriet&agrave;</H4>
     * 
     * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
     * <THEAD>
     * <TR>
     *     <TH>Propriet&agrave;</TH>
     *     <TH>Descrizione</TH>     
     * </TR>
     * </THEAD>
     * <TBODY>
     * <TR>
     *      <TD>{@code param.factory}</TD>
     *      <TD>Nome della classe di factory dei parametri specifici
     *      dell&rsquo;algoritmo; la classe deve implementare
     *      l&rsquo;interfaccia {@code AlgorithmParameterSpecFactory} e
     *      pu&ograve; prevedere altre propriet&agrave;.</TD>          
     * </TR>
     * <TR>
     *      <TD>{@code param.factory.prefix}</TD>
     *      <TD>Eventuale prefisso da applicare al nome delle propriet&agrave;
     *      interrogate dal provider {@code param.factory}.</TD>          
     * </TR> 
     * </TBODY>
     * </TABLE></P>
     *  
     * @param  props  Propriet&agrave;
     * @param  prefix Prefisso da applicare al nome delle propriet&agrave; da
     *                interrogare. Pu&ograve; essere {@code null}.
     * @return        Oggetto.
     */
    private static AlgorithmParameterSpec getAlgorithmParameterSpec(Properties props, String prefix) {
        String name, value;
        Class<?> factoryClass;
        AlgorithmParameterSpec param;
        AlgorithmParameterSpecFactory factory;

        name = Strings.concat(prefix, CryptoUtils.PROP_PARAMFACTORY);
        value = props.getProperty(name);
        if (Strings.isNullOrEmpty(value)) {
            return null;
        }

        try {
            factoryClass = Class.forName(value);
            factory = (AlgorithmParameterSpecFactory) factoryClass.newInstance();
        } catch (Exception ex) {
            throw new ReflectionException(ex);
        }

        name = Strings.concat(prefix, CryptoUtils.PROP_PARAMFACTORY_PREFIX);
        param = factory.newInstance(props, props.getProperty(name));
        if (param == null) {
            throw new ReturnNullException(factory.getClass().getName(), "newInstance");
        }

        return param;
    }

    /**
     * Restituisce la dimensione di una chiave.
     * 
     * <H4>1. Propriet&agrave;</H4>
     * 
     * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5">
     * <THEAD>
     * <TR>
     *     <TH>Propriet&agrave;</TH>
     *     <TH>Descrizione</TH>     
     * </TR>
     * </THEAD>
     * <TBODY>
     * <TR>
     *      <TD>{@code key.size}</TD>
     *      <TD>Dimensione della chiave (numero di bit).</TD>          
     * </TR>
     * </TBODY>
     * </TABLE></P>
     *  
     * @param  props  Propriet&agrave;
     * @param  prefix Prefisso da applicare al nome delle propriet&agrave; da
     *                interrogare. Pu&ograve; essere {@code null}.
     * @return        Valore.
     */
    private static int getKeySize(Properties props, String prefix) {
        String name, value;
        int keySize;

        name = Strings.concat(prefix, CryptoUtils.PROP_KEYSIZE);
        value = props.getProperty(name);
        if (Strings.isNullOrEmpty(value)) {
            return -1;
        }

        keySize = Integer.parseInt(value);
        if (keySize < 0) {
            // Converto i valori negativi nel valore 0 comunque non valido per
            // distinguere il caso di proprieta' non impostata (valore negativo)
            // dal caso di proprieta' impostata con un valore non valido
            keySize = 0;
        }

        return keySize;
    }
}