1/*
2 * Copyright 2007 Netflix, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package net.oauth.signature;
18
19import java.io.UnsupportedEncodingException;
20import java.security.GeneralSecurityException;
21import java.util.Arrays;
22
23import javax.crypto.Mac;
24import javax.crypto.SecretKey;
25import javax.crypto.spec.SecretKeySpec;
26
27import net.oauth.OAuth;
28import net.oauth.OAuthException;
29
30/**
31 * @author John Kristian
32 * @hide
33 */
34class HMAC_SHA1 extends OAuthSignatureMethod {
35
36    @Override
37    protected String getSignature(String baseString) throws OAuthException {
38        try {
39            String signature = base64Encode(computeSignature(baseString));
40            return signature;
41        } catch (GeneralSecurityException e) {
42            throw new OAuthException(e);
43        } catch (UnsupportedEncodingException e) {
44            throw new OAuthException(e);
45        }
46    }
47
48    @Override
49    protected boolean isValid(String signature, String baseString)
50    throws OAuthException {
51        try {
52            byte[] expected = computeSignature(baseString);
53            byte[] actual = decodeBase64(signature);
54            return Arrays.equals(expected, actual);
55        } catch (GeneralSecurityException e) {
56            throw new OAuthException(e);
57        } catch (UnsupportedEncodingException e) {
58            throw new OAuthException(e);
59        }
60    }
61
62    private byte[] computeSignature(String baseString)
63            throws GeneralSecurityException, UnsupportedEncodingException {
64        SecretKey key = null;
65        synchronized (this) {
66            if (this.key == null) {
67                String keyString = OAuth.percentEncode(getConsumerSecret())
68                        + '&' + OAuth.percentEncode(getTokenSecret());
69                byte[] keyBytes = keyString.getBytes(ENCODING);
70                this.key = new SecretKeySpec(keyBytes, MAC_NAME);
71            }
72            key = this.key;
73        }
74        Mac mac = Mac.getInstance(MAC_NAME);
75        mac.init(key);
76        byte[] text = baseString.getBytes(ENCODING);
77        return mac.doFinal(text);
78    }
79
80    /** ISO-8859-1 or US-ASCII would work, too. */
81    private static final String ENCODING = OAuth.ENCODING;
82
83    private static final String MAC_NAME = "HmacSHA1";
84
85    private SecretKey key = null;
86
87    @Override
88    public void setConsumerSecret(String consumerSecret) {
89        synchronized (this) {
90            key = null;
91        }
92        super.setConsumerSecret(consumerSecret);
93    }
94
95    @Override
96    public void setTokenSecret(String tokenSecret) {
97        synchronized (this) {
98            key = null;
99        }
100        super.setTokenSecret(tokenSecret);
101    }
102
103}
104