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.spi; import java.security.*; import java.security.spec.*; import java.util.*; import javax.crypto.spec.*; import org.apache.commons.codec.*; import org.apache.commons.codec.binary.*; import it.scoppelletti.programmerpower.*; import it.scoppelletti.programmerpower.security.*; import it.scoppelletti.programmerpower.types.*; /** * Classe di factory di una chiave per un algoritmo * <ACRONYM TITLE="Password Based Encryption">PBE</ACRONYM>. * * <P>Molti algoritmi di crittografia utilizzano chiavi binarie perché le * persone normalmente faticano a ricordare lunghe sequenze di numeri binari * (anche se rappresentate in esadecimale).<BR> * Le password di caratteri sono molto più facili da ricordare * perchè sono normalmente costituite da una piccola varietà di * caratteri. I protocolli PBE sono stati definiti per generare chiavi binarie * più <I>sicure</I> da password di caratteri.<BR> * Per rallentare il lavoro di chi tenta violare le password attraverso * dizionari di parole comuni già precalcolati (<DFN>dictionary * attack</DFN>), la maggior parte delle implementazioni PBE utilizzano un * numero casuale {@code salt} che appunto incrementa la casualità delle * chiavi.</P> * * <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.alg}</TD> * <TD>Codice dell’algoritmo di crittografia.</TD> * </TR> * <TR> * <TD>{@code pwd}</TD> * <TD>Password dalla quale derivare la chiave.</TD> * <TR> * <TR> * <TD>{@code salt}</TD> * <TD>Sequenza di byte {@code salt} in formato esadecimale.</TD> * </TR> * <TR> * <TD>{@code iterations}</TD> * <TD>Numero di iterazioni.</TD> * </TR> * <TR> * <TD>{@code keylen}</TD> * <TD>Lunghezza della chiave da derivare per un cifratore a dimensione * variabile della chiave.</TD> * </TR> * <TR> * <TR> * <TD COLSPAN="2">Le proprietà {@code salt} e {@code iterations} * devono essere entrambe impostate oppure entrambe non impostate; solo se * sono entrambe impostate e solo per i cifratori a dimensione variabile * della chiave, può essere impostata anche la proprietà * {@code keylen}.</TD> * </TR> * </TBODY> * </TABLE></P> * * @see it.scoppelletti.programmerpower.security.CryptoUtils#getKey * @see <A HREF="{@docRoot}/it/scoppelletti/programmerpower/security/CryptoUtils.html#idAlg">Algoritmi * di crittografia</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/rfc2898.txt" TARGET="_blank">RFC * 2898 / PKCS #5: Password-Based Cryptography Specification</A> * @since 1.0.0 */ public final class PBEKeyFactory extends AbstractCryptoKeyFactory { /** * Nome della proprietà sulla quale deve essere impostata la password * dalla quale derivare la chiave. Il valore della costante è * <CODE>{@value}</CODE>. */ public static final String PROP_PASSWORD = "pwd"; /** * Nome della proprietà sulla quale può essere impostata la * sequenza di byte {@code salt}. Il valore della costante è * <CODE>{@value}</CODE>. */ public static final String PROP_SALT = "salt"; /** * Nome della proprietà sulla quale può essere impostato il * numero di iterazioni. Il valore della costante è * <CODE>{@value}</CODE>. */ public static final String PROP_ITERATIONCOUNT = "iterations"; /** * Nome della proprietà sulla quale può essere impostata la * lunghezza della chiave da derivare. Il valore della costante è * <CODE>{@value}</CODE>. */ public static final String PROP_KEYLEN = "keylen"; /** * Costruttore. */ public PBEKeyFactory() { } @Override protected String getAlgorithm(Properties props, String prefix) { String name, alg; name = Strings.concat(prefix, PBEKeyFactory.PROP_ALGORITHM); alg = props.getProperty(name); if (Strings.isNullOrEmpty(alg)) { throw new ArgumentNullException(name); } return alg; } @Override protected KeyRep.Type getKeyType(Properties props, String prefix) { return KeyRep.Type.SECRET; } @Override protected KeySpec getKeySpec(String alg, KeyRep.Type keyType, Properties props, String prefix) { int count, keyLen; boolean varKeySize; String countName, saltName, name, value; byte[] salt; KeySpec keySpec; SecureString pwd = null; saltName = Strings.concat(prefix, PBEKeyFactory.PROP_SALT); value = props.getProperty(saltName); if (!Strings.isNullOrEmpty(value)) { try { salt = Hex.decodeHex(value.toCharArray()); } catch (DecoderException ex) { throw SecurityUtils.toSecurityException(ex); } } else { salt = null; } countName = Strings.concat(prefix, PBEKeyFactory.PROP_ITERATIONCOUNT); value = props.getProperty(countName); if (!Strings.isNullOrEmpty(value)) { if (salt == null) { throw new ArgumentNullException(saltName); } count = Integer.parseInt(value); } else if (salt != null) { throw new ArgumentNullException(countName); } else { count = 0; } name = Strings.concat(prefix, PBEKeyFactory.PROP_KEYLEN); value = props.getProperty(name); varKeySize = !Strings.isNullOrEmpty(value); if (varKeySize) { if (salt == null) { throw new ArgumentNullException(saltName); } keyLen = Integer.parseInt(value); } else { keyLen = 0; } name = Strings.concat(prefix, PBEKeyFactory.PROP_PASSWORD); pwd = new SecureString(props.getProperty(name)); if (pwd.isEmpty()) { throw new ArgumentNullException(name); } try { if (salt == null) { keySpec = new PBEKeySpec(pwd.getValue()); } else if (varKeySize) { keySpec = new PBEKeySpec(pwd.getValue(), salt, count, keyLen); } else { keySpec = new PBEKeySpec(pwd.getValue(), salt, count); } } finally { if (pwd != null) { pwd.clear(); pwd = null; } } return keySpec; } }