001package com.hfg.util;
002
003import java.io.File;
004import java.io.FileOutputStream;
005import java.io.OutputStream;
006import java.nio.file.Files;
007import java.security.KeyFactory;
008import java.security.KeyPair;
009import java.security.KeyPairGenerator;
010import java.security.PrivateKey;
011import java.security.PublicKey;
012import java.security.Signature;
013import java.security.spec.ECGenParameterSpec;
014import java.security.spec.PKCS8EncodedKeySpec;
015import java.security.spec.X509EncodedKeySpec;
016
017//------------------------------------------------------------------------------
018/**
019 Cryptology-related methods for key & signature handling.
020 <div>
021 @author J. Alex Taylor, hairyfatguy.com
022 </div>
023 */
024//------------------------------------------------------------------------------
025// com.hfg XML/HTML Coding Library
026//
027// This library is free software; you can redistribute it and/or
028// modify it under the terms of the GNU Lesser General Public
029// License as published by the Free Software Foundation; either
030// version 2.1 of the License, or (at your option) any later version.
031//
032// This library is distributed in the hope that it will be useful,
033// but WITHOUT ANY WARRANTY; without even the implied warranty of
034// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
035// Lesser General Public License for more details.
036//
037// You should have received a copy of the GNU Lesser General Public
038// License along with this library; if not, write to the Free Software
039// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
040//
041// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
042// jataylor@hairyfatguy.com
043//------------------------------------------------------------------------------
044
045public class CryptoUtil
046{
047
048   private static String sDefaultEllipticCurveSpec = "secp521r1";
049
050   //---------------------------------------------------------------------------
051   /**
052    * Sets the default SunEC-implemented elliptic curve spec used.
053    * Surely there is a better way to find the possible values but here is one url:
054    * <a href='http://www.docjar.com/html/api/sun/security/ec/SunECEntries.java.html'>
055    *    http://www.docjar.com/html/api/sun/security/ec/SunECEntries.java.html</a>.
056    * Also see "Implementing ECC with Java Standard Edition 7" by V. Martinez.
057    * @param inValue String spec for the SunEC-implemented elliptic curve to use.
058    */
059   public static void setDefaultEllipticCurveSpec(String inValue)
060   {
061      sDefaultEllipticCurveSpec = inValue;
062   }
063
064   //---------------------------------------------------------------------------
065   /**
066    * Returns the default SunEC-implemented elliptic curve spec used.
067    * @return Default String spec for the SunEC-implemented elliptic curve to use
068    */
069   public static String getDefaultEllipticCurveSpec()
070   {
071      return sDefaultEllipticCurveSpec;
072   }
073
074   //---------------------------------------------------------------------------
075   /**
076    * Generates an Elliptic Curve key pair using the default elliptic curve spec.
077    * @return KeyPair which can be written out to public and private key files.
078    * @throws Exception
079    */
080   public static KeyPair generateEllipticCurveKeyPair()
081         throws Exception
082   {
083      return generateEllipticCurveKeyPair(sDefaultEllipticCurveSpec);
084   }
085
086   //---------------------------------------------------------------------------
087   /**
088    * Generates an Elliptic Curve key pair.
089    * @param inEllipticCurveSpec String spec for the SunEC-implemented elliptic curve to use.
090    * @return KeyPair which can be written out to public and private key files.
091    * @throws Exception
092    */
093   public static KeyPair generateEllipticCurveKeyPair(String inEllipticCurveSpec)
094         throws Exception
095   {
096      KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "SunEC");
097
098      keyPairGenerator.initialize(new ECGenParameterSpec(inEllipticCurveSpec));
099
100      return keyPairGenerator.genKeyPair();
101   }
102
103   //---------------------------------------------------------------------------
104   public static void writePrivateEllipticCurveKeyToFile(PrivateKey inPrivateKey, File inFile)
105      throws Exception
106   {
107      PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(inPrivateKey.getEncoded());
108
109      OutputStream fileStream = null;
110      try
111      {
112         fileStream = new FileOutputStream(inFile);
113         fileStream.write(pkcs8EncodedKeySpec.getEncoded());
114      }
115      finally
116      {
117         if (fileStream != null)
118         {
119            fileStream.close();
120         }
121      }
122   }
123
124   //---------------------------------------------------------------------------
125   public static PrivateKey readPrivateEllipticCurveKeyFile(File inPrivateKeyFile)
126      throws Exception
127   {
128      byte[] data = Files.readAllBytes(inPrivateKeyFile.toPath());
129
130      PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(data);
131      KeyFactory factory = KeyFactory.getInstance("EC");
132      return factory.generatePrivate(spec);
133   }
134
135   //---------------------------------------------------------------------------
136   public static void writePublicEllipticCurveKeyToFile(PublicKey inPublicKey, File inFile)
137      throws Exception
138   {
139      X509EncodedKeySpec spec = new X509EncodedKeySpec(inPublicKey.getEncoded());
140
141      OutputStream fileStream = null;
142      try
143      {
144         fileStream = new FileOutputStream(inFile);
145         fileStream.write(spec.getEncoded());
146      }
147      finally
148      {
149         if (fileStream != null)
150         {
151            fileStream.close();
152         }
153      }
154   }
155
156   //---------------------------------------------------------------------------
157   public static PublicKey readPublicEllipticCurveKeyFile(File inPublicKeyFile)
158      throws Exception
159   {
160      byte[] data = Files.readAllBytes(inPublicKeyFile.toPath());
161
162      X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
163      KeyFactory factory = KeyFactory.getInstance("EC");
164      return factory.generatePublic(spec);
165   }
166
167   //---------------------------------------------------------------------------
168   /**
169    * Generates a signature give a private key and the text to sign.
170    * Uses the SHA512withECDSA signature algorithm.
171    * @param inPrivateKey private Elliptic Curve key
172    * @param inText text to sign
173    * @return signature as a byte[]
174    * @throws Exception
175    */
176   public static byte[] generateSignatureWithECDSA(PrivateKey inPrivateKey, String inText)
177         throws Exception
178   {
179      Signature signature = Signature.getInstance("SHA512withECDSA", "SunEC");
180      signature.initSign(inPrivateKey);
181
182      signature.update(inText.getBytes());
183
184      return signature.sign();
185   }
186
187   //---------------------------------------------------------------------------
188   /**
189    * Verifies a signature give a public key, the signed text, and the signature.
190    * Uses the SHA512withECDSA signature algorithm.
191    * @param inPublicKey public Elliptic Curve key
192    * @param inText text that was signed
193    * @param inSignature signature as a byte[]
194    * @return whether the signature is valid
195    * @throws Exception
196    */
197   public static boolean verifySignatureWithECDSA(PublicKey inPublicKey, String inText, byte[] inSignature)
198         throws Exception
199   {
200      Signature signature = Signature.getInstance("SHA512withECDSA", "SunEC");
201      signature.initVerify(inPublicKey);
202
203      signature.update(inText.getBytes());
204
205      return signature.verify(inSignature);
206   }
207}