44 * implementation allows the hashes to be explicitly set, which is required |
43 * implementation allows the hashes to be explicitly set, which is required |
45 * for RSA client authentication. It can be obtained via the |
44 * for RSA client authentication. It can be obtained via the |
46 * getInternalInstance() method. |
45 * getInternalInstance() method. |
47 * |
46 * |
48 * This class is not thread safe. |
47 * This class is not thread safe. |
49 * |
|
50 */ |
48 */ |
51 public final class RSASignature extends SignatureSpi { |
49 public final class RSASignature extends SignatureSpi { |
52 |
|
53 private final Signature rawRsa; |
50 private final Signature rawRsa; |
54 private MessageDigest md5, sha; |
51 private final MessageDigest mdMD5; |
55 |
52 private final MessageDigest mdSHA; |
56 // flag indicating if the MessageDigests are in reset state |
|
57 private boolean isReset; |
|
58 |
53 |
59 public RSASignature() throws NoSuchAlgorithmException { |
54 public RSASignature() throws NoSuchAlgorithmException { |
60 super(); |
55 super(); |
61 rawRsa = JsseJce.getSignature(JsseJce.SIGNATURE_RAWRSA); |
56 rawRsa = JsseJce.getSignature(JsseJce.SIGNATURE_RAWRSA); |
62 isReset = true; |
57 this.mdMD5 = JsseJce.getMessageDigest("MD5"); |
|
58 this.mdSHA = JsseJce.getMessageDigest("SHA"); |
63 } |
59 } |
64 |
60 |
65 /** |
61 /** |
66 * Get an implementation for the RSA signature. Follows the standard |
62 * Get an implementation for the RSA signature. |
67 * JCA getInstance() model, so it return the implementation from the |
63 * |
68 * provider with the highest precedence, which may be this class. |
64 * Follows the standard JCA getInstance() model, so it return the |
|
65 * implementation from the provider with the highest precedence, |
|
66 * which may be this class. |
69 */ |
67 */ |
70 static Signature getInstance() throws NoSuchAlgorithmException { |
68 static Signature getInstance() throws NoSuchAlgorithmException { |
71 return JsseJce.getSignature(JsseJce.SIGNATURE_SSLRSA); |
69 return JsseJce.getSignature(JsseJce.SIGNATURE_SSLRSA); |
72 } |
70 } |
73 |
71 |
74 /** |
|
75 * Get an internal implementation for the RSA signature. Used for RSA |
|
76 * client authentication, which needs the ability to set the digests |
|
77 * to externally provided values via the setHashes() method. |
|
78 */ |
|
79 static Signature getInternalInstance() |
|
80 throws NoSuchAlgorithmException, NoSuchProviderException { |
|
81 return Signature.getInstance(JsseJce.SIGNATURE_SSLRSA, "SunJSSE"); |
|
82 } |
|
83 |
|
84 /** |
|
85 * Set the MD5 and SHA hashes to the provided objects. |
|
86 */ |
|
87 @SuppressWarnings("deprecation") |
|
88 static void setHashes(Signature sig, MessageDigest md5, MessageDigest sha) { |
|
89 sig.setParameter("hashes", new MessageDigest[] {md5, sha}); |
|
90 } |
|
91 |
|
92 /** |
|
93 * Reset the MessageDigests unless they are already reset. |
|
94 */ |
|
95 private void reset() { |
|
96 if (isReset == false) { |
|
97 md5.reset(); |
|
98 sha.reset(); |
|
99 isReset = true; |
|
100 } |
|
101 } |
|
102 |
|
103 private static void checkNull(Key key) throws InvalidKeyException { |
|
104 if (key == null) { |
|
105 throw new InvalidKeyException("Key must not be null"); |
|
106 } |
|
107 } |
|
108 |
|
109 @Override |
72 @Override |
110 protected void engineInitVerify(PublicKey publicKey) |
73 protected void engineInitVerify(PublicKey publicKey) |
111 throws InvalidKeyException { |
74 throws InvalidKeyException { |
112 checkNull(publicKey); |
75 if (publicKey == null) { |
113 reset(); |
76 throw new InvalidKeyException("Public key must not be null"); |
|
77 } |
|
78 mdMD5.reset(); |
|
79 mdSHA.reset(); |
114 rawRsa.initVerify(publicKey); |
80 rawRsa.initVerify(publicKey); |
115 } |
81 } |
116 |
82 |
117 @Override |
83 @Override |
118 protected void engineInitSign(PrivateKey privateKey) |
84 protected void engineInitSign(PrivateKey privateKey) |
121 } |
87 } |
122 |
88 |
123 @Override |
89 @Override |
124 protected void engineInitSign(PrivateKey privateKey, SecureRandom random) |
90 protected void engineInitSign(PrivateKey privateKey, SecureRandom random) |
125 throws InvalidKeyException { |
91 throws InvalidKeyException { |
126 checkNull(privateKey); |
92 if (privateKey == null) { |
127 reset(); |
93 throw new InvalidKeyException("Private key must not be null"); |
|
94 } |
|
95 mdMD5.reset(); |
|
96 mdSHA.reset(); |
128 rawRsa.initSign(privateKey, random); |
97 rawRsa.initSign(privateKey, random); |
129 } |
|
130 |
|
131 // lazily initialize the MessageDigests |
|
132 private void initDigests() { |
|
133 if (md5 == null) { |
|
134 md5 = JsseJce.getMD5(); |
|
135 sha = JsseJce.getSHA(); |
|
136 } |
|
137 } |
98 } |
138 |
99 |
139 @Override |
100 @Override |
140 protected void engineUpdate(byte b) { |
101 protected void engineUpdate(byte b) { |
141 initDigests(); |
102 mdMD5.update(b); |
142 isReset = false; |
103 mdSHA.update(b); |
143 md5.update(b); |
|
144 sha.update(b); |
|
145 } |
104 } |
146 |
105 |
147 @Override |
106 @Override |
148 protected void engineUpdate(byte[] b, int off, int len) { |
107 protected void engineUpdate(byte[] b, int off, int len) { |
149 initDigests(); |
108 mdMD5.update(b, off, len); |
150 isReset = false; |
109 mdSHA.update(b, off, len); |
151 md5.update(b, off, len); |
|
152 sha.update(b, off, len); |
|
153 } |
110 } |
154 |
111 |
155 private byte[] getDigest() throws SignatureException { |
112 private byte[] getDigest() throws SignatureException { |
156 try { |
113 try { |
157 initDigests(); |
|
158 byte[] data = new byte[36]; |
114 byte[] data = new byte[36]; |
159 md5.digest(data, 0, 16); |
115 mdMD5.digest(data, 0, 16); |
160 sha.digest(data, 16, 20); |
116 mdSHA.digest(data, 16, 20); |
161 isReset = true; |
|
162 return data; |
117 return data; |
163 } catch (DigestException e) { |
118 } catch (DigestException e) { |
164 // should never occur |
119 // should never occur |
165 throw new SignatureException(e); |
120 throw new SignatureException(e); |
166 } |
121 } |
184 return rawRsa.verify(sigBytes, offset, length); |
139 return rawRsa.verify(sigBytes, offset, length); |
185 } |
140 } |
186 |
141 |
187 @Override |
142 @Override |
188 @SuppressWarnings("deprecation") |
143 @SuppressWarnings("deprecation") |
189 protected void engineSetParameter(String param, Object value) |
144 protected void engineSetParameter(String param, |
190 throws InvalidParameterException { |
145 Object value) throws InvalidParameterException { |
191 if (param.equals("hashes") == false) { |
146 throw new InvalidParameterException("Parameters not supported"); |
192 throw new InvalidParameterException |
|
193 ("Parameter not supported: " + param); |
|
194 } |
|
195 if (value instanceof MessageDigest[] == false) { |
|
196 throw new InvalidParameterException |
|
197 ("value must be MessageDigest[]"); |
|
198 } |
|
199 MessageDigest[] digests = (MessageDigest[])value; |
|
200 md5 = digests[0]; |
|
201 sha = digests[1]; |
|
202 } |
147 } |
203 |
148 |
204 @Override |
149 @Override |
205 protected void engineSetParameter(AlgorithmParameterSpec params) |
150 protected void engineSetParameter(AlgorithmParameterSpec params) |
206 throws InvalidAlgorithmParameterException { |
151 throws InvalidAlgorithmParameterException { |