1b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/*
2b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Copyright 2007 Google, 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.ByteArrayInputStream;
20b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.UnsupportedEncodingException;
21b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.GeneralSecurityException;
22b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.KeyFactory;
23b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.PrivateKey;
24b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.PublicKey;
25b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.Signature;
26b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.cert.CertificateFactory;
27b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.cert.X509Certificate;
28b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.spec.EncodedKeySpec;
29b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.spec.PKCS8EncodedKeySpec;
30b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.security.spec.X509EncodedKeySpec;
31b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
32b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuth;
33b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthAccessor;
34b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthException;
35b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
36b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/**
37b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Class to handle RSA-SHA1 signatures on OAuth requests. A consumer
38b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * that wishes to use public-key signatures on messages does not need
39b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * a shared secret with the service provider, but it needs a private
40b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * RSA signing key. You create it like this:
41b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
42b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key,
43b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *                                     null, provider);
44b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * c.setProperty(RSA_SHA1.PRIVATE_KEY, consumer_privateRSAKey);
45b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
46b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * consumer_privateRSAKey must be an RSA signing key and
47b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * of type java.security.PrivateKey, String, or byte[]. In the latter two
48b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * cases, the key must be PKCS#8-encoded (byte[]) or PKCS#8-encoded and
49b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * then Base64-encoded (String).
50b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
51b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * A service provider that wishes to verify signatures made by such a
52b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * consumer does not need a shared secret with the consumer, but it needs
53b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * to know the consumer's public key. You create the necessary
54b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * OAuthConsumer object (on the service provider's side) like this:
55b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
56b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key,
57b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *                                     null, provider);
58b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * c.setProperty(RSA_SHA1.PUBLIC_KEY, consumer_publicRSAKey);
59b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
60b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * consumer_publicRSAKey must be the consumer's public RSAkey and
61b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * of type java.security.PublicKey, String, or byte[]. In the latter two
62b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * cases, the key must be X509-encoded (byte[]) or X509-encoded and
63b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * then Base64-encoded (String).
64b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
65b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Alternatively, a service provider that wishes to verify signatures made
66b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * by such a consumer can use a X509 certificate containing the consumer's
67b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * public key. You create the necessary OAuthConsumer object (on the service
68b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * provider's side) like this:
69b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
70b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key,
71b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *                                     null, provider);
72b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * c.setProperty(RSA_SHA1.X509_CERTIFICATE, consumer_cert);
73b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
74b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * consumer_cert must be a X509 Certificate containing the consumer's public
75b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * key and be of type java.security.cert.X509Certificate, String,
76b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * or byte[]. In the latter two cases, the certificate must be DER-encoded
77b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * (byte[]) or PEM-encoded (String).
78b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
79b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @author Dirk Balfanz
80b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @hide
81b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
82b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */
83b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpublic class RSA_SHA1 extends OAuthSignatureMethod {
84b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
85b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    final static public String PRIVATE_KEY = "RSA-SHA1.PrivateKey";
86b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    final static public String PUBLIC_KEY = "RSA-SHA1.PublicKey";
87b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    final static public String X509_CERTIFICATE = "RSA-SHA1.X509Certificate";
88b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
89b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private PrivateKey privateKey = null;
90b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private PublicKey publicKey = null;
91b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
92b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    @Override
93b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    protected void initialize(String name, OAuthAccessor accessor)
94b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    throws OAuthException {
95b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        super.initialize(name, accessor);
96b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
97b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        Object privateKeyObject = accessor.consumer.getProperty(PRIVATE_KEY);
98b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        try {
99b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            if (privateKeyObject != null) {
100b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                if (privateKeyObject instanceof PrivateKey) {
101b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    privateKey = (PrivateKey)privateKeyObject;
102b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                } else if (privateKeyObject instanceof String) {
103b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    privateKey = getPrivateKeyFromPem((String)privateKeyObject);
104b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                } else if (privateKeyObject instanceof byte[]) {
105b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    privateKey = getPrivateKeyFromDer((byte[])privateKeyObject);
106b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                } else {
107b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    throw new IllegalArgumentException(
108b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                            "Private key set through RSA_SHA1.PRIVATE_KEY must be of " +
109b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                            "type PrivateKey, String, or byte[], and not " +
110b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                            privateKeyObject.getClass().getName());
111b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                }
112b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            }
113b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
114b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            Object publicKeyObject = accessor.consumer.getProperty(PUBLIC_KEY);
115b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            if (publicKeyObject != null) {
116b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                if (publicKeyObject instanceof PublicKey) {
117b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    publicKey = (PublicKey)publicKeyObject;
118b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                } else if (publicKeyObject instanceof String) {
119b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    publicKey = getPublicKeyFromPem((String)publicKeyObject);
120b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                } else if (publicKeyObject instanceof byte[]) {
121b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    publicKey = getPublicKeyFromDer((byte[])publicKeyObject);
122b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                } else {
123b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    throw new IllegalArgumentException(
124b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                            "Public key set through RSA_SHA1.PRIVATE_KEY must be of " +
125b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                            "type PublicKey, String, or byte[], and not " +
126b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                            publicKeyObject.getClass().getName());
127b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                }
128b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            } else {  // public key was null. perhaps they gave us a X509 cert.
129b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                Object certObject = accessor.consumer.getProperty(X509_CERTIFICATE);
130b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                if (certObject != null) {
131b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    if (certObject instanceof X509Certificate) {
132b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                        publicKey = ((X509Certificate) certObject).getPublicKey();
133b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    } else if (certObject instanceof String) {
134b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                        publicKey = getPublicKeyFromPemCert((String)certObject);
135b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    } else if (certObject instanceof byte[]) {
136b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                        publicKey = getPublicKeyFromDerCert((byte[])certObject);
137b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    } else {
138b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                        throw new IllegalArgumentException(
139b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                                "X509Certificate set through RSA_SHA1.X509_CERTIFICATE" +
140b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                                " must be of type X509Certificate, String, or byte[]," +
141b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                                " and not " + certObject.getClass().getName());
142b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                    }
143b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                }
144b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            }
145b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        } catch (GeneralSecurityException e) {
146b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throw new OAuthException(e);
147b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
148b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
149b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
150b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private PublicKey getPublicKeyFromPemCert(String certObject)
151b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throws GeneralSecurityException {
152b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        CertificateFactory fac = CertificateFactory.getInstance("X509");
153b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        ByteArrayInputStream in = new ByteArrayInputStream(certObject.getBytes());
154b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        X509Certificate cert = (X509Certificate)fac.generateCertificate(in);
155b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return cert.getPublicKey();
156b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
157b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
158b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private PublicKey getPublicKeyFromDerCert(byte[] certObject)
159b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throws GeneralSecurityException {
160b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        CertificateFactory fac = CertificateFactory.getInstance("X509");
161b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        ByteArrayInputStream in = new ByteArrayInputStream(certObject);
162b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        X509Certificate cert = (X509Certificate)fac.generateCertificate(in);
163b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return cert.getPublicKey();
164b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
165b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
166b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private PublicKey getPublicKeyFromDer(byte[] publicKeyObject)
167b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throws GeneralSecurityException {
168b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        KeyFactory fac = KeyFactory.getInstance("RSA");
169b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(publicKeyObject);
170b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return fac.generatePublic(pubKeySpec);
171b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
172b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
173b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private PublicKey getPublicKeyFromPem(String publicKeyObject)
174b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throws GeneralSecurityException {
175b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return getPublicKeyFromDer(decodeBase64(publicKeyObject));
176b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
177b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
178b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private PrivateKey getPrivateKeyFromDer(byte[] privateKeyObject)
179b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throws GeneralSecurityException {
180b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        KeyFactory fac = KeyFactory.getInstance("RSA");
181b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privateKeyObject);
182b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return fac.generatePrivate(privKeySpec);
183b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
184b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
185b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private PrivateKey getPrivateKeyFromPem(String privateKeyObject)
186b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throws GeneralSecurityException {
187b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return getPrivateKeyFromDer(decodeBase64(privateKeyObject));
188b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
189b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
190b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    @Override
191b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    protected String getSignature(String baseString) throws OAuthException {
192b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        try {
193b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            byte[] signature = sign(baseString.getBytes(OAuth.ENCODING));
194b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            return base64Encode(signature);
195b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        } catch (UnsupportedEncodingException e) {
196b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throw new OAuthException(e);
197b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        } catch (GeneralSecurityException e) {
198b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throw new OAuthException(e);
199b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
200b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
201b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
202b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    @Override
203b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    protected boolean isValid(String signature, String baseString)
204b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throws OAuthException {
205b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        try {
206b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            return verify(decodeBase64(signature),
207b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                          baseString.getBytes(OAuth.ENCODING));
208b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        } catch (UnsupportedEncodingException e) {
209b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throw new OAuthException(e);
210b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        } catch (GeneralSecurityException e) {
211b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throw new OAuthException(e);
212b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
213b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
214b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
215b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private byte[] sign(byte[] message) throws GeneralSecurityException {
216b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        if (privateKey == null) {
217b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throw new IllegalStateException("need to set private key with " +
218b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                                            "OAuthConsumer.setProperty when " +
219b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                                            "generating RSA-SHA1 signatures.");
220b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
221b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        Signature signer = Signature.getInstance("SHA1withRSA");
222b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        signer.initSign(privateKey);
223b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        signer.update(message);
224b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return signer.sign();
225b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
226b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
227b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private boolean verify(byte[] signature, byte[] message)
228b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throws GeneralSecurityException {
229b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        if (publicKey == null) {
230b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            throw new IllegalStateException("need to set public key with " +
231b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                                            " OAuthConsumer.setProperty when " +
232b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                                            "verifying RSA-SHA1 signatures.");
233b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
234b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        Signature verifier = Signature.getInstance("SHA1withRSA");
235b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        verifier.initVerify(publicKey);
236b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        verifier.update(message);
237b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return verifier.verify(signature);
238b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
239b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien}
240