Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 319 lines (210 sloc) 8.427 kB
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
1 package Crypt::OpenSSL::RSA;
2
3 use strict;
4 use Carp;
5
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
6 use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD);
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
7
8 require DynaLoader;
3025d19 @toddr RT 65947 - Fix RSA.pm with perl 5.14+
toddr authored
9 use AutoLoader 'AUTOLOAD';
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
10
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
11 @ISA = qw(DynaLoader);
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
12
52f2d77 @monken RT 56454 - Win32 compatibility patch (kmx@cpan.org)
authored
13 $VERSION = '0.28';
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
14
15 bootstrap Crypt::OpenSSL::RSA $VERSION;
16
2347338 import Crypt-OpenSSL-RSA 0.18 from CPAN
Ian Robertson authored
17 BEGIN { eval { require Crypt::OpenSSL::Bignum; }; }
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
18
19 1;
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
20
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
21 __END__
22
23 =head1 NAME
24
25 Crypt::OpenSSL::RSA - RSA encoding and decoding, using the openSSL libraries
26
27 =head1 SYNOPSIS
28
be9fcb1 import Crypt-OpenSSL-RSA 0.12 from CPAN
Ian Robertson authored
29 use Crypt::OpenSSL::Random;
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
30 use Crypt::OpenSSL::RSA;
31
be9fcb1 import Crypt-OpenSSL-RSA 0.12 from CPAN
Ian Robertson authored
32 # not necessary if we have /dev/random:
33 Crypt::OpenSSL::Random::random_seed($good_entropy);
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
34 Crypt::OpenSSL::RSA->import_random_seed();
35 $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($key_string);
36 $rsa_pub->use_sslv23_padding(); # use_pkcs1_oaep_padding is the default
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
37 $ciphertext = $rsa->encrypt($plaintext);
38
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
39 $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($key_string);
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
40 $plaintext = $rsa->encrypt($ciphertext);
41
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
42 $rsa = Crypt::OpenSSL::RSA->generate_key(1024); # or
43 $rsa = Crypt::OpenSSL::RSA->generate_key(1024, $prime);
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
44
45 print "private key is:\n", $rsa->get_private_key_string();
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
46 print "public key (in PKCS1 format) is:\n",
47 $rsa->get_public_key_string();
48 print "public key (in X509 format) is:\n",
49 $rsa->get_public_key_x509_string();
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
50
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
51 $rsa_priv->use_md5_hash(); # use_sha1_hash is the default
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
52 $signature = $rsa_priv->sign($plaintext);
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
53 print "Signed correctly\n" if ($rsa->verify($plaintext, $signature));
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
54
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
55 =head1 DESCRIPTION
56
57 Crypt::OpenSSL::RSA provides the ability to RSA encrypt strings which are
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
58 somewhat shorter than the block size of a key. It also allows for decryption,
59 signatures and signature verification.
60
61 I<NOTE>: Many of the methods in this package can croak, so use eval, or
62 Error.pm's try/catch mechanism to capture errors. Also, while some
63 methods from earlier versions of this package return true on success,
64 this (never documented) behavior is no longer the case.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
65
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
66 =head1 Class Methods
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
67
68 =over
69
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
70 =item new_public_key
71
72 Create a new Crypt::OpenSSL::RSA object by loading a public key in
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
73 from a string containing Base64/DER-encoding of either the PKCS1 or
74 X.509 representation of the key. The string should include the
75 -----BEGIN...----- and -----END...----- lines.
76
77 The padding is set to PKCS1_OAEP, but can be changed with the
78 use_xxx_padding methods
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
79
80 =cut
81
82 sub new_public_key
83 {
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
84 my ($proto, $p_key_string) = @_;
85 if ($p_key_string =~ /^-----BEGIN RSA PUBLIC KEY-----/)
86 {
87 return $proto->_new_public_key_pkcs1($p_key_string);
88 }
89 elsif ($p_key_string =~ /^-----BEGIN PUBLIC KEY-----/)
90 {
91 return $proto->_new_public_key_x509($p_key_string);
92 }
93 else
94 {
95 croak "unrecognized key format";
96 }
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
97 }
98
99 =item new_private_key
100
101 Create a new Crypt::OpenSSL::RSA object by loading a private key in
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
102 from an string containing the Base64/DER encoding of the PKCS1
103 representation of the key. The string should include the
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
104 -----BEGIN...----- and -----END...----- lines. The padding is set to
105 PKCS1_OAEP, but can be changed with use_xxx_padding.
106
107 =item generate_key
108
109 Create a new Crypt::OpenSSL::RSA object by constructing a
110 private/public key pair. The first (mandetory) argument is the key
111 size, while the second optional argument specifies the public exponent
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
112 (the default public exponent is 65537). The padding is set to
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
113 PKCS1_OAEP, but can be changed with use_xxx_padding methods.
114
2347338 import Crypt-OpenSSL-RSA 0.18 from CPAN
Ian Robertson authored
115 =item new_key_from_parameters
116
117 Given Crypt::OpenSSL::Bignum objects for n, e, and optionally d, p,
118 and q, where p and q are the prime factors of n, e is the public
119 exponent and d is the private exponent, create a new
120 Crypt::OpenSSL::RSA object using these values. If p and q are
121 provided and d is undef, d is computed. Note that while p and q are
122 not necessary for a private key, their presence will speed up
123 computation.
124
125 =cut
126
127 sub new_key_from_parameters
128 {
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
129 my($proto, $n, $e, $d, $p, $q) = @_;
2347338 import Crypt-OpenSSL-RSA 0.18 from CPAN
Ian Robertson authored
130 return $proto->_new_key_from_parameters
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
131 (map { $_ ? $_->pointer_copy() : 0 } $n, $e, $d, $p, $q);
2347338 import Crypt-OpenSSL-RSA 0.18 from CPAN
Ian Robertson authored
132 }
133
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
134 =item import_random_seed
135
136 Import a random seed from Crypt::OpenSSL::Random, since the OpenSSL
137 libraries won't allow sharing of random structures across perl XS
138 modules.
139
140 =cut
141
142 sub import_random_seed
143 {
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
144 until (_random_status())
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
145 {
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
146 _random_seed(Crypt::OpenSSL::Random::random_bytes(20));
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
147 }
148 }
149
150 =back
151
152 =head1 Instance Methods
153
154 =over
155
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
156 =item DESTROY
157
158 Clean up after ourselves. In particular, erase and free the memory
159 occupied by the RSA key structure.
160
161 =item get_public_key_string
162
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
163 Return the Base64/DER-encoded PKCS1 representation of the public
164 key. This string has
165 header and footer lines:
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
166
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
167 -----BEGIN RSA PUBLIC KEY------
168 -----END RSA PUBLIC KEY------
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
169
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
170 =item get_public_key_x509_string
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
171
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
172 Return the Base64/DER-encoded representation of the "subject
173 public key", suitable for use in X509 certificates. This string has
174 header and footer lines:
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
175
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
176 -----BEGIN PUBLIC KEY------
177 -----END PUBLIC KEY------
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
178
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
179 and is the format that is produced by running C<openssl rsa -pubout>.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
180
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
181 =item get_private_key_string
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
182
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
183 Return the DER-encoded PKCS1 representation of the private key.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
184
185 =item encrypt
186
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
187 Encrypt a binary "string" using the public (portion of the) key.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
188
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
189 =item decrypt
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
190
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
191 Decrypt a binary "string". Croaks if the key is public only.
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
192
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
193 =item private_encrypt
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
194
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
195 Encrypt a binary "string" using the private key. Croaks if the key is
196 public only.
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
197
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
198 =item public_decrypt
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
199
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
200 Decrypt a binary "string" using the public (portion of the) key.
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
201
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
202 =item sign
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
203
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
204 Sign a string using the secret (portion of the) key.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
205
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
206 =item verify
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
207
e782515 import Crypt-OpenSSL-RSA 0.22 from CPAN
Ian Robertson authored
208 Check the signature on a text.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
209
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
210 =item use_no_padding
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
211
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
212 Use raw RSA encryption. This mode should only be used to implement
213 cryptographically sound padding modes in the application code.
214 Encrypting user data directly with RSA is insecure.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
215
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
216 =item use_pkcs1_padding
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
217
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
218 Use PKCS #1 v1.5 padding. This currently is the most widely used mode
219 of padding.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
220
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
221 =item use_pkcs1_oaep_padding
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
222
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
223 Use EME-OAEP padding as defined in PKCS #1 v2.0 with SHA-1, MGF1 and
224 an empty encoding parameter. This mode of padding is recommended for
225 all new applications. It is the default mode used by
226 Crypt::OpenSSL::RSA.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
227
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
228 =item use_sslv23_padding
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
229
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
230 Use PKCS #1 v1.5 padding with an SSL-specific modification that
231 denotes that the server is SSL3 capable.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
232
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
233 =item use_md5_hash
234
235 Use the RFC 1321 MD5 hashing algorithm by Ron Rivest when signing and
236 verifying messages.
237
238 =item use_sha1_hash
239
240 Use the RFC 3174 Secure Hashing Algorithm (FIPS 180-1) when signing
241 and verifying messages. This is the default.
242
26711e2 import Crypt-OpenSSL-RSA 0.23 from CPAN
Ian Robertson authored
243 =item use_sha224_hash, use_sha256_hash, use_sha384_hash, use_sha512_hash
244
245 These FIPS 180-2 hash algorithms, for use when signing and verifying
246 messages, are only available with newer openssl versions (>= 0.9.8).
247
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
248 =item use_ripemd160_hash
249
250 Dobbertin, Bosselaers and Preneel's RIPEMD hashing algorithm when
251 signing and verifying messages.
252
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
253 =item size
254
255 Returns the size, in bytes, of the key. All encrypted text will be of
256 this size, and depending on the padding mode used, the length of
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
257 the text to be encrypted should be:
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
258
259 =over
260
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
261 =item pkcs1_oaep_padding
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
262
263 at most 42 bytes less than this size.
264
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
265 =item pkcs1_padding or sslv23_padding
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
266
267 at most 11 bytes less than this size.
268
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
269 =item no_padding
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
270
271 exactly this size.
272
273 =back
274
275 =item check_key
276
4886e57 import Crypt-OpenSSL-RSA 0.17 from CPAN
Ian Robertson authored
277 This function validates the RSA key, returning a true value if the key
8c6c93b import Crypt-OpenSSL-RSA 0.24 from CPAN
Ian Robertson authored
278 is valid, and a false value otherwise. Croaks if the key is public only.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
279
2347338 import Crypt-OpenSSL-RSA 0.18 from CPAN
Ian Robertson authored
280 =item get_key_parameters
281
282 Return Crypt::OpenSSL::Bignum objects representing the values of n, e,
283 d, p, q, d mod (p-1), d mod (q-1), and 1/q mod p, where p and q are
284 the prime factors of n, e is the public exponent and d is the private
285 exponent. Some of these values may return as undef; only n and e will
286 be defined for a public key. The Crypt::OpenSSL::Bignum module must
287 be installed for this to work.
288
8c6c93b import Crypt-OpenSSL-RSA 0.24 from CPAN
Ian Robertson authored
289 =item is_private
290
291 Return true if this is a private key, and false if it is private only.
292
2347338 import Crypt-OpenSSL-RSA 0.18 from CPAN
Ian Robertson authored
293 =cut
294
295 sub get_key_parameters
296 {
297 return map { $_ ? Crypt::OpenSSL::Bignum->bless_pointer($_) : undef }
298 shift->_get_key_parameters();
299 }
300
be9fcb1 import Crypt-OpenSSL-RSA 0.12 from CPAN
Ian Robertson authored
301 =back
302
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
303 =head1 BUGS
304
bd83428 import Crypt-OpenSSL-RSA 0.13 from CPAN
Ian Robertson authored
305 There is a small memory leak when generating new keys of more than 512 bits.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
306
a2d65d5 import Crypt-OpenSSL-RSA 0.10 from CPAN
Ian Robertson authored
307 =head1 AUTHOR
308
aff6ce9 import Crypt-OpenSSL-RSA 0.20 from CPAN
Ian Robertson authored
309 Ian Robertson, iroberts@cpan.org. For support, please email
310 perl-openssl-users@lists.sourceforge.net.
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
311
a2d65d5 import Crypt-OpenSSL-RSA 0.10 from CPAN
Ian Robertson authored
312 =head1 SEE ALSO
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
313
2347338 import Crypt-OpenSSL-RSA 0.18 from CPAN
Ian Robertson authored
314 L<perl(1)>, L<Crypt::OpenSSL::Random(3)>, L<Crypt::OpenSSL::Bignum(3)>,
315 L<rsa(3)>, L<RSA_new(3)>, L<RSA_public_encrypt(3)>, L<RSA_size(3)>,
316 L<RSA_generate_key(3)>, L<RSA_check_key(3)>
be9fcb1 import Crypt-OpenSSL-RSA 0.12 from CPAN
Ian Robertson authored
317
a6040a7 initial import of Crypt-OpenSSL-RSA 0.08 from CPAN
Ian Robertson authored
318 =cut
Something went wrong with that request. Please try again.