• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
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 
17 package org.conscrypt;
18 
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.math.BigInteger;
23 import java.security.InvalidKeyException;
24 import java.security.interfaces.RSAPublicKey;
25 import java.security.spec.InvalidKeySpecException;
26 import java.security.spec.RSAPublicKeySpec;
27 
28 /**
29  * An implementation of {@link java.security.PublicKey} for RSA keys which uses BoringSSL to
30  * perform all the operations.
31  */
32 @Internal
33 public class OpenSSLRSAPublicKey implements RSAPublicKey, OpenSSLKeyHolder {
34     private static final long serialVersionUID = 123125005824688292L;
35 
36     private transient OpenSSLKey key;
37 
38     private BigInteger publicExponent;
39 
40     private BigInteger modulus;
41 
42     private transient boolean fetchedParams;
43 
OpenSSLRSAPublicKey(OpenSSLKey key)44     OpenSSLRSAPublicKey(OpenSSLKey key) {
45         this.key = key;
46     }
47 
48     @Override
getOpenSSLKey()49     public OpenSSLKey getOpenSSLKey() {
50         return key;
51     }
52 
OpenSSLRSAPublicKey(RSAPublicKeySpec spec)53     OpenSSLRSAPublicKey(RSAPublicKeySpec spec) throws InvalidKeySpecException {
54         try {
55             key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
56                     spec.getModulus().toByteArray(),
57                     spec.getPublicExponent().toByteArray(),
58                     null,
59                     null,
60                     null,
61                     null,
62                     null,
63                     null));
64         } catch (Exception e) {
65             throw new InvalidKeySpecException(e);
66         }
67     }
68 
getInstance(RSAPublicKey rsaPublicKey)69     static OpenSSLKey getInstance(RSAPublicKey rsaPublicKey) throws InvalidKeyException {
70         try {
71             return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
72                     rsaPublicKey.getModulus().toByteArray(),
73                     rsaPublicKey.getPublicExponent().toByteArray(),
74                     null,
75                     null,
76                     null,
77                     null,
78                     null,
79                     null));
80         } catch (Exception e) {
81             throw new InvalidKeyException(e);
82         }
83     }
84 
85     @Override
getAlgorithm()86     public String getAlgorithm() {
87         return "RSA";
88     }
89 
90     @Override
getFormat()91     public String getFormat() {
92         return "X.509";
93     }
94 
95     @Override
getEncoded()96     public byte[] getEncoded() {
97         return NativeCrypto.EVP_marshal_public_key(key.getNativeRef());
98     }
99 
ensureReadParams()100     private synchronized void ensureReadParams() {
101         if (fetchedParams) {
102             return;
103         }
104 
105         byte[][] params = NativeCrypto.get_RSA_public_params(key.getNativeRef());
106         modulus = new BigInteger(params[0]);
107         publicExponent = new BigInteger(params[1]);
108 
109         fetchedParams = true;
110     }
111 
112     @Override
getModulus()113     public BigInteger getModulus() {
114         ensureReadParams();
115         return modulus;
116     }
117 
118     @Override
getPublicExponent()119     public BigInteger getPublicExponent() {
120         ensureReadParams();
121         return publicExponent;
122     }
123 
124     @Override
equals(Object o)125     public boolean equals(Object o) {
126         if (o == this) {
127             return true;
128         }
129 
130         if (o instanceof OpenSSLRSAPublicKey) {
131             OpenSSLRSAPublicKey other = (OpenSSLRSAPublicKey) o;
132 
133             /*
134              * We can shortcut the true case, but it still may be equivalent but
135              * different copies.
136              */
137             if (key.equals(other.getOpenSSLKey())) {
138                 return true;
139             }
140         }
141 
142         if (!(o instanceof RSAPublicKey)) {
143             return false;
144         }
145 
146         ensureReadParams();
147 
148         RSAPublicKey other = (RSAPublicKey) o;
149         return modulus.equals(other.getModulus())
150                 && publicExponent.equals(other.getPublicExponent());
151     }
152 
153     @Override
hashCode()154     public int hashCode() {
155         ensureReadParams();
156 
157         return modulus.hashCode() ^ publicExponent.hashCode();
158     }
159 
160     @Override
toString()161     public String toString() {
162         ensureReadParams();
163 
164         final StringBuilder sb = new StringBuilder("OpenSSLRSAPublicKey{");
165         sb.append("modulus=");
166         sb.append(modulus.toString(16));
167         sb.append(',');
168         sb.append("publicExponent=");
169         sb.append(publicExponent.toString(16));
170         sb.append('}');
171 
172         return sb.toString();
173     }
174 
readObject(ObjectInputStream stream)175     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
176         stream.defaultReadObject();
177 
178         key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
179                 modulus.toByteArray(),
180                 publicExponent.toByteArray(),
181                 null,
182                 null,
183                 null,
184                 null,
185                 null,
186                 null));
187         fetchedParams = true;
188     }
189 
writeObject(ObjectOutputStream stream)190     private void writeObject(ObjectOutputStream stream) throws IOException {
191         ensureReadParams();
192         stream.defaultWriteObject();
193     }
194 }
195