    001    /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
    002     *
    003     * Redistribution and use in  source and binary forms, with or without
    004     * modification, are permitted  provided that the following conditions are met:
    005     *
    006     * 1. Redistributions of  source code must retain the above copyright notice,
    007     *    this list of conditions and the following disclaimer.
    008     *
    009     * 2. Redistributions in  binary form must reproduce the above copyright notice,
    010     *    this list of conditions and the following disclaimer in the documentation
    011     *    and/or other materials provided with the distribution.
    012     *
    013     * 3. The end-user documentation included with the redistribution, if any, must
    014     *    include the following acknowledgment:
    015     *
    016     *    "This product includes software developed by IAIK of Graz University of
    017     *     Technology."
    018     *
    019     *    Alternately, this acknowledgment may appear in the software itself, if
    020     *    and wherever such third-party acknowledgments normally appear.
    021     *
    022     * 4. The names "Graz University of Technology" and "IAIK of Graz University of
    023     *    Technology" must not be used to endorse or promote products derived from
    024     *    this software without prior written permission.
    025     *
    026     * 5. Products derived from this software may not be called
    027     *    "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior
    028     *    written permission of Graz University of Technology.
    029     *
    030     *  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
    031     *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    032     *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    033     *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
    034     *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
    035     *  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    036     *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
    037     *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    038     *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    039     *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    040     *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    041     *  POSSIBILITY  OF SUCH DAMAGE.
    042     */
    043
    044    package demo.pkcs.pkcs11;
    045
    046    import java.io.BufferedReader;
    047    import java.io.FileOutputStream;
    048    import java.io.InputStreamReader;
    049    import java.io.PrintWriter;
    050    import java.math.BigInteger;
    051    import java.security.AlgorithmParameterGenerator;
    052    import java.security.AlgorithmParameters;
    053    import java.security.KeyFactory;
    054    import java.security.Security;
    055    import java.security.spec.DSAParameterSpec;
    056    import java.security.spec.DSAPublicKeySpec;
    057    import java.security.spec.X509EncodedKeySpec;
    058    import java.util.Arrays;
    059    import java.util.HashSet;
    060    import java.util.Random;
    061
    062    import iaik.pkcs.pkcs11.Mechanism;
    063    import iaik.pkcs.pkcs11.MechanismInfo;
    064    import iaik.pkcs.pkcs11.Module;
    065    import iaik.pkcs.pkcs11.Session;
    066    import iaik.pkcs.pkcs11.Slot;
    067    import iaik.pkcs.pkcs11.Token;
    068    import iaik.pkcs.pkcs11.TokenInfo;
    069    import iaik.pkcs.pkcs11.objects.DSAPrivateKey;
    070    import iaik.pkcs.pkcs11.objects.DSAPublicKey;
    071    import iaik.pkcs.pkcs11.objects.KeyPair;
    072    import iaik.pkcs.pkcs11.objects.Object;
    073    import iaik.pkcs.pkcs11.wrapper.Functions;
    074    import iaik.security.provider.IAIK;
    075
    076
    077
    078    /**
    079     * This demo program generates a 1024 bit DSA key-pair on the token and writes
    080     * the public key to a file.
    081     *
    082     * @author <a href="mailto:Karl.Scheibelhofer@iaik.at"> Karl Scheibelhofer </a>
    083     * @version 0.1
    084     * @invariants
    085     */
    086    public class GenerateKeyPairDSA {
    087
    088      static BufferedReader input_;
    089
    090      static PrintWriter output_;
    091
    092      static {
    093        try {
    094          //output_ = new PrintWriter(new FileWriter("SignAndVerify_output.txt"), true);
    095          output_ = new PrintWriter(System.out, true);
    096          input_ = new BufferedReader(new InputStreamReader(System.in));
    097        } catch (Throwable thr) {
    098          thr.printStackTrace();
    099          output_ = new PrintWriter(System.out, true);
    100          input_ = new BufferedReader(new InputStreamReader(System.in));
    101       }
    102      }
    103
    104      public static void main(String[] args) {
    105        if (args.length != 2) {
    106          printUsage();
    107          System.exit(1);
    108        }
    109
    110        try {
    111
    112          Security.addProvider(new IAIK());
    113
    114          Module pkcs11Module = Module.getInstance(args[0]);
    115          pkcs11Module.initialize(null);
    116
    117          Slot[] slots = pkcs11Module.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
    118
    119          if (slots.length == 0) {
    120            output_.println("No slot with present token found!");
    121            System.exit(0);
    122          }
    123
    124          Slot selectedSlot = slots[0];
    125          Token token = selectedSlot.getToken();
    126          TokenInfo tokenInfo = token.getTokenInfo();
    127
    128          output_.println("################################################################################");
    129          output_.println("Information of Token:");
    130          output_.println(tokenInfo);
    131          output_.println("################################################################################");
    132
    133          Session session = Util.openAuthorizedSession(token, Token.SessionReadWriteBehavior.RW_SESSION, output_, input_);
    134              // token.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RW_SESSION, null, null);
    135
    136          // generate DSA domain parameters in software
    137          output_.println("################################################################################");
    138          output_.print("Generating new 1024 bit DSA parameters (in software)... ");
    139          output_.flush();
    140          AlgorithmParameterGenerator parameterGenerator = AlgorithmParameterGenerator.getInstance("DSA");
    141          parameterGenerator.init(1024);
    142          AlgorithmParameters parameters = parameterGenerator.generateParameters();
    143          DSAParameterSpec parameterSpec = (DSAParameterSpec) parameters.getParameterSpec(DSAParameterSpec.class);
    144          output_.println("Success");
    145          output_.println("P: " + Functions.toHexString(parameterSpec.getP().toByteArray()));
    146          output_.println("Q: " + Functions.toHexString(parameterSpec.getQ().toByteArray()));
    147          output_.println("G: " + Functions.toHexString(parameterSpec.getG().toByteArray()));
    148          output_.println("################################################################################");
    149
    150          output_.println("################################################################################");
    151          output_.print("Generating new 1024 bit DSA key-pair... ");
    152          output_.flush();
    153
    154          // first check out what attributes of the keys we may set
    155          HashSet supportedMechanisms = new HashSet(Arrays.asList(token.getMechanismList()));
    156
    157          MechanismInfo signatureMechanismInfo;
    158          if (supportedMechanisms.contains(Mechanism.DSA)) {
    159            signatureMechanismInfo = token.getMechanismInfo(Mechanism.DSA);
    160          } else {
    161            signatureMechanismInfo = null;
    162          }
    163
    164          Mechanism keyPairGenerationMechanism = Mechanism.DSA_KEY_PAIR_GEN;
    165          DSAPublicKey dsaPublicKeyTemplate = new DSAPublicKey();
    166          DSAPrivateKey dsaPrivateKeyTemplate = new DSAPrivateKey();
    167
    168          // set the general attributes for the public key
    169          dsaPublicKeyTemplate.getPrime().setByteArrayValue(
    170              iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(parameterSpec.getP()));
    171          dsaPublicKeyTemplate.getSubprime().setByteArrayValue(
    172              iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(parameterSpec.getQ()));
    173          dsaPublicKeyTemplate.getBase().setByteArrayValue(
    174              iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(parameterSpec.getG()));
    175
    176          dsaPublicKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
    177          byte[] id = new byte[20];
    178          new Random().nextBytes(id);
    179          dsaPublicKeyTemplate.getId().setByteArrayValue(id);
    180          //dsaPublicKeyTemplate.getLabel().setCharArrayValue(args[2].toCharArray());
    181
    182          dsaPrivateKeyTemplate.getSensitive().setBooleanValue(Boolean.TRUE);
    183          dsaPrivateKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
    184          dsaPrivateKeyTemplate.getPrivate().setBooleanValue(Boolean.TRUE);
    185          dsaPrivateKeyTemplate.getId().setByteArrayValue(id);
    186          //byte[] subject = args[1].getBytes();
    187          //dsaPrivateKeyTemplate.getSubject().setByteArrayValue(subject);
    188          //dsaPrivateKeyTemplate.getLabel().setCharArrayValue(args[2].toCharArray());
    189
    190          // set the attributes in a way netscape does, this should work with most tokens
    191          if (signatureMechanismInfo != null) {
    192            dsaPublicKeyTemplate.getVerify().setBooleanValue(new Boolean(signatureMechanismInfo.isVerify()));
    193            dsaPublicKeyTemplate.getVerifyRecover().setBooleanValue(new Boolean(signatureMechanismInfo.isVerifyRecover()));
    194            dsaPublicKeyTemplate.getEncrypt().setBooleanValue(new Boolean(signatureMechanismInfo.isEncrypt()));
    195            dsaPublicKeyTemplate.getDerive().setBooleanValue(new Boolean(signatureMechanismInfo.isDerive()));
    196            dsaPublicKeyTemplate.getWrap().setBooleanValue(new Boolean(signatureMechanismInfo.isWrap()));
    197
    198            dsaPrivateKeyTemplate.getSign().setBooleanValue(new Boolean(signatureMechanismInfo.isSign()));
    199            dsaPrivateKeyTemplate.getSignRecover().setBooleanValue(new Boolean(signatureMechanismInfo.isSignRecover()));
    200            dsaPrivateKeyTemplate.getDecrypt().setBooleanValue(new Boolean(signatureMechanismInfo.isDecrypt()));
    201            dsaPrivateKeyTemplate.getDerive().setBooleanValue(new Boolean(signatureMechanismInfo.isDerive()));
    202            dsaPrivateKeyTemplate.getUnwrap().setBooleanValue(new Boolean(signatureMechanismInfo.isUnwrap()));
    203          } else {
    204            // if we have no information we assume these attributes
    205            dsaPrivateKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);
    206
    207            dsaPublicKeyTemplate.getVerify().setBooleanValue(Boolean.TRUE);
    208          }
    209
    210          // netscape does not set these attribute, so we do no either
    211          dsaPublicKeyTemplate.getKeyType().setPresent(false);
    212          dsaPublicKeyTemplate.getObjectClass().setPresent(false);
    213
    214          dsaPrivateKeyTemplate.getKeyType().setPresent(false);
    215          dsaPrivateKeyTemplate.getObjectClass().setPresent(false);
    216
    217          KeyPair generatedKeyPair = session.generateKeyPair(keyPairGenerationMechanism, dsaPublicKeyTemplate, dsaPrivateKeyTemplate);
    218          DSAPublicKey generatedDSAPublicKey = (DSAPublicKey) generatedKeyPair.getPublicKey();
    219          DSAPrivateKey generatedDSAPrivateKey = (DSAPrivateKey) generatedKeyPair.getPrivateKey();
    220          // no we may work with the keys...
    221
    222          output_.println("Success");
    223          output_.println("The public key is");
    224          output_.println("_______________________________________________________________________________");
    225          output_.println(generatedDSAPublicKey);
    226          output_.println("_______________________________________________________________________________");
    227          output_.println("The private key is");
    228          output_.println("_______________________________________________________________________________");
    229          output_.println(generatedDSAPrivateKey);
    230          output_.println("_______________________________________________________________________________");
    231
    232          // write the public key to file
    233          output_.println("################################################################################");
    234          output_.println("Writing the public key of the generated key-pair to file: " + args[1]);
    235          DSAPublicKey exportableDsaPublicKey = generatedDSAPublicKey;
    236          BigInteger p = new BigInteger(1, exportableDsaPublicKey.getPrime().getByteArrayValue());
    237          BigInteger q = new BigInteger(1, exportableDsaPublicKey.getSubprime().getByteArrayValue());
    238          BigInteger g = new BigInteger(1, exportableDsaPublicKey.getBase().getByteArrayValue());
    239          BigInteger y = new BigInteger(1, exportableDsaPublicKey.getValue().getByteArrayValue());
    240          DSAPublicKeySpec rsaPublicKeySpec = new DSAPublicKeySpec(y, p, q, g);
    241          KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    242          java.security.interfaces.DSAPublicKey javaDsaPublicKey = (java.security.interfaces.DSAPublicKey)
    243              keyFactory.generatePublic(rsaPublicKeySpec);
    244          X509EncodedKeySpec x509EncodedPublicKey = (X509EncodedKeySpec)
    245              keyFactory.getKeySpec(javaDsaPublicKey, X509EncodedKeySpec.class);
    246
    247          FileOutputStream publicKeyFileStream = new FileOutputStream(args[1]);
    248          publicKeyFileStream.write(x509EncodedPublicKey.getEncoded());
    249          publicKeyFileStream.flush();
    250          publicKeyFileStream.close();
    251
    252          output_.println("################################################################################");
    253
    254          // now we try to search for the generated keys
    255          output_.println("################################################################################");
    256          output_.println("Trying to search for the public key of the generated key-pair by ID: " +
    257                          Functions.toHexString(id));
    258          // set the search template for the public key
    259          DSAPublicKey exportDsaPublicKeyTemplate = new DSAPublicKey();
    260          exportDsaPublicKeyTemplate.getId().setByteArrayValue(id);
    261
    262          session.findObjectsInit(exportDsaPublicKeyTemplate);
    263          Object[] foundPublicKeys = session.findObjects(1);
    264          session.findObjectsFinal();
    265
    266          if (foundPublicKeys.length != 1) {
    267            output_.println("Error: Cannot find the public key under the given ID!");
    268          } else {
    269            output_.println("Found public key!");
    270            output_.println("_______________________________________________________________________________");
    271            output_.println(foundPublicKeys[0]);
    272            output_.println("_______________________________________________________________________________");
    273          }
    274
    275          output_.println("################################################################################");
    276
    277          session.closeSession();
    278          pkcs11Module.finalize(null);
    279
    280        } catch (Throwable thr) {
    281          thr.printStackTrace();
    282        }
    283      }
    284
    285      public static void printUsage() {
    286        output_.println("Usage: GenerateKeyPair <PKCS#11 module> <X.509 encoded public key output file>");
    287        output_.println(" e.g.: GenerateKeyPair pk2priv.dll publicKey.xpk");
    288        output_.println("The given DLL must be in the search path of the system.");
    289      }
    290
    291    }