/* * Mojito Distributed Hash Table (Mojito DHT) * Copyright (C) 2006-2007 LimeWire LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.limewire.mojito.util; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.zip.GZIPInputStream; import org.limewire.mojito.exceptions.SignatureVerificationException; import org.limewire.util.Base32; /** * Miscellaneous utilities for Cryptography. */ public final class CryptoUtils { /** The algorithm of the Key */ public static final String KEY_ALGORITHM = "DSA"; /** The key size in bit */ public static final int KEY_SIZE = 1024; /** The Signature algorithm */ public static final String SIGNATURE_ALGORITHM = "SHA1withDSA"; private static Signature SIGNATURE; private CryptoUtils() {} /** * Loads a PublicKey from the given File. */ public static PublicKey loadPublicKey(File file) throws IOException, SignatureException, InvalidKeyException { FileInputStream fis = null; GZIPInputStream gz = null; try { fis = new FileInputStream(file); gz = new GZIPInputStream(fis); return loadPublicKey(gz); } finally { if (gz != null) { gz.close(); } } } public static PublicKey loadPublicKey(String base32) throws IOException, SignatureException, InvalidKeyException { ByteArrayInputStream bais = new ByteArrayInputStream(Base32.decode(base32)); GZIPInputStream gz = null; try { gz = new GZIPInputStream(bais); return loadPublicKey(gz); } finally { if (gz != null) { gz.close(); } } } public static PublicKey loadPublicKey(InputStream in) throws IOException, SignatureException, InvalidKeyException { DataInputStream dis = new DataInputStream(in); byte[] signature = new byte[dis.readInt()]; dis.readFully(signature); byte[] encodedKey = new byte[dis.readInt()]; dis.readFully(encodedKey); PublicKey pubKey = createPublicKey(encodedKey); if (!verify(pubKey, signature, encodedKey)) { throw new SignatureVerificationException(); } return pubKey; } /** * Creates a new KeyPair. */ /*public static KeyPair createKeyPair() { try { KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM); kpg.initialize(KEY_SIZE); return kpg.generateKeyPair(); } catch (NoSuchAlgorithmException err) { throw new RuntimeException(err); } }*/ /** * Turns a X509 encoded key into a PublicKey object. */ public static PublicKey createPublicKey(byte[] x509EncodedKey) { try { X509EncodedKeySpec keySpec = new X509EncodedKeySpec(x509EncodedKey); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM); return factory.generatePublic(keySpec); } catch (NoSuchAlgorithmException err) { throw new RuntimeException(err); } catch (InvalidKeySpecException err) { throw new RuntimeException(err); } } /** * Creates a Signature with the given PrivateKey that can be used * for signing Data. */ /*public static Signature createSignSignature(PrivateKey privateKey) { try { Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(privateKey); return signature; } catch (InvalidKeyException err) { throw new RuntimeException(err); } catch (NoSuchAlgorithmException err) { throw new RuntimeException(err); } }*/ /** * Creates a Signature with the given PublicKey that can be used * for verifying Data. */ /*public static Signature createVerifySignature(PublicKey publicKey) { try { Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicKey); return signature; } catch (InvalidKeyException err) { throw new RuntimeException(err); } catch (NoSuchAlgorithmException err) { throw new RuntimeException(err); } }*/ /** * Signs the given array of byte-arrays with the given PrivateKey. */ public static synchronized byte[] sign(PrivateKey privateKey, byte[]... data) throws SignatureException, InvalidKeyException { try { if (SIGNATURE == null) { SIGNATURE = Signature.getInstance(SIGNATURE_ALGORITHM); } SIGNATURE.initSign(privateKey); for(byte[] d : data) { SIGNATURE.update(d, 0, d.length); } return SIGNATURE.sign(); } catch (NoSuchAlgorithmException err) { throw new RuntimeException(err); } } /** * Verifies given signature is correct. */ public static synchronized boolean verify(PublicKey publicKey, byte[] signature, byte[]... data) throws SignatureException, InvalidKeyException { if (signature == null) { return false; } try { if (SIGNATURE == null) { SIGNATURE = Signature.getInstance(SIGNATURE_ALGORITHM); } SIGNATURE.initVerify(publicKey); for(byte[] d : data) { SIGNATURE.update(d, 0, d.length); } return SIGNATURE.verify(signature); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } }