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