1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/**
6 * Licensed to the Apache Software Foundation (ASF) under one
7 * or more contributor license agreements. See the NOTICE file
8 * distributed with this work for additional information
9 * regarding copyright ownership. The ASF licenses this file
10 * to you under the Apache License, Version 2.0 (the
11 * "License"); you may not use this file except in compliance
12 * with the License. You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing,
17 * software distributed under the License is distributed on an
18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 * KIND, either express or implied. See the License for the
20 * specific language governing permissions and limitations
21 * under the License.
22 */
23package com.sun.org.apache.xml.internal.security.algorithms.implementations;
24
25import java.security.InvalidAlgorithmParameterException;
26import java.security.InvalidKeyException;
27import java.security.Key;
28import java.security.SecureRandom;
29import java.security.spec.AlgorithmParameterSpec;
30
31import javax.crypto.Mac;
32import javax.crypto.SecretKey;
33
34import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper;
35import com.sun.org.apache.xml.internal.security.algorithms.MessageDigestAlgorithm;
36import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi;
37import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
38import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
39import com.sun.org.apache.xml.internal.security.utils.Constants;
40import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
41import org.w3c.dom.Document;
42import org.w3c.dom.Element;
43import org.w3c.dom.Text;
44
45public abstract class IntegrityHmac extends SignatureAlgorithmSpi {
46
47    /** {@link org.apache.commons.logging} logging facility */
48    private static java.util.logging.Logger log =
49        java.util.logging.Logger.getLogger(IntegrityHmac.class.getName());
50
51    /** Field macAlgorithm */
52    private Mac macAlgorithm = null;
53
54    /** Field HMACOutputLength */
55    private int HMACOutputLength = 0;
56    private boolean HMACOutputLengthSet = false;
57
58    /**
59     * Method engineGetURI
60     *
61     *@inheritDoc
62     */
63    public abstract String engineGetURI();
64
65    /**
66     * Returns the output length of the hash/digest.
67     */
68    abstract int getDigestLength();
69
70    /**
71     * Method IntegrityHmac
72     *
73     * @throws XMLSignatureException
74     */
75    public IntegrityHmac() throws XMLSignatureException {
76        String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI());
77        if (log.isLoggable(java.util.logging.Level.FINE)) {
78            log.log(java.util.logging.Level.FINE, "Created IntegrityHmacSHA1 using " + algorithmID);
79        }
80
81        try {
82            this.macAlgorithm = Mac.getInstance(algorithmID);
83        } catch (java.security.NoSuchAlgorithmException ex) {
84            Object[] exArgs = { algorithmID, ex.getLocalizedMessage() };
85
86            throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs);
87        }
88    }
89
90    /**
91     * Proxy method for {@link java.security.Signature#setParameter(
92     * java.security.spec.AlgorithmParameterSpec)}
93     * which is executed on the internal {@link java.security.Signature} object.
94     *
95     * @param params
96     * @throws XMLSignatureException
97     */
98    protected void engineSetParameter(AlgorithmParameterSpec params) throws XMLSignatureException {
99        throw new XMLSignatureException("empty");
100    }
101
102    public void reset() {
103        HMACOutputLength = 0;
104        HMACOutputLengthSet = false;
105        this.macAlgorithm.reset();
106    }
107
108    /**
109     * Proxy method for {@link java.security.Signature#verify(byte[])}
110     * which is executed on the internal {@link java.security.Signature} object.
111     *
112     * @param signature
113     * @return true if the signature is correct
114     * @throws XMLSignatureException
115     */
116    protected boolean engineVerify(byte[] signature) throws XMLSignatureException {
117        try {
118            if (this.HMACOutputLengthSet && this.HMACOutputLength < getDigestLength()) {
119                if (log.isLoggable(java.util.logging.Level.FINE)) {
120                    log.log(java.util.logging.Level.FINE, "HMACOutputLength must not be less than " + getDigestLength());
121                }
122                Object[] exArgs = { String.valueOf(getDigestLength()) };
123                throw new XMLSignatureException("algorithms.HMACOutputLengthMin", exArgs);
124            } else {
125                byte[] completeResult = this.macAlgorithm.doFinal();
126                return MessageDigestAlgorithm.isEqual(completeResult, signature);
127            }
128        } catch (IllegalStateException ex) {
129            throw new XMLSignatureException("empty", ex);
130        }
131    }
132
133    /**
134     * Proxy method for {@link java.security.Signature#initVerify(java.security.PublicKey)}
135     * which is executed on the internal {@link java.security.Signature} object.
136     *
137     * @param secretKey
138     * @throws XMLSignatureException
139     */
140    protected void engineInitVerify(Key secretKey) throws XMLSignatureException {
141        if (!(secretKey instanceof SecretKey)) {
142            String supplied = secretKey.getClass().getName();
143            String needed = SecretKey.class.getName();
144            Object exArgs[] = { supplied, needed };
145
146            throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", exArgs);
147        }
148
149        try {
150            this.macAlgorithm.init(secretKey);
151        } catch (InvalidKeyException ex) {
152            // reinstantiate Mac object to work around bug in JDK
153            // see: http://bugs.java.com/view_bug.do?bug_id=4953555
154            Mac mac = this.macAlgorithm;
155            try {
156                this.macAlgorithm = Mac.getInstance(macAlgorithm.getAlgorithm());
157            } catch (Exception e) {
158                // this shouldn't occur, but if it does, restore previous Mac
159                if (log.isLoggable(java.util.logging.Level.FINE)) {
160                    log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Mac:" + e);
161                }
162                this.macAlgorithm = mac;
163            }
164            throw new XMLSignatureException("empty", ex);
165        }
166    }
167
168    /**
169     * Proxy method for {@link java.security.Signature#sign()}
170     * which is executed on the internal {@link java.security.Signature} object.
171     *
172     * @return the result of the {@link java.security.Signature#sign()} method
173     * @throws XMLSignatureException
174     */
175    protected byte[] engineSign() throws XMLSignatureException {
176        try {
177            if (this.HMACOutputLengthSet && this.HMACOutputLength < getDigestLength()) {
178                if (log.isLoggable(java.util.logging.Level.FINE)) {
179                    log.log(java.util.logging.Level.FINE, "HMACOutputLength must not be less than " + getDigestLength());
180                }
181                Object[] exArgs = { String.valueOf(getDigestLength()) };
182                throw new XMLSignatureException("algorithms.HMACOutputLengthMin", exArgs);
183            } else {
184                return this.macAlgorithm.doFinal();
185            }
186        } catch (IllegalStateException ex) {
187            throw new XMLSignatureException("empty", ex);
188        }
189    }
190
191    /**
192     * Method engineInitSign
193     *
194     * @param secretKey
195     * @throws XMLSignatureException
196     */
197    protected void engineInitSign(Key secretKey) throws XMLSignatureException {
198        if (!(secretKey instanceof SecretKey)) {
199            String supplied = secretKey.getClass().getName();
200            String needed = SecretKey.class.getName();
201            Object exArgs[] = { supplied, needed };
202
203            throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", exArgs);
204        }
205
206        try {
207            this.macAlgorithm.init(secretKey);
208        } catch (InvalidKeyException ex) {
209            throw new XMLSignatureException("empty", ex);
210        }
211    }
212
213    /**
214     * Method engineInitSign
215     *
216     * @param secretKey
217     * @param algorithmParameterSpec
218     * @throws XMLSignatureException
219     */
220    protected void engineInitSign(
221        Key secretKey, AlgorithmParameterSpec algorithmParameterSpec
222    ) throws XMLSignatureException {
223        if (!(secretKey instanceof SecretKey)) {
224            String supplied = secretKey.getClass().getName();
225            String needed = SecretKey.class.getName();
226            Object exArgs[] = { supplied, needed };
227
228            throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", exArgs);
229        }
230
231        try {
232            this.macAlgorithm.init(secretKey, algorithmParameterSpec);
233        } catch (InvalidKeyException ex) {
234            throw new XMLSignatureException("empty", ex);
235        } catch (InvalidAlgorithmParameterException ex) {
236            throw new XMLSignatureException("empty", ex);
237        }
238    }
239
240    /**
241     * Method engineInitSign
242     *
243     * @param secretKey
244     * @param secureRandom
245     * @throws XMLSignatureException
246     */
247    protected void engineInitSign(Key secretKey, SecureRandom secureRandom)
248        throws XMLSignatureException {
249        throw new XMLSignatureException("algorithms.CannotUseSecureRandomOnMAC");
250    }
251
252    /**
253     * Proxy method for {@link java.security.Signature#update(byte[])}
254     * which is executed on the internal {@link java.security.Signature} object.
255     *
256     * @param input
257     * @throws XMLSignatureException
258     */
259    protected void engineUpdate(byte[] input) throws XMLSignatureException {
260        try {
261            this.macAlgorithm.update(input);
262        } catch (IllegalStateException ex) {
263            throw new XMLSignatureException("empty", ex);
264        }
265    }
266
267    /**
268     * Proxy method for {@link java.security.Signature#update(byte)}
269     * which is executed on the internal {@link java.security.Signature} object.
270     *
271     * @param input
272     * @throws XMLSignatureException
273     */
274    protected void engineUpdate(byte input) throws XMLSignatureException {
275        try {
276            this.macAlgorithm.update(input);
277        } catch (IllegalStateException ex) {
278            throw new XMLSignatureException("empty", ex);
279        }
280    }
281
282    /**
283     * Proxy method for {@link java.security.Signature#update(byte[], int, int)}
284     * which is executed on the internal {@link java.security.Signature} object.
285     *
286     * @param buf
287     * @param offset
288     * @param len
289     * @throws XMLSignatureException
290     */
291    protected void engineUpdate(byte buf[], int offset, int len) throws XMLSignatureException {
292        try {
293            this.macAlgorithm.update(buf, offset, len);
294        } catch (IllegalStateException ex) {
295            throw new XMLSignatureException("empty", ex);
296        }
297    }
298
299    /**
300     * Method engineGetJCEAlgorithmString
301     * @inheritDoc
302     *
303     */
304    protected String engineGetJCEAlgorithmString() {
305        return this.macAlgorithm.getAlgorithm();
306    }
307
308    /**
309     * Method engineGetJCEAlgorithmString
310     *
311     * @inheritDoc
312     */
313    protected String engineGetJCEProviderName() {
314        return this.macAlgorithm.getProvider().getName();
315    }
316
317    /**
318     * Method engineSetHMACOutputLength
319     *
320     * @param HMACOutputLength
321     */
322    protected void engineSetHMACOutputLength(int HMACOutputLength) {
323        this.HMACOutputLength = HMACOutputLength;
324        this.HMACOutputLengthSet = true;
325    }
326
327    /**
328     * Method engineGetContextFromElement
329     *
330     * @param element
331     */
332    protected void engineGetContextFromElement(Element element) {
333        super.engineGetContextFromElement(element);
334
335        if (element == null) {
336            throw new IllegalArgumentException("element null");
337        }
338
339        Text hmaclength =
340            XMLUtils.selectDsNodeText(element.getFirstChild(), Constants._TAG_HMACOUTPUTLENGTH, 0);
341
342        if (hmaclength != null) {
343            this.HMACOutputLength = Integer.parseInt(hmaclength.getData());
344            this.HMACOutputLengthSet = true;
345        }
346    }
347
348    /**
349     * Method engineAddContextToElement
350     *
351     * @param element
352     */
353    public void engineAddContextToElement(Element element) {
354        if (element == null) {
355            throw new IllegalArgumentException("null element");
356        }
357
358        if (this.HMACOutputLengthSet) {
359            Document doc = element.getOwnerDocument();
360            Element HMElem =
361                XMLUtils.createElementInSignatureSpace(doc, Constants._TAG_HMACOUTPUTLENGTH);
362            Text HMText =
363                doc.createTextNode(Integer.valueOf(this.HMACOutputLength).toString());
364
365            HMElem.appendChild(HMText);
366            XMLUtils.addReturnToElement(element);
367            element.appendChild(HMElem);
368            XMLUtils.addReturnToElement(element);
369        }
370    }
371
372    /**
373     * Class IntegrityHmacSHA1
374     */
375    public static class IntegrityHmacSHA1 extends IntegrityHmac {
376
377        /**
378         * Constructor IntegrityHmacSHA1
379         *
380         * @throws XMLSignatureException
381         */
382        public IntegrityHmacSHA1() throws XMLSignatureException {
383            super();
384        }
385
386        /**
387         * Method engineGetURI
388         * @inheritDoc
389         *
390         */
391        public String engineGetURI() {
392            return XMLSignature.ALGO_ID_MAC_HMAC_SHA1;
393        }
394
395        int getDigestLength() {
396            return 160;
397        }
398    }
399
400    /**
401     * Class IntegrityHmacSHA256
402     */
403    public static class IntegrityHmacSHA256 extends IntegrityHmac {
404
405        /**
406         * Constructor IntegrityHmacSHA256
407         *
408         * @throws XMLSignatureException
409         */
410        public IntegrityHmacSHA256() throws XMLSignatureException {
411            super();
412        }
413
414        /**
415         * Method engineGetURI
416         *
417         * @inheritDoc
418         */
419        public String engineGetURI() {
420            return XMLSignature.ALGO_ID_MAC_HMAC_SHA256;
421        }
422
423        int getDigestLength() {
424            return 256;
425        }
426    }
427
428    /**
429     * Class IntegrityHmacSHA384
430     */
431    public static class IntegrityHmacSHA384 extends IntegrityHmac {
432
433        /**
434         * Constructor IntegrityHmacSHA384
435         *
436         * @throws XMLSignatureException
437         */
438        public IntegrityHmacSHA384() throws XMLSignatureException {
439            super();
440        }
441
442        /**
443         * Method engineGetURI
444         * @inheritDoc
445         *
446         */
447        public String engineGetURI() {
448            return XMLSignature.ALGO_ID_MAC_HMAC_SHA384;
449        }
450
451        int getDigestLength() {
452            return 384;
453        }
454    }
455
456    /**
457     * Class IntegrityHmacSHA512
458     */
459    public static class IntegrityHmacSHA512 extends IntegrityHmac {
460
461        /**
462         * Constructor IntegrityHmacSHA512
463         *
464         * @throws XMLSignatureException
465         */
466        public IntegrityHmacSHA512() throws XMLSignatureException {
467            super();
468        }
469
470        /**
471         * Method engineGetURI
472         * @inheritDoc
473         *
474         */
475        public String engineGetURI() {
476            return XMLSignature.ALGO_ID_MAC_HMAC_SHA512;
477        }
478
479        int getDigestLength() {
480            return 512;
481        }
482    }
483
484    /**
485     * Class IntegrityHmacRIPEMD160
486     */
487    public static class IntegrityHmacRIPEMD160 extends IntegrityHmac {
488
489        /**
490         * Constructor IntegrityHmacRIPEMD160
491         *
492         * @throws XMLSignatureException
493         */
494        public IntegrityHmacRIPEMD160() throws XMLSignatureException {
495            super();
496        }
497
498        /**
499         * Method engineGetURI
500         *
501         * @inheritDoc
502         */
503        public String engineGetURI() {
504            return XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160;
505        }
506
507        int getDigestLength() {
508            return 160;
509        }
510    }
511
512    /**
513     * Class IntegrityHmacMD5
514     */
515    public static class IntegrityHmacMD5 extends IntegrityHmac {
516
517        /**
518         * Constructor IntegrityHmacMD5
519         *
520         * @throws XMLSignatureException
521         */
522        public IntegrityHmacMD5() throws XMLSignatureException {
523            super();
524        }
525
526        /**
527         * Method engineGetURI
528         *
529         * @inheritDoc
530         */
531        public String engineGetURI() {
532            return XMLSignature.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5;
533        }
534
535        int getDigestLength() {
536            return 128;
537        }
538    }
539}
540