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.KeyFactory;
052 import java.security.spec.RSAPublicKeySpec;
053 import java.security.spec.X509EncodedKeySpec;
054 import java.util.Arrays;
055 import java.util.HashSet;
056 import java.util.Random;
057
058 import iaik.pkcs.pkcs11.Mechanism;
059 import iaik.pkcs.pkcs11.MechanismInfo;
060 import iaik.pkcs.pkcs11.Module;
061 import iaik.pkcs.pkcs11.Session;
062 import iaik.pkcs.pkcs11.Slot;
063 import iaik.pkcs.pkcs11.Token;
064 import iaik.pkcs.pkcs11.TokenInfo;
065 import iaik.pkcs.pkcs11.objects.KeyPair;
066 import iaik.pkcs.pkcs11.objects.Object;
067 import iaik.pkcs.pkcs11.objects.RSAPrivateKey;
068 import iaik.pkcs.pkcs11.objects.RSAPublicKey;
069 import iaik.pkcs.pkcs11.wrapper.Functions;
070
071
072
073 /**
074 * This demo program generates a 2048 bit RSA key-pair on the token and writes
075 * the public key to a file.
076 *
077 * @author <a href="mailto:Karl.Scheibelhofer@iaik.at"> Karl Scheibelhofer </a>
078 * @version 0.1
079 * @invariants
080 */
081 public class GenerateKeyPair2048 {
082
083 static BufferedReader input_;
084
085 static PrintWriter output_;
086
087 static {
088 try {
089 //output_ = new PrintWriter(new FileWriter("SignAndVerify_output.txt"), true);
090 output_ = new PrintWriter(System.out, true);
091 input_ = new BufferedReader(new InputStreamReader(System.in));
092 } catch (Throwable thr) {
093 thr.printStackTrace();
094 output_ = new PrintWriter(System.out, true);
095 input_ = new BufferedReader(new InputStreamReader(System.in));
096 }
097 }
098
099 public static void main(String[] args) {
100 if (args.length != 2) {
101 printUsage();
102 System.exit(1);
103 }
104
105 try {
106
107 //Security.addProvider(new IAIK());
108
109 Module pkcs11Module = Module.getInstance(args[0]);
110 pkcs11Module.initialize(null);
111
112 Slot[] slots = pkcs11Module.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
113
114 if (slots.length == 0) {
115 output_.println("No slot with present token found!");
116 System.exit(0);
117 }
118
119 Slot selectedSlot = slots[0];
120 Token token = selectedSlot.getToken();
121 TokenInfo tokenInfo = token.getTokenInfo();
122
123 output_.println("################################################################################");
124 output_.println("Information of Token:");
125 output_.println(tokenInfo);
126 output_.println("################################################################################");
127
128 Session session = Util.openAuthorizedSession(token, Token.SessionReadWriteBehavior.RW_SESSION, output_, input_);
129 // token.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RW_SESSION, null, null);
130
131 output_.println("################################################################################");
132 output_.print("Generating new 2048 bit RSA key-pair... ");
133 output_.flush();
134
135 // first check out what attributes of the keys we may set
136 HashSet supportedMechanisms = new HashSet(Arrays.asList(token.getMechanismList()));
137
138 MechanismInfo signatureMechanismInfo;
139 if (supportedMechanisms.contains(Mechanism.RSA_PKCS)) {
140 signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_PKCS);
141 } else if (supportedMechanisms.contains(Mechanism.RSA_X_509)) {
142 signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_X_509);
143 } else if (supportedMechanisms.contains(Mechanism.RSA_9796)) {
144 signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_9796);
145 } else if (supportedMechanisms.contains(Mechanism.RSA_PKCS_OAEP)) {
146 signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_PKCS_OAEP);
147 } else {
148 signatureMechanismInfo = null;
149 }
150
151 Mechanism keyPairGenerationMechanism = Mechanism.RSA_PKCS_KEY_PAIR_GEN;
152 RSAPublicKey rsaPublicKeyTemplate = new RSAPublicKey();
153 RSAPrivateKey rsaPrivateKeyTemplate = new RSAPrivateKey();
154
155 // set the general attributes for the public key
156 rsaPublicKeyTemplate.getModulusBits().setLongValue(new Long(2048));
157 byte[] publicExponentBytes = {0x01, 0x00, 0x01}; // 2^16 + 1
158 rsaPublicKeyTemplate.getPublicExponent().setByteArrayValue(publicExponentBytes);
159 rsaPublicKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
160 byte[] id = new byte[20];
161 new Random().nextBytes(id);
162 rsaPublicKeyTemplate.getId().setByteArrayValue(id);
163 //rsaPublicKeyTemplate.getLabel().setCharArrayValue(args[2].toCharArray());
164
165 rsaPrivateKeyTemplate.getSensitive().setBooleanValue(Boolean.TRUE);
166 rsaPrivateKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
167 rsaPrivateKeyTemplate.getPrivate().setBooleanValue(Boolean.TRUE);
168 rsaPrivateKeyTemplate.getId().setByteArrayValue(id);
169 //byte[] subject = args[1].getBytes();
170 //rsaPrivateKeyTemplate.getSubject().setByteArrayValue(subject);
171 //rsaPrivateKeyTemplate.getLabel().setCharArrayValue(args[2].toCharArray());
172
173 // set the attributes in a way netscape does, this should work with most tokens
174 if (signatureMechanismInfo != null) {
175 rsaPublicKeyTemplate.getVerify().setBooleanValue(new Boolean(signatureMechanismInfo.isVerify()));
176 rsaPublicKeyTemplate.getVerifyRecover().setBooleanValue(new Boolean(signatureMechanismInfo.isVerifyRecover()));
177 rsaPublicKeyTemplate.getEncrypt().setBooleanValue(new Boolean(signatureMechanismInfo.isEncrypt()));
178 rsaPublicKeyTemplate.getDerive().setBooleanValue(new Boolean(signatureMechanismInfo.isDerive()));
179 rsaPublicKeyTemplate.getWrap().setBooleanValue(new Boolean(signatureMechanismInfo.isWrap()));
180
181 rsaPrivateKeyTemplate.getSign().setBooleanValue(new Boolean(signatureMechanismInfo.isSign()));
182 rsaPrivateKeyTemplate.getSignRecover().setBooleanValue(new Boolean(signatureMechanismInfo.isSignRecover()));
183 rsaPrivateKeyTemplate.getDecrypt().setBooleanValue(new Boolean(signatureMechanismInfo.isDecrypt()));
184 rsaPrivateKeyTemplate.getDerive().setBooleanValue(new Boolean(signatureMechanismInfo.isDerive()));
185 rsaPrivateKeyTemplate.getUnwrap().setBooleanValue(new Boolean(signatureMechanismInfo.isUnwrap()));
186 } else {
187 // if we have no information we assume these attributes
188 rsaPrivateKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);
189 rsaPrivateKeyTemplate.getDecrypt().setBooleanValue(Boolean.TRUE);
190
191 rsaPublicKeyTemplate.getVerify().setBooleanValue(Boolean.TRUE);
192 rsaPublicKeyTemplate.getEncrypt().setBooleanValue(Boolean.TRUE);
193 }
194
195 // netscape does not set these attribute, so we do no either
196 rsaPublicKeyTemplate.getKeyType().setPresent(false);
197 rsaPublicKeyTemplate.getObjectClass().setPresent(false);
198
199 rsaPrivateKeyTemplate.getKeyType().setPresent(false);
200 rsaPrivateKeyTemplate.getObjectClass().setPresent(false);
201
202 KeyPair generatedKeyPair = session.generateKeyPair(keyPairGenerationMechanism, rsaPublicKeyTemplate, rsaPrivateKeyTemplate);
203 RSAPublicKey generatedRSAPublicKey = (RSAPublicKey) generatedKeyPair.getPublicKey();
204 RSAPrivateKey generatedRSAPrivateKey = (RSAPrivateKey) generatedKeyPair.getPrivateKey();
205 // no we may work with the keys...
206
207 output_.println("Success");
208 output_.println("The public key is");
209 output_.println("_______________________________________________________________________________");
210 output_.println(generatedRSAPublicKey);
211 output_.println("_______________________________________________________________________________");
212 output_.println("The private key is");
213 output_.println("_______________________________________________________________________________");
214 output_.println(generatedRSAPrivateKey);
215 output_.println("_______________________________________________________________________________");
216
217 // write the public key to file
218 output_.println("################################################################################");
219 output_.println("Writing the public key of the generated key-pair to file: " + args[1]);
220 RSAPublicKey exportableRsaPublicKey = generatedRSAPublicKey;
221 BigInteger modulus = new BigInteger(1, exportableRsaPublicKey.getModulus().getByteArrayValue());
222 BigInteger publicExponent = new BigInteger(1, exportableRsaPublicKey.getPublicExponent().getByteArrayValue());
223 RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
224 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
225 java.security.interfaces.RSAPublicKey javaRsaPublicKey = (java.security.interfaces.RSAPublicKey)
226 keyFactory.generatePublic(rsaPublicKeySpec);
227 X509EncodedKeySpec x509EncodedPublicKey = (X509EncodedKeySpec)
228 keyFactory.getKeySpec(javaRsaPublicKey, X509EncodedKeySpec.class);
229
230 FileOutputStream publicKeyFileStream = new FileOutputStream(args[1]);
231 publicKeyFileStream.write(x509EncodedPublicKey.getEncoded());
232 publicKeyFileStream.flush();
233 publicKeyFileStream.close();
234
235 output_.println("################################################################################");
236
237 // now we try to search for the generated keys
238 output_.println("################################################################################");
239 output_.println("Trying to search for the public key of the generated key-pair by ID: " +
240 Functions.toHexString(id));
241 // set the search template for the public key
242 RSAPublicKey exportRsaPublicKeyTemplate = new RSAPublicKey();
243 exportRsaPublicKeyTemplate.getId().setByteArrayValue(id);
244
245 session.findObjectsInit(exportRsaPublicKeyTemplate);
246 Object[] foundPublicKeys = session.findObjects(1);
247 session.findObjectsFinal();
248
249 if (foundPublicKeys.length != 1) {
250 output_.println("Error: Cannot find the public key under the given ID!");
251 } else {
252 output_.println("Found public key!");
253 output_.println("_______________________________________________________________________________");
254 output_.println(foundPublicKeys[0]);
255 output_.println("_______________________________________________________________________________");
256 }
257
258 output_.println("################################################################################");
259
260 session.closeSession();
261 pkcs11Module.finalize(null);
262
263 } catch (Throwable thr) {
264 thr.printStackTrace();
265 }
266 }
267
268 public static void printUsage() {
269 output_.println("Usage: GenerateKeyPair2048 <PKCS#11 module> <X.509 encoded public key file>");
270 output_.println(" e.g.: GenerateKeyPair2048 pk2priv.dll publicKey.xpk");
271 output_.println("The given DLL must be in the search path of the system.");
272 }
273
274 }