Java tutorial
/* * 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à 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à {@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ù * 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 è 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’altra.<BR> * Gli algoritmi asimmetrici sono normalmente più lenti di quelli * simmetrici perché non sono progettati per proteggere in modo * efficiente grandi quantità 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’algoritmo è 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’applicazione dell’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> * #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 #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 #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 #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à alla volta (tipicamente un byte).</P> * * <H4 ID="idMode">3. Modalità 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à di feedback</DFN> aggiunge complessità 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à.</TD> * </TR> * <TR> * <TD>{@code CBC}</TD> * <TD>Modalità <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à <ACRONYM TITLE="Cipher FeedBack">CFB</ACRONYM> e * <ACRONYM TITLE="Output FeedBack">OFB</ACRONYM> sono definite da FIPS * 81. Queste modalità consentono ai cifratori a blocco di * crittografare i dati in unità più * piccole dell’effettiva dimensione dei blocchi del cifratore. * L’eventuale parametro <VAR>x</VAR> specifica il numero di bit da * processare alla volta; se il parametro non è specificato, * è utilizzato un valore di default definito dallo specifico * provider JCA.<BR> * Ad esempio, le modalità 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à OFB per la quale il blocco di * input è sostituito da un contatore.</TD> * </TR> * <TR> * <TD>{@code CTS}</TD> * <TD>Modalità <ACRONYM TITLE="Cipher Text Stealing">CTS</ACRONYM> * descritta nella seconda edizione del libro “Applied * Cryptography” di Bruce Schneier (John Wiley and Sons, 1996).</TD> * </TR> * <TR> * <TD>{@code ECB}</TD> * <TD>Modalità <ACRONYM TITLE="Elettronic CodeBook">ECB</ACRONYM> * definita da FIPS 81.</TD> * </TR> * <TR> * <TD>{@code PCBC}</TD> * <TD>Modalità * <ACRONYM TITLE="Propagating Cipher Block Chaining">PCBC</ACRONYM> * definita da Kerberos ver. 4.</TD> * </TR> * </TBODY> * </TABLE></P> * * <H4 ID="idPadding">4. Modalità 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’allineamento * può essere a carico dell’applicazione oppure demandato al * cifratore impostando una modalità 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à di riempimento per i cifratori a blocchi descritta * dal par. 5.2 “Block Encryption Algorithms” della * raccomandazione <ACRONYM TITLE="World Wide Web Consortium">W3C</ACRONYM> * “XML Encryption Syntax and Processing”.</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 #1/RFC 3447; lo schema è 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 #1 e utilizzato con * l’algoritmo RSA.</TD> * </TR> * <TR> * <TD>{@code PKCS5Padding}</TD> * <TD>Schema di riempimento descritto da PKCS #5, ver. 1.5.</TD> * </TR> * <TR> * <TD>{@code SSL3Padding}</TD> * <TD>Schema di riempimento definito dalla sezione 5.2.3.2 “CBC * block cipher” 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 #1: RSA * Cryptography Standard</A> * @see <A HREF="http://www.rsa.com/rsalabs" TARGET="_blank">PKCS #3: * Diffie-Hellman Key Agreement Standard</A> * @see <A HREF="http://www.rsa.com/rsalabs" TARGET="_blank">PKCS #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 "Arcfour"</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à sulla quale deve essere impostato il codice * di un algoritmo di cifratura. Il valore della costante è * <CODE>{@value}</CODE>. * * @see #getCipher */ public static final String PROP_CIPHERALGORITHM = "alg"; /** * Nome della proprietà sulla quale deve essere impostato il codice * di una modalità per un algoritmo di cifratura. Il valore della * costante è <CODE>{@value}</CODE>. * * @see #getCipher */ public static final String PROP_CIPHERMODE = "mode"; /** * Nome della proprietà sulla quale deve essere impostato il codice * di una modalità di riempimento di un algoritmo di cifratura. Il * valore della costante è <CODE>{@value}</CODE>. * * @see #getCipher */ public static final String PROP_CIPHERPADDING = "padding"; /** * Nome della proprietà sulla quale deve essere impostato il codice * di un’operazione di cifratura. Il valore della costante è * <CODE>{@value}</CODE>. * * @see #getCipher * @see it.scoppelletti.programmerpower.security.CipherOperation */ public static final String PROP_CIPHEROPERATION = "op"; /** * Nome della proprietà sulla quale deve essere impostato il codice * di un algoritmo di crittografia. Il valore della costante è * <CODE>{@value}</CODE>. * * @see #getKeyGenerator * @see #getKeyPairGenerator */ public static final String PROP_KEYALGORITHM = "alg"; /** * Nome della proprietà sulla quale deve essere impostata la * dimensione della chiave in numero di bit. Il valore della costante * è <CODE>{@value}</CODE>. * * @see #getKeyGenerator * @see #getKeyPairGenerator */ public static final String PROP_KEYSIZE = "key.size"; /** * Nome della proprietà sulla quale deve essere impostato il nome di * una classe che implementa l’interfaccia {@code CryptoKeyFactory}. * Il valore della costante è <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à sulla quale può essere impostato il * prefisso da applicare al nome delle proprietà interrogate da un * provider {@code CryptoKeyFactory}. Il valore della costante è * <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à sulla quale deve essere impostato il nome di * una classe che implementa l’interfaccia * {@code AlgorithmParameterSpecFactory}. Il valore della costante è * <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à sulla quale può essere impostato il * prefisso da applicare al nome delle proprietà interrogate da un * provider {@code AlgorithmParameterSpecFactory}. Il valore della costante * è <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à</H4> * * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5"> * <THEAD> * <TR> * <TH>Proprietà</TH> * <TH>Descrizione</TH> * </TR> * </THEAD> * <TBODY> * <TR> * <TD>{@code alg}</TD> * <TD>Codice dell’algoritmo di cifratura.</TD> * </TR> * <TR> * <TD>{@code mode}</TD> * <TD>Codice dalla modalità dell’algoritmo di * cifratura.</TD> * </TR> * <TR> * <TD>{@code padding}</TD> * <TD>Codice dalla modalità di riempimento dell’algoritmo * di cifratura.</TD> * </TR> * <TR> * <TD>{@code op}</TD> * <TD>Codice dell’operazione di cifratura.</TD> * </TR> * <TR> * <TD>{@code key.factory}</TD> * <TD>Nome della classe di factory della chiave; la classe deve * implementare l’interfaccia {@code CryptoKeyFactory} e * può prevedere altre proprietà.</TD> * </TR> * <TR> * <TD>{@code key.factory.prefix}</TD> * <TD>Eventuale prefisso da applicare al nome delle proprietà * interrogate dal provider {@code key.factory}.</TD> * </TR> * <TR> * <TD>{@code param.factory}</TD> * <TD>Nome della classe di factory dei parametri specifici * dell’algoritmo; la classe deve implementare * l’interfaccia {@code AlgorithmParameterSpecFactory} e * può prevedere altre proprietà.<BR> * Se la proprietà non è 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à * interrogate dal provider {@code param.factory}.</TD> * </TR> * <TR> * <TD COLSPAN="2">Le proprietà {@code mode} e {@code padding} * devono essere entrambe impostate oppure entrambe non impostate.</TD> * </TR> * </TBODY> * </TABLE></P> * * @param props Proprietà. * @param prefix Prefisso da applicare al nome delle proprietà da * interrogare. Può 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à * degli algoritmi di cifratura</A> * @see <A HREF="{@docRoot}/it/scoppelletti/programmerpower/security/CryptoUtils.html#idMode">Modalità * 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à</H4> * * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5"> * <THEAD> * <TR> * <TH>Proprietà</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’interfaccia {@code CryptoKeyFactory} e * può prevedere altre proprietà.</TD> * </TR> * <TR> * <TD>{@code key.factory.prefix}</TD> * <TD>Eventuale prefisso da applicare al nome delle proprietà * interrogate dal provider {@code key.factory}.</TD> * </TR> * </TBODY> * </TABLE></P> * * @param props Proprietà. * @param prefix Prefisso da applicare al nome delle proprietà da * interrogare. Può 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à. * @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à</H4> * * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5"> * <THEAD> * <TR> * <TH>Proprietà</TH> * <TH>Descrizione</TH> * </TR> * </THEAD> * <TBODY> * <TR> * <TD>{@code alg}</TD> * <TD>Codice dell’algoritmo di crittografia.</TD> * </TR> * <TR> * <TD>{@code param.factory}</TD> * <TD>Nome della classe di factory dei parametri specifici * dell’algoritmo; la classe deve implementare * l’interfaccia {@code AlgorithmParameterSpecFactory} e * può prevedere altre proprietà.</TD> * </TR> * <TR> * <TD>{@code param.factory.prefix}</TD> * <TD>Eventuale prefisso da applicare al nome delle proprietà * 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à {@code param.factory} e * {@code key.size} non possono essere entrambe impostate; se nessuna * delle due proprietà è impostata, il generatore * sarà inizializzato con i parametri di default definiti dallo * specifico provider JCA.</TD> * </TR> * </TBODY> * </TABLE></P> * * @param props Proprietà. * @param prefix Prefisso da applicare al nome delle proprietà da * interrogare. Può 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à</H4> * * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5"> * <THEAD> * <TR> * <TH>Proprietà</TH> * <TH>Descrizione</TH> * </TR> * </THEAD> * <TBODY> * <TR> * <TD>{@code alg}</TD> * <TD>Codice dell’algoritmo di crittografia.</TD> * </TR> * <TR> * <TD>{@code param.factory}</TD> * <TD>Nome della classe di factory dei parametri specifici * dell’algoritmo; la classe deve implementare * l’interfaccia {@code AlgorithmParameterSpecFactory} e * può prevedere altre proprietà.</TD> * </TR> * <TR> * <TD>{@code param.factory.prefix}</TD> * <TD>Eventuale prefisso da applicare al nome delle proprietà * 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à {@code param.factory} e * {@code key.size} non possono essere entrambe impostate; se nessuna * delle due proprietà è impostata, il generatore * sarà inizializzato con i parametri di default definiti dallo * specifico provider JCA.</TD> * </TR> * </TBODY> * </TABLE></P> * * @param props Proprietà. * @param prefix Prefisso da applicare al nome delle proprietà da * interrogare. Può 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’insieme dei parametri specifici di un algoritmo di * crittografia. * * <H4>1. Proprietà</H4> * * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5"> * <THEAD> * <TR> * <TH>Proprietà</TH> * <TH>Descrizione</TH> * </TR> * </THEAD> * <TBODY> * <TR> * <TD>{@code param.factory}</TD> * <TD>Nome della classe di factory dei parametri specifici * dell’algoritmo; la classe deve implementare * l’interfaccia {@code AlgorithmParameterSpecFactory} e * può prevedere altre proprietà.</TD> * </TR> * <TR> * <TD>{@code param.factory.prefix}</TD> * <TD>Eventuale prefisso da applicare al nome delle proprietà * interrogate dal provider {@code param.factory}.</TD> * </TR> * </TBODY> * </TABLE></P> * * @param props Proprietà * @param prefix Prefisso da applicare al nome delle proprietà da * interrogare. Può 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à</H4> * * <P><TABLE WIDTH="100%" BORDER="1" CELLPADDING="5"> * <THEAD> * <TR> * <TH>Proprietà</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à * @param prefix Prefisso da applicare al nome delle proprietà da * interrogare. Può 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; } }