KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ejbca > core > protocol > xkms > common > XKMSUtil


1 /*************************************************************************
2  * *
3  * EJBCA: The OpenSource Certificate Authority *
4  * *
5  * This software is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU Lesser General Public *
7  * License as published by the Free Software Foundation; either *
8  * version 2.1 of the License, or any later version. *
9  * *
10  * See terms of license at gnu.org. *
11  * *
12  *************************************************************************/

13
14 package org.ejbca.core.protocol.xkms.common;
15
16 import gnu.inet.encoding.Stringprep;
17 import gnu.inet.encoding.StringprepException;
18
19 import java.io.UnsupportedEncodingException JavaDoc;
20 import java.math.BigInteger JavaDoc;
21 import java.security.InvalidKeyException JavaDoc;
22 import java.security.KeyFactory JavaDoc;
23 import java.security.NoSuchAlgorithmException JavaDoc;
24 import java.security.PrivateKey JavaDoc;
25 import java.security.interfaces.RSAPrivateCrtKey JavaDoc;
26 import java.security.interfaces.RSAPrivateKey JavaDoc;
27 import java.security.spec.InvalidKeySpecException JavaDoc;
28 import java.security.spec.RSAPrivateCrtKeySpec JavaDoc;
29
30 import javax.crypto.Mac;
31 import javax.crypto.SecretKey;
32 import javax.crypto.spec.SecretKeySpec;
33 import javax.xml.bind.JAXBContext;
34 import javax.xml.bind.JAXBElement;
35 import javax.xml.bind.JAXBException;
36 import javax.xml.bind.Marshaller;
37 import javax.xml.bind.PropertyException;
38 import javax.xml.bind.Unmarshaller;
39 import javax.xml.parsers.DocumentBuilder JavaDoc;
40 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
41 import javax.xml.parsers.ParserConfigurationException JavaDoc;
42
43 import org.apache.log4j.Logger;
44 import org.apache.xml.security.algorithms.SignatureAlgorithm;
45 import org.apache.xml.security.encryption.EncryptedData;
46 import org.apache.xml.security.encryption.XMLCipher;
47 import org.apache.xml.security.encryption.XMLEncryptionException;
48 import org.apache.xml.security.exceptions.XMLSecurityException;
49 import org.apache.xml.security.transforms.Transforms;
50 import org.apache.xml.security.utils.EncryptionConstants;
51 import org.ejbca.util.CertTools;
52 import org.w3._2001._04.xmlenc_.EncryptedDataType;
53 import org.w3._2002._03.xkms_.ObjectFactory;
54 import org.w3._2002._03.xkms_.PrivateKeyType;
55 import org.w3._2002._03.xkms_.RSAKeyPairType;
56 import org.w3c.dom.Document JavaDoc;
57 import org.w3c.dom.Element JavaDoc;
58
59 /**
60  * A util class containing static help methods to process various
61  * XKMS messages
62  *
63  *
64  * @author Philip Vendil 2006 dec 30
65  *
66  * @version $Id: XKMSUtil.java,v 1.1.2.1 2007/02/02 09:34:04 anatom Exp $
67  */

