xref: /aosp_15_r20/external/boringssl/src/crypto/rsa_extra/rsa_crypt.c (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1 /* Copyright (C) 1995-1998 Eric Young ([email protected])
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young ([email protected]).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson ([email protected]).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young ([email protected])"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson ([email protected])"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.] */
56 
57 #include <openssl/base.h>
58 
59 #include <limits.h>
60 
61 #include <openssl/err.h>
62 #include <openssl/rsa.h>
63 #include <openssl/bn.h>
64 #include <openssl/rand.h>
65 #include <openssl/mem.h>
66 #include <openssl/evp.h>
67 
68 #include "../fipsmodule/bn/internal.h"
69 #include "../fipsmodule/rsa/internal.h"
70 #include "../internal.h"
71 #include "internal.h"
72 
73 
rand_nonzero(uint8_t * out,size_t len)74 static void rand_nonzero(uint8_t *out, size_t len) {
75   RAND_bytes(out, len);
76 
77   for (size_t i = 0; i < len; i++) {
78     // Zero values are replaced, and the distribution of zero and non-zero bytes
79     // is public, so leaking this is safe.
80     while (constant_time_declassify_int(out[i] == 0)) {
81       RAND_bytes(out + i, 1);
82     }
83   }
84 }
85 
RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t * to,size_t to_len,const uint8_t * from,size_t from_len,const uint8_t * param,size_t param_len,const EVP_MD * md,const EVP_MD * mgf1md)86 int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, size_t to_len,
87                                     const uint8_t *from, size_t from_len,
88                                     const uint8_t *param, size_t param_len,
89                                     const EVP_MD *md, const EVP_MD *mgf1md) {
90   if (md == NULL) {
91     md = EVP_sha1();
92   }
93   if (mgf1md == NULL) {
94     mgf1md = md;
95   }
96 
97   size_t mdlen = EVP_MD_size(md);
98 
99   if (to_len < 2 * mdlen + 2) {
100     OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
101     return 0;
102   }
103 
104   size_t emlen = to_len - 1;
105   if (from_len > emlen - 2 * mdlen - 1) {
106     OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
107     return 0;
108   }
109 
110   if (emlen < 2 * mdlen + 1) {
111     OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
112     return 0;
113   }
114 
115   to[0] = 0;
116   uint8_t *seed = to + 1;
117   uint8_t *db = to + mdlen + 1;
118 
119   uint8_t *dbmask = NULL;
120   int ret = 0;
121   if (!EVP_Digest(param, param_len, db, NULL, md, NULL)) {
122     goto out;
123   }
124   OPENSSL_memset(db + mdlen, 0, emlen - from_len - 2 * mdlen - 1);
125   db[emlen - from_len - mdlen - 1] = 0x01;
126   OPENSSL_memcpy(db + emlen - from_len - mdlen, from, from_len);
127   if (!RAND_bytes(seed, mdlen)) {
128     goto out;
129   }
130 
131   dbmask = OPENSSL_malloc(emlen - mdlen);
132   if (dbmask == NULL) {
133     goto out;
134   }
135 
136   if (!PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md)) {
137     goto out;
138   }
139   for (size_t i = 0; i < emlen - mdlen; i++) {
140     db[i] ^= dbmask[i];
141   }
142 
143   uint8_t seedmask[EVP_MAX_MD_SIZE];
144   if (!PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md)) {
145     goto out;
146   }
147   for (size_t i = 0; i < mdlen; i++) {
148     seed[i] ^= seedmask[i];
149   }
150   ret = 1;
151 
152 out:
153   OPENSSL_free(dbmask);
154   return ret;
155 }
156 
RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t * out,size_t * out_len,size_t max_out,const uint8_t * from,size_t from_len,const uint8_t * param,size_t param_len,const EVP_MD * md,const EVP_MD * mgf1md)157 int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *out, size_t *out_len,
158                                       size_t max_out, const uint8_t *from,
159                                       size_t from_len, const uint8_t *param,
160                                       size_t param_len, const EVP_MD *md,
161                                       const EVP_MD *mgf1md) {
162   uint8_t *db = NULL;
163 
164   if (md == NULL) {
165     md = EVP_sha1();
166   }
167   if (mgf1md == NULL) {
168     mgf1md = md;
169   }
170 
171   size_t mdlen = EVP_MD_size(md);
172 
173   // The encoded message is one byte smaller than the modulus to ensure that it
174   // doesn't end up greater than the modulus. Thus there's an extra "+1" here
175   // compared to https://tools.ietf.org/html/rfc2437#section-9.1.1.2.
176   if (from_len < 1 + 2 * mdlen + 1) {
177     // 'from_len' is the length of the modulus, i.e. does not depend on the
178     // particular ciphertext.
179     goto decoding_err;
180   }
181 
182   size_t dblen = from_len - mdlen - 1;
183   db = OPENSSL_malloc(dblen);
184   if (db == NULL) {
185     goto err;
186   }
187 
188   const uint8_t *maskedseed = from + 1;
189   const uint8_t *maskeddb = from + 1 + mdlen;
190 
191   uint8_t seed[EVP_MAX_MD_SIZE];
192   if (!PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md)) {
193     goto err;
194   }
195   for (size_t i = 0; i < mdlen; i++) {
196     seed[i] ^= maskedseed[i];
197   }
198 
199   if (!PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md)) {
200     goto err;
201   }
202   for (size_t i = 0; i < dblen; i++) {
203     db[i] ^= maskeddb[i];
204   }
205 
206   uint8_t phash[EVP_MAX_MD_SIZE];
207   if (!EVP_Digest(param, param_len, phash, NULL, md, NULL)) {
208     goto err;
209   }
210 
211   crypto_word_t bad = ~constant_time_is_zero_w(CRYPTO_memcmp(db, phash, mdlen));
212   bad |= ~constant_time_is_zero_w(from[0]);
213 
214   crypto_word_t looking_for_one_byte = CONSTTIME_TRUE_W;
215   size_t one_index = 0;
216   for (size_t i = mdlen; i < dblen; i++) {
217     crypto_word_t equals1 = constant_time_eq_w(db[i], 1);
218     crypto_word_t equals0 = constant_time_eq_w(db[i], 0);
219     one_index =
220         constant_time_select_w(looking_for_one_byte & equals1, i, one_index);
221     looking_for_one_byte =
222         constant_time_select_w(equals1, 0, looking_for_one_byte);
223     bad |= looking_for_one_byte & ~equals0;
224   }
225 
226   bad |= looking_for_one_byte;
227 
228   // Whether the overall padding was valid or not in OAEP is public.
229   if (constant_time_declassify_w(bad)) {
230     goto decoding_err;
231   }
232 
233   // Once the padding is known to be valid, the output length is also public.
234   static_assert(sizeof(size_t) <= sizeof(crypto_word_t),
235                 "size_t does not fit in crypto_word_t");
236   one_index = constant_time_declassify_w(one_index);
237 
238   one_index++;
239   size_t mlen = dblen - one_index;
240   if (max_out < mlen) {
241     OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
242     goto err;
243   }
244 
245   OPENSSL_memcpy(out, db + one_index, mlen);
246   *out_len = mlen;
247   OPENSSL_free(db);
248   return 1;
249 
250 decoding_err:
251   // To avoid chosen ciphertext attacks, the error message should not reveal
252   // which kind of decoding error happened.
253   OPENSSL_PUT_ERROR(RSA, RSA_R_OAEP_DECODING_ERROR);
254 err:
255   OPENSSL_free(db);
256   return 0;
257 }
258 
rsa_padding_add_PKCS1_type_2(uint8_t * to,size_t to_len,const uint8_t * from,size_t from_len)259 static int rsa_padding_add_PKCS1_type_2(uint8_t *to, size_t to_len,
260                                         const uint8_t *from, size_t from_len) {
261   // See RFC 8017, section 7.2.1.
262   if (to_len < RSA_PKCS1_PADDING_SIZE) {
263     OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
264     return 0;
265   }
266 
267   if (from_len > to_len - RSA_PKCS1_PADDING_SIZE) {
268     OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
269     return 0;
270   }
271 
272   to[0] = 0;
273   to[1] = 2;
274 
275   size_t padding_len = to_len - 3 - from_len;
276   rand_nonzero(to + 2, padding_len);
277   to[2 + padding_len] = 0;
278   OPENSSL_memcpy(to + to_len - from_len, from, from_len);
279   return 1;
280 }
281 
rsa_padding_check_PKCS1_type_2(uint8_t * out,size_t * out_len,size_t max_out,const uint8_t * from,size_t from_len)282 static int rsa_padding_check_PKCS1_type_2(uint8_t *out, size_t *out_len,
283                                           size_t max_out, const uint8_t *from,
284                                           size_t from_len) {
285   if (from_len == 0) {
286     OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY);
287     return 0;
288   }
289 
290   // PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography
291   // Standard", section 7.2.2.
292   if (from_len < RSA_PKCS1_PADDING_SIZE) {
293     // |from| is zero-padded to the size of the RSA modulus, a public value, so
294     // this can be rejected in non-constant time.
295     OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
296     return 0;
297   }
298 
299   crypto_word_t first_byte_is_zero = constant_time_eq_w(from[0], 0);
300   crypto_word_t second_byte_is_two = constant_time_eq_w(from[1], 2);
301 
302   crypto_word_t zero_index = 0, looking_for_index = CONSTTIME_TRUE_W;
303   for (size_t i = 2; i < from_len; i++) {
304     crypto_word_t equals0 = constant_time_is_zero_w(from[i]);
305     zero_index =
306         constant_time_select_w(looking_for_index & equals0, i, zero_index);
307     looking_for_index = constant_time_select_w(equals0, 0, looking_for_index);
308   }
309 
310   // The input must begin with 00 02.
311   crypto_word_t valid_index = first_byte_is_zero;
312   valid_index &= second_byte_is_two;
313 
314   // We must have found the end of PS.
315   valid_index &= ~looking_for_index;
316 
317   // PS must be at least 8 bytes long, and it starts two bytes into |from|.
318   valid_index &= constant_time_ge_w(zero_index, 2 + 8);
319 
320   // Skip the zero byte.
321   zero_index++;
322 
323   // NOTE: Although this logic attempts to be constant time, the API contracts
324   // of this function and |RSA_decrypt| with |RSA_PKCS1_PADDING| make it
325   // impossible to completely avoid Bleichenbacher's attack. Consumers should
326   // use |RSA_PADDING_NONE| and perform the padding check in constant-time
327   // combined with a swap to a random session key or other mitigation.
328   CONSTTIME_DECLASSIFY(&valid_index, sizeof(valid_index));
329   CONSTTIME_DECLASSIFY(&zero_index, sizeof(zero_index));
330 
331   if (!valid_index) {
332     OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR);
333     return 0;
334   }
335 
336   const size_t msg_len = from_len - zero_index;
337   if (msg_len > max_out) {
338     // This shouldn't happen because this function is always called with
339     // |max_out| as the key size and |from_len| is bounded by the key size.
340     OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR);
341     return 0;
342   }
343 
344   OPENSSL_memcpy(out, &from[zero_index], msg_len);
345   *out_len = msg_len;
346   return 1;
347 }
348 
RSA_public_encrypt(size_t flen,const uint8_t * from,uint8_t * to,RSA * rsa,int padding)349 int RSA_public_encrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
350                        int padding) {
351   size_t out_len;
352 
353   if (!RSA_encrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
354     return -1;
355   }
356 
357   if (out_len > INT_MAX) {
358     OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
359     return -1;
360   }
361   return (int)out_len;
362 }
363 
RSA_private_encrypt(size_t flen,const uint8_t * from,uint8_t * to,RSA * rsa,int padding)364 int RSA_private_encrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
365                         int padding) {
366   size_t out_len;
367 
368   if (!RSA_sign_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
369     return -1;
370   }
371 
372   if (out_len > INT_MAX) {
373     OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
374     return -1;
375   }
376   return (int)out_len;
377 }
378 
RSA_encrypt(RSA * rsa,size_t * out_len,uint8_t * out,size_t max_out,const uint8_t * in,size_t in_len,int padding)379 int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
380                 const uint8_t *in, size_t in_len, int padding) {
381   if (rsa->n == NULL || rsa->e == NULL) {
382     OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
383     return 0;
384   }
385 
386   if (!rsa_check_public_key(rsa)) {
387     return 0;
388   }
389 
390   const unsigned rsa_size = RSA_size(rsa);
391   BIGNUM *f, *result;
392   uint8_t *buf = NULL;
393   BN_CTX *ctx = NULL;
394   int i, ret = 0;
395 
396   if (max_out < rsa_size) {
397     OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
398     return 0;
399   }
400 
401   ctx = BN_CTX_new();
402   if (ctx == NULL) {
403     goto err;
404   }
405 
406   BN_CTX_start(ctx);
407   f = BN_CTX_get(ctx);
408   result = BN_CTX_get(ctx);
409   buf = OPENSSL_malloc(rsa_size);
410   if (!f || !result || !buf) {
411     goto err;
412   }
413 
414   switch (padding) {
415     case RSA_PKCS1_PADDING:
416       i = rsa_padding_add_PKCS1_type_2(buf, rsa_size, in, in_len);
417       break;
418     case RSA_PKCS1_OAEP_PADDING:
419       // Use the default parameters: SHA-1 for both hashes and no label.
420       i = RSA_padding_add_PKCS1_OAEP_mgf1(buf, rsa_size, in, in_len, NULL, 0,
421                                           NULL, NULL);
422       break;
423     case RSA_NO_PADDING:
424       i = RSA_padding_add_none(buf, rsa_size, in, in_len);
425       break;
426     default:
427       OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
428       goto err;
429   }
430 
431   if (i <= 0) {
432     goto err;
433   }
434 
435   if (BN_bin2bn(buf, rsa_size, f) == NULL) {
436     goto err;
437   }
438 
439   if (BN_ucmp(f, rsa->n) >= 0) {
440     // usually the padding functions would catch this
441     OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
442     goto err;
443   }
444 
445   if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) ||
446       !BN_mod_exp_mont(result, f, rsa->e, &rsa->mont_n->N, ctx, rsa->mont_n)) {
447     goto err;
448   }
449 
450   // put in leading 0 bytes if the number is less than the length of the
451   // modulus
452   if (!BN_bn2bin_padded(out, rsa_size, result)) {
453     OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
454     goto err;
455   }
456 
457   *out_len = rsa_size;
458   ret = 1;
459 
460 err:
461   if (ctx != NULL) {
462     BN_CTX_end(ctx);
463     BN_CTX_free(ctx);
464   }
465   OPENSSL_free(buf);
466 
467   return ret;
468 }
469 
rsa_default_decrypt(RSA * rsa,size_t * out_len,uint8_t * out,size_t max_out,const uint8_t * in,size_t in_len,int padding)470 static int rsa_default_decrypt(RSA *rsa, size_t *out_len, uint8_t *out,
471                                size_t max_out, const uint8_t *in, size_t in_len,
472                                int padding) {
473   const unsigned rsa_size = RSA_size(rsa);
474   uint8_t *buf = NULL;
475   int ret = 0;
476 
477   if (max_out < rsa_size) {
478     OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
479     return 0;
480   }
481 
482   if (padding == RSA_NO_PADDING) {
483     buf = out;
484   } else {
485     // Allocate a temporary buffer to hold the padded plaintext.
486     buf = OPENSSL_malloc(rsa_size);
487     if (buf == NULL) {
488       goto err;
489     }
490   }
491 
492   if (in_len != rsa_size) {
493     OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
494     goto err;
495   }
496 
497   if (!rsa_private_transform(rsa, buf, in, rsa_size)) {
498     goto err;
499   }
500 
501   switch (padding) {
502     case RSA_PKCS1_PADDING:
503       ret =
504           rsa_padding_check_PKCS1_type_2(out, out_len, rsa_size, buf, rsa_size);
505       break;
506     case RSA_PKCS1_OAEP_PADDING:
507       // Use the default parameters: SHA-1 for both hashes and no label.
508       ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, out_len, rsa_size, buf,
509                                               rsa_size, NULL, 0, NULL, NULL);
510       break;
511     case RSA_NO_PADDING:
512       *out_len = rsa_size;
513       ret = 1;
514       break;
515     default:
516       OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
517       goto err;
518   }
519 
520   CONSTTIME_DECLASSIFY(&ret, sizeof(ret));
521   if (!ret) {
522     OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED);
523   } else {
524     CONSTTIME_DECLASSIFY(out, *out_len);
525   }
526 
527 err:
528   if (padding != RSA_NO_PADDING) {
529     OPENSSL_free(buf);
530   }
531 
532   return ret;
533 }
534 
RSA_decrypt(RSA * rsa,size_t * out_len,uint8_t * out,size_t max_out,const uint8_t * in,size_t in_len,int padding)535 int RSA_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
536                 const uint8_t *in, size_t in_len, int padding) {
537   if (rsa->meth->decrypt) {
538     return rsa->meth->decrypt(rsa, out_len, out, max_out, in, in_len, padding);
539   }
540 
541   return rsa_default_decrypt(rsa, out_len, out, max_out, in, in_len, padding);
542 }
543 
RSA_private_decrypt(size_t flen,const uint8_t * from,uint8_t * to,RSA * rsa,int padding)544 int RSA_private_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
545                         int padding) {
546   size_t out_len;
547   if (!RSA_decrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
548     return -1;
549   }
550 
551   if (out_len > INT_MAX) {
552     OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
553     return -1;
554   }
555   return (int)out_len;
556 }
557 
RSA_public_decrypt(size_t flen,const uint8_t * from,uint8_t * to,RSA * rsa,int padding)558 int RSA_public_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
559                        int padding) {
560   size_t out_len;
561   if (!RSA_verify_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
562     return -1;
563   }
564 
565   if (out_len > INT_MAX) {
566     OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
567     return -1;
568   }
569   return (int)out_len;
570 }
571