68
69 public class XKMSUtil {
70     
71     /** HMAC-SHA1 initial key values */
72     public static final byte[] KEY_AUTHENTICATION = {0x1};
73     public static final byte[] KEY_REVOCATIONCODEIDENTIFIER_PASS1 = {0x2};
74     public static final byte[] KEY_REVOCATIONCODEIDENTIFIER_PASS2 = {0x3};
75     public static final byte[] KEY_PRIVATEKEYDATA = {0x4};
76     
77     private static final String JavaDoc ENCRYPTION_ALGORITHMURI = XMLCipher.TRIPLEDES;
78     private static final String JavaDoc SHAREDSECRET_HASH_ALGORITH = "http://www.w3.org/2000/09/xmldsig#hmac-sha1";
79     
80     private static Logger log = Logger.getLogger(XKMSUtil.class);
81     
82     private static ObjectFactory xKMSObjectFactory = new ObjectFactory();
83     
84     private static JAXBContext jAXBContext = null;
85     private static Marshaller marshaller = null;
86     private static Unmarshaller unmarshaller = null;
87     private static DocumentBuilderFactory JavaDoc dbf = null;
88     
89     static{
90         try {
91             CertTools.installBCProvider();
92             org.apache.xml.security.Init.init();
93
94             jAXBContext = JAXBContext.newInstance("org.w3._2002._03.xkms_:org.w3._2001._04.xmlenc_:org.w3._2000._09.xmldsig_");
95             marshaller = jAXBContext.createMarshaller();
96             try {
97                 marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",new XKMSNamespacePrefixMapper());
98             } catch( PropertyException e ) {
99                 log.error("Error registering namespace mapper property",e);
100             }
101             dbf = DocumentBuilderFactory.newInstance();
102             dbf.setNamespaceAware(true);
103             unmarshaller = jAXBContext.createUnmarshaller();
104
105         } catch (JAXBException e) {
106             log.error("Error initializing RequestAbstractTypeResponseGenerator",e);
107         }
108     }
109
110     /**
111      * Encrypting a java RSA Private key into a PrivateKeyType object used in register,reissue and recover respolses.
112      * using the shared secret.
113      *
114      * The method uses the HMAC-SHA1 for generating the shared secret
115      * and tripple des for encryption
116      *
117      * @param rSAPrivateKey the privatekey
118      * @param sharedSecret the shared secret, cannot be null.
119      * @return The Document with the encrypted key included.
120      * @throws StringprepException if the shared secret doesn't conform with the SASLprep profile as specified in the XKMS specification.
121      * @throws XMLEncryptionException if any other exception occurs during the processing.
122      */

123     public static PrivateKeyType getEncryptedXMLFromPrivateKey(RSAPrivateCrtKey JavaDoc rSAPrivateKey, String JavaDoc sharedSecret) throws StringprepException, XMLEncryptionException{
124         PrivateKeyType privateKeyType = null;
125         try{
126         DocumentBuilder JavaDoc db = dbf.newDocumentBuilder();
127         Document JavaDoc rSAKeyPairDoc = db.newDocument();
128
129         SecretKey sk = getSecretKeyFromPassphrase(sharedSecret,true, 24, KEY_PRIVATEKEYDATA);
130         
131         RSAKeyPairType rSAKeyPairType = xKMSObjectFactory.createRSAKeyPairType();
132        
133         rSAKeyPairType.setModulus(rSAPrivateKey.getModulus().toByteArray());
134         rSAKeyPairType.setExponent(rSAPrivateKey.getPublicExponent().toByteArray());
135         rSAKeyPairType.setP(rSAPrivateKey.getPrimeP().toByteArray());
136         rSAKeyPairType.setQ(rSAPrivateKey.getPrimeQ().toByteArray());
137         rSAKeyPairType.setDP(rSAPrivateKey.getPrimeExponentP().toByteArray());
138         rSAKeyPairType.setDQ(rSAPrivateKey.getPrimeExponentQ().toByteArray());
139         rSAKeyPairType.setInverseQ(rSAPrivateKey.getCrtCoefficient().toByteArray());
140         rSAKeyPairType.setD(rSAPrivateKey.getPrivateExponent().toByteArray());
141
142         JAXBElement<RSAKeyPairType> rSAKeyPair = xKMSObjectFactory.createRSAKeyPair(rSAKeyPairType);
143
144         marshaller.marshal( rSAKeyPair, rSAKeyPairDoc );
145
146         Document JavaDoc envelopedDoc = db.newDocument();
147         Element unencryptedElement = envelopedDoc.createElement("PrivateKey");
148         envelopedDoc.appendChild(unencryptedElement);
149         Element node = (Element) envelopedDoc.adoptNode(rSAKeyPairDoc.getDocumentElement());
150         unencryptedElement.appendChild(node);
151         
152         Element rootElement = envelopedDoc.getDocumentElement();
153        
154         
155         XMLCipher xmlCipher =
156             XMLCipher.getProviderInstance(ENCRYPTION_ALGORITHMURI,"BC");
157         xmlCipher.init(XMLCipher.ENCRYPT_MODE, sk);
158
159         EncryptedData encryptedData = xmlCipher.getEncryptedData();
160         encryptedData.setMimeType("text/xml");
161         
162         xmlCipher.doFinal(envelopedDoc,rootElement,true);
163
164         JAXBElement unmarshalledData = (JAXBElement) unmarshaller.unmarshal(envelopedDoc.getDocumentElement().getFirstChild());
165         
166         EncryptedDataType encryptedDataType = (EncryptedDataType) unmarshalledData.getValue();
167         privateKeyType = xKMSObjectFactory.createPrivateKeyType();
168         privateKeyType.setEncryptedData(encryptedDataType);
169         
170         } catch (ParserConfigurationException JavaDoc e) {
171             log.error("Error encryption private key", e);
172             throw new XMLEncryptionException(e.getMessage(),e);
173         } catch (XMLSecurityException e) {
174             log.error("Error encryption private key", e);
175             throw new XMLEncryptionException(e.getMessage(),e);
176         } catch (JAXBException e) {
177             log.error("Error encryption private key", e);
178             throw new XMLEncryptionException(e.getMessage(),e);
179         } catch (Exception JavaDoc e) {
180             log.error("Error encryption private key", e);
181             throw new XMLEncryptionException(e.getMessage(),e);
182         }
183         
184         return privateKeyType;
185     }
186     
187     /**
188      * Method to get the private key from an XKMS message with an encrypted
189      * PrivateKey tag. The method uses the HMAC-SHA1 for generating the shared secret
190      * and tripple des for encryption.
191      *
192      * @param privateKeyType the JAXB version of the PrivateKey tag
193      * @param sharedSecret the shared secret, cannot be null.
194      * @return a java RSAPrivateKey
195      * @throws StringprepException if the shared secret doesn't conform with the SASLprep profile as specified in the XKMS specification.
196      * @throws XMLEncryptionException if any other exception occurs during the processing.
197      */

198     public static RSAPrivateKey JavaDoc getPrivateKeyFromEncryptedXML(PrivateKeyType privateKeyType, String JavaDoc sharedSecret) throws StringprepException, XMLEncryptionException{
199         RSAPrivateKey JavaDoc privkey2 = null;
200         try{
201         DocumentBuilder JavaDoc db = dbf.newDocumentBuilder();
202         Document JavaDoc privateKeyDoc = db.newDocument();
203         marshaller.marshal(privateKeyType, privateKeyDoc);
204         
205         Element encryptedDataElement =
206             (Element) privateKeyDoc.getElementsByTagNameNS(
207                 EncryptionConstants.EncryptionSpecNS,
208                 EncryptionConstants._TAG_ENCRYPTEDDATA).item(0);
209
210         SecretKey sk = getSecretKeyFromPassphrase(sharedSecret,true, 24, KEY_PRIVATEKEYDATA);
211                         
212         XMLCipher xmlDecipher = XMLCipher.getProviderInstance(ENCRYPTION_ALGORITHMURI,"BC");
213         
214         xmlDecipher.init(XMLCipher.DECRYPT_MODE, sk);
215        
216         xmlDecipher.doFinal(privateKeyDoc, encryptedDataElement);
217         
218         JAXBElement<RSAKeyPairType> rSAKeyPair = (JAXBElement<RSAKeyPairType>) unmarshaller.unmarshal(privateKeyDoc.getDocumentElement().getFirstChild());
219         
220         RSAKeyPairType rSAKeyPairType = rSAKeyPair.getValue();
221         
222                 
223         RSAPrivateCrtKeySpec JavaDoc rSAPrivateKeySpec = new RSAPrivateCrtKeySpec JavaDoc(new BigInteger JavaDoc(rSAKeyPairType.getModulus()), new BigInteger JavaDoc(rSAKeyPairType.getExponent()),
224                              new BigInteger JavaDoc(rSAKeyPairType.getD()), new BigInteger JavaDoc(rSAKeyPairType.getP()),
225                              new BigInteger JavaDoc(rSAKeyPairType.getQ()), new BigInteger JavaDoc(rSAKeyPairType.getDP()),
226                              new BigInteger JavaDoc(rSAKeyPairType.getDQ()), new BigInteger JavaDoc(rSAKeyPairType.getInverseQ()));
227         
228         privkey2 = (RSAPrivateKey JavaDoc) KeyFactory.getInstance("RSA").generatePrivate(rSAPrivateKeySpec);
229         
230         } catch (InvalidKeySpecException JavaDoc e) {
231             log.error("Error decrypting private key", e);
232             throw new XMLEncryptionException(e.getMessage(),e);
233         } catch (NoSuchAlgorithmException JavaDoc e) {
234             log.error("Error decrypting private key", e);
235             throw new XMLEncryptionException(e.getMessage(),e);
236         } catch (XMLSecurityException e) {
237             log.error("Error decrypting private key", e);
238             throw new XMLEncryptionException(e.getMessage(),e);
239         } catch (JAXBException e) {
240             log.error("Error decrypting private key", e);
241             throw new XMLEncryptionException(e.getMessage(),e);
242         } catch (ParserConfigurationException JavaDoc e) {
243             log.error("Error decrypting private key", e);
244             throw new XMLEncryptionException(e.getMessage(),e);
245         } catch (Exception JavaDoc e) {
246             log.error("Error decrypting private key", e);
247             throw new XMLEncryptionException(e.getMessage(),e);
248         }
249         
250         return privkey2;
251     }
252     
253     /**
254      * Genereates a secret key from a passphrase according to the
255      * XKMS specifikation. The HMAC-SHA1 algorithm is used.
256      *
257      * The passphrase is first checked against SALSPrep profile
258      * according to the XKMS specificatiom
259      *
260      * @param passphrase the passphrase to use, may no be null
261      * @param performSASLprep if sASLprep should be called on the input string.
262      * @param keylength the length of the key returned.
263      * @param keyType one of the initial KEY_ constants
264      * @return The SecretKey used in encryption/decryption
265      * @throws StringprepException if the passphrase doesn't fullfull the SASLPrep profile
266      * @throws XMLEncryptionException If any other exception occured during generation.
267      */

268     public static SecretKey getSecretKeyFromPassphrase(String JavaDoc passphrase, boolean performSASLprep, int keylength, byte[] keyType) throws StringprepException, XMLEncryptionException{
269         SecretKey retval = null;
270         try{
271         byte[] finalKey = new byte[keylength];
272         
273         int keyIndex = 0;
274         byte[] currentKey = keyType;
275        
276
277         Document JavaDoc doc = dbf.newDocumentBuilder().newDocument();
278         SignatureAlgorithm sa = new SignatureAlgorithm(doc,
279                 SHAREDSECRET_HASH_ALGORITH,
280                 33);
281         
282         // Make the string saslpreped
283
String JavaDoc sASLPrepedPassword = passphrase;
284         if(performSASLprep){
285             sASLPrepedPassword= Stringprep.saslprep(passphrase);
286         }
287         
288         while(keyIndex < keylength){
289             SecretKey sk = new SecretKeySpec(currentKey,
290                     sa.getJCEAlgorithmString());
291
292             Mac m = Mac.getInstance("HmacSHA1");
293             m.init(sk);
294             m.update(sASLPrepedPassword.getBytes("ISO8859-1"));
295             byte[] mac = m.doFinal();
296             for(int i=0;i<mac.length;i++){
297                if(keyIndex < keylength){
298                    finalKey[keyIndex] = mac[i];
299                    keyIndex++;
300                }else{
301                    break;
302                }
303             }
304             mac[0] = (byte) (mac[0] ^ currentKey[0]);
305             currentKey = mac;
306             
307             retval = new SecretKeySpec(finalKey,
308                     sa.getJCEAlgorithmString());
309         }
310         }catch(IllegalMonitorStateException JavaDoc e){
311             
312         } catch (ParserConfigurationException JavaDoc e) {
313             log.error("Error generating secret key", e);
314             throw new XMLEncryptionException(e.getMessage(),e);
315         } catch (XMLSecurityException e) {
316             log.error("Error generating secret key", e);
317             throw new XMLEncryptionException(e.getMessage(),e);
318         } catch (NoSuchAlgorithmException JavaDoc e) {
319             log.error("Error generating secret key", e);
320             throw new XMLEncryptionException(e.getMessage(),e);
321         } catch (InvalidKeyException JavaDoc e) {
322             log.error("Error generating secret key", e);
323             throw new XMLEncryptionException(e.getMessage(),e);
324         } catch (IllegalStateException JavaDoc e) {
325             log.error("Error generating secret key", e);
326             throw new XMLEncryptionException(e.getMessage(),e);
327         } catch (UnsupportedEncodingException JavaDoc e) {
328             log.error("Error generating secret key", e);
329             throw new XMLEncryptionException(e.getMessage(),e);
330         }
331         
332         return retval;
333     }
334     
335     /**
336      * Method appending a authorization keybinding element to
337      * a requestDoc
338      *
339      * @param requestDoc
340      * @param passphrase
341      * @param prototypeKeyBindingId
342      * @return the requestDoc with authorization appended
343      * @throws StringprepException if the passphrase doesn't fullfull the SASLPrep profile
344      * @throws XMLSecurityException If any other exception occured during generation.
345      */

346     public static Document JavaDoc appendKeyBindingAuthentication(Document JavaDoc requestDoc,String JavaDoc passphrase, String JavaDoc prototypeKeyBindingId) throws StringprepException, XMLSecurityException{
347         SecretKey sk = XKMSUtil.getSecretKeyFromPassphrase(passphrase, true, 20, XKMSUtil.KEY_AUTHENTICATION);
348         
349         org.apache.xml.security.signature.XMLSignature authXMLSig = new org.apache.xml.security.signature.XMLSignature(requestDoc, "", org.apache.xml.security.signature.XMLSignature.ALGO_ID_MAC_HMAC_SHA1, org.apache.xml.security.c14n.Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
350         org.apache.xml.security.transforms.Transforms transforms = new org.apache.xml.security.transforms.Transforms(requestDoc);
351         transforms.addTransform(org.apache.xml.security.transforms.Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
352         authXMLSig.addDocument("#" + prototypeKeyBindingId, transforms, org.apache.xml.security.utils.Constants.ALGO_ID_DIGEST_SHA1);
353     
354         authXMLSig.sign(sk);
355         
356         Element authenticationElement = requestDoc.createElementNS("http://www.w3.org/2002/03/xkms#", "Authentication");
357         Element keyBindingAuthenticationElement = requestDoc.createElementNS("http://www.w3.org/2002/03/xkms#", "KeyBindingAuthentication");
358         keyBindingAuthenticationElement.appendChild(authXMLSig.getElement().cloneNode(true));
359         authenticationElement.appendChild(keyBindingAuthenticationElement);
360         requestDoc.getDocumentElement().appendChild(authenticationElement);
361         
362         return requestDoc;
363     }
364
365     public static Document JavaDoc appendProofOfPossession(Document JavaDoc requestDoc,PrivateKey JavaDoc privateKey, String JavaDoc prototypeKeyBindingId)throws XMLSecurityException{
366         org.apache.xml.security.signature.XMLSignature xmlSig = new org.apache.xml.security.signature.XMLSignature(requestDoc, "", org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, org.apache.xml.security.c14n.Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
367         Transforms transforms = new org.apache.xml.security.transforms.Transforms(requestDoc);
368         transforms.addTransform(org.apache.xml.security.transforms.Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
369         
370         xmlSig.addDocument("#" + prototypeKeyBindingId, transforms, org.apache.xml.security.utils.Constants.ALGO_ID_DIGEST_SHA1);
371     
372         xmlSig.sign(privateKey);
373         
374         Element pOPElement = requestDoc.createElementNS("http://www.w3.org/2002/03/xkms#", "ProofOfPossession");
375         pOPElement.appendChild(xmlSig.getElement().cloneNode(true));
376         requestDoc.getDocumentElement().appendChild(pOPElement);
377         
378         return requestDoc;
379     }
380     
381 }
382
Popular Tags